@volter/browser-substrate 0.1.103 → 0.1.105
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/catalog/demand-input.json +133 -0
- package/dist/boot-screen.d.ts +2 -0
- package/dist/boot-screen.d.ts.map +1 -1
- package/dist/boot-screen.js +1 -1
- package/dist/boot-screen.js.map +1 -1
- package/dist/cli/archive.d.ts +1 -0
- package/dist/cli/archive.d.ts.map +1 -1
- package/dist/cli/archive.js +4 -4
- package/dist/cli/archive.js.map +1 -1
- package/dist/cli/build.d.ts +5 -1
- package/dist/cli/build.d.ts.map +1 -1
- package/dist/cli/build.js +21 -2
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/cache-root.d.ts +7 -0
- package/dist/cli/cache-root.d.ts.map +1 -0
- package/dist/cli/cache-root.js +24 -0
- package/dist/cli/cache-root.js.map +1 -0
- package/dist/cli/companions.d.ts +1 -1
- package/dist/cli/companions.d.ts.map +1 -1
- package/dist/cli/companions.js +30 -16
- package/dist/cli/companions.js.map +1 -1
- package/dist/cli/dependency-plan-build.d.ts +4 -0
- package/dist/cli/dependency-plan-build.d.ts.map +1 -1
- package/dist/cli/dependency-plan-build.js +111 -30
- package/dist/cli/dependency-plan-build.js.map +1 -1
- package/dist/cli/docker-build.d.ts +1 -0
- package/dist/cli/docker-build.d.ts.map +1 -1
- package/dist/cli/docker-build.js +4 -4
- package/dist/cli/docker-build.js.map +1 -1
- package/dist/cli/dry-run.d.ts +4 -4
- package/dist/cli/dry-run.d.ts.map +1 -1
- package/dist/cli/dry-run.js +10 -9
- package/dist/cli/dry-run.js.map +1 -1
- package/dist/cli/generated-code.d.ts +2 -1
- package/dist/cli/generated-code.d.ts.map +1 -1
- package/dist/cli/generated-code.js +46 -16
- package/dist/cli/generated-code.js.map +1 -1
- package/dist/cli/host-build.d.ts +1 -0
- package/dist/cli/host-build.d.ts.map +1 -1
- package/dist/cli/host-build.js +10 -9
- package/dist/cli/host-build.js.map +1 -1
- package/dist/cli/host-managers.d.ts +3 -1
- package/dist/cli/host-managers.d.ts.map +1 -1
- package/dist/cli/host-managers.js +7 -3
- package/dist/cli/host-managers.js.map +1 -1
- package/dist/cli/image-layers.d.ts.map +1 -1
- package/dist/cli/image-layers.js +5 -2
- package/dist/cli/image-layers.js.map +1 -1
- package/dist/cli/main.d.ts +5 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +97 -34
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/pack-publication.d.ts +2 -2
- package/dist/cli/pack-publication.d.ts.map +1 -1
- package/dist/cli/pack-publication.js +3 -3
- package/dist/cli/pack-publication.js.map +1 -1
- package/dist/cli/package-pack.d.ts +1 -1
- package/dist/cli/package-pack.d.ts.map +1 -1
- package/dist/cli/package-pack.js +7 -4
- package/dist/cli/package-pack.js.map +1 -1
- package/dist/cli/package-packs.d.ts +1 -0
- package/dist/cli/package-packs.d.ts.map +1 -1
- package/dist/cli/package-packs.js +84 -14
- package/dist/cli/package-packs.js.map +1 -1
- package/dist/cli/plan-tarballs.d.ts +1 -0
- package/dist/cli/plan-tarballs.d.ts.map +1 -1
- package/dist/cli/plan-tarballs.js +6 -3
- package/dist/cli/plan-tarballs.js.map +1 -1
- package/dist/cli/preparation-memory.d.ts +17 -0
- package/dist/cli/preparation-memory.d.ts.map +1 -0
- package/dist/cli/preparation-memory.js +367 -0
- package/dist/cli/preparation-memory.js.map +1 -0
- package/dist/cli/project-build.d.ts +1 -0
- package/dist/cli/project-build.d.ts.map +1 -1
- package/dist/cli/project-build.js +100 -71
- package/dist/cli/project-build.js.map +1 -1
- package/dist/cli/provision-catalog.d.ts +49 -0
- package/dist/cli/provision-catalog.d.ts.map +1 -0
- package/dist/cli/provision-catalog.js +72 -0
- package/dist/cli/provision-catalog.js.map +1 -0
- package/dist/cli/provision-demand.d.ts +45 -0
- package/dist/cli/provision-demand.d.ts.map +1 -0
- package/dist/cli/provision-demand.js +208 -0
- package/dist/cli/provision-demand.js.map +1 -0
- package/dist/cli/rolldown-binding.d.ts +1 -1
- package/dist/cli/rolldown-binding.d.ts.map +1 -1
- package/dist/cli/rolldown-binding.js +8 -4
- package/dist/cli/rolldown-binding.js.map +1 -1
- package/dist/cli/serve.d.ts +3 -0
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +9 -2
- package/dist/cli/serve.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +75 -31
- package/dist/index.js.map +1 -1
- package/dist/origin-reset.d.ts +4 -0
- package/dist/origin-reset.d.ts.map +1 -0
- package/dist/origin-reset.js +76 -0
- package/dist/origin-reset.js.map +1 -0
- package/dist/program-dom.d.ts +2 -0
- package/dist/program-dom.d.ts.map +1 -1
- package/dist/program-dom.js +11 -1
- package/dist/program-dom.js.map +1 -1
- package/dist/program-types.d.ts +2 -0
- package/dist/program-types.d.ts.map +1 -1
- package/dist/shell/assets/browser-opfs-filesystem-worker-CmF6UKMW.js +3 -0
- package/dist/shell/assets/browser-sandbox-bridge-C8nlSsT2.js +237 -0
- package/dist/shell/assets/{filesystem-host-DJbFuokb.js → filesystem-host-BzPlXSri.js} +1 -1
- package/dist/shell/assets/filesystem-host-Pq9IHKRx.js +3 -0
- package/dist/shell/assets/filesystem-worker-CC3pSXUP.js +5 -0
- package/dist/shell/assets/{fork-worker-BXY2kfdX.js → fork-worker-4YKQ4KTo.js} +1 -1
- package/dist/shell/assets/{node-execution-worker-7e8e0c5321ca0d10.js → node-execution-worker-3ddf5efbaa427e9d.js} +8 -8
- package/dist/shell/assets/{sandbox-bMeKqKBn.js → sandbox-mhFzIWaQ.js} +1 -1
- package/dist/shell/assets/{shell-DLIQ6jHu.js → shell-BZbhxnju.js} +763 -757
- package/dist/shell/assets/worker-BmHEnCyv.js +816 -0
- package/dist/shell/assets/{worker-program-worker-B4OcKVtV.js → worker-program-worker-DueMwljE.js} +10 -10
- package/dist/shell/brand/fonts/Geist-Variable.woff2 +0 -0
- package/dist/shell/brand/fonts/GeistMono-Variable.woff2 +0 -0
- package/dist/shell/brand/fonts/InstrumentSerif-Italic.woff2 +0 -0
- package/dist/shell/brand/fonts/InstrumentSerif-Regular.woff2 +0 -0
- package/dist/shell/brand/icons/app-window.svg +1 -0
- package/dist/shell/brand/icons/at-sign.svg +1 -0
- package/dist/shell/brand/icons/box.svg +1 -0
- package/dist/shell/brand/icons/chevron-right.svg +1 -0
- package/dist/shell/brand/icons/folder.svg +1 -0
- package/dist/shell/brand/icons/info.svg +1 -0
- package/dist/shell/brand/icons/key-round.svg +1 -0
- package/dist/shell/brand/icons/link.svg +1 -0
- package/dist/shell/brand/icons/monitor.svg +1 -0
- package/dist/shell/brand/icons/plus.svg +1 -0
- package/dist/shell/brand/icons/rotate-ccw.svg +1 -0
- package/dist/shell/brand/icons/share-2.svg +1 -0
- package/dist/shell/brand/icons/square-arrow-out-up-right.svg +1 -0
- package/dist/shell/brand/icons/terminal.svg +1 -0
- package/dist/shell/brand/icons/x.svg +1 -0
- package/dist/shell/brand/substrate.svg +1 -0
- package/dist/shell/brand/tokens.css +211 -0
- package/dist/shell/brand/wordmark.svg +1 -0
- package/dist/shell/index.html +5 -3
- package/dist/shell/node-execution-worker.js +16 -13
- package/dist/shell/node-host.html +2 -0
- package/dist/shell/python-execution-worker.js +15 -12
- package/dist/shell/python-host.html +2 -0
- package/dist/shell/python-runtime-snapshot.bin +0 -0
- package/dist/shell/python-runtime-snapshot.json +1 -1
- package/dist/shell/sandbox.html +4 -2
- package/dist/toolbar-styles.generated.d.ts +1 -1
- package/dist/toolbar-styles.generated.d.ts.map +1 -1
- package/dist/toolbar-styles.generated.js +1 -1
- package/dist/toolbar-styles.generated.js.map +1 -1
- package/dist/toolbar.d.ts.map +1 -1
- package/dist/toolbar.js +3 -1
- package/dist/toolbar.js.map +1 -1
- package/package.json +1 -1
- package/dist/shell/assets/browser-opfs-filesystem-worker-k2CPzPBU.js +0 -3
- package/dist/shell/assets/browser-sandbox-bridge-BJbQoc4f.js +0 -237
- package/dist/shell/assets/filesystem-host-yMcJuvmT.js +0 -3
- package/dist/shell/assets/filesystem-worker-BbsBhZ9p.js +0 -5
- package/dist/shell/assets/worker-Ce8bBwSJ.js +0 -816
package/dist/cli/main.js
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
import { catalogProvidedPackages } from "../emscripten-catalog.js";
|
|
8
8
|
import { shellPrograms } from "./shell-programs.js";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
|
-
import {
|
|
10
|
+
import { preparationCacheDirectory, selectedCacheRoot } from "./cache-root.js";
|
|
11
|
+
import { preparationBounded, preparationCheckpoint, preparationMemoryLimit, preparationPhase, withPreparationMemory } from "./preparation-memory.js";
|
|
11
12
|
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, watch, writeFileSync } from "node:fs";
|
|
12
13
|
import { basename, join, relative, resolve, sep } from "node:path";
|
|
13
14
|
import { fileURLToPath } from "node:url";
|
|
@@ -38,15 +39,18 @@ import { detectSetup, SetupError } from "../setup.js";
|
|
|
38
39
|
import { carryRegistryTarballs } from "./plan-tarballs.js";
|
|
39
40
|
import { builtForPlan } from "./project-build.js";
|
|
40
41
|
import { TAB_IMAGE_PROGRAMS, TAB_PROVIDED_IMAGES } from "../program-images.js";
|
|
42
|
+
import { formatBrowserProvisionPlan, planBrowserProvisionDemand, readBrowserProvisionDemand } from "./provision-demand.js";
|
|
41
43
|
const USAGE = `Usage:
|
|
42
44
|
browser-substrate dev [--port <n>] [--no-open] [--no-packs] [--world <dir>] [--dir <sub>] [--build <command>] [settings] [-- <command>]
|
|
43
45
|
run this folder in a tab, attached to a World; a command after -- is what serves it,
|
|
44
46
|
run in --dir, the way a developer types it, in place of what the folder's files say;
|
|
45
47
|
--build is the project's own build, run on this machine at its root, its output carried
|
|
46
|
-
browser-substrate build [--out <dir>] [--world <dir>] [--project <id>] [--build-arg <name=value>] [--program <browser-program.json> --programs-dir <dir>] [settings]
|
|
48
|
+
browser-substrate build [--out <dir>] [--cache-root <dir>] [--world <dir>] [--project <id>] [--build-arg <name=value>] [--program <browser-program.json> --programs-dir <dir>] [settings]
|
|
47
49
|
write ./dist: the page and the image; a --program the image's command names
|
|
48
50
|
is carried in its layers, its archives read from <dir><url>; --world images the
|
|
49
51
|
World the tab runs the image's command under; --build-arg is a Dockerfile's ARG
|
|
52
|
+
browser-substrate plan-provisions [--provision-catalog <json>] [--source-pin <commit>] [--definition <file>] [--dependency-plan <json>]
|
|
53
|
+
read and report demand without preparing an image or starting compute
|
|
50
54
|
browser-substrate preview [--port <n>] [--out <dir>] [--no-open] serve ./dist locally with its _headers
|
|
51
55
|
browser-substrate dry-run [--page <url>] [--settle <s>] [--rounds <n>] [--captured <file>] [--steps <file.json>]
|
|
52
56
|
open the image in Chrome and record every install the tab refuses; what a pack
|
|
@@ -59,6 +63,9 @@ Settings, all optional, needed only to serve something yourself:
|
|
|
59
63
|
--sandbox-origin <origin> where a playground's sandbox is served (default: sandbox.<host>)
|
|
60
64
|
--relay <origin> the relay for Git and outbound TCP (default: ours, under its allowance)
|
|
61
65
|
--artifacts <url> where verified runtime artifacts are fetched from (default: ours)
|
|
66
|
+
--cache-root <dir> preparation cache and scratch; overrides BROWSER_SUBSTRATE_CACHE_ROOT
|
|
67
|
+
--provision-catalog <json> local publication directory, pinned catalog digest and runtime profile
|
|
68
|
+
--preparation-memory-mib <n> build's owned-tree RSS admission; overrides BROWSER_SUBSTRATE_PREPARATION_MEMORY_MIB
|
|
62
69
|
--name <image> the image name a page opens (default: app)
|
|
63
70
|
--no-packs skip preparing packs on this machine; the tab never builds a package, so such an
|
|
64
71
|
image is refused at the first import that needs one
|
|
@@ -69,11 +76,18 @@ export async function main(argv) {
|
|
|
69
76
|
const cwd = process.cwd();
|
|
70
77
|
switch (args.command) {
|
|
71
78
|
case "dev": return dev(cwd, args);
|
|
72
|
-
case "build": return build(cwd, args);
|
|
79
|
+
case "build": return withPreparationMemory(args.preparationMemoryMiB, resolve(cwd, args.out), () => build(cwd, args));
|
|
73
80
|
case "init": return init(cwd);
|
|
74
81
|
case "preview": return preview(cwd, args);
|
|
75
82
|
case "dockerfile": return dockerfile(cwd, args);
|
|
76
83
|
case "dry-run": return dryRunCommand(cwd, args);
|
|
84
|
+
case "plan-provisions": {
|
|
85
|
+
const catalog = args.provisionCatalogFile ? JSON.parse(readFileSync(resolve(cwd, args.provisionCatalogFile), "utf8")) : undefined;
|
|
86
|
+
const demand = readBrowserProvisionDemand(cwd, { abi: catalog?.profile.abi ?? "unselected", ...(args.sourcePin ? { sourcePin: args.sourcePin } : {}), ...(args.definition ? { selectedFile: args.definition } : {}), ...(args.dependencyPlanFile ? { plan: JSON.parse(readFileSync(resolve(cwd, args.dependencyPlanFile), "utf8")) } : {}) });
|
|
87
|
+
const plan = catalog ? await planBrowserProvisionDemand(demand, catalog) : undefined;
|
|
88
|
+
process.stdout.write(formatBrowserProvisionPlan(demand, plan));
|
|
89
|
+
return demand.incomplete.length || demand.items.some((item, index) => item.scope === "selected" && plan?.rows[index]?.status !== "resolved") ? 2 : 0;
|
|
90
|
+
}
|
|
77
91
|
default:
|
|
78
92
|
process.stdout.write(USAGE);
|
|
79
93
|
return args.command === undefined || args.command === "help" ? 0 : 2;
|
|
@@ -115,6 +129,18 @@ function parse(argv) {
|
|
|
115
129
|
// builds each package itself, which is what it did before it carried any.
|
|
116
130
|
else if (arg === "--no-packs")
|
|
117
131
|
args.packs = false;
|
|
132
|
+
else if (arg === "--cache-root")
|
|
133
|
+
args.cacheRoot = value();
|
|
134
|
+
else if (arg === "--provision-catalog")
|
|
135
|
+
args.provisionCatalogFile = value();
|
|
136
|
+
else if (arg === "--source-pin")
|
|
137
|
+
args.sourcePin = value();
|
|
138
|
+
else if (arg === "--definition")
|
|
139
|
+
args.definition = value();
|
|
140
|
+
else if (arg === "--dependency-plan")
|
|
141
|
+
args.dependencyPlanFile = value();
|
|
142
|
+
else if (arg === "--preparation-memory-mib")
|
|
143
|
+
args.preparationMemoryMiB = preparationMemoryLimit(value());
|
|
118
144
|
else if (arg === "--out")
|
|
119
145
|
args.out = value();
|
|
120
146
|
else if (arg === "--name")
|
|
@@ -166,6 +192,18 @@ function parse(argv) {
|
|
|
166
192
|
throw new Error("--name must be lowercase letters, digits, dots, dashes, or underscores.");
|
|
167
193
|
if (!Number.isInteger(args.port) || args.port < 1 || args.port > 65_535)
|
|
168
194
|
throw new Error("--port must be a port number.");
|
|
195
|
+
const cacheRoot = selectedCacheRoot(args.cacheRoot);
|
|
196
|
+
if (cacheRoot)
|
|
197
|
+
args.cacheRoot = cacheRoot;
|
|
198
|
+
if (args.command === "build" && args.preparationMemoryMiB === undefined) {
|
|
199
|
+
const memoryLimit = preparationMemoryLimit();
|
|
200
|
+
if (memoryLimit !== undefined)
|
|
201
|
+
args.preparationMemoryMiB = memoryLimit;
|
|
202
|
+
}
|
|
203
|
+
if (args.command !== "build" && args.preparationMemoryMiB !== undefined)
|
|
204
|
+
throw new Error("--preparation-memory-mib applies to build only.");
|
|
205
|
+
if (args.command !== "plan-provisions" && (args.sourcePin || args.definition || args.dependencyPlanFile))
|
|
206
|
+
throw new Error("--source-pin, --definition and --dependency-plan apply to plan-provisions only.");
|
|
169
207
|
return args;
|
|
170
208
|
}
|
|
171
209
|
/** What a folder carries, for the setup reader. */
|
|
@@ -186,6 +224,12 @@ export async function buildImage(folder, name, settings, project) {
|
|
|
186
224
|
}
|
|
187
225
|
export async function buildImageWith(folder, name, settings, project, options) {
|
|
188
226
|
assertShell();
|
|
227
|
+
// Report all static demands before even an archive copy or setup refusal.
|
|
228
|
+
// Existing families remain on their only current path until their genuine
|
|
229
|
+
// replacement is published and their atomic consumer/removal cutover lands.
|
|
230
|
+
const demand = readBrowserProvisionDemand(folder, { abi: options.provisionCatalog?.profile.abi ?? "unselected", ...(options.buildArgs ? { buildArgs: options.buildArgs } : {}) });
|
|
231
|
+
const provisionPlan = options.provisionCatalog ? await planBrowserProvisionDemand(demand, options.provisionCatalog) : undefined;
|
|
232
|
+
process.stdout.write(formatBrowserProvisionPlan(demand, provisionPlan));
|
|
189
233
|
let setup;
|
|
190
234
|
try {
|
|
191
235
|
setup = await detectSetup(projectFiles(folder), { ...(options.serve ? { serve: options.serve } : {}), ...(options.directory ? { directory: options.directory } : {}) });
|
|
@@ -198,7 +242,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
198
242
|
if (!setup) {
|
|
199
243
|
throw new Error(`${folder} carries nothing to run: add a Dockerfile with a CMD, or a package.json with a dev script. An empty folder becomes a playground with \`browser-substrate init\`.`);
|
|
200
244
|
}
|
|
201
|
-
let archive = archiveFolder(folder);
|
|
245
|
+
let archive = archiveFolder(folder, options.cacheRoot ? { cacheRoot: options.cacheRoot } : {});
|
|
202
246
|
let preparation = { location: "none" };
|
|
203
247
|
if (setup.kind === "dockerfile") {
|
|
204
248
|
// A Dockerfile has two halves. The tab builds and runs a file it can take
|
|
@@ -224,6 +268,8 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
224
268
|
// the tab receives what it made.
|
|
225
269
|
const runSteps = parseContainerFile(dockerfile).stages.flatMap((stage) => stage.instructions.filter((instruction) => instruction.kind === "run").map((instruction) => instruction.line));
|
|
226
270
|
if (report.phases.build.verdict !== "native" || runSteps.length > 0) {
|
|
271
|
+
if (preparationBounded())
|
|
272
|
+
throw new Error("Bounded preparation refuses container RUN backends: their external/runtime tasks lack complete owned native-process cancellation/RSS coverage. No fallback was started.");
|
|
227
273
|
process.stdout.write(report.phases.build.verdict !== "native"
|
|
228
274
|
? ` the build half needs more than the tab has (${report.phases.build.blocking.map((b) => `line ${b.line}`).join(", ")}); building it here\n`
|
|
229
275
|
: ` the build half runs ${runSteps.length} RUN step${runSteps.length === 1 ? "" : "s"} (line${runSteps.length === 1 ? "" : "s"} ${runSteps.join(", ")}); building it here, where setup runs\n`);
|
|
@@ -237,6 +283,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
237
283
|
if (options.buildArgs)
|
|
238
284
|
throw new Error(`Build arguments (${Object.keys(options.buildArgs).join(", ")}) are read by Docker`);
|
|
239
285
|
built = await buildOnHost(folder, dockerfile, (text) => process.stdout.write(text), {
|
|
286
|
+
...(options.cacheRoot ? { cacheRoot: options.cacheRoot } : {}),
|
|
240
287
|
...(setup.target ? { target: setup.target } : {}),
|
|
241
288
|
...(setup.context ? { context: setup.context } : {}),
|
|
242
289
|
});
|
|
@@ -254,6 +301,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
254
301
|
...(externalBase(report) ? { base: externalBase(report) } : {}),
|
|
255
302
|
programs: tabLaneTable().programs,
|
|
256
303
|
...(options.buildArgs ? { buildArgs: options.buildArgs } : {}),
|
|
304
|
+
...(options.cacheRoot ? { cacheRoot: options.cacheRoot } : {}),
|
|
257
305
|
...(setup.target ? { target: setup.target } : {}),
|
|
258
306
|
...(setup.context ? { context: setup.context } : {}),
|
|
259
307
|
});
|
|
@@ -274,7 +322,9 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
274
322
|
let rolldown;
|
|
275
323
|
const tarballs = new Map();
|
|
276
324
|
if (options.dependencies !== false && setup.kind === "manifests" && setup.install) {
|
|
325
|
+
preparationPhase("plan");
|
|
277
326
|
const resolved = await resolveDependencyPlan(folder, setup.install, {
|
|
327
|
+
...(options.cacheRoot ? { cacheRoot: options.cacheRoot } : {}),
|
|
278
328
|
...(options.packagesDirectory ? { packagesDirectory: options.packagesDirectory } : {}),
|
|
279
329
|
onOutput: (text) => process.stdout.write(text),
|
|
280
330
|
// What the tab's copy of the project holds is the archive, not the
|
|
@@ -300,7 +350,8 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
300
350
|
if (options.packagesDirectory)
|
|
301
351
|
servePlanTarballsFromOrigin(plan, options.packagesDirectory);
|
|
302
352
|
// What the project's toolchain needs in the tab beyond its lockfile.
|
|
303
|
-
|
|
353
|
+
preparationPhase("generate");
|
|
354
|
+
const companions = await addCompanionPackages(plan, (text) => process.stdout.write(text), options.cacheRoot);
|
|
304
355
|
// The companions are part of what the tab links, so they are part of the
|
|
305
356
|
// plan's key: a workspace linked from an image without them, whose key
|
|
306
357
|
// was the same, kept its tree and never received them.
|
|
@@ -316,6 +367,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
316
367
|
// was the same, would keep its tree and never receive it.
|
|
317
368
|
const generated = await generatedForPlan(folder, plan, setup.install, {
|
|
318
369
|
imageName: name,
|
|
370
|
+
...(options.cacheRoot ? { cacheRoot: options.cacheRoot } : {}),
|
|
319
371
|
...(options.packagesDirectory ? { packagesDirectory: options.packagesDirectory } : {}),
|
|
320
372
|
onOutput: (text) => process.stdout.write(text),
|
|
321
373
|
});
|
|
@@ -332,12 +384,14 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
332
384
|
if (captured.packs.length > 0)
|
|
333
385
|
process.stdout.write(` captured: ${captured.packs.length} packs an earlier dry run asked for\n`);
|
|
334
386
|
if (options.build) {
|
|
387
|
+
preparationPhase("product build");
|
|
335
388
|
const built = await builtForPlan(folder, plan, setup.install, options.build, {
|
|
336
389
|
imageName: name,
|
|
337
390
|
sourcesDigest: archive.integrity,
|
|
338
391
|
holds: (path) => archive.files.has(path),
|
|
339
392
|
...(options.buildEnv ? { env: options.buildEnv } : {}),
|
|
340
393
|
...(options.buildWorld ? { world: options.buildWorld } : {}),
|
|
394
|
+
...(options.cacheRoot ? { cacheRoot: options.cacheRoot } : {}),
|
|
341
395
|
...(options.packagesDirectory ? { packagesDirectory: options.packagesDirectory } : {}),
|
|
342
396
|
onOutput: (text) => process.stdout.write(text),
|
|
343
397
|
});
|
|
@@ -357,7 +411,8 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
357
411
|
if (plan.entries.length > 0)
|
|
358
412
|
plan.key = `${plan.key}-${createHash("sha256").update(plan.entries.map((entry) => `${entry.path}\0${entry.content}`).join("\n")).digest("hex").slice(0, 12)}`;
|
|
359
413
|
// The project's own Rolldown binding, where its version is not the shell's.
|
|
360
|
-
|
|
414
|
+
preparationPhase("generate");
|
|
415
|
+
const binding = await rolldownBindingForPlan(plan, imageRolldownPath(name, plan.packages.find((entry) => entry.name === "rolldown")?.version ?? ""), (text) => process.stdout.write(text), options.cacheRoot);
|
|
361
416
|
if (binding) {
|
|
362
417
|
for (const [served, source] of binding.files)
|
|
363
418
|
tarballs.set(served, source);
|
|
@@ -367,11 +422,12 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
367
422
|
// Every registry package the plan names travels with the image, the
|
|
368
423
|
// companions included: the tab never reaches a registry, and refuses a
|
|
369
424
|
// plan that names one.
|
|
370
|
-
|
|
425
|
+
preparationPhase("package archives");
|
|
426
|
+
const carried = await carryRegistryTarballs(plan, name, options.cacheRoot ? { cacheRoot: options.cacheRoot } : {});
|
|
371
427
|
process.stdout.write(` carried: ${carried.files.size} registry packages, ${formatBytes(carried.bytes)}, ${carried.fetched} fetched here, ${carried.cached} from the cache\n`);
|
|
372
428
|
// What travels is each package's pack, its tree laid out here; the tab
|
|
373
429
|
// never reads a tarball (Article 1), so the tarballs stay on this machine.
|
|
374
|
-
const planPacks = await packPlan(plan, name, carried.files, tarballs, options.packagesDirectory ?? join(folder, PACKAGES_DIRECTORY));
|
|
430
|
+
const planPacks = await packPlan(plan, name, carried.files, tarballs, options.packagesDirectory ?? join(folder, PACKAGES_DIRECTORY), options.cacheRoot);
|
|
375
431
|
for (const [served, source] of planPacks.files)
|
|
376
432
|
tarballs.set(served, source);
|
|
377
433
|
// The packs are what a warm open links; another set of them is another plan.
|
|
@@ -379,9 +435,10 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
379
435
|
process.stdout.write(` packages as packs: ${planPacks.files.size} archives, ${formatBytes(planPacks.bytes)}\n`);
|
|
380
436
|
// Each package's browser build, made here under the key the tab
|
|
381
437
|
// computes for it. The tab links what is carried and builds the rest.
|
|
382
|
-
const moduleWorld = options.moduleWorld ? await buildWorldImage(options.moduleWorld, name) : undefined;
|
|
438
|
+
const moduleWorld = options.moduleWorld ? await buildWorldImage(options.moduleWorld, name, options.cacheRoot) : undefined;
|
|
383
439
|
let builtForLayers;
|
|
384
440
|
if (options.packs !== false) {
|
|
441
|
+
preparationPhase("bundles");
|
|
385
442
|
const built = await packsForPlan(folder, plan, setup.install, {
|
|
386
443
|
moduleSourcesKey: `${archive.integrity}|${moduleWorld?.world.archive.integrity ?? ""}`,
|
|
387
444
|
...(options.moduleWorld ? { moduleSourceTrees: [options.moduleWorld] } : {}),
|
|
@@ -392,6 +449,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
392
449
|
throw new Error(`No carried module pack for ${entry.name}@${entry.version}`);
|
|
393
450
|
return { file, artifact: pack.artifact };
|
|
394
451
|
}),
|
|
452
|
+
...(options.cacheRoot ? { cacheRoot: options.cacheRoot } : {}),
|
|
395
453
|
...(options.packagesDirectory ? { packagesDirectory: options.packagesDirectory } : {}),
|
|
396
454
|
// What the image's dry run captured last time is prepared too (ADR-0043).
|
|
397
455
|
...(prebundled.length > 0 || captured.packs.length > 0 ? { extra: [...prebundled, ...captured.packs] } : {}),
|
|
@@ -404,7 +462,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
404
462
|
const have = new Set(built.modules.map((body) => body.key));
|
|
405
463
|
let carried = 0;
|
|
406
464
|
for (const key of captured.prepared) {
|
|
407
|
-
const file = join(preparedBodiesDirectory(captured.cache), key);
|
|
465
|
+
const file = join(preparedBodiesDirectory(captured.cache, options.cacheRoot), key);
|
|
408
466
|
if (have.has(key) || !existsSync(file))
|
|
409
467
|
continue;
|
|
410
468
|
built.modules.push({ key, file, bytes: statSync(file).size });
|
|
@@ -439,6 +497,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
439
497
|
// What all of that puts in the origin's shared store, laid out as the
|
|
440
498
|
// store keeps it, in parts the tab appends whole (ADR-0045).
|
|
441
499
|
if (options.layers !== false) {
|
|
500
|
+
preparationPhase("layers");
|
|
442
501
|
const startedAt = Date.now();
|
|
443
502
|
// World packages enter the same content-addressed store before its links
|
|
444
503
|
// are placed. Leaving them out makes every cold tab expand them again.
|
|
@@ -450,7 +509,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
450
509
|
{ root: "/workspace/app", tree: treeUnit(archive.bytes, archive.blobs) },
|
|
451
510
|
...(moduleWorld ? [{ root: `/workspace/worlds/${moduleWorld.world.name}`, tree: treeUnit(moduleWorld.archive, moduleWorld.blobs) }] : []),
|
|
452
511
|
].flatMap(({ root, tree }) => tree ? [{ root, ...tree }] : []);
|
|
453
|
-
layers = await buildImageLayers(name, withTrees(layerUnits(layerPlan, layerFiles, builtForLayers, options.programs ?? [], options.programsDirectory), trees.map(({ unit }) => unit)), 0,
|
|
512
|
+
layers = await buildImageLayers(name, withTrees(layerUnits(layerPlan, layerFiles, builtForLayers, options.programs ?? [], options.programsDirectory), trees.map(({ unit }) => unit)), 0, preparationCacheDirectory("layer-parts", options.cacheRoot), {
|
|
454
513
|
plans: [{ root: "/workspace/app", plan }, ...(moduleWorld?.plan ? [{ root: `/workspace/worlds/${moduleWorld.world.name}`, plan: moduleWorld.plan }] : [])],
|
|
455
514
|
trees: trees.map(({ root, unit, integrity, mtimes }) => ({ root, unit: unit.root, integrity, mtimes })),
|
|
456
515
|
});
|
|
@@ -465,8 +524,8 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
465
524
|
// packs is another pre-bundle, which the tab would serve as this one.
|
|
466
525
|
const captureKey = readCaptured(options.capturedFile ?? join(folder, PACKAGES_DIRECTORY, "..", CAPTURED_FILE)).cache;
|
|
467
526
|
const packsDigest = packs ? createHash("sha256").update(JSON.stringify(packs.document)).digest("hex").slice(0, 16) : undefined;
|
|
468
|
-
const warmRecord = captureKey ? readWarmRecord(warmDirectory(captureKey)) : undefined;
|
|
469
|
-
const warm = captureKey && warmRecord && packsDigest && warmRecord.packs?.digest === packsDigest ? warmFiles(join(warmDirectory(captureKey), "files")) : undefined;
|
|
527
|
+
const warmRecord = captureKey ? readWarmRecord(warmDirectory(captureKey, options.cacheRoot)) : undefined;
|
|
528
|
+
const warm = captureKey && warmRecord && packsDigest && warmRecord.packs?.digest === packsDigest ? warmFiles(join(warmDirectory(captureKey, options.cacheRoot), "files")) : undefined;
|
|
470
529
|
for (const file of warm?.files ?? [])
|
|
471
530
|
archive.blobs.set(file.integrity, file.source);
|
|
472
531
|
if (warm)
|
|
@@ -501,7 +560,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
501
560
|
// The origin's Cache Storage the dry run left (an engine's artifacts, the
|
|
502
561
|
// service worker's copies of the project's servers' cacheable answers):
|
|
503
562
|
// a first open puts each back before anything asks for it.
|
|
504
|
-
const caches = captureKey ? capturedCaches(name, cachesDirectory(captureKey)) : undefined;
|
|
563
|
+
const caches = captureKey ? capturedCaches(name, cachesDirectory(captureKey, options.cacheRoot)) : undefined;
|
|
505
564
|
if (caches) {
|
|
506
565
|
const bytes = caches.entries.reduce((total, entry) => total + entry.bytes, 0);
|
|
507
566
|
manifest.caches = { url: `/substrate/${name}.caches.json`, entries: caches.entries.length, bytes };
|
|
@@ -510,7 +569,7 @@ export async function buildImageWith(folder, name, settings, project, options) {
|
|
|
510
569
|
const startup = readStartupRecord(folder);
|
|
511
570
|
let startupStreams;
|
|
512
571
|
if (startup) {
|
|
513
|
-
const streams = layers ? writeStartupStreams(name, startup.digests, layers.files) : undefined;
|
|
572
|
+
const streams = layers ? writeStartupStreams(name, startup.digests, layers.files, options.cacheRoot) : undefined;
|
|
514
573
|
startupStreams = streams?.files;
|
|
515
574
|
manifest.startup = { url: imageStartupPath(name), ranges: startup.ranges, ...(streams ? { streams: streams.streams } : {}) };
|
|
516
575
|
process.stdout.write(` startup: ${startup.ranges} image ranges a first boot read, from ${STARTUP_RECORD}${streams ? `, as ${streams.streams.length} streams of ${formatBytes(streams.streams.reduce((total, stream) => total + stream.bytes, 0))}` : ""}\n`);
|
|
@@ -754,7 +813,7 @@ function decodeBase64Content(value) {
|
|
|
754
813
|
* files, or the project's own in its packages directory, which the plan names
|
|
755
814
|
* at the origin's registry path.
|
|
756
815
|
*/
|
|
757
|
-
function packPlan(plan, imageName, carried, local, packagesDirectory) {
|
|
816
|
+
function packPlan(plan, imageName, carried, local, packagesDirectory, cacheRoot) {
|
|
758
817
|
const own = packagesDirectory ? readOriginRegistry(packagesDirectory) : undefined;
|
|
759
818
|
return preparePlanPacks(plan, imageName, (entry) => {
|
|
760
819
|
// A registry package carried here; a tarball the image names under its
|
|
@@ -764,7 +823,7 @@ function packPlan(plan, imageName, carried, local, packagesDirectory) {
|
|
|
764
823
|
return fromRegistry;
|
|
765
824
|
const file = entry.tarball.startsWith(`${REGISTRY_PATH}/`) ? own?.get(entry.name)?.get(entry.version)?.file : undefined;
|
|
766
825
|
return file && packagesDirectory ? join(packagesDirectory, file) : undefined;
|
|
767
|
-
});
|
|
826
|
+
}, cacheRoot);
|
|
768
827
|
}
|
|
769
828
|
/** Every file of the image and its World by the path it is served at, and where the folder holds it. */
|
|
770
829
|
export function imageBlobs(image) {
|
|
@@ -802,11 +861,11 @@ const STARTUP_STREAMS = 2;
|
|
|
802
861
|
* its served length and its served bytes. One request per helper instead of
|
|
803
862
|
* one per range: 830 requests took 0.85 s on localhost to deliver 43 MB.
|
|
804
863
|
*/
|
|
805
|
-
function writeStartupStreams(name, digests, layerFiles) {
|
|
864
|
+
function writeStartupStreams(name, digests, layerFiles, cacheRoot) {
|
|
806
865
|
const held = [...new Set(digests)].filter((digest) => layerFiles.has(`/substrate/${name}.layers/${digest}.bin`));
|
|
807
866
|
if (held.length === 0)
|
|
808
867
|
return undefined;
|
|
809
|
-
const directory =
|
|
868
|
+
const directory = preparationCacheDirectory("startup-streams", cacheRoot);
|
|
810
869
|
mkdirSync(directory, { recursive: true });
|
|
811
870
|
const streams = [];
|
|
812
871
|
const files = new Map();
|
|
@@ -872,7 +931,7 @@ export function imageFiles(image) {
|
|
|
872
931
|
* directory is the World's, outside any project; the World's own runtime
|
|
873
932
|
* runs from it in the tab.
|
|
874
933
|
*/
|
|
875
|
-
export async function buildWorldImage(directory, imageName) {
|
|
934
|
+
export async function buildWorldImage(directory, imageName, cacheRoot) {
|
|
876
935
|
const folder = resolve(directory);
|
|
877
936
|
const config = ["world.json"].find((name) => existsSync(join(folder, name)));
|
|
878
937
|
if (!config)
|
|
@@ -883,18 +942,18 @@ export async function buildWorldImage(directory, imageName) {
|
|
|
883
942
|
// What travels is the World's state, its data; a runtime's bookkeeping of
|
|
884
943
|
// one instance, its pids, logs, receipts, session keys and proxy, is that
|
|
885
944
|
// runtime's and stays where it ran.
|
|
886
|
-
const archive = archiveFolder(folder, { exclude: new Set([...EXCLUDED_NAMES, ...WORLD_RUNTIME_NAMES]) });
|
|
945
|
+
const archive = archiveFolder(folder, { ...(cacheRoot ? { cacheRoot } : {}), exclude: new Set([...EXCLUDED_NAMES, ...WORLD_RUNTIME_NAMES]) });
|
|
887
946
|
const packagesDirectory = join(folder, PACKAGES_DIRECTORY);
|
|
888
947
|
const tarballs = new Map();
|
|
889
948
|
let plan;
|
|
890
949
|
if (existsSync(join(folder, "package.json"))) {
|
|
891
|
-
const resolved = await resolveDependencyPlan(folder, installCommandOf(folder), { packagesDirectory, onOutput: (text) => process.stdout.write(text), holds: (path) => archive.files.has(path) });
|
|
950
|
+
const resolved = await resolveDependencyPlan(folder, installCommandOf(folder), { ...(cacheRoot ? { cacheRoot } : {}), packagesDirectory, onOutput: (text) => process.stdout.write(text), holds: (path) => archive.files.has(path) });
|
|
892
951
|
if (resolved) {
|
|
893
952
|
plan = resolved.plan;
|
|
894
953
|
servePlanTarballsFromOrigin(plan, packagesDirectory);
|
|
895
954
|
process.stdout.write(` world ${name}: ${plan.packages.length} packages at ${plan.links.length} paths, resolved with ${plan.resolver}${resolved.cached ? ", from the cache" : ` in ${resolved.durationMs} ms`}\n`);
|
|
896
|
-
const carried = await carryRegistryTarballs(plan, imageName);
|
|
897
|
-
for (const [served, source] of (await packPlan(plan, imageName, carried.files, tarballs, packagesDirectory)).files)
|
|
955
|
+
const carried = await carryRegistryTarballs(plan, imageName, cacheRoot ? { cacheRoot } : {});
|
|
956
|
+
for (const [served, source] of (await packPlan(plan, imageName, carried.files, tarballs, packagesDirectory, cacheRoot)).files)
|
|
898
957
|
tarballs.set(served, source);
|
|
899
958
|
plan.key = `${plan.key}-p${createHash("sha256").update(plan.packages.map((entry) => `${entry.pack?.artifact.digest ?? ""}:${entry.linuxX64}`).join("\n")).digest("hex").slice(0, 12)}`;
|
|
900
959
|
if (carried.files.size > 0)
|
|
@@ -924,7 +983,9 @@ export async function buildWorldImage(directory, imageName) {
|
|
|
924
983
|
/** What a command's arguments ask of an image. */
|
|
925
984
|
function imageOptions(args, packagesDirectory) {
|
|
926
985
|
return {
|
|
986
|
+
...(args.provisionCatalogFile ? { provisionCatalog: JSON.parse(readFileSync(resolve(args.provisionCatalogFile), "utf8")) } : {}),
|
|
927
987
|
...(packagesDirectory ? { packagesDirectory } : {}),
|
|
988
|
+
...(args.cacheRoot ? { cacheRoot: args.cacheRoot } : {}),
|
|
928
989
|
packs: args.packs,
|
|
929
990
|
...(args.world ? { moduleWorld: args.world } : {}),
|
|
930
991
|
...(Object.keys(args.buildArgs).length > 0 ? { buildArgs: args.buildArgs } : {}),
|
|
@@ -974,7 +1035,7 @@ async function dev(cwd, args) {
|
|
|
974
1035
|
// The app's image first: its build may run attached to the World and leave
|
|
975
1036
|
// the data it read in the World's directory, which the World's image carries.
|
|
976
1037
|
let image = await buildImageWith(cwd, args.name, args.settings, project, imageOptions(args, packages));
|
|
977
|
-
const world = args.world ? await buildWorldImage(args.world, args.name) : undefined;
|
|
1038
|
+
const world = args.world ? await buildWorldImage(args.world, args.name, args.cacheRoot) : undefined;
|
|
978
1039
|
const attach = (image) => {
|
|
979
1040
|
if (!world)
|
|
980
1041
|
return;
|
|
@@ -991,7 +1052,7 @@ async function dev(cwd, args) {
|
|
|
991
1052
|
// is written beside its packages and carried by every image built from it,
|
|
992
1053
|
// and a rebuilt image whose ranges did not change keeps it (ADR-0078).
|
|
993
1054
|
const startup = { path: imageStartupPath(image.manifest.name), file: join(cwd, STARTUP_RECORD) };
|
|
994
|
-
const server = await serve({ shell: SHELL_DIRECTORY, files, blobs: (pathname) => blobs.get(pathname), port: args.port, registry: world ? [packages, world.packagesDirectory] : packages, startup });
|
|
1055
|
+
const server = await serve({ shell: SHELL_DIRECTORY, manifest: image.manifest, files, blobs: (pathname) => blobs.get(pathname), port: args.port, registry: world ? [packages, world.packagesDirectory] : packages, startup });
|
|
995
1056
|
const summary = `${image.manifest.setup.kind === "dockerfile" ? "Dockerfile" : image.manifest.setup.source}, ${image.manifest.archive.entries} entries, ${formatBytes(image.manifest.archive.fileBytes)}${world ? `; World ${world.world.name} from ${args.world}, ${world.world.archive.entries} entries` : ""}`;
|
|
996
1057
|
const carried = image.manifest.registry
|
|
997
1058
|
? `\n ${PACKAGES_DIRECTORY}: this origin is the registry for ${[...image.manifest.registry.scopes, ...image.manifest.registry.names].join(", ")}`
|
|
@@ -1117,14 +1178,16 @@ async function build(cwd, args) {
|
|
|
1117
1178
|
throw new Error(`--build-arg ${Object.keys(args.buildArgs).join(", ")} applies to a Dockerfile whose build half runs here (a RUN step); this one's setup is ${image.manifest.setup.kind}, built in the tab with its ARG defaults`);
|
|
1118
1179
|
}
|
|
1119
1180
|
if (args.world) {
|
|
1120
|
-
const world = await buildWorldImage(args.world, args.name);
|
|
1181
|
+
const world = await buildWorldImage(args.world, args.name, args.cacheRoot);
|
|
1121
1182
|
image.manifest.world = world.world;
|
|
1122
1183
|
image.world = { archive: world.archive, blobs: world.blobs, ...(world.plan ? { plan: world.plan } : {}) };
|
|
1123
1184
|
for (const [served, source] of world.tarballs)
|
|
1124
1185
|
image.tarballs.set(served, source);
|
|
1125
1186
|
}
|
|
1126
1187
|
const out = resolve(cwd, args.out);
|
|
1188
|
+
preparationPhase("final copy");
|
|
1127
1189
|
const written = writeBuild({ shell: SHELL_DIRECTORY, files: imageFiles(image), blobs: imageBlobs(image), out, manifest: image.manifest });
|
|
1190
|
+
preparationCheckpoint();
|
|
1128
1191
|
process.stdout.write(`\n browser-substrate build\n\n ${out}\n ${written.files} files, ${formatBytes(written.bytes)}\n ${image.manifest.setup.playground
|
|
1129
1192
|
? `a playground: deploy on your page's origin and on ${image.manifest.settings.sandboxOrigin ?? "a sandbox. subdomain of it"}`
|
|
1130
1193
|
: "one origin, static; _headers carries the isolation headers"}\n\n`);
|
|
@@ -1157,34 +1220,34 @@ async function dryRunCommand(cwd, args) {
|
|
|
1157
1220
|
const index = originRegistryIndex(packages);
|
|
1158
1221
|
if (index)
|
|
1159
1222
|
image.manifest.registry = index;
|
|
1160
|
-
server = await serve({ shell: SHELL_DIRECTORY, files: new Map(imageFiles(image)), blobs: ((blobs) => (pathname) => blobs.get(pathname))(imageBlobs(image)), port: 0, registry: packages });
|
|
1223
|
+
server = await serve({ shell: SHELL_DIRECTORY, manifest: image.manifest, files: new Map(imageFiles(image)), blobs: ((blobs) => (pathname) => blobs.get(pathname))(imageBlobs(image)), port: 0, registry: packages });
|
|
1161
1224
|
url = server.url;
|
|
1162
1225
|
}
|
|
1163
1226
|
try {
|
|
1164
1227
|
say(`\n browser-substrate dry-run, round ${round}\n`);
|
|
1165
1228
|
const captureKey = captureKeyFor(file);
|
|
1166
|
-
const warmBefore = warmSignature(warmDirectory(captureKey));
|
|
1167
|
-
const cachesBefore = warmSignature(join(cachesDirectory(captureKey), "files"));
|
|
1229
|
+
const warmBefore = warmSignature(warmDirectory(captureKey, args.cacheRoot));
|
|
1230
|
+
const cachesBefore = warmSignature(join(cachesDirectory(captureKey, args.cacheRoot), "files"));
|
|
1168
1231
|
const steps = args.steps ? JSON.parse(readFileSync(args.steps, "utf8")) : undefined;
|
|
1169
|
-
const result = await dryRun(url, { settleMs: settle * 1000, onOutput: say, ...(steps ? { steps } : {}), preparedInto: preparedBodiesDirectory(captureKey), warmInto: warmDirectory(captureKey), cachesInto: cachesDirectory(captureKey) });
|
|
1232
|
+
const result = await dryRun(url, { settleMs: settle * 1000, onOutput: say, ...(steps ? { steps } : {}), preparedInto: preparedBodiesDirectory(captureKey, args.cacheRoot), warmInto: warmDirectory(captureKey, args.cacheRoot), cachesInto: cachesDirectory(captureKey, args.cacheRoot) });
|
|
1170
1233
|
const captured = readCaptured(file);
|
|
1171
1234
|
const { added: packsAdded, uncapturable } = capture(result.records, captured);
|
|
1172
1235
|
// The bodies the engine prepared in the tab are the image's next time:
|
|
1173
1236
|
// a first open compiles nothing the dry run saw it compile.
|
|
1174
|
-
const bodiesAdded = capturePrepared(result.prepared, captured, preparedBodiesDirectory(captureKey));
|
|
1237
|
+
const bodiesAdded = capturePrepared(result.prepared, captured, preparedBodiesDirectory(captureKey, args.cacheRoot));
|
|
1175
1238
|
// Caches captured for the first time are built into the next image. Later
|
|
1176
1239
|
// captures replace them on disk for whatever build comes next, without a
|
|
1177
1240
|
// round of their own: a cache may differ run to run and never settle.
|
|
1178
1241
|
// And caches the image did not carry (never captured, or assembled from
|
|
1179
1242
|
// packs an earlier round's capture changed): the next build carries them.
|
|
1180
|
-
const warmChanged = result.warm > 0 && (!result.warmCarried || warmBefore === EMPTY_WARM || captured.cache !== captureKey) && warmSignature(warmDirectory(captureKey)) !== EMPTY_WARM ? 1 : 0;
|
|
1243
|
+
const warmChanged = result.warm > 0 && (!result.warmCarried || warmBefore === EMPTY_WARM || captured.cache !== captureKey) && warmSignature(warmDirectory(captureKey, args.cacheRoot)) !== EMPTY_WARM ? 1 : 0;
|
|
1181
1244
|
if (result.warm > 0 || bodiesAdded > 0)
|
|
1182
1245
|
captured.cache = captureKey;
|
|
1183
1246
|
if (warmChanged)
|
|
1184
1247
|
say(` captured the project's caches anew (${result.warm} files)\n`);
|
|
1185
1248
|
// Cache Storage whose bodies are new to this machine is built into the
|
|
1186
1249
|
// next image; the same bodies again (their headers carry a time) are not.
|
|
1187
|
-
const cachesChanged = result.caches > 0 && warmSignature(join(cachesDirectory(captureKey), "files")) !== cachesBefore ? 1 : 0;
|
|
1250
|
+
const cachesChanged = result.caches > 0 && warmSignature(join(cachesDirectory(captureKey, args.cacheRoot), "files")) !== cachesBefore ? 1 : 0;
|
|
1188
1251
|
if (cachesChanged)
|
|
1189
1252
|
say(` captured the origin's Cache Storage anew (${result.caches} entries)\n`);
|
|
1190
1253
|
if (result.caches > 0)
|