From 2129333c15600ef1fa78104cfd6bbd2216ee9ebd Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 22 Oct 2023 12:37:13 +0800 Subject: [PATCH 1/2] separate `--from-zip` in download command --- src/SPC/command/DownloadCommand.php | 82 ++++++++++++++++------------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/src/SPC/command/DownloadCommand.php b/src/SPC/command/DownloadCommand.php index e6588a415..011a5373f 100644 --- a/src/SPC/command/DownloadCommand.php +++ b/src/SPC/command/DownloadCommand.php @@ -33,12 +33,17 @@ public function configure(): void $this->addOption('all', 'A', null, 'Fetch all sources that static-php-cli needed'); $this->addOption('custom-url', 'U', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Specify custom source download url, e.g "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"'); $this->addOption('from-zip', 'Z', InputOption::VALUE_REQUIRED, 'Fetch from zip archive'); + $this->addOption('by-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"'); } public function initialize(InputInterface $input, OutputInterface $output): void { - // --all 等于 "" "",也就是所有东西都要下载 - if ($input->getOption('all') || $input->getOption('clean') || $input->getOption('from-zip')) { + if ( + $input->getOption('all') + || $input->getOption('clean') + || $input->getOption('from-zip') + || $input->getOption('by-extensions') + ) { $input->setArgument('sources', ''); } parent::initialize($input, $output); @@ -73,40 +78,7 @@ public function handle(): int // --from-zip if ($path = $this->getOption('from-zip')) { - if (!file_exists($path)) { - logger()->critical('File ' . $path . ' not exist or not a zip archive.'); - return static::FAILURE; - } - // remove old download files first - if (is_dir(DOWNLOAD_PATH)) { - logger()->warning('You are doing some operations that not recoverable: removing directories below'); - logger()->warning(DOWNLOAD_PATH); - logger()->alert('I will remove these dir after 5 seconds !'); - sleep(5); - f_passthru((PHP_OS_FAMILY === 'Windows' ? 'rmdir /s /q ' : 'rm -rf ') . DOWNLOAD_PATH); - } - // unzip command check - if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) { - logger()->critical('Missing unzip command, you need to install it first !'); - logger()->critical('You can use "bin/spc doctor" command to check and install required tools'); - return static::FAILURE; - } - // create downloads - try { - if (PHP_OS_FAMILY !== 'Windows') { - f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($path)); - } - // Windows TODO - - if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) { - throw new RuntimeException('.lock.json not exist in "downloads/"'); - } - } catch (RuntimeException $e) { - logger()->critical('Extract failed: ' . $e->getMessage()); - return static::FAILURE; - } - logger()->info('Extract success'); - return static::SUCCESS; + return $this->downloadFromZip($path); } // Define PHP major version @@ -177,4 +149,42 @@ public function handle(): int logger()->info('Download complete, used ' . $time . ' s !'); return static::SUCCESS; } + + private function downloadFromZip(string $path): int + { + if (!file_exists($path)) { + logger()->critical('File ' . $path . ' not exist or not a zip archive.'); + return static::FAILURE; + } + // remove old download files first + if (is_dir(DOWNLOAD_PATH)) { + logger()->warning('You are doing some operations that not recoverable: removing directories below'); + logger()->warning(DOWNLOAD_PATH); + logger()->alert('I will remove these dir after 5 seconds !'); + sleep(5); + f_passthru((PHP_OS_FAMILY === 'Windows' ? 'rmdir /s /q ' : 'rm -rf ') . DOWNLOAD_PATH); + } + // unzip command check + if (PHP_OS_FAMILY !== 'Windows' && !$this->findCommand('unzip')) { + logger()->critical('Missing unzip command, you need to install it first !'); + logger()->critical('You can use "bin/spc doctor" command to check and install required tools'); + return static::FAILURE; + } + // create downloads + try { + if (PHP_OS_FAMILY !== 'Windows') { + f_passthru('mkdir ' . DOWNLOAD_PATH . ' && cd ' . DOWNLOAD_PATH . ' && unzip ' . escapeshellarg($path)); + } + // Windows TODO + + if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) { + throw new RuntimeException('.lock.json not exist in "downloads/"'); + } + } catch (RuntimeException $e) { + logger()->critical('Extract failed: ' . $e->getMessage()); + return static::FAILURE; + } + logger()->info('Extract success'); + return static::SUCCESS; + } } From ec903aeb6ca6fe1f7b21778e693306efacb2f47f Mon Sep 17 00:00:00 2001 From: crazywhalecc Date: Sun, 22 Oct 2023 16:35:15 +0800 Subject: [PATCH 2/2] add `--by-extensions` and `--without-suggests` options for download command --- src/SPC/command/DownloadCommand.php | 40 ++++++++++++++++++++++++++--- src/SPC/util/DependencyUtil.php | 37 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/SPC/command/DownloadCommand.php b/src/SPC/command/DownloadCommand.php index 011a5373f..dfad36fee 100644 --- a/src/SPC/command/DownloadCommand.php +++ b/src/SPC/command/DownloadCommand.php @@ -8,8 +8,10 @@ use SPC\exception\DownloaderException; use SPC\exception\FileSystemException; use SPC\exception\RuntimeException; +use SPC\exception\WrongUsageException; use SPC\store\Config; use SPC\store\Downloader; +use SPC\util\DependencyUtil; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -34,6 +36,7 @@ public function configure(): void $this->addOption('custom-url', 'U', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Specify custom source download url, e.g "php-src:https://downloads.php.net/~eric/php-8.3.0beta1.tar.gz"'); $this->addOption('from-zip', 'Z', InputOption::VALUE_REQUIRED, 'Fetch from zip archive'); $this->addOption('by-extensions', 'e', InputOption::VALUE_REQUIRED, 'Fetch by extensions, e.g "openssl,mbstring"'); + $this->addOption('without-suggests', null, null, 'Do not fetch suggested sources when using --by-extensions'); } public function initialize(InputInterface $input, OutputInterface $output): void @@ -105,10 +108,17 @@ public function handle(): int Config::$source['openssl']['regex'] = '/href="(?openssl-(?1.[^"]+)\.tar\.gz)\"/'; } - // get source list that will be downloaded - $sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources')))); - if (empty($sources)) { - $sources = array_keys(Config::getSources()); + // --by-extensions + if ($by_ext = $this->getOption('by-extensions')) { + $ext = array_map('trim', array_filter(explode(',', $by_ext))); + $sources = $this->calculateSourcesByExt($ext, !$this->getOption('without-suggests')); + array_unshift($sources, 'php-src', 'micro', 'pkg-config'); + } else { + // get source list that will be downloaded + $sources = array_map('trim', array_filter(explode(',', $this->getArgument('sources')))); + if (empty($sources)) { + $sources = array_keys(Config::getSources()); + } } $chosen_sources = $sources; @@ -187,4 +197,26 @@ private function downloadFromZip(string $path): int logger()->info('Extract success'); return static::SUCCESS; } + + /** + * Calculate the sources by extensions + * + * @param array $extensions extension list + * @throws FileSystemException + * @throws WrongUsageException + */ + private function calculateSourcesByExt(array $extensions, bool $include_suggests = true): array + { + [$extensions, $libraries] = $include_suggests ? DependencyUtil::getAllExtLibsByDeps($extensions) : DependencyUtil::getExtLibsByDeps($extensions); + $sources = []; + foreach ($extensions as $extension) { + if (Config::getExt($extension, 'type') === 'external') { + $sources[] = Config::getExt($extension, 'source'); + } + } + foreach ($libraries as $library) { + $sources[] = Config::getLib($library, 'source'); + } + return array_values(array_unique($sources)); + } } diff --git a/src/SPC/util/DependencyUtil.php b/src/SPC/util/DependencyUtil.php index ba0d839cb..4e0b74b1e 100644 --- a/src/SPC/util/DependencyUtil.php +++ b/src/SPC/util/DependencyUtil.php @@ -99,6 +99,43 @@ public static function getLibsByDeps(array $libs): array return $final; } + public static function getAllExtLibsByDeps(array $exts): array + { + $sorted = []; + $visited = []; + $not_included_exts = []; + foreach ($exts as $ext) { + if (!isset($visited[$ext])) { + self::visitExtAllDeps($ext, $visited, $sorted); + } + } + $libs = []; + foreach ($sorted as $ext) { + if (!in_array($ext, $exts)) { + $not_included_exts[] = $ext; + } + foreach (array_merge(Config::getExt($ext, 'lib-depends', []), Config::getExt($ext, 'lib-suggests', [])) as $dep) { + if (!in_array($dep, $libs)) { + $libs[] = $dep; + } + } + } + return [$sorted, self::getAllLibsByDeps($libs), $not_included_exts]; + } + + public static function getAllLibsByDeps(array $libs): array + { + $sorted = []; + $visited = []; + + foreach ($libs as $lib) { + if (!isset($visited[$lib])) { + self::visitLibAllDeps($lib, $visited, $sorted); + } + } + return $sorted; + } + /** * @throws FileSystemException * @throws RuntimeException