mirror of
https://github.com/crazywhalecc/static-php-cli.git
synced 2026-03-17 20:34:51 +08:00
Add pie support for downloading sources
This commit is contained in:
parent
8923077120
commit
605c06f85c
@ -999,9 +999,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"spx": {
|
"spx": {
|
||||||
"type": "git",
|
"type": "pie",
|
||||||
"rev": "master",
|
"repo": "noisebynorthwest/php-spx",
|
||||||
"url": "https://github.com/NoiseByNorthwest/php-spx.git",
|
|
||||||
"path": "php-src/ext/spx",
|
"path": "php-src/ext/spx",
|
||||||
"license": {
|
"license": {
|
||||||
"type": "file",
|
"type": "file",
|
||||||
|
|||||||
@ -16,6 +16,42 @@ use SPC\util\SPCTarget;
|
|||||||
*/
|
*/
|
||||||
class Downloader
|
class Downloader
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Get latest version from PIE config (Packagist)
|
||||||
|
*
|
||||||
|
* @param string $name Source name
|
||||||
|
* @param array $source Source meta info: [repo]
|
||||||
|
* @return array<int, string> [url, filename]
|
||||||
|
*/
|
||||||
|
public static function getPIEInfo(string $name, array $source): array
|
||||||
|
{
|
||||||
|
$packagist_url = "https://repo.packagist.org/p2/{$source['repo']}.json";
|
||||||
|
logger()->debug("Fetching {$name} source from packagist index: {$packagist_url}");
|
||||||
|
$data = json_decode(self::curlExec(
|
||||||
|
url: $packagist_url,
|
||||||
|
retries: self::getRetryAttempts()
|
||||||
|
), true);
|
||||||
|
if (!isset($data['packages'][$source['repo']]) || !is_array($data['packages'][$source['repo']])) {
|
||||||
|
throw new DownloaderException("failed to find {$name} repo info from packagist");
|
||||||
|
}
|
||||||
|
// get the first version
|
||||||
|
$first = $data['packages'][$source['repo']][0] ?? [];
|
||||||
|
// check 'type' => 'php-ext' or contains 'php-ext' key
|
||||||
|
if (!isset($first['php-ext'])) {
|
||||||
|
throw new DownloaderException("failed to find {$name} php-ext info from packagist, maybe not a php extension package");
|
||||||
|
}
|
||||||
|
// get download link from dist
|
||||||
|
$dist_url = $first['dist']['url'] ?? null;
|
||||||
|
$dist_type = $first['dist']['type'] ?? null;
|
||||||
|
if (!$dist_url || !$dist_type) {
|
||||||
|
throw new DownloaderException("failed to find {$name} dist info from packagist");
|
||||||
|
}
|
||||||
|
$name = str_replace('/', '_', $source['repo']);
|
||||||
|
$version = $first['version'] ?? 'unknown';
|
||||||
|
// file name use: $name-$version.$dist_type
|
||||||
|
return [$dist_url, "{$name}-{$version}.{$dist_type}"];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get latest version from BitBucket tag
|
* Get latest version from BitBucket tag
|
||||||
*
|
*
|
||||||
@ -317,84 +353,7 @@ class Downloader
|
|||||||
if (self::isAlreadyDownloaded($name, $force, SPC_DOWNLOAD_PACKAGE)) {
|
if (self::isAlreadyDownloaded($name, $force, SPC_DOWNLOAD_PACKAGE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
self::downloadByType($pkg['type'], $name, $pkg, $force, SPC_DOWNLOAD_PACKAGE);
|
||||||
try {
|
|
||||||
switch ($pkg['type']) {
|
|
||||||
case 'bitbuckettag': // BitBucket Tag
|
|
||||||
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
|
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
|
||||||
break;
|
|
||||||
case 'ghtar': // GitHub Release (tar)
|
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
|
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE, hooks: [[CurlHook::class, 'setupGithubToken']]);
|
|
||||||
break;
|
|
||||||
case 'ghtagtar': // GitHub Tag (tar)
|
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
|
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE, hooks: [[CurlHook::class, 'setupGithubToken']]);
|
|
||||||
break;
|
|
||||||
case 'ghrel': // GitHub Release (uploaded)
|
|
||||||
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
|
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE, ['Accept: application/octet-stream'], [[CurlHook::class, 'setupGithubToken']]);
|
|
||||||
break;
|
|
||||||
case 'filelist': // Basic File List (regex based crawler)
|
|
||||||
[$url, $filename] = self::getFromFileList($name, $pkg);
|
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
|
||||||
break;
|
|
||||||
case 'url': // Direct download URL
|
|
||||||
$url = $pkg['url'];
|
|
||||||
$filename = $pkg['filename'] ?? basename($pkg['url']);
|
|
||||||
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWNLOAD_PACKAGE);
|
|
||||||
break;
|
|
||||||
case 'git': // Git repo
|
|
||||||
self::downloadGit(
|
|
||||||
$name,
|
|
||||||
$pkg['url'],
|
|
||||||
$pkg['rev'],
|
|
||||||
$pkg['submodules'] ?? null,
|
|
||||||
$pkg['extract'] ?? null,
|
|
||||||
self::getRetryAttempts(),
|
|
||||||
SPC_DOWNLOAD_PRE_BUILT
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'local':
|
|
||||||
// Local directory, do nothing, just lock it
|
|
||||||
logger()->debug("Locking local source {$name}");
|
|
||||||
LockFile::lockSource($name, [
|
|
||||||
'source_type' => SPC_SOURCE_LOCAL,
|
|
||||||
'dirname' => $pkg['dirname'],
|
|
||||||
'move_path' => $pkg['extract'] ?? null,
|
|
||||||
'lock_as' => SPC_DOWNLOAD_PACKAGE,
|
|
||||||
]);
|
|
||||||
break;
|
|
||||||
case 'custom': // Custom download method, like API-based download or other
|
|
||||||
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/pkg', 'SPC\store\pkg');
|
|
||||||
if (isset($pkg['func']) && is_callable($pkg['func'])) {
|
|
||||||
$pkg['name'] = $name;
|
|
||||||
$pkg['func']($force, $pkg, SPC_DOWNLOAD_PACKAGE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
foreach ($classes as $class) {
|
|
||||||
if (is_a($class, CustomPackage::class, true) && $class !== CustomPackage::class) {
|
|
||||||
$cls = new $class();
|
|
||||||
if (in_array($name, $cls->getSupportName())) {
|
|
||||||
(new $class())->fetch($name, $force, $pkg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new DownloaderException('unknown source type: ' . $pkg['type']);
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// Because sometimes files downloaded through the command line are not automatically deleted after a failure.
|
|
||||||
// Here we need to manually delete the file if it is detected to exist.
|
|
||||||
if (isset($filename) && file_exists(DOWNLOAD_PATH . '/' . $filename)) {
|
|
||||||
logger()->warning('Deleting download file: ' . $filename);
|
|
||||||
unlink(DOWNLOAD_PATH . '/' . $filename);
|
|
||||||
}
|
|
||||||
throw new DownloaderException('Download failed! ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -439,80 +398,7 @@ class Downloader
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
self::downloadByType($source['type'], $name, $source, $force, $download_as);
|
||||||
switch ($source['type']) {
|
|
||||||
case 'bitbuckettag': // BitBucket Tag
|
|
||||||
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
|
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
|
||||||
break;
|
|
||||||
case 'ghtar': // GitHub Release (tar)
|
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $source);
|
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as, hooks: [[CurlHook::class, 'setupGithubToken']]);
|
|
||||||
break;
|
|
||||||
case 'ghtagtar': // GitHub Tag (tar)
|
|
||||||
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
|
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as, hooks: [[CurlHook::class, 'setupGithubToken']]);
|
|
||||||
break;
|
|
||||||
case 'ghrel': // GitHub Release (uploaded)
|
|
||||||
[$url, $filename] = self::getLatestGithubRelease($name, $source);
|
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as, ['Accept: application/octet-stream'], [[CurlHook::class, 'setupGithubToken']]);
|
|
||||||
break;
|
|
||||||
case 'filelist': // Basic File List (regex based crawler)
|
|
||||||
[$url, $filename] = self::getFromFileList($name, $source);
|
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
|
||||||
break;
|
|
||||||
case 'url': // Direct download URL
|
|
||||||
$url = $source['url'];
|
|
||||||
$filename = $source['filename'] ?? basename($source['url']);
|
|
||||||
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
|
|
||||||
break;
|
|
||||||
case 'git': // Git repo
|
|
||||||
self::downloadGit(
|
|
||||||
$name,
|
|
||||||
$source['url'],
|
|
||||||
$source['rev'],
|
|
||||||
$source['submodules'] ?? null,
|
|
||||||
$source['path'] ?? null,
|
|
||||||
self::getRetryAttempts(),
|
|
||||||
$download_as
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'local':
|
|
||||||
// Local directory, do nothing, just lock it
|
|
||||||
logger()->debug("Locking local source {$name}");
|
|
||||||
LockFile::lockSource($name, [
|
|
||||||
'source_type' => SPC_SOURCE_LOCAL,
|
|
||||||
'dirname' => $source['dirname'],
|
|
||||||
'move_path' => $source['extract'] ?? null,
|
|
||||||
'lock_as' => $download_as,
|
|
||||||
]);
|
|
||||||
break;
|
|
||||||
case 'custom': // Custom download method, like API-based download or other
|
|
||||||
if (isset($source['func']) && is_callable($source['func'])) {
|
|
||||||
$source['name'] = $name;
|
|
||||||
$source['func']($force, $source, $download_as);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$classes = FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source');
|
|
||||||
foreach ($classes as $class) {
|
|
||||||
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
|
||||||
(new $class())->fetch($force, $source, $download_as);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new DownloaderException('unknown source type: ' . $source['type']);
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// Because sometimes files downloaded through the command line are not automatically deleted after a failure.
|
|
||||||
// Here we need to manually delete the file if it is detected to exist.
|
|
||||||
if (isset($filename) && file_exists(DOWNLOAD_PATH . '/' . $filename)) {
|
|
||||||
logger()->warning('Deleting download file: ' . $filename);
|
|
||||||
unlink(DOWNLOAD_PATH . '/' . $filename);
|
|
||||||
}
|
|
||||||
throw new DownloaderException('Download failed! ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -713,4 +599,109 @@ class Downloader
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download by type.
|
||||||
|
*
|
||||||
|
* @param string $type Types
|
||||||
|
* @param string $name Download item name
|
||||||
|
* @param array{
|
||||||
|
* url?: string,
|
||||||
|
* repo?: string,
|
||||||
|
* rev?: string,
|
||||||
|
* path?: string,
|
||||||
|
* filename?: string,
|
||||||
|
* dirname?: string,
|
||||||
|
* match?: string,
|
||||||
|
* prefer-stable?: bool,
|
||||||
|
* extract?: string,
|
||||||
|
* submodules?: array<string>,
|
||||||
|
* provide-pre-built?: bool,
|
||||||
|
* func?: ?callable,
|
||||||
|
* license?: array
|
||||||
|
* } $conf Download item config
|
||||||
|
* @param bool $force Force download
|
||||||
|
* @param int $download_as Lock source type
|
||||||
|
*/
|
||||||
|
private static function downloadByType(string $type, string $name, array $conf, bool $force, int $download_as): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
switch ($type) {
|
||||||
|
case 'pie': // Packagist
|
||||||
|
[$url, $filename] = self::getPIEInfo($name, $conf);
|
||||||
|
self::downloadFile($name, $url, $filename, $conf['path'] ?? $conf['extract'] ?? null, $download_as, hooks: [[CurlHook::class, 'setupGithubToken']]);
|
||||||
|
break;
|
||||||
|
case 'bitbuckettag': // BitBucket Tag
|
||||||
|
[$url, $filename] = self::getLatestBitbucketTag($name, $conf);
|
||||||
|
self::downloadFile($name, $url, $filename, $conf['path'] ?? $conf['extract'] ?? null, $download_as);
|
||||||
|
break;
|
||||||
|
case 'ghtar': // GitHub Release (tar)
|
||||||
|
[$url, $filename] = self::getLatestGithubTarball($name, $conf);
|
||||||
|
self::downloadFile($name, $url, $filename, $conf['path'] ?? $conf['extract'] ?? null, $download_as, hooks: [[CurlHook::class, 'setupGithubToken']]);
|
||||||
|
break;
|
||||||
|
case 'ghtagtar': // GitHub Tag (tar)
|
||||||
|
[$url, $filename] = self::getLatestGithubTarball($name, $conf, 'tags');
|
||||||
|
self::downloadFile($name, $url, $filename, $conf['path'] ?? $conf['extract'] ?? null, $download_as, hooks: [[CurlHook::class, 'setupGithubToken']]);
|
||||||
|
break;
|
||||||
|
case 'ghrel': // GitHub Release (uploaded)
|
||||||
|
[$url, $filename] = self::getLatestGithubRelease($name, $conf);
|
||||||
|
self::downloadFile($name, $url, $filename, $conf['path'] ?? $conf['extract'] ?? null, $download_as, ['Accept: application/octet-stream'], [[CurlHook::class, 'setupGithubToken']]);
|
||||||
|
break;
|
||||||
|
case 'filelist': // Basic File List (regex based crawler)
|
||||||
|
[$url, $filename] = self::getFromFileList($name, $conf);
|
||||||
|
self::downloadFile($name, $url, $filename, $conf['path'] ?? $conf['extract'] ?? null, $download_as);
|
||||||
|
break;
|
||||||
|
case 'url': // Direct download URL
|
||||||
|
$url = $conf['url'];
|
||||||
|
$filename = $conf['filename'] ?? basename($conf['url']);
|
||||||
|
self::downloadFile($name, $url, $filename, $conf['path'] ?? $conf['extract'] ?? null, $download_as);
|
||||||
|
break;
|
||||||
|
case 'git': // Git repo
|
||||||
|
self::downloadGit($name, $conf['url'], $conf['rev'], $conf['submodules'] ?? null, $conf['path'] ?? $conf['extract'] ?? null, self::getRetryAttempts(), $download_as);
|
||||||
|
break;
|
||||||
|
case 'local': // Local directory, do nothing, just lock it
|
||||||
|
LockFile::lockSource($name, [
|
||||||
|
'source_type' => SPC_SOURCE_LOCAL,
|
||||||
|
'dirname' => $conf['dirname'],
|
||||||
|
'move_path' => $conf['path'] ?? $conf['extract'] ?? null,
|
||||||
|
'lock_as' => $download_as,
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
case 'custom': // Custom download method, like API-based download or other
|
||||||
|
if (isset($conf['func']) && is_callable($conf['func'])) {
|
||||||
|
$conf['name'] = $name;
|
||||||
|
$conf['func']($force, $conf, $download_as);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$classes = [
|
||||||
|
...FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/source', 'SPC\store\source'),
|
||||||
|
...FileSystem::getClassesPsr4(ROOT_DIR . '/src/SPC/store/pkg', 'SPC\store\pkg'),
|
||||||
|
];
|
||||||
|
foreach ($classes as $class) {
|
||||||
|
if (is_a($class, CustomSourceBase::class, true) && $class::NAME === $name) {
|
||||||
|
(new $class())->fetch($force, $conf, $download_as);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (is_a($class, CustomPackage::class, true) && $class !== CustomPackage::class) {
|
||||||
|
$cls = new $class();
|
||||||
|
if (in_array($name, $cls->getSupportName())) {
|
||||||
|
(new $class())->fetch($name, $force, $conf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new DownloaderException("Unknown download type: {$type}");
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// Because sometimes files downloaded through the command line are not automatically deleted after a failure.
|
||||||
|
// Here we need to manually delete the file if it is detected to exist.
|
||||||
|
if (isset($filename) && file_exists(DOWNLOAD_PATH . '/' . $filename)) {
|
||||||
|
logger()->warning("Deleting download file: {$filename}");
|
||||||
|
unlink(DOWNLOAD_PATH . '/' . $filename);
|
||||||
|
}
|
||||||
|
throw new DownloaderException("Download failed: {$e->getMessage()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user