mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-03 06:45:39 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a00f8945ba | ||
|
|
2bc02bdaac | ||
|
|
b97327d6d7 | ||
|
|
61d1507a4d | ||
|
|
a6f07051c3 | ||
|
|
75417d15b7 | ||
|
|
4bab7ecfab | ||
|
|
7298e2441b | ||
|
|
1ed104d2f6 | ||
|
|
cf6125b9cc | ||
|
|
f2cfe33cdd | ||
|
|
a1e4125ded | ||
|
|
7a1433a994 |
@@ -11,7 +11,7 @@ This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro
|
||||
|
||||
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
|
||||
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
|
||||
@@ -24,7 +24,7 @@ This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro
|
||||
## Compilation Requirements
|
||||
|
||||
Yes, this project is written in PHP, pretty funny.
|
||||
But static-php-cli runtime only requires an environment above PHP 8.0 and `tokenizer`, `iconv` extension.
|
||||
But static-php-cli runtime only requires an environment above PHP 8.1 and `mbstring`, `pcntl` extension.
|
||||
|
||||
Here is the architecture support status, where `CI` represents support for GitHub Action builds,
|
||||
`Local` represents support for local builds, and blank represents not currently supported.
|
||||
|
||||
@@ -12,7 +12,7 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
|
||||
|
||||
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
|
||||
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
|
||||
[](https://github.com/crazywhalecc/static-php-cli/actions/workflows/build.yml)
|
||||
@@ -24,7 +24,7 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
|
||||
## 编译环境需求
|
||||
|
||||
是的,本项目采用 PHP 编写,编译前需要一个 PHP 环境,比较滑稽。
|
||||
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 tokenizer 扩展和 PHP 版本大于等于 8.0 即可。
|
||||
但本项目默认可通过自身构建的 micro 和 static-php 二进制运行,其他只需要包含 mbstring、pcntl 扩展和 PHP 版本大于等于 8.1 即可。
|
||||
|
||||
下面是架构支持情况,`CI` 代表支持 GitHub Action 构建,`Local` 代表支持本地构建,空 代表暂不支持。
|
||||
|
||||
|
||||
@@ -9,16 +9,15 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">= 8.0",
|
||||
"ext-tokenizer": "*",
|
||||
"ext-iconv": "*",
|
||||
"php": ">= 8.1",
|
||||
"ext-mbstring": "*",
|
||||
"ext-pcntl": "*",
|
||||
"laravel/prompts": "^0.1.3",
|
||||
"symfony/console": "^6 || ^5 || ^4",
|
||||
"zhamao/logger": "^1.0",
|
||||
"crazywhalecc/cli-helper": "^0.1.0",
|
||||
"nunomaduro/collision": "*",
|
||||
"ext-pcntl": "*"
|
||||
"zhamao/logger": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nunomaduro/collision": "*",
|
||||
"friendsofphp/php-cs-fixer": "^3.2 != 3.7.0",
|
||||
"phpstan/phpstan": "^1.1",
|
||||
"captainhook/captainhook": "^5.10",
|
||||
|
||||
@@ -135,6 +135,14 @@
|
||||
"imagemagick"
|
||||
]
|
||||
},
|
||||
"glfw": {
|
||||
"type": "external",
|
||||
"arg-type": "custom",
|
||||
"source": "ext-glfw",
|
||||
"lib-depends": [
|
||||
"glfw"
|
||||
]
|
||||
},
|
||||
"imap": {
|
||||
"type": "builtin",
|
||||
"arg-type": "with",
|
||||
@@ -298,7 +306,10 @@
|
||||
"redis": {
|
||||
"type": "external",
|
||||
"source": "redis",
|
||||
"arg-type": "custom"
|
||||
"arg-type": "custom",
|
||||
"ext-suggests": [
|
||||
"session"
|
||||
]
|
||||
},
|
||||
"session": {
|
||||
"type": "builtin"
|
||||
|
||||
@@ -15,6 +15,18 @@
|
||||
"brotli"
|
||||
]
|
||||
},
|
||||
"glfw": {
|
||||
"source": "ext-glfw",
|
||||
"static-libs-unix": [
|
||||
"libglfw3.a"
|
||||
],
|
||||
"frameworks": [
|
||||
"CoreVideo",
|
||||
"OpenGL",
|
||||
"Cocoa",
|
||||
"IOKit"
|
||||
]
|
||||
},
|
||||
"bzip2": {
|
||||
"source": "bzip2",
|
||||
"static-libs-unix": [
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"ext-glfw": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mario-deluna/php-glfw",
|
||||
"rev": "master",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"apcu": {
|
||||
"type": "url",
|
||||
"url": "https://pecl.php.net/get/APCu",
|
||||
@@ -295,7 +304,7 @@
|
||||
"type": "ghrel",
|
||||
"repo": "mongodb/mongo-php-driver",
|
||||
"path": "php-src/ext/mongodb",
|
||||
"match": "mongodb.+\\.tgz",
|
||||
"match": "mongodb.+\\.zip",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
@@ -467,4 +476,4 @@
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC;
|
||||
|
||||
use SPC\command\DeployCommand;
|
||||
use SPC\store\FileSystem;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\HelpCommand;
|
||||
@@ -15,7 +14,7 @@ use Symfony\Component\Console\Command\ListCommand;
|
||||
*/
|
||||
class ConsoleApplication extends Application
|
||||
{
|
||||
public const VERSION = '2.0-rc4';
|
||||
public const VERSION = '2.0-rc5';
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
@@ -32,13 +31,19 @@ class ConsoleApplication extends Application
|
||||
|
||||
// 通过扫描目录 src/static-php-cli/command/ 添加子命令
|
||||
$commands = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/command', 'SPC\\command');
|
||||
$this->addCommands(array_map(function ($x) { return new $x(); }, array_filter($commands, function ($y) {
|
||||
if (is_a($y, DeployCommand::class, true) && (class_exists('\\Phar') && \Phar::running() || !class_exists('\\Phar'))) {
|
||||
$phar = class_exists('\\Phar') && \Phar::running() || !class_exists('\\Phar');
|
||||
$commands = array_filter($commands, function ($y) use ($phar) {
|
||||
$archive_blacklist = [
|
||||
'SPC\command\dev\SortConfigCommand',
|
||||
'SPC\command\DeployCommand',
|
||||
];
|
||||
if ($phar && in_array($y, $archive_blacklist)) {
|
||||
return false;
|
||||
}
|
||||
$reflection = new \ReflectionClass($y);
|
||||
return !$reflection->isAbstract() && !$reflection->isInterface();
|
||||
})));
|
||||
});
|
||||
$this->addCommands(array_map(function ($x) { return new $x(); }, $commands));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
24
src/SPC/builder/extension/glfw.php
Normal file
24
src/SPC/builder/extension/glfw.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\extension;
|
||||
|
||||
use SPC\builder\Extension;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\CustomExt;
|
||||
|
||||
#[CustomExt('glfw')]
|
||||
class glfw extends Extension
|
||||
{
|
||||
public function patchBeforeBuildconf(): bool
|
||||
{
|
||||
FileSystem::copyDir(SOURCE_PATH . '/ext-glfw', SOURCE_PATH . '/php-src/ext/glfw');
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getUnixConfigureArg(): string
|
||||
{
|
||||
return '--enable-glfw --with-glfw-dir=' . BUILD_ROOT_PATH;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,12 @@ class redis extends Extension
|
||||
{
|
||||
public function getUnixConfigureArg(): string
|
||||
{
|
||||
$arg = '--enable-redis --disable-redis-session';
|
||||
$arg = '--enable-redis';
|
||||
if (!$this->builder->getExt('session')) {
|
||||
$arg .= ' --disable-redis-session';
|
||||
} else {
|
||||
$arg .= ' --enable-redis-session';
|
||||
}
|
||||
if ($this->builder->getLib('zstd')) {
|
||||
$arg .= ' --enable-redis-zstd --with-libzstd="' . BUILD_ROOT_PATH . '"';
|
||||
}
|
||||
|
||||
21
src/SPC/builder/macos/library/glfw.php
Normal file
21
src/SPC/builder/macos/library/glfw.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\macos\library;
|
||||
|
||||
class glfw extends MacOSLibraryBase
|
||||
{
|
||||
public const NAME = 'glfw';
|
||||
|
||||
protected function build()
|
||||
{
|
||||
// compile!
|
||||
shell()->cd(SOURCE_PATH . '/ext-glfw/vendor/glfw')
|
||||
->exec("{$this->builder->configure_env} cmake . {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_TESTS=OFF")
|
||||
->exec("make -j{$this->builder->concurrency}")
|
||||
->exec('make install DESTDIR=' . BUILD_ROOT_PATH);
|
||||
// patch pkgconf
|
||||
$this->patchPkgconfPrefix(['glfw3.pc']);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ abstract class BaseCommand extends Command
|
||||
foreach ($msg as $v) {
|
||||
logger()->error($v);
|
||||
}
|
||||
return self::FAILURE;
|
||||
return static::FAILURE;
|
||||
} catch (\Throwable $e) {
|
||||
// 不开 debug 模式就不要再显示复杂的调试栈信息了
|
||||
if ($this->getOption('debug')) {
|
||||
@@ -102,10 +102,10 @@ abstract class BaseCommand extends Command
|
||||
logger()->error($v);
|
||||
}
|
||||
}
|
||||
return self::FAILURE;
|
||||
return static::FAILURE;
|
||||
}
|
||||
}
|
||||
return self::SUCCESS;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
protected function getOption(string $name): mixed
|
||||
|
||||
@@ -51,7 +51,7 @@ class BuildCliCommand extends BuildCommand
|
||||
$this->output->writeln("<comment>\t--build-micro\tBuild phpmicro SAPI</comment>");
|
||||
$this->output->writeln("<comment>\t--build-fpm\tBuild php-fpm SAPI</comment>");
|
||||
$this->output->writeln("<comment>\t--build-all\tBuild all SAPI: cli, micro, fpm</comment>");
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
try {
|
||||
// 构建对象
|
||||
@@ -113,10 +113,10 @@ class BuildCliCommand extends BuildCommand
|
||||
$dumper = new LicenseDumper();
|
||||
$dumper->addExts($extensions)->addLibs($libraries)->addSources(['php-src'])->dump(BUILD_ROOT_PATH . '/license');
|
||||
logger()->info('License path' . $fixed . ': ' . $build_root_path . '/license/');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
} catch (WrongUsageException $e) {
|
||||
logger()->critical($e->getMessage());
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
} catch (\Throwable $e) {
|
||||
if ($this->getOption('debug')) {
|
||||
ExceptionHandler::getInstance()->handle($e);
|
||||
@@ -124,7 +124,7 @@ class BuildCliCommand extends BuildCommand
|
||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
||||
logger()->critical('Please check with --debug option to see more details.');
|
||||
}
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class BuildLibsCommand extends BuildCommand
|
||||
|
||||
$time = round(microtime(true) - START_TIME, 3);
|
||||
logger()->info('Build libs complete, used ' . $time . ' s !');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
} catch (\Throwable $e) {
|
||||
if ($this->getOption('debug')) {
|
||||
ExceptionHandler::getInstance()->handle($e);
|
||||
@@ -71,7 +71,7 @@ class BuildLibsCommand extends BuildCommand
|
||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
||||
logger()->critical('Please check with --debug option to see more details.');
|
||||
}
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use CliHelper\Tools\ArgFixer;
|
||||
use CliHelper\Tools\DataProvider;
|
||||
use CliHelper\Tools\SeekableArrayIterator;
|
||||
use SPC\store\FileSystem;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use function Laravel\Prompts\confirm;
|
||||
use function Laravel\Prompts\text;
|
||||
|
||||
#[AsCommand('deploy', 'Deploy static-php-cli self to an .phar application')]
|
||||
class DeployCommand extends BaseCommand
|
||||
{
|
||||
@@ -20,26 +21,51 @@ class DeployCommand extends BaseCommand
|
||||
$this->addArgument('target', InputArgument::OPTIONAL, 'The file or directory to pack.');
|
||||
$this->addOption('auto-phar-fix', null, InputOption::VALUE_NONE, 'Automatically fix ini option.');
|
||||
$this->addOption('overwrite', 'W', InputOption::VALUE_NONE, 'Overwrite existing files.');
|
||||
$this->addOption('with-no-dev', 'D', InputOption::VALUE_NONE, 'Automatically use non-dev composer dependencies to reduce size');
|
||||
$this->addOption('with-dev', 'd', InputOption::VALUE_NONE, 'Automatically use dev composer dependencies');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
// 第一阶段流程:如果没有写path,将会提示输入要打包的path
|
||||
$prompt = new ArgFixer($this->input, $this->output);
|
||||
$composer = require ROOT_DIR . '/vendor/composer/installed.php';
|
||||
if (($composer['root']['dev'] ?? false) === true) {
|
||||
if (!$this->getOption('with-no-dev')) {
|
||||
$this->output->writeln('<comment>Current static-php-cli dependencies have installed dev-dependencies</comment>');
|
||||
$this->output->writeln('<comment>If you want to remove, you can choose "Yes" to run command "composer update --no-dev" to remove.</comment>');
|
||||
$this->output->writeln('<comment>Or choose "No", just pack, deploy.</comment>');
|
||||
$ask = confirm('Do you want to remove dev-dependencies to reduce size of phar file?');
|
||||
} elseif (!$this->getOption('with-dev')) {
|
||||
$ask = true;
|
||||
} else {
|
||||
$ask = false;
|
||||
}
|
||||
if ($ask) {
|
||||
[$code] = shell()->execWithResult('composer update --no-dev');
|
||||
if ($code !== 0) {
|
||||
$this->output->writeln('<error>"composer update --no-dev" failed with exit code [' . $code . ']</error>');
|
||||
$this->output->writeln('<error>You may need to run this command by your own.</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
$this->output->writeln('<info>Update successfully, you need to re-run deploy command to pack.</info>');
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
// 首先得确认是不是关闭了readonly模式
|
||||
if (ini_get('phar.readonly') == 1) {
|
||||
if ($this->getOption('auto-phar-fix')) {
|
||||
$ask = true;
|
||||
} else {
|
||||
$ask = $prompt->requireBool('<comment>pack command needs "phar.readonly" = "Off" !</comment>' . PHP_EOL . 'If you want to automatically set it and continue, just Enter', true);
|
||||
$this->output->writeln('<comment>pack command needs "phar.readonly" = "Off" !</comment>');
|
||||
$ask = confirm('Do you want to automatically set it and continue ?');
|
||||
// $ask = $prompt->requireBool('<comment>pack command needs "phar.readonly" = "Off" !</comment>' . PHP_EOL . 'If you want to automatically set it and continue, just Enter', true);
|
||||
}
|
||||
if ($ask) {
|
||||
global $argv;
|
||||
$args = array_merge(['-d', 'phar.readonly=0'], $_SERVER['argv']);
|
||||
$args = array_merge(['-d', 'phar.readonly=0'], $_SERVER['argv'], ['--no-motd']);
|
||||
if (function_exists('pcntl_exec')) {
|
||||
$this->output->writeln('<info>Changing to phar.readonly=0 mode ...</info>');
|
||||
if (pcntl_exec(PHP_BINARY, $args) === false) {
|
||||
throw new \PharException('切换到读写模式失败,请检查环境。');
|
||||
throw new \PharException('Switching to read write mode failed, please check the environment.');
|
||||
}
|
||||
} else {
|
||||
$this->output->writeln('<info>Now running command in child process.</info>');
|
||||
@@ -51,23 +77,29 @@ class DeployCommand extends BaseCommand
|
||||
// 获取路径
|
||||
$path = WORKING_DIR;
|
||||
// 如果是目录,则将目录下的所有文件打包
|
||||
$phar_path = $prompt->requireArgument('target', 'Please input the phar target filename', 'static-php-cli.phar');
|
||||
$phar_path = text('Please input the phar target filename', default: '/tmp/static-php-cli.phar');
|
||||
// $phar_path = $prompt->requireArgument('target', 'Please input the phar target filename', 'static-php-cli.phar');
|
||||
|
||||
if (DataProvider::isRelativePath($phar_path)) {
|
||||
$phar_path = '/tmp/' . $phar_path;
|
||||
if (FileSystem::isRelativePath($phar_path)) {
|
||||
$phar_path = WORKING_DIR . '/' . $phar_path;
|
||||
}
|
||||
if (file_exists($phar_path)) {
|
||||
$ask = $this->getOption('overwrite') ? true : $prompt->requireBool('<comment>The file "' . $phar_path . '" already exists, do you want to overwrite it?</comment>' . PHP_EOL . 'If you want to, just Enter');
|
||||
if (!$this->getOption('overwrite')) {
|
||||
$this->output->writeln('<comment>The file "' . $phar_path . '" already exists.</comment>');
|
||||
$ask = confirm('Do you want to overwrite it?');
|
||||
} else {
|
||||
$ask = true;
|
||||
}
|
||||
if (!$ask) {
|
||||
$this->output->writeln('<comment>User canceled.</comment>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
@unlink($phar_path);
|
||||
}
|
||||
$phar = new \Phar($phar_path);
|
||||
$phar->startBuffering();
|
||||
|
||||
$all = DataProvider::scanDirFiles($path, true, true);
|
||||
$all = FileSystem::scanDirFiles($path, true, true);
|
||||
|
||||
$all = array_filter($all, function ($x) {
|
||||
$dirs = preg_match('/(^(config|src|vendor)\\/|^(composer\\.json|README\\.md|source\\.json|LICENSE|README-en\\.md)$)/', $x);
|
||||
@@ -97,7 +129,7 @@ class DeployCommand extends BaseCommand
|
||||
$phar->setStub($phar->createDefaultStub($stub));
|
||||
} catch (\Throwable $e) {
|
||||
$this->output->writeln($e);
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
$phar->addFromString('.prod', 'true');
|
||||
$phar->stopBuffering();
|
||||
@@ -114,7 +146,7 @@ class DeployCommand extends BaseCommand
|
||||
}
|
||||
chmod($phar_path, 0755);
|
||||
$this->output->writeln('<info>Phar Executable: ' . $phar_path . '</info>');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
private function progress(int $max = 0): ProgressBar
|
||||
|
||||
@@ -24,8 +24,8 @@ class DoctorCommand extends BaseCommand
|
||||
} catch (\Throwable $e) {
|
||||
$this->output->writeln('<error>' . $e->getMessage() . '</error>');
|
||||
pcntl_signal(SIGINT, SIG_IGN);
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,14 +68,14 @@ class DownloadCommand extends BaseCommand
|
||||
f_passthru('rm -rf ' . DOWNLOAD_PATH . '/*');
|
||||
f_passthru('rm -rf ' . BUILD_ROOT_PATH . '/*');
|
||||
}
|
||||
return 0;
|
||||
return static::FAILURE;
|
||||
}
|
||||
|
||||
// --from-zip
|
||||
if ($path = $this->getOption('from-zip')) {
|
||||
if (!file_exists($path)) {
|
||||
logger()->critical('File ' . $path . ' not exist or not a zip archive.');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
// remove old download files first
|
||||
if (is_dir(DOWNLOAD_PATH)) {
|
||||
@@ -89,7 +89,7 @@ class DownloadCommand extends BaseCommand
|
||||
if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) {
|
||||
logger()->critical('Missing unzip command, you need to install it first !');
|
||||
logger()->critical('You can use "bin/spc doctor" command to check and install required tools');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
// create downloads
|
||||
try {
|
||||
@@ -103,10 +103,10 @@ class DownloadCommand extends BaseCommand
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
logger()->critical('Extract failed: ' . $e->getMessage());
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
logger()->info('Extract success');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
// Define PHP major version
|
||||
@@ -115,7 +115,7 @@ class DownloadCommand extends BaseCommand
|
||||
preg_match('/^\d+\.\d+$/', $ver, $matches);
|
||||
if (!$matches) {
|
||||
logger()->error("bad version arg: {$ver}, x.y required!");
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
|
||||
// Use shallow-clone can reduce git resource download
|
||||
@@ -175,6 +175,6 @@ class DownloadCommand extends BaseCommand
|
||||
// 打印拉取资源用时
|
||||
$time = round(microtime(true) - START_TIME, 3);
|
||||
logger()->info('Download complete, used ' . $time . ' s !');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ class DumpLicenseCommand extends BaseCommand
|
||||
$this->output->writeln('Dump license with libraries: ' . implode(', ', $libraries));
|
||||
$this->output->writeln('Dump license with' . ($this->getOption('without-php') ? 'out' : '') . ' php-src');
|
||||
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
if ($this->getOption('by-libs') !== null) {
|
||||
$libraries = array_map('trim', array_filter(explode(',', $this->getOption('by-libs'))));
|
||||
@@ -58,16 +58,16 @@ class DumpLicenseCommand extends BaseCommand
|
||||
$dumper->addLibs($libraries);
|
||||
$dumper->dump($this->getOption('dump-dir'));
|
||||
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
if ($this->getOption('by-sources') !== null) {
|
||||
$sources = array_map('trim', array_filter(explode(',', $this->getOption('by-sources'))));
|
||||
$dumper->addSources($sources);
|
||||
$dumper->dump($this->getOption('dump-dir'));
|
||||
$this->output->writeln('Dump target dir: ' . $this->getOption('dump-dir'));
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
$this->output->writeln('You must use one of "--by-extensions=", "--by-libs=", "--by-sources=" to dump');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ class ExtractCommand extends BaseCommand
|
||||
{
|
||||
$sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
||||
if (empty($sources)) {
|
||||
$this->output->writeln('<erorr>sources cannot be empty, at least contain one !</erorr>');
|
||||
return 1;
|
||||
$this->output->writeln('<error>sources cannot be empty, at least contain one !</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
SourceExtractor::initSource(sources: $sources);
|
||||
logger()->info('Extract done !');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\store\Config;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand('list-ext', 'List supported extensions')]
|
||||
class ListExtCommand extends BaseCommand
|
||||
{
|
||||
protected bool $no_motd = true;
|
||||
|
||||
/**
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
foreach (Config::getExts() as $ext => $meta) {
|
||||
echo $ext . PHP_EOL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -35,12 +35,12 @@ class MicroCombineCommand extends BaseCommand
|
||||
// 1. Make sure specified micro.sfx file exists
|
||||
if ($micro_file !== null && !file_exists($micro_file)) {
|
||||
$this->output->writeln('<error>The micro.sfx file you specified is incorrect or does not exist!</error>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
// 2. Make sure buildroot/bin/micro.sfx exists
|
||||
if ($micro_file === null && !file_exists($internal)) {
|
||||
$this->output->writeln('<error>You haven\'t compiled micro.sfx yet, please use "build" command and "--build-micro" to compile phpmicro first!</error>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
// 3. Use buildroot/bin/micro.sfx
|
||||
if ($micro_file === null) {
|
||||
@@ -49,19 +49,19 @@ class MicroCombineCommand extends BaseCommand
|
||||
// 4. Make sure php or phar file exists
|
||||
if (!is_file(FileSystem::convertPath($file))) {
|
||||
$this->output->writeln('<error>The file to combine does not exist!</error>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
// 5. Confirm ini files (ini-set has higher priority)
|
||||
if ($ini_file !== null) {
|
||||
// Check file exist first
|
||||
if (!file_exists($ini_file)) {
|
||||
$this->output->writeln('<error>The ini file to combine does not exist! (' . $ini_file . ')</error>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
$arr = parse_ini_file($ini_file);
|
||||
if ($arr === false) {
|
||||
$this->output->writeln('<error>Cannot parse ini file</error>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
$target_ini = array_merge($target_ini, $arr);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ class MicroCombineCommand extends BaseCommand
|
||||
$arr = parse_ini_string($item);
|
||||
if ($arr === false) {
|
||||
$this->output->writeln('<error>--with-ini-set parse failed</error>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
$target_ini = array_merge($target_ini, $arr);
|
||||
}
|
||||
@@ -90,12 +90,12 @@ class MicroCombineCommand extends BaseCommand
|
||||
$result = file_put_contents($output, $file_target);
|
||||
if ($result === false) {
|
||||
$this->output->writeln('<error>Combine failed.</error>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
// 9. chmod +x
|
||||
chmod($output, 0755);
|
||||
$this->output->writeln('<info>Combine success! Binary file: ' . $output . '</info>');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
private function encodeINI(array $array): string
|
||||
|
||||
@@ -8,17 +8,17 @@ use SPC\command\BaseCommand;
|
||||
use SPC\store\Config;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
||||
#[AsCommand('dev:ext-all', 'Dev command')]
|
||||
#[AsCommand('dev:ext-all', 'Dev command', ['list-ext'])]
|
||||
class AllExtCommand extends BaseCommand
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->addOption('line', 'l', null, 'Show with separate lines');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$this->output->writeln(implode(',', array_keys(Config::getExts())));
|
||||
|
||||
return 0;
|
||||
$this->output->writeln(implode($this->input->getOption('line') ? PHP_EOL : ',', array_keys(Config::getExts())));
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ class ExtInfoCommand extends BaseCommand
|
||||
}
|
||||
$this->output->writeln('');
|
||||
}
|
||||
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ class PhpVerCommand extends BaseCommand
|
||||
$result = preg_match('/#define PHP_VERSION "([^"]+)"/', file_get_contents($file), $match);
|
||||
if ($result === false) {
|
||||
$this->output->writeln('<error>PHP source not found, maybe you need to extract first ?</error>');
|
||||
return 1;
|
||||
return static::FAILURE;
|
||||
}
|
||||
$this->output->writeln('<info>' . $match[1] . '</info>');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
namespace SPC\command\dev;
|
||||
|
||||
use SPC\command\BaseCommand;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\ValidationException;
|
||||
use SPC\store\FileSystem;
|
||||
@@ -12,9 +13,9 @@ use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
/**
|
||||
* 修改 config 后对其 kv 进行排序的操作
|
||||
* Modify config file: sort lib, ext, source by name.
|
||||
*/
|
||||
#[AsCommand('sort-config', 'After config edited, sort it by alphabet')]
|
||||
#[AsCommand('dev:sort-config', 'After config edited, sort it by alphabet', ['sort-config'])]
|
||||
class SortConfigCommand extends BaseCommand
|
||||
{
|
||||
public function configure()
|
||||
@@ -33,25 +34,34 @@ class SortConfigCommand extends BaseCommand
|
||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/lib.json'), true);
|
||||
ConfigValidator::validateLibs($file);
|
||||
ksort($file);
|
||||
file_put_contents(ROOT_DIR . '/config/lib.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
if (!file_put_contents(ROOT_DIR . '/config/lib.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
|
||||
$this->output->writeln('<error>Write file lib.json failed!</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
break;
|
||||
case 'source':
|
||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/source.json'), true);
|
||||
ConfigValidator::validateSource($file);
|
||||
uksort($file, fn ($a, $b) => $a === 'php-src' ? -1 : ($b === 'php-src' ? 1 : ($a < $b ? -1 : 1)));
|
||||
file_put_contents(ROOT_DIR . '/config/source.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
if (!file_put_contents(ROOT_DIR . '/config/source.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
|
||||
$this->output->writeln('<error>Write file source.json failed!</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
break;
|
||||
case 'ext':
|
||||
$file = json_decode(FileSystem::readFile(ROOT_DIR . '/config/ext.json'), true);
|
||||
ConfigValidator::validateExts($file);
|
||||
ksort($file);
|
||||
file_put_contents(ROOT_DIR . '/config/ext.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
if (!file_put_contents(ROOT_DIR . '/config/ext.json', json_encode($file, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE))) {
|
||||
$this->output->writeln('<error>Write file ext.json failed!</error>');
|
||||
return static::FAILURE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->output->writeln("<error>invalid config name: {$name}</error>");
|
||||
return 1;
|
||||
}
|
||||
$this->output->writeln('<info>sort success</info>');
|
||||
return 0;
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ class MacOSToolCheckList
|
||||
'xz',
|
||||
'gzip',
|
||||
'bzip2',
|
||||
'gotop',
|
||||
'cmake',
|
||||
];
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ class ExceptionHandler
|
||||
logger()->error($e->getTraceAsString());
|
||||
return;
|
||||
}
|
||||
|
||||
$this->whoops->handleException($e);
|
||||
|
||||
logger()->critical('You can report this exception to static-php-cli GitHub repo.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,28 +320,7 @@ class FileSystem
|
||||
foreach ($files as $v) {
|
||||
$pathinfo = pathinfo($v);
|
||||
if (($pathinfo['extension'] ?? '') == 'php') {
|
||||
$path = rtrim($dir, '/') . '/' . rtrim($pathinfo['dirname'], './') . '/' . $pathinfo['basename'];
|
||||
|
||||
// 过滤不包含类的文件
|
||||
$tokens = token_get_all(self::readFile($path));
|
||||
$found = false;
|
||||
foreach ($tokens as $token) {
|
||||
if (!is_array($token)) {
|
||||
continue;
|
||||
}
|
||||
if ($token[0] === T_CLASS) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($rule === null) { // 规则未设置回调时候,使用默认的识别过滤规则
|
||||
/*if (substr(file_get_contents($dir . '/' . $v), 6, 6) == '#plain') {
|
||||
continue;
|
||||
}*/
|
||||
if ($rule === null) {
|
||||
if (file_exists($dir . '/' . $pathinfo['basename'] . '.ignore')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user