stim 1.14.0 → 1.16.0
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/README.md +2 -0
- package/dist/activity-BxwdD81S.mjs +609 -0
- package/dist/agent-device-usage-output-Dpih1Tfa.mjs +411 -0
- package/dist/{android-d6rGq1pA.mjs → android-B_NumVyQ.mjs} +169 -81
- package/dist/{android-LbPFRWVL.mjs → android-Ift4kVvt.mjs} +517 -413
- package/dist/android-cas-8U4DPqeR.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-XpvCrV7q.mjs → android-r2rBL8kV.mjs} +2 -2
- package/dist/{app-install-BpgSgkJj.mjs → app-install-CKWdbXIX.mjs} +128 -151
- package/dist/attempt-Bk2ouQVL.mjs +39 -0
- package/dist/budget-DjrURfQn.mjs +2700 -0
- package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-DjeSb2Xl.mjs} +192 -653
- package/dist/build-slots-rUk77xqh.mjs +132 -0
- package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
- package/dist/cli-BkYZ_6hy.mjs +51 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-BTY686R6.mjs +1368 -0
- package/dist/collector-run.mjs +9 -195
- package/dist/{command-output-DVcpw6eE.mjs → command-output-DnJMdEY-.mjs} +1 -1
- package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
- package/dist/{created-devices-CllH_8eb.mjs → created-devices-D5owjN4C.mjs} +2 -2
- package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-B6cMXZab.mjs} +2 -2
- package/dist/{deps-D9IcKqXS.mjs → deps-urbmfXig.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CroAIjjj.mjs +43 -0
- package/dist/{device-CjuuAJjQ.mjs → device-DZQjF7H5.mjs} +8 -7
- package/dist/device-capacity-BHwxNBlu.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +964 -0
- package/dist/device-ios-BadmeL2V.mjs +381 -0
- package/dist/{device-lease-5c3WrVRm.mjs → device-lease-D-hLqx1b.mjs} +43 -36
- package/dist/{device-pool-BiyDyPP-.mjs → device-lease-run-CqjShqWW.mjs} +6 -126
- package/dist/device-pool-CUaEWMMm.mjs +125 -0
- package/dist/{device-remote-D87zEzaq.mjs → device-remote-D5WVWqOq.mjs} +69 -163
- package/dist/{doctor-x9pnU9fq.mjs → doctor-Cimf-gGB.mjs} +241 -103
- package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-B9L4Ae0x.mjs} +15 -18
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-ko6mUAYD.mjs → gc-Bqy4bjEu.mjs} +599 -108
- package/dist/{android-cas-iZK3DOCr.mjs → gradle-BsO1MdsH.mjs} +8 -294
- package/dist/{guide-6R0VNFqI.mjs → guide-B_uyKTxW.mjs} +2511 -239
- package/dist/{guide-status-BZrFPIA_.mjs → guide-status-CjEZMAD4.mjs} +3 -3
- package/dist/hosted-client-a-WmqE2L.mjs +197 -0
- package/dist/hosted-ios-CIWelIqf.mjs +220 -0
- package/dist/hosted-logs-D5g041Q3.mjs +187 -0
- package/dist/hosted-macos-BSZyIb3y.mjs +135 -0
- package/dist/idle-DYVymG92.mjs +1099 -0
- package/dist/idle-shutdown-CTsDnAde.mjs +122 -0
- package/dist/in-use-DvBw0Kxo.mjs +130 -0
- package/dist/{ios-BwDPrnYQ.mjs → ios-BaInn3sW.mjs} +201 -10
- package/dist/ios-Cr1h5gnO.mjs +189 -0
- package/dist/{ios-P1f5nm2n.mjs → ios-aq3QoGI3.mjs} +1159 -633
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{ios-device-DGglU3E_.mjs → ios-device-FfCN_C8p.mjs} +12 -7
- package/dist/ios-state-DS5UpYTH.mjs +48 -0
- package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-2DBRizjo.mjs} +5 -5
- package/dist/logs-CHEVK8zD.mjs +371 -0
- package/dist/machines-BIBUdhpj.mjs +265 -0
- package/dist/macos-CSYEAFmF.mjs +473 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/maintenance-run.d.mts +4 -0
- package/dist/maintenance-run.mjs +254 -0
- package/dist/{metro-CcEo8Fl8.mjs → metro-BeK1ZPz1.mjs} +20 -120
- package/dist/metro-gateway-BJ-rxQAB.mjs +84 -0
- package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Bk_YXEmE.mjs} +6 -59
- package/dist/native-run-NaBrRFtQ.mjs +147 -0
- package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-DBzRnEKS.mjs} +9 -5
- package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
- package/dist/offload-worker.d.mts +122 -0
- package/dist/offload-worker.mjs +606 -0
- package/dist/{ownership-DyYDF5ww.mjs → ownership-DiA16AsN.mjs} +3 -2
- package/dist/ownership-hCkPzGmr.mjs +571 -0
- package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-BguS83ex.mjs → ports-R2k4Knz3.mjs} +3 -3
- package/dist/prebuild-D2fsca_Z.mjs +213 -0
- package/dist/preview-DhVbvPAZ.mjs +318 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-CWlvEaeN.mjs → project-Du91Ilvc.mjs} +74 -19
- package/dist/pull-request-pxnDCQzn.mjs +322 -0
- package/dist/pull-requests.d.mts +120 -0
- package/dist/pull-requests.mjs +2 -0
- package/dist/recordings-BIXOzVnr.mjs +37 -0
- package/dist/{reload-BiniwsSZ.mjs → reload-rM9jV1fz.mjs} +109 -24
- package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-C8-V13XN.mjs} +5 -5
- package/dist/run-f4vI6EnK.mjs +119 -0
- package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-CpPGmnmO.mjs} +33 -15
- package/dist/server-expo-CVqO2c35.mjs +2 -0
- package/dist/{server-expo-BVuwQ65v.mjs → server-expo-MC0rHlOC.mjs} +8 -12
- package/dist/settings-BBpMcDbD.mjs +25 -0
- package/dist/{settings-B-fsC-Om.mjs → settings-ZkDzkzvB.mjs} +22 -10
- package/dist/settings-oTSkkNrM.mjs +1439 -0
- package/dist/settings.schema.json +845 -97
- package/dist/{simslim-DrDN4WuV.mjs → simslim-B8-7AoTI.mjs} +8 -132
- package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-B8VrHxn1.mjs} +11 -8
- package/dist/{spawn-claims-Drw_o-Fb.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-jw19m8Nl.mjs +17 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CX8Ig-U2.mjs +2 -0
- package/dist/{start-s4RXp1wy.mjs → start-ClDfwXa4.mjs} +116 -65
- package/dist/state-3DwSQIBK.mjs +41 -0
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/{state-Dk9RVXI7.mjs → state-C1jB7Q8q.mjs} +70 -8
- package/dist/{state-DHqvsbqC.mjs → state-DcW6vOd_.mjs} +7 -4
- package/dist/stats-CEZ_i5je.mjs +77 -0
- package/dist/{status-BgAuxESg.mjs → status-BuvBFeII.mjs} +118 -20
- package/dist/{status-BsPAnfOI.mjs → status-Cs7VLg9D.mjs} +542 -283
- package/dist/status-DlKvVJBE.mjs +49 -0
- package/dist/stdout-reader-C8yjre1x.mjs +23 -0
- package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
- package/dist/stim-footprint.swift +32 -0
- package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
- package/dist/stop-B0Yxtmiy.mjs +48 -0
- package/dist/{stop-BzreOWJp.mjs → stop-Bffozsac.mjs} +83 -16
- package/dist/{stop-BWIF_6BK.mjs → stop-Dt_dM16A.mjs} +2 -2
- package/dist/stop-cause-CidxIqup.mjs +97 -0
- package/dist/supervisor-run.d.mts +43 -11
- package/dist/supervisor-run.mjs +363 -24
- package/dist/support-CAP8qDUF.mjs +316 -0
- package/dist/support-D4aYJniO.mjs +201 -0
- package/dist/teardown-CL6vDs2Y.mjs +727 -0
- package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DkUflduf.mjs} +364 -14
- package/dist/trigger-Bemu8ytw.mjs +65 -0
- package/dist/trigger-CXts6qt1.mjs +2 -0
- package/dist/warm-progress-CpGv3Wb6.mjs +732 -0
- package/dist/{web-BsQs1WlO.mjs → web-DWUaMp8P.mjs} +37 -21
- package/dist/web-run.mjs +310 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-B8-aJ1_5.mjs +371 -0
- package/dist/workspaces-BV4pdHFz.mjs +306 -0
- package/dist/{worktree-UrQWXSeb.mjs → worktree-K-xj9Db0.mjs} +625 -256
- package/dist/worktree-jnG8Iph5.mjs +2 -0
- package/package.json +10 -5
- package/shim/bundle-response.cjs +28 -12
- package/dist/activity-CYVDcrt3.mjs +0 -356
- package/dist/budget-CGDkhvv_.mjs +0 -1745
- package/dist/build-progress-DxKpwnaS.mjs +0 -247
- package/dist/idle-DXtx3RbX.mjs +0 -191
- package/dist/in-use-DlqBDKqY.mjs +0 -249
- package/dist/logs-Civ4gbBH.mjs +0 -486
- package/dist/merge-state-ytFQCeh4.mjs +0 -262
- package/dist/server-expo-DIHDhvGg.mjs +0 -2
- package/dist/settings-D61iNOsB.mjs +0 -629
- package/dist/start-Cetfvy8l.mjs +0 -2
- package/dist/stats-CFpFGlJV.mjs +0 -62
- package/dist/stats-CX1Z8Tca.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
- package/dist/worktree-BVrHsYZG.mjs +0 -752
- package/dist/worktree-CHWWvm5v.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
|
|
3
|
+
import { D as fingerprintProject, M as refingerprintAfterMutation } from "./device-lease-D-hLqx1b.mjs";
|
|
4
|
+
import { T as CCACHE_UNAVAILABLE, d as buildIos, k as resolveCcache, o as workerToolchain, s as manifestDigest } from "./toolchain-DkUflduf.mjs";
|
|
5
|
+
import { t as logLines } from "./run-f4vI6EnK.mjs";
|
|
6
|
+
import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-urbmfXig.mjs";
|
|
7
|
+
import { n as recordPrebuild, r as runPrebuild, t as planPrebuild } from "./prebuild-D2fsca_Z.mjs";
|
|
8
|
+
import { a as gradlewPath, i as buildAndroid, r as assembleTaskFor } from "./gradle-BsO1MdsH.mjs";
|
|
9
|
+
import { n as stageBundle, t as resolveBundleExtras } from "./stage-CzaiwFsI.mjs";
|
|
10
|
+
import { u as podAction } from "./support-D4aYJniO.mjs";
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
import { chmodSync, constants, copyFileSync, cpSync, createReadStream, existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { basename, dirname, join } from "node:path";
|
|
14
|
+
//#region src/offload/worker.ts
|
|
15
|
+
function emit(value) {
|
|
16
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
17
|
+
}
|
|
18
|
+
function note(phase, msg) {
|
|
19
|
+
emit({
|
|
20
|
+
type: "phase",
|
|
21
|
+
phase,
|
|
22
|
+
msg
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function relayWriter(file) {
|
|
26
|
+
let written = 0;
|
|
27
|
+
return {
|
|
28
|
+
file,
|
|
29
|
+
write(record) {
|
|
30
|
+
written += 1;
|
|
31
|
+
emit({
|
|
32
|
+
type: "log",
|
|
33
|
+
record
|
|
34
|
+
});
|
|
35
|
+
return true;
|
|
36
|
+
},
|
|
37
|
+
close: () => ({
|
|
38
|
+
file,
|
|
39
|
+
written,
|
|
40
|
+
dropped: 0,
|
|
41
|
+
lastError: null
|
|
42
|
+
}),
|
|
43
|
+
get written() {
|
|
44
|
+
return written;
|
|
45
|
+
},
|
|
46
|
+
dropped: 0,
|
|
47
|
+
lastError: null
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function blobPath(blobs, sha256) {
|
|
51
|
+
return join(blobs, sha256.slice(0, 2), sha256);
|
|
52
|
+
}
|
|
53
|
+
/** Whether every directory above `path` inside `root` is a real directory, so removing it cannot leave `root`. */
|
|
54
|
+
function realParents(root, path) {
|
|
55
|
+
let current = root;
|
|
56
|
+
for (const part of path.split("/").slice(0, -1)) {
|
|
57
|
+
current = join(current, part);
|
|
58
|
+
try {
|
|
59
|
+
if (!lstatSync(current).isDirectory()) return false;
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
/** Makes every directory above `path` inside `root` a real directory, replacing a file or symlink in the way. */
|
|
67
|
+
function ensureParents(root, path) {
|
|
68
|
+
let current = root;
|
|
69
|
+
for (const part of path.split("/").slice(0, -1)) {
|
|
70
|
+
current = join(current, part);
|
|
71
|
+
let stat;
|
|
72
|
+
try {
|
|
73
|
+
stat = lstatSync(current);
|
|
74
|
+
} catch {
|
|
75
|
+
mkdirSync(current);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (stat.isDirectory()) continue;
|
|
79
|
+
rmSync(current, { force: true });
|
|
80
|
+
mkdirSync(current);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Makes `src` hold exactly the manifest's files: a file the manifest names is rewritten unless this process
|
|
85
|
+
* wrote that same content there and nothing touched it since; a file that git would list as untracked and not
|
|
86
|
+
* ignored, and that the manifest does not name, is deleted, as is one the previous manifest named. Ignored
|
|
87
|
+
* files (dependencies, generated native projects) stay, and the fingerprint check covers them.
|
|
88
|
+
*/
|
|
89
|
+
function materialize(job, src) {
|
|
90
|
+
const recordFile = join(job.area, "mirror.json");
|
|
91
|
+
let previous = {};
|
|
92
|
+
try {
|
|
93
|
+
previous = JSON.parse(readFileSync(recordFile, "utf8"));
|
|
94
|
+
} catch {}
|
|
95
|
+
mkdirSync(src, { recursive: true });
|
|
96
|
+
if (!existsSync(join(src, ".git"))) {
|
|
97
|
+
getExecutor().runFile("git", [
|
|
98
|
+
"init",
|
|
99
|
+
"--quiet",
|
|
100
|
+
src
|
|
101
|
+
], { timeoutMs: 3e4 });
|
|
102
|
+
getExecutor().runFile("git", [
|
|
103
|
+
"-C",
|
|
104
|
+
src,
|
|
105
|
+
"config",
|
|
106
|
+
"core.excludesFile",
|
|
107
|
+
"/dev/null"
|
|
108
|
+
], { timeoutMs: 3e4 });
|
|
109
|
+
}
|
|
110
|
+
const next = {};
|
|
111
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
112
|
+
let written = 0;
|
|
113
|
+
for (const entry of job.manifest) {
|
|
114
|
+
wanted.add(entry.path);
|
|
115
|
+
const target = join(src, entry.path);
|
|
116
|
+
const known = previous[entry.path];
|
|
117
|
+
let stat = null;
|
|
118
|
+
try {
|
|
119
|
+
stat = lstatSync(target);
|
|
120
|
+
} catch {}
|
|
121
|
+
if (known && stat && known.sha256 === entry.sha256 && known.kind === entry.kind && stat.mtimeMs === known.mtimeMs && stat.size === known.size) {
|
|
122
|
+
next[entry.path] = known;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
ensureParents(src, entry.path);
|
|
126
|
+
if (stat) rmSync(target, {
|
|
127
|
+
recursive: true,
|
|
128
|
+
force: true
|
|
129
|
+
});
|
|
130
|
+
const blob = blobPath(job.blobs, entry.sha256);
|
|
131
|
+
if (entry.kind === "link") symlinkSync(readFileSync(blob, "utf8"), target);
|
|
132
|
+
else {
|
|
133
|
+
copyFileSync(blob, target, constants.COPYFILE_FICLONE);
|
|
134
|
+
chmodSync(target, entry.kind === "exec" ? 493 : 420);
|
|
135
|
+
}
|
|
136
|
+
const after = lstatSync(target);
|
|
137
|
+
next[entry.path] = {
|
|
138
|
+
sha256: entry.sha256,
|
|
139
|
+
kind: entry.kind,
|
|
140
|
+
mtimeMs: after.mtimeMs,
|
|
141
|
+
size: after.size
|
|
142
|
+
};
|
|
143
|
+
written += 1;
|
|
144
|
+
}
|
|
145
|
+
const untracked = getExecutor().runFile("git", [
|
|
146
|
+
"-C",
|
|
147
|
+
src,
|
|
148
|
+
"ls-files",
|
|
149
|
+
"-z",
|
|
150
|
+
"-o",
|
|
151
|
+
"--exclude-standard"
|
|
152
|
+
], {
|
|
153
|
+
untrimmed: true,
|
|
154
|
+
timeoutMs: 12e4
|
|
155
|
+
}).split("\0").filter(Boolean);
|
|
156
|
+
let removed = 0;
|
|
157
|
+
for (const path of /* @__PURE__ */ new Set([...untracked, ...Object.keys(previous)])) {
|
|
158
|
+
if (wanted.has(path) || !realParents(src, path)) continue;
|
|
159
|
+
try {
|
|
160
|
+
rmSync(join(src, path), { force: true });
|
|
161
|
+
removed += 1;
|
|
162
|
+
} catch {}
|
|
163
|
+
}
|
|
164
|
+
const tmp = `${recordFile}.${process.pid}.tmp`;
|
|
165
|
+
writeFileSync(tmp, JSON.stringify(next));
|
|
166
|
+
renameSync(tmp, recordFile);
|
|
167
|
+
return {
|
|
168
|
+
written,
|
|
169
|
+
removed
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function lockfileOf(src) {
|
|
173
|
+
if (existsSync(join(src, "pnpm-lock.yaml"))) return {
|
|
174
|
+
file: "pnpm-lock.yaml",
|
|
175
|
+
command: "pnpm",
|
|
176
|
+
args: (pkg) => [
|
|
177
|
+
"install",
|
|
178
|
+
"--frozen-lockfile",
|
|
179
|
+
...pkg ? ["--filter", `${pkg}...`] : []
|
|
180
|
+
]
|
|
181
|
+
};
|
|
182
|
+
if (existsSync(join(src, "yarn.lock"))) return {
|
|
183
|
+
file: "yarn.lock",
|
|
184
|
+
command: "yarn",
|
|
185
|
+
args: () => ["install", "--frozen-lockfile"]
|
|
186
|
+
};
|
|
187
|
+
if (existsSync(join(src, "package-lock.json"))) return {
|
|
188
|
+
file: "package-lock.json",
|
|
189
|
+
command: "npm",
|
|
190
|
+
args: () => ["ci"]
|
|
191
|
+
};
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
/** Installs JavaScript dependencies when the lockfile, or the install command, changed since the last install. */
|
|
195
|
+
async function ensureDependencies(job, src) {
|
|
196
|
+
const lock = lockfileOf(src);
|
|
197
|
+
if (!lock) return;
|
|
198
|
+
const args = lock.args(job.packageName);
|
|
199
|
+
const lockfile = readFileSync(join(src, lock.file));
|
|
200
|
+
const digest = createHash("sha256").update(lockfile).update(JSON.stringify(args)).digest("hex");
|
|
201
|
+
const marker = join(job.area, "dependencies");
|
|
202
|
+
const installed = () => writeFileSync(join(job.area, "lockfile"), createHash("sha256").update(lockfile).digest("hex"));
|
|
203
|
+
if (existsSync(join(src, job.project, "node_modules")) && existsSync(marker)) {
|
|
204
|
+
if (readFileSync(marker, "utf8") === digest) return installed();
|
|
205
|
+
}
|
|
206
|
+
note("deps", `${lock.command} ${args.join(" ")}`);
|
|
207
|
+
const child = getExecutor().spawn(lock.command, args, {
|
|
208
|
+
cwd: src,
|
|
209
|
+
env: {
|
|
210
|
+
...process.env,
|
|
211
|
+
CI: "1"
|
|
212
|
+
},
|
|
213
|
+
stdio: [
|
|
214
|
+
"ignore",
|
|
215
|
+
"pipe",
|
|
216
|
+
"pipe"
|
|
217
|
+
]
|
|
218
|
+
});
|
|
219
|
+
const tail = [];
|
|
220
|
+
const keep = (chunk) => {
|
|
221
|
+
tail.push(...String(chunk).split("\n").filter(Boolean));
|
|
222
|
+
tail.splice(0, Math.max(0, tail.length - 5));
|
|
223
|
+
};
|
|
224
|
+
child.stdout?.on("data", keep);
|
|
225
|
+
child.stderr?.on("data", keep);
|
|
226
|
+
const code = await new Promise((resolve, reject) => {
|
|
227
|
+
child.on("error", reject);
|
|
228
|
+
child.on("exit", resolve);
|
|
229
|
+
});
|
|
230
|
+
if (code !== 0) throw new Error(`${lock.command} ${args.join(" ")} exited with ${code}: ${tail.join(" | ")}`);
|
|
231
|
+
writeFileSync(marker, digest);
|
|
232
|
+
installed();
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* The generic simulator destination compiles arm64 and x86_64, so the worker names one of its own iPhone
|
|
236
|
+
* simulators on the client's runtime. It is a build destination only: nothing boots or installs on it.
|
|
237
|
+
*/
|
|
238
|
+
function destination(runtime) {
|
|
239
|
+
try {
|
|
240
|
+
const device = (JSON.parse(getExecutor().runFileQuiet("xcrun", [
|
|
241
|
+
"simctl",
|
|
242
|
+
"list",
|
|
243
|
+
"devices",
|
|
244
|
+
"available",
|
|
245
|
+
"-j"
|
|
246
|
+
], { timeoutMs: 2e4 }) ?? "{}").devices?.[runtime] ?? []).find((each) => each.name.startsWith("iPhone"));
|
|
247
|
+
return device ? `id=${device.udid}` : null;
|
|
248
|
+
} catch {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function sha256Of(path) {
|
|
253
|
+
const hash = createHash("sha256");
|
|
254
|
+
for await (const chunk of createReadStream(path)) hash.update(chunk);
|
|
255
|
+
return hash.digest("hex");
|
|
256
|
+
}
|
|
257
|
+
async function build(job) {
|
|
258
|
+
const timings = {
|
|
259
|
+
syncMs: 0,
|
|
260
|
+
depsMs: 0,
|
|
261
|
+
prebuildMs: 0,
|
|
262
|
+
podsMs: 0,
|
|
263
|
+
fingerprintMs: 0,
|
|
264
|
+
buildMs: 0,
|
|
265
|
+
packageMs: 0
|
|
266
|
+
};
|
|
267
|
+
const time = async (key, run) => {
|
|
268
|
+
const started = Date.now();
|
|
269
|
+
try {
|
|
270
|
+
return await run();
|
|
271
|
+
} finally {
|
|
272
|
+
timings[key] += Date.now() - started;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
const failed = (code, message) => ({
|
|
276
|
+
ok: false,
|
|
277
|
+
code,
|
|
278
|
+
message,
|
|
279
|
+
timings
|
|
280
|
+
});
|
|
281
|
+
const src = join(job.area, "src");
|
|
282
|
+
const root = join(src, job.project);
|
|
283
|
+
const log = relayWriter(join(job.area, "build.ndjson"));
|
|
284
|
+
const mirrored = await time("syncMs", () => materialize(job, src));
|
|
285
|
+
const realSrc = realpathSync(src);
|
|
286
|
+
const realRoot = realpathSync(root);
|
|
287
|
+
if (realRoot !== realSrc && !realRoot.startsWith(`${realSrc}/`)) return failed("bad-project", `${job.project} leaves the checkout.`);
|
|
288
|
+
note("sync", `${job.manifest.length} files, ${mirrored.written} written, ${mirrored.removed} removed`);
|
|
289
|
+
let fingerprint;
|
|
290
|
+
let compiled;
|
|
291
|
+
if (job.platform === "macos") {
|
|
292
|
+
fingerprint = await time("fingerprintMs", () => manifestDigest(job.manifest));
|
|
293
|
+
if (fingerprint !== job.expectedFingerprint) return failed("fingerprint-mismatch", `the manifest there fingerprints ${fingerprint.slice(0, 12)}, here ${job.expectedFingerprint.slice(0, 12)}`);
|
|
294
|
+
compiled = await compileMacos(job, root, log, time);
|
|
295
|
+
if (!compiled.ok) return failed(compiled.code, compiled.message);
|
|
296
|
+
} else {
|
|
297
|
+
try {
|
|
298
|
+
await time("depsMs", () => ensureDependencies(job, src));
|
|
299
|
+
} catch (error) {
|
|
300
|
+
return failed("deps-failed", error.message);
|
|
301
|
+
}
|
|
302
|
+
const platform = job.platform;
|
|
303
|
+
const initial = await time("fingerprintMs", () => fingerprintProject(root, { platform }));
|
|
304
|
+
if (!initial) return failed("no-fingerprint", "The build machine could not fingerprint the project.");
|
|
305
|
+
const plan = planPrebuild(root, platform, {
|
|
306
|
+
isExpo: job.isExpo,
|
|
307
|
+
fingerprint: initial.hash,
|
|
308
|
+
sources: initial.sources
|
|
309
|
+
});
|
|
310
|
+
if (plan === "refuse") return failed("prebuild-refused", `${platform}/ is not generated by prebuild and does not match.`);
|
|
311
|
+
const mutations = [];
|
|
312
|
+
if (plan === "generate" || plan === "regenerate") {
|
|
313
|
+
note("prebuild", plan === "generate" ? `generating ${platform}/` : `regenerating ${platform}/ with --clean`);
|
|
314
|
+
recordPrebuild(root, platform, null);
|
|
315
|
+
const result = await time("prebuildMs", () => runPrebuild(root, platform, log, { clean: plan === "regenerate" }));
|
|
316
|
+
if (result?.failed) return failed("prebuild-failed", result.reason ?? "expo prebuild failed.");
|
|
317
|
+
mutations.push("prebuild");
|
|
318
|
+
}
|
|
319
|
+
if (platform === "ios") {
|
|
320
|
+
const podState = readPodState(root);
|
|
321
|
+
const pods = podAction(podState, podsAreStale(podState.lockText, podState.manifestText));
|
|
322
|
+
if (pods.install) {
|
|
323
|
+
note("pods", `${pods.reason ?? "Pods are stale"} -> pod install`);
|
|
324
|
+
const result = await time("podsMs", () => runPodInstall(root, log, { onHeartbeat: (line) => note("pods", line) }));
|
|
325
|
+
if (result?.failed) return failed("pods-failed", result.reason ?? "pod install failed.");
|
|
326
|
+
mutations.push("pods");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
fingerprint = initial.hash;
|
|
330
|
+
if (mutations.length) {
|
|
331
|
+
const after = await time("fingerprintMs", () => refingerprintAfterMutation({
|
|
332
|
+
projectRoot: root,
|
|
333
|
+
platform,
|
|
334
|
+
previousHash: initial.hash
|
|
335
|
+
}));
|
|
336
|
+
if (!after) return failed("no-fingerprint", `No fingerprint after ${mutations.join(", ")}.`);
|
|
337
|
+
fingerprint = after.hash;
|
|
338
|
+
if (mutations.includes("prebuild")) recordPrebuild(root, platform, after.hash);
|
|
339
|
+
}
|
|
340
|
+
if (fingerprint !== job.expectedFingerprint) return failed("fingerprint-mismatch", `the checkout there fingerprints ${fingerprint.slice(0, 12)}, here ${job.expectedFingerprint.slice(0, 12)}`);
|
|
341
|
+
compiled = platform === "android" ? await compileAndroid(job, root, log, time) : await compileIos(job, root, log, time);
|
|
342
|
+
if (!compiled.ok) return failed(compiled.code, compiled.message);
|
|
343
|
+
const settled = await time("fingerprintMs", () => refingerprintAfterMutation({
|
|
344
|
+
projectRoot: root,
|
|
345
|
+
platform,
|
|
346
|
+
previousHash: fingerprint
|
|
347
|
+
}));
|
|
348
|
+
if (!settled || settled.moved) return failed("fingerprint-moved", "The inputs changed during the build there.");
|
|
349
|
+
}
|
|
350
|
+
const out = join(job.area, "out", job.job);
|
|
351
|
+
if (job.platform !== "macos") rmSync(out, {
|
|
352
|
+
recursive: true,
|
|
353
|
+
force: true
|
|
354
|
+
});
|
|
355
|
+
mkdirSync(out, { recursive: true });
|
|
356
|
+
const archive = join(out, "app.tgz");
|
|
357
|
+
const name = basename(compiled.path);
|
|
358
|
+
if (job.platform === "ios") cpSync(compiled.path, join(out, name), {
|
|
359
|
+
recursive: true,
|
|
360
|
+
verbatimSymlinks: true,
|
|
361
|
+
mode: constants.COPYFILE_FICLONE
|
|
362
|
+
});
|
|
363
|
+
await time("packageMs", () => getExecutor().runFileAsync("tar", [
|
|
364
|
+
"-czf",
|
|
365
|
+
archive,
|
|
366
|
+
"--options",
|
|
367
|
+
"gzip:compression-level=1",
|
|
368
|
+
"-C",
|
|
369
|
+
dirname(compiled.path),
|
|
370
|
+
name
|
|
371
|
+
], { timeoutMs: 6e5 }));
|
|
372
|
+
const sha256 = await time("packageMs", () => sha256Of(archive));
|
|
373
|
+
return {
|
|
374
|
+
ok: true,
|
|
375
|
+
artifact: {
|
|
376
|
+
path: archive,
|
|
377
|
+
name,
|
|
378
|
+
size: statSync(archive).size,
|
|
379
|
+
sha256
|
|
380
|
+
},
|
|
381
|
+
fingerprint,
|
|
382
|
+
compilationCache: compiled.cache,
|
|
383
|
+
timings
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
async function compileMacos(job, root, log, time) {
|
|
387
|
+
const options = job.macos;
|
|
388
|
+
if (!options) return {
|
|
389
|
+
ok: false,
|
|
390
|
+
code: "bad-request",
|
|
391
|
+
message: "The job has no SwiftPM options."
|
|
392
|
+
};
|
|
393
|
+
const src = join(job.area, "src");
|
|
394
|
+
const scratch = join(job.area, "macos", job.project.replaceAll("/", "_") || "root");
|
|
395
|
+
const run = async (args, capture = false) => {
|
|
396
|
+
const child = getExecutor().spawn("swift", args, {
|
|
397
|
+
cwd: root,
|
|
398
|
+
stdio: [
|
|
399
|
+
"ignore",
|
|
400
|
+
"pipe",
|
|
401
|
+
"pipe"
|
|
402
|
+
]
|
|
403
|
+
});
|
|
404
|
+
let stdout = "";
|
|
405
|
+
let firstError = null;
|
|
406
|
+
const tail = [];
|
|
407
|
+
const write = (msg) => {
|
|
408
|
+
const plain = stripAnsi(msg);
|
|
409
|
+
if (firstError === null && /\.swift:\d+:\d+: error:/.test(plain)) firstError = plain;
|
|
410
|
+
tail.push(plain);
|
|
411
|
+
if (tail.length > 3) tail.shift();
|
|
412
|
+
note("build", msg);
|
|
413
|
+
log.write({
|
|
414
|
+
src: "build",
|
|
415
|
+
platform: "macos",
|
|
416
|
+
level: "debug",
|
|
417
|
+
msg
|
|
418
|
+
});
|
|
419
|
+
};
|
|
420
|
+
child.stdout?.on("data", (chunk) => {
|
|
421
|
+
if (capture) stdout += chunk.toString("utf8");
|
|
422
|
+
});
|
|
423
|
+
if (child.stdout) logLines(child.stdout, write);
|
|
424
|
+
if (child.stderr) logLines(child.stderr, write);
|
|
425
|
+
await new Promise((done, reject) => {
|
|
426
|
+
child.once("error", reject);
|
|
427
|
+
child.once("close", (code) => code === 0 ? done() : reject(new Error(firstError ?? (tail.join(" | ") || `swift build failed (${code})`))));
|
|
428
|
+
});
|
|
429
|
+
return stdout.trim();
|
|
430
|
+
};
|
|
431
|
+
try {
|
|
432
|
+
const extras = resolveBundleExtras(src, src, options.resources, options.assetCatalog);
|
|
433
|
+
return await time("buildMs", async () => {
|
|
434
|
+
await run([
|
|
435
|
+
"build",
|
|
436
|
+
"-c",
|
|
437
|
+
"debug",
|
|
438
|
+
"--product",
|
|
439
|
+
options.product,
|
|
440
|
+
"--scratch-path",
|
|
441
|
+
scratch,
|
|
442
|
+
"--cache-path",
|
|
443
|
+
job.swiftpmCache
|
|
444
|
+
]);
|
|
445
|
+
const bin = await run([
|
|
446
|
+
"build",
|
|
447
|
+
"-c",
|
|
448
|
+
"debug",
|
|
449
|
+
"--scratch-path",
|
|
450
|
+
scratch,
|
|
451
|
+
"--cache-path",
|
|
452
|
+
job.swiftpmCache,
|
|
453
|
+
"--show-bin-path"
|
|
454
|
+
], true);
|
|
455
|
+
const bundle = join(job.area, "out", job.job, `${options.product}.app`);
|
|
456
|
+
stageBundle(root, options.product, options.infoPlist, bin, bundle, options.bundleId, extras);
|
|
457
|
+
return {
|
|
458
|
+
ok: true,
|
|
459
|
+
path: bundle,
|
|
460
|
+
cache: {}
|
|
461
|
+
};
|
|
462
|
+
});
|
|
463
|
+
} catch (error) {
|
|
464
|
+
return {
|
|
465
|
+
ok: false,
|
|
466
|
+
code: "swift-failed",
|
|
467
|
+
message: error.message
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
async function compileIos(job, root, log, time) {
|
|
472
|
+
const runtime = job.runtime ?? "";
|
|
473
|
+
const target = destination(runtime);
|
|
474
|
+
if (!target) return {
|
|
475
|
+
ok: false,
|
|
476
|
+
code: "no-runtime",
|
|
477
|
+
message: `There is no iPhone simulator on ${runtime} to build for.`
|
|
478
|
+
};
|
|
479
|
+
note("build", `xcodebuild for ${runtime}`);
|
|
480
|
+
const built = await time("buildMs", () => buildIos({
|
|
481
|
+
root,
|
|
482
|
+
destination: target,
|
|
483
|
+
logWriter: log,
|
|
484
|
+
...job.scheme ? { scheme: job.scheme } : {},
|
|
485
|
+
...job.configuration ? { configuration: job.configuration } : {},
|
|
486
|
+
...job.optimizations ? { optimizations: job.optimizations } : {},
|
|
487
|
+
onHeartbeat: (line) => note("build", line),
|
|
488
|
+
onNote: (line) => note("build", line)
|
|
489
|
+
}));
|
|
490
|
+
if (!built.ok) {
|
|
491
|
+
const first = built.diagnostics[0]?.message;
|
|
492
|
+
return {
|
|
493
|
+
ok: false,
|
|
494
|
+
code: built.code,
|
|
495
|
+
message: first ?? (built.tail.slice(-3).join(" | ") || "xcodebuild failed.")
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
return {
|
|
499
|
+
ok: true,
|
|
500
|
+
path: built.appPath,
|
|
501
|
+
cache: built.compilationCache
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Stops the Gradle daemons of this client's Gradle home. A daemon calls setsid, so it leaves the build's
|
|
506
|
+
* process group and would outlive the job and its claim.
|
|
507
|
+
*/
|
|
508
|
+
function stopGradleDaemons(root, timeoutMs) {
|
|
509
|
+
const gradlew = gradlewPath(root);
|
|
510
|
+
if (!existsSync(gradlew)) return;
|
|
511
|
+
getExecutor().runFileQuiet(gradlew, ["--stop"], {
|
|
512
|
+
cwd: dirname(gradlew),
|
|
513
|
+
timeoutMs
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Gradle reads `org.gradle.daemon.idletimeout` from the user home's gradle.properties, which overrides the
|
|
518
|
+
* project's, so the daemon exits after that idle time instead of Gradle's three hours.
|
|
519
|
+
*/
|
|
520
|
+
function limitDaemonIdle(idleMs) {
|
|
521
|
+
const home = process.env.GRADLE_USER_HOME;
|
|
522
|
+
if (!home) return;
|
|
523
|
+
const file = join(home, "gradle.properties");
|
|
524
|
+
const wanted = `org.gradle.daemon.idletimeout=${idleMs}\n`;
|
|
525
|
+
try {
|
|
526
|
+
if (readFileSync(file, "utf8") === wanted) return;
|
|
527
|
+
} catch {}
|
|
528
|
+
mkdirSync(home, { recursive: true });
|
|
529
|
+
writeFileSync(file, wanted);
|
|
530
|
+
}
|
|
531
|
+
async function compileAndroid(job, root, log, time) {
|
|
532
|
+
const options = job.android;
|
|
533
|
+
if (!options) return {
|
|
534
|
+
ok: false,
|
|
535
|
+
code: "bad-request",
|
|
536
|
+
message: "The job has no Gradle options."
|
|
537
|
+
};
|
|
538
|
+
const idleMs = job.gradleDaemonIdleMs ?? 0;
|
|
539
|
+
const keepDaemon = idleMs > 0;
|
|
540
|
+
limitDaemonIdle(keepDaemon ? idleMs : 6e4);
|
|
541
|
+
const onNote = (line) => note("build", line);
|
|
542
|
+
const stop = () => {
|
|
543
|
+
stopGradleDaemons(root, 4e3);
|
|
544
|
+
process.exit(143);
|
|
545
|
+
};
|
|
546
|
+
process.once("SIGTERM", stop);
|
|
547
|
+
note("build", `gradle ${assembleTaskFor(options.variant)} for ${options.abi ?? "every ABI"}`);
|
|
548
|
+
try {
|
|
549
|
+
const built = await time("buildMs", () => buildAndroid({
|
|
550
|
+
root,
|
|
551
|
+
logWriter: log,
|
|
552
|
+
variant: options.variant,
|
|
553
|
+
abi: options.abi
|
|
554
|
+
}, {
|
|
555
|
+
buildCache: options.gradleBuildCache,
|
|
556
|
+
pch: options.pch,
|
|
557
|
+
compilerCacheDisabled: options.compilerCache === "none",
|
|
558
|
+
ccache: options.compilerCache === "ccache" ? resolveCcache({
|
|
559
|
+
root,
|
|
560
|
+
onNote
|
|
561
|
+
}) : null,
|
|
562
|
+
onHeartbeat: onNote,
|
|
563
|
+
onNote
|
|
564
|
+
}));
|
|
565
|
+
if (!built.ok) {
|
|
566
|
+
const first = built.diagnostics[0]?.message;
|
|
567
|
+
return {
|
|
568
|
+
ok: false,
|
|
569
|
+
code: built.code,
|
|
570
|
+
message: first ?? (built.lastLines.slice(-3).join(" | ") || built.reason)
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
return {
|
|
574
|
+
ok: true,
|
|
575
|
+
path: built.apkPath,
|
|
576
|
+
cache: built.ccache ?? CCACHE_UNAVAILABLE
|
|
577
|
+
};
|
|
578
|
+
} finally {
|
|
579
|
+
process.off("SIGTERM", stop);
|
|
580
|
+
if (!keepDaemon) stopGradleDaemons(root, 6e4);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
async function main() {
|
|
584
|
+
const mode = process.argv[2];
|
|
585
|
+
if (mode === "offer") return emit(workerToolchain());
|
|
586
|
+
if (mode === "build") {
|
|
587
|
+
const chunks = [];
|
|
588
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
589
|
+
return emit({
|
|
590
|
+
type: "result",
|
|
591
|
+
...await build(JSON.parse(Buffer.concat(chunks).toString("utf8")))
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
process.stderr.write("usage: offload-worker offer | build < job.json\n");
|
|
595
|
+
process.exitCode = 2;
|
|
596
|
+
}
|
|
597
|
+
main().catch((error) => {
|
|
598
|
+
emit({
|
|
599
|
+
type: "result",
|
|
600
|
+
ok: false,
|
|
601
|
+
code: "worker-crashed",
|
|
602
|
+
message: String(error?.message ?? error)
|
|
603
|
+
});
|
|
604
|
+
});
|
|
605
|
+
//#endregion
|
|
606
|
+
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
2
|
+
import { o as pidExists } from "./metro-BeK1ZPz1.mjs";
|
|
3
|
+
import { c as writeWorkspaceState, o as withWorkspaceStateLock, r as readWorkspaceState } from "./workspace-state-B8-aJ1_5.mjs";
|
|
3
4
|
import { realpathSync } from "node:fs";
|
|
4
5
|
//#region src/collector/state.ts
|
|
5
6
|
function collectorRoot(root) {
|