stim 1.16.0 → 1.17.1
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/dist/{activity-BxwdD81S.mjs → activity-IRvJY_ru.mjs} +23 -3
- package/dist/{agent-device-usage-output-Dpih1Tfa.mjs → agent-device-usage-output-BK41vnzN.mjs} +3 -3
- package/dist/{android-Ift4kVvt.mjs → android-B6rDWrTm.mjs} +681 -319
- package/dist/{android-B_NumVyQ.mjs → android-B_YNZy61.mjs} +7 -43
- package/dist/{android-r2rBL8kV.mjs → android-DE4v59Mb.mjs} +12 -3
- package/dist/{android-cas-8U4DPqeR.mjs → android-cas-ZFpjJBL_.mjs} +6 -5
- package/dist/{app-install-CKWdbXIX.mjs → app-install-VPkI5WEg.mjs} +6 -5
- package/dist/{budget-DjrURfQn.mjs → budget-CUDz870h.mjs} +62 -25
- package/dist/{build-plan-DjeSb2Xl.mjs → build-plan-BJSXzsCL.mjs} +345 -86
- package/dist/{idle-DYVymG92.mjs → build-progress-D0WkjCPd.mjs} +170 -233
- package/dist/{build-slots-rUk77xqh.mjs → build-slots-41v_d2x9.mjs} +35 -25
- package/dist/{cli-BkYZ_6hy.mjs → cli-BLQqDGlX.mjs} +17 -17
- package/dist/cli.mjs +1 -1
- package/dist/{client-BTY686R6.mjs → client-CxNotugx.mjs} +313 -44
- package/dist/collector-run.mjs +3 -3
- package/dist/{command-output-DnJMdEY-.mjs → command-output-CDAIFD-8.mjs} +3 -3
- package/dist/{created-devices-D5owjN4C.mjs → created-devices-CpvzBL25.mjs} +1 -1
- package/dist/{dependency-state-B6cMXZab.mjs → dependency-state-CLcBHH2M.mjs} +1 -1
- package/dist/{deps-urbmfXig.mjs → deps-CVxlsRFn.mjs} +1 -1
- package/dist/{dev-client-CroAIjjj.mjs → dev-client-B-XC4uRH.mjs} +2 -2
- package/dist/{device-DZQjF7H5.mjs → device-C8IOoJPv.mjs} +7 -7
- package/dist/device-capacity-ZC4XSZ4R.mjs +580 -0
- package/dist/device-host-worker.mjs +436 -154
- package/dist/{device-ios-BadmeL2V.mjs → device-ios-C2Um-XUR.mjs} +75 -44
- package/dist/{device-lease-D-hLqx1b.mjs → device-lease-DpoS36_u.mjs} +2 -2
- package/dist/{device-lease-run-CqjShqWW.mjs → device-lease-run-B8YltIH_.mjs} +3 -3
- package/dist/{device-pool-CUaEWMMm.mjs → device-pool-3o7s5lo4.mjs} +2 -2
- package/dist/{device-remote-D5WVWqOq.mjs → device-remote-hFSkpfQu.mjs} +12 -12
- package/dist/{doctor-Cimf-gGB.mjs → doctor-BF_435OC.mjs} +40 -58
- package/dist/{error-diagnostics-B9L4Ae0x.mjs → error-diagnostics-C-NMnhrk.mjs} +7 -7
- package/dist/{gc-Bqy4bjEu.mjs → gc-BsWKa_-d.mjs} +313 -30
- package/dist/{gradle-BsO1MdsH.mjs → gradle-bsBRy6i9.mjs} +3 -3
- package/dist/{guide-B_uyKTxW.mjs → guide-DC3n6-NH.mjs} +1776 -655
- package/dist/{guide-status-CjEZMAD4.mjs → guide-status-Du-ZQ3FD.mjs} +1 -1
- package/dist/hosted-android-DgU31wY3.mjs +32 -0
- package/dist/{hosted-client-a-WmqE2L.mjs → hosted-client-CdSoH-G6.mjs} +5 -6
- package/dist/hosted-ios-BTaVj4Jb.mjs +15 -0
- package/dist/{hosted-logs-D5g041Q3.mjs → hosted-logs-SxfBvSvc.mjs} +16 -16
- package/dist/{hosted-macos-BSZyIb3y.mjs → hosted-macos-CT9E3meL.mjs} +4 -4
- package/dist/{hosted-ios-CIWelIqf.mjs → hosted-native-CZLOrMrN.mjs} +77 -42
- package/dist/idle-BXG__1BA.mjs +176 -0
- package/dist/{idle-shutdown-CTsDnAde.mjs → idle-shutdown-IGyNV8Cr.mjs} +25 -17
- package/dist/{in-use-DvBw0Kxo.mjs → in-use-CvGOUn-x.mjs} +11 -11
- package/dist/{ios-aq3QoGI3.mjs → ios-C7JuT1bI.mjs} +173 -91
- package/dist/{ios-BaInn3sW.mjs → ios-DSfnPfse.mjs} +4 -4
- package/dist/{ios-device-FfCN_C8p.mjs → ios-device-pAN4t54-.mjs} +1 -1
- package/dist/ios-state-8L3lgum6.mjs +89 -0
- package/dist/{launch-verify-2DBRizjo.mjs → launch-verify-lTnWZikR.mjs} +2 -2
- package/dist/{logs-CHEVK8zD.mjs → logs-DNxKcok9.mjs} +36 -23
- package/dist/{macos-CSYEAFmF.mjs → macos-BEs8cwKx.mjs} +75 -34
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +2 -2
- package/dist/{metro-BeK1ZPz1.mjs → metro-g8NqiJp-.mjs} +1 -1
- package/dist/{metro-gateway-BJ-rxQAB.mjs → metro-gateway-CHqK0p-a.mjs} +22 -3
- package/dist/{named-ports-Bk_YXEmE.mjs → named-ports-C8m8EQs2.mjs} +2 -2
- package/dist/{native-run-NaBrRFtQ.mjs → native-run-D1Q56rAD.mjs} +17 -6
- package/dist/{native-runtime-DBzRnEKS.mjs → native-runtime-YhaSxP4v.mjs} +6 -6
- package/dist/offload-worker.mjs +9 -9
- package/dist/{teardown-CL6vDs2Y.mjs → ownership-BMLqyBgJ.mjs} +603 -26
- package/dist/{ownership-DiA16AsN.mjs → ownership-DyRQru0q.mjs} +2 -2
- package/dist/{ports-R2k4Knz3.mjs → ports-4nYqxPWC.mjs} +2 -2
- package/dist/{prebuild-D2fsca_Z.mjs → prebuild-D7RUMkwN.mjs} +3 -3
- package/dist/{preview-DhVbvPAZ.mjs → preview-C_JjkEy4.mjs} +7 -7
- package/dist/{project-Du91Ilvc.mjs → project-D47Rh0ly.mjs} +7 -2
- package/dist/{recordings-BIXOzVnr.mjs → recordings-BNgsD1Tr.mjs} +1 -1
- package/dist/{reload-rM9jV1fz.mjs → reload-byOjE3P4.mjs} +62 -35
- package/dist/{remote-cache-C8-V13XN.mjs → remote-cache-Ci4DQYYj.mjs} +3 -3
- package/dist/{run-f4vI6EnK.mjs → run-CkE9y0nc.mjs} +1 -1
- package/dist/{server-bare-CpPGmnmO.mjs → server-bare-BkrSxSsZ.mjs} +1 -1
- package/dist/{server-expo-MC0rHlOC.mjs → server-expo-CHTyXD0G.mjs} +2 -2
- package/dist/server-expo-CeakhI8P.mjs +2 -0
- package/dist/{settings-oTSkkNrM.mjs → settings-Cfd-0r2d.mjs} +10 -9
- package/dist/{settings-ZkDzkzvB.mjs → settings-SR9OmW9h.mjs} +3 -3
- package/dist/settings.schema.json +123 -76
- package/dist/{simslim-B8-7AoTI.mjs → simslim-BWNrc3M3.mjs} +3 -3
- package/dist/{slot-launch-B8VrHxn1.mjs → slot-launch-DmjBmpQV.mjs} +8 -8
- package/dist/{start-CX8Ig-U2.mjs → start-BEP-XmEA.mjs} +1 -1
- package/dist/{start-ClDfwXa4.mjs → start-BHIersSm.mjs} +11 -11
- package/dist/{state-DcW6vOd_.mjs → state-BKa8wNN5.mjs} +1 -1
- package/dist/{state-3DwSQIBK.mjs → state-DyaNTgfR.mjs} +1 -1
- package/dist/{state-C1jB7Q8q.mjs → state-PeQiJuIu.mjs} +2 -2
- package/dist/{stats-CEZ_i5je.mjs → stats-Bq4fJOdB.mjs} +7 -4
- package/dist/{status-Cs7VLg9D.mjs → status-CqeWbIWW.mjs} +128 -38
- package/dist/{status-BuvBFeII.mjs → status-CzS4bPO9.mjs} +4 -4
- package/dist/{stop-Bffozsac.mjs → stop-Cj01je8D.mjs} +48 -27
- package/dist/{stop-B0Yxtmiy.mjs → stop-D03prQnW.mjs} +4 -4
- package/dist/{stop-Dt_dM16A.mjs → stop-DOxwkH4j.mjs} +2 -2
- package/dist/{stop-cause-CidxIqup.mjs → stop-cause-rhmGfwvt.mjs} +1 -1
- package/dist/supervisor-run.d.mts +7 -4
- package/dist/supervisor-run.mjs +26 -28
- package/dist/{support-D4aYJniO.mjs → support-BE-tbOP9.mjs} +45 -20
- package/dist/{support-CAP8qDUF.mjs → support-WvD__tSV.mjs} +7 -7
- package/dist/{toolchain-DkUflduf.mjs → toolchain-CdrxgUeA.mjs} +8 -8
- package/dist/{warm-progress-CpGv3Wb6.mjs → warm-progress-DF4JRvYI.mjs} +3 -3
- package/dist/watchman-APYjXSQa.mjs +48 -0
- package/dist/{web-DWUaMp8P.mjs → web-DddUdJzr.mjs} +12 -13
- package/dist/web-run.mjs +4 -4
- package/dist/{workspace-process-lock-BL7Q0HCO.mjs → workspace-process-lock-2mNzOlaB.mjs} +3 -2
- package/dist/{workspace-state-B8-aJ1_5.mjs → workspace-state-DqcCbpE7.mjs} +2 -2
- package/dist/{workspaces-BV4pdHFz.mjs → workspaces-Bcib97-6.mjs} +3 -3
- package/dist/{worktree-K-xj9Db0.mjs → worktree-AK_m-d_m.mjs} +141 -40
- package/dist/{worktree-jnG8Iph5.mjs → worktree-CsAjSmEo.mjs} +1 -1
- package/package.json +5 -5
- package/dist/device-capacity-BHwxNBlu.mjs +0 -136
- package/dist/ios-state-DS5UpYTH.mjs +0 -48
- package/dist/machines-BIBUdhpj.mjs +0 -265
- package/dist/ownership-hCkPzGmr.mjs +0 -571
- package/dist/server-expo-CVqO2c35.mjs +0 -2
|
@@ -1,62 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { D as withConfigLock$1, H as projectDeviceSlots } from "./config-D0DbpZtM.mjs";
|
|
1
|
+
import { D as withConfigLock$1 } from "./config-D0DbpZtM.mjs";
|
|
3
2
|
import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
4
|
-
import { a as formatElapsed,
|
|
5
|
-
import { a as updateWorkspaceState,
|
|
6
|
-
import { i as recordGcResult } from "./in-use-DvBw0Kxo.mjs";
|
|
7
|
-
import { o as idleForMs, r as createActivityReader } from "./activity-BxwdD81S.mjs";
|
|
8
|
-
import { z as ownedAvdSerialResolver } from "./android-B_NumVyQ.mjs";
|
|
9
|
-
import { i as teardownOwnedAvd, o as teardownOwnedIosSim } from "./teardown-CL6vDs2Y.mjs";
|
|
3
|
+
import { a as formatElapsed, u as plural } from "./command-output-CDAIFD-8.mjs";
|
|
4
|
+
import { a as updateWorkspaceState, t as clearWorkspaceStateKey } from "./workspace-state-DqcCbpE7.mjs";
|
|
10
5
|
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
11
6
|
import { dirname } from "node:path";
|
|
12
|
-
import { BUILD_HISTORY_KEY, BUILD_HISTORY_LIMIT, BUILD_PHASES, LAST_BUILD_KEYS, STATS_VERSION, decodeStats, parseMissReason, readRunEstimates, readStats as readStats$1, statsFile, statsProjectKey as statsProjectKey$1, trimSamples, wholePhases, workspaceBuildDetailFile } from "@stim-cli/core/state";
|
|
13
|
-
import chalk from "chalk";
|
|
14
|
-
//#region src/watchman.ts
|
|
15
|
-
/** Runs one watchman command with `--no-spawn`, so Stim never starts a daemon, and parses its JSON answer. */
|
|
16
|
-
const runWatchman = async (args, timeoutMs) => JSON.parse(await getExecutor().runFileAsync("watchman", ["--no-spawn", ...args], { timeoutMs }));
|
|
17
|
-
function parseWatchRoots(payload) {
|
|
18
|
-
const roots = payload?.roots;
|
|
19
|
-
if (!Array.isArray(roots)) return null;
|
|
20
|
-
return roots.filter((root) => typeof root === "string");
|
|
21
|
-
}
|
|
22
|
-
function parseSubscriberNames(payload) {
|
|
23
|
-
if (!payload || typeof payload !== "object" || "error" in payload) return null;
|
|
24
|
-
const subscribers = payload.subscribers;
|
|
25
|
-
if (subscribers === void 0) return [];
|
|
26
|
-
if (!Array.isArray(subscribers)) return null;
|
|
27
|
-
const names = [];
|
|
28
|
-
for (const subscriber of subscribers) {
|
|
29
|
-
const name = subscriber?.info?.name;
|
|
30
|
-
if (typeof name !== "string") return null;
|
|
31
|
-
names.push(name);
|
|
32
|
-
}
|
|
33
|
-
return names;
|
|
34
|
-
}
|
|
35
|
-
function parseTriggerCount(payload) {
|
|
36
|
-
const triggers = payload?.triggers;
|
|
37
|
-
return Array.isArray(triggers) ? triggers.length : null;
|
|
38
|
-
}
|
|
39
|
-
function parseWatchmanPid(payload) {
|
|
40
|
-
const pid = payload?.pid;
|
|
41
|
-
return typeof pid === "number" && Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
42
|
-
}
|
|
43
|
-
/** The connected clients in a `debug-status` answer, or null when the answer does not list them. */
|
|
44
|
-
function parseWatchmanClients(payload) {
|
|
45
|
-
if (!payload || typeof payload !== "object" || "error" in payload) return null;
|
|
46
|
-
const clients = payload.clients;
|
|
47
|
-
if (!Array.isArray(clients)) return null;
|
|
48
|
-
const parsed = [];
|
|
49
|
-
for (const client of clients) {
|
|
50
|
-
const peer = client?.peer;
|
|
51
|
-
if (typeof peer?.pid !== "number") return null;
|
|
52
|
-
parsed.push({
|
|
53
|
-
pid: peer.pid,
|
|
54
|
-
name: typeof peer.name === "string" ? peer.name : null
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
return parsed;
|
|
58
|
-
}
|
|
59
|
-
//#endregion
|
|
7
|
+
import { BUILD_HISTORY_KEY, BUILD_HISTORY_LIMIT, BUILD_PHASES, LAST_BUILD_KEYS, STATS_VERSION, decodeStats, isJsonObject, parseMissReason, readRunEstimates, readStats as readStats$1, statsFile, statsProjectKey as statsProjectKey$1, trimCapacityRefusals, trimCapacityWaits, trimSamples, wholePhases, workspaceBuildDetailFile } from "@stim-cli/core/state";
|
|
60
8
|
//#region src/engine/stats.ts
|
|
61
9
|
const PLACEMENT_MAX_AGE_MS = 6048e5;
|
|
62
10
|
function emptyStats() {
|
|
@@ -116,12 +64,16 @@ function updateStats(record, run, now) {
|
|
|
116
64
|
[placement.machine]: applyPlacement(buildMachines?.[placement.machine], placement)
|
|
117
65
|
};
|
|
118
66
|
}
|
|
67
|
+
const capacityRefusals = trimCapacityRefusals(record.capacityRefusals ?? [], now);
|
|
68
|
+
const capacityWaits = trimCapacityWaits(record.capacityWaits ?? [], now);
|
|
119
69
|
return {
|
|
120
70
|
version: STATS_VERSION,
|
|
121
71
|
machine,
|
|
122
72
|
projects,
|
|
123
73
|
...Object.keys(history).length ? { history } : {},
|
|
124
74
|
...placements?.length ? { placements } : {},
|
|
75
|
+
...capacityRefusals.length ? { capacityRefusals } : {},
|
|
76
|
+
...capacityWaits.length ? { capacityWaits } : {},
|
|
125
77
|
...buildMachines && Object.keys(buildMachines).length ? { buildMachines } : {}
|
|
126
78
|
};
|
|
127
79
|
}
|
|
@@ -130,6 +82,7 @@ function buildPlacement(run, before, at) {
|
|
|
130
82
|
const buildMs = wholeMs(placement.decision === "offloaded" ? placement.buildMs : run.coldBuildMs);
|
|
131
83
|
const localEstimateMs = wholeMs(before?.lastColdBuildMs);
|
|
132
84
|
const slotWaitMs = wholeMs(placement.slotWaitMs);
|
|
85
|
+
const deviceSlotWaitMs = wholeMs(placement.deviceSlotWaitMs);
|
|
133
86
|
return {
|
|
134
87
|
at,
|
|
135
88
|
project: run.projectKey,
|
|
@@ -139,6 +92,7 @@ function buildPlacement(run, before, at) {
|
|
|
139
92
|
...placement.machine ? { machine: placement.machine } : {},
|
|
140
93
|
...buildMs > 0 ? { buildMs } : {},
|
|
141
94
|
...slotWaitMs > 0 ? { slotWaitMs } : {},
|
|
95
|
+
...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {},
|
|
142
96
|
...localEstimateMs > 0 ? { localEstimateMs } : {},
|
|
143
97
|
...run.failed ? { failed: true } : {}
|
|
144
98
|
};
|
|
@@ -179,12 +133,53 @@ function recordRunStats(run, now) {
|
|
|
179
133
|
};
|
|
180
134
|
});
|
|
181
135
|
}
|
|
136
|
+
function recordCapacityRefusal(event, now) {
|
|
137
|
+
try {
|
|
138
|
+
withConfigLock$1(() => {
|
|
139
|
+
const path = statsFile();
|
|
140
|
+
const loaded = loadForUpdate(path, now, false);
|
|
141
|
+
if (!loaded.record || loaded.newerVersion !== null) return;
|
|
142
|
+
const capacityRefusals = trimCapacityRefusals([...loaded.record.capacityRefusals ?? [], {
|
|
143
|
+
...event,
|
|
144
|
+
at: new Date(now).toISOString(),
|
|
145
|
+
kind: "device"
|
|
146
|
+
}], now);
|
|
147
|
+
writeStats(path, {
|
|
148
|
+
...loaded.record,
|
|
149
|
+
capacityRefusals
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
} catch {}
|
|
153
|
+
}
|
|
154
|
+
function recordCapacityWait(event, now) {
|
|
155
|
+
try {
|
|
156
|
+
withConfigLock$1(() => {
|
|
157
|
+
const path = statsFile();
|
|
158
|
+
const loaded = loadForUpdate(path, now, false);
|
|
159
|
+
if (!loaded.record || loaded.newerVersion !== null) return;
|
|
160
|
+
const capacityWaits = trimCapacityWaits([...loaded.record.capacityWaits ?? [], {
|
|
161
|
+
platform: event.platform,
|
|
162
|
+
max: event.max,
|
|
163
|
+
workspace: event.workspace,
|
|
164
|
+
ms: wholeMs(event.ms),
|
|
165
|
+
...event.reclaimed && Number.isInteger(event.reclaimed) && event.reclaimed > 0 ? { reclaimed: event.reclaimed } : {},
|
|
166
|
+
at: new Date(now).toISOString(),
|
|
167
|
+
kind: "device-wait"
|
|
168
|
+
}], now);
|
|
169
|
+
writeStats(path, {
|
|
170
|
+
...loaded.record,
|
|
171
|
+
capacityWaits
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
} catch {}
|
|
175
|
+
}
|
|
182
176
|
function createRunRecorder({ platform, write, now, note, phases, deviceSetup }) {
|
|
183
177
|
let projectKey = null;
|
|
184
178
|
let cacheKey = null;
|
|
185
179
|
let coldBuildMs = 0;
|
|
186
180
|
let podsMs = 0;
|
|
187
181
|
let placement = null;
|
|
182
|
+
let deviceSlotWaitMs = 0;
|
|
188
183
|
let recorded = false;
|
|
189
184
|
return {
|
|
190
185
|
setProject(key) {
|
|
@@ -199,6 +194,12 @@ function createRunRecorder({ platform, write, now, note, phases, deviceSetup })
|
|
|
199
194
|
setPodsMs(ms) {
|
|
200
195
|
podsMs = wholeMs(ms);
|
|
201
196
|
},
|
|
197
|
+
addDeviceSlotWaitMs(ms) {
|
|
198
|
+
deviceSlotWaitMs += wholeMs(ms);
|
|
199
|
+
},
|
|
200
|
+
deviceSlotWaitMs() {
|
|
201
|
+
return deviceSlotWaitMs || void 0;
|
|
202
|
+
},
|
|
202
203
|
setPlacement(next) {
|
|
203
204
|
placement = next;
|
|
204
205
|
},
|
|
@@ -219,7 +220,10 @@ function createRunRecorder({ platform, write, now, note, phases, deviceSetup })
|
|
|
219
220
|
...podsMs > 0 ? { podsMs } : {},
|
|
220
221
|
...Object.keys(ran).length ? { phases: ran } : {},
|
|
221
222
|
...failed || deviceSetup?.() === void 0 ? {} : { deviceSetup: deviceSetup() },
|
|
222
|
-
...placement ? { placement
|
|
223
|
+
...placement ? { placement: {
|
|
224
|
+
...placement,
|
|
225
|
+
...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {}
|
|
226
|
+
} } : {}
|
|
223
227
|
}, now());
|
|
224
228
|
if (outcome?.note) note(outcome.note);
|
|
225
229
|
} catch (error) {
|
|
@@ -228,7 +232,7 @@ function createRunRecorder({ platform, write, now, note, phases, deviceSetup })
|
|
|
228
232
|
}
|
|
229
233
|
};
|
|
230
234
|
}
|
|
231
|
-
function loadForUpdate(path, now) {
|
|
235
|
+
function loadForUpdate(path, now, recoverCorrupt = true) {
|
|
232
236
|
let text;
|
|
233
237
|
try {
|
|
234
238
|
text = readFileSync(path, "utf-8");
|
|
@@ -241,6 +245,11 @@ function loadForUpdate(path, now) {
|
|
|
241
245
|
}
|
|
242
246
|
const parsed = decodeStats(text);
|
|
243
247
|
if (!parsed.record && parsed.newerVersion === null) {
|
|
248
|
+
if (!recoverCorrupt) return {
|
|
249
|
+
record: null,
|
|
250
|
+
note: null,
|
|
251
|
+
newerVersion: null
|
|
252
|
+
};
|
|
244
253
|
const aside = `${path}.corrupt-${now}`;
|
|
245
254
|
renameSync(path, aside);
|
|
246
255
|
return {
|
|
@@ -337,6 +346,13 @@ const GRADLE_TASK = /^> Task (:\S+)/;
|
|
|
337
346
|
*/
|
|
338
347
|
const XCODE_TARGET_DONE = /^(Touch|RegisterExecutionPolicyException|CodeSign)$/;
|
|
339
348
|
const GRADLE_CONFIGURE = /^> Configure project /;
|
|
349
|
+
/**
|
|
350
|
+
* SwiftPM prints `[done / total] name` once it plans the build (with U+2009 thin spaces around the slash in Swift 6.4
|
|
351
|
+
* output), `[done/total] Compiling ...` in older toolchains; Swift 6.4 names the target being worked on, and
|
|
352
|
+
* `<product>-product` is the link of a product.
|
|
353
|
+
*/
|
|
354
|
+
const SWIFTPM_PROGRESS = /^\[(\d+)\s*\/\s*(\d+)\](?:\s+(.*))?$/;
|
|
355
|
+
const SWIFTPM_CONFIGURE = /^(Fetching|Fetched|Computing version|Computed|Creating working copy|Working copy of)\b|^\[(Pre-planning|Planning|Using on-disk description)/;
|
|
340
356
|
const XCODE_STEPS = [
|
|
341
357
|
[/^(CpResource|CopyPNGFile|CopyStringsFile|CompileAssetCatalog\w*|CompileStoryboard|CompileXIB|LinkStoryboards|ProcessInfoPlistFile)$/, "resources"],
|
|
342
358
|
[/^(Compile\w*|Swift\w*|ScanDependencies|Precompile\w*)$/, "compile"],
|
|
@@ -374,8 +390,23 @@ function shortXcodeAction(action, args, target) {
|
|
|
374
390
|
const subject = action === "PhaseScriptExecution" ? unescape(tokens[0] ?? "") : baseName(unescape(tokens.findLast((token) => token.startsWith("/")) ?? ""));
|
|
375
391
|
return clip(`${action}${subject ? ` ${subject}` : ""} (${target})`);
|
|
376
392
|
}
|
|
377
|
-
|
|
393
|
+
function swiftpmStep(text) {
|
|
394
|
+
return /^Linking\b|-product$/.test(text) ? "link" : "compile";
|
|
395
|
+
}
|
|
396
|
+
/** What one line of xcodebuild, Gradle or SwiftPM output says about the build's progress, or null for any other line. */
|
|
378
397
|
function parseBuildToolLine(msg) {
|
|
398
|
+
const counted = SWIFTPM_PROGRESS.exec(msg);
|
|
399
|
+
if (counted) {
|
|
400
|
+
const text = counted[3]?.trim() ?? "";
|
|
401
|
+
return {
|
|
402
|
+
kind: "count",
|
|
403
|
+
done: Number(counted[1]),
|
|
404
|
+
total: Number(counted[2]),
|
|
405
|
+
step: swiftpmStep(text),
|
|
406
|
+
line: text ? clip(text) : null
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
if (SWIFTPM_CONFIGURE.test(msg)) return { kind: "configure" };
|
|
379
410
|
const graph = TARGET_GRAPH.exec(msg);
|
|
380
411
|
if (graph) return {
|
|
381
412
|
kind: "total",
|
|
@@ -412,7 +443,8 @@ function parseBuildToolLine(msg) {
|
|
|
412
443
|
}
|
|
413
444
|
/**
|
|
414
445
|
* Accumulates a build's tool output into its detail: xcodebuild counts the distinct targets it finished against the
|
|
415
|
-
* total its dependency graph note gives; Gradle counts the task lines it printed and has no total
|
|
446
|
+
* total its dependency graph note gives; Gradle counts the task lines it printed and has no total; SwiftPM reports
|
|
447
|
+
* its own `[done / total]` counts, which the parser passes through.
|
|
416
448
|
*/
|
|
417
449
|
function createBuildDetailParser() {
|
|
418
450
|
let seen = false;
|
|
@@ -421,6 +453,7 @@ function createBuildDetailParser() {
|
|
|
421
453
|
let total = null;
|
|
422
454
|
let line = null;
|
|
423
455
|
let tasks = 0;
|
|
456
|
+
let counted = null;
|
|
424
457
|
const targets = /* @__PURE__ */ new Set();
|
|
425
458
|
return {
|
|
426
459
|
push(msg) {
|
|
@@ -436,6 +469,16 @@ function createBuildDetailParser() {
|
|
|
436
469
|
step = "configure";
|
|
437
470
|
return true;
|
|
438
471
|
}
|
|
472
|
+
if (parsed.kind === "count") {
|
|
473
|
+
unit = "steps";
|
|
474
|
+
counted = {
|
|
475
|
+
done: parsed.done,
|
|
476
|
+
total: parsed.total
|
|
477
|
+
};
|
|
478
|
+
step = parsed.step;
|
|
479
|
+
if (parsed.line) line = parsed.line;
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
439
482
|
unit = parsed.unit;
|
|
440
483
|
if (parsed.unit === "tasks") tasks += 1;
|
|
441
484
|
else if (parsed.finished) targets.add(parsed.id);
|
|
@@ -445,6 +488,14 @@ function createBuildDetailParser() {
|
|
|
445
488
|
},
|
|
446
489
|
detail(updatedAt) {
|
|
447
490
|
if (!seen) return null;
|
|
491
|
+
if (unit === "steps" && counted) return {
|
|
492
|
+
step,
|
|
493
|
+
unit,
|
|
494
|
+
done: Math.min(counted.done, counted.total),
|
|
495
|
+
total: counted.total,
|
|
496
|
+
line,
|
|
497
|
+
updatedAt
|
|
498
|
+
};
|
|
448
499
|
const done = unit === "tasks" ? tasks : unit === "targets" ? targets.size : null;
|
|
449
500
|
return {
|
|
450
501
|
step,
|
|
@@ -469,6 +520,7 @@ const NO_BUILD_PROGRESS = {
|
|
|
469
520
|
deviceSetupKnown: () => void 0,
|
|
470
521
|
place: () => {},
|
|
471
522
|
waitingOn: () => {},
|
|
523
|
+
waitingFor: () => {},
|
|
472
524
|
output: () => {},
|
|
473
525
|
durations: () => ({}),
|
|
474
526
|
clear: () => {}
|
|
@@ -576,8 +628,9 @@ function startBuildProgress({ root, platform, slot, claim, now = Date.now, note
|
|
|
576
628
|
};
|
|
577
629
|
const settle = (outcome) => {
|
|
578
630
|
record.outcome = outcome;
|
|
579
|
-
if (projectKey) record.estimate = estimateBuild(projectHistory(projectKey), platform, outcome, record.deviceSetup);
|
|
631
|
+
if (projectKey && platform !== "macos") record.estimate = estimateBuild(projectHistory(projectKey), platform, outcome, record.deviceSetup);
|
|
580
632
|
};
|
|
633
|
+
const waits = /* @__PURE__ */ new Map();
|
|
581
634
|
return {
|
|
582
635
|
step(phase) {
|
|
583
636
|
if (phase === record.phase) return;
|
|
@@ -589,11 +642,12 @@ function startBuildProgress({ root, platform, slot, claim, now = Date.now, note
|
|
|
589
642
|
startedAt: at
|
|
590
643
|
});
|
|
591
644
|
if (phase !== "wait") delete record.waitingOn;
|
|
592
|
-
const outcome = record.outcome ? null : settledOutcome(phase, record.phases);
|
|
645
|
+
const outcome = record.outcome || platform === "macos" ? null : settledOutcome(phase, record.phases);
|
|
593
646
|
if (outcome) settle(outcome);
|
|
594
647
|
write();
|
|
595
648
|
},
|
|
596
649
|
estimate(key) {
|
|
650
|
+
if (platform === "macos") return;
|
|
597
651
|
projectKey = key;
|
|
598
652
|
record.estimate = estimateBuild(projectHistory(key), platform, record.outcome ?? null, record.outcome ? record.deviceSetup : void 0);
|
|
599
653
|
write();
|
|
@@ -636,6 +690,15 @@ function startBuildProgress({ root, platform, slot, claim, now = Date.now, note
|
|
|
636
690
|
};
|
|
637
691
|
write();
|
|
638
692
|
},
|
|
693
|
+
waitingFor(info, kind) {
|
|
694
|
+
if (info) waits.set(info.kind, info);
|
|
695
|
+
else if (kind) waits.delete(kind);
|
|
696
|
+
else waits.clear();
|
|
697
|
+
const first = [...waits.values()].toSorted((a, b) => Date.parse(a.since) - Date.parse(b.since))[0];
|
|
698
|
+
if (first) record.waitingFor = first;
|
|
699
|
+
else delete record.waitingFor;
|
|
700
|
+
write();
|
|
701
|
+
},
|
|
639
702
|
waitingOn(holder) {
|
|
640
703
|
if (holder === null) {
|
|
641
704
|
if (!record.waitingOn) return;
|
|
@@ -684,6 +747,7 @@ function completedPhaseDurations(phases) {
|
|
|
684
747
|
return Object.keys(durations).length ? durations : void 0;
|
|
685
748
|
}
|
|
686
749
|
const HISTORY_FIELDS = [
|
|
750
|
+
"devicePlacement",
|
|
687
751
|
"platform",
|
|
688
752
|
"status",
|
|
689
753
|
"configuration",
|
|
@@ -728,6 +792,29 @@ function recordFinishedBuild(root, record, { update = updateWorkspaceState, now
|
|
|
728
792
|
slot: own?.slot ?? "default",
|
|
729
793
|
phases: own ? phaseDurations(own.phases, now()) : {}
|
|
730
794
|
};
|
|
795
|
+
const slot = own?.slot ?? "default";
|
|
796
|
+
const slots = isJsonObject(state.deviceSlots) ? state.deviceSlots : {};
|
|
797
|
+
const savedSlot = isJsonObject(slots[slot]) ? slots[slot] : {};
|
|
798
|
+
const savedDevice = slot === "default" ? state[platform] : savedSlot[platform];
|
|
799
|
+
if (platform !== "macos" && (record.devicePlacement || isJsonObject(savedDevice))) {
|
|
800
|
+
const device = isJsonObject(savedDevice) ? { ...savedDevice } : {};
|
|
801
|
+
if (record.devicePlacement) device.devicePlacement = record.devicePlacement;
|
|
802
|
+
else delete device.devicePlacement;
|
|
803
|
+
state = slot === "default" ? {
|
|
804
|
+
...state,
|
|
805
|
+
[platform]: device
|
|
806
|
+
} : {
|
|
807
|
+
...state,
|
|
808
|
+
deviceSlots: {
|
|
809
|
+
...slots,
|
|
810
|
+
[slot]: {
|
|
811
|
+
...savedSlot,
|
|
812
|
+
[platform]: device
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
if (platform === "macos") return withHistoryEntry(state, platform, entry);
|
|
731
818
|
return withHistoryEntry({
|
|
732
819
|
...state,
|
|
733
820
|
lastBuild: record,
|
|
@@ -738,7 +825,7 @@ function recordFinishedBuild(root, record, { update = updateWorkspaceState, now
|
|
|
738
825
|
function withInterruptedBuild(state) {
|
|
739
826
|
const left = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
|
|
740
827
|
if (!left) return state;
|
|
741
|
-
const last = state[LAST_BUILD_KEYS[left.platform]];
|
|
828
|
+
const last = left.platform === "macos" ? state[BUILD_HISTORY_KEY]?.macos?.[0] : state[LAST_BUILD_KEYS[left.platform]];
|
|
742
829
|
if (Date.parse(String(last?.startedAt)) >= Date.parse(left.startedAt)) return state;
|
|
743
830
|
return withHistoryEntry(state, left.platform, {
|
|
744
831
|
platform: left.platform,
|
|
@@ -762,7 +849,7 @@ function parseActiveBuild(value) {
|
|
|
762
849
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
763
850
|
const record = value;
|
|
764
851
|
const claim = record.claim;
|
|
765
|
-
if (record.platform !== "ios" && record.platform !== "android") return null;
|
|
852
|
+
if (record.platform !== "ios" && record.platform !== "android" && record.platform !== "macos") return null;
|
|
766
853
|
if (!isPhase(record.phase)) return null;
|
|
767
854
|
if (typeof record.startedAt !== "string" || typeof record.phaseStartedAt !== "string") return null;
|
|
768
855
|
if (!claim || typeof claim.root !== "string" || typeof claim.claimId !== "string") return null;
|
|
@@ -770,6 +857,7 @@ function parseActiveBuild(value) {
|
|
|
770
857
|
const missReason = parseMissReason(record.missReason);
|
|
771
858
|
const placement = parsePlacement(record.placement);
|
|
772
859
|
const waitingOn = parseWaitingOn(record.waitingOn);
|
|
860
|
+
const waitingFor = parseWaitingFor(record.waitingFor);
|
|
773
861
|
const estimate = parseEstimate(record.estimate);
|
|
774
862
|
return {
|
|
775
863
|
platform: record.platform,
|
|
@@ -782,6 +870,7 @@ function parseActiveBuild(value) {
|
|
|
782
870
|
...missReason && record.missProvisional === true ? { missProvisional: true } : {},
|
|
783
871
|
...placement ? { placement } : {},
|
|
784
872
|
...waitingOn ? { waitingOn } : {},
|
|
873
|
+
...waitingFor ? { waitingFor } : {},
|
|
785
874
|
...typeof record.deviceSetup === "boolean" ? { deviceSetup: record.deviceSetup } : {},
|
|
786
875
|
...record.outcome === "hit" || record.outcome === "cold" ? { outcome: record.outcome } : {},
|
|
787
876
|
...estimate ? { estimate } : {},
|
|
@@ -809,6 +898,19 @@ function parsePlacement(value) {
|
|
|
809
898
|
phaseStartedAt
|
|
810
899
|
};
|
|
811
900
|
}
|
|
901
|
+
function parseWaitingFor(value) {
|
|
902
|
+
if (!value || typeof value !== "object") return null;
|
|
903
|
+
const { kind, inUse, max, since } = value;
|
|
904
|
+
if (kind !== "build-slot" && kind !== "device-slot") return null;
|
|
905
|
+
if (!Number.isInteger(inUse) || inUse < 0 || !Number.isInteger(max) || max <= 0) return null;
|
|
906
|
+
if (typeof since !== "string" || !Number.isFinite(Date.parse(since))) return null;
|
|
907
|
+
return {
|
|
908
|
+
kind,
|
|
909
|
+
inUse,
|
|
910
|
+
max,
|
|
911
|
+
since
|
|
912
|
+
};
|
|
913
|
+
}
|
|
812
914
|
function parseWaitingOn(value) {
|
|
813
915
|
const path = value?.path;
|
|
814
916
|
return typeof path === "string" && path ? { path } : null;
|
|
@@ -843,7 +945,7 @@ function median(values) {
|
|
|
843
945
|
return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
|
|
844
946
|
}
|
|
845
947
|
function estimateBuild(history, platform, known, deviceSetup) {
|
|
846
|
-
const lists = history?.[platform];
|
|
948
|
+
const lists = platform === "macos" ? void 0 : history?.[platform];
|
|
847
949
|
const outcome = known ?? latestOutcome(lists);
|
|
848
950
|
const samples = matchDeviceSetup(outcome && lists?.[outcome] || [], deviceSetup);
|
|
849
951
|
const phaseMs = {};
|
|
@@ -910,7 +1012,8 @@ function buildReport(record, { state, history }) {
|
|
|
910
1012
|
...record.missReason ? { missReason: record.missReason } : {},
|
|
911
1013
|
...record.missReason && record.missProvisional ? { missProvisional: true } : {},
|
|
912
1014
|
placement: record.placement ?? "local",
|
|
913
|
-
...record.waitingOn ? { waitingOn: record.waitingOn } : {}
|
|
1015
|
+
...record.waitingOn ? { waitingOn: record.waitingOn } : {},
|
|
1016
|
+
...record.waitingFor ? { waitingFor: record.waitingFor } : {}
|
|
914
1017
|
};
|
|
915
1018
|
}
|
|
916
1019
|
function remainingText(remainingMs) {
|
|
@@ -930,170 +1033,4 @@ function buildStatusLine(report, now) {
|
|
|
930
1033
|
return remainingMs > 0 ? `${head} -- ${remainingText(remainingMs)} (${basis})` : `${head} (usually ~${formatElapsed(report.expectedMs)}, ${basis})`;
|
|
931
1034
|
}
|
|
932
1035
|
//#endregion
|
|
933
|
-
|
|
934
|
-
function findOwnedDeviceActivity({ config, sims, androidSerial, readActivity, deadProjects = [] }) {
|
|
935
|
-
const booted = new Map(sims.filter((sim) => sim.state === "Booted").map((sim) => [sim.udid, sim.name]));
|
|
936
|
-
const dead = new Set(deadProjects);
|
|
937
|
-
const found = [];
|
|
938
|
-
for (const [project, record] of Object.entries(config?.projects ?? {})) {
|
|
939
|
-
if (dead.has(project)) continue;
|
|
940
|
-
for (const { slot, platforms } of projectDeviceSlots(record)) {
|
|
941
|
-
const ios = platforms.ios;
|
|
942
|
-
if (ios?.owned && ios.deviceUdid && booted.has(ios.deviceUdid)) found.push({
|
|
943
|
-
kind: "ios",
|
|
944
|
-
id: ios.deviceUdid,
|
|
945
|
-
name: booted.get(ios.deviceUdid) ?? ios.deviceUdid,
|
|
946
|
-
project,
|
|
947
|
-
slot,
|
|
948
|
-
activity: readActivity({
|
|
949
|
-
platform: "ios",
|
|
950
|
-
id: ios.deviceUdid,
|
|
951
|
-
slot,
|
|
952
|
-
workspace: project
|
|
953
|
-
})
|
|
954
|
-
});
|
|
955
|
-
const android = platforms.android;
|
|
956
|
-
const serial = android?.owned && android.avdName ? androidSerial(android.avdName) : null;
|
|
957
|
-
if (android?.avdName && serial) found.push({
|
|
958
|
-
kind: "android",
|
|
959
|
-
id: android.avdName,
|
|
960
|
-
name: android.avdName,
|
|
961
|
-
project,
|
|
962
|
-
slot,
|
|
963
|
-
activity: readActivity({
|
|
964
|
-
platform: "android",
|
|
965
|
-
id: serial,
|
|
966
|
-
slot,
|
|
967
|
-
workspace: project
|
|
968
|
-
})
|
|
969
|
-
});
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
return found;
|
|
973
|
-
}
|
|
974
|
-
function findIdleDevices({ buildInProgress, now, ...inputs }) {
|
|
975
|
-
return findOwnedDeviceActivity(inputs).filter((device) => device.activity.state === "idle").map(({ kind, id, name, project, slot, activity }) => ({
|
|
976
|
-
kind,
|
|
977
|
-
id,
|
|
978
|
-
name,
|
|
979
|
-
project,
|
|
980
|
-
slot,
|
|
981
|
-
lastActivityAt: activity.lastActivityAt ?? null,
|
|
982
|
-
idleForMs: idleForMs(activity, now),
|
|
983
|
-
buildInProgress: buildInProgress(project)
|
|
984
|
-
}));
|
|
985
|
-
}
|
|
986
|
-
function idleShutdownCandidates(devices, idleMs) {
|
|
987
|
-
return devices.filter((d) => !d.buildInProgress && d.idleForMs !== null && d.idleForMs >= idleMs);
|
|
988
|
-
}
|
|
989
|
-
function parseIdleDuration(value) {
|
|
990
|
-
const match = /^([1-9][0-9]*)(m|h|d)$/.exec(value.trim());
|
|
991
|
-
if (!match) return null;
|
|
992
|
-
const unit = {
|
|
993
|
-
m: 6e4,
|
|
994
|
-
h: 36e5,
|
|
995
|
-
d: 864e5
|
|
996
|
-
}[match[2]];
|
|
997
|
-
return Number(match[1]) * unit;
|
|
998
|
-
}
|
|
999
|
-
function workspaceBuildInProgress(project) {
|
|
1000
|
-
const record = parseActiveBuild(readWorkspaceState$1(project)?.[ACTIVE_BUILD_KEY]);
|
|
1001
|
-
if (!record) return false;
|
|
1002
|
-
try {
|
|
1003
|
-
return activeBuildState(record.claim) !== "stale";
|
|
1004
|
-
} catch {
|
|
1005
|
-
return true;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
function deviceActivityInputs(config, sims, now) {
|
|
1009
|
-
const resolve = ownedAvdSerialResolver({ timeoutMs: 5e3 });
|
|
1010
|
-
return {
|
|
1011
|
-
config,
|
|
1012
|
-
sims,
|
|
1013
|
-
readActivity: createActivityReader({ now }),
|
|
1014
|
-
androidSerial: (avdName) => {
|
|
1015
|
-
try {
|
|
1016
|
-
return resolve(avdName).serial ?? null;
|
|
1017
|
-
} catch {
|
|
1018
|
-
return null;
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
};
|
|
1022
|
-
}
|
|
1023
|
-
function collectOwnedDeviceActivity(config, sims, now = Date.now()) {
|
|
1024
|
-
return findOwnedDeviceActivity(deviceActivityInputs(config, sims, now));
|
|
1025
|
-
}
|
|
1026
|
-
function collectIdleDevices(config, sims, deadProjects, now = Date.now()) {
|
|
1027
|
-
return findIdleDevices({
|
|
1028
|
-
...deviceActivityInputs(config, sims, now),
|
|
1029
|
-
deadProjects,
|
|
1030
|
-
now,
|
|
1031
|
-
buildInProgress: workspaceBuildInProgress
|
|
1032
|
-
});
|
|
1033
|
-
}
|
|
1034
|
-
function idleDeviceLines(devices) {
|
|
1035
|
-
if (devices.length === 0) return [];
|
|
1036
|
-
return [`Idle owned devices (${devices.length}) - booted with no driver, claim, or recent activity:`, ...devices.map((d) => {
|
|
1037
|
-
const slot = d.slot === "default" ? "" : ` [${d.slot}]`;
|
|
1038
|
-
const idle = d.idleForMs === null ? "idle for an unknown time" : `idle ${formatLongDuration(d.idleForMs)}`;
|
|
1039
|
-
const build = d.buildInProgress ? ", build in progress" : "";
|
|
1040
|
-
return ` ${d.kind}${slot} ${d.name} (${d.project}) -- ${idle}${build}`;
|
|
1041
|
-
})];
|
|
1042
|
-
}
|
|
1043
|
-
function shutDownIdleDevices(devices, idleMs, recollect) {
|
|
1044
|
-
const candidates = idleShutdownCandidates(devices, idleMs);
|
|
1045
|
-
const shutDown = [];
|
|
1046
|
-
if (candidates.length === 0) {
|
|
1047
|
-
console.log(chalk.dim(`No owned device has been idle for ${formatLongDuration(idleMs)} or more.`));
|
|
1048
|
-
return {
|
|
1049
|
-
failures: 0,
|
|
1050
|
-
shutDown
|
|
1051
|
-
};
|
|
1052
|
-
}
|
|
1053
|
-
const fresh = idleShutdownCandidates(recollect(), idleMs);
|
|
1054
|
-
let failures = 0;
|
|
1055
|
-
for (const device of candidates) {
|
|
1056
|
-
const what = `${device.kind} ${device.name}`;
|
|
1057
|
-
const current = fresh.find((d) => d.kind === device.kind && d.id === device.id && d.project === device.project && d.slot === device.slot);
|
|
1058
|
-
if (!current) {
|
|
1059
|
-
console.log(chalk.dim(`Kept ${what}: it is no longer idle for ${formatLongDuration(idleMs)}.`));
|
|
1060
|
-
recordGcResult("idleDevice", "kept", device.name, {
|
|
1061
|
-
id: device.id,
|
|
1062
|
-
detail: `it is no longer idle for ${formatLongDuration(idleMs)}`
|
|
1063
|
-
});
|
|
1064
|
-
continue;
|
|
1065
|
-
}
|
|
1066
|
-
const outcome = device.kind === "ios" ? teardownOwnedIosSim(device.id, { label: device.name }) : teardownOwnedAvd(device.id, { owner: {
|
|
1067
|
-
projectPath: device.project,
|
|
1068
|
-
slot: device.slot
|
|
1069
|
-
} });
|
|
1070
|
-
if (outcome.status === "torn-down") {
|
|
1071
|
-
shutDown.push(device);
|
|
1072
|
-
console.log(chalk.green(`Shut down ${what}, idle ${formatLongDuration(current.idleForMs)}`));
|
|
1073
|
-
recordGcResult("idleDevice", "done", device.name, {
|
|
1074
|
-
id: device.id,
|
|
1075
|
-
detail: `idle ${formatLongDuration(current.idleForMs)}`
|
|
1076
|
-
});
|
|
1077
|
-
} else if (outcome.status === "missing") console.log(chalk.dim(`${what} is already gone; nothing to shut down.`));
|
|
1078
|
-
else if (outcome.status === "skipped") {
|
|
1079
|
-
console.log(chalk.yellow(`Skipped ${what}: ${outcome.reason}`));
|
|
1080
|
-
recordGcResult("idleDevice", "kept", device.name, {
|
|
1081
|
-
id: device.id,
|
|
1082
|
-
detail: outcome.reason
|
|
1083
|
-
});
|
|
1084
|
-
} else {
|
|
1085
|
-
failures++;
|
|
1086
|
-
console.log(chalk.red(`Failed to shut down ${what}: ${outcome.reason}`));
|
|
1087
|
-
recordGcResult("idleDevice", "failed", device.name, {
|
|
1088
|
-
id: device.id,
|
|
1089
|
-
detail: outcome.reason
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
return {
|
|
1094
|
-
failures,
|
|
1095
|
-
shutDown
|
|
1096
|
-
};
|
|
1097
|
-
}
|
|
1098
|
-
//#endregion
|
|
1099
|
-
export { parseSubscriberNames as C, parseWatchmanPid as D, parseWatchmanClients as E, runWatchman as O, statsProjectKey$1 as S, parseWatchRoots as T, tapBuildLog as _, parseIdleDuration as a, readStats$1 as b, ACTIVE_BUILD_KEY as c, buildReport as d, buildStatusLine as f, startBuildProgress as g, recordFinishedBuild as h, idleShutdownCandidates as i, NO_BUILD_PROGRESS as l, parseActiveBuild as m, collectOwnedDeviceActivity as n, shutDownIdleDevices as o, estimateBuild as p, idleDeviceLines as r, workspaceBuildInProgress as s, collectIdleDevices as t, activeBuildState as u, createRunRecorder as v, parseTriggerCount as w, recordRunStats as x, readRunEstimates as y };
|
|
1036
|
+
export { statsProjectKey$1 as _, buildStatusLine as a, recordFinishedBuild as c, createRunRecorder as d, readRunEstimates as f, recordRunStats as g, recordCapacityWait as h, buildReport as i, startBuildProgress as l, recordCapacityRefusal as m, NO_BUILD_PROGRESS as n, estimateBuild as o, readStats$1 as p, activeBuildState as r, parseActiveBuild as s, ACTIVE_BUILD_KEY as t, tapBuildLog as u };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
2
|
-
import { a as formatElapsed } from "./command-output-
|
|
2
|
+
import { a as formatElapsed } from "./command-output-CDAIFD-8.mjs";
|
|
3
3
|
import { n as declareSpawnsOn, o as stopDeclaringSpawnsOn } from "./spawn-claims-D0XfSe8u.mjs";
|
|
4
4
|
import { readdirSync, statSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
@@ -53,7 +53,7 @@ function tryAcquireBuildSlot({ max, root = null, logFile = null }) {
|
|
|
53
53
|
function slotWaitingLine({ max, elapsedMs }) {
|
|
54
54
|
return `${"build".padEnd(11)} waiting for a build slot (all ${max} in use, ${formatElapsed(elapsedMs)} elapsed) -- stim guide lifecycle concurrency`;
|
|
55
55
|
}
|
|
56
|
-
async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.now, out = () => {}, sleep = sleepAsync, intervalMs = SLOT_POLL_MS, progressMs = SLOT_PROGRESS_MS, ceilingMs = SLOT_CEILING_MS }) {
|
|
56
|
+
async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.now, out = () => {}, waitingFor = () => {}, sleep = sleepAsync, intervalMs = SLOT_POLL_MS, progressMs = SLOT_PROGRESS_MS, ceilingMs = SLOT_CEILING_MS }) {
|
|
57
57
|
if (!max || max <= 0) return {
|
|
58
58
|
acquired: true,
|
|
59
59
|
unlimited: true
|
|
@@ -61,31 +61,41 @@ async function acquireBuildSlot({ max, root = null, logFile = null, now = Date.n
|
|
|
61
61
|
const started = now();
|
|
62
62
|
let lastProgress = started;
|
|
63
63
|
let waited = false;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
throw err;
|
|
80
|
-
}
|
|
81
|
-
if (now() - lastProgress >= progressMs) {
|
|
82
|
-
lastProgress = now();
|
|
83
|
-
out(slotWaitingLine({
|
|
64
|
+
try {
|
|
65
|
+
for (;;) {
|
|
66
|
+
const got = tryAcquireBuildSlot({
|
|
67
|
+
max,
|
|
68
|
+
root,
|
|
69
|
+
logFile
|
|
70
|
+
});
|
|
71
|
+
if (got) return {
|
|
72
|
+
...got,
|
|
73
|
+
slotWaitMs: waited ? Math.max(0, Math.round(now() - started)) : 0
|
|
74
|
+
};
|
|
75
|
+
waited = true;
|
|
76
|
+
waitingFor({
|
|
77
|
+
kind: "build-slot",
|
|
78
|
+
inUse: max,
|
|
84
79
|
max,
|
|
85
|
-
|
|
86
|
-
})
|
|
80
|
+
since: new Date(started).toISOString()
|
|
81
|
+
});
|
|
82
|
+
const elapsed = now() - started;
|
|
83
|
+
if (elapsed >= ceilingMs) {
|
|
84
|
+
const err = /* @__PURE__ */ new Error(`Waited ${formatElapsed(elapsed)} for one of ${max} build slots, and every slot is held by a process that is still running, or by a holder Stim cannot identify. Slots live under ` + buildSlotsDir() + "; remove a slot directory whose builder is not really building, or raise concurrency.maxBuilds.");
|
|
85
|
+
err.code = "STIM_BUILD_SLOT_TIMEOUT";
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
if (now() - lastProgress >= progressMs) {
|
|
89
|
+
lastProgress = now();
|
|
90
|
+
out(slotWaitingLine({
|
|
91
|
+
max,
|
|
92
|
+
elapsedMs: elapsed
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
await sleep(intervalMs);
|
|
87
96
|
}
|
|
88
|
-
|
|
97
|
+
} finally {
|
|
98
|
+
waitingFor(null);
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
101
|
function releaseBuildSlot(handle) {
|