2025-11-30 15:35:04 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace StaticPHP\Command;
|
|
|
|
|
|
|
|
|
|
use StaticPHP\Artifact\ArtifactDownloader;
|
|
|
|
|
use StaticPHP\Artifact\DownloaderOptions;
|
|
|
|
|
use StaticPHP\Package\PackageLoader;
|
|
|
|
|
use StaticPHP\Util\DependencyResolver;
|
|
|
|
|
use StaticPHP\Util\FileSystem;
|
|
|
|
|
use StaticPHP\Util\InteractiveTerm;
|
|
|
|
|
use Symfony\Component\Console\Attribute\AsCommand;
|
|
|
|
|
use Symfony\Component\Console\Input\InputArgument;
|
|
|
|
|
use Symfony\Component\Console\Input\InputOption;
|
|
|
|
|
|
|
|
|
|
#[AsCommand('download')]
|
|
|
|
|
class DownloadCommand extends BaseCommand
|
|
|
|
|
{
|
|
|
|
|
public function configure(): void
|
|
|
|
|
{
|
|
|
|
|
$this->addArgument('artifacts', InputArgument::OPTIONAL, 'Specific artifacts to download, comma separated, e.g "php-src,openssl,curl"');
|
|
|
|
|
|
|
|
|
|
// 2.x compatible options
|
|
|
|
|
$this->addOption('shallow-clone', null, null, '(deprecated) Clone shallowly repositories when downloading sources');
|
|
|
|
|
$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-suggests', null, null, 'Do not fetch suggested sources when using --for-extensions');
|
|
|
|
|
|
2025-12-05 11:15:04 +08:00
|
|
|
$this->addOption('without-suggestions', null, null, '(deprecated) Do not fetch suggested sources when using --for-extensions');
|
|
|
|
|
|
2025-11-30 15:35:04 +08:00
|
|
|
// download command specific options
|
|
|
|
|
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
|
|
|
|
|
$this->addOption('for-packages', null, InputOption::VALUE_REQUIRED, 'Fetch by packages, e.g "php,libssl,libcurl"');
|
|
|
|
|
|
|
|
|
|
// shared downloader options (no prefix for download command)
|
|
|
|
|
$this->getDefinition()->addOptions(DownloaderOptions::getConsoleOptions());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function handle(): int
|
|
|
|
|
{
|
|
|
|
|
// handle --clean option
|
|
|
|
|
if ($this->getOption('clean')) {
|
|
|
|
|
return $this->handleClean();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$downloader = new ArtifactDownloader(DownloaderOptions::extractFromConsoleOptions($this->input->getOptions()));
|
|
|
|
|
|
|
|
|
|
// arguments
|
|
|
|
|
if ($artifacts = $this->getArgument('artifacts')) {
|
|
|
|
|
$artifacts = parse_comma_list($artifacts);
|
|
|
|
|
$downloader->addArtifacts($artifacts);
|
|
|
|
|
}
|
|
|
|
|
// for-extensions
|
|
|
|
|
$packages = [];
|
|
|
|
|
if ($exts = $this->getOption('for-extensions')) {
|
|
|
|
|
$packages = array_map(fn ($x) => "ext-{$x}", parse_extension_list($exts));
|
|
|
|
|
// when using for-extensions, also include php package
|
|
|
|
|
array_unshift($packages, 'php');
|
|
|
|
|
array_unshift($packages, 'php-micro');
|
|
|
|
|
array_unshift($packages, 'php-embed');
|
|
|
|
|
array_unshift($packages, 'php-fpm');
|
|
|
|
|
}
|
|
|
|
|
// for-libs / for-packages
|
|
|
|
|
if ($libs = $this->getOption('for-libs')) {
|
|
|
|
|
$packages = array_merge($packages, parse_comma_list($libs));
|
|
|
|
|
}
|
|
|
|
|
if ($libs = $this->getOption('for-packages')) {
|
|
|
|
|
$packages = array_merge($packages, parse_comma_list($libs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// resolve package dependencies and get artifacts directly
|
2025-12-04 21:19:11 +08:00
|
|
|
$suggests = !($this->getOption('without-suggests') || $this->getOption('without-suggestions'));
|
|
|
|
|
$resolved = DependencyResolver::resolve($packages, [], $suggests);
|
2025-11-30 15:35:04 +08:00
|
|
|
foreach ($resolved as $pkg_name) {
|
|
|
|
|
$pkg = PackageLoader::getPackage($pkg_name);
|
|
|
|
|
if ($artifact = $pkg->getArtifact()) {
|
|
|
|
|
$downloader->add($artifact);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$starttime = microtime(true);
|
|
|
|
|
$downloader->download();
|
|
|
|
|
|
|
|
|
|
$endtime = microtime(true);
|
|
|
|
|
$elapsed = round($endtime - $starttime);
|
|
|
|
|
$this->output->writeln('');
|
|
|
|
|
$this->output->writeln('<info>Download completed in ' . $elapsed . ' s.</info>');
|
|
|
|
|
return static::SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function handleClean(): int
|
|
|
|
|
{
|
|
|
|
|
logger()->warning('You are doing some operations that are not recoverable:');
|
|
|
|
|
logger()->warning('- Removing directory: ' . SOURCE_PATH);
|
|
|
|
|
logger()->warning('- Removing directory: ' . DOWNLOAD_PATH);
|
|
|
|
|
logger()->warning('- Removing directory: ' . BUILD_ROOT_PATH);
|
|
|
|
|
logger()->alert('I will remove these directories after 5 seconds!');
|
|
|
|
|
sleep(5);
|
|
|
|
|
|
|
|
|
|
if (is_dir(SOURCE_PATH)) {
|
|
|
|
|
InteractiveTerm::indicateProgress('Removing: ' . SOURCE_PATH);
|
|
|
|
|
FileSystem::removeDir(SOURCE_PATH);
|
|
|
|
|
InteractiveTerm::finish('Removed: ' . SOURCE_PATH);
|
|
|
|
|
}
|
|
|
|
|
if (is_dir(DOWNLOAD_PATH)) {
|
|
|
|
|
InteractiveTerm::indicateProgress('Removing: ' . DOWNLOAD_PATH);
|
|
|
|
|
FileSystem::removeDir(DOWNLOAD_PATH);
|
|
|
|
|
InteractiveTerm::finish('Removed: ' . DOWNLOAD_PATH);
|
|
|
|
|
}
|
|
|
|
|
if (is_dir(BUILD_ROOT_PATH)) {
|
|
|
|
|
InteractiveTerm::indicateProgress('Removing: ' . BUILD_ROOT_PATH);
|
|
|
|
|
FileSystem::removeDir(BUILD_ROOT_PATH);
|
|
|
|
|
InteractiveTerm::finish('Removed: ' . BUILD_ROOT_PATH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InteractiveTerm::notice('Clean completed.');
|
|
|
|
|
return static::SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
}
|