From 5a880092e5227fae527fe506df04e8db21636cc9 Mon Sep 17 00:00:00 2001 From: Juan Lago Date: Sat, 1 Oct 2016 21:49:21 +0200 Subject: [PATCH] Decoupled controllers --- src/App/Controller/Build.php | 233 +++++++++++++++++++++- src/App/Controller/Main.php | 374 ++--------------------------------- src/App/Controller/New.php | 188 ++++++++++++++++++ src/App/View/help_build.txt | 18 ++ src/App/View/help_main.txt | 14 -- src/App/View/help_new.txt | 14 ++ src/Config/Version.php | 4 +- 7 files changed, 471 insertions(+), 374 deletions(-) create mode 100644 src/App/Controller/New.php create mode 100644 src/App/View/help_build.txt create mode 100644 src/App/View/help_new.txt diff --git a/src/App/Controller/Build.php b/src/App/Controller/Build.php index 96ab88f..3587016 100644 --- a/src/App/Controller/Build.php +++ b/src/App/Controller/Build.php @@ -1,12 +1,235 @@ action_help('build'); + return Apprunner::EXIT_SUCCESS; + } + + $this->read_manifest(); + $this->open_target_conf(); + + return parent::action_main(); + } + + + + /** + * Perform the build command + */ + protected function action_build() + { + + + // Check dependencies + // ------------------ + if (!Phar::canWrite()) + $this->exit_error('phar.readonly was set to 1, please modify your php.ini'); + + + $compression_method = false; + + if (Params::get('compress')) + { + + switch (Params::get('compress')) + { + + case 'bz2': + $compression_method = Phar::BZ2; + + if (!Phar::canCompress($compression_method)) + $this->exit_error('BZ2 compression method not available. Install the BZIP2 extension'); + + case 'gz': + default: + + $compression_method = Phar::GZ; + + if (!Phar::canCompress($compression_method)) + $this->exit_error('GZ compression method not available. Install the ZLIB extension'); + + } + } + + + // Improve phar security + // --------------------- + ini_set('phar.require_hash', true); + + + // Compute buildpath + // ----------------- + if (empty($GLOBALS['manifest']->paths->build)) + $buildpath = getcwd() . DS; + else + $buildpath = dirname($GLOBALS['manifest']->_manifest_path) . DS . $GLOBALS['manifest']->paths->build; + + $buildpath = realpath($buildpath) . DS; + + + // Create temp directory + // --------------------- + $this->term->br()->out('Creating build base...'); + + $tmpdir = $buildpath . 'temp_' . uniqid() . DS; + + if (!@mkdir($tmpdir)) + $this->exit_error('Unable to create temp directory: ' . $tmpdir); + + + // Read version + // ------------ + $external_version = (array) $external_version = $this->external_conf->load('version');; + + + // Copy src files + // -------------- + $this->term->br()->out("Copying base files..."); + if (!File::xcopy($GLOBALS['manifest']->_srcpath . '*', $tmpdir, 0755, File::EXCLUDE_HIDDEN)) + $this->exit_error("Unable to copy project files from {$GLOBALS['manifest']->_srcpath} to temporal directory: $tmpdir"); + + + // Set version to build file + // ------------------------- + $GLOBALS['manifest']->build->name = Replacer::replace_from_array($external_version, $GLOBALS['manifest']->build->name, 'VERSION'); + + + // Set phar file path + // ------------------ + $pharfile = $buildpath . $GLOBALS['manifest']->build->name; + + + // Read and process project files + // ------------------------------ + $this->term->br()->out("Replacing symbols and striping files..."); + $p_files = File::ls($tmpdir, true, File::EXCLUDE_BLOCK | File::EXCLUDE_DIRECTORIES | File::EXCLUDE_LINKS | File::LIST_RECURSIVE); + + foreach ($p_files as $file) + { + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $file_mime = finfo_file($finfo, $file); + + @list($file_type, $file_format) = explode('/', $file_mime); + + // Replace only text files + if ($file_type == 'text' || $file_format == 'php') + { + + if ($file_format == 'php' || $file_format == 'x-php') + $file_content = php_strip_whitespace($file); + else + $file_content = file_get_contents($file); + + $file_content = Replacer::replace_from_array($external_version, $file_content, 'VERSION'); + + file_put_contents($file, $file_content); + } + + } + + + + // Modify versions + // --------------- + if (Params::get('inc-major')) + $this->action_inc_major(); + + if (Params::get('inc-minor')) + $this->action_inc_minor(); + + $this->action_inc_build(); + + + + // Build phar + // ---------- + $this->term->br()->out("Building PHAR..."); + $phar = new Model_PharBuilder($tmpdir); + + // Prepare signature + // ----------------- + if (!empty(Params::get('private-key'))) + { + $signature = new Model_SignatureManager(Params::get('private-key')); + $key_password = ''; + + if ($signature->is_protected()) + { + $input_password = $this->term->br()->password(Juanparati\Emoji\Emoji::char('lock') . ' Enter the private key password:'); + $key_password = $input_password->prompt(); + } + + $this->term->br()->out('Exporting signature...'); + + $signature->export($key_password); + $phar->set('private_key', $signature->get()); + + Params::set('signature-type', 'openssl'); + } + + + // Set signature type + $signature_type = Params::get('signature-type'); + + if (is_string($signature_type)) + $signature_type = strtolower($signature_type); + + + switch ($signature_type) + { + + case 'openssl': + $phar->set('signature', Phar::OPENSSL); + break; + + case 'md5': + $phar->set('signature', Phar::MD5); + break; + + case 'sha1': + $phar->set('signature', Phar::SHA1); + break; + + case 'sha256': + $phar->set('signature', Phar::SHA256); + break; + + case 'sha512': + $phar->set('signature', Phar::SHA512); + break; + } + + + if (Params::get('executable')) + $phar->set('executable', true); + + $phar->set('compress', $compression_method); + + if (($build_status = $phar->build($pharfile)) !== true) + $this->exit_error($build_status); + + $this->term->br()->out(Juanparati\Emoji\Emoji::char('beer mug') . " Build performed, enjoy of your new PHAR at: $pharfile"); + + + if (Params::get('remove-tmp') && File::deltree(substr($tmpdir, 0, -1))) + $this->term->br()->out("Removed temporal folder: $tmpdir"); + + + } + } \ No newline at end of file diff --git a/src/App/Controller/Main.php b/src/App/Controller/Main.php index 4f49c96..81bbe7d 100755 --- a/src/App/Controller/Main.php +++ b/src/App/Controller/Main.php @@ -42,383 +42,44 @@ public function action_main() $controller = 'action_' . strtolower(Params::get('command')); $controller = str_replace('-', '_', $controller); - if (!Params::get('command') || $controller == __FUNCTION__) + if (!Params::get('command') || $controller == __FUNCTION__ || $controller == 'action_help') $this->action_help(); else { if (method_exists($this, $controller)) { - - if ($controller != 'action_new') - { - $this->read_manifest(); - $this->open_target_conf(); - } - $this->{$controller}(); $this->term->br()->out('Operation completed!'); } else - $this->action_help(); - } - - return Apprunner::terminate(Apprunner::EXIT_SUCCESS); - - } - - - /** - * Display help message - */ - protected function action_help() - { - $help = file_get_contents(APPPATH . 'View/help_main.txt'); - $help = str_replace('#{{__EXECUTABLE__}}', basename(Phar::running()), $help); - - $this->term->out($help); - } - - - /** - * Start a new project - * - * @return int - */ - protected function action_new() - { - - // Read destination directory - // -------------------------- - $dest = Params::get('source') ? Params::get('source') : '.'; - - if ($dest[0] != DS) - $dest = getcwd() . DS . $dest; - - $dest = realpath($dest); - - if (!is_writable($dest)) - $this->exit_error('Unable to write in path!'); - - - // Retrieve release binary URL - // --------------------------- - if (!Params::get('release')) - Params::set('release', 'latest'); - - $package = new Model_ReleasePackage(Params::get('release')); - $package_url = $package->getBinaryURL(); - - if (!$package_url) - $this->exit_error('Release package is not available (Wrong version?)'); - - - // Get release binary size - // ----------------------- - $fsize = get_headers($package_url, true); - $fsize = isset($fsize['Content-Length']) ? $fsize['Content-Length'] : false; - - - // Download file - // ------------- - if (!$fpsrc = fopen($package_url, 'r')) - $this->exit_error('Unable to download ' . $package_url); - - $this->term->br()->out('Downloading: ' . $package_url); - - $fptmp = tmpfile(); - - while(!feof($fpsrc)) - { - fwrite($fptmp, fread($fpsrc, 65536)); - - if ($fsize) - $this->show_progressbar(array('total' => $fsize, 'current' => fstat($fptmp)['size'])); - } - - fclose($fpsrc); - - - // Decompress file - // --------------- - $this->term->br()->out('Uncompressing...'); - - $zip = new ZipArchive(); - $zippath = stream_get_meta_data($fptmp)['uri']; - - if ($zip->open($zippath) === true) - { - - $total_files = $zip->numFiles; - - for ($i = 0; $i < $total_files; $i++) { - $entry = $zip->getNameIndex($i); + $controller = ucfirst(Params::get('command')); - if ($entry === 'mamuph_base/') - continue; - - $name = str_replace('mamuph_base/', '/', $entry); - $dir = $dest . dirname($name); - - if (!file_exists($dir)) - mkdir($dir); - - @copy('zip://' . $zippath . '#' . $entry, $dest . $name); - - $this->show_progressbar(['total' => $total_files, 'current' => $i + 1]); + if (Apprunner::find_file(APPPATH . 'Controller', $controller, 'php')) + Apprunner::execute($controller); + else + $this->action_help(); } - $zip->close(); - - } - else - $this->exit_error('Unable to decompress source file'); - - fclose($fptmp); - - - // Set project name - // ---------------- - $manifest_path = $dest . DS . 'manifest.json'; - - if (!File::exists($manifest_path, File::SCOPE_EXTERNAL)) - $this->exit_error('Unable to find manifest.json'); - - $manifest = json_decode(file_get_contents($manifest_path), true); - $project_name = Params::get('name'); - - if (!$project_name) - { - do - { - $input = $this->term->br()->input('Project name?'); - $project_name = $input->prompt(); - - if (empty(trim($project_name))) - $project_name = false; - - } while (!$project_name); - } - $manifest['name'] = $project_name; - - file_put_contents($manifest_path, json_encode($manifest, JSON_PRETTY_PRINT)); - - - // End action - // ---------- - $this->term->br()->out(\Juanparati\Emoji\Emoji::char('thumbs up') . " New project $project_name deployed"); - - return Apprunner::EXIT_SUCCESS; + return Apprunner::terminate(Apprunner::EXIT_SUCCESS); } - /** - * Perform the build command + * Display help view + * + * @param string $help_view */ - protected function action_build() + protected function action_help($help_view = 'main') { + $help = file_get_contents(APPPATH . 'View/help_' . $help_view . '.txt'); + $help = str_replace('#{{__EXECUTABLE__}}', basename(Phar::running()), $help); - - // Check dependencies - // ------------------ - if (!Phar::canWrite()) - $this->exit_error('phar.readonly was set to 1, please modify your php.ini'); - - - $compression_method = false; - - if (Params::get('compress')) - { - - switch (Params::get('compress')) - { - - case 'bz2': - $compression_method = Phar::BZ2; - - if (!Phar::canCompress($compression_method)) - $this->exit_error('BZ2 compression method not available. Install the BZIP2 extension'); - - case 'gz': - default: - - $compression_method = Phar::GZ; - - if (!Phar::canCompress($compression_method)) - $this->exit_error('GZ compression method not available. Install the ZLIB extension'); - - } - } - - - // Improve phar security - // --------------------- - ini_set('phar.require_hash', true); - - - // Compute buildpath - // ----------------- - if (empty($GLOBALS['manifest']->paths->build)) - $buildpath = getcwd() . DS; - else - $buildpath = dirname($GLOBALS['manifest']->_manifest_path) . DS . $GLOBALS['manifest']->paths->build; - - $buildpath = realpath($buildpath) . DS; - - - // Create temp directory - // --------------------- - $this->term->br()->out('Creating build base...'); - - $tmpdir = $buildpath . 'temp_' . uniqid() . DS; - - if (!@mkdir($tmpdir)) - $this->exit_error('Unable to create temp directory: ' . $tmpdir); - - - // Read version - // ------------ - $external_version = (array) $external_version = $this->external_conf->load('version');; - - - // Copy src files - // -------------- - $this->term->br()->out("Copying base files..."); - if (!File::xcopy($GLOBALS['manifest']->_srcpath . '*', $tmpdir, 0755, File::EXCLUDE_HIDDEN)) - $this->exit_error("Unable to copy project files from {$GLOBALS['manifest']->_srcpath} to temporal directory: $tmpdir"); - - - // Set version to build file - // ------------------------- - $GLOBALS['manifest']->build->name = Replacer::replace_from_array($external_version, $GLOBALS['manifest']->build->name, 'VERSION'); - - - // Set phar file path - // ------------------ - $pharfile = $buildpath . $GLOBALS['manifest']->build->name; - - - // Read and process project files - // ------------------------------ - $this->term->br()->out("Replacing symbols and striping files..."); - $p_files = File::ls($tmpdir, true, File::EXCLUDE_BLOCK | File::EXCLUDE_DIRECTORIES | File::EXCLUDE_LINKS | File::LIST_RECURSIVE); - - foreach ($p_files as $file) - { - $finfo = finfo_open(FILEINFO_MIME_TYPE); - $file_mime = finfo_file($finfo, $file); - - @list($file_type, $file_format) = explode('/', $file_mime); - - // Replace only text files - if ($file_type == 'text' || $file_format == 'php') - { - - if ($file_format == 'php' || $file_format == 'x-php') - $file_content = php_strip_whitespace($file); - else - $file_content = file_get_contents($file); - - $file_content = Replacer::replace_from_array($external_version, $file_content, 'VERSION'); - - file_put_contents($file, $file_content); - } - - } - - - - // Modify versions - // --------------- - if (Params::get('inc-major')) - $this->action_inc_major(); - - if (Params::get('inc-minor')) - $this->action_inc_minor(); - - $this->action_inc_build(); - - - - // Build phar - // ---------- - $this->term->br()->out("Building PHAR..."); - $phar = new Model_PharBuilder($tmpdir); - - // Prepare signature - // ----------------- - if (!empty(Params::get('private-key'))) - { - $signature = new Model_SignatureManager(Params::get('private-key')); - $key_password = ''; - - if ($signature->is_protected()) - { - $input_password = $this->term->br()->password(Juanparati\Emoji\Emoji::char('lock') . ' Enter the private key password:'); - $key_password = $input_password->prompt(); - } - - $this->term->br()->out('Exporting signature...'); - - $signature->export($key_password); - $phar->set('private_key', $signature->get()); - - Params::set('signature-type', 'openssl'); - } - - - // Set signature type - $signature_type = Params::get('signature-type'); - - if (is_string($signature_type)) - $signature_type = strtolower($signature_type); - - - switch ($signature_type) - { - - case 'openssl': - $phar->set('signature', Phar::OPENSSL); - break; - - case 'md5': - $phar->set('signature', Phar::MD5); - break; - - case 'sha1': - $phar->set('signature', Phar::SHA1); - break; - - case 'sha256': - $phar->set('signature', Phar::SHA256); - break; - - case 'sha512': - $phar->set('signature', Phar::SHA512); - break; - } - - - if (Params::get('executable')) - $phar->set('executable', true); - - $phar->set('compress', $compression_method); - - if (($build_status = $phar->build($pharfile)) !== true) - $this->exit_error($build_status); - - $this->term->br()->out(Juanparati\Emoji\Emoji::char('beer mug') . " Build performed, enjoy of your new PHAR at: $pharfile"); - - - if (Params::get('remove-tmp') && File::deltree(substr($tmpdir, 0, -1))) - $this->term->br()->out("Removed temporal folder: $tmpdir"); - - + $this->term->out($help); } @@ -496,6 +157,13 @@ public function action_dec_build() protected function modify_version($key, $inc = 1) { + + if (empty($GLOBALS['manifest'])) + { + $this->read_manifest(); + $this->open_target_conf(); + } + $external_version = $this->external_conf->load('version'); $external_version->{$key} = $external_version->{$key} + $inc; $external_version->set($key, $external_version->{$key}); diff --git a/src/App/Controller/New.php b/src/App/Controller/New.php new file mode 100644 index 0000000..7090fe6 --- /dev/null +++ b/src/App/Controller/New.php @@ -0,0 +1,188 @@ +action_help('new'); + return Apprunner::EXIT_SUCCESS; + } + + + return parent::action_main(); + } + + + /** + * Deploy a new project + * + * @return int + */ + protected function action_new() + { + + // Read destination directory + // -------------------------- + $dest = Params::get('source') ? Params::get('source') : '.'; + + if ($dest[0] != DS) + $dest = getcwd() . DS . $dest; + + $dest = realpath($dest); + + if (is_file($dest)) + $this->exit_error('Wrong path'); + + if (!is_writable($dest)) + $this->exit_error("Unable to write in $dest"); + + if (is_dir($dest)) + { + + // Check if directory is empty + if ((new \FilesystemIterator($dest))->valid()) + { + $this->term->br()->out('Directory already exists and it is not empty'); + + $input = $this->term->confirm('Continue?'); + + if (!$input->confirmed()) + $this->exit_error('Aborting...'); + } + + } + else + { + if (@mkdir($dest, 0774)) + $this->exit_error("Unable to create directory $dest"); + } + + + // Retrieve release binary URL + // --------------------------- + if (!Params::get('release')) + Params::set('release', 'latest'); + + $package = new Model_ReleasePackage(Params::get('release')); + $package_url = $package->getBinaryURL(); + + if (!$package_url) + $this->exit_error('Release package is not available (Wrong version?)'); + + + // Get release binary size + // ----------------------- + $fsize = get_headers($package_url, true); + $fsize = isset($fsize['Content-Length']) ? $fsize['Content-Length'] : false; + + + // Download file + // ------------- + if (!$fpsrc = fopen($package_url, 'r')) + $this->exit_error('Unable to download ' . $package_url); + + $this->term->br()->out('Downloading: ' . $package_url); + + $fptmp = tmpfile(); + + while(!feof($fpsrc)) + { + fwrite($fptmp, fread($fpsrc, 65536)); + + if ($fsize) + $this->show_progressbar(array('total' => $fsize, 'current' => fstat($fptmp)['size'])); + } + + fclose($fpsrc); + + + // Decompress file + // --------------- + $this->term->br()->out('Decompressing...'); + + $zip = new ZipArchive(); + $zippath = stream_get_meta_data($fptmp)['uri']; + + if ($zip->open($zippath) === true) + { + + $total_files = $zip->numFiles; + + for ($i = 0; $i < $total_files; $i++) + { + $entry = $zip->getNameIndex($i); + + if ($entry === 'mamuph_base/') + continue; + + $name = str_replace('mamuph_base/', '/', $entry); + $dir = $dest . dirname($name); + + if (!file_exists($dir)) + mkdir($dir); + + @copy('zip://' . $zippath . '#' . $entry, $dest . $name); + + $this->show_progressbar(['total' => $total_files, 'current' => $i + 1]); + } + + $zip->close(); + + } + else + $this->exit_error('Unable to decompress source file'); + + fclose($fptmp); + + + // Set project name + // ---------------- + $manifest_path = $dest . DS . 'manifest.json'; + + if (!File::exists($manifest_path, File::SCOPE_EXTERNAL)) + $this->exit_error('Unable to find manifest.json'); + + $manifest = json_decode(file_get_contents($manifest_path), true); + $project_name = Params::get('name'); + + if (!$project_name) + { + do + { + $input = $this->term->br()->input('Project name?'); + $project_name = $input->prompt(); + + if (empty(trim($project_name))) + $project_name = false; + + } while (!$project_name); + + } + + $manifest['name'] = $project_name; + + file_put_contents($manifest_path, json_encode($manifest, JSON_PRETTY_PRINT)); + + + // End action + // ---------- + $this->term->br()->out(\Juanparati\Emoji\Emoji::char('thumbs up') . " New project $project_name deployed"); + + return Apprunner::EXIT_SUCCESS; + + } + + +} \ No newline at end of file diff --git a/src/App/View/help_build.txt b/src/App/View/help_build.txt new file mode 100644 index 0000000..302fbe4 --- /dev/null +++ b/src/App/View/help_build.txt @@ -0,0 +1,18 @@ + + _____ + / ___/__ __ _____ ______ _ ___ ____ + / /__/ _ `/ |/ / -_) __/ ' \/ _ `/ _ \ + \___/\_,_/|___/\__/_/ /_/_/_/\_,_/_//_/ #{{VERSION.MAJOR}}.#{{VERSION.MINOR}} + The Mamuph Helper Tool + + + Usage: + #{{__EXECUTABLE__}} build [project path] [options] + + Options: + -x Build PHAR as autoexecutable + -r or --remove-tmp Remove temporal files + -z or --compress Compress PHAR (Use --compress=bz2 for BZIP2 compression) + --inc-major Increase major version + --inc-minor Increase minor version + --private-key=key Sign with private key (PEM format) diff --git a/src/App/View/help_main.txt b/src/App/View/help_main.txt index 51e7eaa..377d518 100644 --- a/src/App/View/help_main.txt +++ b/src/App/View/help_main.txt @@ -16,22 +16,8 @@ new [base] Initialize a new empty project - Options: - --release=release Release (Default latest) - --name=project name Project name - - build [base] Build a new release - Options: - -x Build PHAR as autoexecutable - -r or --remove-tmp Remove temporal files - -z or --compress Compress PHAR (Use --compress=bz2 for BZIP2 compression) - --inc-major Increase major version - --inc-minor Increase minor version - --private-key=key Sign with private key (PEM format) - - inc-major [base] Increase major version dec-major [base] Decrease major version diff --git a/src/App/View/help_new.txt b/src/App/View/help_new.txt new file mode 100644 index 0000000..2b9c1ca --- /dev/null +++ b/src/App/View/help_new.txt @@ -0,0 +1,14 @@ + + _____ + / ___/__ __ _____ ______ _ ___ ____ + / /__/ _ `/ |/ / -_) __/ ' \/ _ `/ _ \ + \___/\_,_/|___/\__/_/ /_/_/_/\_,_/_//_/ #{{VERSION.MAJOR}}.#{{VERSION.MINOR}} + The Mamuph Helper Tool + + + Usage: + #{{__EXECUTABLE__}} new [project path] [options] + + Options: + --release=release Release (Default latest) + --name=project name Project name diff --git a/src/Config/Version.php b/src/Config/Version.php index ef2da9b..d0aa771 100644 --- a/src/Config/Version.php +++ b/src/Config/Version.php @@ -1,7 +1,7 @@ 1, - 'minor' => 5, - 'build' => 34, + 'minor' => 7, + 'build' => 41, 'codename' => 'Caverman', ); \ No newline at end of file