fix(install): detect arch-suffixed desktop builds on repair/upgrade reruns (#94703)

electron-builder names the unpacked output <os>-unpacked on x64 and
<os>-<arch>-unpacked elsewhere (linux-arm64-unpacked, win-arm64-unpacked).
install.sh desktop_product_present and install.ps1
Test-DesktopProductPresent only listed the x64 names, so a rerun on an
ARM64 desktop install skipped the desktop rebuild and left a bundle built
from the previous code. List every unpacked dir main_desktop.py already
resolves, in both installers.
This commit is contained in:
Hermes Agent
2026-09-24 23:47:46 -05:00
committed by brooklyn!
parent 723c50233b
commit 980318e689
3 changed files with 64 additions and 4 deletions

View File

@@ -978,8 +978,12 @@ function Test-DesktopProductPresent {
# upgrade rerun on a desktop install must REBUILD it rather than leave a
# bundle built by the previous code: the app is part of that install and its
# artifacts live inside the tree, so an update makes them stale, not gone.
# electron-builder suffixes the output dir with the arch on every non-x64
# target (win-arm64-unpacked, linux-arm64-unpacked, mac-arm64), so the x64
# names alone miss a desktop build on ARM64 (#94703).
$release = Join-Path $InstallDir "apps/desktop/release"
foreach ($candidate in @("win-unpacked", "linux-unpacked", "mac", "mac-arm64")) {
foreach ($candidate in @("win-unpacked", "win-ia32-unpacked", "win-arm64-unpacked",
"linux-unpacked", "linux-arm64-unpacked", "mac", "mac-arm64")) {
if (Test-Path (Join-Path $release $candidate)) { return $true }
}
return $false

View File

@@ -612,9 +612,15 @@ desktop_product_present() {
# bundle built from the previous code: the app is part of that install, and
# the artifacts live inside the tree (gitignored), so an update makes them
# stale instead of removing them.
local release="$INSTALL_DIR/apps/desktop/release"
[ -d "$release/linux-unpacked" ] || [ -d "$release/mac" ] \
|| [ -d "$release/mac-arm64" ] || [ -d "$release/win-unpacked" ]
# electron-builder suffixes the output dir with the arch on every non-x64
# target (linux-arm64-unpacked, mac-arm64, win-arm64-unpacked), so the x64
# names alone miss a desktop build on ARM64 Linux/Windows (#94703).
local release="$INSTALL_DIR/apps/desktop/release" dir
for dir in linux-unpacked linux-arm64-unpacked mac mac-arm64 \
win-unpacked win-ia32-unpacked win-arm64-unpacked; do
[ -d "$release/$dir" ] && return 0
done
return 1
}
append_shell_path() {

View File

@@ -0,0 +1,50 @@
"""Installer repair/upgrade reruns detect a built desktop app on every arch (#94703).
electron-builder names the unpacked output ``<os>-unpacked`` on x64 but
``<os>-<arch>-unpacked`` elsewhere (``linux-arm64-unpacked``,
``win-arm64-unpacked``; macOS uses ``mac-arm64``). install.sh and install.ps1
only knew the x64 names, so a rerun on an ARM64 desktop install skipped the
desktop rebuild and left a bundle built from the previous code.
"""
from __future__ import annotations
import os
import re
import shlex
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[3]
INSTALL_SH = ROOT / "scripts" / "install.sh"
INSTALL_PS1 = ROOT / "scripts" / "install.ps1"
UNPACKED_DIRS = ("linux-unpacked", "linux-arm64-unpacked", "mac", "mac-arm64",
"win-unpacked", "win-ia32-unpacked", "win-arm64-unpacked")
def _desktop_product_present(tmp_path: Path) -> int:
env = dict(os.environ, HOME=tmp_path.as_posix(), HERMES_HOME=(tmp_path / "home").as_posix(),
HERMES_INSTALL_DIR=(tmp_path / "install").as_posix())
script = f"source {shlex.quote(INSTALL_SH.as_posix())} --manifest >/dev/null\ndesktop_product_present\n"
return subprocess.run(["bash", "-c", script], env=env, capture_output=True, text=True, timeout=30).returncode
@pytest.mark.parametrize("unpacked", UNPACKED_DIRS)
def test_install_sh_detects_desktop_build(tmp_path, unpacked):
(tmp_path / "install" / "apps" / "desktop" / "release" / unpacked).mkdir(parents=True)
assert _desktop_product_present(tmp_path) == 0
def test_install_sh_without_desktop_build(tmp_path):
(tmp_path / "install" / "apps" / "desktop" / "release" / "builder-debug").mkdir(parents=True)
assert _desktop_product_present(tmp_path) != 0
def test_install_ps1_candidates_match_install_sh():
body = INSTALL_PS1.read_text(encoding="utf-8")
fn = body[body.index("function Test-DesktopProductPresent"):]
listed = re.search(r"foreach \(\$candidate in @\((.*?)\)\)", fn, re.S)
assert listed, "Test-DesktopProductPresent candidate list not found"
assert set(re.findall(r'"([^"]+)"', listed.group(1))) == set(UNPACKED_DIRS)