mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-14 12:25:36 +08:00
Compare commits
17 Commits
6de5c1dab0
...
2.0-rc6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be8eb90b86 | ||
|
|
54e98666e7 | ||
|
|
e8b277ad0d | ||
|
|
3bd037f48f | ||
|
|
4d0e825b43 | ||
|
|
b14179a8de | ||
|
|
01111c51ee | ||
|
|
e7230d9f50 | ||
|
|
c22c5617ad | ||
|
|
cae7bb1dda | ||
|
|
c0830a9e1f | ||
|
|
33798ff108 | ||
|
|
8d348b9e14 | ||
|
|
3d2f6e4c3a | ||
|
|
88e9639482 | ||
|
|
0381a1c412 | ||
|
|
fdc3a7a04b |
98
.github/workflows/tests.yml
vendored
Normal file
98
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
php-cs-fixer:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
extensions: curl, openssl, mbstring
|
||||
ini-values: memory_limit=-1
|
||||
tools: pecl, composer, php-cs-fixer
|
||||
|
||||
- name: Run PHP-CS-Fixer fix
|
||||
run: php-cs-fixer fix --dry-run --diff --ansi
|
||||
|
||||
phpstan:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
extensions: curl, openssl, mbstring
|
||||
ini-values: memory_limit=-1
|
||||
tools: composer
|
||||
|
||||
- name: Cache Composer packages
|
||||
id: composer-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vendor
|
||||
key: ${{ runner.os }}-phpstan-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-phpstan-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||
|
||||
- name: Run phpstan
|
||||
run: vendor/bin/phpstan analyse
|
||||
|
||||
phpunit:
|
||||
name: PHPUnit (PHP ${{ matrix.php }})
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- php: '8.1'
|
||||
- php: '8.2'
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "${{ matrix.php }}"
|
||||
tools: pecl, composer
|
||||
extensions: curl, openssl, mbstring
|
||||
ini-values: memory_limit=-1
|
||||
|
||||
- name: Cache Composer packages
|
||||
id: composer-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vendor
|
||||
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-php-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||
|
||||
- name: Run PHPUnit tests
|
||||
run: |
|
||||
vendor/bin/phpunit tests/ --no-coverage
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -17,11 +17,15 @@ composer.lock
|
||||
# default source build root directory
|
||||
/buildroot/
|
||||
|
||||
# php cs fixer cache file
|
||||
# tools cache files
|
||||
.php-cs-fixer.cache
|
||||
.phpunit.result.cache
|
||||
|
||||
# exclude self-runtime
|
||||
/bin/*
|
||||
!/bin/spc
|
||||
!/bin/setup-runtime
|
||||
!/bin/spc-alpine-docker
|
||||
|
||||
# default test directory
|
||||
/tests/var/
|
||||
|
||||
@@ -65,5 +65,5 @@ return (new PhpCsFixer\Config())
|
||||
'phpdoc_var_without_name' => false,
|
||||
])
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()->in(__DIR__ . '/src')
|
||||
PhpCsFixer\Finder::create()->in([__DIR__ . '/src', __DIR__ . '/tests/SPC'])
|
||||
);
|
||||
|
||||
29
README-en.md
29
README-en.md
@@ -1,15 +1,17 @@
|
||||
# static-php-cli
|
||||
|
||||
Compile A Statically Linked PHP With Swoole and other Extensions.
|
||||
Build single static PHP binary, with PHP project together, with popular extensions included.
|
||||
|
||||
The project name is static-php-cli, but it actually supports cli, fpm, micro and embed (on the way) SAPI 😎
|
||||
|
||||
Compile a purely static php-cli binary file with various extensions to make PHP applications more portable! (cli SAPI)
|
||||
|
||||
<img width="600" alt="截屏2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png">
|
||||
<img width="600" alt="2023-05-02 15 53 13" src="https://user-images.githubusercontent.com/20330940/235610282-23e58d68-bd35-4092-8465-171cff2d5ba8.png">
|
||||
|
||||
You can also use the micro binary file to combine php binary and php source code into one for distribution!
|
||||
This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro). (micro SAPI)
|
||||
|
||||
<img width="600" alt="截屏2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
|
||||
<img width="600" alt="2023-05-02 15 52 33" src="https://user-images.githubusercontent.com/20330940/235610318-2ef4e3f1-278b-4ca4-99f4-b38120efc395.png">
|
||||
|
||||
[]()
|
||||
[]()
|
||||
@@ -19,8 +21,6 @@ This feature is provided by [dixyes/phpmicro](https://github.com/dixyes/phpmicro
|
||||
[]()
|
||||
[]()
|
||||
|
||||
> The project has renamed the `refactor` branch to the `main` branch, please pay attention to changing the branch name for dependent projects.
|
||||
|
||||
## Compilation Requirements
|
||||
|
||||
Yes, this project is written in PHP, pretty funny.
|
||||
@@ -194,18 +194,6 @@ Because php-fpm must specify a configuration file before running, the php-fpm co
|
||||
|
||||
Specifying `php-fpm.conf` can use the command parameter `-y`, for example: `./php-fpm -y php-fpm.conf`.
|
||||
|
||||
## Current Status
|
||||
|
||||
- [X] Basic CLI framework (by `symfony/console`)
|
||||
- [X] Linux support
|
||||
- [X] macOS support
|
||||
- [X] Exception handler
|
||||
- [ ] Windows support
|
||||
- [X] PHP 7.4 support
|
||||
- [X] fpm support
|
||||
|
||||
More functions and features are coming soon, Bugs and TODOs: https://github.com/crazywhalecc/static-php-cli/issues/32
|
||||
|
||||
## Contribution
|
||||
|
||||
Currently, there are only a few supported extensions.
|
||||
@@ -236,8 +224,9 @@ You can sponsor my project on [this page](https://github.com/crazywhalecc/crazyw
|
||||
|
||||
## Open-Source License
|
||||
|
||||
This project is based on the tradition of using the MIT License for old versions,
|
||||
while the new version references source code from some other projects:
|
||||
This project itself is based on MIT License,
|
||||
some newly added extensions and dependencies may originate from the following projects (including but not limited to),
|
||||
and the headers of these code files will also be given additional instructions LICENSE and AUTHOR:
|
||||
|
||||
- [dixyes/lwmbs](https://github.com/dixyes/lwmbs) (Mulun Permissive License)
|
||||
- [swoole/swoole-cli](https://github.com/swoole/swoole-cli) (Apache 2.0 LICENSE+SWOOLE-CLI LICENSE)
|
||||
@@ -253,4 +242,4 @@ and comply with the corresponding project's LICENSE.
|
||||
|
||||
The refactoring branch of this project is written modularly.
|
||||
If you are interested in this project and want to join the development,
|
||||
you can refer to the [Contribution Guide](https://static-php-cli.zhamao.me) of the documentation to contribute code or documentation. (TODO)
|
||||
you can refer to the [Contribution Guide](https://static-php-cli.zhamao.me) of the documentation to contribute code or documentation.
|
||||
|
||||
18
README.md
18
README.md
@@ -1,6 +1,6 @@
|
||||
# static-php-cli
|
||||
|
||||
Compile A Statically Linked PHP With Swoole and other Extensions.
|
||||
Build single static PHP binary, with PHP project together, with popular extensions included.
|
||||
|
||||
**If you are using English, see [English README](README-en.md).**
|
||||
|
||||
@@ -19,7 +19,7 @@ Compile A Statically Linked PHP With Swoole and other Extensions.
|
||||
[]()
|
||||
[]()
|
||||
|
||||
> 项目已重命名 `refactor` 分支为 `main` 分支,请依赖的项目注意更改分支名称。
|
||||
> 项目名称是 static-php-cli,但其实支持 cli、fpm、micro 和 embed(正在路上)SAPI 😎
|
||||
|
||||
## 编译环境需求
|
||||
|
||||
@@ -181,18 +181,6 @@ cat micro.sfx code.php > single-app && chmod +x single-app
|
||||
|
||||
指定 `php-fpm.conf` 可以使用命令参数 `-y`,例如:`./php-fpm -y php-fpm.conf`。
|
||||
|
||||
## 项目支持情况
|
||||
|
||||
- [X] 基础结构编写(采用 `symfony/console`)
|
||||
- [X] 错误处理
|
||||
- [X] macOS 支持
|
||||
- [ ] Windows 支持
|
||||
- [X] Linux 支持
|
||||
- [X] PHP 7.4 支持
|
||||
- [X] fpm 支持
|
||||
|
||||
更多功能和特性正在陆续支持中,详见:https://github.com/crazywhalecc/static-php-cli/issues/32
|
||||
|
||||
## 贡献
|
||||
|
||||
目前支持的扩展较少,如果缺少你需要的扩展,可发起 Issue。如果你对本项目较熟悉,也欢迎为本项目发起 Pull Request。
|
||||
@@ -224,4 +212,4 @@ cat micro.sfx code.php > single-app && chmod +x single-app
|
||||
|
||||
## 进阶
|
||||
|
||||
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php-cli.zhamao.me) 贡献代码或文档。(TODO)
|
||||
本项目重构分支为模块化编写。如果你对本项目感兴趣,想加入开发,可以参照文档的 [贡献指南](https://static-php-cli.zhamao.me) 贡献代码或文档。
|
||||
|
||||
@@ -13,15 +13,16 @@
|
||||
"ext-mbstring": "*",
|
||||
"ext-pcntl": "*",
|
||||
"laravel/prompts": "^0.1.3",
|
||||
"symfony/console": "^6 || ^5 || ^4",
|
||||
"symfony/console": "^5.4 || ^6 || ^7",
|
||||
"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",
|
||||
"captainhook/plugin-composer": "^5.3"
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"friendsofphp/php-cs-fixer": "^3.25",
|
||||
"nunomaduro/collision": "^7.8",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^10.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -32,13 +33,18 @@
|
||||
"src/globals/functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"SPC\\Tests\\": "tests/SPC"
|
||||
}
|
||||
},
|
||||
"bin": [
|
||||
"bin/spc"
|
||||
],
|
||||
"scripts": {
|
||||
"analyse": "phpstan analyse --memory-limit 300M",
|
||||
"cs-fix": "php-cs-fixer fix",
|
||||
"test": "bin/phpunit --no-coverage"
|
||||
"test": "vendor/bin/phpunit tests/ --no-coverage"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
|
||||
@@ -325,6 +325,18 @@
|
||||
"libxml2"
|
||||
]
|
||||
},
|
||||
"snappy": {
|
||||
"type": "external",
|
||||
"source": "ext-snappy",
|
||||
"cpp-extension": true,
|
||||
"arg-type": "custom",
|
||||
"lib-depends": [
|
||||
"snappy"
|
||||
],
|
||||
"ext-suggest": [
|
||||
"apcu"
|
||||
]
|
||||
},
|
||||
"snmp": {
|
||||
"type": "builtin",
|
||||
"arg-type": "with",
|
||||
@@ -490,4 +502,4 @@
|
||||
"zstd"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +445,22 @@
|
||||
"ncurses"
|
||||
]
|
||||
},
|
||||
"snappy": {
|
||||
"source": "snappy",
|
||||
"static-libs-unix": [
|
||||
"libsnappy.a"
|
||||
],
|
||||
"headers-unix": [
|
||||
"snappy-c.h",
|
||||
"snappy-sinksource.h",
|
||||
"snappy.h",
|
||||
"snappy-stubs-internal.h",
|
||||
"snappy-stubs-public.h"
|
||||
],
|
||||
"lib-depends": [
|
||||
"zlib"
|
||||
]
|
||||
},
|
||||
"sqlite": {
|
||||
"source": "sqlite",
|
||||
"static-libs-unix": [
|
||||
@@ -511,4 +527,4 @@
|
||||
"zstd_errors.h"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,16 @@
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"ext-snappy": {
|
||||
"type": "git",
|
||||
"path": "php-src/ext/snappy",
|
||||
"rev": "master",
|
||||
"url": "https://github.com/kjdev/php-ext-snappy",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "LICENSE"
|
||||
}
|
||||
},
|
||||
"ext-ssh2": {
|
||||
"type": "url",
|
||||
"url": "https://pecl.php.net/get/ssh2",
|
||||
@@ -401,6 +411,16 @@
|
||||
"path": "COPYING"
|
||||
}
|
||||
},
|
||||
"snappy": {
|
||||
"type": "git",
|
||||
"repo": "google/snappy",
|
||||
"rev": "main",
|
||||
"url": "https://github.com/google/snappy",
|
||||
"license": {
|
||||
"type": "file",
|
||||
"path": "COPYING"
|
||||
}
|
||||
},
|
||||
"sqlite": {
|
||||
"type": "url",
|
||||
"url": "https://www.sqlite.org/2023/sqlite-autoconf-3410100.tar.gz",
|
||||
@@ -476,4 +496,4 @@
|
||||
"path": "LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use Symfony\Component\Console\Command\ListCommand;
|
||||
*/
|
||||
class ConsoleApplication extends Application
|
||||
{
|
||||
public const VERSION = '2.0.0';
|
||||
public const VERSION = '2.0-rc6';
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
|
||||
33
src/SPC/builder/extension/snappy.php
Normal file
33
src/SPC/builder/extension/snappy.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\extension;
|
||||
|
||||
use SPC\builder\Extension;
|
||||
use SPC\builder\macos\MacOSBuilder;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\CustomExt;
|
||||
|
||||
#[CustomExt('snappy')]
|
||||
class snappy extends Extension
|
||||
{
|
||||
/**
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
public function patchBeforeConfigure(): bool
|
||||
{
|
||||
FileSystem::replaceFileRegex(
|
||||
SOURCE_PATH . '/php-src/configure',
|
||||
'/-lsnappy/',
|
||||
$this->getLibFilesString() . ($this->builder instanceof MacOSBuilder ? ' -lc++' : ' -lstdc++')
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getUnixConfigureArg(): string
|
||||
{
|
||||
return '--enable-snappy --with-snappy-includedir="' . BUILD_ROOT_PATH . '"';
|
||||
}
|
||||
}
|
||||
12
src/SPC/builder/linux/library/snappy.php
Normal file
12
src/SPC/builder/linux/library/snappy.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
class snappy extends LinuxLibraryBase
|
||||
{
|
||||
use \SPC\builder\unix\library\snappy;
|
||||
|
||||
public const NAME = 'snappy';
|
||||
}
|
||||
12
src/SPC/builder/macos/library/snappy.php
Normal file
12
src/SPC/builder/macos/library/snappy.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\macos\library;
|
||||
|
||||
class snappy extends MacOSLibraryBase
|
||||
{
|
||||
use \SPC\builder\unix\library\snappy;
|
||||
|
||||
public const NAME = 'snappy';
|
||||
}
|
||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\traits;
|
||||
|
||||
trait LibraryTrait
|
||||
{
|
||||
}
|
||||
trait LibraryTrait {}
|
||||
|
||||
34
src/SPC/builder/unix/library/snappy.php
Normal file
34
src/SPC/builder/unix/library/snappy.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\unix\library;
|
||||
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\store\FileSystem;
|
||||
|
||||
trait snappy
|
||||
{
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
protected function build(): void
|
||||
{
|
||||
FileSystem::resetDir($this->source_dir . '/cmake/build');
|
||||
|
||||
shell()->cd($this->source_dir . '/cmake/build')
|
||||
->exec(
|
||||
"{$this->builder->configure_env} cmake " .
|
||||
"-DCMAKE_TOOLCHAIN_FILE={$this->builder->cmake_toolchain_file} " .
|
||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||
'-DCMAKE_INSTALL_PREFIX=' . escapeshellarg(BUILD_ROOT_PATH) . ' ' .
|
||||
'-DSNAPPY_BUILD_TESTS=OFF ' .
|
||||
'-DSNAPPY_BUILD_BENCHMARKS=OFF ' .
|
||||
'../..'
|
||||
)
|
||||
->exec("cmake --build . -j {$this->builder->concurrency}")
|
||||
->exec('make install');
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,19 @@ namespace SPC\command\dev;
|
||||
|
||||
use SPC\command\BaseCommand;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\store\Config;
|
||||
use SPC\util\DependencyUtil;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand('dev:ext-all', 'Dev command', ['list-ext'])]
|
||||
#[AsCommand('dev:extensions', 'Helper command that lists available extension details', ['list-ext'])]
|
||||
class AllExtCommand extends BaseCommand
|
||||
{
|
||||
public function configure(): void
|
||||
{
|
||||
$this->addOption('line', 'l', null, 'Show with separate lines');
|
||||
$this->addArgument('extensions', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Extension name', null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,7 +26,45 @@ class AllExtCommand extends BaseCommand
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$this->output->writeln(implode($this->input->getOption('line') ? PHP_EOL : ',', array_keys(Config::getExts())));
|
||||
$extensions = $this->input->getArgument('extensions') ?: [];
|
||||
|
||||
$style = new SymfonyStyle($this->input, $this->output);
|
||||
$style->writeln($extensions ? 'Available extensions:' : 'Extensions:');
|
||||
|
||||
$data = [];
|
||||
foreach (Config::getExts() as $extension => $details) {
|
||||
if ($extensions !== [] && !\in_array($extension, $extensions, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]);
|
||||
} catch (WrongUsageException) {
|
||||
$libraries = $not_included = [];
|
||||
}
|
||||
|
||||
$lib_suggests = Config::getExt($extension, 'lib-suggests', []);
|
||||
$ext_suggests = Config::getExt($extension, 'ext-suggests', []);
|
||||
|
||||
$data[] = [
|
||||
$extension,
|
||||
implode(', ', $libraries),
|
||||
implode(', ', $lib_suggests),
|
||||
implode(',', $not_included),
|
||||
implode(', ', $ext_suggests),
|
||||
Config::getExt($extension, 'unix-only', false) ? 'true' : 'false',
|
||||
];
|
||||
}
|
||||
|
||||
if ($data === []) {
|
||||
$style->warning('Unknown extension selected: ' . implode(',', $extensions));
|
||||
} else {
|
||||
$style->table(
|
||||
['Extension', 'lib-depends', 'lib-suggests', 'ext-depends', 'ext-suggests', 'unix-only'],
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command\dev;
|
||||
|
||||
use SPC\command\BaseCommand;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\store\Config;
|
||||
use SPC\util\DependencyUtil;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
#[AsCommand('dev:ext-info', 'Dev command')]
|
||||
class ExtInfoCommand extends BaseCommand
|
||||
{
|
||||
public function configure(): void
|
||||
{
|
||||
$this->addArgument('extensions', InputArgument::REQUIRED, 'The extension name you need to get info');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WrongUsageException
|
||||
* @throws FileSystemException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$extensions = array_map('trim', array_filter(explode(',', $this->getArgument('extensions'))));
|
||||
|
||||
// 根据提供的扩展列表获取依赖库列表并编译
|
||||
foreach ($extensions as $extension) {
|
||||
$this->output->writeln('<comment>[ ' . $extension . ' ]</comment>');
|
||||
[, $libraries, $not_included] = DependencyUtil::getExtLibsByDeps([$extension]);
|
||||
$lib_suggests = Config::getExt($extension, 'lib-suggests', []);
|
||||
$ext_suggests = Config::getExt($extension, 'ext-suggests', []);
|
||||
$this->output->writeln("<info>lib-depends:\t" . implode(', ', $libraries) . '</info>');
|
||||
$this->output->writeln("<info>lib-suggests:\t" . implode(', ', $lib_suggests) . '</info>');
|
||||
$this->output->writeln("<info>ext-depends:\t" . implode(',', $not_included) . '</info>');
|
||||
$this->output->writeln("<info>ext-suggests:\t" . implode(', ', $ext_suggests) . '</info>');
|
||||
if (Config::getExt($extension, 'unix-only', false)) {
|
||||
$this->output->writeln("<info>Unix only:\ttrue</info>");
|
||||
}
|
||||
$this->output->writeln('');
|
||||
}
|
||||
return static::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,5 @@ class AsCheckItem
|
||||
public ?string $limit_os = null,
|
||||
public int $level = 100,
|
||||
public bool $manual = false,
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,5 @@ namespace SPC\doctor;
|
||||
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
class AsFixItem
|
||||
{
|
||||
public function __construct(public string $name)
|
||||
{
|
||||
}
|
||||
public function __construct(public string $name) {}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ namespace SPC\doctor;
|
||||
|
||||
class CheckResult
|
||||
{
|
||||
public function __construct(private readonly bool $ok, private readonly ?string $message = null, private string $fix_item = '', private array $fix_params = [])
|
||||
{
|
||||
}
|
||||
public function __construct(private readonly bool $ok, private readonly ?string $message = null, private string $fix_item = '', private array $fix_params = []) {}
|
||||
|
||||
public static function fail(string $message, string $fix_item = '', array $fix_params = []): CheckResult
|
||||
{
|
||||
|
||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\exception;
|
||||
|
||||
class DownloaderException extends \Exception
|
||||
{
|
||||
}
|
||||
class DownloaderException extends \Exception {}
|
||||
|
||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\exception;
|
||||
|
||||
class FileSystemException extends \Exception
|
||||
{
|
||||
}
|
||||
class FileSystemException extends \Exception {}
|
||||
|
||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\exception;
|
||||
|
||||
class InvalidArgumentException extends \Exception
|
||||
{
|
||||
}
|
||||
class InvalidArgumentException extends \Exception {}
|
||||
|
||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\exception;
|
||||
|
||||
class RuntimeException extends \Exception
|
||||
{
|
||||
}
|
||||
class RuntimeException extends \Exception {}
|
||||
|
||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\exception;
|
||||
|
||||
class ValidationException extends \Exception
|
||||
{
|
||||
}
|
||||
class ValidationException extends \Exception {}
|
||||
|
||||
@@ -4,6 +4,4 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\exception;
|
||||
|
||||
class WrongUsageException extends \Exception
|
||||
{
|
||||
}
|
||||
class WrongUsageException extends \Exception {}
|
||||
|
||||
@@ -13,9 +13,7 @@ class CustomExt
|
||||
{
|
||||
private static array $custom_ext_class = [];
|
||||
|
||||
public function __construct(protected string $ext_name)
|
||||
{
|
||||
}
|
||||
public function __construct(protected string $ext_name) {}
|
||||
|
||||
/**
|
||||
* Load all custom extension classes
|
||||
|
||||
@@ -45,46 +45,58 @@ class LicenseDumper
|
||||
{
|
||||
// mkdir first
|
||||
if (is_dir($target_dir) && !FileSystem::removeDir($target_dir)) {
|
||||
logger()->warning('Target dump directory is noe empty, be aware!');
|
||||
logger()->warning('Target dump directory is not empty, be aware!');
|
||||
}
|
||||
FileSystem::createDir($target_dir);
|
||||
foreach ($this->exts as $ext) {
|
||||
if (Config::getExt($ext, 'type') !== 'external') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$source_name = Config::getExt($ext, 'source');
|
||||
$content = $this->getSourceLicense($source_name);
|
||||
file_put_contents($target_dir . '/ext_' . $ext . '.txt', $content);
|
||||
foreach ($this->getSourceLicenses($source_name) as $index => $license) {
|
||||
file_put_contents("{$target_dir}/ext_{$ext}_{$index}.txt", $license);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->libs as $lib) {
|
||||
$source_name = Config::getLib($lib, 'source');
|
||||
$content = $this->getSourceLicense($source_name);
|
||||
file_put_contents($target_dir . '/lib_' . $lib . '.txt', $content);
|
||||
foreach ($this->getSourceLicenses($source_name) as $index => $license) {
|
||||
file_put_contents("{$target_dir}/lib_{$lib}_{$index}.txt", $license);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->sources as $source) {
|
||||
file_put_contents($target_dir . '/src_' . $source . '.txt', $this->getSourceLicense($source));
|
||||
foreach ($this->getSourceLicenses($source) as $index => $license) {
|
||||
file_put_contents("{$target_dir}/src_{$source}_{$index}.txt", $license);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @throws FileSystemException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function getSourceLicense(string $source_name): ?string
|
||||
private function getSourceLicenses(string $source_name): iterable
|
||||
{
|
||||
$src = Config::getSource($source_name)['license'] ?? null;
|
||||
if ($src === null) {
|
||||
throw new RuntimeException('source [' . $source_name . '] license meta is not exist');
|
||||
$licenses = Config::getSource($source_name)['license'] ?? [];
|
||||
if ($licenses === []) {
|
||||
throw new RuntimeException('source [' . $source_name . '] license meta not exist');
|
||||
}
|
||||
|
||||
return match ($src['type']) {
|
||||
'text' => $src['text'],
|
||||
'file' => $this->loadSourceFile($source_name, $src['path'], Config::getSource($source_name)['path'] ?? null),
|
||||
default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'),
|
||||
};
|
||||
if (!array_is_list($licenses)) {
|
||||
$licenses = [$licenses];
|
||||
}
|
||||
|
||||
foreach ($licenses as $index => $license) {
|
||||
yield ($license['suffix'] ?? $index) => match ($license['type']) {
|
||||
'text' => $license['text'],
|
||||
'file' => $this->loadSourceFile($source_name, $license['path'], Config::getSource($source_name)['path'] ?? null),
|
||||
default => throw new RuntimeException('source [' . $source_name . '] license type is not allowed'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,8 +105,9 @@ class LicenseDumper
|
||||
private function loadSourceFile(string $source_name, string $in_path, ?string $custom_base_path = null): string
|
||||
{
|
||||
if (!file_exists(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path)) {
|
||||
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] is not exist');
|
||||
throw new RuntimeException('source [' . $source_name . '] license file [' . $in_path . '] not exist');
|
||||
}
|
||||
|
||||
return file_get_contents(SOURCE_PATH . '/' . ($custom_base_path ?? $source_name) . '/' . $in_path);
|
||||
}
|
||||
}
|
||||
|
||||
87
tests/SPC/util/LicenseDumperTest.php
Normal file
87
tests/SPC/util/LicenseDumperTest.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\Tests\util;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use SPC\store\Config;
|
||||
use SPC\util\LicenseDumper;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class LicenseDumperTest extends TestCase
|
||||
{
|
||||
private const DIRECTORY = '../../var/license-dump';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
@rmdir(self::DIRECTORY);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
array_map('unlink', glob(self::DIRECTORY . '/*.txt'));
|
||||
}
|
||||
|
||||
public function testDumpWithSingleLicense(): void
|
||||
{
|
||||
Config::$lib = [
|
||||
'fake_lib' => [
|
||||
'source' => 'fake_lib',
|
||||
],
|
||||
];
|
||||
Config::$source = [
|
||||
'fake_lib' => [
|
||||
'license' => [
|
||||
'type' => 'text',
|
||||
'text' => 'license',
|
||||
'suffix' => 'zend',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$dumper = new LicenseDumper();
|
||||
$dumper->addLibs(['fake_lib']);
|
||||
$dumper->dump(self::DIRECTORY);
|
||||
|
||||
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt');
|
||||
}
|
||||
|
||||
public function testDumpWithMultipleLicenses(): void
|
||||
{
|
||||
Config::$lib = [
|
||||
'fake_lib' => [
|
||||
'source' => 'fake_lib',
|
||||
],
|
||||
];
|
||||
Config::$source = [
|
||||
'fake_lib' => [
|
||||
'license' => [
|
||||
[
|
||||
'type' => 'text',
|
||||
'text' => 'license',
|
||||
],
|
||||
[
|
||||
'type' => 'text',
|
||||
'text' => 'license',
|
||||
],
|
||||
[
|
||||
'type' => 'text',
|
||||
'text' => 'license',
|
||||
'suffix' => 'zend',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$dumper = new LicenseDumper();
|
||||
$dumper->addLibs(['fake_lib']);
|
||||
$dumper->dump(self::DIRECTORY);
|
||||
|
||||
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_0.txt');
|
||||
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_1.txt');
|
||||
$this->assertFileExists(self::DIRECTORY . '/lib_fake_lib_zend.txt');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user