Merge branch 'main' into fix/icurel

This commit is contained in:
Marc 2025-05-31 22:32:08 +07:00 committed by GitHub
commit 93eb6378ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 975 additions and 342 deletions

15
.editorconfig Normal file
View File

@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml, vue}]
indent_size = 2

View File

@ -17,8 +17,7 @@ on:
- 'box.json' - 'box.json'
- '.php-cs-fixer.php' - '.php-cs-fixer.php'
permissions: permissions: read-all
contents: read
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -191,7 +190,7 @@ jobs:
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $GITHUB_ENV echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $GITHUB_ENV
- name: "Run Build Tests (download)" - name: "Run Build Tests (download)"
run: php src/globals/test-extensions.php download_cmd ${{ matrix.os }} ${{ matrix.php }} run: GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} php src/globals/test-extensions.php download_cmd ${{ matrix.os }} ${{ matrix.php }}
- name: "Run Build Tests (build)" - name: "Run Build Tests (build)"
run: php src/globals/test-extensions.php build_cmd ${{ matrix.os }} ${{ matrix.php }} run: php src/globals/test-extensions.php build_cmd ${{ matrix.os }} ${{ matrix.php }}

4
.gitignore vendored
View File

@ -50,3 +50,7 @@ packlib_files.txt
/docs/.vitepress/cache/ /docs/.vitepress/cache/
package-lock.json package-lock.json
pnpm-lock.yaml pnpm-lock.yaml
# craft.log
craft.log
craft.yml

View File

@ -1,6 +1,7 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# This file is using docker to run commands # This file is using docker to run commands
SPC_DOCKER_VERSION=v3
# Detect docker can run # Detect docker can run
if ! which docker >/dev/null; then if ! which docker >/dev/null; then
@ -50,9 +51,9 @@ else
fi fi
# Detect docker env is setup # Detect docker env is setup
if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH-v2; then if ! $DOCKER_EXECUTABLE images | grep -q cwcc-spc-$SPC_USE_ARCH-$SPC_DOCKER_VERSION; then
echo "Docker container does not exist. Building docker image ..." echo "Docker container does not exist. Building docker image ..."
$DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH-v2 -f- . <<EOF $DOCKER_EXECUTABLE build -t cwcc-spc-$SPC_USE_ARCH-$SPC_DOCKER_VERSION -f- . <<EOF
FROM $ALPINE_FROM FROM $ALPINE_FROM
$SPC_USE_MIRROR $SPC_USE_MIRROR
RUN apk update; \ RUN apk update; \
@ -116,6 +117,16 @@ MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/source:/app/source"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/dist:/app/dist" MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/dist:/app/dist"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/downloads:/app/downloads" MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/downloads:/app/downloads"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot" MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot"
if [ -f "$(pwd)/craft.yml" ]; then
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/craft.yml:/app/craft.yml"
fi
# Environment variable passthrough
ENV_LIST=""
ENV_LIST="$ENV_LIST -e SPC_FIX_DEPLOY_ROOT="$(pwd)""
if [ ! -z "$GITHUB_TOKEN" ]; then
ENV_LIST="$ENV_LIST -e GITHUB_TOKEN=$GITHUB_TOKEN"
fi
# Run docker # Run docker
# shellcheck disable=SC2068 # shellcheck disable=SC2068
@ -135,8 +146,8 @@ if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
echo "* ./downloads: $(pwd)/downloads" echo "* ./downloads: $(pwd)/downloads"
echo "* ./pkgroot: $(pwd)/pkgroot" echo "* ./pkgroot: $(pwd)/pkgroot"
echo "*" echo "*"
set -ex
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 $DOCKER_EXECUTABLE run --rm $INTERACT $ENV_LIST $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-$SPC_DOCKER_VERSION
else else
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-v2 bin/spc $@ $DOCKER_EXECUTABLE run --rm $INTERACT $ENV_LIST $MOUNT_LIST cwcc-spc-$SPC_USE_ARCH-$SPC_DOCKER_VERSION bin/spc $@
fi fi

View File

@ -1,8 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# This file is using docker to run commands
set -e
# Detect docker can run # Detect docker can run
if ! which docker >/dev/null; then if ! which docker >/dev/null; then
echo "Docker is not installed, please install docker first !" echo "Docker is not installed, please install docker first !"
@ -129,6 +126,9 @@ MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/source:/app/source"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/dist:/app/dist" MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/dist:/app/dist"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/downloads:/app/downloads" MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/downloads:/app/downloads"
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot" MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/pkgroot:/app/pkgroot"
if [ -f "$(pwd)/craft.yml" ]; then
MOUNT_LIST="$MOUNT_LIST -v ""$(pwd)""/craft.yml:/app/craft.yml"
fi
# Apply env in temp env file # Apply env in temp env file
echo 'CC=/opt/rh/devtoolset-10/root/usr/bin/gcc' > /tmp/spc-gnu-docker.env echo 'CC=/opt/rh/devtoolset-10/root/usr/bin/gcc' > /tmp/spc-gnu-docker.env
@ -140,6 +140,13 @@ echo 'SPC_LIBC=glibc' >> /tmp/spc-gnu-docker.env
echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-Wl,-O1 -pie"' >> /tmp/spc-gnu-docker.env echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LDFLAGS_PROGRAM="-Wl,-O1 -pie"' >> /tmp/spc-gnu-docker.env
echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"' >> /tmp/spc-gnu-docker.env echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"' >> /tmp/spc-gnu-docker.env
# Environment variable passthrough
ENV_LIST=""
ENV_LIST="$ENV_LIST -e SPC_FIX_DEPLOY_ROOT="$(pwd)""
if [ ! -z "$GITHUB_TOKEN" ]; then
ENV_LIST="$ENV_LIST -e GITHUB_TOKEN=$GITHUB_TOKEN"
fi
# Run docker # Run docker
# shellcheck disable=SC2068 # shellcheck disable=SC2068
# shellcheck disable=SC2086 # shellcheck disable=SC2086
@ -159,8 +166,8 @@ if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
echo "* ./downloads: $(pwd)/downloads" echo "* ./downloads: $(pwd)/downloads"
echo "* ./pkgroot: $(pwd)/pkgroot" echo "* ./pkgroot: $(pwd)/pkgroot"
echo "*" echo "*"
set -ex
$DOCKER_EXECUTABLE run --rm -it --privileged $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH $DOCKER_EXECUTABLE run --rm -it --privileged $INTERACT $ENV_LIST --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH
else else
$DOCKER_EXECUTABLE run --rm $INTERACT -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@ $DOCKER_EXECUTABLE run --rm $INTERACT $ENV_LIST --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@
fi fi

View File

