fix(install): request the native bootstrap Python on Windows-on-ARM

A bare version request lets uv pick an emulated x86_64 CPython on
Windows arm64 hosts ("support for the native architecture (aarch64) is
not yet mature"). The bootstrap interpreter then ran as win-amd64.

Request cpython-<minor>-windows-<arch>-none from the machine
architecture the scripts already detect, in install.ps1,
setup-hermes.ps1 and setup-hermes.sh (win32 only; POSIX keeps the bare
version so uv still picks the right libc variant).
This commit is contained in:
ethernet
2026-09-24 10:58:07 -04:00
parent 0372a8b2da
commit 419a3cbe00
4 changed files with 20 additions and 8 deletions

View File

@@ -764,11 +764,14 @@ function Get-BootstrapPython {
$lock = Get-Content (Join-Path $InstallDir "pm\lock.json") -Raw | ConvertFrom-Json $lock = Get-Content (Join-Path $InstallDir "pm\lock.json") -Raw | ConvertFrom-Json
$pyPin = $lock.packages.python $pyPin = $lock.packages.python
$pyVersion = if ($pyPin) { ($pyPin.version -split '\+')[0] -replace '^(\d+\.\d+).*', '$1' } else { '3.14' } $pyVersion = if ($pyPin) { ($pyPin.version -split '\+')[0] -replace '^(\d+\.\d+).*', '$1' } else { '3.14' }
$bootPy = (Invoke-Native { & $uv python find --managed-python --no-project $pyVersion 2>$null }) -join "`n" # A bare version lets uv pick emulated x86_64 on Windows-on-ARM.
$pyArch = if ((Get-WindowsArch) -eq 'arm64') { 'aarch64' } else { 'x86_64' }
$pyRequest = "cpython-$pyVersion-windows-$pyArch-none"
$bootPy = (Invoke-Native { & $uv python find --managed-python --no-project $pyRequest 2>$null }) -join "`n"
if ($LASTEXITCODE -or -not $bootPy) { if ($LASTEXITCODE -or -not $bootPy) {
Invoke-Native { & $uv python install --no-bin --no-registry $pyVersion } | Out-Host Invoke-Native { & $uv python install --no-bin --no-registry $pyRequest } | Out-Host
if ($LASTEXITCODE) { Fail "bootstrap Python installation failed" } if ($LASTEXITCODE) { Fail "bootstrap Python installation failed" }
$bootPy = (Invoke-Native { & $uv python find --managed-python --no-project $pyVersion }) -join "`n" $bootPy = (Invoke-Native { & $uv python find --managed-python --no-project $pyRequest }) -join "`n"
} }
if ($LASTEXITCODE -or -not $bootPy) { Fail "bootstrap Python lookup failed" } if ($LASTEXITCODE -or -not $bootPy) { Fail "bootstrap Python lookup failed" }
return $bootPy.Trim() return $bootPy.Trim()

View File

@@ -51,7 +51,8 @@ exit /b 0
# cmd's `echo %* >> file` keeps the space before `>>` in the recorded line. # cmd's `echo %* >> file` keeps the space before `>>` in the recorded line.
$recorded = @(Get-Content -LiteralPath $argsFile | ForEach-Object { $_.Trim() }) $recorded = @(Get-Content -LiteralPath $argsFile | ForEach-Object { $_.Trim() })
Assert-True ($recorded.Count -eq 1) 'uv locates the available bootstrap Python without reinstalling it' Assert-True ($recorded.Count -eq 1) 'uv locates the available bootstrap Python without reinstalling it'
Assert-True ($recorded[0] -eq 'python find --managed-python --no-project 3.13') 'Python minor comes from the lockfile; lookup ignores ambient project discovery' $pyArch = if ((Get-WindowsArch) -eq 'arm64') { 'aarch64' } else { 'x86_64' }
Assert-True ($recorded[0] -eq "python find --managed-python --no-project cpython-3.13-windows-$pyArch-none") 'Python minor comes from the lockfile, pinned to the machine architecture; lookup ignores ambient project discovery'
Assert-True ((Get-Content -LiteralPath $pythonArgsFile -Raw).Trim() -eq '-m pm.cli install') 'Python launches PM without a uv parent' Assert-True ((Get-Content -LiteralPath $pythonArgsFile -Raw).Trim() -eq '-m pm.cli install') 'Python launches PM without a uv parent'
# The installer owns no node stage: tool and frontend provisioning belongs # The installer owns no node stage: tool and frontend provisioning belongs

View File

@@ -82,9 +82,11 @@ Write-Host '(first run on a fresh checkout can take 1-5 minutes)'
Push-Location $repo Push-Location $repo
try { try {
# PM can replace its uv entry only after the bootstrap uv has exited. # PM can replace its uv entry only after the bootstrap uv has exited.
& $uv python install --no-bin --no-registry $pyVersion # A bare version lets uv pick emulated x86_64 on Windows-on-ARM.
$pyRequest = "cpython-$pyVersion-windows-$(if ($arch -eq 'arm64') { 'aarch64' } else { 'x86_64' })-none"
& $uv python install --no-bin --no-registry $pyRequest
if ($LASTEXITCODE -ne 0) { throw 'bootstrap Python installation failed' } if ($LASTEXITCODE -ne 0) { throw 'bootstrap Python installation failed' }
$bootPy = (& $uv python find --managed-python $pyVersion) -join "`n" $bootPy = (& $uv python find --managed-python $pyRequest) -join "`n"
if ($LASTEXITCODE -ne 0 -or -not $bootPy) { throw 'bootstrap Python lookup failed' } if ($LASTEXITCODE -ne 0 -or -not $bootPy) { throw 'bootstrap Python lookup failed' }
& $bootPy.Trim() -m pm.cli install $(if ($RuntimeOnly) { '--trust-recorded' }) "--test-environment=$TestExtras" & $bootPy.Trim() -m pm.cli install $(if ($RuntimeOnly) { '--trust-recorded' }) "--test-environment=$TestExtras"
if ($LASTEXITCODE -ne 0) { throw 'pm install failed - see output above.' } if ($LASTEXITCODE -ne 0) { throw 'pm install failed - see output above.' }

View File

@@ -164,8 +164,14 @@ fi
echo -e "${CYAN}→${NC} Installing python + tools + dependencies via pm (hash-verified via uv.lock)..." echo -e "${CYAN}→${NC} Installing python + tools + dependencies via pm (hash-verified via uv.lock)..."
echo -e "${CYAN}→${NC} (first run on a fresh checkout can take 1-5 minutes)" echo -e "${CYAN}→${NC} (first run on a fresh checkout can take 1-5 minutes)"
# PM can replace its uv entry only after the bootstrap uv has exited. # PM can replace its uv entry only after the bootstrap uv has exited.
"$uv" python install --no-bin --no-registry "$py_version" # A bare version lets uv pick emulated x86_64 on Windows-on-ARM.
boot_py="$("$uv" python find --managed-python "$py_version")" py_request="$py_version"
if [ "$os" = win32 ]; then
case "$arch" in arm64) py_request="cpython-$py_version-windows-aarch64-none" ;;
*) py_request="cpython-$py_version-windows-x86_64-none" ;; esac
fi
"$uv" python install --no-bin --no-registry "$py_request"
boot_py="$("$uv" python find --managed-python "$py_request")"
boot_py="${boot_py%$'\r'}" boot_py="${boot_py%$'\r'}"
# Activation trusts the recorded tool digest; a direct setup re-checks it # Activation trusts the recorded tool digest; a direct setup re-checks it
# (setup-hermes.ps1 draws the same line). # (setup-hermes.ps1 draws the same line).