feat(installer): self-select release download source (#176)
This commit is contained in:
1 parent
747077cabb
commit
38df4e62ee
7 files changed
+347
-50
No files matched your search
+86
-13
@@ -3,9 +3,11 @@
|
||||
# irm https://penguin.ooo/install.ps1 | iex
|
||||
#
|
||||
# Options:
|
||||
# $env:PENGUIN_VERSION = "vX.Y.Z" pin a version (same as -Version vX.Y.Z); default is the latest Release
|
||||
# $env: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
|
||||
# $env:PENGUIN_INSTALL_DIR = "<dir>" install dir; default $env:USERPROFILE\.penguin
|
||||
# $env:PENGUIN_ARCHIVE = "<file>" install a local Release zip without network access (same as -ArchivePath)
|
||||
# $env:PENGUIN_DOWNLOAD_SOURCE = "auto|oss|github" choose the online source; default auto (OSS, then same-version GitHub)
|
||||
# $env:PENGUIN_DOWNLOAD_BASE_URL = "https://..." exact online asset directory selected by the stable forwarder
|
||||
# $env:PENGUIN_DOWNLOAD_FALLBACK_BASE_URL = "https://..." same-version fallback asset directory
|
||||
#
|
||||
@@ -35,8 +37,15 @@ $ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue" # Invoke-WebRequest progress rendering slows downloads massively on PS 5.1
|
||||
|
||||
$Repo = "https://github.com/Prism-Shadow/penguin-harness"
|
||||
$OssOrigin = "https://penguin-harness-releases.oss-cn-beijing.aliyuncs.com"
|
||||
$OssReleaseRoot = "$OssOrigin/releases"
|
||||
$GitHubReleaseRoot = "$Repo/releases/download"
|
||||
$GitHubLatestBase = "$Repo/releases/latest/download"
|
||||
$Asset = "penguin-win32-x64.zip"
|
||||
$PayloadName = "payload.zip"
|
||||
# The release workflow replaces this token with the immutable tag before publishing both the
|
||||
# standalone installer and the copy sealed inside the Windows bundle.
|
||||
$EmbeddedReleaseVersion = "__PENGUIN_RELEASE_VERSION__"
|
||||
|
||||
function Fail([string]$Message) {
|
||||
# `throw` rather than `exit`: the penguin.ooo forwarder runs this installer as an in-memory
|
||||
@@ -76,6 +85,32 @@ function Assert-HttpsUrl([string]$Name, [string]$Value) {
|
||||
}
|
||||
}
|
||||
|
||||
function Test-ReleaseTag([string]$Value) {
|
||||
return $Value -match '^v[0-9A-Za-z][0-9A-Za-z._-]*$'
|
||||
}
|
||||
|
||||
function Get-OssLatestTag([string]$ManifestPath) {
|
||||
Remove-Item -LiteralPath $ManifestPath -Force -ErrorAction SilentlyContinue
|
||||
try {
|
||||
Invoke-WebRequest -Uri "$OssOrigin/latest.json" -OutFile $ManifestPath -UseBasicParsing -TimeoutSec 8 | Out-Null
|
||||
} catch {
|
||||
Remove-Item -LiteralPath $ManifestPath -Force -ErrorAction SilentlyContinue
|
||||
return ""
|
||||
}
|
||||
try {
|
||||
$Manifest = [IO.File]::ReadAllText($ManifestPath, [Text.UTF8Encoding]::new($false)) | ConvertFrom-Json
|
||||
$CandidateTag = [string]$Manifest.tag
|
||||
$CandidateBase = ([string]$Manifest.releaseBaseUrl).TrimEnd('/')
|
||||
if ([int]$Manifest.schemaVersion -eq 1 -and
|
||||
(Test-ReleaseTag $CandidateTag) -and
|
||||
$CandidateBase -eq "$OssReleaseRoot/$CandidateTag") {
|
||||
return $CandidateTag
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function Get-DownloadSourceLabel([string]$BaseUrl) {
|
||||
try { $HostName = ([Uri]$BaseUrl).Host } catch { return "configured mirror" }
|
||||
if ($HostName -like "*.aliyuncs.com") { return "OSS mirror" }
|
||||
@@ -141,6 +176,11 @@ $DownloadFallbackBaseUrl = if ($env:PENGUIN_DOWNLOAD_FALLBACK_BASE_URL) {
|
||||
} else {
|
||||
""
|
||||
}
|
||||
$SourceMode = if ($env:PENGUIN_DOWNLOAD_SOURCE) {
|
||||
$env:PENGUIN_DOWNLOAD_SOURCE.ToLowerInvariant()
|
||||
} else {
|
||||
"auto"
|
||||
}
|
||||
# An extracted installer bundle keeps install.cmd, this script, payload.zip and its checksum
|
||||
# together. `$PSScriptRoot` is empty for the documented `irm ... | iex` path, so online installs
|
||||
# do not accidentally pick up an unrelated archive from the caller's current directory.
|
||||
@@ -151,9 +191,19 @@ if (-not $ArchivePath -and $PSScriptRoot) {
|
||||
if ($ArchivePath -and $Version) {
|
||||
Fail "-ArchivePath/PENGUIN_ARCHIVE cannot be combined with -Version/PENGUIN_VERSION"
|
||||
}
|
||||
if ($Version -and $Version -notmatch '^v[0-9A-Za-z][0-9A-Za-z._-]*$') {
|
||||
if ($Version -and -not (Test-ReleaseTag $Version)) {
|
||||
Fail "invalid release version: $Version"
|
||||
}
|
||||
if ($SourceMode -notin @("auto", "oss", "github")) {
|
||||
Fail "PENGUIN_DOWNLOAD_SOURCE must be auto, oss, or github"
|
||||
}
|
||||
$ResolvedReleaseVersion = if ($Version) {
|
||||
$Version
|
||||
} elseif (Test-ReleaseTag $EmbeddedReleaseVersion) {
|
||||
$EmbeddedReleaseVersion
|
||||
} else {
|
||||
""
|
||||
}
|
||||
if ($DownloadBaseUrl) {
|
||||
Assert-HttpsUrl "PENGUIN_DOWNLOAD_BASE_URL" $DownloadBaseUrl
|
||||
}
|
||||
@@ -176,14 +226,10 @@ try {
|
||||
# .NET builds where the enum is immutable already default to TLS 1.2+.
|
||||
}
|
||||
|
||||
# --- Download (latest GitHub Release by default; the stable forwarder may select exact mirrors) ---
|
||||
if ($DownloadBaseUrl) {
|
||||
$BaseUrl = $DownloadBaseUrl
|
||||
} elseif ($Version) {
|
||||
$BaseUrl = "$Repo/releases/download/$Version"
|
||||
} else {
|
||||
$BaseUrl = "$Repo/releases/latest/download"
|
||||
}
|
||||
# --- Download. 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. ---
|
||||
$Tmp = Join-Path ([IO.Path]::GetTempPath()) "penguin-install-$PID"
|
||||
if (Test-Path $Tmp) { Remove-Item -Recurse -Force $Tmp }
|
||||
New-Item -ItemType Directory -Path $Tmp | Out-Null
|
||||
@@ -203,14 +249,41 @@ try {
|
||||
$ArchiveName = [IO.Path]::GetFileName($ZipPath)
|
||||
Write-Host "Using local archive $ZipPath ..."
|
||||
} else {
|
||||
$BaseUrl = ""
|
||||
$FallbackBaseUrl = $DownloadFallbackBaseUrl
|
||||
if ($DownloadBaseUrl) {
|
||||
$BaseUrl = $DownloadBaseUrl
|
||||
} elseif ($SourceMode -eq "github") {
|
||||
$BaseUrl = if ($ResolvedReleaseVersion) {
|
||||
"$GitHubReleaseRoot/$ResolvedReleaseVersion"
|
||||
} else {
|
||||
$GitHubLatestBase
|
||||
}
|
||||
} else {
|
||||
$SelectedTag = $ResolvedReleaseVersion
|
||||
if (-not $SelectedTag) {
|
||||
$SelectedTag = Get-OssLatestTag (Join-Path $Tmp "latest.json")
|
||||
}
|
||||
if ($SelectedTag) {
|
||||
$BaseUrl = "$OssReleaseRoot/$SelectedTag"
|
||||
if ($SourceMode -eq "auto" -and -not $FallbackBaseUrl) {
|
||||
$FallbackBaseUrl = "$GitHubReleaseRoot/$SelectedTag"
|
||||
}
|
||||
} elseif ($SourceMode -eq "oss") {
|
||||
Fail "the OSS mirror is unavailable or its release metadata is invalid."
|
||||
} else {
|
||||
$BaseUrl = $GitHubLatestBase
|
||||
}
|
||||
}
|
||||
|
||||
# Online: download the canonical bundle; the published checksum is mandatory.
|
||||
$ZipPath = Join-Path $Tmp $Asset
|
||||
$ArchiveName = $Asset
|
||||
$ShaPath = Join-Path $Tmp "$Asset.sha256"
|
||||
if (-not (Get-ReleasePair $BaseUrl $ZipPath $ShaPath)) {
|
||||
if ($DownloadFallbackBaseUrl -and $DownloadFallbackBaseUrl -ne $BaseUrl) {
|
||||
Write-Host "Primary download source unavailable; trying $(Get-DownloadSourceLabel $DownloadFallbackBaseUrl) ..."
|
||||
if (-not (Get-ReleasePair $DownloadFallbackBaseUrl $ZipPath $ShaPath)) {
|
||||
if ($FallbackBaseUrl -and $FallbackBaseUrl -ne $BaseUrl) {
|
||||
Write-Host "Primary download source unavailable; trying $(Get-DownloadSourceLabel $FallbackBaseUrl) ..."
|
||||
if (-not (Get-ReleasePair $FallbackBaseUrl $ZipPath $ShaPath)) {
|
||||
Fail "download failed from both the primary source and its fallback. Check your network, then retry."
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user