diff --git a/src/spice2x/build_all.sh b/src/spice2x/build_all.sh index 26f2b64..a75b712 100755 --- a/src/spice2x/build_all.sh +++ b/src/spice2x/build_all.sh @@ -354,6 +354,10 @@ mkdir ${OUTDIR_EXTRAS}/api find ./api/resources/python -name "__pycache__" -exec rm -rf {} + cp -r ./api/resources/* ${OUTDIR_EXTRAS}/api +# generate the standalone updater scripts from the shared template and drop them +# straight into the output folder (included in both the regular and full archives) +bash ./build_updaters.sh ${OUTDIR} + # build distribution archive if ((DIST_ENABLE > 0)) then diff --git a/src/spice2x/build_updaters.sh b/src/spice2x/build_updaters.sh new file mode 100644 index 0000000..4b3e0d9 --- /dev/null +++ b/src/spice2x/build_updaters.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# builds the standalone updater scripts from the shared PowerShell logic in +# update_spice.ps1. each output is a self-contained polyglot .bat: a small batch +# header (with the release channel baked in) followed by the shared PowerShell +# body after the marker line. +# +# usage: build_updaters.sh OUT_DIR +# OUT_DIR directory to write the generated .bat files into + +set -eu + +if [ $# -lt 1 ]; then + echo "usage: build_updaters.sh OUT_DIR" >&2 + exit 1 +fi + +SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PS_BODY="${SRC_DIR}/update_spice.ps1" +OUT_DIR="$1" + +[ -f "$PS_BODY" ] || { echo "error: $PS_BODY not found" >&2; exit 1; } + +MARKER='#___PS___' + +gen() { + channel="$1"; label="$2"; out="$3" + { + cat <
"${OUT_DIR}/${out}" + echo " generated ${OUT_DIR}/${out}" +} + +echo "Generating updater scripts from $(basename "$PS_BODY")..." +gen "" "stable (pre-releases excluded)" "update_spice.bat" +gen "beta" "beta (newest, pre-releases included)" "update_spice_beta.bat" diff --git a/src/spice2x/update_spice.ps1 b/src/spice2x/update_spice.ps1 new file mode 100644 index 0000000..e769838 --- /dev/null +++ b/src/spice2x/update_spice.ps1 @@ -0,0 +1,66 @@ +$ErrorActionPreference = 'Stop' + +# --- configuration ---------------------------------------------------------- +$scriptDir = if ($env:SPICE_DIR) { $env:SPICE_DIR } elseif ($PSScriptRoot) { $PSScriptRoot } else { (Get-Location).Path } +$repo = 'spice2x/spice2x.github.io' +$targets = @('spice.exe', 'spice64.exe', 'spicecfg.exe') +$beta = ($env:SPICE_CHANNEL -match 'beta') +$rc = 0 + +$title = if ($beta) { '=== spice2x updater (beta channel) ===' } else { '=== spice2x updater ===' } +Write-Host "`n$title" +Write-Host "Target folder: $scriptDir`n" + +try { + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + $headers = @{ 'User-Agent' = 'spice2x-updater'; 'Accept' = 'application/vnd.github+json' } + + # --- find the newest release (beta = include pre-releases) -------------- + Write-Host 'Querying latest release...' + $url = if ($beta) { "https://api.github.com/repos/$repo/releases?per_page=1" } else { "https://api.github.com/repos/$repo/releases/latest" } + $rel = Invoke-RestMethod -Headers $headers -Uri $url | Select-Object -First 1 + if (-not $rel) { throw 'No releases found.' } + + # --- pick the distribution zip (spice2x-.zip, not the -full one) -- + $asset = $rel.assets | Where-Object { $_.name -like 'spice2x-*.zip' -and $_.name -notlike '*-full.zip' } | Select-Object -First 1 + if (-not $asset) { throw 'No .zip asset found in the release.' } + Write-Host "Latest release: $($rel.tag_name)$(if ($rel.prerelease) { ' [pre-release]' }) (asset: $($asset.name))" + + # --- download the zip into memory --------------------------------------- + # note: on Windows PowerShell 5.1 .Content is a String (empty for binary + # responses), so read the raw byte stream instead + Write-Host 'Downloading...' + $bytes = (Invoke-WebRequest -Headers $headers -Uri $asset.browser_download_url -UseBasicParsing).RawContentStream.ToArray() + + # --- extract just the three executables straight into this folder ------- + # PS 5.1 needs these assemblies loaded; PS 7 already has the types (and the + # FileSystem assembly name no longer resolves there), so only load if missing + if (-not ('System.IO.Compression.ZipFile' -as [type])) { + Add-Type -AssemblyName System.IO.Compression, System.IO.Compression.FileSystem + } + $zip = [IO.Compression.ZipArchive]::new([IO.MemoryStream]::new([byte[]]$bytes)) + try { + $updated = 0 + foreach ($name in $targets) { + $entry = $zip.Entries | Where-Object { $_.Name -eq $name } | Select-Object -First 1 + if (-not $entry) { Write-Warning " $name not found in the archive"; continue } + try { + [IO.Compression.ZipFileExtensions]::ExtractToFile($entry, (Join-Path $scriptDir $name), $true) + Write-Host " updated $name"; $updated++ + } catch { + Write-Warning " FAILED to write $name (running / read-only?): $($_.Exception.Message)" + } + } + } finally { $zip.Dispose() } + + Write-Host "`nDone. $updated of $($targets.Count) executables updated to $($rel.tag_name)." + Write-Host "Only the .exe files are updated; if you copied any DLL stubs, they were not changed." + if ($updated -ne $targets.Count) { $rc = 1 } +} catch { + Write-Host ''; Write-Error $_.Exception.Message; $rc = 1 +} + +# --- result ------------------------------------------------------------------ +Write-Host $(if ($rc) { "`nUpdate FAILED. See the error above." } else { "`nUpdate finished successfully." }) +Start-Sleep -Seconds 5 +exit $rc