mirror of
https://github.com/nexu-io/open-design.git
synced 2026-07-14 05:32:21 +08:00
* Optimize Windows packaged web output * Fix packaged contracts runtime build * Optimize Windows packaged size pruning * Prune Windows root Next payload * Remove Windows bundled Node runtime * Prune Windows standalone duplicate Next * Add tools-pack cache foundation * Cache Windows packaged build layers * Cache Windows workspace builds * Cache Electron-ready Windows app * Split Windows tools-pack module * Cache Windows dir build outputs * Split Windows pack build modules * Document Windows NSIS smoke namespace limits * Move Windows NSIS smoke note to agents guide * Optimize Windows beta packaging * Bump packaged beta base version * Improve Windows installer namespace UX * Improve Windows tools-pack cache keys * Stabilize Windows beta cache version keys * Cache Windows workspace build outputs * Optimize windows release beta cache layers * Cache windows release dependencies * Trim windows release cache before save * Refresh windows tools-pack cache key * Improve windows installer preflight prompts * Fallback NSIS installer strings to English * Fix Windows installer cleanup and preflight * Improve Windows NSIS state logging * Fix system NSIS Persian language alias * Use long-path removal for Windows uninstall * Fix mac tools-pack tests on Windows * Address Windows packaging review feedback * Fix Windows installer cache namespace isolation * Include web output mode in Windows tarball cache key * Use unique Windows release cache save keys
126 lines
4.8 KiB
TypeScript
126 lines
4.8 KiB
TypeScript
import { access, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import { ToolPackCache } from "../src/cache.js";
|
|
|
|
async function pathExists(path: string): Promise<boolean> {
|
|
try {
|
|
await access(path);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
describe("ToolPackCache", () => {
|
|
it("builds once, materializes copies, and reports cache hits", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "open-design-tools-pack-cache-"));
|
|
const cacheRoot = join(root, "cache");
|
|
const firstOut = join(root, "first", "payload");
|
|
const secondOut = join(root, "second", "payload");
|
|
let builds = 0;
|
|
const cache = new ToolPackCache(cacheRoot);
|
|
const node = {
|
|
id: "test.node",
|
|
key: "key-1",
|
|
outputs: ["payload"],
|
|
invalidate: async () => null,
|
|
build: async ({ entryRoot }: { entryRoot: string }) => {
|
|
builds += 1;
|
|
await mkdir(join(entryRoot, "payload"), { recursive: true });
|
|
await writeFile(join(entryRoot, "payload", "value.txt"), `build-${builds}\n`, "utf8");
|
|
return { builds };
|
|
},
|
|
};
|
|
|
|
try {
|
|
const firstManifest = await cache.acquire({ materialize: [{ from: "payload", to: firstOut }], node });
|
|
await writeFile(join(firstOut, "value.txt"), "mutated\n", "utf8");
|
|
await cache.acquire({ materialize: [{ from: "payload", to: secondOut }], node });
|
|
|
|
expect(builds).toBe(1);
|
|
expect(firstManifest.entryPath).toContain("test.node");
|
|
expect(await readFile(join(secondOut, "value.txt"), "utf8")).toBe("build-1\n");
|
|
expect(cache.report().entries.map((entry) => entry.status)).toEqual(["miss", "hit"]);
|
|
} finally {
|
|
await rm(root, { force: true, recursive: true });
|
|
}
|
|
});
|
|
|
|
it("rebuilds stale entries when declared outputs are missing", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "open-design-tools-pack-cache-stale-"));
|
|
const cacheRoot = join(root, "cache");
|
|
const out = join(root, "out", "payload");
|
|
let builds = 0;
|
|
const cache = new ToolPackCache(cacheRoot);
|
|
const node = {
|
|
id: "test.stale",
|
|
key: "key-1",
|
|
outputs: ["payload"],
|
|
invalidate: async () => null,
|
|
build: async ({ entryRoot }: { entryRoot: string }) => {
|
|
builds += 1;
|
|
if (builds === 1) {
|
|
await mkdir(join(entryRoot, "payload"), { recursive: true });
|
|
await writeFile(join(entryRoot, "payload", "value.txt"), "first\n", "utf8");
|
|
return { builds };
|
|
}
|
|
await mkdir(join(entryRoot, "payload"), { recursive: true });
|
|
await writeFile(join(entryRoot, "payload", "value.txt"), "second\n", "utf8");
|
|
return { builds };
|
|
},
|
|
};
|
|
|
|
try {
|
|
await cache.acquire({ materialize: [{ from: "payload", to: out }], node });
|
|
const entryPath = cache.report().entries[0]?.entryPath;
|
|
expect(entryPath).toBeDefined();
|
|
await rm(join(entryPath!, "payload"), { force: true, recursive: true });
|
|
await cache.acquire({ materialize: [{ from: "payload", to: out }], node });
|
|
|
|
expect(builds).toBe(2);
|
|
expect(await readFile(join(out, "value.txt"), "utf8")).toBe("second\n");
|
|
expect(cache.report().entries.map((entry) => entry.status)).toEqual(["miss", "stale"]);
|
|
expect(await pathExists(join(cacheRoot, "locks", "global.lock"))).toBe(false);
|
|
} finally {
|
|
await rm(root, { force: true, recursive: true });
|
|
}
|
|
});
|
|
|
|
it("reads existing hits without building", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "open-design-tools-pack-cache-read-hit-"));
|
|
const cacheRoot = join(root, "cache");
|
|
const out = join(root, "out", "payload");
|
|
let builds = 0;
|
|
const cache = new ToolPackCache(cacheRoot);
|
|
const node = {
|
|
id: "test.read-hit",
|
|
key: "key-1",
|
|
outputs: ["payload"],
|
|
invalidate: async () => null,
|
|
build: async ({ entryRoot }: { entryRoot: string }) => {
|
|
builds += 1;
|
|
await mkdir(join(entryRoot, "payload"), { recursive: true });
|
|
await writeFile(join(entryRoot, "payload", "value.txt"), `build-${builds}\n`, "utf8");
|
|
return { builds };
|
|
},
|
|
};
|
|
|
|
try {
|
|
expect(await cache.readHit({ materialize: [{ from: "payload", to: out }], node })).toBeNull();
|
|
await cache.acquire({ materialize: [], node });
|
|
const hit = await cache.readHit({ materialize: [{ from: "payload", to: out }], node });
|
|
|
|
expect(hit?.payloadMetadata.builds).toBe(1);
|
|
expect(builds).toBe(1);
|
|
expect(await readFile(join(out, "value.txt"), "utf8")).toBe("build-1\n");
|
|
expect(cache.report().entries.map((entry) => entry.status)).toEqual(["miss", "hit"]);
|
|
} finally {
|
|
await rm(root, { force: true, recursive: true });
|
|
}
|
|
});
|
|
});
|