fix(desktop): re-download Electron binary via mirror when pack fails (#47266) (#47276)

* fix(desktop): re-download Electron binary via mirror when pack fails (#47266)

Since #38673 pinned build.electronDist to node_modules/electron/dist,
electron-builder reads the Electron binary straight from there and never
downloads it during `npm run pack`. That dist tree is only produced by the
electron package's postinstall (install.js) during `npm ci`. When that
download is blocked or throttled (GitHub's release host is unreachable in
some regions), the dist is missing and the build dies with:

    The specified electronDist does not exist: .../node_modules/electron/dist

The existing ELECTRON_MIRROR fallback in all three desktop-build paths
(scripts/install.ps1, scripts/install.sh, and `hermes desktop` in
hermes_cli/main.py) re-ran `npm run pack` with ELECTRON_MIRROR set — but
pack never downloads Electron anymore, so the mirror was never used and the
retry re-read the same missing dist. The fallback was effectively dead.

Drive the mirror through electron's own downloader instead:

- Add a dist-presence check + a downloader helper (Test-ElectronDist /
  Restore-ElectronDist, _electron_dist_ok / _restore_electron_dist,
  _electron_dist_ok / _redownload_electron_dist) that wipes a partial dist
  + the path.txt version marker (electron's install.js short-circuits on it)
  and re-runs `node install.js`, optionally via a mirror.
- On the first retry, repopulate a missing dist from the canonical source;
  on the mirror retry, re-fetch through npmmirror.com, then pack.
- Gate the re-download on the dist check so an unrelated build failure
  (tsc/vite) doesn't trigger a pointless ~200 MB refetch, and skip the final
  pack when the binary still can't be fetched instead of failing the same way.

* test(desktop): cover Electron dist re-download mirror fallback (#47266)

Add behavior coverage for the electronDist re-download fix:

- _electron_dist_ok across linux/win32/darwin, including the partial-dist
  case (dir present but binary missing) that makes the pinned electronDist
  fail.
- _redownload_electron_dist: no-op when the binary is present, bail when
  install.js is absent, wipe a stale dist + path.txt marker and run
  electron's downloader with ELECTRON_MIRROR injected, and report failure
  when the download still produces no binary.
- `hermes desktop`: the mirror fallback now drives electron's own downloader
  before re-running pack, and skips the final pack entirely when the binary
  can't be fetched.

Replaces the old mirror test that asserted the (now-fixed) dead behavior of
re-running `npm run pack` with ELECTRON_MIRROR set — pack never downloads
Electron under the pinned electronDist, so that retry could never help.
This commit is contained in:
xxxigm 2026-06-17 03:40:55 +07:00 committed by GitHub
parent db44af004c
commit d1ecebcbfd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 431 additions and 28 deletions

View file

@ -2407,6 +2407,58 @@ _desktop_pack() {
# failed, and we never override a user-pinned ELECTRON_MIRROR.
DESKTOP_ELECTRON_FALLBACK_MIRROR="https://npmmirror.com/mirrors/electron/"
# True (returns 0) when node_modules/electron/dist holds a usable Electron
# binary. electron-builder reads the binary from build.electronDist
# (node_modules/electron/dist) since #38673, so this is the exact file whose
# absence makes a pack fail with "The specified electronDist does not exist". A
# dist dir that exists but is missing the binary (partial extraction / aborted
# postinstall) is NOT ok. $1 = the workspace root holding node_modules.
_electron_dist_ok() {
local install_dir="$1"
local electron_dir="$install_dir/node_modules/electron"
if [ "$OS" = "macos" ]; then
[ -e "$electron_dir/dist/Electron.app/Contents/MacOS/Electron" ]
else
[ -e "$electron_dir/dist/electron" ]
fi
}
# (Re)populate node_modules/electron/dist via electron's own downloader.
#
# Since #38673 the desktop build pins build.electronDist to
# node_modules/electron/dist, so electron-builder reads the Electron binary
# straight from there and never downloads it during `npm run pack`. That dist
# tree is produced by the electron package's postinstall (install.js) during
# `npm ci`. When that download is blocked/throttled (GitHub's release host is
# unreachable in some regions - #47266), dist is missing and re-running pack only
# re-throws "The specified electronDist does not exist". The mirror fallback
# therefore has to drive THIS downloader, not another pack.
#
# No-op (returns 0) when the dist binary is already present. Otherwise drops a
# partial dist + version marker (electron's install.js short-circuits when
# path.txt already matches) and runs the downloader once. $1 = the workspace root
# holding node_modules; optional $2 = an ELECTRON_MIRROR base URL. Best-effort:
# returns 0 iff the dist binary exists afterward.
_restore_electron_dist() {
local install_dir="$1"
local mirror="${2:-}"
local electron_dir="$install_dir/node_modules/electron"
_electron_dist_ok "$install_dir" && return 0
[ -f "$electron_dir/install.js" ] || return 1
command -v node >/dev/null 2>&1 || return 1
rm -rf "$electron_dir/dist" 2>/dev/null || true
rm -f "$electron_dir/path.txt" 2>/dev/null || true
if [ -n "$mirror" ]; then
( cd "$electron_dir" && ELECTRON_MIRROR="$mirror" node install.js ) || true
else
( cd "$electron_dir" && node install.js ) || true
fi
_electron_dist_ok "$install_dir"
}
# Build apps/desktop into a launchable native app. Mirrors install.ps1's
# Install-Desktop: a root-level npm install so the apps/* workspace resolves
# the desktop's own deps (Electron ~150MB), then `npm run pack`
@ -2479,8 +2531,19 @@ install_desktop() {
# (b) Corrupt cached Electron zip is the most common self-healable cause.
local purged
purged="$(clear_electron_build_cache "$desktop_dir")"
if [ -n "$purged" ]; then
log_warn "Desktop build failed; cleared cached Electron download and retrying once..."
# electronDist is pinned to node_modules/electron/dist (#38673):
# electron-builder reads the binary from there and `pack` never downloads
# it, so purging the cache + re-running pack can't by itself repopulate a
# missing/partial dist. When the dist is actually gone, re-run electron's
# own downloader so the retry has a binary to read. Gated on the dist
# check so an unrelated build failure (tsc/vite) doesn't trigger a
# pointless ~200MB refetch.
local restored=false
if ! _electron_dist_ok "$INSTALL_DIR"; then
if _restore_electron_dist "$INSTALL_DIR"; then restored=true; fi
fi
if [ -n "$purged" ] || [ "$restored" = true ]; then
log_warn "Desktop build failed; refreshed the Electron download and retrying once..."
if _desktop_pack "$desktop_dir"; then
pack_ok=true
fi
@ -2488,14 +2551,26 @@ install_desktop() {
fi
# (c) Still failing and the user hasn't pinned their own mirror: the GitHub
# release host is likely blocked/throttled. Retry once via a public
# Electron mirror (@electron/get still SHASUM-verifies the download).
# release host is likely blocked/throttled. Re-download the Electron
# binary via a public mirror, then retry. The mirror MUST drive
# electron's own downloader — `npm run pack` reads the pinned electronDist
# and never downloads, so a mirror passed only to pack is a no-op (#47266).
if [ "$pack_ok" = false ] && [ -z "${ELECTRON_MIRROR:-}" ]; then
log_warn "Desktop build still failing — the Electron download from GitHub looks blocked."
log_warn "Retrying once via a public Electron mirror ($DESKTOP_ELECTRON_FALLBACK_MIRROR)..."
log_warn "Re-downloading Electron via a public mirror ($DESKTOP_ELECTRON_FALLBACK_MIRROR), then rebuilding..."
log_warn " (set ELECTRON_MIRROR yourself to use a different/trusted mirror)"
if _desktop_pack "$desktop_dir" "$DESKTOP_ELECTRON_FALLBACK_MIRROR"; then
pack_ok=true
local have_dist=false
if _electron_dist_ok "$INSTALL_DIR"; then
have_dist=true
elif _restore_electron_dist "$INSTALL_DIR" "$DESKTOP_ELECTRON_FALLBACK_MIRROR"; then
have_dist=true
fi
if [ "$have_dist" = true ]; then
if _desktop_pack "$desktop_dir" "$DESKTOP_ELECTRON_FALLBACK_MIRROR"; then
pack_ok=true
fi
else
log_warn "Could not re-download Electron from the mirror (node_modules/electron/dist still missing)"
fi
fi