Allow locking different arch pre-built content

This commit is contained in:
crazywhalecc
2025-03-30 16:53:14 +08:00
parent 5648681ecc
commit 87c0535624
12 changed files with 150 additions and 76 deletions

View File

@@ -189,7 +189,7 @@ class Downloader
* @throws RuntimeException
* @throws WrongUsageException
*/
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $lock_as = SPC_LOCK_SOURCE): void
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null, int $download_as = SPC_DOWN_SOURCE): void
{
logger()->debug("Downloading {$url}");
$cancel_func = function () use ($filename) {
@@ -202,12 +202,23 @@ class Downloader
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"), retry: self::getRetryTime());
self::unregisterCancelEvent();
logger()->debug("Locking {$filename}");
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $lock_as]);
if ($download_as === SPC_DOWN_PRE_BUILT) {
$name = self::getPreBuiltName($name);
}
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path, 'lock_as' => $download_as]);
}
/**
* Try to lock source.
*
* @param string $name Source name
* @param array{
* source_type: string,
* dirname: ?string,
* filename: ?string,
* move_path: ?string,
* lock_as: int
* } $data Source data
* @throws FileSystemException
*/
public static function lockSource(string $name, array $data): void
@@ -228,7 +239,7 @@ class Downloader
* @throws RuntimeException
* @throws WrongUsageException
*/
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_LOCK_SOURCE): void
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null, int $retry = 0, int $lock_as = SPC_DOWN_SOURCE): void
{
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
if (file_exists($download_path)) {
@@ -316,50 +327,36 @@ class Downloader
FileSystem::createDir(DOWNLOAD_PATH);
}
// load lock file
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
$lock = [];
} else {
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
}
// If lock file exists, skip downloading
if (isset($lock[$name]) && !$force) {
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['filename']);
return;
}
if ($lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])) {
logger()->notice("Package [{$name}] already downloaded: " . $lock[$name]['dirname']);
return;
}
if (self::isAlreadyDownloaded($name, $force, SPC_DOWN_PACKAGE)) {
return;
}
try {
switch ($pkg['type']) {
case 'bitbuckettag': // BitBucket Tag
[$url, $filename] = self::getLatestBitbucketTag($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWN_PACKAGE);
break;
case 'ghtar': // GitHub Release (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWN_PACKAGE);
break;
case 'ghtagtar': // GitHub Tag (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $pkg, 'tags');
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWN_PACKAGE);
break;
case 'ghrel': // GitHub Release (uploaded)
[$url, $filename] = self::getLatestGithubRelease($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWN_PACKAGE);
break;
case 'filelist': // Basic File List (regex based crawler)
[$url, $filename] = self::getFromFileList($name, $pkg);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_LOCK_PRE_BUILT);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWN_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_LOCK_PRE_BUILT);
self::downloadFile($name, $url, $filename, $pkg['extract'] ?? null, SPC_DOWN_PACKAGE);
break;
case 'git': // Git repo
self::downloadGit(
@@ -368,7 +365,7 @@ class Downloader
$pkg['rev'],
$pkg['extract'] ?? null,
self::getRetryTime(),
SPC_LOCK_PRE_BUILT
SPC_DOWN_PRE_BUILT
);
break;
case 'custom': // Custom download method, like API-based download or other
@@ -414,13 +411,13 @@ class Downloader
* text: ?string
* }
* } $source source meta info: [type, path, rev, url, filename, regex, license]
* @param bool $force Whether to force download (default: false)
* @param int $lock_as Lock source type (default: SPC_LOCK_SOURCE)
* @param bool $force Whether to force download (default: false)
* @param int $download_as Lock source type (default: SPC_LOCK_SOURCE)
* @throws DownloaderException
* @throws FileSystemException
* @throws WrongUsageException
*/
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $lock_as = SPC_LOCK_SOURCE): void
public static function downloadSource(string $name, ?array $source = null, bool $force = false, int $download_as = SPC_DOWN_SOURCE): void
{
if ($source === null) {
$source = Config::getSource($name);
@@ -436,49 +433,36 @@ class Downloader
}
// load lock file
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
$lock = [];
} else {
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
}
// If lock file exists, skip downloading
if (isset($lock[$name]) && !$force && ($lock[$name]['lock_as'] ?? SPC_LOCK_SOURCE) === $lock_as) {
if ($lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename'])) {
logger()->notice("Source [{$name}] already downloaded: " . $lock[$name]['filename']);
return;
}
if ($lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])) {
logger()->notice("Source [{$name}] already downloaded: " . $lock[$name]['dirname']);
return;
}
if (self::isAlreadyDownloaded($name, $force, $download_as)) {
return;
}
try {
switch ($source['type']) {
case 'bitbuckettag': // BitBucket Tag
[$url, $filename] = self::getLatestBitbucketTag($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
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, $lock_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
break;
case 'ghtagtar': // GitHub Tag (tar)
[$url, $filename] = self::getLatestGithubTarball($name, $source, 'tags');
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
break;
case 'ghrel': // GitHub Release (uploaded)
[$url, $filename] = self::getLatestGithubRelease($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
break;
case 'filelist': // Basic File List (regex based crawler)
[$url, $filename] = self::getFromFileList($name, $source);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $lock_as);
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, $lock_as);
self::downloadFile($name, $url, $filename, $source['path'] ?? null, $download_as);
break;
case 'git': // Git repo
self::downloadGit(
@@ -487,14 +471,14 @@ class Downloader
$source['rev'],
$source['path'] ?? null,
self::getRetryTime(),
$lock_as
$download_as
);
break;
case 'custom': // Custom download method, like API-based download or other
$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, $lock_as);
(new $class())->fetch($force, $source, $download_as);
break;
}
}
@@ -609,6 +593,11 @@ class Downloader
}
}
public static function getPreBuiltName(string $source): string
{
return "{$source}-" . PHP_OS_FAMILY . '-' . getenv('GNU_ARCH') . '-' . (getenv('SPC_LIBC') ?: 'default');
}
/**
* Register CTRL+C event for different OS.
*
@@ -641,4 +630,39 @@ class Downloader
{
return intval(getenv('SPC_RETRY_TIME') ? getenv('SPC_RETRY_TIME') : 0);
}
/**
* @throws FileSystemException
*/
private static function isAlreadyDownloaded(string $name, bool $force, int $download_as = SPC_DOWN_SOURCE): bool
{
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
$lock = [];
} else {
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
}
// If lock file exists, skip downloading for source mode
if (!$force && $download_as === SPC_DOWN_SOURCE && isset($lock[$name])) {
if (
$lock[$name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$name]['filename']) ||
$lock[$name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$name]['dirname'])
) {
logger()->notice("Source [{$name}] already downloaded: " . ($lock[$name]['filename'] ?? $lock[$name]['dirname']));
return true;
}
}
// If lock file exists for current arch and glibc target, skip downloading
$lock_name = self::getPreBuiltName($name);
if (!$force && $download_as === SPC_DOWN_PRE_BUILT && isset($lock[$lock_name])) {
// lock name with env
if (
$lock[$lock_name]['source_type'] === 'archive' && file_exists(DOWNLOAD_PATH . '/' . $lock[$lock_name]['filename']) ||
$lock[$lock_name]['source_type'] === 'dir' && is_dir(DOWNLOAD_PATH . '/' . $lock[$lock_name]['dirname'])
) {
logger()->notice("Pre-built content [{$name}] already downloaded: " . ($lock[$lock_name]['filename'] ?? $lock[$lock_name]['dirname']));
return true;
}
}
return false;
}
}