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
10 changes: 8 additions & 2 deletions apps/server/src/update/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ import { activeBundle, Build, bundlePaths, renderShim, type InstalledLayout } fr
import { assetUrl } from "./release.js";
import { compareVersions, parseVersion } from "./version.js";

// Windows archives are zip files that only the bundled bsdtar reads, and a PATH lookup can pick another tar.
export const tarProgram =
process.platform === "win32"
? join(process.env.SystemRoot ?? "C:\\Windows", "System32", "tar.exe")
: "tar";

async function download(url: string, limit: number, fetcher: typeof fetch, signal?: AbortSignal) {
const response = await fetcher(url, {
signal: AbortSignal.any([AbortSignal.timeout(10 * 60_000), ...(signal ? [signal] : [])]),
Expand Down Expand Up @@ -147,7 +153,7 @@ export async function prepareUpdate(
if (!existing) {
const file = join(work, archive);
await writeFile(file, bytes, { mode: 0o600 });
const listing = await run("tar", ["-tf", file]);
const listing = await run(tarProgram, ["-tf", file]);
if (
listing.code !== 0 ||
!listing.stdout.trim() ||
Expand All @@ -162,7 +168,7 @@ export async function prepareUpdate(
)
)
throw new UpdateError("Archive contains an unsafe path or cannot be read.");
if ((await run("tar", ["-xf", file, "-C", work])).code !== 0)
if ((await run(tarProgram, ["-xf", file, "-C", work])).code !== 0)
throw new UpdateError("Release extraction failed.");
await verifyBundle(join(work, "inbot"), layout, version, run);
await writeFile(join(work, "inbot", ".archive-sha256"), `${hash}\n`, { mode: 0o600 });
Expand Down
6 changes: 3 additions & 3 deletions apps/server/src/update/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { dirname, join } from "node:path";
import { expect, test, vi } from "vitest";
import { runCommand, type CommandRunner } from "../../../cli/src/service.js";
import { runCli } from "../../../cli/src/cli.js";
import { prepareUpdate } from "./install.js";
import { prepareUpdate, tarProgram } from "./install.js";
import {
activeBundle,
bundlePaths,
Expand Down Expand Up @@ -43,7 +43,7 @@ export async function updateFixture(target = `${process.platform}-${process.arch
await createBundle(join(stage, "inbot"), "0.2.0");
const archive = `inbot-0.2.0-${target}.${windows ? "zip" : "tar.gz"}`;
const archivePath = join(root, archive);
const packed = await runCommand("tar", [
const packed = await runCommand(tarProgram, [
windows ? "-acf" : "-czf",
archivePath,
"-C",
Expand Down Expand Up @@ -251,7 +251,7 @@ test("CLI update reinstalls the service on the new runtime and preserves its por
username: "synthetic",
health: async () => registered,
run: async (program: string, args: readonly string[]) => {
if (program === "tar" || program.includes("codesign")) return f.run(program, args);
if (program === tarProgram || program.includes("codesign")) return f.run(program, args);
managerCalls.push([...args]);
if (args.includes("bootout") || args.includes("disable") || args.includes("/Delete"))
registered = false;
Expand Down
10 changes: 6 additions & 4 deletions scripts/install-windows.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { promisify } from "node:util";
const exec = promisify(execFile);
const root = fileURLToPath(new URL("../", import.meta.url));
const windows = process.platform === "win32";
// PowerShell 7 exports its own module path, which stops Windows PowerShell from loading its cmdlets.
const { PSModulePath: _, ...baseEnv } = process.env;
const architecture = windows
? (
await powershell(
Expand All @@ -20,7 +22,7 @@ const architecture = windows
: undefined;
const target = `win32-${architecture}`;

function powershell(command, env = process.env) {
function powershell(command, env = baseEnv) {
return exec("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", command], { env });
}

Expand Down Expand Up @@ -49,7 +51,7 @@ function runShim(argument, env) {

function installEnv(temporary, release) {
return {
...process.env,
...baseEnv,
INBOT_HOME: join(temporary, "home"),
INBOT_TEST_MEMORY_KEYCHAIN: "1",
INBOT_INSTALL_ROOT: join(temporary, "installed app"),
Expand Down Expand Up @@ -107,7 +109,7 @@ test(
} finally { $zip.Dispose() }
`,
{
...process.env,
...baseEnv,
INBOT_TEST_BUNDLE: bundle,
INBOT_TEST_ARCHIVE: join(release, archive),
},
Expand Down Expand Up @@ -184,7 +186,7 @@ test(
$zip = [System.IO.Compression.ZipFile]::Open($env:INBOT_TEST_ARCHIVE, 'Create')
try { $zip.CreateEntry($env:INBOT_TEST_ENTRY) | Out-Null } finally { $zip.Dispose() }
`,
{ ...process.env, INBOT_TEST_ARCHIVE: archivePath, INBOT_TEST_ENTRY: entry },
{ ...baseEnv, INBOT_TEST_ARCHIVE: archivePath, INBOT_TEST_ENTRY: entry },
);
const digest = createHash("sha256")
.update(await readFile(archivePath))
Expand Down
Loading