diff --git a/src/Globals/global_defines_app.php b/src/Globals/global_defines_app.php index 39560b37..5cbb924a 100644 --- a/src/Globals/global_defines_app.php +++ b/src/Globals/global_defines_app.php @@ -51,8 +51,8 @@ const ZM_PLUGIN_TYPE_PHAR = 1; // Phar 类型的插件 const ZM_PLUGIN_TYPE_SOURCE = 2; // 源码类型的插件 const ZM_PLUGIN_TYPE_COMPOSER = 3; // Composer 依赖的插件 -const LOAD_MODE_VENDOR = 0; // 从 vendor 加载 -const LOAD_MODE_SRC = 1; // 从 src 加载 +const LOAD_MODE_SRC = 0; // 从 src 加载 +const LOAD_MODE_VENDOR = 1; // 从 vendor 加载 /* 定义工作目录 */ define('WORKING_DIR', getcwd()); @@ -70,12 +70,12 @@ if (DIRECTORY_SEPARATOR === '\\') { define('TMP_DIR', getcwd() . '/.zm-tmp'); } -/* 定义启动模式,这里指的是框架本身的源码目录是通过 composer 加入 vendor 加载的还是直接放到 src 目录加载的,前者为 1,后者为 0 */ -define('LOAD_MODE', is_dir(zm_dir(SOURCE_ROOT_DIR . '/src/ZM')) ? LOAD_MODE_VENDOR : LOAD_MODE_SRC); +/* 定义启动模式,这里指的是框架本身的源码目录是通过 composer 加入 vendor 加载的还是直接放到 src 目录加载的 */ +define('LOAD_MODE', is_dir(zm_dir(SOURCE_ROOT_DIR . '/src/ZM')) ? LOAD_MODE_SRC : LOAD_MODE_VENDOR); -/* 定义框架本身所处的根目录,此处如果 LOAD_MODE 为 1 的话,框架自身的根目录在 vendor/zhamao/framework 子目录下 */ +/* 定义框架本身所处的根目录,此处如果 LOAD_MODE 为 VENDOR 的话,框架自身的根目录在 vendor/zhamao/framework 子目录下 */ if (Phar::running() !== '') { - define('FRAMEWORK_ROOT_DIR', zm_dir(LOAD_MODE == 1 ? (SOURCE_ROOT_DIR . '/vendor/zhamao/framework') : SOURCE_ROOT_DIR)); + define('FRAMEWORK_ROOT_DIR', zm_dir(LOAD_MODE === LOAD_MODE_VENDOR ? (SOURCE_ROOT_DIR . '/vendor/zhamao/framework') : SOURCE_ROOT_DIR)); } else { define('FRAMEWORK_ROOT_DIR', realpath(zm_dir(__DIR__ . '/../../'))); } diff --git a/src/Globals/global_defines_framework.php b/src/Globals/global_defines_framework.php index 48235af8..9bdb2d7d 100644 --- a/src/Globals/global_defines_framework.php +++ b/src/Globals/global_defines_framework.php @@ -11,5 +11,5 @@ if (!defined('ZM_START_TIME')) { /* 定义使用炸毛框架应用的版本 */ if (!defined('APP_VERSION')) { - define('APP_VERSION', LOAD_MODE == 1 ? (ZMUtil::getComposerMetadata()['version'] ?? ZM_VERSION) : ZM_VERSION); + define('APP_VERSION', LOAD_MODE === LOAD_MODE_VENDOR ? (ZMUtil::getComposerMetadata()['version'] ?? ZM_VERSION) : ZM_VERSION); } diff --git a/src/ZM/Command/BuildCommand.php b/src/ZM/Command/BuildCommand.php index 5526da05..17d540e7 100644 --- a/src/ZM/Command/BuildCommand.php +++ b/src/ZM/Command/BuildCommand.php @@ -41,7 +41,8 @@ class BuildCommand extends Command $build_dir = WORKING_DIR . '/' . $build_dir; } $target = $build_dir . '/' . $target; - // 确认 Phar 文件可以写入 + + // 确认目标文件可写 FileSystem::createDir($build_dir); FileSystem::ensureFileWritable($target); @@ -52,7 +53,14 @@ class BuildCommand extends Command unlink($target); } - // TODO: 增加开发依赖的判定并提醒 + // 检查是否安装了开发依赖 + if ((LOAD_MODE === LOAD_MODE_SRC) && file_exists(SOURCE_ROOT_DIR . '/vendor/composer/installed.php')) { + $installed = require SOURCE_ROOT_DIR . '/vendor/composer/installed.php'; + if ($installed['root']['dev']) { + $this->comment('检测到当前项目安装了开发依赖,这对于构建的 Phar 包来说是不必要的,建议在构建前执行 composer install --no-dev 以缩减包体积及加快构建速度'); + $this->confirmOrExit('是否继续构建?'); + } + } $this->info('正在构建 Phar 包'); diff --git a/src/ZM/Command/Command.php b/src/ZM/Command/Command.php index d5e54c5f..c685a5fd 100644 --- a/src/ZM/Command/Command.php +++ b/src/ZM/Command/Command.php @@ -4,15 +4,14 @@ declare(strict_types=1); namespace ZM\Command; -use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\ConsoleSectionOutput; use Symfony\Component\Console\Output\OutputInterface; -use ZM\Exception\ZMException; abstract class Command extends \Symfony\Component\Console\Command\Command { + use CommandInteractTrait; + /** * 输入 */ @@ -25,115 +24,6 @@ abstract class Command extends \Symfony\Component\Console\Command\Command */ protected OutputInterface $output; - /** - * 输出一段文本,默认样式 - * - * @param string $message 要输出的文本 - * @param bool $newline 是否在文本后换行 - * @see OutputInterface::write() - */ - public function write(string $message, bool $newline = true): void - { - $this->output->write($message, $newline); - } - - /** - * 输出文本,一般用于提示信息 - * - * @param string $message 要输出的文本 - * @param bool $newline 是否在文本后换行 - */ - public function info(string $message, bool $newline = true): void - { - $this->write("{$message}", $newline); - } - - /** - * 输出文本,一般用于错误信息 - * - * @param string $message 要输出的文本 - * @param bool $newline 是否在文本后换行 - */ - public function error(string $message, bool $newline = true): void - { - $this->write("{$message}", $newline); - } - - /** - * 输出文本,一般用于警告或附注信息 - * - * @param string $message 要输出的文本 - * @param bool $newline 是否在文本后换行 - */ - public function comment(string $message, bool $newline = true): void - { - $this->write("{$message}", $newline); - } - - /** - * 输出文本,一般用于提问信息 - * - * @param string $message 要输出的文本 - * @param bool $newline 是否在文本后换行 - */ - public function question(string $message, bool $newline = true): void - { - $this->write("{$message}", $newline); - } - - /** - * 输出文本,一般用于详细信息 - * - * @param string $message 要输出的文本 - * @param bool $newline 是否在文本后换行 - */ - public function detail(string $message, bool $newline = true): void - { - $this->write("{$message}", $newline); - } - - /** - * 输出一个区块,区块内内容可以覆写 - * - * 此功能需要 $output 为 {@see ConsoleOutputInterface} 类型 - * - * @param string $message 作为标题的文本 - * @param callable $callback 回调函数,接收一个参数,类型为 {@see ConsoleSectionOutput} - */ - public function section(string $message, callable $callback): void - { - $output = $this->output; - if (!$output instanceof ConsoleOutputInterface) { - throw new \LogicException('Section 功能只能在 ConsoleOutputInterface 中使用'); - } - - $this->info($message); - $section = $output->section(); - try { - $callback($section); - } catch (ZMException $e) { - $this->error($e->getMessage()); - exit(self::FAILURE); - } - } - - /** - * 获取一个进度条实例 - * - * @param int $max 最大进度值,可以稍后再设置 - */ - public function progress(int $max = 0): ProgressBar - { - $progress = new ProgressBar($this->output, $max); - $progress->setBarCharacter('⚬'); - $progress->setEmptyBarCharacter('⚬'); - $progress->setProgressCharacter('➤'); - $progress->setFormat( - "%current%/%max% [%bar%] %percent:3s%%\n🪅 %estimated:-20s% %memory:20s%" . PHP_EOL - ); - return $progress; - } - /** * {@inheritdoc} * @internal 不建议覆写此方法,建议使用 {@see handle()} 方法 diff --git a/src/ZM/Command/CommandInteractTrait.php b/src/ZM/Command/CommandInteractTrait.php new file mode 100644 index 00000000..7344a7ba --- /dev/null +++ b/src/ZM/Command/CommandInteractTrait.php @@ -0,0 +1,160 @@ +output->write($message, $newline); + } + + /** + * 输出文本,一般用于提示信息 + * + * @param string $message 要输出的文本 + * @param bool $newline 是否在文本后换行 + */ + public function info(string $message, bool $newline = true): void + { + $this->write("{$message}", $newline); + } + + /** + * 输出文本,一般用于错误信息 + * + * @param string $message 要输出的文本 + * @param bool $newline 是否在文本后换行 + */ + public function error(string $message, bool $newline = true): void + { + $this->write("{$message}", $newline); + } + + /** + * 输出文本,一般用于警告或附注信息 + * + * @param string $message 要输出的文本 + * @param bool $newline 是否在文本后换行 + */ + public function comment(string $message, bool $newline = true): void + { + $this->write("{$message}", $newline); + } + + /** + * 输出文本,一般用于提问信息 + * + * @param string $message 要输出的文本 + * @param bool $newline 是否在文本后换行 + */ + public function question(string $message, bool $newline = true): void + { + $this->write("{$message}", $newline); + } + + /** + * 输出文本,一般用于详细信息 + * + * @param string $message 要输出的文本 + * @param bool $newline 是否在文本后换行 + */ + public function detail(string $message, bool $newline = true): void + { + $this->write("{$message}", $newline); + } + + /** + * 输出一个区块,区块内内容可以覆写 + * + * 此功能需要 $output 为 {@see ConsoleOutputInterface} 类型 + * + * @param string $message 作为标题的文本 + * @param callable $callback 回调函数,接收一个参数,类型为 {@see ConsoleSectionOutput} + */ + public function section(string $message, callable $callback): void + { + $output = $this->output; + if (!$output instanceof ConsoleOutputInterface) { + throw new \LogicException('Section 功能只能在 ConsoleOutputInterface 中使用'); + } + + $this->info($message); + $section = $output->section(); + try { + $callback($section); + } catch (ZMException $e) { + $this->error($e->getMessage()); + exit(self::FAILURE); + } + } + + /** + * 获取一个进度条实例 + * + * @param int $max 最大进度值,可以稍后再设置 + */ + public function progress(int $max = 0): ProgressBar + { + $progress = new ProgressBar($this->output, $max); + $progress->setBarCharacter('⚬'); + $progress->setEmptyBarCharacter('⚬'); + $progress->setProgressCharacter('➤'); + $progress->setFormat( + "%current%/%max% [%bar%] %percent:3s%%\n🪅 %estimated:-20s% %memory:20s%" . PHP_EOL + ); + return $progress; + } + + /** + * 询问用户是否确认 + * + * @param string $prompt 提示信息 + * @param bool $default 默认值 + * @return bool 用户是否确认 + */ + public function confirm(string $prompt, bool $default = true): bool + { + /** @var QuestionHelper $helper */ + $helper = $this->getHelper('question'); + + $affix = $default ? '[Y/n]' : '[y/N]'; + + $question = new ConfirmationQuestion("{$prompt} {$affix} ", $default); + return $helper->ask($this->input, $this->output, $question); + } + + /** + * 询问用户是否确认,否则退出 + * + * @param string $prompt 提示信息 + * @param bool $default 默认值 + */ + public function confirmOrExit(string $prompt, bool $default = true): void + { + if (!$this->confirm($prompt, $default)) { + exit(self::SUCCESS); + } + } +} diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index e47341b2..9279e92b 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -271,7 +271,7 @@ class Framework // 打印logger显示等级 $properties['log_level'] = $this->argv['log-level'] ?? config('global.log_level') ?? 'info'; // 打印框架版本 - $properties['version'] = self::VERSION . (LOAD_MODE === 0 ? (' (build ' . ZM_VERSION_ID . ')') : ''); + $properties['version'] = self::VERSION . (LOAD_MODE === LOAD_MODE_SRC ? (' (build ' . ZM_VERSION_ID . ')') : ''); // 打印 PHP 版本 $properties['php_version'] = PHP_VERSION; // 打印 master 进程的 pid @@ -337,7 +337,7 @@ class Framework $properties['redis[' . $name . ']'] = $redis['host'] . ':' . $redis['port']; } } - if (LOAD_MODE === 0) { + if (LOAD_MODE === LOAD_MODE_SRC) { logger()->info('框架正以源码模式启动'); } logger()->debug('Starting framework with properties: ' . json_encode($properties, JSON_UNESCAPED_SLASHES));