Skip to content

Commit 2673db9

Browse files
committed
Skip re-hashing cached v86 assets on dev runs
Size-compare against a pinned manifest for the fast path; full SHA-256 verification still runs under --verify or CI=true. Atomic writes mean a matching size implies the hash matched at write time.
1 parent 28ac8c3 commit 2673db9

1 file changed

Lines changed: 47 additions & 28 deletions

File tree

scripts/fetch-v86-assets.mjs

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,55 @@ import { fileURLToPath } from "node:url";
1515

1616
const HOST = "https://copy.sh/v86/";
1717

18-
const files = [
18+
const remote = [
1919
{
2020
url: HOST + "bios/seabios.bin",
2121
out: "public/v86/bios/seabios.bin",
22+
size: 131072,
2223
sha256: "73e3f359102e3a9982c35fce98eb7cd08f18303ac7f1ba6ebfbe6cdc1c244d98",
2324
},
2425
{
2526
url: HOST + "bios/vgabios.bin",
2627
out: "public/v86/bios/vgabios.bin",
28+
size: 36352,
2729
sha256: "a4bc0d80cc3ca028c73dafa8fee396b8d054ce87ebd8abfbd31b06b437607880",
2830
},
2931
{
3032
url: HOST + "images/linux4.iso",
3133
out: "public/v86/images/linux.iso",
34+
size: 7712768,
3235
sha256: "cb403835be0d857191cdeb86efc8d559b94a787d6fcb57e0a04667296405c223",
3336
},
3437
];
3538

39+
const bundled = [
40+
{ src: "node_modules/v86/build/v86.wasm", out: "public/v86/build/v86.wasm" },
41+
{ src: "node_modules/v86/build/v86-fallback.wasm", out: "public/v86/build/v86-fallback.wasm" },
42+
];
43+
3644
const root = dirname(dirname(fileURLToPath(import.meta.url)));
45+
const verify = process.argv.includes("--verify") || process.env.CI === "true";
3746

3847
const sha256 = async (path) => {
3948
const hash = createHash("sha256");
4049
await pipeline(createReadStream(path), hash);
4150
return hash.digest("hex");
4251
};
4352

44-
const download = async (url, outRel, expectedHash) => {
45-
const out = join(root, outRel);
46-
if (existsSync(out) && statSync(out).size > 0) {
47-
const actual = await sha256(out);
48-
if (actual === expectedHash) {
49-
console.log(`✓ cached ${outRel}`);
50-
return;
51-
}
52-
console.warn(`! hash mismatch for cached ${outRel}; re-downloading`);
53-
unlinkSync(out);
53+
const isCached = async (path, size, hash) => {
54+
if (!existsSync(path) || statSync(path).size !== size) return false;
55+
if (!verify) return true;
56+
return (await sha256(path)) === hash;
57+
};
58+
59+
const fetchOne = async ({ url, out, size, sha256: expected }) => {
60+
const abs = join(root, out);
61+
if (await isCached(abs, size, expected)) {
62+
console.log(`✓ cached ${out}`);
63+
return;
5464
}
55-
mkdirSync(dirname(out), { recursive: true });
65+
if (existsSync(abs)) unlinkSync(abs);
66+
mkdirSync(dirname(abs), { recursive: true });
5667
console.log(`↓ ${url}`);
5768
const res = await fetch(url);
5869
if (!res.ok || !res.body) {
@@ -61,37 +72,45 @@ const download = async (url, outRel, expectedHash) => {
6172
`${url}${res.status} ${res.statusText} ${snippet.slice(0, 120).replace(/\s+/g, " ")}`.trim(),
6273
);
6374
}
64-
const tmp = out + ".part";
75+
const tmp = abs + ".part";
6576
try {
6677
await pipeline(res.body, createWriteStream(tmp));
6778
const actual = await sha256(tmp);
68-
if (actual !== expectedHash) {
69-
throw new Error(`sha256 mismatch for ${outRel}: got ${actual}, expected ${expectedHash}`);
79+
if (actual !== expected) {
80+
throw new Error(`sha256 mismatch for ${out}: got ${actual}, expected ${expected}`);
7081
}
71-
renameSync(tmp, out);
82+
renameSync(tmp, abs);
7283
} catch (e) {
7384
try {
7485
unlinkSync(tmp);
7586
} catch {}
7687
throw e;
7788
}
78-
console.log(` saved ${outRel} (${statSync(out).size} bytes)`);
89+
console.log(` saved ${out} (${statSync(abs).size} bytes)`);
7990
};
8091

81-
for (const f of files) {
92+
const copyOne = ({ src, out }) => {
93+
const absSrc = join(root, src);
94+
const absOut = join(root, out);
95+
const srcSize = statSync(absSrc).size;
96+
if (existsSync(absOut) && statSync(absOut).size === srcSize) {
97+
console.log(`✓ cached ${out}`);
98+
return;
99+
}
100+
mkdirSync(dirname(absOut), { recursive: true });
101+
copyFileSync(absSrc, absOut);
102+
console.log(` copied ${out}`);
103+
};
104+
105+
let failed = false;
106+
for (const f of remote) {
82107
try {
83-
await download(f.url, f.out, f.sha256);
108+
await fetchOne(f);
84109
} catch (e) {
85110
console.error(`failed ${f.url}:`, e.message);
86-
process.exitCode = 1;
111+
failed = true;
87112
}
88113
}
114+
for (const f of bundled) copyOne(f);
89115

90-
const wasms = ["v86.wasm", "v86-fallback.wasm"];
91-
for (const name of wasms) {
92-
const src = join(root, "node_modules/v86/build", name);
93-
const out = join(root, "public/v86/build", name);
94-
mkdirSync(dirname(out), { recursive: true });
95-
copyFileSync(src, out);
96-
console.log(`✓ copied ${name}`);
97-
}
116+
if (failed) process.exitCode = 1;

0 commit comments

Comments
 (0)