mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-08 17:35:36 +08:00
Compare commits
22 Commits
4872ff58bb
...
2.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97eff64b5b | ||
|
|
e522258693 | ||
|
|
b84c68fe11 | ||
|
|
8505feaa66 | ||
|
|
41f49c20ff | ||
|
|
1912ae36e6 | ||
|
|
08efc81cf0 | ||
|
|
a3b09c69cc | ||
|
|
5cf105c3a5 | ||
|
|
7408781d13 | ||
|
|
0afc8ea2c3 | ||
|
|
67b073776c | ||
|
|
8b48cf7f70 | ||
|
|
63287dd9c4 | ||
|
|
fc7ac921e2 | ||
|
|
57e3193a2a | ||
|
|
388f547878 | ||
|
|
f2e483540b | ||
|
|
7d31c371e0 | ||
|
|
bc750733d5 | ||
|
|
a66e22d9ed | ||
|
|
cc5974d07d |
40
.github/workflows/download-cache.yml
vendored
Normal file
40
.github/workflows/download-cache.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: archive download sources weekly
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "* 14 * * 5"
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
download:
|
||||
name: cache download sources
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
php-version: [ "8.0", "8.1", "8.2" ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# Cache composer dependencies
|
||||
- id: cache-composer-deps
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: vendor
|
||||
key: composer-dependencies
|
||||
|
||||
# If there's no Composer cache, install dependencies
|
||||
- if: steps.cache-composer-deps.outputs.cache-hit != 'true'
|
||||
run: composer update --no-dev
|
||||
|
||||
# If there's no dependencies cache, fetch sources, with or without debug
|
||||
- if: steps.cache-download.outputs.cache-hit != 'true'
|
||||
run: ./bin/spc download --with-php=${{ matrix.php-version }} --all --debug
|
||||
|
||||
# Upload downloaded files
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: download-files-${{ matrix.php-version }}
|
||||
path: downloads/
|
||||
12
README-en.md
12
README-en.md
@@ -37,7 +37,11 @@ Here is the architecture support status, where `CI` represents support for GitHu
|
||||
|
||||
Currently supported PHP versions for compilation are: `7.4`, `8.0`, `8.1`, `8.2`.
|
||||
|
||||
## Usage
|
||||
## Docs
|
||||
|
||||
docs here: <https://static-php-cli.zhamao.me>.
|
||||
|
||||
## Simple Usage
|
||||
|
||||
Please first select the extension you want to compile based on the extension list below.
|
||||
|
||||
@@ -49,7 +53,7 @@ If you don't compile yourself, you can download pre-compiled artifact from Actio
|
||||
|
||||
### Supported Extensions
|
||||
|
||||
[Supported Extension List](/ext-support.md)
|
||||
[Supported Extension List](https://static-php-cli.zhamao.me/en/guide/extensions.html)
|
||||
|
||||
> If there is no extension you need here, you can submit an issue.
|
||||
|
||||
@@ -100,7 +104,7 @@ Basic usage for building php and micro with some extensions:
|
||||
cd static-php-cli
|
||||
composer update
|
||||
chmod +x bin/spc
|
||||
# Check system tool dependencies, fix them automatically (only support macOS) (TODO: Linux distro support)
|
||||
# Check system tool dependencies, fix them automatically
|
||||
./bin/spc doctor
|
||||
# fetch all libraries
|
||||
./bin/spc fetch --all
|
||||
@@ -217,6 +221,8 @@ The basic principles for contributing are as follows:
|
||||
camelCase and underscore formats should be followed, and mixing within the same module is prohibited.
|
||||
- When compiling external libraries and creating patches, compatibility with different operating systems should be considered.
|
||||
|
||||
If you want to contribute document content, please go to [crazywhalecc/static-php-cli-docs](https://github.com/crazywhalecc/static-php-cli-docs).
|
||||
|
||||
## Sponsor this project
|
||||
|
||||
You can sponsor my project on [this page](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md).
|
||||
|
||||
10
README.md
10
README.md
@@ -36,6 +36,10 @@ If you are using English, see [English README](README-en.md).
|
||||
|
||||
目前支持编译的 PHP 版本为:`7.4`,`8.0`,`8.1`,`8.2`。
|
||||
|
||||
## 文档
|
||||
|
||||
点击这里查看文档:<https://static-php-cli.zhamao.me>。
|
||||
|
||||
## 使用
|
||||
|
||||
请先根据下方扩展列表选择你要编译的扩展。
|
||||
@@ -48,7 +52,7 @@ If you are using English, see [English README](README-en.md).
|
||||
|
||||
### 支持的扩展情况
|
||||
|
||||
[扩展支持列表](/ext-support.md)
|
||||
[扩展支持列表](https://static-php-cli.zhamao.me/zh/guide/extensions.html)
|
||||
|
||||
> 如果这里没有你需要的扩展,可以提交 Issue。
|
||||
|
||||
@@ -94,7 +98,7 @@ chmod +x bin/setup-runtime
|
||||
cd static-php-cli
|
||||
composer update
|
||||
chmod +x bin/spc
|
||||
# 检查环境依赖,并根据提示的命令安装缺失的编译工具(目前仅支持 macOS,Linux 后续会支持)
|
||||
# 检查环境依赖,并根据提示的命令安装缺失的编译工具
|
||||
./bin/spc doctor
|
||||
# 拉取所有依赖库
|
||||
./bin/spc fetch --all
|
||||
@@ -200,6 +204,8 @@ cat micro.sfx code.php > single-app && chmod +x single-app
|
||||
|
||||
另外,添加新扩展的贡献方式,可以参考下方 `进阶`。
|
||||
|
||||
如果你想贡献文档内容,请到项目仓库 [crazywhalecc/static-php-cli-docs](https://github.com/crazywhalecc/static-php-cli-docs) 贡献。
|
||||
|
||||
## 赞助本项目
|
||||
|
||||
你可以在 [我的个人赞助页](https://github.com/crazywhalecc/crazywhalecc/blob/master/FUNDING.md) 支持我和我的项目。
|
||||
|
||||
@@ -91,9 +91,8 @@
|
||||
}
|
||||
},
|
||||
"gmp": {
|
||||
"type": "filelist",
|
||||
"url": "https://gmplib.org/download/gmp/",
|
||||
"regex": "/href=\"(?<file>gmp-(?<version>[^\"]+)\\.tar\\.xz)\"/",
|
||||
"type": "ghtagtar",
|
||||
"repo": "alisw/GMP",
|
||||
"license": {
|
||||
"type": "text",
|
||||
"text": "Since version 6, GMP is distributed under the dual licenses, GNU LGPL v3 and GNU GPL v2. These licenses make the library free to use, share, and improve, and allow you to pass on the result. The GNU licenses give freedoms, but also set firm restrictions on the use with non-free programs."
|
||||
|
||||
110
ext-support.md
110
ext-support.md
@@ -1,111 +1,3 @@
|
||||
# Extension List
|
||||
|
||||
> - yes: supported and tested
|
||||
> - untested: supported, but not tested
|
||||
> - empty: not supported yet
|
||||
> - no with issue link: not supported yet due to issue
|
||||
> - partial with issue link: supported but not perfect due to issue
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
|-----------------|---------------------------------------------------------------------|----------------------------------------------------------------|---------|
|
||||
| apcu | yes, untested | yes, untested | |
|
||||
| bcmath | yes | yes | |
|
||||
| bz2 | yes | yes | |
|
||||
| calendar | yes | yes | |
|
||||
| ctype | yes | yes | |
|
||||
| curl | yes | yes | |
|
||||
| dba | yes | yes | |
|
||||
| dom | yes | yes | |
|
||||
| enchant | | | |
|
||||
| event | yes | yes | |
|
||||
| exif | yes | yes | |
|
||||
| ffi | | yes, [docs]() | |
|
||||
| filter | yes | yes | |
|
||||
| fileinfo | yes | yes | |
|
||||
| ftp | yes | yes | |
|
||||
| gd | yes | yes | |
|
||||
| gettext | | | |
|
||||
| gmp | yes | yes | |
|
||||
| iconv | yes | yes | |
|
||||
| imagick | yes | yes | |
|
||||
| inotify | yes | yes | |
|
||||
| intl | [partial](https://github.com/crazywhalecc/static-php-cli/issues/66) | yes | |
|
||||
| mbstring | yes | yes | |
|
||||
| mbregex | yes | yes | |
|
||||
| mcrypt | | [no](https://github.com/crazywhalecc/static-php-cli/issues/32) | |
|
||||
| mongodb | yes | yes | |
|
||||
| mysqli | yes | yes | |
|
||||
| mysqlnd | yes | yes | |
|
||||
| openssl | yes | yes | |
|
||||
| password-argon2 | | | |
|
||||
| pcntl | yes | yes | |
|
||||
| pdo | yes | yes | |
|
||||
| pdo_mysql | yes | yes | |
|
||||
| pdo_sqlite | yes | yes | |
|
||||
| pdo_pgsql | | | |
|
||||
| phar | yes | yes | |
|
||||
| posix | yes | yes | |
|
||||
| protobuf | yes | yes | |
|
||||
| readline | yes, untested | yes, untested | |
|
||||
| redis | yes | yes | |
|
||||
| session | yes | yes | |
|
||||
| shmop | yes | yes | |
|
||||
| simplexml | yes | yes | |
|
||||
| soap | yes | yes | |
|
||||
| sockets | yes | yes | |
|
||||
| sodium | yes | yes | |
|
||||
| sqlite3 | yes | yes | |
|
||||
| ssh2 | yes, untested | yes, untested | |
|
||||
| swow | yes | yes | |
|
||||
| swoole | [partial](https://github.com/crazywhalecc/static-php-cli/issues/51) | yes | |
|
||||
| tokenizer | yes | yes | |
|
||||
| xlswriter | yes | yes | |
|
||||
| xml | yes | yes | |
|
||||
| xmlreader | yes, untested | yes, untested | |
|
||||
| xmlwriter | yes, untested | yes, untested | |
|
||||
| zip | yes, untested | yes, untested | |
|
||||
| zlib | yes | yes | |
|
||||
| zstd | yes | yes | |
|
||||
|
||||
## Additional Requirements
|
||||
|
||||
- phpmicro requires PHP >= 8.0
|
||||
- swoole >= 5.0 requires PHP >= 8.0
|
||||
- swow requires PHP >= 8.0
|
||||
|
||||
## Typical Extension List Example
|
||||
|
||||
Here are some extension list example for different use.
|
||||
|
||||
- For general use: `"bcmath,bz2,calendar,ctype,curl,dom,exif,fileinfo,ftp,filter,gd,iconv,xml,mbstring,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,redis,simplexml,soap,sockets,sqlite3,tokenizer,xmlwriter,xmlreader,zlib,zip"`
|
||||
- For static-php-cli self: `"posix,pcntl,phar,tokenizer,iconv,zlib"`
|
||||
- For static-php-cli self (with dev dependencies): `"posix,pcntl,phar,tokenizer,iconv,zlib,xml,dom,xmlwriter,xmlreader,fileinfo"`
|
||||
- Minimum, with no extension: `""`
|
||||
|
||||
Compile with all supported extensions (exclude `swow`, `swoole`, because these will change the default behavior of php):
|
||||
|
||||
```bash
|
||||
bin/spc build --build-all bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,iconv,mbregex,mbstring,mongodb,mysqli,mysqlnd,openssl,pcntl,pdo,pdo_mysql,pdo_sqlite,phar,posix,protobuf,redis,session,shmop,simplexml,soap,sockets,sqlite3,tokenizer,xml,xmlreader,xmlwriter,yaml,zip,zlib,zstd --with-libs=libjpeg,freetype,libwebp,libavif --debug
|
||||
```
|
||||
|
||||
## Additional Libraries
|
||||
|
||||
Some extensions have soft dependencies, you can enable extra features by adding these libs using `--with-libs`.
|
||||
|
||||
For example, to compile with gd extension, with `libwebp, libgif, libavif, libjpeg, freetype` extra features:
|
||||
|
||||
```bash
|
||||
bin/spc build gd --with-libs=libjpeg,freetype,libwebp,libavif --build-cli
|
||||
```
|
||||
|
||||
> If you don't add them, your compilation will not enable these features.
|
||||
|
||||
## Limitations
|
||||
|
||||
- swow and swoole cannot be compiled at the same time.
|
||||
- openssl needs manual configuration for ssl certificate. (TODO: I will write a wiki about it)
|
||||
- some extensions need system configuration, e.g. `curl` and `openssl` will search ssl certificate on your system.
|
||||
|
||||
## Bugs and TODOs
|
||||
|
||||
See [#32](https://github.com/crazywhalecc/static-php-cli/issues/32).
|
||||
See: [Docs - Extensions](https://static-php-cli.zhamao.me/en/guide/extensions.html)
|
||||
|
||||
@@ -21,7 +21,7 @@ class LinuxBuilder extends BuilderBase
|
||||
use UnixBuilderTrait;
|
||||
|
||||
/** @var string[] Linux 环境下编译依赖的命令 */
|
||||
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'pkg-config', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
|
||||
public const REQUIRED_COMMANDS = ['make', 'bison', 'flex', 'git', 'autoconf', 'automake', 'tar', 'unzip', /* 'xz', 好像不需要 */ 'gzip', 'bzip2', 'cmake'];
|
||||
|
||||
/** @var string 使用的 libc */
|
||||
public string $libc;
|
||||
|
||||
@@ -40,6 +40,7 @@ class libpng extends MacOSLibraryBase
|
||||
};
|
||||
shell()->cd($this->source_dir)
|
||||
->exec('chmod +x ./configure')
|
||||
->exec('chmod +x ./install-sh')
|
||||
->exec(
|
||||
"{$this->builder->configure_env} ./configure " .
|
||||
"--host={$this->builder->gnu_arch}-apple-darwin " .
|
||||
|
||||
@@ -10,11 +10,16 @@ use Symfony\Component\Console\Attribute\AsCommand;
|
||||
#[AsCommand('doctor', 'Diagnose whether the current environment can compile normally')]
|
||||
class DoctorCommand extends BaseCommand
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->addOption('auto-fix', null, null, 'Automatically fix failed items (if possible)');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
try {
|
||||
$checker = new CheckListHandler($this->input, $this->output);
|
||||
$checker->runCheck(FIX_POLICY_PROMPT);
|
||||
$checker->runCheck($this->input->getOption('auto-fix') ? FIX_POLICY_AUTOFIX : FIX_POLICY_PROMPT);
|
||||
$this->output->writeln('<info>Doctor check complete !</info>');
|
||||
} catch (\Throwable $e) {
|
||||
$this->output->writeln('<error>' . $e->getMessage() . '</error>');
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||
use SPC\exception\DownloaderException;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
@@ -18,6 +19,8 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
#[AsCommand('download', 'Download required sources', ['fetch'])]
|
||||
class DownloadCommand extends BaseCommand
|
||||
{
|
||||
use UnixSystemUtilTrait;
|
||||
|
||||
protected string $php_major_ver;
|
||||
|
||||
public function configure()
|
||||
@@ -28,12 +31,13 @@ class DownloadCommand extends BaseCommand
|
||||
$this->addOption('with-php', null, InputOption::VALUE_REQUIRED, 'version in major.minor format like 8.1', '8.1');
|
||||
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
|
||||
$this->addOption('all', 'A', null, 'Fetch all sources that static-php-cli needed');
|
||||
$this->addOption('from-zip', 'Z', InputOption::VALUE_REQUIRED, 'Fetch from zip archive');
|
||||
}
|
||||
|
||||
public function initialize(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// --all 等于 "" "",也就是所有东西都要下载
|
||||
if ($input->getOption('all') || $input->getOption('clean')) {
|
||||
if ($input->getOption('all') || $input->getOption('clean') || $input->getOption('from-zip')) {
|
||||
$input->setArgument('sources', '');
|
||||
}
|
||||
parent::initialize($input, $output);
|
||||
@@ -66,6 +70,44 @@ class DownloadCommand extends BaseCommand
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --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;
|
||||
}
|
||||
// remove old download files first
|
||||
if (is_dir(DOWNLOAD_PATH)) {
|
||||
logger()->warning('You are doing some operations that not recoverable: removing directories below');
|
||||
logger()->warning(DOWNLOAD_PATH);
|
||||
logger()->alert('I will remove these dir after 5 seconds !');
|
||||
sleep(5);
|
||||
f_passthru((PHP_OS_FAMILY === 'Windows' ? 'rmdir /s /q ' : 'rm -rf ') . DOWNLOAD_PATH);
|
||||
}
|
||||
// unzip command check
|
||||
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;
|
||||
}
|
||||
// create downloads
|
||||
try {
|
||||
if (PHP_OS_FAMILY !== 'Windows') {
|
||||
f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($path));
|
||||
}
|
||||
// Windows TODO
|
||||
|
||||
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
||||
throw new RuntimeException('.lock.json not exist in "downloads/"');
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
logger()->critical('Extract failed: ' . $e->getMessage());
|
||||
return 1;
|
||||
}
|
||||
logger()->info('Extract success');
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Define PHP major version
|
||||
$ver = $this->php_major_ver = $this->getOption('with-php') ?? '8.1';
|
||||
define('SPC_BUILD_PHP_VERSION', $ver);
|
||||
|
||||
116
src/SPC/command/MicroCombineCommand.php
Normal file
116
src/SPC/command/MicroCombineCommand.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command;
|
||||
|
||||
use SPC\store\FileSystem;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
#[AsCommand('micro:combine', 'Combine micro.sfx and php code together')]
|
||||
class MicroCombineCommand extends BaseCommand
|
||||
{
|
||||
public function configure()
|
||||
{
|
||||
$this->addArgument('file', InputArgument::REQUIRED, 'The php or phar file to be combined');
|
||||
$this->addOption('with-micro', 'M', InputOption::VALUE_REQUIRED, 'Customize your micro.sfx file');
|
||||
$this->addOption('with-ini-set', 'I', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'ini to inject into micro.sfx when combining');
|
||||
$this->addOption('with-ini-file', 'N', InputOption::VALUE_REQUIRED, 'ini file to inject into micro.sfx when combining');
|
||||
$this->addOption('output', 'O', InputOption::VALUE_REQUIRED, 'Customize your output binary file name');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
// 0. Initialize path variables
|
||||
$internal = FileSystem::convertPath(BUILD_ROOT_PATH . '/bin/micro.sfx');
|
||||
$micro_file = $this->input->getOption('with-micro');
|
||||
$file = $this->getArgument('file');
|
||||
$ini_set = $this->input->getOption('with-ini-set');
|
||||
$ini_file = $this->input->getOption('with-ini-file');
|
||||
$target_ini = [];
|
||||
$output = $this->input->getOption('output') ?? 'my-app';
|
||||
$ini_part = '';
|
||||
// 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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
// 3. Use buildroot/bin/micro.sfx
|
||||
if ($micro_file === null) {
|
||||
$micro_file = $internal;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
$arr = parse_ini_file($ini_file);
|
||||
if ($arr === false) {
|
||||
$this->output->writeln('<error>Cannot parse ini file</error>');
|
||||
return 1;
|
||||
}
|
||||
$target_ini = array_merge($target_ini, $arr);
|
||||
}
|
||||
// 6. Confirm ini sets
|
||||
if ($ini_set !== []) {
|
||||
foreach ($ini_set as $item) {
|
||||
$arr = parse_ini_string($item);
|
||||
if ($arr === false) {
|
||||
$this->output->writeln('<error>--with-ini-set parse failed</error>');
|
||||
return 1;
|
||||
}
|
||||
$target_ini = array_merge($target_ini, $arr);
|
||||
}
|
||||
}
|
||||
// 7. Generate ini injection parts
|
||||
if (!empty($target_ini)) {
|
||||
$ini_str = $this->encodeINI($target_ini);
|
||||
logger()->debug('Injecting ini parts: ' . PHP_EOL . $ini_str);
|
||||
$ini_part = "\xfd\xf6\x69\xe6";
|
||||
$ini_part .= pack('N', strlen($ini_str));
|
||||
$ini_part .= $ini_str;
|
||||
}
|
||||
// 8. Combine !
|
||||
$output = FileSystem::isRelativePath($output) ? (WORKING_DIR . '/' . $output) : $output;
|
||||
$file_target = file_get_contents($micro_file) . $ini_part . file_get_contents($file);
|
||||
$result = file_put_contents($output, $file_target);
|
||||
if ($result === false) {
|
||||
$this->output->writeln('<error>Combine failed.</error>');
|
||||
return 1;
|
||||
}
|
||||
// 9. chmod +x
|
||||
chmod($output, 0755);
|
||||
$this->output->writeln('<info>Combine success! Binary file: ' . $output . '</info>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function encodeINI(array $array): string
|
||||
{
|
||||
$res = [];
|
||||
foreach ($array as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$res[] = "[{$key}]";
|
||||
foreach ($val as $skey => $sval) {
|
||||
$res[] = "{$skey}=" . (is_numeric($sval) ? $sval : '"' . $sval . '"');
|
||||
}
|
||||
} else {
|
||||
$res[] = "{$key}=" . (is_numeric($val) ? $val : '"' . $val . '"');
|
||||
}
|
||||
}
|
||||
return implode("\n", $res);
|
||||
}
|
||||
}
|
||||
90
src/SPC/doctor/item/LinuxToolCheckList.php
Normal file
90
src/SPC/doctor/item/LinuxToolCheckList.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\doctor\item;
|
||||
|
||||
use SPC\builder\linux\SystemUtil;
|
||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||
use SPC\doctor\AsCheckItem;
|
||||
use SPC\doctor\AsFixItem;
|
||||
use SPC\doctor\CheckResult;
|
||||
use SPC\exception\RuntimeException;
|
||||
|
||||
class LinuxToolCheckList
|
||||
{
|
||||
use UnixSystemUtilTrait;
|
||||
|
||||
public const TOOLS_ALPINE = [
|
||||
'make', 'bison', 'flex',
|
||||
'git', 'autoconf', 'automake',
|
||||
'tar', 'unzip', 'gzip',
|
||||
'bzip2', 'cmake', 'gcc',
|
||||
'g++', 'patch',
|
||||
];
|
||||
|
||||
public const TOOLS_DEBIAN = [
|
||||
'make', 'bison', 'flex',
|
||||
'git', 'autoconf', 'automake',
|
||||
'tar', 'unzip', 'gzip',
|
||||
'bzip2', 'cmake', 'patch',
|
||||
];
|
||||
|
||||
#[AsCheckItem('if necessary tools are installed', limit_os: 'Linux')]
|
||||
public function checkCliTools(): ?CheckResult
|
||||
{
|
||||
$distro = SystemUtil::getOSRelease();
|
||||
|
||||
$required = match ($distro['dist']) {
|
||||
'alpine' => self::TOOLS_ALPINE,
|
||||
default => self::TOOLS_DEBIAN,
|
||||
};
|
||||
$missing = [];
|
||||
foreach ($required as $cmd) {
|
||||
if ($this->findCommand($cmd) === null) {
|
||||
$missing[] = $cmd;
|
||||
}
|
||||
}
|
||||
if (!empty($missing)) {
|
||||
return match ($distro['dist']) {
|
||||
'ubuntu', 'alpine', 'debian' => CheckResult::fail(implode(', ', $missing) . ' not installed on your system', 'install-linux-tools', [$distro, $missing]),
|
||||
default => CheckResult::fail(implode(', ', $missing) . ' not installed on your system'),
|
||||
};
|
||||
}
|
||||
return CheckResult::ok();
|
||||
}
|
||||
|
||||
#[AsCheckItem('if necessary packages are installed', limit_os: 'Linux')]
|
||||
public function checkSystemOSPackages(): ?CheckResult
|
||||
{
|
||||
$distro = SystemUtil::getOSRelease();
|
||||
if ($distro['dist'] === 'alpine') {
|
||||
// check linux-headers installation
|
||||
if (!file_exists('/usr/include/linux/mman.h')) {
|
||||
return CheckResult::fail('linux-headers not installed on your system', 'install-linux-tools', [$distro, ['linux-headers']]);
|
||||
}
|
||||
}
|
||||
return CheckResult::ok();
|
||||
}
|
||||
|
||||
#[AsFixItem('install-linux-tools')]
|
||||
public function fixBuildTools(array $distro, array $missing): bool
|
||||
{
|
||||
$install_cmd = match ($distro['dist']) {
|
||||
'ubuntu', 'debian' => 'apt install -y',
|
||||
'alpine' => 'apk add',
|
||||
default => throw new RuntimeException('Current linux distro is not supported for auto-install musl packages'),
|
||||
};
|
||||
$prefix = '';
|
||||
if (get_current_user() !== 'root') {
|
||||
$prefix = 'sudo ';
|
||||
logger()->warning('Current user is not root, using sudo for running command');
|
||||
}
|
||||
try {
|
||||
shell(true)->exec($prefix . $install_cmd . ' ' . implode(' ', $missing));
|
||||
} catch (RuntimeException) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -439,6 +439,20 @@ class FileSystem
|
||||
self::$_extract_hook[$name][] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the path is a relative path (judging according to whether the first character is "/")
|
||||
*
|
||||
* @param string $path Path
|
||||
*/
|
||||
public static function isRelativePath(string $path): bool
|
||||
{
|
||||
// 适配 Windows 的多盘符目录形式
|
||||
if (DIRECTORY_SEPARATOR === '\\') {
|
||||
return !(strlen($path) > 2 && ctype_alpha($path[0]) && $path[1] === ':');
|
||||
}
|
||||
return strlen($path) > 0 && $path[0] !== '/';
|
||||
}
|
||||
|
||||
private static function emitSourceExtractHook(string $name)
|
||||
{
|
||||
foreach ((self::$_extract_hook[$name] ?? []) as $hook) {
|
||||
|
||||
Reference in New Issue
Block a user