fix(release): upload Linux AppImage under feed x64 name
Prevent stale TTRPGPlayer-x64.AppImage on the updates host when electron-builder leaves an x86_64 alias beside an older x64 file. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -34,11 +34,16 @@ function normalizeLinuxReleaseNames() {
|
|||||||
for (const name of fs.readdirSync(releaseDir)) {
|
for (const name of fs.readdirSync(releaseDir)) {
|
||||||
if (!name.includes('x86_64')) continue;
|
if (!name.includes('x86_64')) continue;
|
||||||
const from = path.join(releaseDir, name);
|
const from = path.join(releaseDir, name);
|
||||||
const to = path.join(releaseDir, name.replaceAll('x86_64', 'x64'));
|
const toName = name.replaceAll('x86_64', 'x64');
|
||||||
if (from !== to && !fs.existsSync(to)) {
|
const to = path.join(releaseDir, toName);
|
||||||
fs.renameSync(from, to);
|
if (from === to) continue;
|
||||||
console.log(`[pack:linux] renamed ${name} -> ${path.basename(to)}`);
|
// Always replace stale x64 — otherwise feed points at an old AppImage.
|
||||||
|
if (fs.existsSync(to)) {
|
||||||
|
fs.rmSync(to, { force: true });
|
||||||
|
console.log(`[pack:linux] removed stale ${toName}`);
|
||||||
}
|
}
|
||||||
|
fs.renameSync(from, to);
|
||||||
|
console.log(`[pack:linux] renamed ${name} -> ${toName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ymlName of fs.readdirSync(releaseDir)) {
|
for (const ymlName of fs.readdirSync(releaseDir)) {
|
||||||
|
|||||||
@@ -367,20 +367,37 @@ function Copy-ReleaseArtifacts {
|
|||||||
|
|
||||||
$copied = 0
|
$copied = 0
|
||||||
foreach ($name in ($names | Sort-Object)) {
|
foreach ($name in ($names | Sort-Object)) {
|
||||||
|
# Always publish Linux AppImage under feed/site name (x64), never leave x86_64 alias.
|
||||||
|
if ($name -match 'x86_64' -and $name -match '\.AppImage$') {
|
||||||
|
$canonical = $name -replace 'x86_64', 'x64'
|
||||||
|
if ($names.Contains($canonical)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
$name = $canonical
|
||||||
|
}
|
||||||
|
|
||||||
$src = Join-Path $BuildReleaseDir $name
|
$src = Join-Path $BuildReleaseDir $name
|
||||||
|
$destName = $name
|
||||||
if (-not (Test-Path -LiteralPath $src)) {
|
if (-not (Test-Path -LiteralPath $src)) {
|
||||||
if ($name -match 'x64' -and $name -notmatch 'x86_64') {
|
if ($name -match 'x64' -and $name -notmatch 'x86_64') {
|
||||||
$alt = $name -replace 'x64', 'x86_64'
|
$alt = $name -replace 'x64', 'x86_64'
|
||||||
$src = Join-Path $BuildReleaseDir $alt
|
$altPath = Join-Path $BuildReleaseDir $alt
|
||||||
|
if (Test-Path -LiteralPath $altPath) {
|
||||||
|
$src = $altPath
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (-not (Test-Path -LiteralPath $src)) {
|
if (-not (Test-Path -LiteralPath $src)) {
|
||||||
Write-Host " [--] skip (not built): $name" -ForegroundColor Yellow
|
Write-Host " [--] skip (not built): $name" -ForegroundColor Yellow
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
$dest = Join-Path $TargetDir ([System.IO.Path]::GetFileName($src))
|
$dest = Join-Path $TargetDir $destName
|
||||||
Copy-Item -LiteralPath $src -Destination $dest -Force
|
Copy-Item -LiteralPath $src -Destination $dest -Force
|
||||||
Write-Ok "copied $([System.IO.Path]::GetFileName($src))"
|
if ([System.IO.Path]::GetFileName($src) -ne $destName) {
|
||||||
|
Write-Ok "copied $([System.IO.Path]::GetFileName($src)) -> $destName"
|
||||||
|
} else {
|
||||||
|
Write-Ok "copied $destName"
|
||||||
|
}
|
||||||
$copied += 1
|
$copied += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,12 +102,36 @@ function Resolve-ReleaseFile([string]$name) {
|
|||||||
return $null
|
return $null
|
||||||
}
|
}
|
||||||
|
|
||||||
function Add-FileToUploadSet {
|
# electron-builder may leave TTRPGPlayer-x86_64.AppImage while yml/site expect x64.
|
||||||
|
# Prefer the newer x86_64 build and force the feed name before upload.
|
||||||
|
function Normalize-LinuxAppImageNames {
|
||||||
|
$imgs = Get-ChildItem -LiteralPath $ReleaseDir -Filter 'TTRPGPlayer-*.AppImage' -File -ErrorAction SilentlyContinue
|
||||||
|
foreach ($img in $imgs) {
|
||||||
|
if ($img.Name -notmatch 'x86_64') { continue }
|
||||||
|
$toName = $img.Name -replace 'x86_64', 'x64'
|
||||||
|
$toPath = Join-Path $ReleaseDir $toName
|
||||||
|
if (Test-Path -LiteralPath $toPath) {
|
||||||
|
Remove-Item -LiteralPath $toPath -Force
|
||||||
|
Write-Warn "removed stale $toName (replaced by $($img.Name))"
|
||||||
|
}
|
||||||
|
Rename-Item -LiteralPath $img.FullName -NewName $toName
|
||||||
|
Write-Ok "normalized $($img.Name) -> $toName"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Add-Upload {
|
||||||
param(
|
param(
|
||||||
[System.Collections.Generic.HashSet[string]]$set,
|
[System.Collections.Generic.Dictionary[string, string]]$map,
|
||||||
|
[string]$remoteName,
|
||||||
[System.IO.FileInfo]$file
|
[System.IO.FileInfo]$file
|
||||||
)
|
)
|
||||||
[void]$set.Add($file.FullName)
|
if ($map.ContainsKey($remoteName)) {
|
||||||
|
$prev = $map[$remoteName]
|
||||||
|
if (-not $prev.Equals($file.FullName, [StringComparison]::OrdinalIgnoreCase)) {
|
||||||
|
Write-Warn "upload name collision for $remoteName: keeping $($file.Name)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$map[$remoteName] = $file.FullName
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Title 'TTRPG Release Publisher'
|
Write-Title 'TTRPG Release Publisher'
|
||||||
@@ -129,7 +153,8 @@ if (-not (Test-Path -LiteralPath $sshKey)) {
|
|||||||
|
|
||||||
$errors = [System.Collections.Generic.List[string]]::new()
|
$errors = [System.Collections.Generic.List[string]]::new()
|
||||||
$warnings = [System.Collections.Generic.List[string]]::new()
|
$warnings = [System.Collections.Generic.List[string]]::new()
|
||||||
$uploadFiles = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
|
# remote file name -> local full path (scp must use the feed/site name, not disk alias)
|
||||||
|
$uploadMap = [System.Collections.Generic.Dictionary[string, string]]::new([StringComparer]::OrdinalIgnoreCase)
|
||||||
|
|
||||||
Write-Title 'Windows (required)'
|
Write-Title 'Windows (required)'
|
||||||
$winYml = Join-Path $ReleaseDir 'latest.yml'
|
$winYml = Join-Path $ReleaseDir 'latest.yml'
|
||||||
@@ -137,14 +162,14 @@ if (-not (Test-Path -LiteralPath $winYml)) {
|
|||||||
$errors.Add('Missing latest.yml')
|
$errors.Add('Missing latest.yml')
|
||||||
} else {
|
} else {
|
||||||
Write-Ok 'latest.yml'
|
Write-Ok 'latest.yml'
|
||||||
[void]$uploadFiles.Add($winYml)
|
Add-Upload $uploadMap ([System.IO.Path]::GetFileName($winYml)) (Get-Item -LiteralPath $winYml)
|
||||||
foreach ($name in (Get-YmlReferencedFiles $winYml)) {
|
foreach ($name in (Get-YmlReferencedFiles $winYml)) {
|
||||||
$file = Resolve-ReleaseFile $name
|
$file = Resolve-ReleaseFile $name
|
||||||
if ($null -eq $file) {
|
if ($null -eq $file) {
|
||||||
$errors.Add("Windows: missing file $name (from latest.yml)")
|
$errors.Add("Windows: missing file $name (from latest.yml)")
|
||||||
} else {
|
} else {
|
||||||
Write-Ok $file.Name
|
Write-Ok $file.Name
|
||||||
Add-FileToUploadSet $uploadFiles $file
|
Add-Upload $uploadMap $name $file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$blockmap = Resolve-ReleaseFile 'TTRPGPlayer-Setup.exe.blockmap'
|
$blockmap = Resolve-ReleaseFile 'TTRPGPlayer-Setup.exe.blockmap'
|
||||||
@@ -152,29 +177,30 @@ if (-not (Test-Path -LiteralPath $winYml)) {
|
|||||||
$warnings.Add('Missing TTRPGPlayer-Setup.exe.blockmap (recommended)')
|
$warnings.Add('Missing TTRPGPlayer-Setup.exe.blockmap (recommended)')
|
||||||
} else {
|
} else {
|
||||||
Write-Ok $blockmap.Name
|
Write-Ok $blockmap.Name
|
||||||
Add-FileToUploadSet $uploadFiles $blockmap
|
Add-Upload $uploadMap 'TTRPGPlayer-Setup.exe.blockmap' $blockmap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Title 'Linux (if latest-linux*.yml present)'
|
Write-Title 'Linux (if latest-linux*.yml present)'
|
||||||
|
Normalize-LinuxAppImageNames
|
||||||
$linuxYmls = Get-ChildItem -LiteralPath $ReleaseDir -Filter 'latest-linux*.yml' -File -ErrorAction SilentlyContinue
|
$linuxYmls = Get-ChildItem -LiteralPath $ReleaseDir -Filter 'latest-linux*.yml' -File -ErrorAction SilentlyContinue
|
||||||
if ($linuxYmls.Count -eq 0) {
|
if ($linuxYmls.Count -eq 0) {
|
||||||
Write-Warn 'No latest-linux*.yml - skipping Linux'
|
Write-Warn 'No latest-linux*.yml - skipping Linux'
|
||||||
} else {
|
} else {
|
||||||
foreach ($yml in $linuxYmls) {
|
foreach ($yml in $linuxYmls) {
|
||||||
Write-Ok $yml.Name
|
Write-Ok $yml.Name
|
||||||
[void]$uploadFiles.Add($yml.FullName)
|
Add-Upload $uploadMap $yml.Name $yml
|
||||||
foreach ($name in (Get-YmlReferencedFiles $yml.FullName)) {
|
foreach ($name in (Get-YmlReferencedFiles $yml.FullName)) {
|
||||||
$file = Resolve-ReleaseFile $name
|
$file = Resolve-ReleaseFile $name
|
||||||
if ($null -eq $file) {
|
if ($null -eq $file) {
|
||||||
$errors.Add("Linux ($($yml.Name)): missing file $name")
|
$errors.Add("Linux ($($yml.Name)): missing file $name")
|
||||||
} else {
|
} else {
|
||||||
if ($file.Name -ne $name) {
|
if ($file.Name -ne $name) {
|
||||||
Write-Warn "$($yml.Name): yml expects $name, disk has $($file.Name) - will upload $($file.Name)"
|
Write-Warn "$($yml.Name): yml expects $name, disk has $($file.Name) - uploading as $name"
|
||||||
} else {
|
} else {
|
||||||
Write-Ok "$($yml.Name) -> $name"
|
Write-Ok "$($yml.Name) -> $name"
|
||||||
}
|
}
|
||||||
Add-FileToUploadSet $uploadFiles $file
|
Add-Upload $uploadMap $name $file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +214,7 @@ if ($SkipMac) {
|
|||||||
Write-Warn 'No latest-mac.yml - skipping macOS'
|
Write-Warn 'No latest-mac.yml - skipping macOS'
|
||||||
} else {
|
} else {
|
||||||
Write-Ok 'latest-mac.yml'
|
Write-Ok 'latest-mac.yml'
|
||||||
[void]$uploadFiles.Add($macYml)
|
Add-Upload $uploadMap ([System.IO.Path]::GetFileName($macYml)) (Get-Item -LiteralPath $macYml)
|
||||||
|
|
||||||
$macVersion = Get-YmlVersion $macYml
|
$macVersion = Get-YmlVersion $macYml
|
||||||
$winYml = Join-Path $ReleaseDir 'latest.yml'
|
$winYml = Join-Path $ReleaseDir 'latest.yml'
|
||||||
@@ -216,7 +242,7 @@ if ($SkipMac) {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Write-Ok "primary update: $($primaryFile.Name)"
|
Write-Ok "primary update: $($primaryFile.Name)"
|
||||||
Add-FileToUploadSet $uploadFiles $primaryFile
|
Add-Upload $uploadMap $primaryName $primaryFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +252,7 @@ if ($SkipMac) {
|
|||||||
$warnings.Add("macOS: optional file missing (not uploaded): $name")
|
$warnings.Add("macOS: optional file missing (not uploaded): $name")
|
||||||
} else {
|
} else {
|
||||||
Write-Ok "optional: $($file.Name)"
|
Write-Ok "optional: $($file.Name)"
|
||||||
Add-FileToUploadSet $uploadFiles $file
|
Add-Upload $uploadMap $name $file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,9 +271,14 @@ if ($errors.Count -gt 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Write-Host ''
|
Write-Host ''
|
||||||
Write-Host "Files to upload: $($uploadFiles.Count)" -ForegroundColor Green
|
Write-Host "Files to upload: $($uploadMap.Count)" -ForegroundColor Green
|
||||||
foreach ($path in ($uploadFiles | Sort-Object)) {
|
foreach ($remoteName in ($uploadMap.Keys | Sort-Object)) {
|
||||||
Write-Host " - $([System.IO.Path]::GetFileName($path))"
|
$localName = [System.IO.Path]::GetFileName($uploadMap[$remoteName])
|
||||||
|
if ($localName -eq $remoteName) {
|
||||||
|
Write-Host " - $remoteName"
|
||||||
|
} else {
|
||||||
|
Write-Host " - $remoteName (from $localName)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($CheckOnly) {
|
if ($CheckOnly) {
|
||||||
@@ -260,12 +291,12 @@ Write-Title 'Upload'
|
|||||||
Write-Host "Target: ${sshTarget}:${remoteDir}"
|
Write-Host "Target: ${sshTarget}:${remoteDir}"
|
||||||
Write-Host "Feed: $feedUrl"
|
Write-Host "Feed: $feedUrl"
|
||||||
|
|
||||||
foreach ($path in ($uploadFiles | Sort-Object)) {
|
foreach ($remoteName in ($uploadMap.Keys | Sort-Object)) {
|
||||||
$name = [System.IO.Path]::GetFileName($path)
|
$localPath = $uploadMap[$remoteName]
|
||||||
Write-Host " -> $name"
|
Write-Host " -> $remoteName"
|
||||||
& scp -i $sshKey -q $path "${sshTarget}:${remoteDir}/"
|
& scp -i $sshKey -q $localPath "${sshTarget}:${remoteDir}/$remoteName"
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
throw "scp failed for $name (exit $LASTEXITCODE)"
|
throw "scp failed for $remoteName (exit $LASTEXITCODE)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user