diff --git a/src/ZM/Command/BuildCommand.php b/src/ZM/Command/BuildCommand.php index 8bda4150..608c7a12 100644 --- a/src/ZM/Command/BuildCommand.php +++ b/src/ZM/Command/BuildCommand.php @@ -7,8 +7,9 @@ namespace ZM\Command; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputOption; use ZM\Store\FileSystem; +use ZM\Store\PharHelper; -#[AsCommand(name: 'build', description: '将项目构建一个 Phar 包')] +#[AsCommand(name: 'build', description: '将炸毛框架项目构建一个 Phar 包')] class BuildCommand extends Command { use NonPharLoadModeOnly; @@ -18,20 +19,29 @@ class BuildCommand extends Command */ protected function configure() { - $this->setHelp('此功能将会把整个项目打包为 Phar' . PHP_EOL . '默认会启用压缩功能,通过去除文件中的注释和空格,以减小文件大小,但可能增加构建耗时'); - $this->addOption('target', 'D', InputOption::VALUE_REQUIRED, '指定输出文件位置', 'zm.phar'); + $this->setHelp('此功能将会把整个框架项目打包为 Phar' . PHP_EOL . '默认会启用压缩功能,通过去除文件中的注释和空格,以减小文件大小,但可能增加构建耗时'); + $this->addOption('build-dir', 'D', InputOption::VALUE_REQUIRED, '指定输出文件夹(默认为 build/)', WORKING_DIR . '/build'); + $this->addOption('target', 'T', InputOption::VALUE_REQUIRED, '指定输出文件名称(默认为 zm.phar)', 'zm.phar'); $this->addOption('no-compress', null, InputOption::VALUE_NONE, '是否不压缩文件,以减小构建耗时'); } + /** + * @throws \PharException + */ protected function handle(): int { - $this->ensurePharWritable(); + // 确认可写 Phar + PharHelper::ensurePharWritable(); $target = $this->input->getOption('target'); - if (FileSystem::isRelativePath($target)) { - $target = SOURCE_ROOT_DIR . '/' . $target; + $build_dir = $this->input->getOption('build-dir'); + if (FileSystem::isRelativePath($build_dir)) { + $build_dir = WORKING_DIR . '/' . $build_dir; } - $this->ensureTargetWritable($target); + $target = $build_dir . '/' . $target; + // 确认 Phar 文件可以写入 + PharHelper::ensurePharFileWritable($target); + $this->comment("目标文件:{$target}"); if (file_exists($target)) { @@ -51,38 +61,6 @@ class BuildCommand extends Command return self::SUCCESS; } - private function ensurePharWritable(): void - { - if (ini_get('phar.readonly') === '1') { - if (!function_exists('pcntl_exec')) { - $this->error('Phar 处于只读模式,且 pcntl 扩展未加载,无法自动切换到读写模式。'); - $this->error('请修改 php.ini 中的 phar.readonly 为 0,或执行 php -d phar.readonly=0 ' . $_SERVER['PHP_SELF'] . ' build'); - exit(1); - } - // Windows 下无法使用 pcntl_exec - if (DIRECTORY_SEPARATOR === '\\') { - $this->error('Phar 处于只读模式,且当前运行环境为 Windows,无法自动切换到读写模式。'); - $this->error('请修改 php.ini 中的 phar.readonly 为 0,或执行 php -d phar.readonly=0 ' . $_SERVER['PHP_SELF'] . ' build'); - exit(1); - } - $this->info('Phar 处于只读模式,正在尝试切换到读写模式...'); - sleep(1); - $args = array_merge(['-d', 'phar.readonly=0'], $_SERVER['argv']); - if (pcntl_exec(PHP_BINARY, $args) === false) { - $this->error('切换到读写模式失败,请检查环境。'); - exit(1); - } - } - } - - private function ensureTargetWritable(string $target): void - { - if (file_exists($target) && !is_writable($target)) { - $this->error('目标文件不可写:' . $target); - exit(1); - } - } - private function build(string $target, string $entry): void { $phar = new \Phar($target, 0); diff --git a/src/ZM/Store/PharHelper.php b/src/ZM/Store/PharHelper.php new file mode 100644 index 00000000..d8c3c54d --- /dev/null +++ b/src/ZM/Store/PharHelper.php @@ -0,0 +1,52 @@ +info('Phar 处于只读模式,正在尝试切换到读写模式...'); + } + sleep(1); + $args = array_merge(['-d', 'phar.readonly=0'], $_SERVER['argv']); + if (pcntl_exec(PHP_BINARY, $args) === false) { + throw new \PharException('切换到读写模式失败,请检查环境。'); + } + } + } + + /** + * 调用该方法将确认传入的 Phar 文件是否可写,如果不可写将抛出 \PharException 异常。 + * + * @throws \PharException + */ + public static function ensurePharFileWritable(string $phar_path): void + { + if (file_exists($phar_path) && !is_writable($phar_path)) { + throw new \PharException('目标文件不可写:' . $phar_path); + } + } +}