@wp-playground/cli 3.0.15 → 3.0.17

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.
@@ -1,896 +0,0 @@
1
- import { logger as p, LogSeverity as I, errorLogPath as A } from "@php-wasm/logger";
2
- import { PHPResponse as E, consumeAPI as R, SupportedPHPVersions as X, printDebugDetails as Y, exposeAPI as G, exposeSyncAPI as K } from "@php-wasm/universal";
3
- import { resolveRemoteBlueprint as ee, resolveRuntimeConfiguration as te, compileBlueprintV1 as re, isBlueprintBundle as oe, runBlueprintV1Steps as ie } from "@wp-playground/blueprints";
4
- import { zipDirectory as se, RecommendedPHPVersion as _ } from "@wp-playground/common";
5
- import c, { mkdirSync as D } from "fs";
6
- import { Worker as H, MessageChannel as ne } from "worker_threads";
7
- import { p as V, a as ae, e as le } from "./mounts-D1_eXSTw.js";
8
- import pe from "express";
9
- import { FileLockManagerForNode as ue } from "@php-wasm/node";
10
- import q, { cpus as de } from "os";
11
- import { jspi as ce } from "wasm-feature-detect";
12
- import fe from "yargs";
13
- import f, { basename as he } from "path";
14
- import { NodeJsFilesystem as me, OverlayFilesystem as we, InMemoryFilesystem as ye, ZipFilesystem as be } from "@wp-playground/storage";
15
- import { EmscriptenDownloadMonitor as ge, ProgressTracker as Pe } from "@php-wasm/progress";
16
- import { resolveWordPressRelease as ve } from "@wp-playground/wordpress";
17
- import S from "fs-extra";
18
- import { startBridge as ke } from "@php-wasm/xdebug-bridge";
19
- import { dir as Se, setGracefulCleanup as xe } from "tmp-promise";
20
- import We from "ps-man";
21
- async function Le(e) {
22
- const r = pe(), t = await new Promise((i, n) => {
23
- const l = r.listen(e.port, () => {
24
- const a = l.address();
25
- a === null || typeof a == "string" ? n(new Error("Server address is not available")) : i(l);
26
- });
27
- });
28
- r.use("/", async (i, n) => {
29
- let l;
30
- try {
31
- l = await e.handleRequest({
32
- url: i.url,
33
- headers: $e(i),
34
- method: i.method,
35
- body: await Re(i)
36
- });
37
- } catch (a) {
38
- p.error(a), l = E.forHttpCode(500);
39
- }
40
- n.statusCode = l.httpStatusCode;
41
- for (const a in l.headers)
42
- n.setHeader(a, l.headers[a]);
43
- n.end(l.bytes);
44
- });
45
- const o = t.address().port;
46
- return await e.onBind(t, o);
47
- }
48
- const Re = async (e) => await new Promise((r) => {
49
- const t = [];
50
- e.on("data", (s) => {
51
- t.push(s);
52
- }), e.on("end", () => {
53
- r(new Uint8Array(Buffer.concat(t)));
54
- });
55
- }), $e = (e) => {
56
- const r = {};
57
- if (e.rawHeaders && e.rawHeaders.length)
58
- for (let t = 0; t < e.rawHeaders.length; t += 2)
59
- r[e.rawHeaders[t].toLowerCase()] = e.rawHeaders[t + 1];
60
- return r;
61
- };
62
- class Be {
63
- constructor(r) {
64
- this.workerLoads = [], this.addWorker(r);
65
- }
66
- addWorker(r) {
67
- this.workerLoads.push({
68
- worker: r,
69
- activeRequests: /* @__PURE__ */ new Set()
70
- });
71
- }
72
- async handleRequest(r) {
73
- let t = this.workerLoads[0];
74
- for (let o = 1; o < this.workerLoads.length; o++) {
75
- const i = this.workerLoads[o];
76
- i.activeRequests.size < t.activeRequests.size && (t = i);
77
- }
78
- const s = t.worker.request(r);
79
- return t.activeRequests.add(s), s.url = r.url, s.finally(() => {
80
- t.activeRequests.delete(s);
81
- });
82
- }
83
- }
84
- function Me(e) {
85
- return /^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e);
86
- }
87
- async function Ie({
88
- sourceString: e,
89
- blueprintMayReadAdjacentFiles: r
90
- }) {
91
- if (!e)
92
- return;
93
- if (e.startsWith("http://") || e.startsWith("https://"))
94
- return await ee(e);
95
- let t = f.resolve(process.cwd(), e);
96
- if (!c.existsSync(t))
97
- throw new Error(`Blueprint file does not exist: ${t}`);
98
- const s = c.statSync(t);
99
- if (s.isDirectory() && (t = f.join(t, "blueprint.json")), !s.isFile() && s.isSymbolicLink())
100
- throw new Error(
101
- `Blueprint path is neither a file nor a directory: ${t}`
102
- );
103
- const o = f.extname(t);
104
- switch (o) {
105
- case ".zip":
106
- return be.fromArrayBuffer(
107
- c.readFileSync(t).buffer
108
- );
109
- case ".json": {
110
- const i = c.readFileSync(t, "utf-8");
111
- try {
112
- JSON.parse(i);
113
- } catch {
114
- throw new Error(
115
- `Blueprint file at ${t} is not a valid JSON file`
116
- );
117
- }
118
- const n = f.dirname(t), l = new me(n);
119
- return new we([
120
- new ye({
121
- "blueprint.json": i
122
- }),
123
- /**
124
- * Wrap the NodeJS filesystem to prevent access to local files
125
- * unless the user explicitly allowed it.
126
- */
127
- {
128
- read(a) {
129
- if (!r)
130
- throw new Error(
131
- `Error: Blueprint contained tried to read a local file at path "${a}" (via a resource of type "bundled"). Playground restricts access to local resources by default as a security measure.
132
-
133
- You can allow this Blueprint to read files from the same parent directory by explicitly adding the --blueprint-may-read-adjacent-files option to your command.`
134
- );
135
- return l.read(a);
136
- }
137
- }
138
- ]);
139
- }
140
- default:
141
- throw new Error(
142
- `Unsupported blueprint file extension: ${o}. Only .zip and .json files are supported.`
143
- );
144
- }
145
- }
146
- class Ee {
147
- constructor(r, t) {
148
- this.lastProgressMessage = "", this.args = r, this.siteUrl = t.siteUrl, this.processIdSpaceLength = t.processIdSpaceLength, this.phpVersion = r.php;
149
- }
150
- getWorkerType() {
151
- return "v2";
152
- }
153
- async bootPrimaryWorker(r, t, s) {
154
- const o = R(r);
155
- await o.useFileLockManager(t);
156
- const i = {
157
- ...this.args,
158
- phpVersion: this.phpVersion,
159
- siteUrl: this.siteUrl,
160
- firstProcessId: 1,
161
- processIdSpaceLength: this.processIdSpaceLength,
162
- trace: this.args.debug || !1,
163
- blueprint: this.args.blueprint,
164
- nativeInternalDirPath: s
165
- };
166
- return await o.bootAsPrimaryWorker(i), o;
167
- }
168
- async bootSecondaryWorker({
169
- worker: r,
170
- fileLockManagerPort: t,
171
- firstProcessId: s,
172
- nativeInternalDirPath: o
173
- }) {
174
- const i = R(r.phpPort);
175
- await i.useFileLockManager(t);
176
- const n = {
177
- ...this.args,
178
- phpVersion: this.phpVersion,
179
- siteUrl: this.siteUrl,
180
- firstProcessId: s,
181
- processIdSpaceLength: this.processIdSpaceLength,
182
- trace: this.args.debug || !1,
183
- nativeInternalDirPath: o,
184
- mountsBeforeWpInstall: this.args["mount-before-install"] || [],
185
- mountsAfterWpInstall: this.args.mount || []
186
- };
187
- return await i.bootAsSecondaryWorker(n), i;
188
- }
189
- writeProgressUpdate(r, t, s) {
190
- t !== this.lastProgressMessage && (this.lastProgressMessage = t, r.isTTY ? (r.cursorTo(0), r.write(t), r.clearLine(1), s && r.write(`
191
- `)) : r.write(`${t}
192
- `));
193
- }
194
- }
195
- const T = f.join(q.homedir(), ".wordpress-playground");
196
- async function Te(e) {
197
- return await z(
198
- "https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/develop.zip",
199
- "sqlite.zip",
200
- e
201
- );
202
- }
203
- async function z(e, r, t) {
204
- const s = f.join(T, r);
205
- return S.existsSync(s) || (S.ensureDirSync(T), await Fe(e, s, t)), O(s);
206
- }
207
- async function Fe(e, r, t) {
208
- const o = (await t.monitorFetch(fetch(e))).body.getReader(), i = `${r}.partial`, n = S.createWriteStream(i);
209
- for (; ; ) {
210
- const { done: l, value: a } = await o.read();
211
- if (a && n.write(a), l)
212
- break;
213
- }
214
- n.close(), n.closed || await new Promise((l, a) => {
215
- n.on("finish", () => {
216
- S.renameSync(i, r), l(null);
217
- }), n.on("error", (d) => {
218
- S.removeSync(i), a(d);
219
- });
220
- });
221
- }
222
- function O(e, r) {
223
- return new File([S.readFileSync(e)], he(e));
224
- }
225
- class Ce {
226
- constructor(r, t) {
227
- this.lastProgressMessage = "", this.args = r, this.siteUrl = t.siteUrl, this.processIdSpaceLength = t.processIdSpaceLength;
228
- }
229
- getWorkerType() {
230
- return "v1";
231
- }
232
- async bootPrimaryWorker(r, t, s) {
233
- let o;
234
- const i = new ge();
235
- if (!this.args.skipWordPressSetup) {
236
- let y = !1;
237
- i.addEventListener("progress", ($) => {
238
- if (y)
239
- return;
240
- const { loaded: C, total: B } = $.detail, P = Math.floor(
241
- Math.min(100, 100 * C / B)
242
- );
243
- y = P === 100, this.writeProgressUpdate(
244
- process.stdout,
245
- `Downloading WordPress ${P}%...`,
246
- y
247
- );
248
- }), o = await ve(this.args.wp), p.log(
249
- `Resolved WordPress release URL: ${o?.releaseUrl}`
250
- );
251
- }
252
- const n = o && f.join(
253
- T,
254
- `prebuilt-wp-content-for-wp-${o.version}.zip`
255
- ), l = o ? c.existsSync(n) ? O(n) : await z(
256
- o.releaseUrl,
257
- `${o.version}.zip`,
258
- i
259
- ) : void 0;
260
- p.log("Fetching SQLite integration plugin...");
261
- const a = this.args.skipSqliteSetup ? void 0 : await Te(i), d = this.args.followSymlinks === !0, b = this.args.experimentalTrace === !0, W = this.args["mount-before-install"] || [], g = this.args.mount || [], m = R(r);
262
- await m.isConnected(), p.log("Booting WordPress...");
263
- const x = await te(
264
- this.getEffectiveBlueprint()
265
- );
266
- return await m.useFileLockManager(t), await m.bootAsPrimaryWorker({
267
- phpVersion: x.phpVersion,
268
- wpVersion: x.wpVersion,
269
- siteUrl: this.siteUrl,
270
- mountsBeforeWpInstall: W,
271
- mountsAfterWpInstall: g,
272
- wordPressZip: l && await l.arrayBuffer(),
273
- sqliteIntegrationPluginZip: await a?.arrayBuffer(),
274
- firstProcessId: 0,
275
- processIdSpaceLength: this.processIdSpaceLength,
276
- followSymlinks: d,
277
- trace: b,
278
- internalCookieStore: this.args.internalCookieStore,
279
- withXdebug: this.args.xdebug,
280
- nativeInternalDirPath: s
281
- }), o && !this.args["mount-before-install"] && !c.existsSync(n) && (p.log("Caching preinstalled WordPress for the next boot..."), c.writeFileSync(
282
- n,
283
- await se(m, "/wordpress")
284
- ), p.log("Cached!")), m;
285
- }
286
- async bootSecondaryWorker({
287
- worker: r,
288
- fileLockManagerPort: t,
289
- firstProcessId: s,
290
- nativeInternalDirPath: o
291
- }) {
292
- const i = R(
293
- r.phpPort
294
- );
295
- return await i.isConnected(), await i.useFileLockManager(t), await i.bootAsSecondaryWorker({
296
- phpVersion: this.phpVersion,
297
- siteUrl: this.siteUrl,
298
- mountsBeforeWpInstall: this.args["mount-before-install"] || [],
299
- mountsAfterWpInstall: this.args.mount || [],
300
- firstProcessId: s,
301
- processIdSpaceLength: this.processIdSpaceLength,
302
- followSymlinks: this.args.followSymlinks === !0,
303
- trace: this.args.experimentalTrace === !0,
304
- // @TODO: Move this to the request handler or else every worker
305
- // will have a separate cookie store.
306
- internalCookieStore: this.args.internalCookieStore,
307
- withXdebug: this.args.xdebug,
308
- nativeInternalDirPath: o
309
- }), await i.isReady(), i;
310
- }
311
- async compileInputBlueprint(r) {
312
- const t = this.getEffectiveBlueprint(), s = new Pe();
313
- let o = "", i = !1;
314
- return s.addEventListener("progress", (n) => {
315
- if (i)
316
- return;
317
- i = n.detail.progress === 100;
318
- const l = Math.floor(n.detail.progress);
319
- o = n.detail.caption || o || "Running the Blueprint";
320
- const a = `${o.trim()} – ${l}%`;
321
- this.writeProgressUpdate(
322
- process.stdout,
323
- a,
324
- i
325
- );
326
- }), await re(t, {
327
- progress: s,
328
- additionalSteps: r
329
- });
330
- }
331
- getEffectiveBlueprint() {
332
- const r = this.args.blueprint;
333
- return oe(r) ? r : {
334
- login: this.args.login,
335
- ...r || {},
336
- preferredVersions: {
337
- php: this.args.php ?? r?.preferredVersions?.php ?? _,
338
- wp: this.args.wp ?? r?.preferredVersions?.wp ?? "latest",
339
- ...r?.preferredVersions || {}
340
- }
341
- };
342
- }
343
- writeProgressUpdate(r, t, s) {
344
- this.args.verbosity !== F.Quiet.name && t !== this.lastProgressMessage && (this.lastProgressMessage = t, r.isTTY ? (r.cursorTo(0), r.write(t), r.clearLine(1), s && r.write(`
345
- `)) : r.write(`${t}
346
- `));
347
- }
348
- }
349
- async function Ue(e, r = !0) {
350
- const s = `${f.basename(process.argv0)}${e}${process.pid}-`, o = (await Se({
351
- prefix: s,
352
- /*
353
- * Allow recursive cleanup on process exit.
354
- *
355
- * NOTE: I worried about whether this cleanup would follow symlinks
356
- * and delete target files instead of unlinking the symlink,
357
- * but this feature uses rimraf under the hood which respects symlinks:
358
- * https://github.com/raszi/node-tmp/blob/3d2fe387f3f91b13830b9182faa02c3231ea8258/lib/tmp.js#L318
359
- */
360
- unsafeCleanup: !0
361
- })).path;
362
- return r && xe(), o;
363
- }
364
- async function Ae(e, r, t) {
365
- const o = (await De(
366
- e,
367
- r,
368
- t
369
- )).map(
370
- (i) => new Promise((n) => {
371
- c.rm(i, { recursive: !0 }, (l) => {
372
- l ? p.warn(
373
- `Failed to delete stale Playground temp dir: ${i}`,
374
- l
375
- ) : p.info(
376
- `Deleted stale Playground temp dir: ${i}`
377
- ), n();
378
- });
379
- })
380
- );
381
- await Promise.all(o);
382
- }
383
- async function De(e, r, t) {
384
- try {
385
- const s = c.readdirSync(t).map((i) => f.join(t, i)), o = [];
386
- for (const i of s)
387
- await He(
388
- e,
389
- r,
390
- i
391
- ) && o.push(i);
392
- return o;
393
- } catch (s) {
394
- return p.warn(`Failed to find stale Playground temp dirs: ${s}`), [];
395
- }
396
- }
397
- async function He(e, r, t) {
398
- if (!c.lstatSync(t).isDirectory())
399
- return !1;
400
- const o = f.basename(t);
401
- if (!o.includes(e))
402
- return !1;
403
- const i = o.match(
404
- new RegExp(`^(.+)${e}(\\d+)-`)
405
- );
406
- if (!i)
407
- return !1;
408
- const n = {
409
- executableName: i[1],
410
- pid: i[2]
411
- };
412
- if (await Ve(n.pid, n.executableName))
413
- return !1;
414
- const l = Date.now() - r;
415
- return c.statSync(t).mtime.getTime() < l;
416
- }
417
- async function Ve(e, r) {
418
- const [t] = await new Promise(
419
- (s, o) => {
420
- We.list(
421
- {
422
- pid: e,
423
- name: r,
424
- // Remove path from executable name in the results.
425
- clean: !0
426
- },
427
- (i, n) => {
428
- i ? o(i) : s(n);
429
- }
430
- );
431
- }
432
- );
433
- return !!t && t.pid === e && t.command === r;
434
- }
435
- const F = {
436
- Quiet: { name: "quiet", severity: I.Fatal },
437
- Normal: { name: "normal", severity: I.Info },
438
- Debug: { name: "debug", severity: I.Debug }
439
- };
440
- async function dt() {
441
- try {
442
- const e = fe(process.argv.slice(2)).usage("Usage: wp-playground <command> [options]").positional("command", {
443
- describe: "Command to run",
444
- choices: ["server", "run-blueprint", "build-snapshot"],
445
- demandOption: !0
446
- }).option("outfile", {
447
- describe: "When building, write to this output file.",
448
- type: "string",
449
- default: "wordpress.zip"
450
- }).option("port", {
451
- describe: "Port to listen on when serving.",
452
- type: "number",
453
- default: 9400
454
- }).option("site-url", {
455
- describe: "Site URL to use for WordPress. Defaults to http://127.0.0.1:{port}",
456
- type: "string"
457
- }).option("php", {
458
- describe: "PHP version to use.",
459
- type: "string",
460
- default: _,
461
- choices: X
462
- }).option("wp", {
463
- describe: "WordPress version to use.",
464
- type: "string",
465
- default: "latest"
466
- }).option("mount", {
467
- describe: "Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path",
468
- type: "array",
469
- string: !0,
470
- coerce: V
471
- }).option("mount-before-install", {
472
- describe: "Mount a directory to the PHP runtime before WordPress installation (can be used multiple times). Format: /host/path:/vfs/path",
473
- type: "array",
474
- string: !0,
475
- coerce: V
476
- }).option("mount-dir", {
477
- describe: 'Mount a directory to the PHP runtime (can be used multiple times). Format: "/host/path" "/vfs/path"',
478
- type: "array",
479
- nargs: 2,
480
- array: !0
481
- // coerce: parseMountDirArguments,
482
- }).option("mount-dir-before-install", {
483
- describe: 'Mount a directory before WordPress installation (can be used multiple times). Format: "/host/path" "/vfs/path"',
484
- type: "string",
485
- nargs: 2,
486
- array: !0,
487
- coerce: ae
488
- }).option("login", {
489
- describe: "Should log the user in",
490
- type: "boolean",
491
- default: !1
492
- }).option("blueprint", {
493
- describe: "Blueprint to execute.",
494
- type: "string"
495
- }).option("blueprint-may-read-adjacent-files", {
496
- describe: 'Consent flag: Allow "bundled" resources in a local blueprint to read files in the same directory as the blueprint file.',
497
- type: "boolean",
498
- default: !1
499
- }).option("skip-wordpress-setup", {
500
- describe: "Do not download, unzip, and install WordPress. Useful for mounting a pre-configured WordPress directory at /wordpress.",
501
- type: "boolean",
502
- default: !1
503
- }).option("skip-sqlite-setup", {
504
- describe: "Skip the SQLite integration plugin setup to allow the WordPress site to use MySQL.",
505
- type: "boolean",
506
- default: !1
507
- }).option("quiet", {
508
- describe: "Do not output logs and progress messages.",
509
- type: "boolean",
510
- default: !1,
511
- hidden: !0
512
- }).option("verbosity", {
513
- describe: "Output logs and progress messages.",
514
- type: "string",
515
- choices: Object.values(F).map(
516
- (o) => o.name
517
- ),
518
- default: "normal"
519
- }).option("debug", {
520
- describe: "Print PHP error log content if an error occurs during Playground boot.",
521
- type: "boolean",
522
- default: !1
523
- }).option("auto-mount", {
524
- describe: "Automatically mount the specified directory. If no path is provided, mount the current working directory. You can mount a WordPress directory, a plugin directory, a theme directory, a wp-content directory, or any directory containing PHP and HTML files.",
525
- type: "string"
526
- }).option("follow-symlinks", {
527
- describe: `Allow Playground to follow symlinks by automatically mounting symlinked directories and files encountered in mounted directories.
528
- Warning: Following symlinks will expose files outside mounted directories to Playground and could be a security risk.`,
529
- type: "boolean",
530
- default: !1
531
- }).option("experimental-trace", {
532
- describe: "Print detailed messages about system behavior to the console. Useful for troubleshooting.",
533
- type: "boolean",
534
- default: !1,
535
- // Hide this option because we want to replace with a more general log-level flag.
536
- hidden: !0
537
- }).option("internal-cookie-store", {
538
- describe: "Enable internal cookie handling. When enabled, Playground will manage cookies internally using an HttpCookieStore that persists cookies across requests. When disabled, cookies are handled externally (e.g., by a browser in Node.js environments).",
539
- type: "boolean",
540
- default: !1
541
- }).option("xdebug", {
542
- describe: "Enable Xdebug.",
543
- type: "boolean",
544
- default: !1
545
- }).option("experimental-devtools", {
546
- describe: "Enable experimental browser development tools.",
547
- type: "boolean",
548
- default: !1
549
- }).option("experimental-multi-worker", {
550
- describe: "Enable experimental multi-worker support which requires a /wordpress directory backed by a real filesystem. Pass a positive number to specify the number of workers to use. Otherwise, default to the number of CPUs minus 1.",
551
- type: "number",
552
- coerce: (o) => o ?? de().length - 1
553
- }).option("experimental-blueprints-v2-runner", {
554
- describe: "Use the experimental Blueprint V2 runner.",
555
- type: "boolean",
556
- default: !1,
557
- // Remove the "hidden" flag once Blueprint V2 is fully supported
558
- hidden: !0
559
- }).option("mode", {
560
- describe: "Blueprints v2 runner mode to use. This option is required when using the --experimental-blueprints-v2-runner flag with a blueprint.",
561
- type: "string",
562
- choices: ["create-new-site", "apply-to-existing-site"],
563
- // Remove the "hidden" flag once Blueprint V2 is fully supported
564
- hidden: !0
565
- }).showHelpOnFail(!1).strictOptions().check(async (o) => {
566
- if ((o["skip-wordpress-setup"] || o.skipWordpressSetup) && (o.skipWordPressSetup = !0), o.wp !== void 0 && !Me(o.wp))
567
- try {
568
- new URL(o.wp);
569
- } catch {
570
- throw new Error(
571
- 'Unrecognized WordPress version. Please use "latest", a URL, or a numeric version such as "6.2", "6.0.1", "6.2-beta1", or "6.2-RC1"'
572
- );
573
- }
574
- if (o["site-url"] !== void 0 && o["site-url"] !== "")
575
- try {
576
- new URL(o["site-url"]);
577
- } catch {
578
- throw new Error(
579
- `Invalid site-url "${o["site-url"]}". Please provide a valid URL (e.g., http://localhost:8080 or https://example.com)`
580
- );
581
- }
582
- if (o["auto-mount"]) {
583
- let i = !1;
584
- try {
585
- i = c.statSync(o["auto-mount"]).isDirectory();
586
- } catch {
587
- i = !1;
588
- }
589
- if (!i)
590
- throw new Error(
591
- `The specified --auto-mount path is not a directory: '${o["auto-mount"]}'.`
592
- );
593
- }
594
- if (o["experimental-multi-worker"] !== void 0 && o["experimental-multi-worker"] <= 1)
595
- throw new Error(
596
- "The --experimental-multi-worker flag must be a positive integer greater than 1."
597
- );
598
- if (o["experimental-blueprints-v2-runner"] === !0) {
599
- if (o.mode !== void 0) {
600
- if ("skip-wordpress-setup" in o)
601
- throw new Error(
602
- "The --skipWordPressSetup option cannot be used with the --mode option. Use one or the other."
603
- );
604
- if ("skip-sqlite-setup" in o)
605
- throw new Error(
606
- "The --skipSqliteSetup option is not supported in Blueprint V2 mode."
607
- );
608
- if (o["auto-mount"] !== void 0)
609
- throw new Error(
610
- "The --mode option cannot be used with --auto-mount because --auto-mount automatically sets the mode."
611
- );
612
- } else
613
- o["skip-wordpress-setup"] === !0 ? o.mode = "apply-to-existing-site" : o.mode = "create-new-site";
614
- const i = o.allow || [];
615
- o.followSymlinks === !0 && i.push("follow-symlinks"), o["blueprint-may-read-adjacent-files"] === !0 && i.push("read-local-fs"), o.allow = i;
616
- } else if (o.mode !== void 0)
617
- throw new Error(
618
- "The --mode option requires the --experimentalBlueprintsV2Runner flag."
619
- );
620
- return !0;
621
- });
622
- e.wrap(e.terminalWidth());
623
- const r = await e.argv, t = r._[0];
624
- ["run-blueprint", "server", "build-snapshot"].includes(t) || (e.showHelp(), process.exit(1));
625
- const s = {
626
- ...r,
627
- command: t,
628
- mount: [...r.mount || [], ...r["mount-dir"] || []],
629
- "mount-before-install": [
630
- ...r["mount-before-install"] || [],
631
- ...r["mount-dir-before-install"] || []
632
- ]
633
- };
634
- await je(s);
635
- } catch (e) {
636
- if (!(e instanceof Error))
637
- throw e;
638
- if (process.argv.includes("--debug"))
639
- Y(e);
640
- else {
641
- const t = [];
642
- let s = e;
643
- do
644
- t.push(s.message), s = s.cause;
645
- while (s instanceof Error);
646
- console.error(
647
- "\x1B[1m" + t.join(" caused by ") + "\x1B[0m"
648
- );
649
- }
650
- process.exit(1);
651
- }
652
- }
653
- async function je(e) {
654
- let r, t;
655
- const s = [];
656
- if (e.autoMount !== void 0 && (e.autoMount === "" && (e = { ...e, autoMount: process.cwd() }), e = le(e)), e.quiet && (e.verbosity = "quiet", delete e.quiet), e.debug ? e.verbosity = "debug" : e.verbosity === "debug" && (e.debug = !0), e.verbosity) {
657
- const a = Object.values(F).find(
658
- (d) => d.name === e.verbosity
659
- ).severity;
660
- p.setSeverityFilterLevel(a);
661
- }
662
- const o = q.platform() === "win32" ? (
663
- // @TODO: Enable fs-ext here when it works with Windows.
664
- void 0
665
- ) : await import("fs-ext").then((a) => a.flockSync).catch(() => {
666
- p.warn(
667
- "The fs-ext package is not installed. Internal file locking will not be integrated with host OS file locking."
668
- );
669
- }), i = new ue(o);
670
- let n = !1, l = !0;
671
- return p.log("Starting a PHP server..."), Le({
672
- port: e.port,
673
- onBind: async (a, d) => {
674
- const b = `http://127.0.0.1:${d}`, W = e["site-url"] || b, g = e.experimentalMultiWorker ?? 1, m = Math.floor(
675
- Number.MAX_SAFE_INTEGER / g
676
- ), x = "-playground-cli-site-", y = await Ue(
677
- x
678
- );
679
- p.debug(`Native temp dir for VFS root: ${y}`);
680
- const $ = f.dirname(y), B = 2 * 24 * 60 * 60 * 1e3;
681
- Ae(
682
- x,
683
- B,
684
- $
685
- );
686
- const P = f.join(y, "internal");
687
- D(P);
688
- const N = [
689
- "wordpress",
690
- // Note: These dirs are from Emscripten's "default dirs" list:
691
- // https://github.com/emscripten-core/emscripten/blob/f431ec220e472e1f8d3db6b52fe23fb377facf30/src/lib/libfs.js#L1400-L1402
692
- //
693
- // Any Playground process with multiple workers may assume
694
- // these are part of a shared filesystem, so let's recognize
695
- // them explicitly here.
696
- "tmp",
697
- "home"
698
- ];
699
- for (const u of N) {
700
- const w = (h) => h.vfsPath === `/${u}`;
701
- if (!(e["mount-before-install"]?.some(w) || e.mount?.some(w))) {
702
- const h = f.join(
703
- y,
704
- u
705
- );
706
- D(h), e["mount-before-install"] === void 0 && (e["mount-before-install"] = []), e["mount-before-install"].unshift({
707
- vfsPath: `/${u}`,
708
- hostPath: h
709
- });
710
- }
711
- }
712
- if (e["mount-before-install"])
713
- for (const u of e["mount-before-install"])
714
- p.debug(
715
- `Mount before WP install: ${u.vfsPath} -> ${u.hostPath}`
716
- );
717
- if (e.mount)
718
- for (const u of e.mount)
719
- p.debug(
720
- `Mount after WP install: ${u.vfsPath} -> ${u.hostPath}`
721
- );
722
- let v;
723
- e["experimental-blueprints-v2-runner"] ? v = new Ee(e, {
724
- siteUrl: W,
725
- processIdSpaceLength: m
726
- }) : (v = new Ce(e, {
727
- siteUrl: W,
728
- processIdSpaceLength: m
729
- }), typeof e.blueprint == "string" && (e.blueprint = await Ie({
730
- sourceString: e.blueprint,
731
- blueprintMayReadAdjacentFiles: e["blueprint-may-read-adjacent-files"] === !0
732
- })));
733
- const Z = _e(
734
- g,
735
- v.getWorkerType(),
736
- ({ exitCode: u, isMain: w, workerIndex: L }) => {
737
- u !== 0 && (p.error(
738
- `Worker ${L} exited with code ${u}
739
- `
740
- ), w && e.exitOnPrimaryWorkerCrash && process.exit(1));
741
- }
742
- );
743
- p.log(`Setting up WordPress ${e.wp}`);
744
- try {
745
- const [u, ...w] = await Z, L = await j(
746
- i
747
- );
748
- if (t = await v.bootPrimaryWorker(
749
- u.phpPort,
750
- L,
751
- P
752
- ), s.push({
753
- playground: t,
754
- worker: u.worker
755
- }), await t.isReady(), n = !0, p.log("Booted!"), r = new Be(t), !e["experimental-blueprints-v2-runner"]) {
756
- const h = await v.compileInputBlueprint(
757
- e["additional-blueprint-steps"] || []
758
- );
759
- h && (p.log("Running the Blueprint..."), await ie(
760
- h,
761
- t
762
- ), p.log("Finished running the blueprint"));
763
- }
764
- if (e.command === "build-snapshot" ? (await ze(t, e.outfile), p.log(`WordPress exported to ${e.outfile}`), process.exit(0)) : e.command === "run-blueprint" && (p.log("Blueprint executed"), process.exit(0)), e.experimentalMultiWorker && e.experimentalMultiWorker > 1) {
765
- p.log("Preparing additional workers...");
766
- const h = m;
767
- await Promise.all(
768
- w.map(async (k, M) => {
769
- const J = h + M * m, Q = await j(i), U = await v.bootSecondaryWorker({
770
- worker: k,
771
- fileLockManagerPort: Q,
772
- firstProcessId: J,
773
- nativeInternalDirPath: P
774
- });
775
- s.push({
776
- playground: U,
777
- worker: k.worker
778
- }), r.addWorker(U);
779
- })
780
- );
781
- }
782
- return p.log(
783
- `WordPress is running on ${b} with ${g} worker(s)`
784
- ), e.experimentalDevtools && e.xdebug && (await ke({
785
- phpInstance: t,
786
- phpRoot: "/wordpress"
787
- })).start(), {
788
- playground: t,
789
- server: a,
790
- serverUrl: b,
791
- [Symbol.asyncDispose]: async function() {
792
- await Promise.all(
793
- s.map(
794
- async ({ playground: k, worker: M }) => {
795
- await k.dispose(), await M.terminate();
796
- }
797
- )
798
- ), await new Promise((k) => a.close(k));
799
- },
800
- workerThreadCount: g
801
- };
802
- } catch (u) {
803
- if (!e.debug)
804
- throw u;
805
- let w = "";
806
- throw await t?.fileExists(A) && (w = await t.readFileAsText(A)), new Error(w, { cause: u });
807
- }
808
- },
809
- async handleRequest(a) {
810
- if (!n)
811
- return E.forHttpCode(
812
- 502,
813
- "WordPress is not ready yet"
814
- );
815
- if (l) {
816
- l = !1;
817
- const d = {
818
- "Content-Type": ["text/plain"],
819
- "Content-Length": ["0"],
820
- Location: [a.url]
821
- };
822
- return a.headers?.cookie?.includes(
823
- "playground_auto_login_already_happened"
824
- ) && (d["Set-Cookie"] = [
825
- "playground_auto_login_already_happened=1; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/"
826
- ]), new E(302, d, new Uint8Array());
827
- }
828
- return await r.handleRequest(a);
829
- }
830
- });
831
- }
832
- async function _e(e, r, t) {
833
- const s = [];
834
- for (let o = 0; o < e; o++) {
835
- const i = await qe(r), n = (l) => {
836
- t({
837
- exitCode: l,
838
- isMain: o === 0,
839
- workerIndex: o
840
- });
841
- };
842
- s.push(
843
- new Promise(
844
- (l, a) => {
845
- i.once("message", function(d) {
846
- d.command === "worker-script-initialized" && l({ worker: i, phpPort: d.phpPort });
847
- }), i.once("error", function(d) {
848
- console.error(d);
849
- const b = new Error(
850
- `Worker failed to load worker. ${d.message ? `Original error: ${d.message}` : ""}`
851
- );
852
- a(b);
853
- }), i.once("exit", n);
854
- }
855
- )
856
- );
857
- }
858
- return Promise.all(s);
859
- }
860
- async function qe(e) {
861
- return e === "v1" ? new H(new URL("./worker-thread-v1.js", import.meta.url)) : new H(new URL("./worker-thread-v2.js", import.meta.url));
862
- }
863
- async function j(e) {
864
- const { port1: r, port2: t } = new ne();
865
- return await ce() ? G(e, null, r) : await K(e, r), t;
866
- }
867
- async function ze(e, r) {
868
- await e.run({
869
- code: `<?php
870
- $zip = new ZipArchive();
871
- if(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
872
- throw new Exception('Failed to create ZIP');
873
- }
874
- $files = new RecursiveIteratorIterator(
875
- new RecursiveDirectoryIterator('/wordpress')
876
- );
877
- foreach ($files as $file) {
878
- echo $file . PHP_EOL;
879
- if (!$file->isFile()) {
880
- continue;
881
- }
882
- $zip->addFile($file->getPathname(), $file->getPathname());
883
- }
884
- $zip->close();
885
-
886
- `
887
- });
888
- const t = await e.readFileAsBuffer("/tmp/build.zip");
889
- c.writeFileSync(r, t);
890
- }
891
- export {
892
- F as L,
893
- dt as p,
894
- je as r
895
- };
896
- //# sourceMappingURL=run-cli-C0WqHEVM.js.map