feat(installer): self-select release download source (#176)

This commit is contained in:
Laodouuu authored and GitHub committed 2026-08-04 18:44:30 +08:00
1 parent 747077cabb
commit 38df4e62ee
7 files changed
+347 -50

No files matched your search

+72 -11
View File
@@ -4,9 +4,11 @@
# curl -fsSL https://github.com/Prism-Shadow/penguin-harness/releases/latest/download/install.sh | sh
#
# Options:
# PENGUIN_VERSION=vX.Y.Z pin a version (same as --version vX.Y.Z); default is the latest Release
# PENGUIN_VERSION=vX.Y.Z choose a version (same as --version vX.Y.Z); a published Release
# installer defaults to its own version, an unstamped source copy to latest
# PENGUIN_INSTALL_DIR=<dir> install dir; default ~/.penguin
# PENGUIN_ARCHIVE=<file> install a local Release archive without network access (same as --archive <file>)
# PENGUIN_DOWNLOAD_SOURCE=auto|oss|github choose the online source; default auto (OSS, then same-version GitHub)
# PENGUIN_DOWNLOAD_BASE_URL=<url> exact online asset directory selected by the stable forwarder
# PENGUIN_DOWNLOAD_FALLBACK_BASE_URL=<url> same-version fallback asset directory
# --universal install the universal package (no bundled Node runtime; needs system Node >= 24)
@@ -26,14 +28,22 @@
set -eu
REPO="https://github.com/Prism-Shadow/penguin-harness"
OSS_ORIGIN="https://penguin-harness-releases.oss-cn-beijing.aliyuncs.com"
OSS_RELEASE_ROOT="$OSS_ORIGIN/releases"
GITHUB_RELEASE_ROOT="$REPO/releases/download"
GITHUB_LATEST_BASE="$REPO/releases/latest/download"
VERSION="${PENGUIN_VERSION:-}"
INSTALL_DIR="${PENGUIN_INSTALL_DIR:-$HOME/.penguin}"
BIN_DIR="$HOME/.local/bin"
UNIVERSAL=0
ARCHIVE="${PENGUIN_ARCHIVE:-}"
SOURCE_MODE="${PENGUIN_DOWNLOAD_SOURCE:-auto}"
DOWNLOAD_BASE_URL="${PENGUIN_DOWNLOAD_BASE_URL:-}"
DOWNLOAD_FALLBACK_BASE_URL="${PENGUIN_DOWNLOAD_FALLBACK_BASE_URL:-}"
PAYLOAD_NAME="payload.tar.gz"
# The release workflow replaces this token with the immutable tag before publishing both the
# standalone installer and the copies sealed inside the Linux, macOS and universal bundles.
EMBEDDED_RELEASE_VERSION="__PENGUIN_RELEASE_VERSION__"
fail() {
echo "error: $1" >&2
@@ -47,14 +57,19 @@ validate_https_url() {
esac
}
validate_release_tag() {
is_release_tag() {
case "$1" in
v[0-9A-Za-z]* ) ;;
*) fail "invalid release version: $1" ;;
*) return 1 ;;
esac
case "$1" in
*[!0-9A-Za-z._-]*) fail "invalid release version: $1" ;;
*[!0-9A-Za-z._-]*) return 1 ;;
esac
return 0
}
validate_release_tag() {
is_release_tag "$1" || fail "invalid release version: $1"
}
download_source_label() {
@@ -111,6 +126,14 @@ fi
if [ -n "$VERSION" ]; then
validate_release_tag "$VERSION"
fi
case "$SOURCE_MODE" in
auto | oss | github) ;;
*) fail "PENGUIN_DOWNLOAD_SOURCE must be auto, oss, or github" ;;
esac
RESOLVED_RELEASE_VERSION="$VERSION"
if [ -z "$RESOLVED_RELEASE_VERSION" ] && is_release_tag "$EMBEDDED_RELEASE_VERSION"; then
RESOLVED_RELEASE_VERSION="$EMBEDDED_RELEASE_VERSION"
fi
if [ -n "$DOWNLOAD_BASE_URL" ]; then
DOWNLOAD_BASE_URL="${DOWNLOAD_BASE_URL%/}"
validate_https_url PENGUIN_DOWNLOAD_BASE_URL "$DOWNLOAD_BASE_URL"
@@ -239,6 +262,23 @@ download_release_pair() {
return 0
}
# Resolves the OSS mirror's latest immutable tag. The advertised base URL must exactly match
# the expected bucket path so metadata cannot redirect downloads to an arbitrary host.
get_oss_latest_tag() {
gol_manifest="$1"
rm -f "$gol_manifest"
curl -fsSL --connect-timeout 3 --max-time 8 "$OSS_ORIGIN/latest.json" -o "$gol_manifest" 2>/dev/null \
|| return 1
gol_schema_version="$(sed -n 's/.*"schemaVersion":[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$gol_manifest" | head -n 1)"
gol_candidate_tag="$(sed -n 's/.*"tag":[[:space:]]*"\([^"]*\)".*/\1/p' "$gol_manifest" | head -n 1)"
gol_candidate_base="$(sed -n 's/.*"releaseBaseUrl":[[:space:]]*"\([^"]*\)".*/\1/p' "$gol_manifest" | head -n 1)"
[ "$gol_schema_version" = "1" ] \
&& is_release_tag "$gol_candidate_tag" \
&& [ "$gol_candidate_base" = "$OSS_RELEASE_ROOT/$gol_candidate_tag" ] \
|| return 1
printf '%s\n' "$gol_candidate_tag"
}
# --- Resolve the program payload. Three entries converge on PAYLOAD_PATH:
# (a) bundled offline: this script sits next to payload.tar.gz in an extracted bundle;
# (b) --archive <file>: a local installer bundle, or a payload/legacy program archive;
@@ -285,20 +325,41 @@ elif [ -n "$ARCHIVE" ]; then
LOCAL_ARCHIVE=1
echo "Using local archive $ARCHIVE_PATH ..."
else
# (c) Online: download the canonical bundle; the published checksum is mandatory.
# (c) Online: explicit forwarder/configured URLs win. Otherwise a stamped Release installer
# uses its own immutable version: auto prefers OSS and falls back only to the same GitHub
# tag. An unstamped source-tree installer resolves latest.json first so it also locks one
# version before downloading assets.
FALLBACK_BASE_URL="$DOWNLOAD_FALLBACK_BASE_URL"
if [ -n "$DOWNLOAD_BASE_URL" ]; then
BASE_URL="$DOWNLOAD_BASE_URL"
elif [ -n "$VERSION" ]; then
BASE_URL="$REPO/releases/download/$VERSION"
elif [ "$SOURCE_MODE" = "github" ]; then
if [ -n "$RESOLVED_RELEASE_VERSION" ]; then
BASE_URL="$GITHUB_RELEASE_ROOT/$RESOLVED_RELEASE_VERSION"
else
BASE_URL="$GITHUB_LATEST_BASE"
fi
else
BASE_URL="$REPO/releases/latest/download"
SELECTED_TAG="$RESOLVED_RELEASE_VERSION"
if [ -z "$SELECTED_TAG" ]; then
SELECTED_TAG="$(get_oss_latest_tag "$TMP/latest.json" || :)"
fi
if [ -n "$SELECTED_TAG" ]; then
BASE_URL="$OSS_RELEASE_ROOT/$SELECTED_TAG"
if [ "$SOURCE_MODE" = "auto" ] && [ -z "$FALLBACK_BASE_URL" ]; then
FALLBACK_BASE_URL="$GITHUB_RELEASE_ROOT/$SELECTED_TAG"
fi
elif [ "$SOURCE_MODE" = "oss" ]; then
fail "the OSS mirror is unavailable or its release metadata is invalid."
else
BASE_URL="$GITHUB_LATEST_BASE"
fi
fi
ARCHIVE_PATH="$TMP/$ASSET"
ARCHIVE_NAME="$ASSET"
if ! download_release_pair "$BASE_URL"; then
if [ -n "$DOWNLOAD_FALLBACK_BASE_URL" ] && [ "$DOWNLOAD_FALLBACK_BASE_URL" != "$BASE_URL" ]; then
echo "Primary download source unavailable; trying $(download_source_label "$DOWNLOAD_FALLBACK_BASE_URL") ..."
download_release_pair "$DOWNLOAD_FALLBACK_BASE_URL" \
if [ -n "$FALLBACK_BASE_URL" ] && [ "$FALLBACK_BASE_URL" != "$BASE_URL" ]; then
echo "Primary download source unavailable; trying $(download_source_label "$FALLBACK_BASE_URL") ..."
download_release_pair "$FALLBACK_BASE_URL" \
|| fail "download failed from both the primary source and its fallback. Check your network, then retry."
else
fail "download failed from $(download_source_label "$BASE_URL"). Check the version tag and your network, then retry."