mirror of
https://github.com/shivammathur/setup-php.git
synced 2026-08-29 10:19:26 +07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5240f9517c |
@@ -254,27 +254,6 @@ describe('Utils tests', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('builds the run-script path from only the script filename', () => {
|
||||
const scriptPath = path.join(
|
||||
'/tmp',
|
||||
'feature',
|
||||
'php-darwin-cache',
|
||||
'src',
|
||||
'scripts',
|
||||
'darwin.sh'
|
||||
);
|
||||
expect(utils.scriptRunPath(scriptPath)).toBe(
|
||||
path.join(
|
||||
'/tmp',
|
||||
'feature',
|
||||
'php-darwin-cache',
|
||||
'src',
|
||||
'scripts',
|
||||
'run.sh'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('checking scriptTool', async () => {
|
||||
expect(await utils.scriptTool('linux')).toBe('bash ');
|
||||
expect(await utils.scriptTool('darwin')).toBe('bash ');
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -17,7 +17,7 @@ export async function getScript(os: string): Promise<string> {
|
||||
const url = 'https://setup-php.com/sponsor';
|
||||
const filename = os + (await utils.scriptExtension(os));
|
||||
const script_path = path.join(__dirname, '../src/scripts', filename);
|
||||
const run_path = utils.scriptRunPath(script_path);
|
||||
const run_path = script_path.replace(os, 'run');
|
||||
const extension_csv: string = utils.sanitizeShellInput(
|
||||
await utils.getInput('extensions', false),
|
||||
true
|
||||
|
||||
+21
-9
@@ -174,11 +174,23 @@ get_brewed_php() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Install PHP from the architecture-specific php-darwin cache.
|
||||
add_php_from_cache() {
|
||||
cache_root="${src:?}/scripts/tools/php-darwin"
|
||||
PHP_DARWIN_ROOT="$cache_root" bash "$cache_root/scripts/install.sh" \
|
||||
"$version" "${debug:?}" "${ts:?}"
|
||||
# Function to setup PHP from the cached builds.
|
||||
setup_cached_versions() {
|
||||
local cache_log
|
||||
local cache_status
|
||||
|
||||
cache_log=$(mktemp "${RUNNER_TEMP:-/tmp}/setup-php-php-darwin.XXXXXX") || return 1
|
||||
if run_script "php-darwin" "$version" "${debug:?}" "${ts:?}" >"$cache_log" 2>&1; then
|
||||
rm -f "$cache_log"
|
||||
return 0
|
||||
else
|
||||
cache_status=$?
|
||||
fi
|
||||
printf 'setup-php: php-darwin cache installation failed (exit %s); falling back to Homebrew\n' \
|
||||
"$cache_status" >&4
|
||||
cat "$cache_log" >&4
|
||||
rm -f "$cache_log"
|
||||
return "$cache_status"
|
||||
}
|
||||
|
||||
# Function to setup PHP 5.6 and newer using Homebrew.
|
||||
@@ -189,7 +201,7 @@ add_php() {
|
||||
php_keg="php@$version$suffix"
|
||||
php_formula="shivammathur/php/$php_keg"
|
||||
if [[ "$existing_version" = "false" || -n "$suffix" || "$action" = "upgrade" ]]; then
|
||||
if add_php_from_cache; then
|
||||
if [ "${runner:?}" != "self-hosted" ] && [ "${use_package_cache:-true}" != "false" ] && setup_cached_versions; then
|
||||
return 0
|
||||
fi
|
||||
update_dependencies
|
||||
@@ -262,13 +274,13 @@ setup_php() {
|
||||
if [[ "$version" =~ ${old_versions:?} ]]; then
|
||||
run_script "php5-darwin" "${version/./}" >/dev/null 2>&1
|
||||
status="Installed"
|
||||
elif [ "${existing_version:0:3}" != "$version" ]; then
|
||||
add_php "install" "$existing_version" >/dev/null 2>&1
|
||||
elif [[ "${existing_version:0:3}" != "$version" || -n "$(get_php_formula_suffix)" ]]; then
|
||||
add_php "install" "$existing_version" 4>&2 >/dev/null 2>&1
|
||||
status="Installed"
|
||||
elif [[ "${existing_version:0:3}" = "$version" && "${update:?}" = "true" ]]; then
|
||||
brew_php_version="$(brew info --json "php@$version" 2>/dev/null | jq -r '.[].versions.stable')"
|
||||
if [ "$brew_php_version" != "$existing_version" ]; then
|
||||
add_php "upgrade" "$existing_version" >/dev/null 2>&1
|
||||
add_php "upgrade" "$existing_version" 4>&2 >/dev/null 2>&1
|
||||
status="Upgraded"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# Homebrew prefix roots permitted in an archive and merged during installation.
|
||||
Cellar
|
||||
etc
|
||||
opt
|
||||
var
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"archive_media_type": "application/vnd.shivammathur.php-darwin.cache.layer.v1.tar+zstd",
|
||||
"artifact_type": "application/vnd.shivammathur.php-darwin.cache.v1",
|
||||
"compression_level": 19,
|
||||
"current_version": "8.5",
|
||||
"image": "ghcr.io/shivammathur/php-darwin",
|
||||
"max_install_seconds": 60,
|
||||
"registry_manifest_media_type": "application/vnd.oci.image.manifest.v1+json",
|
||||
"tap": "shivammathur/php",
|
||||
"tap_branch": "main",
|
||||
"tap_repository": "https://github.com/shivammathur/homebrew-php"
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"arm64": {
|
||||
"build_runner": "macos-15",
|
||||
"brew_prefix": "/opt/homebrew",
|
||||
"minimum_macos": 15,
|
||||
"platform_key": "arm64_sequoia",
|
||||
"test_runners": ["macos-15", "macos-26"]
|
||||
},
|
||||
"x86_64": {
|
||||
"build_runner": "macos-15-intel",
|
||||
"brew_prefix": "/usr/local",
|
||||
"minimum_macos": 15,
|
||||
"platform_key": "sequoia",
|
||||
"test_runners": ["macos-15-intel", "macos-26-intel"]
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
# channel version
|
||||
stable 5.6
|
||||
stable 7.0
|
||||
stable 7.1
|
||||
stable 7.2
|
||||
stable 7.3
|
||||
stable 7.4
|
||||
stable 8.0
|
||||
stable 8.1
|
||||
stable 8.2
|
||||
stable 8.3
|
||||
stable 8.4
|
||||
stable 8.5
|
||||
nightly 8.6
|
||||
@@ -1,52 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
prefix=${1:?}
|
||||
output=${2:?}
|
||||
roots_file=${3:?}
|
||||
path_list="$output.paths.$$"
|
||||
trap 'rm -f "$path_list"' EXIT
|
||||
|
||||
[ -d "$prefix" ] || {
|
||||
printf 'Missing Homebrew prefix: %s\n' "$prefix" >&2
|
||||
exit 1
|
||||
}
|
||||
[ -f "$roots_file" ] || {
|
||||
printf 'Missing archive roots: %s\n' "$roots_file" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
: > "$output" || exit 1
|
||||
while IFS= read -r managed_dir extra; do
|
||||
[ -n "$managed_dir" ] || continue
|
||||
case "$managed_dir" in \#*) continue ;; esac
|
||||
[ -z "$extra" ] || {
|
||||
printf 'Invalid archive root: %s %s\n' "$managed_dir" "$extra" >&2
|
||||
exit 1
|
||||
}
|
||||
case "$managed_dir" in Cellar|etc|opt|var) ;; *)
|
||||
printf 'Unsafe archive root: %s\n' "$managed_dir" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ "$managed_dir" = Cellar ]; then
|
||||
# One exclusion per existing keg protects its complete subtree and keeps
|
||||
# the pattern file small even on runner images with hundreds of formulae.
|
||||
find "$prefix/Cellar" -mindepth 2 -maxdepth 2 -print0 > "$path_list" || exit 1
|
||||
else
|
||||
find "$prefix/$managed_dir" ! -type d -print0 > "$path_list" || exit 1
|
||||
fi
|
||||
while IFS= read -r -d '' existing_path; do
|
||||
relative_path=${existing_path#"$prefix"/}
|
||||
case "$relative_path" in *$'\n'*|*$'\r'*)
|
||||
printf 'Unsupported Homebrew path: %s\n' "$relative_path" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
tar_pattern=${relative_path//\\/\\\\}
|
||||
tar_pattern=${tar_pattern//\[/\\[}
|
||||
tar_pattern=${tar_pattern//\]/\\]}
|
||||
tar_pattern=${tar_pattern//\*/\\*}
|
||||
tar_pattern=${tar_pattern//\?/\\?}
|
||||
printf '%s\n' "$tar_pattern" >> "$output" || exit 1
|
||||
done < "$path_list"
|
||||
done < "$roots_file"
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
archive=${1:?}
|
||||
prefix=${2:?}
|
||||
exclude_file=${3:?}
|
||||
|
||||
[ -f "$archive" ] || {
|
||||
printf 'Archive not found: %s\n' "$archive" >&2
|
||||
exit 1
|
||||
}
|
||||
[ -d "$prefix" ] || {
|
||||
printf 'Extraction prefix not found: %s\n' "$prefix" >&2
|
||||
exit 1
|
||||
}
|
||||
[ -f "$exclude_file" ] || {
|
||||
printf 'Extraction exclusion list not found: %s\n' "$exclude_file" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
zstd -dc "$archive" | tar -xmpf - --no-same-owner -X "$exclude_file" -C "$prefix"
|
||||
pipeline_status=("${PIPESTATUS[@]}")
|
||||
[ "${pipeline_status[0]}" -eq 0 ] && [ "${pipeline_status[1]}" -eq 0 ]
|
||||
@@ -1,149 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck source=scripts/lib.sh
|
||||
. "$script_dir/lib.sh"
|
||||
|
||||
version=${1:-8.5}
|
||||
build=${2:-release}
|
||||
ts=${3:-nts}
|
||||
local_archive=${4:-}
|
||||
arch=$(php_darwin_normalize_arch "$(uname -m)")
|
||||
formula=$(php_darwin_formula "$version" "$build" "$ts")
|
||||
requested_formula=$(php_darwin_requested_formula "$version" "$build" "$ts")
|
||||
asset=$(php_darwin_asset "$version" "$build" "$ts" "$arch")
|
||||
expected_prefix=$(php_darwin_expected_prefix "$arch")
|
||||
tap=$(php_darwin_package_config tap)
|
||||
archive_roots="$script_dir/../conf/archive-paths"
|
||||
|
||||
[ "$(uname -s)" = Darwin ] || php_darwin_die 'the cache installer only supports macOS'
|
||||
command -v brew >/dev/null 2>&1 || php_darwin_die 'Homebrew is required'
|
||||
brew_prefix=$(brew --prefix)
|
||||
[ "$brew_prefix" = "$expected_prefix" ] || php_darwin_die "architecture $arch requires Homebrew at $expected_prefix, found $brew_prefix"
|
||||
command -v zstd >/dev/null 2>&1 || php_darwin_die 'zstd is required to extract the cache'
|
||||
macos_version=$(sw_vers -productVersion) || php_darwin_die 'could not determine the macOS version'
|
||||
macos_major=${macos_version%%.*}
|
||||
|
||||
while IFS= read -r managed_dir extra; do
|
||||
[ -n "$managed_dir" ] || continue
|
||||
case "$managed_dir" in \#*) continue ;; esac
|
||||
[ -z "$extra" ] || php_darwin_die "invalid archive root: $managed_dir $extra"
|
||||
case "$managed_dir" in Cellar|etc|opt|var) ;; *) php_darwin_die "unsafe archive root: $managed_dir" ;; esac
|
||||
[ -d "$brew_prefix/$managed_dir" ] || mkdir -p "$brew_prefix/$managed_dir" || \
|
||||
php_darwin_die "could not create Homebrew directory: $brew_prefix/$managed_dir"
|
||||
[ -w "$brew_prefix/$managed_dir" ] || \
|
||||
php_darwin_die "Homebrew directory is not writable: $brew_prefix/$managed_dir"
|
||||
done < "$archive_roots"
|
||||
|
||||
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||
export HOMEBREW_NO_ENV_HINTS=1
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
export HOMEBREW_NO_INSTALL_FROM_API=1
|
||||
|
||||
# Use Homebrew to establish the formula source and trust state. In setup-php the
|
||||
# tap is already present, so this is a local no-op and adds no install request.
|
||||
brew tap "$tap" || php_darwin_die "could not tap $tap"
|
||||
brew trust "$tap" || php_darwin_die "could not trust $tap"
|
||||
brew formula "$tap/$requested_formula" >/dev/null || php_darwin_die "could not resolve $tap/$requested_formula"
|
||||
|
||||
tmp_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-install.XXXXXX")
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
archive="$tmp_dir/$asset"
|
||||
external_metadata=
|
||||
|
||||
if [ -n "$local_archive" ]; then
|
||||
archive=$local_archive
|
||||
checksum="$local_archive.sha256"
|
||||
external_metadata="$(dirname "$local_archive")/${asset%.tar.zst}.json"
|
||||
[ -f "$archive" ] || php_darwin_die "archive not found: $archive"
|
||||
[ -f "$checksum" ] || php_darwin_die "checksum not found: $checksum"
|
||||
[ -f "$external_metadata" ] || php_darwin_die "metadata not found: $external_metadata"
|
||||
expected_hash=$(awk -v name="$asset" '$2 == name { print $1; found=1; exit } END { exit !found }' "$checksum") || \
|
||||
php_darwin_die "checksum file does not contain $asset"
|
||||
[[ "$expected_hash" =~ ^[0-9a-f]{64}$ ]] || php_darwin_die "checksum is invalid for $asset"
|
||||
actual_hash=$(php_darwin_sha256 "$archive") || php_darwin_die "could not hash $asset"
|
||||
[ "$actual_hash" = "$expected_hash" ] || php_darwin_die "checksum mismatch for $asset"
|
||||
else
|
||||
image=${PHP_DARWIN_IMAGE:-$(php_darwin_package_config image)}
|
||||
tag="php-$version-$ts-$build"
|
||||
descriptor="$tmp_dir/descriptor.json"
|
||||
bash "$script_dir/registry.sh" pull "$image" "$tag" "$asset" "$archive" "$descriptor" || \
|
||||
php_darwin_die "could not pull $image:$tag"
|
||||
if ! jq -e --arg version "$version" --arg build "$build" --arg ts "$ts" \
|
||||
--arg artifact_type "$(php_darwin_package_config artifact_type)" \
|
||||
--arg manifest_media_type "$(php_darwin_package_config registry_manifest_media_type)" \
|
||||
--arg media_type "$(php_darwin_package_config archive_media_type)" \
|
||||
--argjson macos_major "$macos_major" \
|
||||
'.annotations["com.setup-php.php-darwin.php-version"] == $version and
|
||||
.annotations["com.setup-php.php-darwin.build"] == $build and
|
||||
.annotations["com.setup-php.php-darwin.thread-safety"] == $ts and
|
||||
(.annotations["com.setup-php.php-darwin.minimum-macos"] | tonumber) <= $macos_major and
|
||||
(.annotations["com.setup-php.php-darwin.homebrew-php-commit"] |
|
||||
type == "string" and test("^[0-9a-f]{40}$")) and
|
||||
(.annotations["com.setup-php.php-darwin.source-hash"] |
|
||||
type == "string" and test("^[0-9a-f]{64}$")) and
|
||||
(.annotations["org.opencontainers.image.version"] |
|
||||
type == "string" and startswith($version + ".") and test("^[0-9]+\\.[0-9]+\\.[0-9]+$")) and
|
||||
.schema_version == 2 and .artifact_type == $artifact_type and
|
||||
.manifest_media_type == $manifest_media_type and
|
||||
.layer.mediaType == $media_type' "$descriptor" >/dev/null; then
|
||||
php_darwin_die 'OCI manifest annotations did not match the request'
|
||||
fi
|
||||
tap_path=$(brew --repository "$tap") || php_darwin_die "could not resolve the $tap repository"
|
||||
current_source_hash=$(HOMEBREW_PHP_PATH="$tap_path" bash "$script_dir/source-hash.sh" "$version") || \
|
||||
php_darwin_die "could not compute the installed $tap source hash"
|
||||
cached_source_hash=$(jq -er '.annotations["com.setup-php.php-darwin.source-hash"]' "$descriptor") || \
|
||||
php_darwin_die 'OCI manifest source hash is missing'
|
||||
[ "$cached_source_hash" = "$current_source_hash" ] || \
|
||||
php_darwin_die "cache is stale for the installed $tap formulae"
|
||||
fi
|
||||
|
||||
if [ -n "$external_metadata" ]; then
|
||||
if ! jq -e --arg version "$version" --arg build "$build" --arg ts "$ts" \
|
||||
--arg arch "$arch" --arg brew_prefix "$brew_prefix" --arg asset "$asset" --arg formula "$formula" \
|
||||
--arg expected_commit "${HOMEBREW_PHP_COMMIT:-}" --arg requested_formula "$requested_formula" \
|
||||
--argjson macos_major "$macos_major" \
|
||||
'.schema == 1 and .php_version == $version and .build == $build and
|
||||
.thread_safety == $ts and .architecture == $arch and .brew_prefix == $brew_prefix and
|
||||
.archive == $asset and .formula == $formula and .requested_formula == $requested_formula and
|
||||
.minimum_macos <= $macos_major and
|
||||
(.homebrew_php_commit | type == "string" and test("^[0-9a-f]{40}$")) and
|
||||
($expected_commit == "" or .homebrew_php_commit == $expected_commit) and
|
||||
(.formula_sha256 | type == "string" and test("^[0-9a-f]{64}$")) and
|
||||
(.php_semver | type == "string" and startswith($version + ".") and test("^[0-9]+\\.[0-9]+\\.[0-9]+$")) and
|
||||
(.packages | type == "array" and length > 0) and any(.packages[]; .name == $formula)' \
|
||||
"$external_metadata" >/dev/null; then
|
||||
php_darwin_die 'archive metadata did not match the runner or request'
|
||||
fi
|
||||
fi
|
||||
|
||||
# Let Homebrew remove only the requested PHP formula, then build a literal
|
||||
# exclusion list for every remaining file and symlink. The archive has no
|
||||
# directory entries, so tar can stream it straight into the prefix without
|
||||
# reading, copying, chmodding, or replacing any existing Homebrew path.
|
||||
if brew list --versions "$formula" >/dev/null 2>&1; then
|
||||
brew uninstall --force --ignore-dependencies "$formula" >/dev/null || \
|
||||
php_darwin_die "could not remove the existing $formula keg"
|
||||
fi
|
||||
exclude_file="$tmp_dir/existing-paths.txt"
|
||||
bash "$script_dir/existing-paths.sh" "$brew_prefix" "$exclude_file" "$archive_roots" || \
|
||||
php_darwin_die 'could not record existing Homebrew paths'
|
||||
bash "$script_dir/extract.sh" "$archive" "$brew_prefix" "$exclude_file" || \
|
||||
php_darwin_die "could not extract $asset into Homebrew"
|
||||
|
||||
brew link --overwrite --force "$formula" >/dev/null || php_darwin_die "could not link $formula"
|
||||
missing=$(brew missing "$formula" 2>&1)
|
||||
missing_status=$?
|
||||
[ "$missing_status" -eq 0 ] || [ -n "$missing" ] || php_darwin_die 'Homebrew dependency validation failed without diagnostics'
|
||||
[ -z "$missing" ] || php_darwin_die "cache has missing Homebrew dependencies: $missing"
|
||||
|
||||
php_bin="$brew_prefix/opt/$formula/bin/php"
|
||||
[ -x "$php_bin" ] || php_darwin_die "PHP binary missing after cache extraction: $php_bin"
|
||||
installed_semver=$($php_bin -r 'echo PHP_VERSION;') || php_darwin_die 'cached PHP could not report its version'
|
||||
[ "${installed_semver%.*}" = "$version" ] || php_darwin_die "cache installed PHP $installed_semver for requested $version"
|
||||
|
||||
if [ -n "${GITHUB_PATH:-}" ]; then
|
||||
printf '%s\n%s\n' "$brew_prefix/opt/$formula/bin" "$brew_prefix/opt/$formula/sbin" >> "$GITHUB_PATH"
|
||||
fi
|
||||
printf 'Installed PHP %s (%s, %s, %s) from %s\n' "$installed_semver" "$build" "$ts" "$arch" "$asset"
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
php_darwin_root=${PHP_DARWIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}
|
||||
|
||||
php_darwin_die() {
|
||||
printf 'php-darwin: %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
php_darwin_validate_version() {
|
||||
awk '!/^#/ && $2 == version { found=1 } END { exit !found }' version="${1:-}" "$php_darwin_root/conf/versions" || \
|
||||
php_darwin_die "unsupported PHP version: ${1:-<empty>}"
|
||||
}
|
||||
|
||||
php_darwin_version_channel() {
|
||||
awk '!/^#/ && $2 == version { print $1; found=1; exit } END { exit !found }' \
|
||||
version="${1:-}" "$php_darwin_root/conf/versions" || \
|
||||
php_darwin_die "unsupported PHP version: ${1:-<empty>}"
|
||||
}
|
||||
|
||||
php_darwin_validate_channel() {
|
||||
local version=${1:-}
|
||||
local expected=${2:-}
|
||||
local actual
|
||||
|
||||
case "$expected" in stable|nightly) ;; *) php_darwin_die "unsupported release channel: ${expected:-<empty>}" ;; esac
|
||||
actual=$(php_darwin_version_channel "$version")
|
||||
[ "$actual" = "$expected" ] || php_darwin_die "PHP $version is $actual, not $expected"
|
||||
}
|
||||
|
||||
php_darwin_validate_build() {
|
||||
case "${1:-}" in
|
||||
release|debug) ;;
|
||||
*) php_darwin_die "build must be release or debug: ${1:-<empty>}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
php_darwin_validate_ts() {
|
||||
case "${1:-}" in
|
||||
nts|zts) ;;
|
||||
*) php_darwin_die "thread safety must be nts or zts: ${1:-<empty>}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
php_darwin_normalize_arch() {
|
||||
case "${1:-$(uname -m)}" in
|
||||
arm64|aarch64) printf 'arm64\n' ;;
|
||||
x86_64|amd64) printf 'x86_64\n' ;;
|
||||
*) php_darwin_die "unsupported architecture: ${1:-<empty>}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
php_darwin_expected_prefix() {
|
||||
jq -er --arg arch "$(php_darwin_normalize_arch "${1:-}")" '.[$arch].brew_prefix' \
|
||||
"$php_darwin_root/conf/platforms.json" || php_darwin_die 'Homebrew prefix is not configured'
|
||||
}
|
||||
|
||||
php_darwin_package_config() {
|
||||
jq -er --arg key "$1" '.[$key]' "$php_darwin_root/conf/package.json" || \
|
||||
php_darwin_die "package configuration is missing: $1"
|
||||
}
|
||||
|
||||
php_darwin_formula_suffix() {
|
||||
local build=${1:-release}
|
||||
local ts=${2:-nts}
|
||||
local suffix=
|
||||
|
||||
php_darwin_validate_build "$build"
|
||||
php_darwin_validate_ts "$ts"
|
||||
[ "$build" = debug ] && suffix=-debug
|
||||
[ "$ts" = zts ] && suffix="$suffix-zts"
|
||||
printf '%s\n' "$suffix"
|
||||
}
|
||||
|
||||
php_darwin_formula() {
|
||||
local version=$1
|
||||
local current_version
|
||||
local suffix
|
||||
|
||||
php_darwin_validate_version "$version"
|
||||
suffix=$(php_darwin_formula_suffix "${2:-release}" "${3:-nts}")
|
||||
current_version=$(php_darwin_package_config current_version)
|
||||
if [ "$version" = "$current_version" ]; then
|
||||
printf 'php%s\n' "$suffix"
|
||||
else
|
||||
printf 'php@%s%s\n' "$version" "$suffix"
|
||||
fi
|
||||
}
|
||||
|
||||
php_darwin_requested_formula() {
|
||||
local version=$1
|
||||
local suffix
|
||||
|
||||
php_darwin_validate_version "$version"
|
||||
suffix=$(php_darwin_formula_suffix "${2:-release}" "${3:-nts}")
|
||||
printf 'php@%s%s\n' "$version" "$suffix"
|
||||
}
|
||||
|
||||
php_darwin_asset() {
|
||||
local version=$1
|
||||
local version_major
|
||||
local version_minor
|
||||
local build=${2:-release}
|
||||
local ts=${3:-nts}
|
||||
local arch
|
||||
|
||||
IFS=. read -r version_major version_minor _ <<< "$version"
|
||||
php_darwin_validate_version "$version_major.$version_minor"
|
||||
php_darwin_validate_build "$build"
|
||||
php_darwin_validate_ts "$ts"
|
||||
arch=$(php_darwin_normalize_arch "${4:-}")
|
||||
printf 'php_%s-%s-%s+darwin_%s.tar.zst\n' "$version" "$ts" "$build" "$arch"
|
||||
}
|
||||
|
||||
php_darwin_sha256() {
|
||||
local hash_output
|
||||
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
hash_output=$(sha256sum "$1") || return 1
|
||||
else
|
||||
hash_output=$(shasum -a 256 "$1") || return 1
|
||||
fi
|
||||
printf '%s\n' "${hash_output%% *}"
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck source=scripts/lib.sh
|
||||
. "$script_dir/lib.sh"
|
||||
|
||||
manifest_media_type=$(php_darwin_package_config registry_manifest_media_type)
|
||||
artifact_type=$(php_darwin_package_config artifact_type)
|
||||
archive_media_type=$(php_darwin_package_config archive_media_type)
|
||||
configured_layer_count=$(jq 'keys | length' "$script_dir/../conf/platforms.json") || \
|
||||
php_darwin_die 'could not read the configured platform count'
|
||||
|
||||
registry_auth() {
|
||||
registry_image=$1
|
||||
[[ "$registry_image" =~ ^[A-Za-z0-9.-]+/[A-Za-z0-9._/-]+$ ]] || \
|
||||
php_darwin_die "invalid registry image: $registry_image"
|
||||
case "$registry_image" in *..*) php_darwin_die "invalid registry image: $registry_image" ;; esac
|
||||
registry_host=${registry_image%%/*}
|
||||
registry_repository=${registry_image#*/}
|
||||
registry_token_url="https://$registry_host/token"
|
||||
registry_token_args=(--retry 3 --retry-all-errors -fsSLG)
|
||||
registry_credential=${GHCR_TOKEN:-${GITHUB_TOKEN:-${GH_TOKEN:-}}}
|
||||
[ -z "$registry_credential" ] || registry_token_args+=(-u "${GITHUB_ACTOR:-token}:$registry_credential")
|
||||
registry_token_response=$(curl "${registry_token_args[@]}" "$registry_token_url" \
|
||||
--data-urlencode "service=$registry_host" \
|
||||
--data-urlencode "scope=repository:$registry_repository:pull") || \
|
||||
php_darwin_die "could not get a registry token for $registry_image"
|
||||
registry_token=$(jq -er '.token // .access_token' <<< "$registry_token_response") || \
|
||||
php_darwin_die "registry token response was invalid for $registry_image"
|
||||
}
|
||||
|
||||
registry_manifest() {
|
||||
manifest_tag=$1
|
||||
manifest_output=$2
|
||||
manifest_headers=$3
|
||||
[[ "$manifest_tag" =~ ^[A-Za-z0-9._-]+$ ]] || php_darwin_die "invalid OCI tag: $manifest_tag"
|
||||
curl --retry 3 --retry-all-errors -fsSL \
|
||||
-H "Authorization: Bearer $registry_token" \
|
||||
-H "Accept: $manifest_media_type" \
|
||||
-D "$manifest_headers" \
|
||||
"https://$registry_host/v2/$registry_repository/manifests/$manifest_tag" \
|
||||
-o "$manifest_output" || return 1
|
||||
|
||||
jq -e --arg archive_media_type "$archive_media_type" --arg artifact_type "$artifact_type" \
|
||||
--arg media_type "$manifest_media_type" --argjson layer_count "$configured_layer_count" \
|
||||
'.schemaVersion == 2 and .mediaType == $media_type and .artifactType == $artifact_type and
|
||||
(.layers | type == "array" and length == $layer_count) and
|
||||
all(.layers[];
|
||||
.mediaType == $archive_media_type and
|
||||
(.digest | type == "string" and test("^sha256:[0-9a-f]{64}$")) and
|
||||
(.size | type == "number" and . >= 0 and . == floor) and
|
||||
(.annotations["org.opencontainers.image.title"] | type == "string" and
|
||||
test("^php_[0-9]+\\.[0-9]+-(nts|zts)-(debug|release)\\+darwin_(arm64|x86_64)\\.tar\\.zst$"))) and
|
||||
([.layers[].annotations["org.opencontainers.image.title"]] | unique | length) == $layer_count and
|
||||
any(.layers[]; .annotations["org.opencontainers.image.title"] | endswith("_arm64.tar.zst")) and
|
||||
any(.layers[]; .annotations["org.opencontainers.image.title"] | endswith("_x86_64.tar.zst"))' \
|
||||
"$manifest_output" >/dev/null || \
|
||||
php_darwin_die 'registry returned an invalid php-darwin OCI manifest'
|
||||
|
||||
header_digest=$(awk 'tolower($1) == "docker-content-digest:" {gsub("\\r", "", $2); digest=$2} END {print digest}' "$manifest_headers") || \
|
||||
php_darwin_die 'could not read the registry manifest digest header'
|
||||
manifest_hash=$(php_darwin_sha256 "$manifest_output") || php_darwin_die 'could not hash the OCI manifest'
|
||||
manifest_digest="sha256:$manifest_hash"
|
||||
[ -z "$header_digest" ] || [[ "$header_digest" =~ ^sha256:[0-9a-f]{64}$ ]] || \
|
||||
php_darwin_die 'registry returned an invalid manifest digest header'
|
||||
[ -z "$header_digest" ] || [ "$header_digest" = "$manifest_digest" ] || \
|
||||
php_darwin_die "registry manifest digest mismatch: expected $header_digest, got $manifest_digest"
|
||||
}
|
||||
|
||||
registry_inspect() {
|
||||
inspect_image=$1
|
||||
inspect_tag=$2
|
||||
inspect_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-registry.XXXXXX")
|
||||
trap 'rm -rf "$inspect_dir"' EXIT
|
||||
registry_auth "$inspect_image"
|
||||
registry_manifest "$inspect_tag" "$inspect_dir/manifest.json" "$inspect_dir/headers" || return 1
|
||||
jq -n --arg digest "$manifest_digest" --slurpfile manifest "$inspect_dir/manifest.json" \
|
||||
'{digest:$digest,manifest:$manifest[0]}'
|
||||
}
|
||||
|
||||
registry_inspect_many() {
|
||||
inspect_image=$1
|
||||
shift
|
||||
inspect_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-registry.XXXXXX")
|
||||
trap 'rm -rf "$inspect_dir"' EXIT
|
||||
inspect_jsonl="$inspect_dir/manifests.jsonl"
|
||||
: > "$inspect_jsonl"
|
||||
registry_auth "$inspect_image"
|
||||
inspect_index=0
|
||||
for inspect_tag in "$@"; do
|
||||
[[ "$inspect_tag" =~ ^[A-Za-z0-9._-]+$ ]] || php_darwin_die "invalid OCI tag: $inspect_tag"
|
||||
inspect_index=$((inspect_index + 1))
|
||||
registry_manifest "$inspect_tag" "$inspect_dir/manifest-$inspect_index.json" "$inspect_dir/headers-$inspect_index" || return 1
|
||||
jq -cn --arg tag "$inspect_tag" --arg digest "$manifest_digest" \
|
||||
--slurpfile manifest "$inspect_dir/manifest-$inspect_index.json" \
|
||||
'{key:$tag,value:{digest:$digest,manifest:$manifest[0]}}' >> "$inspect_jsonl" || \
|
||||
php_darwin_die "could not record OCI manifest $inspect_tag"
|
||||
done
|
||||
jq -s 'from_entries' "$inspect_jsonl" || php_darwin_die 'could not combine OCI manifests'
|
||||
}
|
||||
|
||||
registry_pull() {
|
||||
pull_image=$1
|
||||
pull_tag=$2
|
||||
pull_asset=$3
|
||||
pull_output=$4
|
||||
pull_descriptor=$5
|
||||
pull_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-registry.XXXXXX")
|
||||
trap 'rm -rf "$pull_dir"' EXIT
|
||||
registry_auth "$pull_image"
|
||||
registry_manifest "$pull_tag" "$pull_dir/manifest.json" "$pull_dir/headers" || \
|
||||
php_darwin_die "could not fetch $pull_image:$pull_tag"
|
||||
|
||||
jq -c --arg asset "$pull_asset" \
|
||||
'[.layers[] | select(.annotations["org.opencontainers.image.title"] == $asset)]' \
|
||||
"$pull_dir/manifest.json" > "$pull_dir/layers.json" || php_darwin_die 'could not parse OCI layers'
|
||||
[ "$(jq 'length' "$pull_dir/layers.json")" -eq 1 ] || \
|
||||
php_darwin_die "expected one $pull_asset layer in $pull_tag"
|
||||
layer_digest=$(jq -er '.[0].digest' "$pull_dir/layers.json") || php_darwin_die 'OCI layer digest is missing'
|
||||
layer_size=$(jq -er '.[0].size' "$pull_dir/layers.json") || php_darwin_die 'OCI layer size is missing'
|
||||
[[ "$layer_digest" =~ ^sha256:[0-9a-f]{64}$ ]] || php_darwin_die 'OCI layer digest is invalid'
|
||||
[[ "$layer_size" =~ ^[0-9]+$ ]] || php_darwin_die 'OCI layer size is invalid'
|
||||
|
||||
curl --retry 3 --retry-all-errors -fsSL \
|
||||
-H "Authorization: Bearer $registry_token" \
|
||||
"https://$registry_host/v2/$registry_repository/blobs/$layer_digest" \
|
||||
-o "$pull_output" || php_darwin_die "could not download $pull_asset"
|
||||
actual_hash=$(php_darwin_sha256 "$pull_output") || php_darwin_die 'could not hash the OCI archive layer'
|
||||
actual_digest="sha256:$actual_hash"
|
||||
[ "$actual_digest" = "$layer_digest" ] || \
|
||||
php_darwin_die "registry blob digest mismatch: expected $layer_digest, got $actual_digest"
|
||||
actual_size=$(wc -c < "$pull_output")
|
||||
actual_size=${actual_size//[[:space:]]/}
|
||||
[ "$actual_size" = "$layer_size" ] || \
|
||||
php_darwin_die "registry blob size mismatch: expected $layer_size, got $actual_size"
|
||||
|
||||
jq --arg manifest_digest "$manifest_digest" \
|
||||
--slurpfile manifest "$pull_dir/manifest.json" \
|
||||
--slurpfile layers "$pull_dir/layers.json" \
|
||||
'.manifest_digest=$manifest_digest |
|
||||
.schema_version=$manifest[0].schemaVersion |
|
||||
.manifest_media_type=$manifest[0].mediaType |
|
||||
.artifact_type=$manifest[0].artifactType |
|
||||
.annotations=($manifest[0].annotations // {}) |
|
||||
.layer=$layers[0][0]' \
|
||||
"$script_dir/../templates/oci-descriptor.json" \
|
||||
> "$pull_descriptor" || php_darwin_die 'could not write the OCI descriptor'
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
inspect)
|
||||
[ "$#" -eq 3 ] || php_darwin_die 'usage: registry.sh inspect IMAGE TAG'
|
||||
registry_inspect "$2" "$3"
|
||||
;;
|
||||
inspect-many)
|
||||
[ "$#" -ge 4 ] || php_darwin_die 'usage: registry.sh inspect-many IMAGE TAG TAG [...]'
|
||||
registry_inspect_many "$2" "${@:3}"
|
||||
;;
|
||||
pull)
|
||||
[ "$#" -eq 6 ] || php_darwin_die 'usage: registry.sh pull IMAGE TAG ASSET OUTPUT DESCRIPTOR'
|
||||
registry_pull "$2" "$3" "$4" "$5" "$6"
|
||||
;;
|
||||
*) php_darwin_die 'usage: registry.sh inspect|inspect-many|pull ...' ;;
|
||||
esac
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck source=scripts/lib.sh
|
||||
. "$script_dir/lib.sh"
|
||||
|
||||
version=${1:?}
|
||||
tap_path=${HOMEBREW_PHP_PATH:-}
|
||||
php_darwin_validate_version "$version"
|
||||
repository=$(php_darwin_package_config tap_repository)
|
||||
branch=$(php_darwin_package_config tap_branch)
|
||||
tmp_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-source.XXXXXX")
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
hashes="$tmp_dir/formulae.tsv"
|
||||
|
||||
for build in release debug; do
|
||||
for ts in nts zts; do
|
||||
formula=$(php_darwin_formula "$version" "$build" "$ts")
|
||||
formula_file="$tmp_dir/$formula.rb"
|
||||
if [ -n "$tap_path" ]; then
|
||||
cp "$tap_path/Formula/$formula.rb" "$formula_file" || php_darwin_die "could not read $formula from the local tap"
|
||||
else
|
||||
curl --retry 3 --retry-all-errors -fsSL \
|
||||
"${repository/github.com/raw.githubusercontent.com}/$branch/Formula/$formula.rb" \
|
||||
-o "$formula_file" || php_darwin_die "could not download $formula"
|
||||
fi
|
||||
formula_hash=$(php_darwin_sha256 "$formula_file") || php_darwin_die "could not hash $formula"
|
||||
printf '%s\t%s\n' "$formula" "$formula_hash" >> "$hashes" || php_darwin_die 'could not record a formula hash'
|
||||
done
|
||||
done
|
||||
|
||||
LC_ALL=C sort -u "$hashes" -o "$hashes" || php_darwin_die 'could not sort formula hashes'
|
||||
php_darwin_sha256 "$hashes" || php_darwin_die 'could not hash formula metadata'
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"annotations": {},
|
||||
"artifact_type": "",
|
||||
"layer": {},
|
||||
"manifest_digest": "",
|
||||
"manifest_media_type": "",
|
||||
"schema_version": 0
|
||||
}
|
||||
@@ -407,15 +407,6 @@ export async function scriptExtension(os: string): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generated run-script path without rewriting parent directories.
|
||||
*
|
||||
* @param scriptPath
|
||||
*/
|
||||
export function scriptRunPath(scriptPath: string): string {
|
||||
return path.join(path.dirname(scriptPath), `run${path.extname(scriptPath)}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get script tool
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user