diff --git a/.gitignore b/.gitignore index d4933c3..9cbcfba 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,6 @@ composer.lock *.swp *.swo *.zip +*.phar .DS_Store .interactive_history \ No newline at end of file diff --git a/LICENSE.md b/LICENSE similarity index 100% rename from LICENSE.md rename to LICENSE diff --git a/examples/liteApp b/examples/liteApp index 5147bfd..e988fc2 100644 --- a/examples/liteApp +++ b/examples/liteApp @@ -1,7 +1,7 @@ #!/usr/bin/env php controller('home', HomeController::class); +$app->controller(PharController::class); diff --git a/examples/tests/phar.php b/examples/tests/phar.php new file mode 100644 index 0000000..deeadc8 --- /dev/null +++ b/examples/tests/phar.php @@ -0,0 +1,28 @@ +setSignatureAlgorithm(Phar::SHA1); + +// 开始打包 +$phar->startBuffering(); + +// add all files in the project, only include php files +$phar->buildFromDirectory($srcDir, '/[\.php|app]$/'); +$phar->setStub($phar::createDefaultStub('examples/app')); +//$phar->setStub($phar::createDefaultStub('examples/app', 'www/index.php')); + +$phar->stopBuffering(); + +// 打包完成 +echo "Finished {$pharFile}\n"; diff --git a/src/Application.php b/src/Application.php index 0caf087..177c270 100644 --- a/src/Application.php +++ b/src/Application.php @@ -9,7 +9,6 @@ namespace Inhere\Console; use Inhere\Console\Base\AbstractApplication; -use LightCms\Web\App; /** * Class App @@ -17,6 +16,16 @@ */ class Application extends AbstractApplication { + /** + * @var string|null + */ + protected $commandsNamespace; + + /** + * @var string|null + */ + protected $controllersNamespace; + /********************************************************** * register console controller/command **********************************************************/ @@ -266,4 +275,36 @@ public function runAction($name, $action, $believable = false, $standAlone = fal return $object->run($action); } + /** + * @return null|string + */ + public function getCommandsNamespace() + { + return $this->commandsNamespace; + } + + /** + * @param null|string $commandsNamespace + */ + public function setCommandsNamespace($commandsNamespace) + { + $this->commandsNamespace = $commandsNamespace; + } + + /** + * @return null|string + */ + public function getControllersNamespace() + { + return $this->controllersNamespace; + } + + /** + * @param null|string $controllersNamespace + */ + public function setControllersNamespace($controllersNamespace) + { + $this->controllersNamespace = $controllersNamespace; + } + } diff --git a/src/Base/ApplicationInterface.php b/src/Base/ApplicationInterface.php index 82578f8..6590d08 100644 --- a/src/Base/ApplicationInterface.php +++ b/src/Base/ApplicationInterface.php @@ -23,7 +23,6 @@ interface ApplicationInterface /** * @param bool $exit - * @return int */ public function run($exit = true); diff --git a/src/BuiltIn/PharController.php b/src/BuiltIn/PharController.php new file mode 100644 index 0000000..8a67a1d --- /dev/null +++ b/src/BuiltIn/PharController.php @@ -0,0 +1,57 @@ +* + * phar The output phar file path + * + * @options + * -c,--compress Want compress php file. + * --file-include Append file include + * + */ + public function packCommand() + { + $pcr = new PharCompiler(BASE_PATH); + $pcr->setOptions([ + 'cliIndex' => 'examples/app', + 'webIndex' => null, + + 'compress' => $this->getSameOpt(['c', 'compress'], false), + + 'dirExclude' => '#[\.git|tests]#', + + 'fileInclude' => ['LICENSE', 'app', 'liteApp'], + 'fileMatch' => '#\.php#', + ]); + + $pharFile = BASE_PATH . '/test.phar'; + $count = $pcr->pack($pharFile); + + $this->output->json([ + 'count' => $count, + 'size' => round(filesize($pharFile) / 1000, 2) . ' kb', + ]); + } +} \ No newline at end of file diff --git a/src/LiteApplication.php b/src/LiteApplication.php index 3fe47f2..f81921a 100644 --- a/src/LiteApplication.php +++ b/src/LiteApplication.php @@ -8,6 +8,8 @@ namespace Inhere\Console; +use Inhere\Console\Style\LiteStyle; + /** * Class LiteApplication * @package Inhere\Console @@ -227,11 +229,11 @@ public function commands(array $commands) public function showCommands($err = '') { if ($err) { - echo "ERROR: $err\n\n"; + echo LiteStyle::color("ERROR: $err\n\n"); } $commandWidth = 12; - $help = "Welcome to the Lite Console Application.\n\nAvailable Commands:\n"; + $help = "Welcome to the Lite Console Application.\n\nAvailable Commands:\n"; foreach ($this->messages as $command => $desc) { $command = str_pad($command, $commandWidth, ' '); @@ -239,7 +241,7 @@ public function showCommands($err = '') $help .= " $command $desc\n"; } - echo $help . PHP_EOL; + echo LiteStyle::color($help) . PHP_EOL; exit(0); } diff --git a/src/_resources/art-fonts/404.txt b/src/Resources/art-fonts/404.txt similarity index 100% rename from src/_resources/art-fonts/404.txt rename to src/Resources/art-fonts/404.txt diff --git a/src/Style/Style.php b/src/Style/Style.php index c1340ac..4b27476 100644 --- a/src/Style/Style.php +++ b/src/Style/Style.php @@ -10,6 +10,7 @@ namespace Inhere\Console\Style; +use Inhere\Console\Application; use Inhere\Console\Utils\Helper; /** @@ -146,7 +147,7 @@ public function format($text) } // if don't support output color text, clear color tag. - if (!Helper::isSupportColor()) { + if (!Helper::isSupportColor() || Application::isNoColor()) { return static::stripColor($text); } diff --git a/src/Traits/FormatOutputTrait.php b/src/Traits/FormatOutputTrait.php index ec5cf70..2b5a644 100644 --- a/src/Traits/FormatOutputTrait.php +++ b/src/Traits/FormatOutputTrait.php @@ -8,6 +8,7 @@ namespace Inhere\Console\Traits; +use Inhere\Console\Application; use Inhere\Console\Style\Style; use Inhere\Console\Utils\Helper; use Inhere\Console\Utils\Show; diff --git a/src/Traits/InputOutputTrait.php b/src/Traits/InputOutputTrait.php index 60d49f2..57e77f3 100644 --- a/src/Traits/InputOutputTrait.php +++ b/src/Traits/InputOutputTrait.php @@ -57,9 +57,9 @@ public function getRequiredArg($name) * @see Input::getSameArg() * {@inheritdoc} */ - public function getSameArg($name, $default = null) + public function getSameArg(array $names, $default = null) { - return $this->input->getSameArg($name, $default); + return $this->input->getSameArg($names, $default); } /** @@ -75,9 +75,9 @@ public function getOpt($name, $default = null) * @see Input::getSameOpt() * {@inheritdoc} */ - public function getSameOpt($name, $default = null) + public function getSameOpt(array $names, $default = null) { - return $this->input->getSameOpt($name, $default); + return $this->input->getSameOpt($names, $default); } /** diff --git a/src/Utils/Helper.php b/src/Utils/Helper.php index 8a7edd4..4bd175b 100644 --- a/src/Utils/Helper.php +++ b/src/Utils/Helper.php @@ -88,6 +88,23 @@ public static function init($object, array $options) } } + /** + * @param string $srcDir + * @param callable $filter + * @return \RecursiveIteratorIterator + */ + public static function recursiveDirectoryIterator(string $srcDir, callable $filter) + { + if (!$srcDir || !file_exists($srcDir)) { + throw new \LogicException('Please provide a exists source directory.'); + } + + $directory = new \RecursiveDirectoryIterator($srcDir); + $filterIterator = new \RecursiveCallbackFilterIterator($directory, $filter); + + return new \RecursiveIteratorIterator($filterIterator); + } + /** * wrap a style tag * @param string $string diff --git a/src/Utils/PharCompiler.php b/src/Utils/PharCompiler.php new file mode 100644 index 0000000..f1be123 --- /dev/null +++ b/src/Utils/PharCompiler.php @@ -0,0 +1,341 @@ + null, + 'webIndex' => null, + + // compress php code + 'compress' => false, + + 'dirExclude' => '#[\.git|tests]#', + + 'fileInclude' => [], + 'fileMatch' => '#\.php#', + ]; + + /** @var array */ + private $srcDirs; + + /** @var array */ + private $appendFiles; + + /** @var string */ + private $dstDir; + + /** + * PharCompiler constructor. + * @param null|string|array $srcDirs + * @param null $dstDir + * @param array $options + */ + public function __construct($srcDirs = null, $dstDir = null, array $options = []) + { + $this->srcDirs = $srcDirs ? (array)$srcDirs : []; + $this->dstDir = $dstDir; + + $this->setOptions($options); + } + + /** + * Compiles some dirs into a single phar file. + * @param string $pharFile The full path to the file to create + * @param string $version + * @return int + */ + public function pack($pharFile = 'your.phar', $version = '0.0.1') + { + if (file_exists($pharFile)) { + unlink($pharFile); + } + + $pharName = basename($pharFile); + $this->version = $version; + + if (!$this->srcDirs) { + throw new \LogicException('Please setting the source directory for pack'); + } + + $phar = new Phar($pharFile, 0, $pharName); +// $phar = new Phar($pharFile, \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::KEY_AS_FILENAME, $pharName); + $phar->setMetadata(['author' => 'inhere']); + $phar->setSignatureAlgorithm(Phar::SHA1); + + // begin + $phar->startBuffering(); + + foreach ($this->srcDirs as $srcDir) { + $this->collectFiles($phar, $srcDir); + } + + // Stubs +// $phar->setStub($this->getStub()); +// $stub = Phar::createDefaultStub($this->options['cliIndex'], $this->options['webIndex']); +// $phar->setStub($stub); + + // 设置入口 + $phar->setStub(""); + + $phar->stopBuffering(); + $count = $phar->count(); + unset($phar); + + return $count; + } + + /** + * @param string $file + * @param string|null $distDir + */ + public function unpack(string $file, string $distDir = null) + { + if (!$distDir = $distDir ?: $this->dstDir) { + throw new \LogicException('Please setting the dist directory for unpack'); + } + } + + protected function collectFiles(Phar $phar, $srcDir) + { + $iterator = Helper::recursiveDirectoryIterator($srcDir, function ($file) { + /** @var \SplFileInfo $file */ + $name = $file->getFilename(); + + // Skip hidden files and directories. + if ($name[0] === '.') { + return false; + } + + if ($file->isDir()) { + // Only recurse into intended subdirectories. + return preg_match($this->options['dirExclude'], $name); + } + + if (in_array($name, $this->options['fileInclude'], true)) { + return true; + } + + // Only consume files of interest. + return preg_match($this->options['fileMatch'], $name); + }); + + $phar->buildFromIterator($iterator, $srcDir); +// $phar->buildFromDirectory($srcDir, '/[\.php|app]$/'); + +// foreach ($iterator as $file) { +// $this->addFileToPhar($phar, $file, $srcDir); +// } + } + + /** + * Add a file to the Phar. + * @param Phar $phar + * @param \SplFileInfo $file + * @param string $basePath + */ + private function addFileToPhar($phar, \SplFileInfo $file, $basePath) + { + $isPhp = $file->getExtension() === 'php'; + // $path = str_replace($basePath . DIRECTORY_SEPARATOR, '', $file->getRealPath()); + $path = substr($file->getRealPath(), strlen($basePath) + 1); + + if ($isPhp && $this->options['compress']) { + $content = php_strip_whitespace($file); + } elseif ('LICENSE' === basename($file)) { + $content = file_get_contents($file); + $content = "\n" . $content . "\n"; + } else { + $content = file_get_contents($file); + } + + $phar->addFromString($path, $content); + } + + const STUB_AUTOLOAD = <<>> \*/}sm', self::STUB_AUTOLOAD, $content); + $content = preg_replace('/\\(c\\) .*?with this source code./sm', self::getStubLicense(), $content); + + $content .= '__HALT_COMPILER();'; + + return $content; + } + + private static function getStubLicense() + { + $license = file_get_contents(__DIR__ . '/../../LICENSE'); + $license = str_replace('The MIT License (MIT)', '', $license); + $license = str_replace("\n", "\n * ", trim($license)); + + return $license; + } + + /** + * @param string $file + * @return $this + */ + public function setCliIndex(string $file) + { + $this->options['cliIndex'] = $file; + + return $this; + } + + /** + * @param string $file + * @return $this + */ + public function setWebIndex(string $file) + { + $this->options['webIndex'] = $file; + + return $this; + } + + /** + * @param string|array $name + * @return $this + */ + public function addFileInclude($name) + { + $this->options['fileInclude'] = array_merge($this->options['fileInclude'], (array)$name); + + return $this; + } + + /** + * @param string $regex + * @return $this + */ + public function setDirExclude(string $regex) + { + $this->options['dirExclude'] = $regex; + + return $this; + } + + /** + * @param string $regex + * @return $this + */ + public function setFileMatch(string $regex) + { + $this->options['fileMatch'] = $regex; + + return $this; + } + + /** + * @param string $srcDir + * @return $this + */ + public function addSrcDir(string $srcDir) + { + $this->srcDirs[] = $srcDir; + + return $this; + } + + /** + * @return array + */ + public function getAppendFiles(): array + { + return $this->appendFiles; + } + + /** + * @param array $appendFiles + * @return PharCompiler + */ + public function setAppendFiles(array $appendFiles): PharCompiler + { + $this->appendFiles = $appendFiles; + + return $this; + } + + /** + * @return array + */ + public function getSrcDirs(): array + { + return $this->srcDirs; + } + + /** + * @param string|array $srcDirs + */ + public function setSrcDirs($srcDirs) + { + $this->srcDirs = (array)$srcDirs; + } + + /** + * @return string + */ + public function getDstDir(): ?string + { + return $this->dstDir; + } + + /** + * @param string $dstDir + */ + public function setDstDir(string $dstDir) + { + $this->dstDir = $dstDir; + } + + /** + * @return array + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * @param array $options + */ + public function setOptions(array $options) + { + $this->options = array_merge($this->options, $options); + } +} diff --git a/src/Utils/Show.php b/src/Utils/Show.php index 8a646ed..b72072e 100644 --- a/src/Utils/Show.php +++ b/src/Utils/Show.php @@ -8,6 +8,7 @@ namespace Inhere\Console\Utils; +use Inhere\Console\Application; use Inhere\Console\Style\Style; /**