mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-07-03 23:05:41 +08:00
Add pre-built lib feature
This commit is contained in:
@@ -148,7 +148,7 @@ class BuildCliCommand extends BuildCommand
|
||||
// validate libs and exts
|
||||
$builder->validateLibsAndExts();
|
||||
// build libraries
|
||||
$builder->buildLibs();
|
||||
$builder->setupLibs();
|
||||
|
||||
if ($this->input->getOption('with-clean')) {
|
||||
logger()->info('Cleaning source dir...');
|
||||
|
||||
@@ -65,7 +65,7 @@ class BuildLibsCommand extends BuildCommand
|
||||
sleep(2);
|
||||
$builder->proveLibs($libraries);
|
||||
$builder->validateLibsAndExts();
|
||||
$builder->buildLibs();
|
||||
$builder->setupLibs();
|
||||
|
||||
$time = round(microtime(true) - START_TIME, 3);
|
||||
logger()->info('Build libs complete, used ' . $time . ' s !');
|
||||
|
||||
@@ -38,8 +38,9 @@ class DownloadCommand extends BaseCommand
|
||||
$this->addOption('for-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"');
|
||||
$this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Fetch by libraries, e.g "libcares,openssl,onig"');
|
||||
$this->addOption('without-suggestions', null, null, 'Do not fetch suggested sources when using --for-extensions');
|
||||
$this->addOption('ignore-cache-sources', null, InputOption::VALUE_OPTIONAL, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', '');
|
||||
$this->addOption('ignore-cache-sources', null, InputOption::VALUE_OPTIONAL, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', false);
|
||||
$this->addOption('retry', 'R', InputOption::VALUE_REQUIRED, 'Set retry time when downloading failed (default: 0)', '0');
|
||||
$this->addOption('prefer-pre-built', 'P', null, 'Download pre-built libraries when available');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,12 +148,22 @@ class DownloadCommand extends BaseCommand
|
||||
}
|
||||
|
||||
$chosen_sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources'))));
|
||||
$force_all = empty($this->getOption('ignore-cache-sources'));
|
||||
if (!$force_all) {
|
||||
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources'))));
|
||||
} else {
|
||||
|
||||
$sss = $this->getOption('ignore-cache-sources');
|
||||
if ($sss === false) {
|
||||
// false is no-any-ignores, that is, default.
|
||||
$force_all = false;
|
||||
$force_list = [];
|
||||
} elseif ($sss === null) {
|
||||
// null means all sources will be ignored, equals to --force-all (but we don't want to add too many options)
|
||||
$force_all = true;
|
||||
$force_list = [];
|
||||
} else {
|
||||
// ignore some sources
|
||||
$force_all = false;
|
||||
$force_list = array_map('trim', array_filter(explode(',', $this->getOption('ignore-cache-sources'))));
|
||||
}
|
||||
|
||||
if ($this->getOption('all')) {
|
||||
logger()->notice('Downloading with --all option will take more times to download, we recommend you to download with --for-extensions option !');
|
||||
}
|
||||
@@ -164,6 +175,17 @@ class DownloadCommand extends BaseCommand
|
||||
$custom_urls[$source_name] = $url;
|
||||
}
|
||||
|
||||
// If passing --prefer-pre-built option, we need to load pre-built library list from pre-built.json targeted releases
|
||||
if ($this->getOption('prefer-pre-built')) {
|
||||
$repo = Config::getPreBuilt('repo');
|
||||
$pre_built_libs = Downloader::getLatestGithubRelease($repo, [
|
||||
'repo' => $repo,
|
||||
'prefer-stable' => Config::getPreBuilt('prefer-stable'),
|
||||
], false);
|
||||
} else {
|
||||
$pre_built_libs = [];
|
||||
}
|
||||
|
||||
// Download them
|
||||
f_mkdir(DOWNLOAD_PATH);
|
||||
$cnt = count($chosen_sources);
|
||||
@@ -185,8 +207,21 @@ class DownloadCommand extends BaseCommand
|
||||
logger()->info("Fetching source {$source} from custom url [{$ni}/{$cnt}]");
|
||||
Downloader::downloadSource($source, $new_config, true);
|
||||
} else {
|
||||
$config = Config::getSource($source);
|
||||
// Prefer pre-built, we need to search pre-built library
|
||||
if ($this->getOption('prefer-pre-built') && ($config['provide-pre-built'] ?? false) === true) {
|
||||
// We need to replace pattern
|
||||
$find = str_replace(['{name}', '{arch}', '{os}'], [$source, arch2gnu(php_uname('m')), strtolower(PHP_OS_FAMILY)], Config::getPreBuilt('match-pattern'));
|
||||
// find filename in asset list
|
||||
if (($url = $this->findPreBuilt($pre_built_libs, $find)) !== null) {
|
||||
logger()->info("Fetching pre-built content {$source} [{$ni}/{$cnt}]");
|
||||
Downloader::downloadSource($source, ['type' => 'url', 'url' => $url], $force_all || in_array($source, $force_list), SPC_LOCK_PRE_BUILT);
|
||||
continue;
|
||||
}
|
||||
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
|
||||
}
|
||||
logger()->info("Fetching source {$source} [{$ni}/{$cnt}]");
|
||||
Downloader::downloadSource($source, Config::getSource($source), $force_all || in_array($source, $force_list));
|
||||
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
|
||||
}
|
||||
}
|
||||
$time = round(microtime(true) - START_TIME, 3);
|
||||
@@ -286,4 +321,19 @@ class DownloadCommand extends BaseCommand
|
||||
}
|
||||
return array_values(array_unique($sources));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $assets Asset list from GitHub API
|
||||
* @param string $filename Match file name, e.g. pkg-config-aarch64-darwin.txz
|
||||
* @return null|string Return the download URL if found, otherwise null
|
||||
*/
|
||||
private function findPreBuilt(array $assets, string $filename): ?string
|
||||
{
|
||||
foreach ($assets as $asset) {
|
||||
if ($asset['name'] === $filename) {
|
||||
return $asset['browser_download_url'];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
85
src/SPC/command/dev/PackLibCommand.php
Normal file
85
src/SPC/command/dev/PackLibCommand.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\command\dev;
|
||||
|
||||
use SPC\builder\BuilderProvider;
|
||||
use SPC\command\BuildCommand;
|
||||
use SPC\exception\ExceptionHandler;
|
||||
use SPC\store\Config;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\DependencyUtil;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
#[AsCommand('dev:pack-lib', 'Build and pack library as pre-built release')]
|
||||
class PackLibCommand extends BuildCommand
|
||||
{
|
||||
public function configure(): void
|
||||
{
|
||||
$this->addArgument('library', InputArgument::REQUIRED, 'The library will be compiled');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
try {
|
||||
$lib_name = $this->getArgument('library');
|
||||
$builder = BuilderProvider::makeBuilderByInput($this->input);
|
||||
$builder->setLibsOnly();
|
||||
$libraries = DependencyUtil::getLibs([$lib_name]);
|
||||
logger()->info('Building libraries: ' . implode(',', $libraries));
|
||||
sleep(2);
|
||||
|
||||
FileSystem::createDir(WORKING_DIR . '/dist');
|
||||
|
||||
$builder->proveLibs($libraries);
|
||||
$builder->validateLibsAndExts();
|
||||
foreach ($builder->getLibs() as $lib) {
|
||||
if ($lib->getName() !== $lib_name) {
|
||||
// other dependencies: install or build, both ok
|
||||
$lib->setup();
|
||||
} else {
|
||||
// Get lock info
|
||||
$lock = json_decode(file_get_contents(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
|
||||
$source = Config::getLib($lib->getName(), 'source');
|
||||
if (!isset($lock[$source]) || ($lock[$source]['lock_as'] ?? SPC_LOCK_SOURCE) === SPC_LOCK_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;
|
||||
}
|
||||
// Before build: load buildroot/ directory
|
||||
$before_buildroot = FileSystem::scanDirFiles(BUILD_ROOT_PATH, relative: true);
|
||||
// build
|
||||
$lib->tryBuild(true);
|
||||
// do something like patching pkg-conf files.
|
||||
$lib->beforePack();
|
||||
// After build: load buildroot/ directory, and calculate increase files
|
||||
$after_buildroot = FileSystem::scanDirFiles(BUILD_ROOT_PATH, relative: true);
|
||||
$increase_files = array_diff($after_buildroot, $before_buildroot);
|
||||
// every file mapped with BUILD_ROOT_PATH
|
||||
// get BUILD_ROOT_PATH last dir part
|
||||
$buildroot_part = basename(BUILD_ROOT_PATH);
|
||||
$increase_files = array_map(fn ($file) => $buildroot_part . '/' . $file, $increase_files);
|
||||
// write list to packlib_files.txt
|
||||
FileSystem::writeFile(WORKING_DIR . '/packlib_files.txt', implode("\n", $increase_files));
|
||||
// pack
|
||||
$filename = WORKING_DIR . '/dist/' . $lib->getName() . '-' . arch2gnu(php_uname('m')) . '-' . strtolower(PHP_OS_FAMILY) . '.' . Config::getPreBuilt('suffix');
|
||||
f_passthru('tar -czf ' . $filename . ' -T ' . WORKING_DIR . '/packlib_files.txt -C ' . WORKING_DIR);
|
||||
logger()->info('Pack library ' . $lib->getName() . ' to ' . $filename . ' complete.');
|
||||
}
|
||||
}
|
||||
|
||||
$time = round(microtime(true) - START_TIME, 3);
|
||||
logger()->info('Build libs complete, used ' . $time . ' s !');
|
||||
return static::SUCCESS;
|
||||
} catch (\Throwable $e) {
|
||||
if ($this->getOption('debug')) {
|
||||
ExceptionHandler::getInstance()->handle($e);
|
||||
} else {
|
||||
logger()->critical('Build failed with ' . get_class($e) . ': ' . $e->getMessage());
|
||||
logger()->critical('Please check with --debug option to see more details.');
|
||||
}
|
||||
return static::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user