Skip to content

Commit 2167dea

Browse files
authored
Merge branch 'v3-dev' into v3-feat/musl-docker
2 parents 600ba82 + 106b55d commit 2167dea

File tree

10 files changed

+154
-55
lines changed

10 files changed

+154
-55
lines changed

src/Package/Artifact/go_xcaddy.php

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use StaticPHP\Artifact\Downloader\DownloadResult;
1010
use StaticPHP\Attribute\Artifact\AfterBinaryExtract;
1111
use StaticPHP\Attribute\Artifact\CustomBinary;
12-
use StaticPHP\Exception\ValidationException;
12+
use StaticPHP\Exception\DownloaderException;
1313
use StaticPHP\Runtime\SystemTarget;
1414
use StaticPHP\Util\System\LinuxUtil;
1515

@@ -28,29 +28,41 @@ public function downBinary(ArtifactDownloader $downloader): DownloadResult
2828
$arch = match (explode('-', $name)[1]) {
2929
'x86_64' => 'amd64',
3030
'aarch64' => 'arm64',
31-
default => throw new ValidationException('Unsupported architecture: ' . $name),
31+
default => throw new DownloaderException('Unsupported architecture: ' . $name),
3232
};
3333
$os = match (explode('-', $name)[0]) {
3434
'linux' => 'linux',
3535
'macos' => 'darwin',
36-
default => throw new ValidationException('Unsupported OS: ' . $name),
36+
default => throw new DownloaderException('Unsupported OS: ' . $name),
3737
};
38-
$hash = match ("{$os}-{$arch}") {
39-
'linux-amd64' => '2852af0cb20a13139b3448992e69b868e50ed0f8a1e5940ee1de9e19a123b613',
40-
'linux-arm64' => '05de75d6994a2783699815ee553bd5a9327d8b79991de36e38b66862782f54ae',
41-
'darwin-amd64' => '5bd60e823037062c2307c71e8111809865116714d6f6b410597cf5075dfd80ef',
42-
'darwin-arm64' => '544932844156d8172f7a28f77f2ac9c15a23046698b6243f633b0a0b00c0749c',
43-
};
44-
$go_version = '1.25.0';
45-
$url = "https://go.dev/dl/go{$go_version}.{$os}-{$arch}.tar.gz";
46-
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . "go{$go_version}.{$os}-{$arch}.tar.gz";
38+
39+
// get version and hash
40+
[$version] = explode("\n", default_shell()->executeCurl('https://go.dev/VERSION?m=text') ?: '');
41+
if ($version === '') {
42+
throw new DownloaderException('Failed to get latest Go version from https://go.dev/VERSION?m=text');
43+
}
44+
$page = default_shell()->executeCurl('https://go.dev/dl/');
45+
if ($page === '' || $page === false) {
46+
throw new DownloaderException('Failed to get Go download page from https://go.dev/dl/');
47+
}
48+
49+
$version_regex = str_replace('.', '\.', $version);
50+
$pattern = "/href=\"\\/dl\\/{$version_regex}\\.{$os}-{$arch}\\.tar\\.gz\">.*?<tt>([a-f0-9]{64})<\\/tt>/s";
51+
if (preg_match($pattern, $page, $matches)) {
52+
$hash = $matches[1];
53+
} else {
54+
throw new DownloaderException("Failed to find download hash for Go {$version} {$os}-{$arch}");
55+
}
56+
57+
$url = "https://go.dev/dl/{$version}.{$os}-{$arch}.tar.gz";
58+
$path = DOWNLOAD_PATH . DIRECTORY_SEPARATOR . "{$version}.{$os}-{$arch}.tar.gz";
4759
default_shell()->executeCurlDownload($url, $path, retries: $downloader->getRetry());
4860
// verify hash
4961
$file_hash = hash_file('sha256', $path);
5062
if ($file_hash !== $hash) {
51-
throw new ValidationException("Hash mismatch for downloaded go-xcaddy binary. Expected {$hash}, got {$file_hash}");
63+
throw new DownloaderException("Hash mismatch for downloaded go-xcaddy binary. Expected {$hash}, got {$file_hash}");
5264
}
53-
return DownloadResult::archive(basename($path), ['url' => $url, 'version' => $go_version], extract: "{$pkgroot}/go-xcaddy", verified: true, version: $go_version);
65+
return DownloadResult::archive(basename($path), ['url' => $url, 'version' => $version], extract: "{$pkgroot}/go-xcaddy", verified: true, version: $version);
5466
}
5567

5668
#[AfterBinaryExtract('go-xcaddy', [

src/StaticPHP/Artifact/ArtifactDownloader.php

