Skip to content

Commit fb92acd

Browse files
committed
fix: reuse Playground direct input mounts
1 parent 2bf574c commit fb92acd

3 files changed

Lines changed: 101 additions & 3 deletions

File tree

‎packages/runtime-playground/src/mount-materialization.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,25 @@ export interface MountMaterializationResult {
3434

3535
export type StagedInputMaterializationResult = MountMaterializationResult
3636

37+
export function directMountedPlaygroundStagedInputs(mounts: MountSpec[]): StagedInputMaterializationResult {
38+
return {
39+
materialized: 0,
40+
deleted: 0,
41+
skipped: 0,
42+
phaseResult: materializationPhaseResult({
43+
phase: "playground-staged-input-materialization",
44+
status: mounts.length > 0 ? "completed" : "skipped",
45+
metadata: {
46+
materialized: 0,
47+
deleted: 0,
48+
skipped: 0,
49+
mounts: mounts.length,
50+
transport: "direct-nodefs-mount",
51+
},
52+
}),
53+
}
54+
}
55+
3756
export interface ReadonlyMountStaging {
3857
mounts: MountSpec[]
3958
diagnostics: MaterializationDiagnostic[]

‎packages/runtime-playground/src/playground-runtime.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { PlaygroundCommandCrashError, assertPlaygroundResponseOk, errorMessage,
2121
import { startPlaygroundCliServer, type PlaygroundCliModule } from "./playground-cli-runner.js"
2222
import type { PlaygroundCliServer } from "./preview-server.js"
2323
import { collectPlaygroundArtifacts } from "./runtime-artifact-helpers.js"
24-
import { materializePlaygroundMountsFromVfs, materializePlaygroundStagedInputs } from "./mount-materialization.js"
24+
import { directMountedPlaygroundStagedInputs, materializePlaygroundMountsFromVfs } from "./mount-materialization.js"
2525
import { runAbilityCommand, runAdminActionInventoryCommand, runBenchCommand, runCacheChurnObservationCommand, runCorePhpunitCommand, runHttpRequestCommand, runPageLoadCommand, runPhpCommand, runPhpunitCommand, runPluginCheckCommand, runPluginSetupCommand, runPluginStateCommand, runRestPerformanceObservationCommand, runRestRequestCommand, runRuntimeDiscoveryCommand, runRuntimeInventoryCommand, runServerPageLoadCommand, runThemeCheckCommand, runThemeSetupCommand, runWordPressExecutionActionCommand } from "./wordpress-command-runners.js"
2626
import { PlaygroundSnapshotRestoreError, contentDigest, mountsFromSnapshot, runtimeSnapshotExportPayload, runtimeSnapshotExportPhp, runtimeSnapshotPayload, runtimeSnapshotRestorePhp, runtimeSpecFromSnapshot, snapshotDigest, type RuntimeSnapshotArtifact, type RuntimeSnapshotExportOptions } from "./runtime-snapshot.js"
2727
import { createRuntimeWpCliBridge, type RuntimeWpCliBridge } from "./runtime-wp-cli-bridge.js"
@@ -337,8 +337,9 @@ class PlaygroundRuntime implements Runtime {
337337
return undefined
338338
}
339339

340-
const materialization = await materializePlaygroundStagedInputs(await this.bootPlayground(), mounts)
341-
this.recordEvent("runtime.staged-inputs.materialized", { ...materialization, source: "host-to-vfs" })
340+
await this.bootPlayground()
341+
const materialization = directMountedPlaygroundStagedInputs(mounts)
342+
this.recordEvent("runtime.staged-inputs.materialized", { ...materialization, source: "direct-nodefs-mount" })
342343
return materialization
343344
}
344345

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import assert from "node:assert/strict"
2+
import { access, mkdir, readFile, writeFile } from "node:fs/promises"
3+
import { join } from "node:path"
4+
5+
import { createRuntime } from "../packages/runtime-core/src/index.js"
6+
import { createPlaygroundRuntimeBackend } from "../packages/runtime-playground/src/index.js"
7+
import type { PlaygroundCliModule } from "../packages/runtime-playground/src/playground-cli-runner.js"
8+
import { withTempDir } from "../scripts/test-kit.js"
9+
10+
await withTempDir("wp-codebox-direct-mount-materialization-", async (root) => {
11+
const source = join(root, "source")
12+
const wordpressDirectory = join(root, "wordpress")
13+
await mkdir(source)
14+
await mkdir(wordpressDirectory)
15+
await writeFile(join(source, "fixture.txt"), "direct mount fixture")
16+
17+
let directWrites = 0
18+
let mountedHostPath = ""
19+
const cliModule: PlaygroundCliModule = {
20+
async runCLI(options) {
21+
const mount = options.mount.find((candidate) => candidate.vfsPath === "/workspace/fixture")
22+
assert.ok(mount)
23+
mountedHostPath = mount.hostPath
24+
assert.equal(await readFile(join(mount.hostPath, "fixture.txt"), "utf8"), "direct mount fixture")
25+
return {
26+
serverUrl: "http://127.0.0.1:9404",
27+
playground: {
28+
async run() { return { text: "" } },
29+
async writeFile() { directWrites++ },
30+
},
31+
async [Symbol.asyncDispose]() {},
32+
}
33+
},
34+
}
35+
36+
const runtime = await createRuntime({
37+
backend: "wordpress-playground",
38+
artifactsDirectory: join(root, "artifacts"),
39+
environment: {
40+
kind: "wordpress",
41+
name: "direct-mount-materialization",
42+
version: "mounted-wordpress-source",
43+
phpVersion: "8.4",
44+
wordpressInstallMode: "do-not-attempt-installing",
45+
assets: { wordpressDirectory },
46+
blueprint: {},
47+
},
48+
policy: {
49+
network: "deny",
50+
filesystem: "readonly-mounts",
51+
commands: [],
52+
secrets: "none",
53+
approvals: "never",
54+
},
55+
}, createPlaygroundRuntimeBackend({ cliModule }))
56+
57+
const mount = { type: "directory" as const, source, target: "/workspace/fixture", mode: "readonly" as const }
58+
try {
59+
await runtime.mount(mount)
60+
const result = await runtime.materializeStagedInputs?.([mount]) as { phaseResult?: { status?: string; metadata?: Record<string, unknown> } }
61+
assert.equal(directWrites, 0, "mounted files are not rewritten through the Playground API")
62+
assert.notEqual(mountedHostPath, source, "readonly isolation still uses a private staged source")
63+
assert.equal(result.phaseResult?.status, "completed")
64+
assert.deepEqual(result.phaseResult?.metadata, {
65+
materialized: 0,
66+
deleted: 0,
67+
skipped: 0,
68+
mounts: 1,
69+
transport: "direct-nodefs-mount",
70+
})
71+
} finally {
72+
await runtime.destroy()
73+
}
74+
75+
await assert.rejects(access(mountedHostPath), /ENOENT/, "readonly staging is removed with the runtime")
76+
})
77+
78+
console.log("Playground staged inputs use direct NODEFS mounts")

0 commit comments

Comments
 (0)