Skip to content

Commit 7fa6fd0

Browse files
committed
Add HostedPackageBin downloader and enhance artifact handling
1 parent 52553fb commit 7fa6fd0

File tree

6 files changed

+111
-14
lines changed

6 files changed

+111
-14
lines changed

src/StaticPHP/Artifact/ArtifactDownloader.php

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use StaticPHP\Artifact\Downloader\Type\Git;
1313
use StaticPHP\Artifact\Downloader\Type\GitHubRelease;
1414
use StaticPHP\Artifact\Downloader\Type\GitHubTarball;
15+
use StaticPHP\Artifact\Downloader\Type\HostedPackageBin;
1516
use StaticPHP\Artifact\Downloader\Type\LocalDir;
1617
use StaticPHP\Artifact\Downloader\Type\PhpRelease;
1718
use StaticPHP\Artifact\Downloader\Type\PIE;
@@ -35,6 +36,19 @@
3536
*/
3637
class ArtifactDownloader
3738
{
39+
public const array DOWNLOADERS = [
40+
'bitbuckettag' => BitBucketTag::class,
41+
'filelist' => FileList::class,
42+
'git' => Git::class,
43+
'ghrel' => GitHubRelease::class,
44+
'ghtar', 'ghtagtar' => GitHubTarball::class,
45+
'local' => LocalDir::class,
46+
'pie' => PIE::class,
47+
'url' => Url::class,
48+
'php-release' => PhpRelease::class,
49+
'hosted' => HostedPackageBin::class,
50+
];
51+
3852
/** @var array<string, Artifact> Artifact objects */
3953
protected array $artifacts = [];
4054

@@ -355,18 +369,7 @@ private function downloadWithType(Artifact $artifact, int $current, int $total,
355369
foreach ($queue as $item) {
356370
try {
357371
$instance = null;
358-
$call = match ($item['config']['type']) {
359-
'bitbuckettag' => BitBucketTag::class,
360-
'filelist' => FileList::class,
361-
'git' => Git::class,
362-
'ghrel' => GitHubRelease::class,
363-
'ghtar', 'ghtagtar' => GitHubTarball::class,
364-
'local' => LocalDir::class,
365-
'pie' => PIE::class,
366-
'url' => Url::class,
367-
'php-release' => PhpRelease::class,
368-
default => null,
369-
};
372+
$call = self::DOWNLOADERS[$item['config']['type']] ?? null;
370373
$type_display_name = match (true) {
371374
$item['lock'] === 'source' && ($callback = $artifact->getCustomSourceCallback()) !== null => 'user defined source downloader',
372375
$item['lock'] === 'binary' && ($callback = $artifact->getCustomBinaryCallback()) !== null => 'user defined binary downloader',

src/StaticPHP/Artifact/Downloader/Type/GitHubRelease.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,26 @@ class GitHubRelease implements DownloadTypeInterface, ValidatorInterface
2121

2222
private ?string $version = null;
2323

24+
public function getGitHubReleases(string $name, string $repo, bool $prefer_stable = true): array
25+
{
26+
logger()->debug("Fetching {$name} GitHub releases from {$repo}");
27+
$url = str_replace('{repo}', $repo, self::API_URL);
28+
$headers = $this->getGitHubTokenHeaders();
29+
$data2 = default_shell()->executeCurl($url, headers: $headers);
30+
$data = json_decode($data2 ?: '', true);
31+
if (!is_array($data)) {
32+
throw new DownloaderException("Failed to get GitHub release API info for {$repo} from {$url}");
33+
}
34+
$releases = [];
35+
foreach ($data as $release) {
36+
if ($prefer_stable && $release['prerelease'] === true) {
37+
continue;
38+
}
39+
$releases[] = $release;
40+
}
41+
return $releases;
42+
}
43+
2444
/**
2545
* Get the latest GitHub release assets for a given repository.
2646
* match_asset is provided, only return the asset that matches the regex.

src/StaticPHP/Artifact/Downloader/Type/GitHubTokenSetupTrait.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
trait GitHubTokenSetupTrait
88
{
99
public function getGitHubTokenHeaders(): array
10+
{
11+
return self::getGitHubTokenHeadersStatic();
12+
}
13+
14+
public static function getGitHubTokenHeadersStatic(): array
1015
{
1116
// GITHUB_TOKEN support
1217
if (($token = getenv('GITHUB_TOKEN')) !== false && ($user = getenv('GITHUB_USER')) !== false) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace StaticPHP\Artifact\Downloader\Type;
6+
7+
use StaticPHP\Artifact\ArtifactDownloader;
8+
use StaticPHP\Artifact\Downloader\DownloadResult;
9+
use StaticPHP\Exception\DownloaderException;
10+
use StaticPHP\Runtime\SystemTarget;
11+
12+
class HostedPackageBin implements DownloadTypeInterface
13+
{
14+
use GitHubTokenSetupTrait;
15+
16+
public const string BASE_REPO = 'static-php/package-bin';
17+
18+
public const array ASSET_MATCHES = [
19+
'linux' => '{name}-{arch}-{os}-{libc}-{libcver}.txz',
20+
'darwin' => '{name}-{arch}-{os}.txz',
21+
'windows' => '{name}-{arch}-{os}.tgz',
22+
];
23+
24+
private static array $release_info = [];
25+
26+
public static function getReleaseInfo(): array
27+
{
28+
if (empty(self::$release_info)) {
29+
$rel = (new GitHubRelease())->getGitHubReleases('hosted', self::BASE_REPO);
30+
if (empty($rel)) {
31+
throw new DownloaderException('No releases found for hosted package-bin');
32+
}
33+
self::$release_info = $rel[0];
34+
}
35+
return self::$release_info;
36+
}
37+
38+
public function download(string $name, array $config, ArtifactDownloader $downloader): DownloadResult
39+
{
40+
$info = self::getReleaseInfo();
41+
$replace = [
42+
'{name}' => $name,
43+
'{arch}' => SystemTarget::getTargetArch(),
44+
'{os}' => strtolower(SystemTarget::getTargetOS()),
45+
'{libc}' => SystemTarget::getLibc() ?? 'default',
46+
'{libcver}' => SystemTarget::getLibcVersion() ?? 'default',
47+
];
48+
$find_str = str_replace(array_keys($replace), array_values($replace), self::ASSET_MATCHES[strtolower(SystemTarget::getTargetOS())]);
49+
foreach ($info['assets'] as $asset) {
50+
if ($asset['name'] === $find_str) {
51+
$download_url = $asset['browser_download_url'];
52+
$filename = $asset['name'];
53+
$version = ltrim($info['tag_name'], 'v');
54+
logger()->debug("Downloading hosted package-bin {$name} version {$version} from GitHub: {$download_url}");
55+
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . $filename;
56+
$headers = $this->getGitHubTokenHeaders();
57+
default_shell()->executeCurlDownload($download_url, $path, headers: $headers, retries: $downloader->getRetry());
58+
return DownloadResult::archive($filename, $config, extract: $config['extract'] ?? null, version: $version);
59+
}
60+
}
61+
throw new DownloaderException("No matching asset found for hosted package-bin {$name} with criteria: {$find_str}");
62+
}
63+
}

src/StaticPHP/Command/SPCConfigCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function handle(): int
3333
{
3434
// transform string to array
3535
$libraries = parse_comma_list($this->getOption('with-libs'));
36-
$libraries = array_merge($libraries, $this->getOption('with-packages'));
36+
$libraries = array_merge($libraries, parse_comma_list($this->getOption('with-packages')));
3737
// transform string to array
3838
$extensions = $this->getArgument('extensions') ? parse_extension_list($this->getArgument('extensions')) : [];
3939
$include_suggests = $this->getOption('with-suggests') ?: $this->getOption('with-suggested-libs') || $this->getOption('with-suggested-exts');

src/StaticPHP/Config/ConfigValidator.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,14 @@ public static function validateAndLintArtifacts(string $config_file_name, mixed
137137
];
138138
continue;
139139
}
140-
// TODO: expand hosted to static-php hosted download urls
141140
if ($v === 'hosted') {
141+
$data[$name][$k] = [
142+
'linux-x86_64' => ['type' => 'hosted'],
143+
'linux-aarch64' => ['type' => 'hosted'],
144+
'windows-x86_64' => ['type' => 'hosted'],
145+
'macos-x86_64' => ['type' => 'hosted'],
146+
'macos-aarch64' => ['type' => 'hosted'],
147+
];
142148
continue;
143149
}
144150
if (is_assoc_array($v)) {

0 commit comments

Comments
 (0)