Skip to content
110 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge branch 'worktree-agent-a19b06d959c105bf7' into claude/cool-newton-7nm8r91import assert from "node:assert/strict";
2import { execFileSync } from "node:child_process";
3import { lstatSync, mkdtempSync, readFileSync, readlinkSync, rmSync, writeFileSync } from "node:fs";
4import { tmpdir } from "node:os";
5import { join } from "node:path";
6import { test } from "node:test";
7import { gunzipSync } from "node:zlib";
8
9import { paxRecord, splitPath, tar, tarGz } from "./tar.ts";
10
11const text = (value: string) => new TextEncoder().encode(value);
12const SHA = "4807077b296e6edbf410d55e72749d3e1170c291";
13const ROOT = "acme-rocket-4807077";
14const LONG = `${ROOT}/${"deep/".repeat(40)}${"n".repeat(120)}.txt`;
15
16const entries = [
17 { path: `${ROOT}/README.md`, data: text("hello\n") },
18 { path: `${ROOT}/bin/run`, data: text("#!/bin/sh\necho hi\n"), kind: "exec" as const },
19 { path: `${ROOT}/latest`, data: text("README.md"), kind: "symlink" as const },
20 { path: `${ROOT}/empty`, data: new Uint8Array() },
21 { path: LONG, data: text("far down\n") },
22 { path: `${ROOT}/${"p".repeat(90)}/${"q".repeat(90)}.md`, data: text("split\n") },
23];
24
25/** Whether `tar` can be run here. */
26function hasTar(): boolean {
27 try {
28 execFileSync("tar", ["--version"], { stdio: "ignore" });
29 return true;
30 } catch {
31 return false;
32 }
33}
34
35test("a pax record's length counts itself", () => {
36 const record = new TextDecoder().decode(paxRecord("comment", text(SHA)));
37 assert.equal(record, `52 comment=${SHA}\n`);
38 assert.equal(record.length, 52);
39 // Where adding the length's digits adds a digit.
40 const value = "x".repeat(91);
41 const near = new TextDecoder().decode(paxRecord("path", text(value)));
42 assert.equal(Number(near.split(" ")[0]), near.length);
43});
44
45test("a long path splits into ustar's prefix and name when it can", () => {
46 assert.deepEqual(splitPath(text("a/b")), { name: text("a/b"), prefix: new Uint8Array() });
47 const split = splitPath(text(`${"p".repeat(90)}/${"q".repeat(90)}`))!;
48 assert.equal(new TextDecoder().decode(split.prefix), "p".repeat(90));
49 assert.equal(new TextDecoder().decode(split.name), "q".repeat(90));
50 assert.equal(splitPath(text(`a/${"n".repeat(120)}`)), null);
51 assert.equal(splitPath(text(`${"p".repeat(200)}/b`)), null);
52});
53
54test("headers are ustar, with the commit in a pax global header", () => {
55 const out = tar(entries, { mtime: 1_700_000_000, comment: SHA });
56 assert.equal(out.length % 512, 0);
57 const decoder = new TextDecoder();
58 // The global header first, as git archive writes it.
59 assert.equal(decoder.decode(out.subarray(0, 17)), "pax_global_header");
60 assert.equal(String.fromCharCode(out[156]!), "g");
61 assert.equal(decoder.decode(out.subarray(257, 263)), "ustar\0");
62 assert.equal(decoder.decode(out.subarray(512, 564)), `52 comment=${SHA}\n`);
63 // Every header's checksum holds.
64 const second = out.subarray(1024, 1536);
65 const stored = parseInt(decoder.decode(second.subarray(148, 154)), 8);
66 let sum = 0;
67 for (let i = 0; i < 512; i++) sum += i >= 148 && i < 156 ? 32 : second[i]!;
68 assert.equal(stored, sum);
69 // Ends in two zero blocks.
70 assert.ok(out.subarray(out.length - 1024).every((byte) => byte === 0));
71});
72
73test("tar reads the archive back: files, folders, modes, a symlink and long paths", { skip: !hasTar() && "no tar here" }, async () => {
74 const dir = mkdtempSync(join(tmpdir(), "g1t-tar-"));
75 try {
76 const file = join(dir, "archive.tar.gz");
77 const archive = await tarGz(entries, { mtime: 1_700_000_000, comment: SHA });
78 // A gzip stream around the tar.
79 assert.equal(gunzipSync(archive).length % 512, 0);
80 writeFileSync(file, archive);
81 const listed = execFileSync("tar", ["-tzf", file], { encoding: "utf8" }).trim().split("\n");
82 assert.equal(listed[0], `${ROOT}/`);
83 for (const entry of entries) assert.ok(listed.includes(entry.path), entry.path);
84 assert.ok(listed.includes(`${ROOT}/bin/`));
85 // One top-level folder, as actions/checkout expects.
86 assert.deepEqual([...new Set(listed.map((path) => path.split("/")[0]))], [ROOT]);
87 const out = join(dir, "out");
88 execFileSync("mkdir", [out]);
89 execFileSync("tar", ["-xzf", file, "-C", out]);
90 assert.equal(readFileSync(join(out, ROOT, "README.md"), "utf8"), "hello\n");
91 assert.equal(readFileSync(join(out, LONG), "utf8"), "far down\n");
92 assert.equal(readFileSync(join(out, ROOT, "empty"), "utf8"), "");
93 assert.equal(lstatSync(join(out, ROOT, "bin/run")).mode & 0o111, 0o111);
94 assert.equal(lstatSync(join(out, ROOT, "README.md")).mode & 0o111, 0);
95 assert.ok(lstatSync(join(out, ROOT, "latest")).isSymbolicLink());
96 assert.equal(readlinkSync(join(out, ROOT, "latest")), "README.md");
97 // Dated by the commit.
98 assert.equal(Math.round(lstatSync(join(out, ROOT, "README.md")).mtimeMs / 1000), 1_700_000_000);
99 // git's own reader finds the commit.
100 try {
101 const id = execFileSync("sh", ["-c", `gzip -dc "${file}" | git get-tar-commit-id`], { encoding: "utf8" }).trim();
102 assert.equal(id, SHA);
103 } catch (error) {
104 if ((error as { status?: number }).status === 127) return;
105 throw error;
106 }
107 } finally {
108 rmSync(dir, { recursive: true, force: true });
109 }
110});

This file's history is long; its oldest lines are credited to the oldest commit read.