mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-18 04:44:53 +08:00
Merge branch 'main' into feat/xdebug-dynamic
This commit is contained in:
commit
fc4872c5d6
20
.github/workflows/build-unix.yml
vendored
20
.github/workflows/build-unix.yml
vendored
@ -6,10 +6,13 @@ on:
|
|||||||
os:
|
os:
|
||||||
required: true
|
required: true
|
||||||
description: Build target OS
|
description: Build target OS
|
||||||
|
default: 'linux-x86_64'
|
||||||
type: choice
|
type: choice
|
||||||
options:
|
options:
|
||||||
- 'linux-x86_64'
|
- 'linux-x86_64'
|
||||||
- 'linux-aarch64'
|
- 'linux-aarch64'
|
||||||
|
- 'linux-x86_64-glibc'
|
||||||
|
- 'linux-aarch64-glibc'
|
||||||
- 'macos-x86_64'
|
- 'macos-x86_64'
|
||||||
- 'macos-aarch64'
|
- 'macos-aarch64'
|
||||||
php-version:
|
php-version:
|
||||||
@ -22,7 +25,6 @@ on:
|
|||||||
- '8.3'
|
- '8.3'
|
||||||
- '8.2'
|
- '8.2'
|
||||||
- '8.1'
|
- '8.1'
|
||||||
- '8.0'
|
|
||||||
extensions:
|
extensions:
|
||||||
description: Extensions to build (comma separated)
|
description: Extensions to build (comma separated)
|
||||||
required: true
|
required: true
|
||||||
@ -77,9 +79,19 @@ jobs:
|
|||||||
RUNS_ON="ubuntu-latest"
|
RUNS_ON="ubuntu-latest"
|
||||||
;;
|
;;
|
||||||
linux-aarch64)
|
linux-aarch64)
|
||||||
DOWN_CMD="SPC_USE_ARCH=aarch64 ./bin/spc-alpine-docker download"
|
DOWN_CMD="./bin/spc-alpine-docker download"
|
||||||
BUILD_CMD="SPC_USE_ARCH=aarch64 ./bin/spc-alpine-docker build"
|
BUILD_CMD="./bin/spc-alpine-docker build"
|
||||||
RUNS_ON="ubuntu-latest"
|
RUNS_ON="ubuntu-24.04-arm"
|
||||||
|
;;
|
||||||
|
linux-x86_64-glibc)
|
||||||
|
DOWN_CMD="./bin/spc-gnu-docker download"
|
||||||
|
BUILD_CMD="./bin/spc-gnu-docker build"
|
||||||
|
RUNS_ON="ubuntu-22.04"
|
||||||
|
;;
|
||||||
|
linux-aarch64-glibc)
|
||||||
|
DOWN_CMD="./bin/spc-gnu-docker download"
|
||||||
|
BUILD_CMD="./bin/spc-gnu-docker build"
|
||||||
|
RUNS_ON="ubuntu-22.04-arm"
|
||||||
;;
|
;;
|
||||||
macos-x86_64)
|
macos-x86_64)
|
||||||
DOWN_CMD="composer update --no-dev --classmap-authoritative && ./bin/spc doctor --auto-fix && ./bin/spc download"
|
DOWN_CMD="composer update --no-dev --classmap-authoritative && ./bin/spc doctor --auto-fix && ./bin/spc download"
|
||||||
|
|||||||
10
.github/workflows/tests.yml
vendored
10
.github/workflows/tests.yml
vendored
@ -176,18 +176,18 @@ jobs:
|
|||||||
run: composer update -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
run: composer update -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
|
||||||
|
|
||||||
- name: "Run Build Tests (doctor)"
|
- name: "Run Build Tests (doctor)"
|
||||||
run: bin/spc doctor --auto-fix --debug
|
run: php src/globals/test-extensions.php doctor_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||||
|
|
||||||
- name: "Prepare UPX for Windows"
|
- name: "Prepare UPX for Windows"
|
||||||
if: matrix.os == 'windows-latest'
|
if: ${{ startsWith(matrix.os, 'windows-') }}
|
||||||
run: |
|
run: |
|
||||||
bin/spc install-pkg upx
|
php src/globals/test-extensions.php install_upx_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||||
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $env:GITHUB_ENV
|
echo "UPX_CMD=$(php src/globals/test-extensions.php upx)" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
- name: "Prepare UPX for Linux"
|
- name: "Prepare UPX for Linux"
|
||||||
if: matrix.os == 'ubunut-latest'
|
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
|
||||||
run: |
|
run: |
|
||||||
bin/spc install-pkg upx
|
php src/globals/test-extensions.php install_upx_cmd ${{ matrix.os }} ${{ matrix.php }}
|
||||||
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)"
|
||||||
|
|||||||
@ -95,7 +95,7 @@ WORKDIR /app
|
|||||||
ADD ./src /app/src
|
ADD ./src /app/src
|
||||||
COPY ./composer.* /app/
|
COPY ./composer.* /app/
|
||||||
ADD ./bin /app/bin
|
ADD ./bin /app/bin
|
||||||
RUN composer install --no-dev --classmap-authoritative
|
RUN composer install --no-dev
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@ -145,7 +145,6 @@ echo 'SPC_CMD_VAR_PHP_MAKE_EXTRA_LIBS="-ldl -lpthread -lm -lresolv -lutil -lrt"'
|
|||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
# shellcheck disable=SC2090
|
# shellcheck disable=SC2090
|
||||||
|
|
||||||
|
|
||||||
if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
|
if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
|
||||||
echo "* Debug mode enabled, run docker in interactive mode."
|
echo "* Debug mode enabled, run docker in interactive mode."
|
||||||
echo "* You can use 'exit' to exit the docker container."
|
echo "* You can use 'exit' to exit the docker container."
|
||||||
@ -161,7 +160,8 @@ if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
|
|||||||
echo "* ./pkgroot: $(pwd)/pkgroot"
|
echo "* ./pkgroot: $(pwd)/pkgroot"
|
||||||
echo "*"
|
echo "*"
|
||||||
|
|
||||||
$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
|
if [ "$SPC_DOCKER_DEBUG" = "yes" ]; then
|
||||||
|
$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
|
||||||
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 -e SPC_FIX_DEPLOY_ROOT="$(pwd)" --env-file /tmp/spc-gnu-docker.env $MOUNT_LIST cwcc-spc-gnu-$SPC_USE_ARCH bin/spc $@
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"repo": "static-php/static-php-cli-hosted",
|
"repo": "static-php/static-php-cli-hosted",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"match-pattern": "{name}-{arch}-{os}.txz",
|
"match-pattern-linux": "{name}-{arch}-{os}-{libc}-{libcver}.txz",
|
||||||
"suffix": "txz"
|
"match-pattern": "{name}-{arch}-{os}.txz"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use SPC\exception\FileSystemException;
|
|||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
use SPC\store\Config;
|
use SPC\store\Config;
|
||||||
|
use SPC\store\Downloader;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use SPC\store\SourceManager;
|
use SPC\store\SourceManager;
|
||||||
|
|
||||||
@ -45,8 +46,9 @@ abstract class LibraryBase
|
|||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
$source = Config::getLib(static::NAME, 'source');
|
$source = Config::getLib(static::NAME, 'source');
|
||||||
// if source is locked as pre-built, we just tryInstall it
|
// if source is locked as pre-built, we just tryInstall it
|
||||||
if (isset($lock[$source]) && ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
|
$pre_built_name = Downloader::getPreBuiltLockName($source);
|
||||||
return $this->tryInstall($lock[$source]['filename'], $force);
|
if (isset($lock[$pre_built_name]) && ($lock[$pre_built_name]['lock_as'] ?? SPC_DOWNLOAD_SOURCE) === SPC_DOWNLOAD_PRE_BUILT) {
|
||||||
|
return $this->tryInstall($lock[$pre_built_name]['filename'], $force);
|
||||||
}
|
}
|
||||||
return $this->tryBuild($force);
|
return $this->tryBuild($force);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -182,4 +182,39 @@ class SystemUtil
|
|||||||
'arch', 'manjaro',
|
'arch', 'manjaro',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get libc version string from ldd
|
||||||
|
*/
|
||||||
|
public static function getLibcVersionIfExists(): ?string
|
||||||
|
{
|
||||||
|
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'glibc') {
|
||||||
|
$result = shell()->execWithResult('ldd --version', false);
|
||||||
|
if ($result[0] !== 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// get first line
|
||||||
|
$first_line = $result[1][0];
|
||||||
|
// match ldd version: "ldd (some useless text) 2.17" match 2.17
|
||||||
|
$pattern = '/ldd\s+\(.*?\)\s+(\d+\.\d+)/';
|
||||||
|
if (preg_match($pattern, $first_line, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') {
|
||||||
|
if (self::isMuslDist()) {
|
||||||
|
$result = shell()->execWithResult('ldd 2>&1', false);
|
||||||
|
} else {
|
||||||
|
$result = shell()->execWithResult('/usr/local/musl/lib/libc.so 2>&1', false);
|
||||||
|
}
|
||||||
|
// Match Version * line
|
||||||
|
// match ldd version: "Version 1.2.3" match 1.2.3
|
||||||
|
$pattern = '/Version\s+(\d+\.\d+\.\d+)/';
|
||||||
|
if (preg_match($pattern, $result[1][1] ?? '', $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ namespace SPC\command;
|
|||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\WrongUsageException;
|
use SPC\exception\WrongUsageException;
|
||||||
|
use SPC\store\Downloader;
|
||||||
use SPC\store\FileSystem;
|
use SPC\store\FileSystem;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
@ -47,30 +48,35 @@ class DeleteDownloadCommand extends BaseCommand
|
|||||||
$chosen_sources = $sources;
|
$chosen_sources = $sources;
|
||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
|
|
||||||
|
$deleted_sources = [];
|
||||||
foreach ($chosen_sources as $source) {
|
foreach ($chosen_sources as $source) {
|
||||||
$source = trim($source);
|
$source = trim($source);
|
||||||
if (!isset($lock[$source])) {
|
foreach ([$source, Downloader::getPreBuiltLockName($source)] as $name) {
|
||||||
logger()->warning("Source/Package [{$source}] not locked or not downloaded, skipped.");
|
if (isset($lock[$name])) {
|
||||||
continue;
|
$deleted_sources[] = $name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($deleted_sources as $lock_name) {
|
||||||
// remove download file/dir if exists
|
// remove download file/dir if exists
|
||||||
if ($lock[$source]['source_type'] === 'archive') {
|
if ($lock[$lock_name]['source_type'] === 'archive') {
|
||||||
if (file_exists($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$source]['filename']))) {
|
if (file_exists($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$lock_name]['filename']))) {
|
||||||
logger()->info('Deleting file ' . $path);
|
logger()->info('Deleting file ' . $path);
|
||||||
unlink($path);
|
unlink($path);
|
||||||
} else {
|
} else {
|
||||||
logger()->warning("Source/Package [{$source}] file not found, skip deleting file.");
|
logger()->warning("Source/Package [{$lock_name}] file not found, skip deleting file.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_dir($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$source]['dirname']))) {
|
if (is_dir($path = FileSystem::convertPath(DOWNLOAD_PATH . '/' . $lock[$lock_name]['dirname']))) {
|
||||||
logger()->info('Deleting dir ' . $path);
|
logger()->info('Deleting dir ' . $path);
|
||||||
FileSystem::removeDir($path);
|
FileSystem::removeDir($path);
|
||||||
} else {
|
} else {
|
||||||
logger()->warning("Source/Package [{$source}] directory not found, skip deleting dir.");
|
logger()->warning("Source/Package [{$lock_name}] directory not found, skip deleting dir.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove locked sources
|
// remove locked sources
|
||||||
unset($lock[$source]);
|
unset($lock[$lock_name]);
|
||||||
}
|
}
|
||||||
FileSystem::writeFile(DOWNLOAD_PATH . '/.lock.json', json_encode($lock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
FileSystem::writeFile(DOWNLOAD_PATH . '/.lock.json', json_encode($lock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||||
logger()->info('Delete success!');
|
logger()->info('Delete success!');
|
||||||
|
|||||||
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\command;
|
namespace SPC\command;
|
||||||
|
|
||||||
|
use SPC\builder\linux\SystemUtil;
|
||||||
use SPC\builder\traits\UnixSystemUtilTrait;
|
use SPC\builder\traits\UnixSystemUtilTrait;
|
||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
@ -212,7 +213,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
if (isset($config['filename'])) {
|
if (isset($config['filename'])) {
|
||||||
$new_config['filename'] = $config['filename'];
|
$new_config['filename'] = $config['filename'];
|
||||||
}
|
}
|
||||||
logger()->info("Fetching source {$source} from custom url [{$ni}/{$cnt}]");
|
logger()->info("[{$ni}/{$cnt}] Downloading source {$source} from custom url: {$new_config['url']}");
|
||||||
Downloader::downloadSource($source, $new_config, true);
|
Downloader::downloadSource($source, $new_config, true);
|
||||||
} elseif (isset($custom_gits[$source])) {
|
} elseif (isset($custom_gits[$source])) {
|
||||||
$config = Config::getSource($source);
|
$config = Config::getSource($source);
|
||||||
@ -224,23 +225,30 @@ class DownloadCommand extends BaseCommand
|
|||||||
if (isset($config['path'])) {
|
if (isset($config['path'])) {
|
||||||
$new_config['path'] = $config['path'];
|
$new_config['path'] = $config['path'];
|
||||||
}
|
}
|
||||||
logger()->info("Fetching source {$source} from custom git [{$ni}/{$cnt}]");
|
logger()->info("[{$ni}/{$cnt}] Downloading source {$source} from custom git: {$new_config['url']}");
|
||||||
Downloader::downloadSource($source, $new_config, true);
|
Downloader::downloadSource($source, $new_config, true);
|
||||||
} else {
|
} else {
|
||||||
$config = Config::getSource($source);
|
$config = Config::getSource($source);
|
||||||
// Prefer pre-built, we need to search pre-built library
|
// Prefer pre-built, we need to search pre-built library
|
||||||
if ($this->getOption('prefer-pre-built') && ($config['provide-pre-built'] ?? false) === true) {
|
if ($this->getOption('prefer-pre-built') && ($config['provide-pre-built'] ?? false) === true) {
|
||||||
// We need to replace pattern
|
// We need to replace pattern
|
||||||
$find = str_replace(['{name}', '{arch}', '{os}'], [$source, arch2gnu(php_uname('m')), strtolower(PHP_OS_FAMILY)], Config::getPreBuilt('match-pattern'));
|
$replace = [
|
||||||
|
'{name}' => $source,
|
||||||
|
'{arch}' => arch2gnu(php_uname('m')),
|
||||||
|
'{os}' => strtolower(PHP_OS_FAMILY),
|
||||||
|
'{libc}' => getenv('SPC_LIBC') ?: 'default',
|
||||||
|
'{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default',
|
||||||
|
];
|
||||||
|
$find = str_replace(array_keys($replace), array_values($replace), Config::getPreBuilt('match-pattern'));
|
||||||
// find filename in asset list
|
// find filename in asset list
|
||||||
if (($url = $this->findPreBuilt($pre_built_libs, $find)) !== null) {
|
if (($url = $this->findPreBuilt($pre_built_libs, $find)) !== null) {
|
||||||
logger()->info("Fetching pre-built content {$source} [{$ni}/{$cnt}]");
|
logger()->info("[{$ni}/{$cnt}] Downloading pre-built content {$source}");
|
||||||
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_LOCK_PRE_BUILT);
|
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_DOWNLOAD_PRE_BUILT);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
|
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
|
||||||
}
|
}
|
||||||
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
|
logger()->info("[{$ni}/{$cnt}] Downloading source {$source}");
|
||||||
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
|
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,6 +360,7 @@ class DownloadCommand extends BaseCommand
|
|||||||
*/
|
*/
|
||||||
private function findPreBuilt(array $assets, string $filename): ?string
|
private function findPreBuilt(array $assets, string $filename): ?string
|
||||||
{
|
{
|
||||||
|
logger()->debug("Finding pre-built asset {$filename}");
|
||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
if ($asset['name'] === $filename) {
|
if ($asset['name'] === $filename) {
|
||||||
return $asset['browser_download_url'];
|
return $asset['browser_download_url'];
|
||||||
|
|||||||
@ -6,6 +6,7 @@ namespace SPC\command\dev;
|
|||||||
|
|
||||||
use SPC\builder\BuilderProvider;
|
use SPC\builder\BuilderProvider;
|
||||||
use SPC\builder\LibraryBase;
|
use SPC\builder\LibraryBase;
|
||||||
|
use SPC\builder\linux\SystemUtil;
|
||||||
use SPC\command\BuildCommand;
|
use SPC\command\BuildCommand;
|
||||||
use SPC\exception\ExceptionHandler;
|
use SPC\exception\ExceptionHandler;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
@ -23,6 +24,7 @@ class PackLibCommand extends BuildCommand
|
|||||||
public function configure(): void
|
public function configure(): void
|
||||||
{
|
{
|
||||||
$this->addArgument('library', InputArgument::REQUIRED, 'The library will be compiled');
|
$this->addArgument('library', InputArgument::REQUIRED, 'The library will be compiled');
|
||||||
|
$this->addOption('show-libc-ver', null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
@ -47,7 +49,7 @@ class PackLibCommand extends BuildCommand
|
|||||||
// Get lock info
|
// Get lock info
|
||||||
$lock = json_decode(file_get_contents(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
$lock = json_decode(file_get_contents(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
$source = Config::getLib($lib->getName(), 'source');
|
$source = Config::getLib($lib->getName(), 'source');
|
||||||
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_PRE_BUILT) {
|
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_DOWNLOAD_SOURCE) === SPC_DOWNLOAD_PRE_BUILT) {
|
||||||
logger()->critical("The library {$lib->getName()} is downloaded as pre-built, we need to build it instead of installing pre-built.");
|
logger()->critical("The library {$lib->getName()} is downloaded as pre-built, we need to build it instead of installing pre-built.");
|
||||||
return static::FAILURE;
|
return static::FAILURE;
|
||||||
}
|
}
|
||||||
@ -69,7 +71,16 @@ class PackLibCommand extends BuildCommand
|
|||||||
// write list to packlib_files.txt
|
// write list to packlib_files.txt
|
||||||
FileSystem::writeFile(WORKING_DIR . '/packlib_files.txt', implode("\n", $increase_files));
|
FileSystem::writeFile(WORKING_DIR . '/packlib_files.txt', implode("\n", $increase_files));
|
||||||
// pack
|
// pack
|
||||||
$filename = WORKING_DIR . '/dist/' . $lib->getName() . '-' . arch2gnu(php_uname('m')) . '-' . strtolower(PHP_OS_FAMILY) . '.' . Config::getPreBuilt('suffix');
|
$filename = Config::getPreBuilt('match-pattern');
|
||||||
|
$replace = [
|
||||||
|
'{name}' => $lib->getName(),
|
||||||
|
'{arch}' => arch2gnu(php_uname('m')),
|
||||||
|
'{os}' => strtolower(PHP_OS_FAMILY),
|
||||||
|
'{libc}' => getenv('SPC_LIBC') ?: 'default',
|
||||||
|
'{libcver}' => PHP_OS_FAMILY === 'Linux' ? (SystemUtil::getLibcVersionIfExists() ?? 'default') : 'default',
|
||||||
|
];
|
||||||
|
$filename = str_replace(array_keys($replace), array_values($replace), $filename);
|
||||||
|
$filename = WORKING_DIR . '/dist/' . $filename;
|
||||||
f_passthru('tar -czf ' . $filename . ' -T ' . WORKING_DIR . '/packlib_files.txt');
|
f_passthru('tar -czf ' . $filename . ' -T ' . WORKING_DIR . '/packlib_files.txt');
|
||||||
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
|
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,11 +22,30 @@ class Config
|
|||||||
|
|
||||||
public static ?array $pre_built = null;
|
public static ?array $pre_built = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws WrongUsageException
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
public static function getPreBuilt(string $name): mixed
|
public static function getPreBuilt(string $name): mixed
|
||||||
{
|
{
|
||||||
if (self::$pre_built === null) {
|
if (self::$pre_built === null) {
|
||||||
self::$pre_built = FileSystem::loadConfigArray('pre-built');
|
self::$pre_built = FileSystem::loadConfigArray('pre-built');
|
||||||
}
|
}
|
||||||
|
$supported_sys_based = ['match-pattern', 'prefer-stable', 'repo'];
|
||||||
|
if (in_array($name, $supported_sys_based)) {
|
||||||
|
$m_key = match (PHP_OS_FAMILY) {
|
||||||
|
'Windows' => ['-windows', '-win', ''],
|
||||||
|
'Darwin' => ['-macos', '-unix', ''],
|
||||||
|
'Linux' => ['-linux', '-unix', ''],
|
||||||
|
'BSD' => ['-freebsd', '-bsd', '-unix', ''],
|
||||||
|
default => throw new WrongUsageException('OS ' . PHP_OS_FAMILY . ' is not supported'),
|
||||||
|
};
|
||||||
|
foreach ($m_key as $v) {
|
||||||
|
if (isset(self::$pre_built["{$name}{$v}"])) {
|
||||||
|
return self::$pre_built["{$name}{$v}"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return self::$pre_built[$name] ?? null;
|
return self::$pre_built[$name] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace SPC\store;
|
namespace SPC\store;
|
||||||
|
|
||||||
|
use SPC\builder\linux\SystemUtil;
|
||||||
use SPC\exception\DownloaderException;
|
use SPC\exception\DownloaderException;
|
||||||
use SPC\exception\FileSystemException;
|
use SPC\exception\FileSystemException;
|
||||||
use SPC\exception\RuntimeException;
|
use SPC\exception\RuntimeException;
|
||||||
@ -124,6 +125,7 @@ class Downloader
|
|||||||
if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) {
|
if (($source['prefer-stable'] ?? false) === true && $release['prerelease'] === true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
logger()->debug("Found {$release['name']} releases assets");
|
||||||
if (!$match_result) {
|
if (!$match_result) {
|
||||||
return $release['assets'];
|
return $release['assets'];
|
||||||
}
|
}
|
||||||
@ -189,7 +191,7 @@ class Downloader
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $lock_as = SPC_LOCK_SOURCE): void
|
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $download_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
logger()->debug("Downloading {$url}");
|
logger()->debug("Downloading {$url}");
|
||||||
$cancel_func = function () use ($filename) {
|
$cancel_func = function () use ($filename) {
|
||||||
@ -202,12 +204,23 @@ class Downloader
|
|||||||
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: self::getRetryTime());
|
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: self::getRetryTime());
|
||||||
self::unregisterCancelEvent();
|
self::unregisterCancelEvent();
|
||||||
logger()->debug("Locking {$filename}");
|
logger()->debug("Locking {$filename}");
|
||||||
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $lock_as]);
|
if ($download_as === SPC_DOWNLOAD_PRE_BUILT) {
|
||||||
|
$name = self::getPreBuiltLockName($name);
|
||||||
|
}
|
||||||
|
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $download_as]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to lock source.
|
* Try to lock source.
|
||||||
*
|
*
|
||||||
|
* @param string $name Source name
|
||||||
|
* @param array{
|
||||||
|
* source_type: string,
|
||||||
|
* dirname: ?string,
|
||||||
|
* filename: ?string,
|
||||||
|
* move_path: ?string,
|
||||||
|
* lock_as: int
|
||||||
|
* } $data Source data
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public static function lockSource(string $name, array $data): void
|
public static function lockSource(string $name, array $data): void
|
||||||
@ -228,7 +241,7 @@ class Downloader
|
|||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_LOCK_SOURCE): void
|
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
|
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
|
||||||
if (file_exists($download_path)) {
|
if (file_exists($download_path)) {
|
||||||
@ -246,6 +259,7 @@ class Downloader
|
|||||||
self::registerCancelEvent($cancel_func);
|
self::registerCancelEvent($cancel_func);
|
||||||
f_passthru(
|
f_passthru(
|
||||||
SPC_GIT_EXEC . ' clone' . $check .
|
SPC_GIT_EXEC . ' clone' . $check .
|
||||||
|
(defined('DEBUG_MODE') ? '' : ' --quiet') .
|
||||||
' --config core.autocrlf=false ' .
|
' --config core.autocrlf=false ' .
|
||||||
"--branch \"{$branch}\" " . (defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '') . " --recursive \"{$url}\" \"{$download_path}\""
|
"--branch \"{$branch}\" " . (defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '') . " --recursive \"{$url}\" \"{$download_path}\""
|
||||||
);
|
);
|
||||||
@ -283,8 +297,22 @@ class Downloader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param string $name Package name
|
||||||
|
* @param null|array{
|
||||||
|
* type: string,
|
||||||
|
* repo: ?string,
|
||||||
|
* url: ?string,
|
||||||
|
* rev: ?string,
|
||||||
|
* path: ?string,
|
||||||
|
* filename: ?string,
|
||||||
|
* match: ?string,
|
||||||
|
* prefer-stable: ?bool,
|
||||||
|
* extract-files: ?array<string, string>
|
||||||
|
* } $pkg Package config
|
||||||
|
* @param bool $force Download all the time even if it exists
|
||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public static function downloadPackage(string $name, ?array $pkg = null, bool $force = false): void
|
public static function downloadPackage(string $name, ?array $pkg = null, bool $force = false): void
|
||||||
{
|
{
|
||||||
@ -301,50 +329,36 @@ class Downloader
|
|||||||
FileSystem::createDir(DOWNLOAD_PATH);
|
FileSystem::createDir(DOWNLOAD_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load lock file
|
if (self::isAlreadyDownloaded($name, $force, SPC_DOWNLOAD_PACKAGE)) {
|
||||||
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
return;
|
||||||
$lock = [];
|
|
||||||
} else {
|
|
||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
|
||||||
}
|
|
||||||
// If lock file exists, skip downloading
|
|
||||||
if (isset($lock[$name]) && !$force) {
|
|
||||||
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
|
|
||||||
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['filename']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])) {
|
|
||||||
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['dirname']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch ($pkg['type']) {
|
switch ($pkg['type']) {
|
||||||
case 'bitbuckettag': // BitBucket Tag
|
case 'bitbuckettag': // BitBucket Tag
|
||||||
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
|
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'ghtar': // GitHub Release (tar)
|
case 'ghtar': // GitHub Release (tar)
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
|
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'ghtagtar': // GitHub Tag (tar)
|
case 'ghtagtar': // GitHub Tag (tar)
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
|
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'ghrel': // GitHub Release (uploaded)
|
case 'ghrel': // GitHub Release (uploaded)
|
||||||
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
|
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'filelist': // Basic File List (regex based crawler)
|
case 'filelist': // Basic File List (regex based crawler)
|
||||||
[$url, $filename] = self::getFromFileList($name, $pkg);
|
[$url, $filename] = self::getFromFileList($name, $pkg);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'url': // Direct download URL
|
case 'url': // Direct download URL
|
||||||
$url = $pkg['url'];
|
$url = $pkg['url'];
|
||||||
$filename = $pkg['filename'] ?? basename($pkg['url']);
|
$filename = $pkg['filename'] ?? basename($pkg['url']);
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
|
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 'git': // Git repo
|
case 'git': // Git repo
|
||||||
self::downloadGit(
|
self::downloadGit(
|
||||||
@ -353,7 +367,7 @@ class Downloader
|
|||||||
$pkg['rev'],
|
$pkg['rev'],
|
||||||
$pkg['extract'] ?? null,
|
$pkg['extract'] ?? null,
|
||||||
self::getRetryTime(),
|
self::getRetryTime(),
|
||||||
SPC_LOCK_PRE_BUILT
|
SPC_DOWNLOAD_PRE_BUILT
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'custom': // Custom download method, like API-based download or other
|
case 'custom': // Custom download method, like API-based download or other
|
||||||
@ -382,15 +396,30 @@ class Downloader
|
|||||||
/**
|
/**
|
||||||
* Download source by name and meta.
|
* Download source by name and meta.
|
||||||
*
|
*
|
||||||
* @param string $name source name
|
* @param string $name source name
|
||||||
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
|
* @param null|array{
|
||||||
* @param bool $force Whether to force download (default: false)
|
* type: string,
|
||||||
* @param int $lock_as Lock source type (default: SPC_LOCK_SOURCE)
|
* repo: ?string,
|
||||||
|
* url: ?string,
|
||||||
|
* rev: ?string,
|
||||||
|
* path: ?string,
|
||||||
|
* filename: ?string,
|
||||||
|
* match: ?string,
|
||||||
|
* prefer-stable: ?bool,
|
||||||
|
* provide-pre-built: ?bool,
|
||||||
|
* license: array{
|
||||||
|
* type: string,
|
||||||
|
* path: ?string,
|
||||||
|
* text: ?string
|
||||||
|
* }
|
||||||
|
* } $source source meta info: [type, path, rev, url, filename, regex, license]
|
||||||
|
* @param bool $force Whether to force download (default: false)
|
||||||
|
* @param int $download_as Lock source type (default: SPC_LOCK_SOURCE)
|
||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
* @throws WrongUsageException
|
* @throws WrongUsageException
|
||||||
*/
|
*/
|
||||||
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $lock_as = SPC_LOCK_SOURCE): void
|
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $download_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
if ($source === null) {
|
if ($source === null) {
|
||||||
$source = Config::getSource($name);
|
$source = Config::getSource($name);
|
||||||
@ -406,49 +435,36 @@ class Downloader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// load lock file
|
// load lock file
|
||||||
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
if (self::isAlreadyDownloaded($name, $force, $download_as)) {
|
||||||
$lock = [];
|
return;
|
||||||
} else {
|
|
||||||
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
|
||||||
}
|
|
||||||
// If lock file exists, skip downloading
|
|
||||||
if (isset($lock[$name]) && !$force && ($lock[$name]['lock_as'] ?? SPC_LOCK_SOURCE) === $lock_as) {
|
|
||||||
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
|
|
||||||
logger()->notice("source [{$name}] already downloaded: " . $lock[$name]['filename']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])) {
|
|
||||||
logger()->notice("source [{$name}] already downloaded: " . $lock[$name]['dirname']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch ($source['type']) {
|
switch ($source['type']) {
|
||||||
case 'bitbuckettag': // BitBucket Tag
|
case 'bitbuckettag': // BitBucket Tag
|
||||||
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
|
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'ghtar': // GitHub Release (tar)
|
case 'ghtar': // GitHub Release (tar)
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $source);
|
[$url, $filename] = self::getLatestGithubTarball($name, $source);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'ghtagtar': // GitHub Tag (tar)
|
case 'ghtagtar': // GitHub Tag (tar)
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
|
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'ghrel': // GitHub Release (uploaded)
|
case 'ghrel': // GitHub Release (uploaded)
|
||||||
[$url, $filename] = self::getLatestGithubRelease($name, $source);
|
[$url, $filename] = self::getLatestGithubRelease($name, $source);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'filelist': // Basic File List (regex based crawler)
|
case 'filelist': // Basic File List (regex based crawler)
|
||||||
[$url, $filename] = self::getFromFileList($name, $source);
|
[$url, $filename] = self::getFromFileList($name, $source);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'url': // Direct download URL
|
case 'url': // Direct download URL
|
||||||
$url = $source['url'];
|
$url = $source['url'];
|
||||||
$filename = $source['filename'] ?? basename($source['url']);
|
$filename = $source['filename'] ?? basename($source['url']);
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
|
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
||||||
break;
|
break;
|
||||||
case 'git': // Git repo
|
case 'git': // Git repo
|
||||||
self::downloadGit(
|
self::downloadGit(
|
||||||
@ -457,14 +473,14 @@ class Downloader
|
|||||||
$source['rev'],
|
$source['rev'],
|
||||||
$source['path'] ?? null,
|
$source['path'] ?? null,
|
||||||
self::getRetryTime(),
|
self::getRetryTime(),
|
||||||
$lock_as
|
$download_as
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'custom': // Custom download method, like API-based download or other
|
case 'custom': // Custom download method, like API-based download or other
|
||||||
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
|
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
|
||||||
foreach ($classes as $class) {
|
foreach ($classes as $class) {
|
||||||
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
||||||
(new $class())->fetch($force, $source, $lock_as);
|
(new $class())->fetch($force, $source, $download_as);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -579,6 +595,11 @@ class Downloader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getPreBuiltLockName(string $source): string
|
||||||
|
{
|
||||||
|
return "{$source}-" . PHP_OS_FAMILY . '-' . getenv('GNU_ARCH') . '-' . (getenv('SPC_LIBC') ?: 'default') . '-' . (SystemUtil::getLibcVersionIfExists() ?? 'default');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register CTRL+C event for different OS.
|
* Register CTRL+C event for different OS.
|
||||||
*
|
*
|
||||||
@ -611,4 +632,39 @@ class Downloader
|
|||||||
{
|
{
|
||||||
return intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0);
|
return intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws FileSystemException
|
||||||
|
*/
|
||||||
|
private static function isAlreadyDownloaded(string $name, bool $force, int $download_as = SPC_DOWNLOAD_SOURCE): bool
|
||||||
|
{
|
||||||
|
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
|
||||||
|
$lock = [];
|
||||||
|
} else {
|
||||||
|
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||||
|
}
|
||||||
|
// If lock file exists, skip downloading for source mode
|
||||||
|
if (!$force && $download_as === SPC_DOWNLOAD_SOURCE && isset($lock[$name])) {
|
||||||
|
if (
|
||||||
|
$lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename']) ||
|
||||||
|
$lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])
|
||||||
|
) {
|
||||||
|
logger()->notice("Source [{$name}] already downloaded: " . ($lock[$name]['filename'] ?? $lock[$name]['dirname']));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If lock file exists for current arch and glibc target, skip downloading
|
||||||
|
|
||||||
|
if (!$force && $download_as === SPC_DOWNLOAD_PRE_BUILT && isset($lock[$lock_name = self::getPreBuiltLockName($name)])) {
|
||||||
|
// lock name with env
|
||||||
|
if (
|
||||||
|
$lock[$lock_name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$lock_name]['filename']) ||
|
||||||
|
$lock[$lock_name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$lock_name]['dirname'])
|
||||||
|
) {
|
||||||
|
logger()->notice("Pre-built content [{$name}] already downloaded: " . ($lock[$lock_name]['filename'] ?? $lock[$lock_name]['dirname']));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,15 +54,22 @@ class SourceManager
|
|||||||
if (Config::getSource($source) === null) {
|
if (Config::getSource($source) === null) {
|
||||||
throw new WrongUsageException("Source [{$source}] does not exist, please check the name and correct it !");
|
throw new WrongUsageException("Source [{$source}] does not exist, please check the name and correct it !");
|
||||||
}
|
}
|
||||||
if (!isset($lock[$source])) {
|
// check source downloaded
|
||||||
throw new WrongUsageException('Source [' . $source . '] not downloaded or not locked, you should download it first !');
|
$pre_built_name = Downloader::getPreBuiltLockName($source);
|
||||||
|
if (!isset($lock[$pre_built_name])) {
|
||||||
|
if (!isset($lock[$source])) {
|
||||||
|
throw new WrongUsageException("Source [{$source}] not downloaded or not locked, you should download it first !");
|
||||||
|
}
|
||||||
|
$lock_name = $source;
|
||||||
|
} else {
|
||||||
|
$lock_name = $pre_built_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check source dir exist
|
// check source dir exist
|
||||||
$check = $lock[$source]['move_path'] === null ? (SOURCE_PATH . '/' . $source) : (SOURCE_PATH . '/' . $lock[$source]['move_path']);
|
$check = $lock[$lock_name]['move_path'] === null ? (SOURCE_PATH . '/' . $source) : (SOURCE_PATH . '/' . $lock[$lock_name]['move_path']);
|
||||||
if (!is_dir($check)) {
|
if (!is_dir($check)) {
|
||||||
logger()->debug('Extracting source [' . $source . '] to ' . $check . ' ...');
|
logger()->debug('Extracting source [' . $source . '] to ' . $check . ' ...');
|
||||||
FileSystem::extractSource($source, DOWNLOAD_PATH . '/' . ($lock[$source]['filename'] ?? $lock[$source]['dirname']), $lock[$source]['move_path']);
|
FileSystem::extractSource($source, DOWNLOAD_PATH . '/' . ($lock[$lock_name]['filename'] ?? $lock[$lock_name]['dirname']), $lock[$lock_name]['move_path']);
|
||||||
} else {
|
} else {
|
||||||
logger()->debug('Source [' . $source . '] already extracted in ' . $check . ', skip !');
|
logger()->debug('Source [' . $source . '] already extracted in ' . $check . ', skip !');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,5 @@ abstract class CustomSourceBase
|
|||||||
{
|
{
|
||||||
public const NAME = 'unknown';
|
public const NAME = 'unknown';
|
||||||
|
|
||||||
abstract public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void;
|
abstract public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_DOWNLOAD_SOURCE): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ class PhpSource extends CustomSourceBase
|
|||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
|
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.3';
|
$major = defined('SPC_BUILD_PHP_VERSION') ? SPC_BUILD_PHP_VERSION : '8.3';
|
||||||
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force);
|
Downloader::downloadSource('php-src', self::getLatestPHPInfo($major), $force);
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class PostgreSQLSource extends CustomSourceBase
|
|||||||
* @throws DownloaderException
|
* @throws DownloaderException
|
||||||
* @throws FileSystemException
|
* @throws FileSystemException
|
||||||
*/
|
*/
|
||||||
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_LOCK_SOURCE): void
|
public function fetch(bool $force = false, ?array $config = null, int $lock_as = SPC_DOWNLOAD_SOURCE): void
|
||||||
{
|
{
|
||||||
Downloader::downloadSource('postgresql', self::getLatestInfo(), $force);
|
Downloader::downloadSource('postgresql', self::getLatestInfo(), $force);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,8 +41,9 @@ const SPC_EXTENSION_ALIAS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// spc lock type
|
// spc lock type
|
||||||
const SPC_LOCK_SOURCE = 1; // lock source
|
const SPC_DOWNLOAD_SOURCE = 1; // lock source
|
||||||
const SPC_LOCK_PRE_BUILT = 2; // lock pre-built
|
const SPC_DOWNLOAD_PRE_BUILT = 2; // lock pre-built
|
||||||
|
const SPC_DOWNLOAD_PACKAGE = 3; // lock as package
|
||||||
|
|
||||||
// file replace strategy
|
// file replace strategy
|
||||||
const REPLACE_FILE_STR = 1;
|
const REPLACE_FILE_STR = 1;
|
||||||
|
|||||||
@ -13,9 +13,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
// test php version (8.1 ~ 8.4 available, multiple for matrix)
|
// test php version (8.1 ~ 8.4 available, multiple for matrix)
|
||||||
$test_php_version = [
|
$test_php_version = [
|
||||||
'8.1',
|
// '8.1',
|
||||||
'8.2',
|
// '8.2',
|
||||||
'8.3',
|
// '8.3',
|
||||||
'8.4',
|
'8.4',
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -24,7 +24,9 @@ $test_os = [
|
|||||||
// 'macos-13',
|
// 'macos-13',
|
||||||
// 'macos-14',
|
// 'macos-14',
|
||||||
'ubuntu-latest',
|
'ubuntu-latest',
|
||||||
'windows-latest',
|
'ubuntu-22.04',
|
||||||
|
'ubuntu-22.04-arm',
|
||||||
|
'ubuntu-24.04-arm',
|
||||||
];
|
];
|
||||||
|
|
||||||
// whether enable thread safe
|
// whether enable thread safe
|
||||||
@ -33,14 +35,14 @@ $zts = false;
|
|||||||
$no_strip = false;
|
$no_strip = false;
|
||||||
|
|
||||||
// compress with upx
|
// compress with upx
|
||||||
$upx = false;
|
$upx = true;
|
||||||
|
|
||||||
// prefer downloading pre-built packages to speed up the build process
|
// prefer downloading pre-built packages to speed up the build process
|
||||||
$prefer_pre_built = false;
|
$prefer_pre_built = true;
|
||||||
|
|
||||||
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
// If you want to test your added extensions and libs, add below (comma separated, example `bcmath,openssl`).
|
||||||
$extensions = match (PHP_OS_FAMILY) {
|
$extensions = match (PHP_OS_FAMILY) {
|
||||||
'Linux', 'Darwin' => 'pgsql,pdo_pgsql',
|
'Linux', 'Darwin' => 'imagick',
|
||||||
'Windows' => 'pgsql,pdo_pgsql',
|
'Windows' => 'pgsql,pdo_pgsql',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,6 +117,13 @@ if ($argv[1] === 'download_cmd') {
|
|||||||
$down_cmd .= $prefer_pre_built ? '--prefer-pre-built ' : '';
|
$down_cmd .= $prefer_pre_built ? '--prefer-pre-built ' : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($argv[1] === 'doctor_cmd') {
|
||||||
|
$doctor_cmd = 'doctor --auto-fix --debug';
|
||||||
|
}
|
||||||
|
if ($argv[1] === 'install_upx_cmd') {
|
||||||
|
$install_upx_cmd = 'install-pkg upx';
|
||||||
|
}
|
||||||
|
|
||||||
// generate build command
|
// generate build command
|
||||||
if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') {
|
if ($argv[1] === 'build_cmd' || $argv[1] === 'build_embed_cmd') {
|
||||||
$build_cmd = 'build ';
|
$build_cmd = 'build ';
|
||||||
@ -139,30 +148,36 @@ echo match ($argv[1]) {
|
|||||||
'upx' => $upx ? '--with-upx-pack' : '',
|
'upx' => $upx ? '--with-upx-pack' : '',
|
||||||
'prefer_pre_built' => $prefer_pre_built ? '--prefer-pre-built' : '',
|
'prefer_pre_built' => $prefer_pre_built ? '--prefer-pre-built' : '',
|
||||||
'download_cmd' => $down_cmd,
|
'download_cmd' => $down_cmd,
|
||||||
|
'install_upx_cmd' => $install_upx_cmd,
|
||||||
|
'doctor_cmd' => $doctor_cmd,
|
||||||
'build_cmd' => $build_cmd,
|
'build_cmd' => $build_cmd,
|
||||||
'build_embed_cmd' => $build_cmd,
|
'build_embed_cmd' => $build_cmd,
|
||||||
default => '',
|
default => '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$prefix = match ($argv[2] ?? null) {
|
||||||
|
'windows-latest', 'windows-2022', 'windows-2019', 'windows-2025' => 'powershell.exe -file .\bin\spc.ps1 ',
|
||||||
|
'ubuntu-latest', 'ubuntu-24.04', 'ubuntu-24.04-arm' => './bin/spc ',
|
||||||
|
'ubuntu-22.04', 'ubuntu-22.04-arm' => 'bin/spc-gnu-docker ',
|
||||||
|
'ubuntu-20.04' => 'bin/spc-alpine-docker ',
|
||||||
|
default => 'bin/spc ',
|
||||||
|
};
|
||||||
|
|
||||||
if ($argv[1] === 'download_cmd') {
|
if ($argv[1] === 'download_cmd') {
|
||||||
if (str_starts_with($argv[2], 'windows-')) {
|
passthru($prefix . $down_cmd, $retcode);
|
||||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $down_cmd, $retcode);
|
|
||||||
} else {
|
|
||||||
passthru('./bin/spc ' . $down_cmd, $retcode);
|
|
||||||
}
|
|
||||||
} elseif ($argv[1] === 'build_cmd') {
|
} elseif ($argv[1] === 'build_cmd') {
|
||||||
if (str_starts_with($argv[2], 'windows-')) {
|
passthru($prefix . $build_cmd . ' --build-cli --build-micro', $retcode);
|
||||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd . ' --build-cli --build-micro', $retcode);
|
|
||||||
} else {
|
|
||||||
passthru('./bin/spc ' . $build_cmd . ' --build-cli --build-micro', $retcode);
|
|
||||||
}
|
|
||||||
} elseif ($argv[1] === 'build_embed_cmd') {
|
} elseif ($argv[1] === 'build_embed_cmd') {
|
||||||
if (str_starts_with($argv[2], 'windows-')) {
|
if (str_starts_with($argv[2], 'windows-')) {
|
||||||
// windows does not accept embed SAPI
|
// windows does not accept embed SAPI
|
||||||
passthru('powershell.exe -file .\bin\spc.ps1 ' . $build_cmd . ' --build-cli', $retcode);
|
passthru($prefix . $build_cmd . ' --build-cli', $retcode);
|
||||||
} else {
|
} else {
|
||||||
passthru('./bin/spc ' . $build_cmd . ' --build-embed', $retcode);
|
passthru($prefix . $build_cmd . ' --build-embed', $retcode);
|
||||||
}
|
}
|
||||||
|
} elseif ($argv[1] === 'doctor_cmd') {
|
||||||
|
passthru($prefix . $doctor_cmd, $retcode);
|
||||||
|
} elseif ($argv[1] === 'install_upx_cmd') {
|
||||||
|
passthru($prefix . $install_upx_cmd, $retcode);
|
||||||
} else {
|
} else {
|
||||||
$retcode = 0;
|
$retcode = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user