Skip to content

Commit 455ed7d

Browse files
authored
Add alt download for Downloader (#706)
* Add alt download for Downloader * Test broken url * Break another source * Good! * Rename alt_sources variable * Use SPC_DOWNLOAD_RETRIES instead of SPC_RETRY_TIME * Apply new curlExec args
1 parent 637ae89 commit 455ed7d

File tree

4 files changed

+74
-19
lines changed

4 files changed

+74
-19
lines changed

config/source.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,6 @@
905905
"path": "php-src/ext/swow-src",
906906
"rev": "ci",
907907
"url": "https://github.com/swow/swow",
908-
"patch": "patchSwow",
909908
"license": {
910909
"type": "file",
911910
"path": "LICENSE"

src/SPC/builder/Extension.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,16 @@ public function __construct(protected string $name, protected BuilderBase $build
4040
// set source_dir for builtin
4141
if ($ext_type === 'builtin') {
4242
$this->source_dir = SOURCE_PATH . '/php-src/ext/' . $this->name;
43-
} else {
43+
} elseif ($ext_type === 'external') {
4444
$source = Config::getExt($this->name, 'source');
4545
if ($source === null) {
4646
throw new RuntimeException("{$ext_type} extension {$name} source not found");
4747
}
4848
$source_path = Config::getSource($source)['path'] ?? null;
4949
$source_path = $source_path === null ? SOURCE_PATH . '/' . $source : SOURCE_PATH . '/' . $source_path;
5050
$this->source_dir = $source_path;
51+
} else {
52+
$this->source_dir = SOURCE_PATH . '/php-src';
5153
}
5254
}
5355

src/SPC/command/DownloadCommand.php

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public function configure(): void
4343
$this->addOption('ignore-cache-sources', null, InputOption::VALUE_OPTIONAL, 'Ignore some source caches, comma separated, e.g "php-src,curl,openssl"', false);
4444
$this->addOption('retry', 'R', InputOption::VALUE_REQUIRED, 'Set retry time when downloading failed (default: 0)', '0');
4545
$this->addOption('prefer-pre-built', 'P', null, 'Download pre-built libraries when available');
46+
$this->addOption('no-alt', null, null, 'Do not download alternative sources');
4647
}
4748

4849
/**
@@ -95,22 +96,7 @@ public function handle(): int
9596
{
9697
try {
9798
if ($this->getOption('clean')) {
98-
logger()->warning('You are doing some operations that not recoverable: removing directories below');
99-
logger()->warning(SOURCE_PATH);
100-
logger()->warning(DOWNLOAD_PATH);
101-
logger()->warning(BUILD_ROOT_PATH);
102-
logger()->alert('I will remove these dir after 5 seconds !');
103-
sleep(5);
104-
if (PHP_OS_FAMILY === 'Windows') {
105-
f_passthru('rmdir /s /q ' . SOURCE_PATH);
106-
f_passthru('rmdir /s /q ' . DOWNLOAD_PATH);
107-
f_passthru('rmdir /s /q ' . BUILD_ROOT_PATH);
108-
} else {
109-
f_passthru('rm -rf ' . SOURCE_PATH . '/*');
110-
f_passthru('rm -rf ' . DOWNLOAD_PATH . '/*');
111-
f_passthru('rm -rf ' . BUILD_ROOT_PATH . '/*');
112-
}
113-
return static::FAILURE;
99+
return $this->_clean();
114100
}
115101

116102
// --from-zip
@@ -249,7 +235,24 @@ public function handle(): int
249235
logger()->warning("Pre-built content not found for {$source}, fallback to source download");
250236
}
251237
logger()->info("[{$ni}/{$cnt}] Downloading source {$source}");
252-
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
238+
try {
239+
Downloader::downloadSource($source, $config, $force_all || in_array($source, $force_list));
240+
} /* @noinspection PhpRedundantCatchClauseInspection */ catch (DownloaderException|RuntimeException $e) {
241+
// if `--no-alt` option is set, we will not download alternative sources
242+
if ($this->getOption('no-alt')) {
243+
throw $e;
244+
}
245+
// if download failed, we will try to download alternative sources
246+
logger()->warning("Download failed: {$e->getMessage()}");
247+
logger()->notice("Trying to download alternative sources for {$source}");
248+
$alt_sources = Config::getSource($source)['alt'] ?? null;
249+
if ($alt_sources === null) {
250+
$alt_config = array_merge($config, $this->getDefaultAlternativeSource($source));
251+
} else {
252+
$alt_config = array_merge($config, $alt_sources);
253+
}
254+
Downloader::downloadSource($source, $alt_config, $force_all || in_array($source, $force_list));
255+
}
253256
}
254257
}
255258
$time = round(microtime(true) - START_TIME, 3);
@@ -368,4 +371,50 @@ private function findPreBuilt(array $assets, string $filename): ?string
368371
}
369372
return null;
370373
}
374+
375+
/**
376+
* @throws RuntimeException
377+
*/
378+
private function _clean(): int
379+
{
380+
logger()->warning('You are doing some operations that not recoverable: removing directories below');
381+
logger()->warning(SOURCE_PATH);
382+
logger()->warning(DOWNLOAD_PATH);
383+
logger()->warning(BUILD_ROOT_PATH);
384+
logger()->alert('I will remove these dir after 5 seconds !');
385+
sleep(5);
386+
if (PHP_OS_FAMILY === 'Windows') {
387+
f_passthru('rmdir /s /q ' . SOURCE_PATH);
388+
f_passthru('rmdir /s /q ' . DOWNLOAD_PATH);
389+
f_passthru('rmdir /s /q ' . BUILD_ROOT_PATH);
390+
} else {
391+
f_passthru('rm -rf ' . SOURCE_PATH . '/*');
392+
f_passthru('rm -rf ' . DOWNLOAD_PATH . '/*');
393+
f_passthru('rm -rf ' . BUILD_ROOT_PATH . '/*');
394+
}
395+
return static::FAILURE;
396+
}
397+
398+
private function getDefaultAlternativeSource(string $source_name): array
399+
{
400+
return [
401+
'type' => 'custom',
402+
'func' => function (bool $force, array $source, int $download_as) use ($source_name) {
403+
logger()->debug("Fetching alternative source for {$source_name}");
404+
// get from dl.static-php.dev
405+
$url = "https://dl.static-php.dev/static-php-cli/deps/spc-download-mirror/{$source_name}/?format=json";
406+
$json = json_decode(Downloader::curlExec(url: $url, retries: intval(getenv('SPC_DOWNLOAD_RETRIES') ?: 0)), true);
407+
if (!is_array($json)) {
408+
throw new RuntimeException('failed http fetch');
409+
}
410+
$item = $json[0] ?? null;
411+
if ($item === null) {
412+
throw new RuntimeException('failed to parse json');
413+
}
414+
$full_url = 'https://dl.static-php.dev' . $item['full_path'];
415+
$filename = basename($item['full_path']);
416+
Downloader::downloadFile($source_name, $full_url, $filename, $source['path'] ?? null, $download_as);
417+
},
418+
];
419+
}
371420
}

src/SPC/store/Downloader.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,11 @@ public static function downloadSource(string $name, ?array $source = null, bool
477477
);
478478
break;
479479
case 'custom': // Custom download method, like API-based download or other
480+
if (isset($source['func']) && is_callable($source['func'])) {
481+
$source['name'] = $name;
482+
$source['func']($force, $source, $download_as);
483+
break;
484+
}
480485
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
481486
foreach ($classes as $class) {
482487
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {

0 commit comments

Comments
 (0)