Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions contrib/install/install-ps1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,24 @@ describe("install.ps1", () => {
expect(scriptContent).toContain("win32-arm64");
});

test("detects architecture from processor environment variables", () => {
expect(scriptContent).toContain("PROCESSOR_ARCHITEW6432");
expect(scriptContent).toContain("PROCESSOR_ARCHITECTURE");
// RuntimeInformation's OSArchitecture is missing on the shadowed type in
// Windows PowerShell 5.1 and throws under Set-StrictMode, so the script must
// not depend on it for architecture detection.
expect(scriptContent).not.toContain("OSArchitecture");
});

test("maps every shipped Windows architecture token to a platform id", () => {
expect(scriptContent).toContain("\"arm64\"");
// AMD64 is the only token PROCESSOR_ARCHITECTURE reports on x64 Windows, so
// the amd64 case is load-bearing; without it every x64 host would fall through
// to the default branch and fail.
expect(scriptContent).toContain("\"amd64\"");
expect(scriptContent).toContain("\"x64\"");
});

windowsPowerShellTest(
"uses %APPDATA%\\oo\\downloads as the default Windows download directory",
() => {
Expand Down Expand Up @@ -182,6 +200,51 @@ describe("install.ps1", () => {
expect(result.exitCode).toBe(7);
},
);

const resolvePlatformCases = [
{ architew6432: "", processor: "AMD64", expected: "win32-x64" },
// Inbox Windows PowerShell 5.1 on an ARM64 host runs as a 32-bit (WOW64)
// process, so PROCESSOR_ARCHITECTURE is x86 but PROCESSOR_ARCHITEW6432 carries
// the true host architecture; the platform must still resolve to arm64.
{ architew6432: "ARM64", processor: "x86", expected: "win32-arm64" },
{ architew6432: "", processor: "ARM64", expected: "win32-arm64" },
];

for (const { architew6432, processor, expected } of resolvePlatformCases) {
windowsPowerShellTest(
`Resolve-Platform maps ARCHITEW6432='${architew6432}' ARCHITECTURE='${processor}' to ${expected}`,
() => {
const result = runPowerShellCommand(
[
`$env:PROCESSOR_ARCHITEW6432 = '${escapePowerShellString(architew6432)}'`,
`$env:PROCESSOR_ARCHITECTURE = '${escapePowerShellString(processor)}'`,
`. '${escapePowerShellString(installScriptPath)}'`,
"Resolve-Platform",
].join("; "),
);

expect(result.exitCode).toBe(0);
expect(decodeSpawnOutput(result.stdout).trim()).toBe(expected);
},
);
}

windowsPowerShellTest(
"Resolve-Platform fails on an unsupported architecture",
() => {
const result = runPowerShellCommand(
[
"$env:PROCESSOR_ARCHITEW6432 = ''",
"$env:PROCESSOR_ARCHITECTURE = 'x86'",
`. '${escapePowerShellString(installScriptPath)}'`,
"Resolve-Platform",
].join("; "),
);

expect(result.exitCode).not.toBe(0);
expect(decodeSpawnOutput(result.stderr)).toContain("Unsupported Windows architecture");
},
);
});

function resolvePowerShellCommand(): string | undefined {
Expand Down Expand Up @@ -220,3 +283,24 @@ function resolvePowerShellCommand(): string | undefined {
function escapePowerShellString(value: string): string {
return value.replaceAll("'", "''");
}

function runPowerShellCommand(command: string) {
return Bun.spawnSync(
[
powerShellCommand!,
"-NoLogo",
"-NoProfile",
"-Command",
command,
],
{
// Neutralize OO_INSTALL_PLATFORM so a value inherited from the caller's
// environment cannot short-circuit Resolve-Platform and make the
// architecture-detection tests nondeterministic.
env: { ...process.env, OO_INSTALL_PLATFORM: "" },
stderr: "pipe",
stdin: "ignore",
stdout: "pipe",
},
);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
26 changes: 22 additions & 4 deletions contrib/install/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,32 @@ function Resolve-Platform {

Assert-Windows

$architecture = (
[System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture
).ToString().ToLowerInvariant()
# Detect the host architecture from environment variables rather than the .NET
# RuntimeInformation architecture API. That API can be absent on the type
# PowerShell resolves in Windows PowerShell 5.1 (a shadowing assembly such as
# PSReadLine can define its own RuntimeInformation without it), which throws under
# Set-StrictMode; on .NET Framework it also reports the emulated process
# architecture rather than the host. PROCESSOR_ARCHITEW6432 is populated only
# inside a 32-bit (WOW64) process and holds the true host architecture, so the
# inbox 32-bit Windows PowerShell 5.1 on an ARM64 host still resolves to arm64.
# Reading $env: under StrictMode is provider access and safely yields $null when
# the variable is unset.
$architecture = $env:PROCESSOR_ARCHITEW6432
if ([string]::IsNullOrWhiteSpace($architecture)) {
$architecture = $env:PROCESSOR_ARCHITECTURE
}

if ([string]::IsNullOrWhiteSpace($architecture)) {
Fail "Could not determine the Windows processor architecture."
}

switch ($architecture) {
switch ($architecture.ToLowerInvariant()) {
"arm64" {
return "win32-arm64"
}
"amd64" {
return "win32-x64"
}
"x64" {
return "win32-x64"
}
Expand Down
Loading