@ -14,6 +14,8 @@
"ext-zlib": "*", "ext-zlib": "*",
"laravel/prompts": "^0.1.12", "laravel/prompts": "^0.1.12",
"symfony/console": "^5.4 || ^6 || ^7", "symfony/console": "^5.4 || ^6 || ^7",
"symfony/process": "^7.2",
"symfony/yaml": "^7.2",
"zhamao/logger": "^1.0" "zhamao/logger": "^1.0"
}, },
"require-dev": { "require-dev": {

440
composer.lock generated
View File

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "7e3bd0c36428da870d1a0ae206c3b83e", "content-hash": "d705cec8270679a463d9e04310208967",
"packages": [ "packages": [
{ {
"name": "illuminate/collections", "name": "illuminate/collections",
"version": "v11.44.1", "version": "v11.44.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/collections.git", "url": "https://github.com/illuminate/collections.git",
"reference": "48f5357348093bc8b94c691aa3ffc861d2ecc2a0" "reference": "856b1da953e46281ba61d7c82d337072d3ee1825"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/collections/zipball/48f5357348093bc8b94c691aa3ffc861d2ecc2a0", "url": "https://api.github.com/repos/illuminate/collections/zipball/856b1da953e46281ba61d7c82d337072d3ee1825",
"reference": "48f5357348093bc8b94c691aa3ffc861d2ecc2a0", "reference": "856b1da953e46281ba61d7c82d337072d3ee1825",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -60,20 +60,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2025-02-28T16:55:51+00:00" "time": "2025-03-24T11:54:20+00:00"
}, },
{ {
"name": "illuminate/conditionable", "name": "illuminate/conditionable",
"version": "v11.44.1", "version": "v11.44.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/conditionable.git", "url": "https://github.com/illuminate/conditionable.git",
"reference": "911df1bda950a3b799cf80671764e34eede131c6" "reference": "319b717e0587bd7c8a3b44464f0e27867b4bcda9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/conditionable/zipball/911df1bda950a3b799cf80671764e34eede131c6", "url": "https://api.github.com/repos/illuminate/conditionable/zipball/319b717e0587bd7c8a3b44464f0e27867b4bcda9",
"reference": "911df1bda950a3b799cf80671764e34eede131c6", "reference": "319b717e0587bd7c8a3b44464f0e27867b4bcda9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -106,20 +106,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2024-11-21T16:28:56+00:00" "time": "2025-03-24T11:54:20+00:00"
}, },
{ {
"name": "illuminate/contracts", "name": "illuminate/contracts",
"version": "v11.44.1", "version": "v11.44.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/contracts.git", "url": "https://github.com/illuminate/contracts.git",
"reference": "b350a3cd8450846325cb49e1cbc1293598b18898" "reference": "4b2a67d1663f50085bc91e6371492697a5d2d4e8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/b350a3cd8450846325cb49e1cbc1293598b18898", "url": "https://api.github.com/repos/illuminate/contracts/zipball/4b2a67d1663f50085bc91e6371492697a5d2d4e8",
"reference": "b350a3cd8450846325cb49e1cbc1293598b18898", "reference": "4b2a67d1663f50085bc91e6371492697a5d2d4e8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -154,11 +154,11 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2025-02-10T14:20:57+00:00" "time": "2025-03-24T11:54:20+00:00"
}, },
{ {
"name": "illuminate/macroable", "name": "illuminate/macroable",
"version": "v11.44.1", "version": "v11.44.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/macroable.git", "url": "https://github.com/illuminate/macroable.git",
@ -416,16 +416,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.4.17", "version": "v6.4.20",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "799445db3f15768ecc382ac5699e6da0520a0a04" "reference": "2e4af9c952617cc3f9559ff706aee420a8464c36"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", "url": "https://api.github.com/repos/symfony/console/zipball/2e4af9c952617cc3f9559ff706aee420a8464c36",
"reference": "799445db3f15768ecc382ac5699e6da0520a0a04", "reference": "2e4af9c952617cc3f9559ff706aee420a8464c36",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -490,7 +490,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v6.4.17" "source": "https://github.com/symfony/console/tree/v6.4.20"
}, },
"funding": [ "funding": [
{ {
@ -506,7 +506,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-12-07T12:07:30+00:00" "time": "2025-03-03T17:16:38+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@ -893,6 +893,67 @@
], ],
"time": "2024-09-09T11:45:10+00:00" "time": "2024-09-09T11:45:10+00:00"
}, },
{
"name": "symfony/process",
"version": "v7.2.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d",
"reference": "87b7c93e57df9d8e39a093d32587702380ff045d",
"shasum": ""
},
"require": {
"php": ">=8.2"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.2.5"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-03-13T12:21:46+00:00"
},
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
"version": "v3.5.1", "version": "v3.5.1",
@ -1064,17 +1125,89 @@
"time": "2024-11-13T13:31:26+00:00" "time": "2024-11-13T13:31:26+00:00"
}, },
{ {
"name": "zhamao/logger", "name": "symfony/yaml",
"version": "1.1.1", "version": "v7.2.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/zhamao-robot/zhamao-logger.git", "url": "https://github.com/symfony/yaml.git",
"reference": "1b7e34349330a842887d816f0344aba996cfeec0" "reference": "4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/zhamao-robot/zhamao-logger/zipball/1b7e34349330a842887d816f0344aba996cfeec0", "url": "https://api.github.com/repos/symfony/yaml/zipball/4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912",
"reference": "1b7e34349330a842887d816f0344aba996cfeec0", "reference": "4c4b6f4cfcd7e52053f0c8bfad0f7f30fb924912",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"symfony/console": "<6.4"
},
"require-dev": {
"symfony/console": "^6.4|^7.0"
},
"bin": [
"Resources/bin/yaml-lint"
],
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v7.2.5"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-03-03T07:12:39+00:00"
},
{
"name": "zhamao/logger",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/zhamao-robot/zhamao-logger.git",
"reference": "1d7427abd8b1b3387ed7d9244953049356db3e62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zhamao-robot/zhamao-logger/zipball/1d7427abd8b1b3387ed7d9244953049356db3e62",
"reference": "1d7427abd8b1b3387ed7d9244953049356db3e62",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1128,9 +1261,9 @@
"description": "Another Console Logger for CLI Applications", "description": "Another Console Logger for CLI Applications",
"support": { "support": {
"issues": "https://github.com/zhamao-robot/zhamao-logger/issues", "issues": "https://github.com/zhamao-robot/zhamao-logger/issues",
"source": "https://github.com/zhamao-robot/zhamao-logger/tree/1.1.1" "source": "https://github.com/zhamao-robot/zhamao-logger/tree/1.1.2"
}, },
"time": "2023-03-09T15:41:10+00:00" "time": "2025-04-24T02:02:28+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -1217,16 +1350,16 @@
}, },
{ {
"name": "amphp/byte-stream", "name": "amphp/byte-stream",
"version": "v2.1.1", "version": "v2.1.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/amphp/byte-stream.git", "url": "https://github.com/amphp/byte-stream.git",
"reference": "daa00f2efdbd71565bf64ffefa89e37542addf93" "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/amphp/byte-stream/zipball/daa00f2efdbd71565bf64ffefa89e37542addf93", "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46",
"reference": "daa00f2efdbd71565bf64ffefa89e37542addf93", "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1280,7 +1413,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/amphp/byte-stream/issues", "issues": "https://github.com/amphp/byte-stream/issues",
"source": "https://github.com/amphp/byte-stream/tree/v2.1.1" "source": "https://github.com/amphp/byte-stream/tree/v2.1.2"
}, },
"funding": [ "funding": [
{ {
@ -1288,7 +1421,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-02-17T04:49:38+00:00" "time": "2025-03-16T17:10:27+00:00"
}, },
{ {
"name": "amphp/cache", "name": "amphp/cache",
@ -1592,16 +1725,16 @@
}, },
{ {
"name": "amphp/pipeline", "name": "amphp/pipeline",
"version": "v1.2.2", "version": "v1.2.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/amphp/pipeline.git", "url": "https://github.com/amphp/pipeline.git",
"reference": "97cbf289f4d8877acfe58dd90ed5a4370a43caa4" "reference": "7b52598c2e9105ebcddf247fc523161581930367"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/amphp/pipeline/zipball/97cbf289f4d8877acfe58dd90ed5a4370a43caa4", "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367",
"reference": "97cbf289f4d8877acfe58dd90ed5a4370a43caa4", "reference": "7b52598c2e9105ebcddf247fc523161581930367",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1647,7 +1780,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/amphp/pipeline/issues", "issues": "https://github.com/amphp/pipeline/issues",
"source": "https://github.com/amphp/pipeline/tree/v1.2.2" "source": "https://github.com/amphp/pipeline/tree/v1.2.3"
}, },
"funding": [ "funding": [
{ {
@ -1655,7 +1788,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-01-19T15:42:46+00:00" "time": "2025-03-16T16:33:53+00:00"
}, },
{ {
"name": "amphp/process", "name": "amphp/process",
@ -1944,23 +2077,23 @@
}, },
{ {
"name": "captainhook/captainhook-phar", "name": "captainhook/captainhook-phar",
"version": "5.25.0", "version": "5.25.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/captainhookphp/captainhook-phar.git", "url": "https://github.com/captainhook-git/captainhook-phar.git",
"reference": "de7a0e8a2d4ee7b63f46ac61c6f9a89ff0a30011" "reference": "ab47b0561ec7997bf9b88181d090857874f2cf8c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/captainhookphp/captainhook-phar/zipball/de7a0e8a2d4ee7b63f46ac61c6f9a89ff0a30011", "url": "https://api.github.com/repos/captainhook-git/captainhook-phar/zipball/ab47b0561ec7997bf9b88181d090857874f2cf8c",
"reference": "de7a0e8a2d4ee7b63f46ac61c6f9a89ff0a30011", "reference": "ab47b0561ec7997bf9b88181d090857874f2cf8c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"composer-plugin-api": "^1.1||^2.0", "composer-plugin-api": "^1.1||^2.0",
"ext-json": "*", "ext-json": "*",
"ext-spl": "*", "ext-spl": "*",
"phar-io/composer-distributor": "^1.0", "phar-io/composer-distributor": "^1.0.1",
"php": ">=8.0" "php": ">=8.0"
}, },
"require-dev": { "require-dev": {
@ -1998,7 +2131,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/captainhookphp/captainhook/issues", "issues": "https://github.com/captainhookphp/captainhook/issues",
"source": "https://github.com/captainhookphp/captainhook-phar/tree/5.25.0" "source": "https://github.com/captainhook-git/captainhook-phar/tree/5.25.2"
}, },
"funding": [ "funding": [
{ {
@ -2006,20 +2139,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-01-16T12:46:49+00:00" "time": "2025-03-30T17:19:44+00:00"
}, },
{ {
"name": "captainhook/hook-installer", "name": "captainhook/hook-installer",
"version": "1.0.3", "version": "1.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/captainhookphp/hook-installer.git", "url": "https://github.com/captainhook-git/hook-installer.git",
"reference": "3308a9152727af4e3d1c7b63ca219d6938b702b8" "reference": "fb3c45f6204b08baba999f4ffc4ae707bf684e8b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/captainhookphp/hook-installer/zipball/3308a9152727af4e3d1c7b63ca219d6938b702b8", "url": "https://api.github.com/repos/captainhook-git/hook-installer/zipball/fb3c45f6204b08baba999f4ffc4ae707bf684e8b",
"reference": "3308a9152727af4e3d1c7b63ca219d6938b702b8", "reference": "fb3c45f6204b08baba999f4ffc4ae707bf684e8b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2050,10 +2183,10 @@
], ],
"description": "Composer Plugin that makes everyone activate the CaptainHook git hooks locally", "description": "Composer Plugin that makes everyone activate the CaptainHook git hooks locally",
"support": { "support": {
"issues": "https://github.com/captainhookphp/hook-installer/issues", "issues": "https://github.com/captainhook-git/hook-installer/issues",
"source": "https://github.com/captainhookphp/hook-installer/tree/1.0.3" "source": "https://github.com/captainhook-git/hook-installer/tree/1.0.4"
}, },
"time": "2024-03-21T13:39:59+00:00" "time": "2025-04-08T07:12:26+00:00"
}, },
{ {
"name": "clue/ndjson-react", "name": "clue/ndjson-react",
@ -2391,26 +2524,29 @@
}, },
{ {
"name": "doctrine/deprecations", "name": "doctrine/deprecations",
"version": "1.1.4", "version": "1.1.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/deprecations.git", "url": "https://github.com/doctrine/deprecations.git",
"reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9" "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9", "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
"reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9", "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.1 || ^8.0" "php": "^7.1 || ^8.0"
}, },
"conflict": {
"phpunit/phpunit": "<=7.5 || >=13"
},
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^9 || ^12", "doctrine/coding-standard": "^9 || ^12 || ^13",
"phpstan/phpstan": "1.4.10 || 2.0.3", "phpstan/phpstan": "1.4.10 || 2.1.11",
"phpstan/phpstan-phpunit": "^1.0 || ^2", "phpstan/phpstan-phpunit": "^1.0 || ^2",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
"psr/log": "^1 || ^2 || ^3" "psr/log": "^1 || ^2 || ^3"
}, },
"suggest": { "suggest": {
@ -2430,9 +2566,9 @@
"homepage": "https://www.doctrine-project.org/", "homepage": "https://www.doctrine-project.org/",
"support": { "support": {
"issues": "https://github.com/doctrine/deprecations/issues", "issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/1.1.4" "source": "https://github.com/doctrine/deprecations/tree/1.1.5"
}, },
"time": "2024-12-07T21:18:45+00:00" "time": "2025-04-07T20:06:18+00:00"
}, },
{ {
"name": "evenement/evenement", "name": "evenement/evenement",
@ -2696,16 +2832,16 @@
}, },
{ {
"name": "filp/whoops", "name": "filp/whoops",
"version": "2.17.0", "version": "2.18.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/filp/whoops.git", "url": "https://github.com/filp/whoops.git",
"reference": "075bc0c26631110584175de6523ab3f1652eb28e" "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/075bc0c26631110584175de6523ab3f1652eb28e", "url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"reference": "075bc0c26631110584175de6523ab3f1652eb28e", "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2755,7 +2891,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/filp/whoops/issues", "issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.17.0" "source": "https://github.com/filp/whoops/tree/2.18.0"
}, },
"funding": [ "funding": [
{ {
@ -2763,20 +2899,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-01-25T12:00:00+00:00" "time": "2025-03-15T12:00:00+00:00"
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.70.2", "version": "v3.75.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "1ca468270efbb75ce0c7566a79cca8ea2888584d" "reference": "399a128ff2fdaf4281e4e79b755693286cdf325c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/1ca468270efbb75ce0c7566a79cca8ea2888584d", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/399a128ff2fdaf4281e4e79b755693286cdf325c",
"reference": "1ca468270efbb75ce0c7566a79cca8ea2888584d", "reference": "399a128ff2fdaf4281e4e79b755693286cdf325c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2784,6 +2920,7 @@
"composer/semver": "^3.4", "composer/semver": "^3.4",
"composer/xdebug-handler": "^3.0.3", "composer/xdebug-handler": "^3.0.3",
"ext-filter": "*", "ext-filter": "*",
"ext-hash": "*",
"ext-json": "*", "ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"fidry/cpu-core-counter": "^1.2", "fidry/cpu-core-counter": "^1.2",
@ -2806,18 +2943,18 @@
"symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0"
}, },
"require-dev": { "require-dev": {
"facile-it/paraunit": "^1.3.1 || ^2.5", "facile-it/paraunit": "^1.3.1 || ^2.6",
"infection/infection": "^0.29.10", "infection/infection": "^0.29.14",
"justinrainbow/json-schema": "^5.3 || ^6.0", "justinrainbow/json-schema": "^5.3 || ^6.2",
"keradus/cli-executor": "^2.1", "keradus/cli-executor": "^2.1",
"mikey179/vfsstream": "^1.6.12", "mikey179/vfsstream": "^1.6.12",
"php-coveralls/php-coveralls": "^2.7", "php-coveralls/php-coveralls": "^2.7",
"php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/accessible-object": "^1.1",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
"phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.7", "phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.12",
"symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.0", "symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.3",
"symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.0" "symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.3"
}, },
"suggest": { "suggest": {
"ext-dom": "For handling output formats in XML", "ext-dom": "For handling output formats in XML",
@ -2858,7 +2995,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.70.2" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.75.0"
}, },
"funding": [ "funding": [
{ {
@ -2866,7 +3003,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-03-03T21:07:23+00:00" "time": "2025-03-31T18:40:42+00:00"
}, },
{ {
"name": "humbug/box", "name": "humbug/box",
@ -3579,40 +3716,40 @@
}, },
{ {
"name": "nunomaduro/collision", "name": "nunomaduro/collision",
"version": "v7.11.0", "version": "v7.12.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nunomaduro/collision.git", "url": "https://github.com/nunomaduro/collision.git",
"reference": "994ea93df5d4132f69d3f1bd74730509df6e8a05" "reference": "995245421d3d7593a6960822063bdba4f5d7cf1a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/994ea93df5d4132f69d3f1bd74730509df6e8a05", "url": "https://api.github.com/repos/nunomaduro/collision/zipball/995245421d3d7593a6960822063bdba4f5d7cf1a",
"reference": "994ea93df5d4132f69d3f1bd74730509df6e8a05", "reference": "995245421d3d7593a6960822063bdba4f5d7cf1a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"filp/whoops": "^2.16.0", "filp/whoops": "^2.17.0",
"nunomaduro/termwind": "^1.15.1", "nunomaduro/termwind": "^1.17.0",
"php": "^8.1.0", "php": "^8.1.0",
"symfony/console": "^6.4.12" "symfony/console": "^6.4.17"
}, },
"conflict": { "conflict": {
"laravel/framework": ">=11.0.0" "laravel/framework": ">=11.0.0"
}, },
"require-dev": { "require-dev": {
"brianium/paratest": "^7.3.1", "brianium/paratest": "^7.4.8",
"laravel/framework": "^10.48.22", "laravel/framework": "^10.48.29",
"laravel/pint": "^1.18.1", "laravel/pint": "^1.21.2",
"laravel/sail": "^1.36.0", "laravel/sail": "^1.41.0",
"laravel/sanctum": "^3.3.3", "laravel/sanctum": "^3.3.3",
"laravel/tinker": "^2.10.0", "laravel/tinker": "^2.10.1",
"nunomaduro/larastan": "^2.9.8", "nunomaduro/larastan": "^2.10.0",
"orchestra/testbench-core": "^8.28.3", "orchestra/testbench-core": "^8.35.0",
"pestphp/pest": "^2.35.1", "pestphp/pest": "^2.36.0",
"phpunit/phpunit": "^10.5.36", "phpunit/phpunit": "^10.5.36",
"sebastian/environment": "^6.1.0", "sebastian/environment": "^6.1.0",
"spatie/laravel-ignition": "^2.8.0" "spatie/laravel-ignition": "^2.9.1"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -3671,7 +3808,7 @@
"type": "patreon" "type": "patreon"
} }
], ],
"time": "2024-10-15T15:12:40+00:00" "time": "2025-03-14T22:35:49+00:00"
}, },
{ {
"name": "nunomaduro/termwind", "name": "nunomaduro/termwind",
@ -4145,16 +4282,16 @@
}, },
{ {
"name": "phpdocumentor/reflection-docblock", "name": "phpdocumentor/reflection-docblock",
"version": "5.6.1", "version": "5.6.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8" "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62",
"reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8", "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4203,9 +4340,9 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": { "support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.1" "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2"
}, },
"time": "2024-12-07T09:39:29+00:00" "time": "2025-04-13T19:20:35+00:00"
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
@ -4314,16 +4451,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.12.20", "version": "1.12.24",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "3240b1972042c7f73cf1045e879ea5bd5f761bb7" "reference": "338b92068f58d9f8035b76aed6cf2b9e5624c025"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/3240b1972042c7f73cf1045e879ea5bd5f761bb7", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/338b92068f58d9f8035b76aed6cf2b9e5624c025",
"reference": "3240b1972042c7f73cf1045e879ea5bd5f761bb7", "reference": "338b92068f58d9f8035b76aed6cf2b9e5624c025",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4368,7 +4505,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-03-05T13:37:43+00:00" "time": "2025-04-16T13:01:53+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@ -7085,67 +7222,6 @@
], ],
"time": "2024-09-09T12:04:04+00:00" "time": "2024-09-09T12:04:04+00:00"
}, },
{
"name": "symfony/process",
"version": "v7.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
"reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
"shasum": ""
},
"require": {
"php": ">=8.2"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.2.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-02-05T08:33:46+00:00"
},
{ {
"name": "symfony/stopwatch", "name": "symfony/stopwatch",
"version": "v7.2.4", "version": "v7.2.4",
@ -7293,16 +7369,16 @@
}, },
{ {
"name": "thecodingmachine/safe", "name": "thecodingmachine/safe",
"version": "v3.0.2", "version": "v3.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thecodingmachine/safe.git", "url": "https://github.com/thecodingmachine/safe.git",
"reference": "22ffad3248982a784f9870a37aeb2e522bd19645" "reference": "e14ac96126e6c19ea9d1f4029abb51487f4cf2cf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/22ffad3248982a784f9870a37aeb2e522bd19645", "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/e14ac96126e6c19ea9d1f4029abb51487f4cf2cf",
"reference": "22ffad3248982a784f9870a37aeb2e522bd19645", "reference": "e14ac96126e6c19ea9d1f4029abb51487f4cf2cf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -7412,7 +7488,7 @@
"description": "PHP core functions that throw exceptions instead of returning FALSE on error", "description": "PHP core functions that throw exceptions instead of returning FALSE on error",
"support": { "support": {
"issues": "https://github.com/thecodingmachine/safe/issues", "issues": "https://github.com/thecodingmachine/safe/issues",
"source": "https://github.com/thecodingmachine/safe/tree/v3.0.2" "source": "https://github.com/thecodingmachine/safe/tree/v3.1.0"
}, },
"funding": [ "funding": [
{ {
@ -7428,7 +7504,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-02-19T19:23:00+00:00" "time": "2025-04-12T06:41:26+00:00"
}, },
{ {
"name": "theseer/tokenizer", "name": "theseer/tokenizer",
@ -7545,7 +7621,7 @@
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "~8.4.0", "php": ">= 8.3",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-zlib": "*" "ext-zlib": "*"
}, },

View File

@ -177,6 +177,12 @@
{{ buildCommandString }} {{ buildCommandString }}
</div> </div>
</div> </div>
<div class="command-container">
<b>craft.yml</b>
<div id="craft-cmd" class="command-preview pre">
{{ craftCommandString }}
</div>
</div>
</div> </div>
</template> </template>
@ -509,6 +515,38 @@ const buildCommandString = computed(() => {
return `${spcCommand.value} build ${buildCommand.value} "${extList.value}"${additionalLibs.value}${debug.value ? ' --debug' : ''}${zts.value ? ' --enable-zts' : ''}${enableUPX.value ? ' --with-upx-pack' : ''}${displayINI.value}`; return `${spcCommand.value} build ${buildCommand.value} "${extList.value}"${additionalLibs.value}${debug.value ? ' --debug' : ''}${zts.value ? ' --enable-zts' : ''}${enableUPX.value ? ' --with-upx-pack' : ''}${displayINI.value}`;
}); });
const craftCommandString = computed(() => {
let str = `php-version: ${selectedPhpVersion.value}\n`;
str += `extensions: "${extList.value}"\n`;
if (checkedTargets.value.join(',') === 'all') {
str += 'sapi: ' + ['cli', 'fpm', 'micro', 'embed'].join(',') + '\n';
} else {
str += `sapi: ${checkedTargets.value.join(',')}\n`;
}
if (additionalLibs.value) {
str += `libs: ${additionalLibs.value.replace('--with-libs="', '').replace('"', '').trim()}\n`;
}
if (debug.value) {
str += 'debug: true\n';
}
str += '{{position_hold}}';
if (enableUPX.value) {
str += ' with-upx-pack: true\n';
}
if (zts.value) {
str += ' enable-zts: true\n';
}
if (preBuilt.value) {
str += ' prefer-pre-built: true\n';
}
if (!str.endsWith('{{position_hold}}')) {
str = str.replace('{{position_hold}}', 'build-options:\n');
} else {
str = str.replace('{{position_hold}}', '');
}
return str;
});
const calculateExtLibDepends = (input) => { const calculateExtLibDepends = (input) => {
const result = new Set(); const result = new Set();
@ -627,6 +665,12 @@ h2 {
overflow-wrap: break-word; overflow-wrap: break-word;
} }
.pre {
white-space: pre-wrap;
word-break: break-word;
overflow-wrap: break-word;
}
.option-line { .option-line {
padding: 4px 8px; padding: 4px 8px;
} }

View File

@ -1,56 +1,57 @@
export default { export default {
'/en/guide/': [ '/en/guide/': [
{ {
text: 'Basic Build Guides', text: 'Basic Build Guides',
items: [ items: [
{text: 'Guide', link: '/en/guide/'}, {text: 'Guide', link: '/en/guide/'},
{text: 'Build (Local)', link: '/en/guide/manual-build'}, {text: 'Build (Local)', link: '/en/guide/manual-build'},
{text: 'Build (CI)', link: '/en/guide/action-build'}, {text: 'Build (CI)', link: '/en/guide/action-build'},
{text: 'Supported Extensions', link: '/en/guide/extensions'}, {text: 'Supported Extensions', link: '/en/guide/extensions'},
{text: 'Extension Notes', link: '/en/guide/extension-notes'}, {text: 'Extension Notes', link: '/en/guide/extension-notes'},
{text: 'Build Command Generator', link: '/en/guide/cli-generator'}, {text: 'Build Command Generator', link: '/en/guide/cli-generator'},
{text: 'Environment Variables', link: '/en/guide/env-vars', collapsed: true,}, {text: 'Environment Variables', link: '/en/guide/env-vars', collapsed: true,},
{text: 'Dependency Table', link: '/en/guide/deps-map'}, {text: 'Dependency Table', link: '/en/guide/deps-map'},
] ]
}, },
{ {
text: 'Extended Build Guides', text: 'Extended Build Guides',
items: [ items: [
{text: 'Troubleshooting', link: '/en/guide/troubleshooting'}, {text: 'Troubleshooting', link: '/en/guide/troubleshooting'},
{text: 'Build on Windows', link: '/en/guide/build-on-windows'}, {text: 'Build on Windows', link: '/en/guide/build-on-windows'},
{text: 'Build with GNU libc', link: '/en/guide/build-with-glibc'}, {text: 'Build with GNU libc', link: '/en/guide/build-with-glibc'},
], ],
} }
], ],
'/en/develop/': [ '/en/develop/': [
{ {
text: 'Development', text: 'Development',
items: [ items: [
{text: 'Get Started', link: '/en/develop/'}, {text: 'Get Started', link: '/en/develop/'},
{text: 'Project Structure', link: '/en/develop/structure'}, {text: 'Project Structure', link: '/en/develop/structure'},
{text: 'PHP Source Modification', link: '/en/develop/php-src-changes'}, {text: 'PHP Source Modification', link: '/en/develop/php-src-changes'},
], ],
}, },
{ {
text: 'Module', text: 'Module',
items: [ items: [
{text: 'Doctor ', link: '/en/develop/doctor-module'}, {text: 'Doctor ', link: '/en/develop/doctor-module'},
{text: 'Source', link: '/en/develop/source-module'}, {text: 'Source', link: '/en/develop/source-module'},
] ]
}, },
{ {
text: 'Extra', text: 'Extra',
items: [ items: [
{text: 'Compilation Tools', link: '/en/develop/system-build-tools'}, {text: 'Compilation Tools', link: '/en/develop/system-build-tools'},
] {text: 'craft.yml Configuration', link: '/zh/develop/craft-yml'},
} ]
], }
'/en/contributing/': [ ],
{ '/en/contributing/': [
text: 'Contributing', {
items: [ text: 'Contributing',
{text: 'Contributing', link: '/en/contributing/'}, items: [
], {text: 'Contributing', link: '/en/contributing/'},
} ],
], }
],
}; };

View File

@ -1,56 +1,57 @@
export default { export default {
'/zh/guide/': [ '/zh/guide/': [
{ {
text: '构建指南', text: '构建指南',
items: [ items: [
{text: '指南', link: '/zh/guide/'}, {text: '指南', link: '/zh/guide/'},
{text: '本地构建', link: '/zh/guide/manual-build'}, {text: '本地构建', link: '/zh/guide/manual-build'},
{text: 'Actions 构建', link: '/zh/guide/action-build'}, {text: 'Actions 构建', link: '/zh/guide/action-build'},
{text: '扩展列表', link: '/zh/guide/extensions'}, {text: '扩展列表', link: '/zh/guide/extensions'},
{text: '扩展注意事项', link: '/zh/guide/extension-notes'}, {text: '扩展注意事项', link: '/zh/guide/extension-notes'},
{text: '编译命令生成器', link: '/zh/guide/cli-generator'}, {text: '编译命令生成器', link: '/zh/guide/cli-generator'},
{text: '环境变量列表', link: '/zh/guide/env-vars'}, {text: '环境变量列表', link: '/zh/guide/env-vars'},
{text: '依赖关系图表', link: '/zh/guide/deps-map'}, {text: '依赖关系图表', link: '/zh/guide/deps-map'},
] ]
}, },
{ {
text: '扩展构建指南', text: '扩展构建指南',
items: [ items: [
{text: '故障排除', link: '/zh/guide/troubleshooting'}, {text: '故障排除', link: '/zh/guide/troubleshooting'},
{text: '在 Windows 上构建', link: '/zh/guide/build-on-windows'}, {text: '在 Windows 上构建', link: '/zh/guide/build-on-windows'},
{text: '构建 GNU libc 兼容的二进制', link: '/zh/guide/build-with-glibc'}, {text: '构建 GNU libc 兼容的二进制', link: '/zh/guide/build-with-glibc'},
], ],
} }
], ],
'/zh/develop/': [ '/zh/develop/': [
{ {
text: '开发指南', text: '开发指南',
items: [ items: [
{ text: '开发简介', link: '/zh/develop/' }, {text: '开发简介', link: '/zh/develop/'},
{ text: '项目结构简介', link: '/zh/develop/structure' }, {text: '项目结构简介', link: '/zh/develop/structure'},
{text: '对 PHP 源码的修改', link: '/zh/develop/php-src-changes'}, {text: '对 PHP 源码的修改', link: '/zh/develop/php-src-changes'},
], ],
}, },
{ {
text: '模块', text: '模块',
items: [ items: [
{ text: 'Doctor 环境检查工具', link: '/zh/develop/doctor-module' }, {text: 'Doctor 环境检查工具', link: '/zh/develop/doctor-module'},
{ text: '资源模块', link: '/zh/develop/source-module' }, {text: '资源模块', link: '/zh/develop/source-module'},
] ]
}, },
{ {
text: '其他', text: '其他',
items: [ items: [
{text: '系统编译工具', link: '/zh/develop/system-build-tools'}, {text: '系统编译工具', link: '/zh/develop/system-build-tools'},
] {text: 'craft.yml 配置详解', link: '/zh/develop/craft-yml'},
} ]
], }
'/zh/contributing/': [ ],
{ '/zh/contributing/': [
text: '贡献指南', {
items: [ text: '贡献指南',
{text: '贡献指南', link: '/zh/contributing/'}, items: [
], {text: '贡献指南', link: '/zh/contributing/'},
} ],
], }
],
}; };

67
docs/deps-craft-yml.md Normal file
View File

@ -0,0 +1,67 @@
```yaml
# PHP version to build (default: 8.4)
php-version: 8.4
# [REQUIRED] Static PHP extensions to build (list or comma-separated are both accepted)
extensions: bcmath,fileinfo,phar,zlib,sodium,posix,pcntl
# Extra libraries to build (list or comma-separated are both accepted)
libs: [ ]
# [REQUIRED] Build SAPIs (list or comma-separated are both accepted)
sapi: cli,micro,fpm
# Show full console output (default: false)
debug: false
# Build options (same as `build` command options, all options are optional)
build-options:
# Before build, remove all old build files and sources (default: false)
with-clean: false
# Build with all suggested libraries (default: false)
with-suggested-libs: false
# Build with all suggested extensions (default: false)
with-suggested-exts: false
# Build extra shared extensions (list or comma-separated are both accepted)
build-shared: [ ]
# Build without stripping the binary (default: false)
no-strip: false
# Disable Opcache JIT (default: false)
disable-opcache-jit: false
# PHP configuration options (same as --with-config-file-path)
with-config-file-path: ""
# PHP configuration options (same as --with-config-file-scan-dir)
with-config-file-scan-dir: ""
# Hardcoded INI options for cli and micro SAPI (e.g. "memory_limit=4G", list accepted)
with-hardcoded-ini: [ ]
# Pretend micro SAPI as cli SAPI to avoid some frameworks to limit the usage of micro SAPI
with-micro-fake-cli: false
# Additional patch point injection files (e.g. "path/to/patch.php", list accepted)
with-added-patch: [ ]
# Ignore micro extension tests (if you are using micro SAPI, default: false)
without-micro-ext-test: false
# UPX pack the binary (default: false)
with-upx-pack: false
# Set the micro.exe program icon (only for Windows, default: "")
with-micro-logo: ""
# Set micro SAPI as win32 mode, without this, micro SAPI will be compiled as a console application (only for Windows, default: false)
enable-micro-win32: false
# Download options
download-options:
# Use custom url for specified sources, format: "{source-name}:{url}" (e.g. "php-src:https://example.com/php-8.4.0.tar.gz")
custom-url: [ ]
# Use custom git repo for specified sources, format: "{source-name}:{branch}:{url}" (e.g. "php-src:master:https://github.com/php/php-src.git")
custom-git: [ ]
# Retries count for downloading sources (default: 5)
retry: 5
# Use pre-built libraries if available (default: false)
prefer-pre-built: true
# Do not download from alternative sources (default: false)
no-alt: false
craft-options:
doctor: true
download: true
build: true
# Extra environment variables
extra-env:
# e.g. Use github token to avoid rate limit
GITHUB_TOKEN: your-github-token
```

View File

@ -0,0 +1,7 @@
---
aside: false
---
# craft.yml Configuration
<!--@include: ../../deps-craft-yml.md-->

View File

@ -1,3 +1,7 @@
---
outline: 'deep'
---
# Build (Linux, macOS, FreeBSD) # Build (Linux, macOS, FreeBSD)
This section covers the build process for Linux, macOS, and FreeBSD. If you want to build on Windows, This section covers the build process for Linux, macOS, and FreeBSD. If you want to build on Windows,
@ -133,7 +137,47 @@ and then install the latest version of PHP and tokenizer, XML, and phar extensio
Older versions of Debian may have an older (<= 7.4) version of PHP installed by default, it is recommended to upgrade Debian first. Older versions of Debian may have an older (<= 7.4) version of PHP installed by default, it is recommended to upgrade Debian first.
::: :::
## Command - download ## Build with craft (recommended)
Using `bin/spc craft`, you can use a configuration file and a command to automatically check the environment, download source code, build dependency libraries, build PHP and extensions, etc.
You need to write a `craft.yml` file and save it in the current working directory. `craft.yml` can be generated by [command generator](./cli-generator) or written manually.
For manual writing, please refer to the comments in [craft.yml configuration](../develop/craft-yml.md) to write it.
Let's assume that you compile an extension combination and choose PHP 8.4, outputting `cli` and `fpm`:
```yaml
# path/to/craft.yml
php-version: 8.4
extensions: bcmath,posix,phar,zlib,openssl,curl,fileinfo,tokenizer
sapi:
- cli
- fpm
```
Then use the `bin/spc craft` command to compile:
```bash
bin/spc craft --debug
```
If the build is successful, you will see the `buildroot/bin` directory in the current directory, which contains the compiled PHP binary file, or the corresponding SAPI.
- cli: The build result is `buildroot/bin/php.exe` on Windows and `buildroot/bin/php` on other platforms.
- fpm: The build result is `buildroot/bin/php-fpm`.
- micro: The build result is `buildroot/bin/micro.sfx`. If you need to further package it with PHP code, please refer to [Packaging micro binary](./manual-build#command-micro-combine).
- embed: See [Using embed](./manual-build#embed-usage).
If the build fails, you can use the `--debug` parameter to view detailed error information,
or use the `--with-clean` to clear the old compilation results and recompile.
If the build still fails to use the above method, please submit an issue and attach your `craft.yml` and `craft.log`.
## Step-by-step build command
If you have customized requirements, or the need to download and compile PHP and dependent libraries separately, you can use the `bin/spc` command to execute step by step.
### Command download - Download dependency packages
Use the command `bin/spc download` to download the source code required for compilation, Use the command `bin/spc download` to download the source code required for compilation,
including php-src and the source code of various dependent libraries. including php-src and the source code of various dependent libraries.
@ -217,7 +261,7 @@ bin/spc download --for-extensions=redis -G "php-src:master:https://github.com/ph
bin/spc download --for-extensions=swoole -G "swoole:master:https://github.com/swoole/swoole-src.git" bin/spc download --for-extensions=swoole -G "swoole:master:https://github.com/swoole/swoole-src.git"
``` ```
## Command - doctor ### Command - doctor
If you can run `bin/spc` normally but cannot compile static PHP or dependent libraries normally, If you can run `bin/spc` normally but cannot compile static PHP or dependent libraries normally,
you can run `bin/spc doctor` first to check whether the system itself lacks dependencies. you can run `bin/spc doctor` first to check whether the system itself lacks dependencies.
@ -230,13 +274,13 @@ bin/spc doctor
bin/spc doctor --auto-fix bin/spc doctor --auto-fix
``` ```
## Command - build ### Command - build
Use the build command to start building the static php binary. Use the build command to start building the static php binary.
Before executing the `bin/spc build` command, be sure to use the `download` command to download sources. Before executing the `bin/spc build` command, be sure to use the `download` command to download sources.
It is recommended to use `doctor` to check the environment. It is recommended to use `doctor` to check the environment.
### Basic build #### Basic build
You need to go to [Extension List](./extensions) or [Command Generator](./cli-generator) to select the extension you want to add, You need to go to [Extension List](./extensions) or [Command Generator](./cli-generator) to select the extension you want to add,
and then use the command `bin/spc build` to compile. and then use the command `bin/spc build` to compile.
@ -283,16 +327,7 @@ bin/spc build bcmath,curl,openssl,ftp,posix,pcntl --build-cli
``` ```
::: :::
### Debug #### Build Options
If you encounter problems during the compilation process, or want to view each executing shell command,
you can use `--debug` to enable debug mode and view all terminal logs:
```bash
bin/spc build mysqlnd,pdo_mysql --build-all --debug
```
### Build Options
During the compilation process, in some special cases, During the compilation process, in some special cases,
the compiler and the content of the compilation directory need to be intervened. the compiler and the content of the compilation directory need to be intervened.
@ -322,6 +357,15 @@ For hardcoding INI options, it works for cli, micro, embed sapi. Here is a simpl
bin/spc build bcmath,pcntl,posix --build-all -I "memory_limit=4G" -I "disable_functions=system" bin/spc build bcmath,pcntl,posix --build-all -I "memory_limit=4G" -I "disable_functions=system"
``` ```
## Debug
If you encounter problems during the compilation process, or want to view each executing shell command,
you can use `--debug` to enable debug mode and view all terminal logs:
```bash
bin/spc build mysqlnd,pdo_mysql --build-all --debug
```
## Command - micro:combine ## Command - micro:combine
Use the `micro:combine` command to build the compiled `micro.sfx` and your code (`.php` or `.phar` file) into an executable binary. Use the `micro:combine` command to build the compiled `micro.sfx` and your code (`.php` or `.phar` file) into an executable binary.

View File

@ -0,0 +1,7 @@
---
aside: false
---
# craft.yml 配置
<!--@include: ../../deps-craft-yml.md-->

View File

@ -1,3 +1,7 @@
---
outline: 'deep'
---
# 本地构建Linux、macOS、FreeBSD # 本地构建Linux、macOS、FreeBSD
本章节为 Linux、macOS、FreeBSD 的构建过程,如果你要在 Windows 上构建,请到 [在 Windows 上构建](./build-on-windows)。 本章节为 Linux、macOS、FreeBSD 的构建过程,如果你要在 Windows 上构建,请到 [在 Windows 上构建](./build-on-windows)。
@ -112,7 +116,45 @@ sudo apt install php-cli composer php-tokenizer
较老版本的 Debian 默认安装的可能为旧版本(<= 8.3)版本的 PHP建议先升级 Debian 或使用 Docker 或自带的静态二进制环境。 较老版本的 Debian 默认安装的可能为旧版本(<= 8.3)版本的 PHP建议先升级 Debian 或使用 Docker 或自带的静态二进制环境。
::: :::
## 命令 download - 下载依赖包 ## 使用 craft 构建(推荐)
使用 `bin/spc craft` 可以使用一个配置文件,一个命令实现自动检查环境、下载源代码、构建依赖库、构建 PHP 及扩展等。
你需要编写一个 `craft.yml` 文件,存放在当前工作目录下。`craft.yml` 可以由 [命令生成器](./cli-generator) 生成,或者手动编写。
手动编写可参考 [craft.yml 配置](../develop/craft-yml.md) 中的注释来编写。我们下面假设你编译一个扩展组合,并选用 PHP 8.4,输出 `cli``fpm`
```yaml
# path/to/craft.yml
php-version: 8.4
extensions: bcmath,posix,phar,zlib,openssl,curl,fileinfo,tokenizer
sapi:
- cli
- fpm
```
然后使用 `bin/spc craft` 命令来编译:
```bash
bin/spc craft --debug
```
如果构建成功,你会在当前目录下看到 `buildroot/bin` 目录,里面包含了编译好的 PHP 二进制文件,或相应的 SAPI。
- cli: Windows 下构建结果为 `buildroot/bin/php.exe`,其他平台为 `buildroot/bin/php`
- fpm: 构建结果为 `buildroot/bin/php-fpm`
- micro: 构建结果为 `buildroot/bin/micro.sfx`,如需进一步与 PHP 代码打包,请查看 [打包 micro 二进制](./manual-build#命令-micro-combine-打包-micro-二进制)。
- embed: 参见 [embed 使用](./manual-build#embed-使用)。
如果中途构建出错,你可以使用 `--debug` 参数查看详细的错误信息,或者使用 `--with-clean` 参数清除旧的编译结果,重新编译。
如使用以上方式仍构建失败,请提交一个 issue附上你的 `craft.yml``craft.log`
## 分步构建命令
如果你有定制化需求,或分开下载、编译 PHP 和依赖库的需求,可以使用 `bin/spc` 命令分步执行。
### 命令 download - 下载依赖包
使用命令 `bin/spc download` 可以下载编译需要的源代码,包括 php-src 以及依赖的各种库的源码。 使用命令 `bin/spc download` 可以下载编译需要的源代码,包括 php-src 以及依赖的各种库的源码。
@ -184,7 +226,7 @@ bin/spc download --for-extensions=redis,phar -G "php-src:master:https://github.c
bin/spc download --for-extensions=swoole -G "swoole:master:https://github.com/swoole/swoole-src.git" bin/spc download --for-extensions=swoole -G "swoole:master:https://github.com/swoole/swoole-src.git"
``` ```
## 命令 doctor - 环境检查 ### 命令 doctor - 环境检查
如果你可以正常运行 `bin/spc` 但无法正常编译静态的 PHP 或依赖库,可以先运行 `bin/spc doctor` 检查系统自身是否缺少依赖。 如果你可以正常运行 `bin/spc` 但无法正常编译静态的 PHP 或依赖库,可以先运行 `bin/spc doctor` 检查系统自身是否缺少依赖。
@ -196,11 +238,11 @@ bin/spc doctor
bin/spc doctor --auto-fix bin/spc doctor --auto-fix
``` ```
## 命令 build - 编译 PHP ### 命令 build - 编译 PHP
使用 build 命令可以开始构建静态 php 二进制,在执行 `bin/spc build` 命令前,务必先使用 `download` 命令下载资源,建议使用 `doctor` 检查环境。 使用 build 命令可以开始构建静态 php 二进制,在执行 `bin/spc build` 命令前,务必先使用 `download` 命令下载资源,建议使用 `doctor` 检查环境。
### 基本用法 #### 基本用法
你需要先到 [扩展列表](./extensions) 或 [命令生成器](./cli-generator) 选择你要加入的扩展,然后使用命令 `bin/spc build` 进行编译。你需要指定一个编译目标,从如下参数中选择: 你需要先到 [扩展列表](./extensions) 或 [命令生成器](./cli-generator) 选择你要加入的扩展,然后使用命令 `bin/spc build` 进行编译。你需要指定一个编译目标,从如下参数中选择:
@ -244,15 +286,7 @@ bin/spc build bcmath,curl,openssl,ftp,posix,pcntl --build-cli
``` ```
::: :::
### 调试 #### 编译运行选项
如果你在编译过程中遇到了问题,或者想查看每个执行的 shell 命令,可以使用 `--debug` 开启 debug 模式,查看所有终端日志:
```bash
bin/spc build mysqlnd,pdo_mysql --build-all --debug
```
### 编译运行选项
在编译过程中,有些特殊情况需要对编译器、编译目录的内容进行干预,可以尝试使用以下命令: 在编译过程中,有些特殊情况需要对编译器、编译目录的内容进行干预,可以尝试使用以下命令:
@ -340,6 +374,14 @@ memory_limit=1G
如果要打包 phar只需要将 `a.php` 替换为打包好的 phar 文件即可。但要注意phar 下的 micro.sfx 需要额外注意路径问题,见 [Developing - Phar 路径问题](../develop/structure#phar-应用目录问题) 如果要打包 phar只需要将 `a.php` 替换为打包好的 phar 文件即可。但要注意phar 下的 micro.sfx 需要额外注意路径问题,见 [Developing - Phar 路径问题](../develop/structure#phar-应用目录问题)
## 调试
如果你在编译过程中遇到了问题,或者想查看每个执行的 shell 命令,可以使用 `--debug` 开启 debug 模式,查看所有终端日志:
```bash
bin/spc build mysqlnd,pdo_mysql --build-all --debug
```
## 命令 extract - 手动解压某个库 ## 命令 extract - 手动解压某个库
使用命令 `bin/spc extract` 可以解包和拷贝编译需要的源代码,包括 php-src 以及依赖的各种库的源码(需要自己指定要解包的库名)。 使用命令 `bin/spc extract` 可以解包和拷贝编译需要的源代码,包括 php-src 以及依赖的各种库的源码(需要自己指定要解包的库名)。

View File

@ -6,6 +6,7 @@ namespace SPC;
use SPC\command\BuildLibsCommand; use SPC\command\BuildLibsCommand;
use SPC\command\BuildPHPCommand; use SPC\command\BuildPHPCommand;
use SPC\command\CraftCommand;
use SPC\command\DeleteDownloadCommand; use SPC\command\DeleteDownloadCommand;
use SPC\command\dev\AllExtCommand; use SPC\command\dev\AllExtCommand;
use SPC\command\dev\ExtVerCommand; use SPC\command\dev\ExtVerCommand;
@ -43,6 +44,8 @@ final class ConsoleApplication extends Application
$this->addCommands( $this->addCommands(
[ [
// Craft command
new CraftCommand(),
// Common commands // Common commands
new BuildPHPCommand(), new BuildPHPCommand(),
new BuildLibsCommand(), new BuildLibsCommand(),

View File

@ -9,6 +9,7 @@ use Laravel\Prompts\Prompt;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
use SPC\ConsoleApplication; use SPC\ConsoleApplication;
use SPC\exception\ExceptionHandler; use SPC\exception\ExceptionHandler;
use SPC\exception\ValidationException;
use SPC\exception\WrongUsageException; use SPC\exception\WrongUsageException;
use SPC\util\GlobalEnvManager; use SPC\util\GlobalEnvManager;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
@ -58,12 +59,12 @@ abstract class BaseCommand extends Command
}); });
$version = ConsoleApplication::VERSION; $version = ConsoleApplication::VERSION;
if (!$this->no_motd) { if (!$this->no_motd) {
echo " _ _ _ _ echo " _ _ _ _
___| |_ __ _| |_(_) ___ _ __ | |__ _ __ ___| |_ __ _| |_(_) ___ _ __ | |__ _ __
/ __| __/ _` | __| |/ __|____| '_ \\| '_ \\| '_ \\ / __| __/ _` | __| |/ __|____| '_ \\| '_ \\| '_ \\
\\__ \\ || (_| | |_| | (_|_____| |_) | | | | |_) | \\__ \\ || (_| | |_| | (_|_____| |_) | | | | |_) |
|___/\\__\\__,_|\\__|_|\\___| | .__/|_| |_| .__/ v{$version} |___/\\__\\__,_|\\__|_|\\___| | .__/|_| |_| .__/ v{$version}
|_| |_| |_| |_|
"; ";
} }
} }
@ -104,7 +105,7 @@ abstract class BaseCommand extends Command
// show raw argv list for logger()->debug // show raw argv list for logger()->debug
logger()->debug('argv: ' . implode(' ', $_SERVER['argv'])); logger()->debug('argv: ' . implode(' ', $_SERVER['argv']));
return $this->handle(); return $this->handle();
} catch (WrongUsageException $e) { } catch (ValidationException|WrongUsageException $e) {
$msg = explode("\n", $e->getMessage()); $msg = explode("\n", $e->getMessage());
foreach ($msg as $v) { foreach ($msg as $v) {
logger()->error($v); logger()->error($v);

View File

@ -0,0 +1,178 @@
<?php
declare(strict_types=1);
namespace SPC\command;
use SPC\exception\ValidationException;
use SPC\util\ConfigValidator;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Process\Process;
#[AsCommand('craft', 'Build static-php from craft.yml')]
class CraftCommand extends BaseCommand
{
public function configure(): void
{
$this->addArgument('craft', null, 'Path to craft.yml file', WORKING_DIR . '/craft.yml');
}
public function handle(): int
{
$craft_file = $this->getArgument('craft');
// Check if the craft.yml file exists
if (!file_exists($craft_file)) {
$this->output->writeln('<error>craft.yml not found, please create one!</error>');
return static::FAILURE;
}
// Check if the craft.yml file is valid
try {
$craft = ConfigValidator::validateAndParseCraftFile($craft_file, $this);
if ($craft['debug']) {
$this->input->setOption('debug', true);
}
} catch (ValidationException $e) {
$this->output->writeln('<error>craft.yml parse error: ' . $e->getMessage() . '</error>');
return static::FAILURE;
}
// Craft!!!
$this->output->writeln('<info>Crafting...</info>');
// apply env
if (isset($craft['extra-env'])) {
$env = $craft['extra-env'];
foreach ($env as $key => $val) {
f_putenv("{$key}={$val}");
}
}
$extensions = implode(',', $craft['extensions']);
$libs = implode(',', $craft['libs']);
// init log
if (file_exists(WORKING_DIR . '/craft.log')) {
unlink(WORKING_DIR . '/craft.log');
}
// craft doctor
if ($craft['craft-options']['doctor']) {
$retcode = $this->runCommand('doctor', '--auto-fix');
if ($retcode !== 0) {
$this->output->writeln('<error>craft doctor failed</error>');
$this->log("craft doctor failed with code: {$retcode}", true);
return static::FAILURE;
}
}
// craft download
if ($craft['craft-options']['download']) {
$args = ["--for-extensions={$extensions}"];
if ($craft['libs'] !== []) {
$args[] = "--for-libs={$libs}";
}
if (isset($craft['php-version'])) {
$args[] = '--with-php=' . $craft['php-version'];
if (!array_key_exists('ignore-cache-sources', $craft['download-options']) || $craft['download-options']['ignore-cache-sources'] === false) {
$craft['download-options']['ignore-cache-sources'] = 'php-src';
} elseif ($craft['download-options']['ignore-cache-sources'] !== null) {
$craft['download-options']['ignore-cache-sources'] .= ',php-src';
}
}
$this->optionsToArguments($craft['download-options'], $args);
$retcode = $this->runCommand('download', ...$args);
if ($retcode !== 0) {
$this->output->writeln('<error>craft download failed</error>');
$this->log('craft download failed with code: ' . $retcode, true);
return static::FAILURE;
}
}
// craft build
if ($craft['craft-options']['build']) {
$args = [$extensions, "--with-libs={$libs}", ...array_map(fn ($x) => "--build-{$x}", $craft['sapi'])];
$this->optionsToArguments($craft['build-options'], $args);
$retcode = $this->runCommand('build', ...$args);
if ($retcode !== 0) {
$this->output->writeln('<error>craft build failed</error>');
$this->log('craft build failed with code: ' . $retcode, true);
return static::FAILURE;
}
}
return 0;
}
public function processLogCallback($type, $buffer): void
{
if ($type === Process::ERR) {
fwrite(STDERR, $buffer);
} else {
fwrite(STDOUT, $buffer);
$this->log($buffer);
}
}
private function log(string $log, bool $master_log = false): void
{
if ($master_log) {
$log = "\n[static-php-cli]> " . $log . "\n\n";
} else {
$log = preg_replace('/\x1b\[[0-9;]*m/', '', $log);
}
file_put_contents('craft.log', $log, FILE_APPEND);
}
private function runCommand(string $cmd, ...$args): int
{
global $argv;
if ($this->getOption('debug')) {
array_unshift($args, '--debug');
}
$prefix = PHP_SAPI === 'cli' ? [PHP_BINARY, $argv[0]] : [$argv[0]];
$process = new Process([...$prefix, $cmd, '--no-motd', ...$args], timeout: null);
$this->log("Running: {$process->getCommandLine()}", true);
if (PHP_OS_FAMILY === 'Windows') {
sapi_windows_set_ctrl_handler(function () use ($process) {
if ($process->isRunning()) {
$process->signal(-1073741510);
}
});
} elseif (extension_loaded('pcntl')) {
pcntl_signal(SIGINT, function () use ($process) {
/* @noinspection PhpComposerExtensionStubsInspection */
$process->signal(SIGINT);
});
} else {
logger()->debug('You have not enabled `pcntl` extension, cannot prevent download file corruption when Ctrl+C');
}
// $process->setTty(true);
$process->run([$this, 'processLogCallback']);
return $process->getExitCode();
}
private function optionsToArguments(array $options, array &$args): void
{
foreach ($options as $option => $val) {
if ((is_bool($val) && $val) || $val === null) {
$args[] = "--{$option}";
continue;
}
if (is_string($val)) {
$args[] = "--{$option}={$val}";
continue;
}
if (is_array($val)) {
foreach ($val as $v) {
if (is_string($v)) {
$args[] = "--{$option}={$v}";
}
}
}
}
}
}

View File

@ -15,18 +15,20 @@ class CurlHook
*/ */
public static function setupGithubToken(string $method, string $url, array &$headers): void public static function setupGithubToken(string $method, string $url, array &$headers): void
{ {
if (!getenv('GITHUB_TOKEN')) { $token = getenv('GITHUB_TOKEN');
if (!$token) {
logger()->debug('no github token found, skip');
return; return;
} }
if (getenv('GITHUB_USER')) { if (getenv('GITHUB_USER')) {
$auth = base64_encode(getenv('GITHUB_USER') . ':' . getenv('GITHUB_TOKEN')); $auth = base64_encode(getenv('GITHUB_USER') . ':' . $token);
$he = "Authorization: Basic {$auth}"; $he = "Authorization: Basic {$auth}";
if (!in_array($he, $headers)) { if (!in_array($he, $headers)) {
$headers[] = $he; $headers[] = $he;
} }
logger()->info("using basic github token for {$method} {$url}"); logger()->info("using basic github token for {$method} {$url}");
} else { } else {
$auth = getenv('GITHUB_TOKEN'); $auth = $token;
$he = "Authorization: Bearer {$auth}"; $he = "Authorization: Bearer {$auth}";
if (!in_array($he, $headers)) { if (!in_array($he, $headers)) {
$headers[] = $he; $headers[] = $he;

View File

@ -5,6 +5,9 @@ declare(strict_types=1);
namespace SPC\util; namespace SPC\util;
use SPC\exception\ValidationException; use SPC\exception\ValidationException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
class ConfigValidator class ConfigValidator
{ {
@ -110,4 +113,123 @@ class ConfigValidator
{ {
is_array($data) || throw new ValidationException('pkg.json is broken'); is_array($data) || throw new ValidationException('pkg.json is broken');
} }
/**
* @param mixed $craft_file craft.yml path
* @param Command $command craft command instance
* @return array{
* php-version?: string,
* extensions: array<string>,
* libs?: array<string>,
* sapi: array<string>,
* debug?: bool,
* clean-build?: bool,
* build-options?: array<string, mixed>,
* download-options?: array<string, mixed>,
* extra-env?: array<string, string>,
* craft-options?: array{
* doctor?: bool,
* download?: bool,
* build?: bool
* }
* }
* @throws ValidationException
*/
public static function validateAndParseCraftFile(mixed $craft_file, Command $command): array
{
$build_options = $command->getApplication()->find('build')->getDefinition()->getOptions();
$download_options = $command->getApplication()->find('download')->getDefinition()->getOptions();
try {
$craft = Yaml::parse(file_get_contents($craft_file));
} catch (ParseException $e) {
throw new ValidationException('Craft file is broken: ' . $e->getMessage());
}
if (!is_assoc_array($craft)) {
throw new ValidationException('Craft file is broken');
}
// check php-version
if (isset($craft['php-version'])) {
// validdate version, accept 8.x, 7.x, 8.x.x, 7.x.x, 8, 7
$version = strval($craft['php-version']);
if (!preg_match('/^(\d+)(\.\d+)?(\.\d+)?$/', $version, $matches)) {
throw new ValidationException('Craft file php-version is invalid');
}
}
// check extensions
if (!isset($craft['extensions'])) {
throw new ValidationException('Craft file must have extensions');
}
if (is_string($craft['extensions'])) {
$craft['extensions'] = array_filter(array_map(fn ($x) => trim($x), explode(',', $craft['extensions'])));
}
// check libs
if (isset($craft['libs']) && is_string($craft['libs'])) {
$craft['libs'] = array_filter(array_map(fn ($x) => trim($x), explode(',', $craft['libs'])));
} elseif (!isset($craft['libs'])) {
$craft['libs'] = [];
}
// check sapi
if (!isset($craft['sapi'])) {
throw new ValidationException('Craft file must have sapi');
}
if (is_string($craft['sapi'])) {
$craft['sapi'] = array_filter(array_map(fn ($x) => trim($x), explode(',', $craft['sapi'])));
}
// debug as boolean
if (isset($craft['debug'])) {
$craft['debug'] = filter_var($craft['debug'], FILTER_VALIDATE_BOOLEAN);
} else {
$craft['debug'] = false;
}
// check clean-build
$craft['clean-build'] ??= false;
// check build-options
if (isset($craft['build-options'])) {
if (!is_assoc_array($craft['build-options'])) {
throw new ValidationException('Craft file build-options must be an object');
}
foreach ($craft['build-options'] as $key => $value) {
if (!isset($build_options[$key])) {
throw new ValidationException("Craft file build-options {$key} is invalid");
}
// check an array
if ($build_options[$key]->isArray() && !is_array($value)) {
throw new ValidationException("Craft file build-options {$key} must be an array");
}
}
} else {
$craft['build-options'] = [];
}
// check download options
if (isset($craft['download-options'])) {
if (!is_assoc_array($craft['download-options'])) {
throw new ValidationException('Craft file download-options must be an object');
}
foreach ($craft['download-options'] as $key => $value) {
if (!isset($download_options[$key])) {
throw new ValidationException("Craft file download-options {$key} is invalid");
}
// check an array
if ($download_options[$key]->isArray() && !is_array($value)) {
throw new ValidationException("Craft file download-options {$key} must be an array");
}
}
} else {
$craft['download-options'] = [];
}
// check extra-env
if (isset($craft['extra-env'])) {
if (!is_assoc_array($craft['extra-env'])) {
throw new ValidationException('Craft file extra-env must be an object');
}
} else {
$craft['extra-env'] = [];
}
// check craft-options
$craft['craft-options']['doctor'] ??= true;
$craft['craft-options']['download'] ??= true;
$craft['craft-options']['build'] ??= true;
return $craft;
}
} }

View File

@ -85,4 +85,4 @@ const AUTOCONF_LDFLAGS = 8;
const AUTOCONF_ALL = 15; const AUTOCONF_ALL = 15;
ConsoleLogger::$date_format = 'H:i:s'; ConsoleLogger::$date_format = 'H:i:s';
ConsoleLogger::$format = '[%date%] [I] %body%'; ConsoleLogger::$format = '[%date%] [%level_short%] %body%';

View File

@ -24,7 +24,7 @@ $test_os = [
'macos-13', 'macos-13',
// 'macos-14', // 'macos-14',
'macos-15', 'macos-15',
'ubuntu-latest', // 'ubuntu-latest',
'ubuntu-22.04', 'ubuntu-22.04',
'ubuntu-24.04', 'ubuntu-24.04',
'ubuntu-22.04-arm', 'ubuntu-22.04-arm',
@ -131,7 +131,7 @@ if ($argv[1] === 'doctor_cmd') {
$doctor_cmd = 'doctor --auto-fix --debug'; $doctor_cmd = 'doctor --auto-fix --debug';
} }
if ($argv[1] === 'install_upx_cmd') { if ($argv[1] === 'install_upx_cmd') {
$install_upx_cmd = 'install-pkg upx'; $install_upx_cmd = 'install-pkg upx --debug';
} }
$prefix = match ($argv[2] ?? null) { $prefix = match ($argv[2] ?? null) {