@wp-playground/cli 3.0.15 → 3.0.16
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/cli.cjs +1 -1
- package/cli.cjs.map +1 -1
- package/cli.js +1 -1
- package/cli.js.map +1 -1
- package/index.cjs +1 -1
- package/index.js +1 -1
- package/mounts-BJFrPHGW.cjs.map +1 -1
- package/mounts-D1_eXSTw.js.map +1 -1
- package/package.json +15 -13
- package/run-cli-B59N7dQd.js +1325 -0
- package/run-cli-B59N7dQd.js.map +1 -0
- package/run-cli-BKsGTaC9.cjs +46 -0
- package/run-cli-BKsGTaC9.cjs.map +1 -0
- package/run-cli.d.ts +4 -1
- package/worker-thread-v1.cjs.map +1 -1
- package/worker-thread-v1.js.map +1 -1
- package/worker-thread-v2.cjs.map +1 -1
- package/worker-thread-v2.js.map +1 -1
- package/xdebug-path-mappings.d.ts +90 -0
- package/run-cli-Bb8U_jz3.cjs +0 -27
- package/run-cli-Bb8U_jz3.cjs.map +0 -1
- package/run-cli-C0WqHEVM.js +0 -896
- package/run-cli-C0WqHEVM.js.map +0 -1
|
@@ -0,0 +1,1325 @@
|
|
|
1
|
+
import { logger as m, LogSeverity as M, errorLogPath as _ } from "@php-wasm/logger";
|
|
2
|
+
import { PHPResponse as U, consumeAPI as j, SupportedPHPVersions as ce, printDebugDetails as pe, exposeAPI as ue, exposeSyncAPI as de } from "@php-wasm/universal";
|
|
3
|
+
import { resolveRemoteBlueprint as fe, resolveRuntimeConfiguration as me, compileBlueprintV1 as he, isBlueprintBundle as ge, runBlueprintV1Steps as ye } from "@wp-playground/blueprints";
|
|
4
|
+
import { zipDirectory as we, RecommendedPHPVersion as Z } from "@wp-playground/common";
|
|
5
|
+
import u, { mkdirSync as H } from "fs";
|
|
6
|
+
import { Worker as q, MessageChannel as be } from "worker_threads";
|
|
7
|
+
import { p as z, a as ve, e as Pe } from "./mounts-D1_eXSTw.js";
|
|
8
|
+
import Se from "express";
|
|
9
|
+
import { FileLockManagerForNode as ke } from "@php-wasm/node";
|
|
10
|
+
import Y, { cpus as xe } from "os";
|
|
11
|
+
import { jspi as Ee } from "wasm-feature-detect";
|
|
12
|
+
import Ie from "yargs";
|
|
13
|
+
import g, { basename as Ce } from "path";
|
|
14
|
+
import { NodeJsFilesystem as Le, OverlayFilesystem as We, InMemoryFilesystem as $e, ZipFilesystem as Te } from "@wp-playground/storage";
|
|
15
|
+
import { EmscriptenDownloadMonitor as Be, ProgressTracker as je } from "@php-wasm/progress";
|
|
16
|
+
import { resolveWordPressRelease as Fe } from "@wp-playground/wordpress";
|
|
17
|
+
import T from "fs-extra";
|
|
18
|
+
import { startBridge as Re } from "@php-wasm/xdebug-bridge";
|
|
19
|
+
import { dir as Me, setGracefulCleanup as De } from "tmp-promise";
|
|
20
|
+
import Ae from "ps-man";
|
|
21
|
+
import { XMLParser as K, XMLBuilder as Q } from "fast-xml-parser";
|
|
22
|
+
import v from "jsonc-parser";
|
|
23
|
+
async function Ue(e) {
|
|
24
|
+
const o = Se(), t = await new Promise((n, s) => {
|
|
25
|
+
const l = o.listen(e.port, () => {
|
|
26
|
+
const a = l.address();
|
|
27
|
+
a === null || typeof a == "string" ? s(new Error("Server address is not available")) : n(l);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
o.use("/", async (n, s) => {
|
|
31
|
+
let l;
|
|
32
|
+
try {
|
|
33
|
+
l = await e.handleRequest({
|
|
34
|
+
url: n.url,
|
|
35
|
+
headers: Ve(n),
|
|
36
|
+
method: n.method,
|
|
37
|
+
body: await Ne(n)
|
|
38
|
+
});
|
|
39
|
+
} catch (a) {
|
|
40
|
+
m.error(a), l = U.forHttpCode(500);
|
|
41
|
+
}
|
|
42
|
+
s.statusCode = l.httpStatusCode;
|
|
43
|
+
for (const a in l.headers)
|
|
44
|
+
s.setHeader(a, l.headers[a]);
|
|
45
|
+
s.end(l.bytes);
|
|
46
|
+
});
|
|
47
|
+
const r = t.address().port;
|
|
48
|
+
return await e.onBind(t, r);
|
|
49
|
+
}
|
|
50
|
+
const Ne = async (e) => await new Promise((o) => {
|
|
51
|
+
const t = [];
|
|
52
|
+
e.on("data", (i) => {
|
|
53
|
+
t.push(i);
|
|
54
|
+
}), e.on("end", () => {
|
|
55
|
+
o(new Uint8Array(Buffer.concat(t)));
|
|
56
|
+
});
|
|
57
|
+
}), Ve = (e) => {
|
|
58
|
+
const o = {};
|
|
59
|
+
if (e.rawHeaders && e.rawHeaders.length)
|
|
60
|
+
for (let t = 0; t < e.rawHeaders.length; t += 2)
|
|
61
|
+
o[e.rawHeaders[t].toLowerCase()] = e.rawHeaders[t + 1];
|
|
62
|
+
return o;
|
|
63
|
+
};
|
|
64
|
+
class Oe {
|
|
65
|
+
constructor(o) {
|
|
66
|
+
this.workerLoads = [], this.addWorker(o);
|
|
67
|
+
}
|
|
68
|
+
addWorker(o) {
|
|
69
|
+
this.workerLoads.push({
|
|
70
|
+
worker: o,
|
|
71
|
+
activeRequests: /* @__PURE__ */ new Set()
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async handleRequest(o) {
|
|
75
|
+
let t = this.workerLoads[0];
|
|
76
|
+
for (let r = 1; r < this.workerLoads.length; r++) {
|
|
77
|
+
const n = this.workerLoads[r];
|
|
78
|
+
n.activeRequests.size < t.activeRequests.size && (t = n);
|
|
79
|
+
}
|
|
80
|
+
const i = t.worker.request(o);
|
|
81
|
+
return t.activeRequests.add(i), i.url = o.url, i.finally(() => {
|
|
82
|
+
t.activeRequests.delete(i);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function _e(e) {
|
|
87
|
+
return /^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e);
|
|
88
|
+
}
|
|
89
|
+
async function He({
|
|
90
|
+
sourceString: e,
|
|
91
|
+
blueprintMayReadAdjacentFiles: o
|
|
92
|
+
}) {
|
|
93
|
+
if (!e)
|
|
94
|
+
return;
|
|
95
|
+
if (e.startsWith("http://") || e.startsWith("https://"))
|
|
96
|
+
return await fe(e);
|
|
97
|
+
let t = g.resolve(process.cwd(), e);
|
|
98
|
+
if (!u.existsSync(t))
|
|
99
|
+
throw new Error(`Blueprint file does not exist: ${t}`);
|
|
100
|
+
const i = u.statSync(t);
|
|
101
|
+
if (i.isDirectory() && (t = g.join(t, "blueprint.json")), !i.isFile() && i.isSymbolicLink())
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Blueprint path is neither a file nor a directory: ${t}`
|
|
104
|
+
);
|
|
105
|
+
const r = g.extname(t);
|
|
106
|
+
switch (r) {
|
|
107
|
+
case ".zip":
|
|
108
|
+
return Te.fromArrayBuffer(
|
|
109
|
+
u.readFileSync(t).buffer
|
|
110
|
+
);
|
|
111
|
+
case ".json": {
|
|
112
|
+
const n = u.readFileSync(t, "utf-8");
|
|
113
|
+
try {
|
|
114
|
+
JSON.parse(n);
|
|
115
|
+
} catch {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Blueprint file at ${t} is not a valid JSON file`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
const s = g.dirname(t), l = new Le(s);
|
|
121
|
+
return new We([
|
|
122
|
+
new $e({
|
|
123
|
+
"blueprint.json": n
|
|
124
|
+
}),
|
|
125
|
+
/**
|
|
126
|
+
* Wrap the NodeJS filesystem to prevent access to local files
|
|
127
|
+
* unless the user explicitly allowed it.
|
|
128
|
+
*/
|
|
129
|
+
{
|
|
130
|
+
read(a) {
|
|
131
|
+
if (!o)
|
|
132
|
+
throw new Error(
|
|
133
|
+
`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.
|
|
134
|
+
|
|
135
|
+
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.`
|
|
136
|
+
);
|
|
137
|
+
return l.read(a);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
]);
|
|
141
|
+
}
|
|
142
|
+
default:
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Unsupported blueprint file extension: ${r}. Only .zip and .json files are supported.`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
class qe {
|
|
149
|
+
constructor(o, t) {
|
|
150
|
+
this.lastProgressMessage = "", this.args = o, this.siteUrl = t.siteUrl, this.processIdSpaceLength = t.processIdSpaceLength, this.phpVersion = o.php;
|
|
151
|
+
}
|
|
152
|
+
getWorkerType() {
|
|
153
|
+
return "v2";
|
|
154
|
+
}
|
|
155
|
+
async bootPrimaryWorker(o, t, i) {
|
|
156
|
+
const r = j(o);
|
|
157
|
+
await r.useFileLockManager(t);
|
|
158
|
+
const n = {
|
|
159
|
+
...this.args,
|
|
160
|
+
phpVersion: this.phpVersion,
|
|
161
|
+
siteUrl: this.siteUrl,
|
|
162
|
+
firstProcessId: 1,
|
|
163
|
+
processIdSpaceLength: this.processIdSpaceLength,
|
|
164
|
+
trace: this.args.debug || !1,
|
|
165
|
+
blueprint: this.args.blueprint,
|
|
166
|
+
withXdebug: !!this.args.xdebug,
|
|
167
|
+
xdebug: typeof this.args.xdebug == "object" ? this.args.xdebug : void 0,
|
|
168
|
+
nativeInternalDirPath: i
|
|
169
|
+
};
|
|
170
|
+
return await r.bootAsPrimaryWorker(n), r;
|
|
171
|
+
}
|
|
172
|
+
async bootSecondaryWorker({
|
|
173
|
+
worker: o,
|
|
174
|
+
fileLockManagerPort: t,
|
|
175
|
+
firstProcessId: i,
|
|
176
|
+
nativeInternalDirPath: r
|
|
177
|
+
}) {
|
|
178
|
+
const n = j(o.phpPort);
|
|
179
|
+
await n.useFileLockManager(t);
|
|
180
|
+
const s = {
|
|
181
|
+
...this.args,
|
|
182
|
+
phpVersion: this.phpVersion,
|
|
183
|
+
siteUrl: this.siteUrl,
|
|
184
|
+
firstProcessId: i,
|
|
185
|
+
processIdSpaceLength: this.processIdSpaceLength,
|
|
186
|
+
trace: this.args.debug || !1,
|
|
187
|
+
withXdebug: !!this.args.xdebug,
|
|
188
|
+
nativeInternalDirPath: r,
|
|
189
|
+
mountsBeforeWpInstall: this.args["mount-before-install"] || [],
|
|
190
|
+
mountsAfterWpInstall: this.args.mount || []
|
|
191
|
+
};
|
|
192
|
+
return await n.bootAsSecondaryWorker(s), n;
|
|
193
|
+
}
|
|
194
|
+
writeProgressUpdate(o, t, i) {
|
|
195
|
+
t !== this.lastProgressMessage && (this.lastProgressMessage = t, o.isTTY ? (o.cursorTo(0), o.write(t), o.clearLine(1), i && o.write(`
|
|
196
|
+
`)) : o.write(`${t}
|
|
197
|
+
`));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const N = g.join(Y.homedir(), ".wordpress-playground");
|
|
201
|
+
async function ze(e) {
|
|
202
|
+
return await G(
|
|
203
|
+
"https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/develop.zip",
|
|
204
|
+
"sqlite.zip",
|
|
205
|
+
e
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
async function G(e, o, t) {
|
|
209
|
+
const i = g.join(N, o);
|
|
210
|
+
return T.existsSync(i) || (T.ensureDirSync(N), await Xe(e, i, t)), ee(i);
|
|
211
|
+
}
|
|
212
|
+
async function Xe(e, o, t) {
|
|
213
|
+
const r = (await t.monitorFetch(fetch(e))).body.getReader(), n = `${o}.partial`, s = T.createWriteStream(n);
|
|
214
|
+
for (; ; ) {
|
|
215
|
+
const { done: l, value: a } = await r.read();
|
|
216
|
+
if (a && s.write(a), l)
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
s.close(), s.closed || await new Promise((l, a) => {
|
|
220
|
+
s.on("finish", () => {
|
|
221
|
+
T.renameSync(n, o), l(null);
|
|
222
|
+
}), s.on("error", (p) => {
|
|
223
|
+
T.removeSync(n), a(p);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function ee(e, o) {
|
|
228
|
+
return new File([T.readFileSync(e)], Ce(e));
|
|
229
|
+
}
|
|
230
|
+
class Je {
|
|
231
|
+
constructor(o, t) {
|
|
232
|
+
this.lastProgressMessage = "", this.args = o, this.siteUrl = t.siteUrl, this.processIdSpaceLength = t.processIdSpaceLength;
|
|
233
|
+
}
|
|
234
|
+
getWorkerType() {
|
|
235
|
+
return "v1";
|
|
236
|
+
}
|
|
237
|
+
async bootPrimaryWorker(o, t, i) {
|
|
238
|
+
let r;
|
|
239
|
+
const n = new Be();
|
|
240
|
+
if (!this.args.skipWordPressSetup) {
|
|
241
|
+
let C = !1;
|
|
242
|
+
n.addEventListener("progress", (x) => {
|
|
243
|
+
if (C)
|
|
244
|
+
return;
|
|
245
|
+
const { loaded: k, total: f } = x.detail, B = Math.floor(
|
|
246
|
+
Math.min(100, 100 * k / f)
|
|
247
|
+
);
|
|
248
|
+
C = B === 100, this.writeProgressUpdate(
|
|
249
|
+
process.stdout,
|
|
250
|
+
`Downloading WordPress ${B}%...`,
|
|
251
|
+
C
|
|
252
|
+
);
|
|
253
|
+
}), r = await Fe(this.args.wp), m.log(
|
|
254
|
+
`Resolved WordPress release URL: ${r?.releaseUrl}`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
const s = r && g.join(
|
|
258
|
+
N,
|
|
259
|
+
`prebuilt-wp-content-for-wp-${r.version}.zip`
|
|
260
|
+
), l = r ? u.existsSync(s) ? ee(s) : await G(
|
|
261
|
+
r.releaseUrl,
|
|
262
|
+
`${r.version}.zip`,
|
|
263
|
+
n
|
|
264
|
+
) : void 0;
|
|
265
|
+
m.log("Fetching SQLite integration plugin...");
|
|
266
|
+
const a = this.args.skipSqliteSetup ? void 0 : await ze(n), p = this.args.followSymlinks === !0, c = this.args.experimentalTrace === !0, d = this.args["mount-before-install"] || [], h = this.args.mount || [], w = j(o);
|
|
267
|
+
await w.isConnected(), m.log("Booting WordPress...");
|
|
268
|
+
const b = await me(
|
|
269
|
+
this.getEffectiveBlueprint()
|
|
270
|
+
);
|
|
271
|
+
return await w.useFileLockManager(t), await w.bootAsPrimaryWorker({
|
|
272
|
+
phpVersion: b.phpVersion,
|
|
273
|
+
wpVersion: b.wpVersion,
|
|
274
|
+
siteUrl: this.siteUrl,
|
|
275
|
+
mountsBeforeWpInstall: d,
|
|
276
|
+
mountsAfterWpInstall: h,
|
|
277
|
+
wordPressZip: l && await l.arrayBuffer(),
|
|
278
|
+
sqliteIntegrationPluginZip: await a?.arrayBuffer(),
|
|
279
|
+
firstProcessId: 0,
|
|
280
|
+
processIdSpaceLength: this.processIdSpaceLength,
|
|
281
|
+
followSymlinks: p,
|
|
282
|
+
trace: c,
|
|
283
|
+
internalCookieStore: this.args.internalCookieStore,
|
|
284
|
+
withXdebug: !!this.args.xdebug,
|
|
285
|
+
nativeInternalDirPath: i
|
|
286
|
+
}), r && !this.args["mount-before-install"] && !u.existsSync(s) && (m.log("Caching preinstalled WordPress for the next boot..."), u.writeFileSync(
|
|
287
|
+
s,
|
|
288
|
+
await we(w, "/wordpress")
|
|
289
|
+
), m.log("Cached!")), w;
|
|
290
|
+
}
|
|
291
|
+
async bootSecondaryWorker({
|
|
292
|
+
worker: o,
|
|
293
|
+
fileLockManagerPort: t,
|
|
294
|
+
firstProcessId: i,
|
|
295
|
+
nativeInternalDirPath: r
|
|
296
|
+
}) {
|
|
297
|
+
const n = j(
|
|
298
|
+
o.phpPort
|
|
299
|
+
);
|
|
300
|
+
return await n.isConnected(), await n.useFileLockManager(t), await n.bootAsSecondaryWorker({
|
|
301
|
+
phpVersion: this.phpVersion,
|
|
302
|
+
siteUrl: this.siteUrl,
|
|
303
|
+
mountsBeforeWpInstall: this.args["mount-before-install"] || [],
|
|
304
|
+
mountsAfterWpInstall: this.args.mount || [],
|
|
305
|
+
firstProcessId: i,
|
|
306
|
+
processIdSpaceLength: this.processIdSpaceLength,
|
|
307
|
+
followSymlinks: this.args.followSymlinks === !0,
|
|
308
|
+
trace: this.args.experimentalTrace === !0,
|
|
309
|
+
// @TODO: Move this to the request handler or else every worker
|
|
310
|
+
// will have a separate cookie store.
|
|
311
|
+
internalCookieStore: this.args.internalCookieStore,
|
|
312
|
+
withXdebug: !!this.args.xdebug,
|
|
313
|
+
nativeInternalDirPath: r
|
|
314
|
+
}), await n.isReady(), n;
|
|
315
|
+
}
|
|
316
|
+
async compileInputBlueprint(o) {
|
|
317
|
+
const t = this.getEffectiveBlueprint(), i = new je();
|
|
318
|
+
let r = "", n = !1;
|
|
319
|
+
return i.addEventListener("progress", (s) => {
|
|
320
|
+
if (n)
|
|
321
|
+
return;
|
|
322
|
+
n = s.detail.progress === 100;
|
|
323
|
+
const l = Math.floor(s.detail.progress);
|
|
324
|
+
r = s.detail.caption || r || "Running the Blueprint";
|
|
325
|
+
const a = `${r.trim()} – ${l}%`;
|
|
326
|
+
this.writeProgressUpdate(
|
|
327
|
+
process.stdout,
|
|
328
|
+
a,
|
|
329
|
+
n
|
|
330
|
+
);
|
|
331
|
+
}), await he(t, {
|
|
332
|
+
progress: i,
|
|
333
|
+
additionalSteps: o
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
getEffectiveBlueprint() {
|
|
337
|
+
const o = this.args.blueprint;
|
|
338
|
+
return ge(o) ? o : {
|
|
339
|
+
login: this.args.login,
|
|
340
|
+
...o || {},
|
|
341
|
+
preferredVersions: {
|
|
342
|
+
php: this.args.php ?? o?.preferredVersions?.php ?? Z,
|
|
343
|
+
wp: this.args.wp ?? o?.preferredVersions?.wp ?? "latest",
|
|
344
|
+
...o?.preferredVersions || {}
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
writeProgressUpdate(o, t, i) {
|
|
349
|
+
this.args.verbosity !== V.Quiet.name && t !== this.lastProgressMessage && (this.lastProgressMessage = t, o.isTTY ? (o.cursorTo(0), o.write(t), o.clearLine(1), i && o.write(`
|
|
350
|
+
`)) : o.write(`${t}
|
|
351
|
+
`));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async function Ze(e, o = !0) {
|
|
355
|
+
const i = `${g.basename(process.argv0)}${e}${process.pid}-`, r = (await Me({
|
|
356
|
+
prefix: i,
|
|
357
|
+
/*
|
|
358
|
+
* Allow recursive cleanup on process exit.
|
|
359
|
+
*
|
|
360
|
+
* NOTE: I worried about whether this cleanup would follow symlinks
|
|
361
|
+
* and delete target files instead of unlinking the symlink,
|
|
362
|
+
* but this feature uses rimraf under the hood which respects symlinks:
|
|
363
|
+
* https://github.com/raszi/node-tmp/blob/3d2fe387f3f91b13830b9182faa02c3231ea8258/lib/tmp.js#L318
|
|
364
|
+
*/
|
|
365
|
+
unsafeCleanup: !0
|
|
366
|
+
})).path;
|
|
367
|
+
return o && De(), r;
|
|
368
|
+
}
|
|
369
|
+
async function Ye(e, o, t) {
|
|
370
|
+
const r = (await Ke(
|
|
371
|
+
e,
|
|
372
|
+
o,
|
|
373
|
+
t
|
|
374
|
+
)).map(
|
|
375
|
+
(n) => new Promise((s) => {
|
|
376
|
+
u.rm(n, { recursive: !0 }, (l) => {
|
|
377
|
+
l ? m.warn(
|
|
378
|
+
`Failed to delete stale Playground temp dir: ${n}`,
|
|
379
|
+
l
|
|
380
|
+
) : m.info(
|
|
381
|
+
`Deleted stale Playground temp dir: ${n}`
|
|
382
|
+
), s();
|
|
383
|
+
});
|
|
384
|
+
})
|
|
385
|
+
);
|
|
386
|
+
await Promise.all(r);
|
|
387
|
+
}
|
|
388
|
+
async function Ke(e, o, t) {
|
|
389
|
+
try {
|
|
390
|
+
const i = u.readdirSync(t).map((n) => g.join(t, n)), r = [];
|
|
391
|
+
for (const n of i)
|
|
392
|
+
await Qe(
|
|
393
|
+
e,
|
|
394
|
+
o,
|
|
395
|
+
n
|
|
396
|
+
) && r.push(n);
|
|
397
|
+
return r;
|
|
398
|
+
} catch (i) {
|
|
399
|
+
return m.warn(`Failed to find stale Playground temp dirs: ${i}`), [];
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
async function Qe(e, o, t) {
|
|
403
|
+
if (!u.lstatSync(t).isDirectory())
|
|
404
|
+
return !1;
|
|
405
|
+
const r = g.basename(t);
|
|
406
|
+
if (!r.includes(e))
|
|
407
|
+
return !1;
|
|
408
|
+
const n = r.match(
|
|
409
|
+
new RegExp(`^(.+)${e}(\\d+)-`)
|
|
410
|
+
);
|
|
411
|
+
if (!n)
|
|
412
|
+
return !1;
|
|
413
|
+
const s = {
|
|
414
|
+
executableName: n[1],
|
|
415
|
+
pid: n[2]
|
|
416
|
+
};
|
|
417
|
+
if (await Ge(s.pid, s.executableName))
|
|
418
|
+
return !1;
|
|
419
|
+
const l = Date.now() - o;
|
|
420
|
+
return u.statSync(t).mtime.getTime() < l;
|
|
421
|
+
}
|
|
422
|
+
async function Ge(e, o) {
|
|
423
|
+
const [t] = await new Promise(
|
|
424
|
+
(i, r) => {
|
|
425
|
+
Ae.list(
|
|
426
|
+
{
|
|
427
|
+
pid: e,
|
|
428
|
+
name: o,
|
|
429
|
+
// Remove path from executable name in the results.
|
|
430
|
+
clean: !0
|
|
431
|
+
},
|
|
432
|
+
(n, s) => {
|
|
433
|
+
n ? r(n) : i(s);
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
return !!t && t.pid === e && t.command === o;
|
|
439
|
+
}
|
|
440
|
+
async function et(e, o, t) {
|
|
441
|
+
const i = t === "win32" ? (
|
|
442
|
+
// On Windows, creating a 'dir' symlink can require elevated permissions.
|
|
443
|
+
// In this case, let's make junction points because they function like
|
|
444
|
+
// symlinks and do not require elevated permissions.
|
|
445
|
+
"junction"
|
|
446
|
+
) : "dir";
|
|
447
|
+
u.symlinkSync(e, o, i);
|
|
448
|
+
}
|
|
449
|
+
async function tt(e) {
|
|
450
|
+
try {
|
|
451
|
+
u.lstatSync(e).isSymbolicLink() && u.unlinkSync(e);
|
|
452
|
+
} catch {
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function ot(e, o) {
|
|
456
|
+
return o.filter((t) => {
|
|
457
|
+
const i = g.resolve(t.hostPath), r = g.join(e, g.sep);
|
|
458
|
+
return (
|
|
459
|
+
// If auto-mounting from the current directory,
|
|
460
|
+
// the entire project directory can be mapped.
|
|
461
|
+
i === e || i.startsWith(r)
|
|
462
|
+
);
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
const I = {
|
|
466
|
+
ignoreAttributes: !1,
|
|
467
|
+
attributeNamePrefix: "",
|
|
468
|
+
preserveOrder: !0,
|
|
469
|
+
cdataPropName: "__cdata",
|
|
470
|
+
commentPropName: "__xmlComment",
|
|
471
|
+
allowBooleanAttributes: !0,
|
|
472
|
+
trimValues: !0
|
|
473
|
+
}, te = {
|
|
474
|
+
ignoreAttributes: I.ignoreAttributes,
|
|
475
|
+
attributeNamePrefix: I.attributeNamePrefix,
|
|
476
|
+
preserveOrder: I.preserveOrder,
|
|
477
|
+
cdataPropName: I.cdataPropName,
|
|
478
|
+
commentPropName: I.commentPropName,
|
|
479
|
+
suppressBooleanAttributes: !I.allowBooleanAttributes,
|
|
480
|
+
format: !0,
|
|
481
|
+
indentBy: " "
|
|
482
|
+
}, F = {
|
|
483
|
+
allowEmptyContent: !0,
|
|
484
|
+
allowTrailingComma: !0
|
|
485
|
+
};
|
|
486
|
+
function rt(e, o) {
|
|
487
|
+
const { name: t, host: i, port: r, mappings: n, ideKey: s } = o, l = new K(I), a = (() => {
|
|
488
|
+
try {
|
|
489
|
+
return l.parse(e, !0);
|
|
490
|
+
} catch {
|
|
491
|
+
throw new Error("PhpStorm configuration file is not valid XML.");
|
|
492
|
+
}
|
|
493
|
+
})(), p = {
|
|
494
|
+
server: [
|
|
495
|
+
{
|
|
496
|
+
path_mappings: n.map((f) => ({
|
|
497
|
+
mapping: [],
|
|
498
|
+
":@": {
|
|
499
|
+
"local-root": `$PROJECT_DIR$/${f.hostPath.replace(
|
|
500
|
+
/^\.\/?/,
|
|
501
|
+
""
|
|
502
|
+
)}`,
|
|
503
|
+
"remote-root": f.vfsPath
|
|
504
|
+
}
|
|
505
|
+
}))
|
|
506
|
+
}
|
|
507
|
+
],
|
|
508
|
+
":@": {
|
|
509
|
+
name: t,
|
|
510
|
+
// NOTE: PhpStorm quirk: Xdebug only works when the full URL (including port)
|
|
511
|
+
// is provided in `host`. The separate `port` field is ignored or misinterpreted,
|
|
512
|
+
// so we rely solely on host: "host:port".
|
|
513
|
+
host: `${i}:${r}`,
|
|
514
|
+
use_path_mappings: "true"
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
let c = a?.find((f) => !!f?.project);
|
|
518
|
+
if (c) {
|
|
519
|
+
const f = c[":@"]?.version;
|
|
520
|
+
if (f === void 0)
|
|
521
|
+
throw new Error(
|
|
522
|
+
'PhpStorm IDE integration only supports <project version="4"> in workspace.xml, but the <project> configuration has no version number.'
|
|
523
|
+
);
|
|
524
|
+
if (f !== "4")
|
|
525
|
+
throw new Error(
|
|
526
|
+
`PhpStorm IDE integration only supports <project version="4"> in workspace.xml, but we found a <project> configuration with version "${f}".`
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
c === void 0 && (c = {
|
|
530
|
+
project: [],
|
|
531
|
+
":@": { version: "4" }
|
|
532
|
+
}, a.push(c));
|
|
533
|
+
let d = c.project?.find(
|
|
534
|
+
(f) => !!f?.component && f?.[":@"]?.name === "PhpServers"
|
|
535
|
+
);
|
|
536
|
+
d === void 0 && (d = {
|
|
537
|
+
component: [],
|
|
538
|
+
":@": { name: "PhpServers" }
|
|
539
|
+
}, c.project === void 0 && (c.project = []), c.project.push(d));
|
|
540
|
+
let h = d.component?.find(
|
|
541
|
+
(f) => !!f?.servers
|
|
542
|
+
);
|
|
543
|
+
h === void 0 && (h = { servers: [] }, d.component === void 0 && (d.component = []), d.component.push(h));
|
|
544
|
+
const w = h.servers?.findIndex(
|
|
545
|
+
(f) => !!f?.server && f?.[":@"]?.name === t
|
|
546
|
+
);
|
|
547
|
+
(w === void 0 || w < 0) && (h.servers === void 0 && (h.servers = []), h.servers.push(p));
|
|
548
|
+
let b = c.project?.find(
|
|
549
|
+
(f) => !!f?.component && f?.[":@"]?.name === "RunManager"
|
|
550
|
+
);
|
|
551
|
+
if (b === void 0 && (b = {
|
|
552
|
+
component: [],
|
|
553
|
+
":@": { name: "RunManager" }
|
|
554
|
+
}, c.project === void 0 && (c.project = []), c.project.push(b)), (b.component?.findIndex(
|
|
555
|
+
(f) => !!f?.configuration && f?.[":@"]?.name === t
|
|
556
|
+
) ?? -1) < 0) {
|
|
557
|
+
const f = {
|
|
558
|
+
configuration: [
|
|
559
|
+
{
|
|
560
|
+
method: [],
|
|
561
|
+
":@": { v: "2" }
|
|
562
|
+
}
|
|
563
|
+
],
|
|
564
|
+
":@": {
|
|
565
|
+
name: t,
|
|
566
|
+
type: "PhpRemoteDebugRunConfigurationType",
|
|
567
|
+
factoryName: "PHP Remote Debug",
|
|
568
|
+
filter_connections: "FILTER",
|
|
569
|
+
server_name: t,
|
|
570
|
+
session_id: s
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
b.component === void 0 && (b.component = []), b.component.push(f);
|
|
574
|
+
}
|
|
575
|
+
const k = new Q(te).build(a);
|
|
576
|
+
try {
|
|
577
|
+
l.parse(k, !0);
|
|
578
|
+
} catch {
|
|
579
|
+
throw new Error(
|
|
580
|
+
"The resulting PhpStorm configuration file is not valid XML."
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
return k;
|
|
584
|
+
}
|
|
585
|
+
function nt(e, o) {
|
|
586
|
+
const { name: t, mappings: i } = o, r = [];
|
|
587
|
+
let n = e, s = v.parseTree(n, r, F);
|
|
588
|
+
if (s === void 0 || r.length)
|
|
589
|
+
throw new Error("VS Code configuration file is not valid JSON.");
|
|
590
|
+
let l = v.findNodeAtLocation(s, ["configurations"]);
|
|
591
|
+
if (l === void 0 || l.children === void 0) {
|
|
592
|
+
const p = v.modify(n, ["configurations"], [], {});
|
|
593
|
+
n = v.applyEdits(n, p), s = v.parseTree(n, [], F), l = v.findNodeAtLocation(s, [
|
|
594
|
+
"configurations"
|
|
595
|
+
]);
|
|
596
|
+
}
|
|
597
|
+
const a = l?.children?.findIndex(
|
|
598
|
+
(p) => v.findNodeAtLocation(p, ["name"])?.value === t
|
|
599
|
+
);
|
|
600
|
+
if (a === void 0 || a < 0) {
|
|
601
|
+
const p = {
|
|
602
|
+
name: t,
|
|
603
|
+
type: "php",
|
|
604
|
+
request: "launch",
|
|
605
|
+
port: 9003,
|
|
606
|
+
pathMappings: i.reduce((h, w) => (h[w.vfsPath] = `\${workspaceFolder}/${w.hostPath.replace(
|
|
607
|
+
/^\.\/?/,
|
|
608
|
+
""
|
|
609
|
+
)}`, h), {})
|
|
610
|
+
}, c = l?.children?.length || 0, d = v.modify(
|
|
611
|
+
n,
|
|
612
|
+
["configurations", c],
|
|
613
|
+
p,
|
|
614
|
+
{
|
|
615
|
+
formattingOptions: {
|
|
616
|
+
insertSpaces: !0,
|
|
617
|
+
tabSize: 4,
|
|
618
|
+
eol: `
|
|
619
|
+
`
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
);
|
|
623
|
+
n = oe(n, d);
|
|
624
|
+
}
|
|
625
|
+
return n;
|
|
626
|
+
}
|
|
627
|
+
async function it({
|
|
628
|
+
name: e,
|
|
629
|
+
ides: o,
|
|
630
|
+
host: t,
|
|
631
|
+
port: i,
|
|
632
|
+
cwd: r,
|
|
633
|
+
mounts: n,
|
|
634
|
+
ideKey: s = "PLAYGROUNDCLI"
|
|
635
|
+
}) {
|
|
636
|
+
const l = ot(r, n), a = [];
|
|
637
|
+
if (o.includes("phpstorm")) {
|
|
638
|
+
const p = ".idea/workspace.xml", c = g.join(
|
|
639
|
+
r,
|
|
640
|
+
p
|
|
641
|
+
);
|
|
642
|
+
if (!u.existsSync(c)) {
|
|
643
|
+
if (u.existsSync(g.dirname(c)))
|
|
644
|
+
u.writeFileSync(
|
|
645
|
+
c,
|
|
646
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
647
|
+
<project version="4">
|
|
648
|
+
</project>`
|
|
649
|
+
);
|
|
650
|
+
else if (o.length == 1)
|
|
651
|
+
throw new Error(
|
|
652
|
+
"PhpStorm IDE integration requested, but no '.idea' directory was found in the current working directory."
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
if (u.existsSync(c)) {
|
|
656
|
+
const d = u.readFileSync(c, "utf8"), h = rt(d, {
|
|
657
|
+
name: e,
|
|
658
|
+
host: t,
|
|
659
|
+
port: i,
|
|
660
|
+
mappings: l,
|
|
661
|
+
ideKey: s
|
|
662
|
+
});
|
|
663
|
+
u.writeFileSync(c, h);
|
|
664
|
+
}
|
|
665
|
+
a.push(p);
|
|
666
|
+
}
|
|
667
|
+
if (o.includes("vscode")) {
|
|
668
|
+
const p = ".vscode/launch.json", c = g.join(
|
|
669
|
+
r,
|
|
670
|
+
p
|
|
671
|
+
);
|
|
672
|
+
if (!u.existsSync(c)) {
|
|
673
|
+
if (u.existsSync(g.dirname(c)))
|
|
674
|
+
u.writeFileSync(
|
|
675
|
+
c,
|
|
676
|
+
`{
|
|
677
|
+
"configurations": []
|
|
678
|
+
}`
|
|
679
|
+
);
|
|
680
|
+
else if (o.length == 1)
|
|
681
|
+
throw new Error(
|
|
682
|
+
"VS Code IDE integration requested, but no '.vscode' directory was found in the current working directory."
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
if (u.existsSync(c)) {
|
|
686
|
+
const d = u.readFileSync(c, "utf-8"), h = nt(d, {
|
|
687
|
+
name: e,
|
|
688
|
+
mappings: l
|
|
689
|
+
});
|
|
690
|
+
h !== d && (u.writeFileSync(c, h), a.push(p));
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return a;
|
|
694
|
+
}
|
|
695
|
+
async function st(e, o) {
|
|
696
|
+
const t = g.join(o, ".idea/workspace.xml");
|
|
697
|
+
if (u.existsSync(t)) {
|
|
698
|
+
const r = u.readFileSync(t, "utf8"), n = new K(I), s = (() => {
|
|
699
|
+
try {
|
|
700
|
+
return n.parse(r, !0);
|
|
701
|
+
} catch {
|
|
702
|
+
throw new Error(
|
|
703
|
+
"PhpStorm configuration file is not valid XML."
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
})(), p = s.find(
|
|
707
|
+
(d) => !!d?.project
|
|
708
|
+
)?.project?.find(
|
|
709
|
+
(d) => !!d?.component && d?.[":@"]?.name === "PhpServers"
|
|
710
|
+
)?.component?.find(
|
|
711
|
+
(d) => !!d?.servers
|
|
712
|
+
), c = p?.servers?.findIndex(
|
|
713
|
+
(d) => !!d?.server && d?.[":@"]?.name === e
|
|
714
|
+
);
|
|
715
|
+
if (c !== void 0 && c >= 0) {
|
|
716
|
+
p.servers.splice(c, 1);
|
|
717
|
+
const h = new Q(te).build(s);
|
|
718
|
+
try {
|
|
719
|
+
n.parse(h, !0);
|
|
720
|
+
} catch {
|
|
721
|
+
throw new Error(
|
|
722
|
+
"The resulting PhpStorm configuration file is not valid XML."
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
h === `<?xml version="1.0" encoding="UTF-8"?>
|
|
726
|
+
<project version="4">
|
|
727
|
+
<component name="PhpServers">
|
|
728
|
+
<servers></servers>
|
|
729
|
+
</component>
|
|
730
|
+
</project>` ? u.unlinkSync(t) : u.writeFileSync(t, h);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
const i = g.join(o, ".vscode/launch.json");
|
|
734
|
+
if (u.existsSync(i)) {
|
|
735
|
+
const r = [], n = u.readFileSync(i, "utf-8"), s = v.parseTree(n, r, F);
|
|
736
|
+
if (s === void 0 || r.length)
|
|
737
|
+
throw new Error("VS Code configuration file is not valid JSON.");
|
|
738
|
+
const a = v.findNodeAtLocation(s, [
|
|
739
|
+
"configurations"
|
|
740
|
+
])?.children?.findIndex(
|
|
741
|
+
(p) => v.findNodeAtLocation(p, ["name"])?.value === e
|
|
742
|
+
);
|
|
743
|
+
if (a !== void 0 && a >= 0) {
|
|
744
|
+
const p = v.modify(
|
|
745
|
+
n,
|
|
746
|
+
["configurations", a],
|
|
747
|
+
void 0,
|
|
748
|
+
{
|
|
749
|
+
formattingOptions: {
|
|
750
|
+
insertSpaces: !0,
|
|
751
|
+
tabSize: 4,
|
|
752
|
+
eol: `
|
|
753
|
+
`
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
), c = oe(n, p);
|
|
757
|
+
c === `{
|
|
758
|
+
"configurations": []
|
|
759
|
+
}` ? u.unlinkSync(i) : u.writeFileSync(i, c);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function oe(e, o) {
|
|
764
|
+
const t = [], i = v.applyEdits(e, o);
|
|
765
|
+
if (t.length = 0, v.parseTree(i, t, F), t.length) {
|
|
766
|
+
const r = t.map((s) => ({
|
|
767
|
+
message: v.printParseErrorCode(s.error),
|
|
768
|
+
offset: s.offset,
|
|
769
|
+
length: s.length,
|
|
770
|
+
fragment: i.slice(
|
|
771
|
+
Math.max(0, s.offset - 20),
|
|
772
|
+
Math.min(i.length, s.offset + s.length + 10)
|
|
773
|
+
)
|
|
774
|
+
})).map(
|
|
775
|
+
(s) => `${s.message} at ${s.offset}:${s.length} (${s.fragment})`
|
|
776
|
+
), n = o.map(
|
|
777
|
+
(s) => `At ${s.offset}:${s.length} - (${s.content})`
|
|
778
|
+
);
|
|
779
|
+
throw new Error(
|
|
780
|
+
`VS Code configuration file (.vscode/launch.json) is not valid a JSONC after Playground CLI modifications. This is likely a Playground CLI bug. Please report it at https://github.com/WordPress/wordpress-playground/issues and include the contents of your ".vscode/launch.json" file.
|
|
781
|
+
|
|
782
|
+
Applied edits: ${n.join(
|
|
783
|
+
`
|
|
784
|
+
`
|
|
785
|
+
)}
|
|
786
|
+
|
|
787
|
+
The errors are: ${r.join(`
|
|
788
|
+
`)}`
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
return i;
|
|
792
|
+
}
|
|
793
|
+
const V = {
|
|
794
|
+
Quiet: { name: "quiet", severity: M.Fatal },
|
|
795
|
+
Normal: { name: "normal", severity: M.Info },
|
|
796
|
+
Debug: { name: "debug", severity: M.Debug }
|
|
797
|
+
};
|
|
798
|
+
async function Rt() {
|
|
799
|
+
try {
|
|
800
|
+
const e = Ie(process.argv.slice(2)).usage("Usage: wp-playground <command> [options]").positional("command", {
|
|
801
|
+
describe: "Command to run",
|
|
802
|
+
choices: ["server", "run-blueprint", "build-snapshot"],
|
|
803
|
+
demandOption: !0
|
|
804
|
+
}).option("outfile", {
|
|
805
|
+
describe: "When building, write to this output file.",
|
|
806
|
+
type: "string",
|
|
807
|
+
default: "wordpress.zip"
|
|
808
|
+
}).option("port", {
|
|
809
|
+
describe: "Port to listen on when serving.",
|
|
810
|
+
type: "number",
|
|
811
|
+
default: 9400
|
|
812
|
+
}).option("site-url", {
|
|
813
|
+
describe: "Site URL to use for WordPress. Defaults to http://127.0.0.1:{port}",
|
|
814
|
+
type: "string"
|
|
815
|
+
}).option("php", {
|
|
816
|
+
describe: "PHP version to use.",
|
|
817
|
+
type: "string",
|
|
818
|
+
default: Z,
|
|
819
|
+
choices: ce
|
|
820
|
+
}).option("wp", {
|
|
821
|
+
describe: "WordPress version to use.",
|
|
822
|
+
type: "string",
|
|
823
|
+
default: "latest"
|
|
824
|
+
}).option("mount", {
|
|
825
|
+
describe: "Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path",
|
|
826
|
+
type: "array",
|
|
827
|
+
string: !0,
|
|
828
|
+
coerce: z
|
|
829
|
+
}).option("mount-before-install", {
|
|
830
|
+
describe: "Mount a directory to the PHP runtime before WordPress installation (can be used multiple times). Format: /host/path:/vfs/path",
|
|
831
|
+
type: "array",
|
|
832
|
+
string: !0,
|
|
833
|
+
coerce: z
|
|
834
|
+
}).option("mount-dir", {
|
|
835
|
+
describe: 'Mount a directory to the PHP runtime (can be used multiple times). Format: "/host/path" "/vfs/path"',
|
|
836
|
+
type: "array",
|
|
837
|
+
nargs: 2,
|
|
838
|
+
array: !0
|
|
839
|
+
// coerce: parseMountDirArguments,
|
|
840
|
+
}).option("mount-dir-before-install", {
|
|
841
|
+
describe: 'Mount a directory before WordPress installation (can be used multiple times). Format: "/host/path" "/vfs/path"',
|
|
842
|
+
type: "string",
|
|
843
|
+
nargs: 2,
|
|
844
|
+
array: !0,
|
|
845
|
+
coerce: ve
|
|
846
|
+
}).option("login", {
|
|
847
|
+
describe: "Should log the user in",
|
|
848
|
+
type: "boolean",
|
|
849
|
+
default: !1
|
|
850
|
+
}).option("blueprint", {
|
|
851
|
+
describe: "Blueprint to execute.",
|
|
852
|
+
type: "string"
|
|
853
|
+
}).option("blueprint-may-read-adjacent-files", {
|
|
854
|
+
describe: 'Consent flag: Allow "bundled" resources in a local blueprint to read files in the same directory as the blueprint file.',
|
|
855
|
+
type: "boolean",
|
|
856
|
+
default: !1
|
|
857
|
+
}).option("skip-wordpress-setup", {
|
|
858
|
+
describe: "Do not download, unzip, and install WordPress. Useful for mounting a pre-configured WordPress directory at /wordpress.",
|
|
859
|
+
type: "boolean",
|
|
860
|
+
default: !1
|
|
861
|
+
}).option("skip-sqlite-setup", {
|
|
862
|
+
describe: "Skip the SQLite integration plugin setup to allow the WordPress site to use MySQL.",
|
|
863
|
+
type: "boolean",
|
|
864
|
+
default: !1
|
|
865
|
+
}).option("quiet", {
|
|
866
|
+
describe: "Do not output logs and progress messages.",
|
|
867
|
+
type: "boolean",
|
|
868
|
+
default: !1,
|
|
869
|
+
hidden: !0
|
|
870
|
+
}).option("verbosity", {
|
|
871
|
+
describe: "Output logs and progress messages.",
|
|
872
|
+
type: "string",
|
|
873
|
+
choices: Object.values(V).map(
|
|
874
|
+
(r) => r.name
|
|
875
|
+
),
|
|
876
|
+
default: "normal"
|
|
877
|
+
}).option("debug", {
|
|
878
|
+
describe: "Print PHP error log content if an error occurs during Playground boot.",
|
|
879
|
+
type: "boolean",
|
|
880
|
+
default: !1
|
|
881
|
+
}).option("auto-mount", {
|
|
882
|
+
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.",
|
|
883
|
+
type: "string"
|
|
884
|
+
}).option("follow-symlinks", {
|
|
885
|
+
describe: `Allow Playground to follow symlinks by automatically mounting symlinked directories and files encountered in mounted directories.
|
|
886
|
+
Warning: Following symlinks will expose files outside mounted directories to Playground and could be a security risk.`,
|
|
887
|
+
type: "boolean",
|
|
888
|
+
default: !1
|
|
889
|
+
}).option("experimental-trace", {
|
|
890
|
+
describe: "Print detailed messages about system behavior to the console. Useful for troubleshooting.",
|
|
891
|
+
type: "boolean",
|
|
892
|
+
default: !1,
|
|
893
|
+
// Hide this option because we want to replace with a more general log-level flag.
|
|
894
|
+
hidden: !0
|
|
895
|
+
}).option("internal-cookie-store", {
|
|
896
|
+
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).",
|
|
897
|
+
type: "boolean",
|
|
898
|
+
default: !1
|
|
899
|
+
}).option("xdebug", {
|
|
900
|
+
describe: "Enable Xdebug.",
|
|
901
|
+
type: "boolean",
|
|
902
|
+
default: !1
|
|
903
|
+
}).option("experimental-unsafe-ide-integration", {
|
|
904
|
+
describe: "Enable experimental IDE development tools. This option edits IDE config files to set Xdebug path mappings and web server details. CAUTION: If there are bugs, this feature may break your IDE config files. Please consider backing up your IDE configs before using this feature.",
|
|
905
|
+
type: "string",
|
|
906
|
+
// The empty value means the option is enabled for all
|
|
907
|
+
// supported IDEs and, if needed, will create the relevant
|
|
908
|
+
// config file for each.
|
|
909
|
+
choices: ["", "vscode", "phpstorm"],
|
|
910
|
+
coerce: (r) => r === "" ? ["vscode", "phpstorm"] : [r]
|
|
911
|
+
}).option("experimental-devtools", {
|
|
912
|
+
describe: "Enable experimental browser development tools.",
|
|
913
|
+
type: "boolean"
|
|
914
|
+
}).conflicts(
|
|
915
|
+
"experimental-unsafe-ide-integration",
|
|
916
|
+
"experimental-devtools"
|
|
917
|
+
).option("experimental-multi-worker", {
|
|
918
|
+
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.",
|
|
919
|
+
type: "number",
|
|
920
|
+
coerce: (r) => r ?? xe().length - 1
|
|
921
|
+
}).option("experimental-blueprints-v2-runner", {
|
|
922
|
+
describe: "Use the experimental Blueprint V2 runner.",
|
|
923
|
+
type: "boolean",
|
|
924
|
+
default: !1,
|
|
925
|
+
// Remove the "hidden" flag once Blueprint V2 is fully supported
|
|
926
|
+
hidden: !0
|
|
927
|
+
}).option("mode", {
|
|
928
|
+
describe: "Blueprints v2 runner mode to use. This option is required when using the --experimental-blueprints-v2-runner flag with a blueprint.",
|
|
929
|
+
type: "string",
|
|
930
|
+
choices: ["create-new-site", "apply-to-existing-site"],
|
|
931
|
+
// Remove the "hidden" flag once Blueprint V2 is fully supported
|
|
932
|
+
hidden: !0
|
|
933
|
+
}).showHelpOnFail(!1).strictOptions().check(async (r) => {
|
|
934
|
+
if ((r["skip-wordpress-setup"] || r.skipWordpressSetup) && (r.skipWordPressSetup = !0), r.wp !== void 0 && !_e(r.wp))
|
|
935
|
+
try {
|
|
936
|
+
new URL(r.wp);
|
|
937
|
+
} catch {
|
|
938
|
+
throw new Error(
|
|
939
|
+
'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"'
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
if (r["site-url"] !== void 0 && r["site-url"] !== "")
|
|
943
|
+
try {
|
|
944
|
+
new URL(r["site-url"]);
|
|
945
|
+
} catch {
|
|
946
|
+
throw new Error(
|
|
947
|
+
`Invalid site-url "${r["site-url"]}". Please provide a valid URL (e.g., http://localhost:8080 or https://example.com)`
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
if (r["auto-mount"]) {
|
|
951
|
+
let n = !1;
|
|
952
|
+
try {
|
|
953
|
+
n = u.statSync(r["auto-mount"]).isDirectory();
|
|
954
|
+
} catch {
|
|
955
|
+
n = !1;
|
|
956
|
+
}
|
|
957
|
+
if (!n)
|
|
958
|
+
throw new Error(
|
|
959
|
+
`The specified --auto-mount path is not a directory: '${r["auto-mount"]}'.`
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
if (r["experimental-multi-worker"] !== void 0 && r["experimental-multi-worker"] <= 1)
|
|
963
|
+
throw new Error(
|
|
964
|
+
"The --experimental-multi-worker flag must be a positive integer greater than 1."
|
|
965
|
+
);
|
|
966
|
+
if (r["experimental-blueprints-v2-runner"] === !0) {
|
|
967
|
+
if (r.mode !== void 0) {
|
|
968
|
+
if ("skip-wordpress-setup" in r)
|
|
969
|
+
throw new Error(
|
|
970
|
+
"The --skipWordPressSetup option cannot be used with the --mode option. Use one or the other."
|
|
971
|
+
);
|
|
972
|
+
if ("skip-sqlite-setup" in r)
|
|
973
|
+
throw new Error(
|
|
974
|
+
"The --skipSqliteSetup option is not supported in Blueprint V2 mode."
|
|
975
|
+
);
|
|
976
|
+
if (r["auto-mount"] !== void 0)
|
|
977
|
+
throw new Error(
|
|
978
|
+
"The --mode option cannot be used with --auto-mount because --auto-mount automatically sets the mode."
|
|
979
|
+
);
|
|
980
|
+
} else
|
|
981
|
+
r["skip-wordpress-setup"] === !0 ? r.mode = "apply-to-existing-site" : r.mode = "create-new-site";
|
|
982
|
+
const n = r.allow || [];
|
|
983
|
+
r.followSymlinks === !0 && n.push("follow-symlinks"), r["blueprint-may-read-adjacent-files"] === !0 && n.push("read-local-fs"), r.allow = n;
|
|
984
|
+
} else if (r.mode !== void 0)
|
|
985
|
+
throw new Error(
|
|
986
|
+
"The --mode option requires the --experimentalBlueprintsV2Runner flag."
|
|
987
|
+
);
|
|
988
|
+
return !0;
|
|
989
|
+
});
|
|
990
|
+
e.wrap(e.terminalWidth());
|
|
991
|
+
const o = await e.argv, t = o._[0];
|
|
992
|
+
["run-blueprint", "server", "build-snapshot"].includes(t) || (e.showHelp(), process.exit(1));
|
|
993
|
+
const i = {
|
|
994
|
+
...o,
|
|
995
|
+
command: t,
|
|
996
|
+
mount: [...o.mount || [], ...o["mount-dir"] || []],
|
|
997
|
+
"mount-before-install": [
|
|
998
|
+
...o["mount-before-install"] || [],
|
|
999
|
+
...o["mount-dir-before-install"] || []
|
|
1000
|
+
]
|
|
1001
|
+
};
|
|
1002
|
+
await lt(i);
|
|
1003
|
+
} catch (e) {
|
|
1004
|
+
if (!(e instanceof Error))
|
|
1005
|
+
throw e;
|
|
1006
|
+
if (process.argv.includes("--debug"))
|
|
1007
|
+
pe(e);
|
|
1008
|
+
else {
|
|
1009
|
+
const t = [];
|
|
1010
|
+
let i = e;
|
|
1011
|
+
do
|
|
1012
|
+
t.push(i.message), i = i.cause;
|
|
1013
|
+
while (i instanceof Error);
|
|
1014
|
+
console.error(
|
|
1015
|
+
"\x1B[1m" + t.join(" caused by ") + "\x1B[0m"
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
process.exit(1);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
const D = (e) => process.stdout.isTTY ? "\x1B[1m" + e + "\x1B[0m" : e, at = (e) => process.stdout.isTTY ? `\x1B[2m${e}\x1B[0m` : e, A = (e) => process.stdout.isTTY ? `\x1B[3m${e}\x1B[0m` : e, X = (e) => process.stdout.isTTY ? `\x1B[33m${e}\x1B[0m` : e;
|
|
1022
|
+
async function lt(e) {
|
|
1023
|
+
let o, t;
|
|
1024
|
+
const i = [];
|
|
1025
|
+
if (e.autoMount !== void 0 && (e.autoMount === "" && (e = { ...e, autoMount: process.cwd() }), e = Pe(e)), e.quiet && (e.verbosity = "quiet", delete e.quiet), e.debug ? e.verbosity = "debug" : e.verbosity === "debug" && (e.debug = !0), e.verbosity) {
|
|
1026
|
+
const a = Object.values(V).find(
|
|
1027
|
+
(p) => p.name === e.verbosity
|
|
1028
|
+
).severity;
|
|
1029
|
+
m.setSeverityFilterLevel(a);
|
|
1030
|
+
}
|
|
1031
|
+
const r = Y.platform() === "win32" ? (
|
|
1032
|
+
// @TODO: Enable fs-ext here when it works with Windows.
|
|
1033
|
+
void 0
|
|
1034
|
+
) : await import("fs-ext").then((a) => a.flockSync).catch(() => {
|
|
1035
|
+
m.warn(
|
|
1036
|
+
"The fs-ext package is not installed. Internal file locking will not be integrated with host OS file locking."
|
|
1037
|
+
);
|
|
1038
|
+
}), n = new ke(r);
|
|
1039
|
+
let s = !1, l = !0;
|
|
1040
|
+
return m.log("Starting a PHP server..."), Ue({
|
|
1041
|
+
port: e.port,
|
|
1042
|
+
onBind: async (a, p) => {
|
|
1043
|
+
const c = "127.0.0.1", d = `http://${c}:${p}`, h = e["site-url"] || d, w = e.experimentalMultiWorker ?? 1, b = Math.floor(
|
|
1044
|
+
Number.MAX_SAFE_INTEGER / w
|
|
1045
|
+
), C = "-playground-cli-site-", x = await Ze(
|
|
1046
|
+
C
|
|
1047
|
+
);
|
|
1048
|
+
m.debug(`Native temp dir for VFS root: ${x}`);
|
|
1049
|
+
const k = "WP Playground CLI - Listen for Xdebug", f = ".playground-xdebug-root", B = g.join(process.cwd(), f);
|
|
1050
|
+
if (await tt(B), e.xdebug && e.experimentalUnsafeIdeIntegration) {
|
|
1051
|
+
await et(
|
|
1052
|
+
x,
|
|
1053
|
+
B,
|
|
1054
|
+
process.platform
|
|
1055
|
+
);
|
|
1056
|
+
const y = {
|
|
1057
|
+
hostPath: `./${f}`,
|
|
1058
|
+
vfsPath: "/"
|
|
1059
|
+
};
|
|
1060
|
+
try {
|
|
1061
|
+
await st(k, process.cwd());
|
|
1062
|
+
const S = typeof e.xdebug == "object" ? e.xdebug : void 0, W = await it({
|
|
1063
|
+
name: k,
|
|
1064
|
+
host: c,
|
|
1065
|
+
port: p,
|
|
1066
|
+
ides: e.experimentalUnsafeIdeIntegration,
|
|
1067
|
+
cwd: process.cwd(),
|
|
1068
|
+
mounts: [
|
|
1069
|
+
y,
|
|
1070
|
+
...e["mount-before-install"] || [],
|
|
1071
|
+
...e.mount || []
|
|
1072
|
+
],
|
|
1073
|
+
ideKey: S?.ideKey
|
|
1074
|
+
}), P = e.experimentalUnsafeIdeIntegration, E = P.includes("vscode"), $ = P.includes("phpstorm");
|
|
1075
|
+
console.log(""), console.log(D("Xdebug configured successfully")), console.log(
|
|
1076
|
+
X("Updated IDE config: ") + W.join(" ")
|
|
1077
|
+
), console.log(
|
|
1078
|
+
X("Playground source root: ") + ".playground-xdebug-root" + A(
|
|
1079
|
+
at(
|
|
1080
|
+
" – you can set breakpoints and preview Playground's VFS structure in there."
|
|
1081
|
+
)
|
|
1082
|
+
)
|
|
1083
|
+
), console.log(""), E && (console.log(D("VS Code / Cursor instructions:")), console.log(
|
|
1084
|
+
" 1. Open the Run and Debug panel on the left sidebar"
|
|
1085
|
+
), console.log(
|
|
1086
|
+
` 2. Select "${A(
|
|
1087
|
+
k
|
|
1088
|
+
)}" from the dropdown`
|
|
1089
|
+
), console.log(' 3. Click "start debugging"'), console.log(
|
|
1090
|
+
" 4. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"
|
|
1091
|
+
), console.log(
|
|
1092
|
+
" 5. Visit Playground in your browser to hit the breakpoint"
|
|
1093
|
+
), $ && console.log("")), $ && (console.log(D("PhpStorm instructions:")), console.log(
|
|
1094
|
+
` 1. Choose "${A(
|
|
1095
|
+
k
|
|
1096
|
+
)}" debug configuration in the toolbar`
|
|
1097
|
+
), console.log(" 2. Click the debug button (bug icon)`"), console.log(
|
|
1098
|
+
" 3. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"
|
|
1099
|
+
), console.log(
|
|
1100
|
+
" 4. Visit Playground in your browser to hit the breakpoint"
|
|
1101
|
+
)), console.log("");
|
|
1102
|
+
} catch (S) {
|
|
1103
|
+
m.error(
|
|
1104
|
+
"Could not configure Xdebug:",
|
|
1105
|
+
S?.message
|
|
1106
|
+
), process.exit(1);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
const re = g.dirname(x), ne = 2 * 24 * 60 * 60 * 1e3;
|
|
1110
|
+
Ye(
|
|
1111
|
+
C,
|
|
1112
|
+
ne,
|
|
1113
|
+
re
|
|
1114
|
+
);
|
|
1115
|
+
const R = g.join(x, "internal");
|
|
1116
|
+
H(R);
|
|
1117
|
+
const ie = [
|
|
1118
|
+
"wordpress",
|
|
1119
|
+
// Note: These dirs are from Emscripten's "default dirs" list:
|
|
1120
|
+
// https://github.com/emscripten-core/emscripten/blob/f431ec220e472e1f8d3db6b52fe23fb377facf30/src/lib/libfs.js#L1400-L1402
|
|
1121
|
+
//
|
|
1122
|
+
// Any Playground process with multiple workers may assume
|
|
1123
|
+
// these are part of a shared filesystem, so let's recognize
|
|
1124
|
+
// them explicitly here.
|
|
1125
|
+
"tmp",
|
|
1126
|
+
"home"
|
|
1127
|
+
];
|
|
1128
|
+
for (const y of ie) {
|
|
1129
|
+
const S = (P) => P.vfsPath === `/${y}`;
|
|
1130
|
+
if (!(e["mount-before-install"]?.some(S) || e.mount?.some(S))) {
|
|
1131
|
+
const P = g.join(
|
|
1132
|
+
x,
|
|
1133
|
+
y
|
|
1134
|
+
);
|
|
1135
|
+
H(P), e["mount-before-install"] === void 0 && (e["mount-before-install"] = []), e["mount-before-install"].unshift({
|
|
1136
|
+
vfsPath: `/${y}`,
|
|
1137
|
+
hostPath: P
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
if (e["mount-before-install"])
|
|
1142
|
+
for (const y of e["mount-before-install"])
|
|
1143
|
+
m.debug(
|
|
1144
|
+
`Mount before WP install: ${y.vfsPath} -> ${y.hostPath}`
|
|
1145
|
+
);
|
|
1146
|
+
if (e.mount)
|
|
1147
|
+
for (const y of e.mount)
|
|
1148
|
+
m.debug(
|
|
1149
|
+
`Mount after WP install: ${y.vfsPath} -> ${y.hostPath}`
|
|
1150
|
+
);
|
|
1151
|
+
let L;
|
|
1152
|
+
e["experimental-blueprints-v2-runner"] ? L = new qe(e, {
|
|
1153
|
+
siteUrl: h,
|
|
1154
|
+
processIdSpaceLength: b
|
|
1155
|
+
}) : (L = new Je(e, {
|
|
1156
|
+
siteUrl: h,
|
|
1157
|
+
processIdSpaceLength: b
|
|
1158
|
+
}), typeof e.blueprint == "string" && (e.blueprint = await He({
|
|
1159
|
+
sourceString: e.blueprint,
|
|
1160
|
+
blueprintMayReadAdjacentFiles: e["blueprint-may-read-adjacent-files"] === !0
|
|
1161
|
+
})));
|
|
1162
|
+
const se = ct(
|
|
1163
|
+
w,
|
|
1164
|
+
L.getWorkerType(),
|
|
1165
|
+
({ exitCode: y, isMain: S, workerIndex: W }) => {
|
|
1166
|
+
y !== 0 && (m.error(
|
|
1167
|
+
`Worker ${W} exited with code ${y}
|
|
1168
|
+
`
|
|
1169
|
+
), S && e.exitOnPrimaryWorkerCrash && process.exit(1));
|
|
1170
|
+
}
|
|
1171
|
+
);
|
|
1172
|
+
m.log(`Setting up WordPress ${e.wp}`);
|
|
1173
|
+
try {
|
|
1174
|
+
const [y, ...S] = await se, W = await J(
|
|
1175
|
+
n
|
|
1176
|
+
);
|
|
1177
|
+
if (t = await L.bootPrimaryWorker(
|
|
1178
|
+
y.phpPort,
|
|
1179
|
+
W,
|
|
1180
|
+
R
|
|
1181
|
+
), i.push({
|
|
1182
|
+
playground: t,
|
|
1183
|
+
worker: y.worker
|
|
1184
|
+
}), await t.isReady(), s = !0, m.log("Booted!"), o = new Oe(t), !e["experimental-blueprints-v2-runner"]) {
|
|
1185
|
+
const P = await L.compileInputBlueprint(
|
|
1186
|
+
e["additional-blueprint-steps"] || []
|
|
1187
|
+
);
|
|
1188
|
+
P && (m.log("Running the Blueprint..."), await ye(
|
|
1189
|
+
P,
|
|
1190
|
+
t
|
|
1191
|
+
), m.log("Finished running the blueprint"));
|
|
1192
|
+
}
|
|
1193
|
+
if (e.command === "build-snapshot" ? (await ut(t, e.outfile), m.log(`WordPress exported to ${e.outfile}`), process.exit(0)) : e.command === "run-blueprint" && (m.log("Blueprint executed"), process.exit(0)), e.experimentalMultiWorker && e.experimentalMultiWorker > 1) {
|
|
1194
|
+
m.log("Preparing additional workers...");
|
|
1195
|
+
const P = b;
|
|
1196
|
+
await Promise.all(
|
|
1197
|
+
S.map(async (E, $) => {
|
|
1198
|
+
const ae = P + $ * b, le = await J(n), O = await L.bootSecondaryWorker({
|
|
1199
|
+
worker: E,
|
|
1200
|
+
fileLockManagerPort: le,
|
|
1201
|
+
firstProcessId: ae,
|
|
1202
|
+
nativeInternalDirPath: R
|
|
1203
|
+
});
|
|
1204
|
+
i.push({
|
|
1205
|
+
playground: O,
|
|
1206
|
+
worker: E.worker
|
|
1207
|
+
}), o.addWorker(O);
|
|
1208
|
+
})
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
return m.log(
|
|
1212
|
+
`WordPress is running on ${d} with ${w} worker(s)`
|
|
1213
|
+
), e.xdebug && e.experimentalDevtools && (await Re({
|
|
1214
|
+
phpInstance: t,
|
|
1215
|
+
phpRoot: "/wordpress"
|
|
1216
|
+
})).start(), {
|
|
1217
|
+
playground: t,
|
|
1218
|
+
server: a,
|
|
1219
|
+
serverUrl: d,
|
|
1220
|
+
[Symbol.asyncDispose]: async function() {
|
|
1221
|
+
await Promise.all(
|
|
1222
|
+
i.map(
|
|
1223
|
+
async ({ playground: E, worker: $ }) => {
|
|
1224
|
+
await E.dispose(), await $.terminate();
|
|
1225
|
+
}
|
|
1226
|
+
)
|
|
1227
|
+
), await new Promise((E) => a.close(E));
|
|
1228
|
+
},
|
|
1229
|
+
workerThreadCount: w
|
|
1230
|
+
};
|
|
1231
|
+
} catch (y) {
|
|
1232
|
+
if (!e.debug)
|
|
1233
|
+
throw y;
|
|
1234
|
+
let S = "";
|
|
1235
|
+
throw await t?.fileExists(_) && (S = await t.readFileAsText(_)), new Error(S, { cause: y });
|
|
1236
|
+
}
|
|
1237
|
+
},
|
|
1238
|
+
async handleRequest(a) {
|
|
1239
|
+
if (!s)
|
|
1240
|
+
return U.forHttpCode(
|
|
1241
|
+
502,
|
|
1242
|
+
"WordPress is not ready yet"
|
|
1243
|
+
);
|
|
1244
|
+
if (l) {
|
|
1245
|
+
l = !1;
|
|
1246
|
+
const p = {
|
|
1247
|
+
"Content-Type": ["text/plain"],
|
|
1248
|
+
"Content-Length": ["0"],
|
|
1249
|
+
Location: [a.url]
|
|
1250
|
+
};
|
|
1251
|
+
return a.headers?.cookie?.includes(
|
|
1252
|
+
"playground_auto_login_already_happened"
|
|
1253
|
+
) && (p["Set-Cookie"] = [
|
|
1254
|
+
"playground_auto_login_already_happened=1; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/"
|
|
1255
|
+
]), new U(302, p, new Uint8Array());
|
|
1256
|
+
}
|
|
1257
|
+
return await o.handleRequest(a);
|
|
1258
|
+
}
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
async function ct(e, o, t) {
|
|
1262
|
+
const i = [];
|
|
1263
|
+
for (let r = 0; r < e; r++) {
|
|
1264
|
+
const n = await pt(o), s = (l) => {
|
|
1265
|
+
t({
|
|
1266
|
+
exitCode: l,
|
|
1267
|
+
isMain: r === 0,
|
|
1268
|
+
workerIndex: r
|
|
1269
|
+
});
|
|
1270
|
+
};
|
|
1271
|
+
i.push(
|
|
1272
|
+
new Promise(
|
|
1273
|
+
(l, a) => {
|
|
1274
|
+
n.once("message", function(p) {
|
|
1275
|
+
p.command === "worker-script-initialized" && l({ worker: n, phpPort: p.phpPort });
|
|
1276
|
+
}), n.once("error", function(p) {
|
|
1277
|
+
console.error(p);
|
|
1278
|
+
const c = new Error(
|
|
1279
|
+
`Worker failed to load worker. ${p.message ? `Original error: ${p.message}` : ""}`
|
|
1280
|
+
);
|
|
1281
|
+
a(c);
|
|
1282
|
+
}), n.once("exit", s);
|
|
1283
|
+
}
|
|
1284
|
+
)
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
return Promise.all(i);
|
|
1288
|
+
}
|
|
1289
|
+
async function pt(e) {
|
|
1290
|
+
return e === "v1" ? new q(new URL("./worker-thread-v1.js", import.meta.url)) : new q(new URL("./worker-thread-v2.js", import.meta.url));
|
|
1291
|
+
}
|
|
1292
|
+
async function J(e) {
|
|
1293
|
+
const { port1: o, port2: t } = new be();
|
|
1294
|
+
return await Ee() ? ue(e, null, o) : await de(e, o), t;
|
|
1295
|
+
}
|
|
1296
|
+
async function ut(e, o) {
|
|
1297
|
+
await e.run({
|
|
1298
|
+
code: `<?php
|
|
1299
|
+
$zip = new ZipArchive();
|
|
1300
|
+
if(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
|
|
1301
|
+
throw new Exception('Failed to create ZIP');
|
|
1302
|
+
}
|
|
1303
|
+
$files = new RecursiveIteratorIterator(
|
|
1304
|
+
new RecursiveDirectoryIterator('/wordpress')
|
|
1305
|
+
);
|
|
1306
|
+
foreach ($files as $file) {
|
|
1307
|
+
echo $file . PHP_EOL;
|
|
1308
|
+
if (!$file->isFile()) {
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
$zip->addFile($file->getPathname(), $file->getPathname());
|
|
1312
|
+
}
|
|
1313
|
+
$zip->close();
|
|
1314
|
+
|
|
1315
|
+
`
|
|
1316
|
+
});
|
|
1317
|
+
const t = await e.readFileAsBuffer("/tmp/build.zip");
|
|
1318
|
+
u.writeFileSync(o, t);
|
|
1319
|
+
}
|
|
1320
|
+
export {
|
|
1321
|
+
V as L,
|
|
1322
|
+
Rt as p,
|
|
1323
|
+
lt as r
|
|
1324
|
+
};
|
|
1325
|
+
//# sourceMappingURL=run-cli-B59N7dQd.js.map
|