fix(desktop): recover from corrupt Electron cache in bootstrap install (Windows)

Windows counterpart of #39127: scripts/install.ps1 `Install-Desktop` runs
`npm run pack` once and throws on the opaque ENOENT a corrupt cached Electron
download produces, with no recovery. Add `Clear-ElectronBuildCache` plus a
purge-and-retry-once on pack failure, mirroring the install.sh fix: remove the
cached electron-*.zip (%LOCALAPPDATA%\electron\Cache + ELECTRON_CACHE /
electron_config_cache overrides) and stale *-unpacked output, then retry so
@electron/get re-downloads with its own SHASUM verification.

Refs #37544.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
youngstar-eth
2026-06-04 17:44:22 +03:00
committed by Teknium
parent ff5652d0f6
commit 338f0b2234

View File

@ -1934,6 +1934,55 @@ function Install-NodeDeps {
} }
} }
# Clear the cached Electron download + any half-written unpacked output so the
# next `npm run pack` re-downloads and re-stages from scratch. A corrupt zip in
# the per-user Electron download cache - most often a partial download resumed
# into the same file, leaving concatenated junk - makes electron-builder's
# `app-builder unpack-electron` extract a tree MISSING the electron binary, so
# the final `electron` -> `Hermes` rename dies with ENOENT and every re-run
# repeats the broken extraction forever.
#
# We deliberately do not validate the zip ourselves: the common
# prepended/concatenated-junk corruption slips past naive checks, so a
# self-rolled gate would skip the real-world case. We unconditionally drop the
# cached electron-*.zip (loose copy and any @electron/get hash-subdir copy) plus
# the stale unpacked dir, then let the caller retry once - @electron/get
# re-downloads with its own SHASUM verification, the real source of truth.
#
# Returns the removed paths. Best-effort: never throws.
function Clear-ElectronBuildCache {
param([string]$DesktopDir)
$removed = @()
# Per-user Electron download cache dirs, honoring the overrides @electron/get
# respects, then the Windows default (%LOCALAPPDATA%\electron\Cache).
$cacheDirs = @()
if ($env:electron_config_cache) { $cacheDirs += $env:electron_config_cache }
if ($env:ELECTRON_CACHE) { $cacheDirs += $env:ELECTRON_CACHE }
if ($env:LOCALAPPDATA) { $cacheDirs += (Join-Path $env:LOCALAPPDATA 'electron\Cache') }
$cacheDirs += (Join-Path $HOME 'AppData\Local\electron\Cache')
foreach ($dir in $cacheDirs) {
if (-not (Test-Path -LiteralPath $dir)) { continue }
# Recurse: the bad copy may be the top-level zip OR a copy inside an
# @electron/get hash subdir.
$removed += @(Get-ChildItem -LiteralPath $dir -Recurse -Filter 'electron-*.zip' -File -ErrorAction SilentlyContinue | ForEach-Object {
try { Remove-Item -LiteralPath $_.FullName -Force -ErrorAction Stop; $_.FullName } catch { }
})
}
# A half-written unpacked dir from an interrupted prior pack poisons the
# rename even after the zip is fixed (win-unpacked / win-arm64-unpacked).
$releaseDir = Join-Path $DesktopDir 'release'
if (Test-Path -LiteralPath $releaseDir) {
$removed += @(Get-ChildItem -LiteralPath $releaseDir -Directory -Filter '*-unpacked' -ErrorAction SilentlyContinue | ForEach-Object {
try { Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction Stop; $_.FullName } catch { }
})
}
return $removed
}
function Install-Desktop { function Install-Desktop {
# Build apps/desktop into a launchable Hermes.exe. Only called from # Build apps/desktop into a launchable Hermes.exe. Only called from
# Stage-Desktop, which is itself only included in the manifest when # Stage-Desktop, which is itself only included in the manifest when
@ -2067,6 +2116,22 @@ function Install-Desktop {
$env:WIN_CSC_KEY_PASSWORD = "" $env:WIN_CSC_KEY_PASSWORD = ""
& $npmExe run pack 2>&1 | ForEach-Object { "$_" } | Tee-Object -FilePath $buildLog & $npmExe run pack 2>&1 | ForEach-Object { "$_" } | Tee-Object -FilePath $buildLog
$code = $LASTEXITCODE $code = $LASTEXITCODE
if ($code -ne 0) {
# A corrupt cached Electron zip makes `pack` fail with an opaque
# ENOENT on the final `electron` -> `Hermes` rename: app-builder's
# unpack-electron extracted a partial tree (missing the binary) from
# the bad zip, and re-running reuses the poisoned cache forever.
# Purge the cached download + any stale unpacked output and retry
# once; @electron/get re-downloads with its own SHASUM check. Without
# this a corrupt download hard-fails the whole installer.
$purged = @(Clear-ElectronBuildCache -DesktopDir $desktopDir)
if ($purged.Count -gt 0) {
Write-Warn "Desktop build failed - cleared cached Electron download, retrying once:"
foreach ($p in $purged) { Write-Info " - $p" }
& $npmExe run pack 2>&1 | ForEach-Object { "$_" } | Tee-Object -FilePath $buildLog
$code = $LASTEXITCODE
}
}
$ErrorActionPreference = $prevEAP $ErrorActionPreference = $prevEAP
if ($code -ne 0) { if ($code -ne 0) {
$errText = Get-Content $buildLog -Raw -ErrorAction SilentlyContinue $errText = Get-Content $buildLog -Raw -ErrorAction SilentlyContinue