Lines changed: 17 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,21 @@
3536
*/
3637
class ArtifactDownloader
3738
{
39+
/** @var array<string, class-string<DownloadTypeInterface>> */
40+
public const array DOWNLOADERS = [
41+
'bitbuckettag' => BitBucketTag::class,
42+
'filelist' => FileList::class,
43+
'git' => Git::class,
44+
'ghrel' => GitHubRelease::class,
45+
'ghtar' => GitHubTarball::class,
46+
'ghtagtar' => GitHubTarball::class,
47+
'local' => LocalDir::class,
48+
'pie' => PIE::class,
49+
'url' => Url::class,
50+
'php-release' => PhpRelease::class,
51+
'hosted' => HostedPackageBin::class,
52+
];
53+
3854
/** @var array<string, Artifact> Artifact objects */
3955
protected array $artifacts = [];
4056

@@ -355,18 +371,7 @@ private function downloadWithType(Artifact $artifact, int $current, int $total,
355371
foreach ($queue as $item) {
356372
try {
357373
$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-
};
374+
$call = self::DOWNLOADERS[$item['config']['type']] ?? null;
370375
$type_display_name = match (true) {
371376
$item['lock'] === 'source' && ($callback = $artifact->getCustomSourceCallback()) !== null => 'user defined source downloader',
372377
$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}: {$find_str}");
62+
}
63+
}

src/StaticPHP/Command/DownloadCommand.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public function configure(): void
2727
$this->addOption('for-libs', 'l', InputOption::VALUE_REQUIRED, 'Fetch by libraries, e.g "libcares,openssl,onig"');
2828
$this->addOption('without-suggests', null, null, 'Do not fetch suggested sources when using --for-extensions');
2929

30+
$this->addOption('without-suggestions', null, null, '(deprecated) Do not fetch suggested sources when using --for-extensions');
31+
3032
// download command specific options
3133
$this->addOption('clean', null, null, 'Clean old download cache and source before fetch');
3234
$this->addOption('for-packages', null, InputOption::VALUE_REQUIRED, 'Fetch by packages, e.g "php,libssl,libcurl"');

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)) {

src/StaticPHP/Util/FileSystem.php

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -370,17 +370,6 @@ public static function resetDir(string $dir_name): void
370370
self::createDir($dir_name);
371371
}
372372

373-
/**
374-
* Add source extraction hook
375-
*
376-
* @param string $name Source name
377-
* @param callable $callback Callback function
378-
*/
379-
public static function addSourceExtractHook(string $name, callable $callback): void
380-
{
381-
self::$_extract_hook[$name][] = $callback;
382-
}
383-
384373
/**
385374
* Check if path is relative
386375
*

src/StaticPHP/Util/SPCConfigUtil.php

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use StaticPHP\Config\PackageConfig;
88
use StaticPHP\Exception\WrongUsageException;
9+
use StaticPHP\Package\LibraryPackage;
10+
use StaticPHP\Package\PhpExtensionPackage;
911
use StaticPHP\Runtime\SystemTarget;
1012

1113
class SPCConfigUtil
@@ -99,42 +101,37 @@ public function config(array $packages = [], bool $include_suggests = false): ar
99101
* [Helper function]
100102
* Get configuration for a specific extension(s) dependencies.
101103
*
102-
* @param Extension|Extension[] $extension Extension instance or list
103-
* @param bool $include_suggest_ext Whether to include suggested extensions
104-
* @param bool $include_suggest_lib Whether to include suggested libraries
104+
* @param array|PhpExtensionPackage $extension_packages Extension instance or list
105105
* @return array{
106106
* cflags: string,
107107
* ldflags: string,
108108
* libs: string
109109
* }
110110
*/
111-
public function getExtensionConfig(array|Extension $extension, bool $include_suggest_ext = false, bool $include_suggest_lib = false): array
111+
public function getExtensionConfig(array|PhpExtensionPackage $extension_packages, bool $include_suggests = false): array
112112
{
113-
if (!is_array($extension)) {
114-
$extension = [$extension];
113+
if (!is_array($extension_packages)) {
114+
$extension_packages = [$extension_packages];
115115
}
116-
$libs = array_map(fn ($y) => $y->getName(), array_merge(...array_map(fn ($x) => $x->getLibraryDependencies(true), $extension)));
117116
return $this->config(
118-
extensions: array_map(fn ($x) => $x->getName(), $extension),
119-
libraries: $libs,
120-
include_suggest_ext: $include_suggest_ext ?: $this->builder?->getOption('with-suggested-exts') ?? false,
121-
include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false,
117+
packages: array_map(fn ($y) => $y->getName(), $extension_packages),
118+
include_suggests: $include_suggests,
122119
);
123120
}
124121

125122
/**
126123
* [Helper function]
127124
* Get configuration for a specific library(s) dependencies.
128125
*
129-
* @param LibraryBase|LibraryBase[] $lib Library instance or list
130-
* @param bool $include_suggest_lib Whether to include suggested libraries
126+
* @param array|LibraryPackage $lib Library instance or list
127+
* @param bool $include_suggests Whether to include suggested libraries
131128
* @return array{
132129
* cflags: string,
133130
* ldflags: string,
134131
* libs: string
135132
* }
136133
*/
137-
public function getLibraryConfig(array|LibraryBase $lib, bool $include_suggest_lib = false): array
134+
public function getLibraryConfig(array|LibraryPackage $lib, bool $include_suggests = false): array
138135
{
139136
if (!is_array($lib)) {
140137
$lib = [$lib];
@@ -144,8 +141,8 @@ public function getLibraryConfig(array|LibraryBase $lib, bool $include_suggest_l
144141
$save_libs_only_deps = $this->libs_only_deps;
145142
$this->libs_only_deps = true;
146143
$ret = $this->config(
147-
libraries: array_map(fn ($x) => $x->getName(), $lib),
148-
include_suggest_lib: $include_suggest_lib ?: $this->builder?->getOption('with-suggested-libs') ?? false,
144+
packages: array_map(fn ($y) => $y->getName(), $lib),
145+
include_suggests: $include_suggests,
149146
);
150147
$this->no_php = $save_no_php;
151148
$this->libs_only_deps = $save_libs_only_deps;

0 commit comments

Comments
 (0)