stim 1.25.0 → 1.27.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 +1 -1
- package/dist/{acquire-artifact-zA4S7RHE.mjs → acquire-artifact-BKN2Yuhg.mjs} +2 -2
- package/dist/{act-BbHS3oV8.mjs → act-ROviTF_t.mjs} +415 -118
- package/dist/{activity-BpjwrQXU.mjs → activity-Cd-ysFes.mjs} +6 -7
- package/dist/{agent-device-usage-output-Bnkerfod.mjs → agent-device-usage-output-C5nCKWp9.mjs} +5 -5
- package/dist/{android-CNZgRC-4.mjs → android--HBgpvpW.mjs} +5 -5
- package/dist/{android-BGwuK3Mc.mjs → android-Cd6w7_qw.mjs} +134 -57
- package/dist/{android-saBeB4lr.mjs → android-Deb9X3_Y.mjs} +37 -15
- package/dist/{android-Cjcj8MCw.mjs → android-DriNoAVy.mjs} +99 -47
- package/dist/{android-cas-BVqh2Zep.mjs → android-cas-D5e6ecUg.mjs} +4 -4
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/{android-project-CTYaETc0.d.mts → android-project-DUGMbq28.d.mts} +55 -1
- package/dist/api.d.mts +20 -7
- package/dist/api.mjs +42 -32
- package/dist/apk-signed-tail-BHQHx3Rm.mjs +142 -0
- package/dist/{artifact-Co8zixVx.mjs → artifact-0AGJYB9O.mjs} +28 -28
- package/dist/{artifact-DN8JNwqS.mjs → artifact-faemIZv5.mjs} +40 -30
- package/dist/{artifact-platform-CMRc0M_r.mjs → artifact-platform-BO2Uvk_A.mjs} +1 -1
- package/dist/{attempt-DW-mQqM7.mjs → attempt-ClyJlZPT.mjs} +4 -2
- package/dist/auto-placement-z-H5pJza.mjs +350 -0
- package/dist/{browser-web-CCgZsHmI.mjs → browser-web-slD8AvLp.mjs} +16 -17
- package/dist/{build-cache-CKCzxzxA.mjs → build-cache-gBJ-WKzA.mjs} +141 -37
- package/dist/{build-CAiw8Ezm.mjs → build-hS0QyFlQ.mjs} +38 -31
- package/dist/{build-plan-zCuHGlA8.mjs → build-plan-CBqYbzYM.mjs} +7 -6
- package/dist/{cache-manifest-BPXRONJz.mjs → cache-manifest-DEjqGGat.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{budget-HyShrIpL.mjs → ccache-BWTze1Ls.mjs} +634 -1514
- package/dist/{cdp-BG3FJCCx.mjs → cdp-C3svvXiE.mjs} +1 -1
- package/dist/{chrome-BvV8ssI3.mjs → chrome-DyDWurWG.mjs} +1 -1
- package/dist/{cli-C4w607Pz.mjs → cli-ftXDLto1.mjs} +24 -23
- package/dist/cli.mjs +1 -1
- package/dist/{client-BQsmyp_-.mjs → client-xsdxrhWA.mjs} +77 -116
- package/dist/collector-run.d.mts +10 -9
- package/dist/collector-run.mjs +42 -27
- package/dist/{command-output-BBvS1H6v.mjs → command-output-Dj-WT4BP.mjs} +1 -1
- package/dist/{config-BZhXY15H.mjs → config-Cn94Jc0g.mjs} +343 -18
- package/dist/{launch-DscF1QfM.mjs → dependencies-BGokZ-Ng.mjs} +330 -279
- package/dist/{dependency-state-BwNCYG5Q.mjs → dependency-state-C3OtgG94.mjs} +14 -7
- package/dist/{detached-entry-KmieOKgN.mjs → detached-entry-BPlSaCwC.mjs} +1 -1
- package/dist/{dev-client-CHoXXZeg.mjs → dev-client-BMca82xo.mjs} +2 -2
- package/dist/{device-F5-4z9ef.mjs → device-BJm0irrq.mjs} +16 -16
- package/dist/{device-capacity-ZYaRALv5.mjs → device-capacity-6LP7QsaA.mjs} +103 -25
- package/dist/device-host-worker.mjs +19 -21
- package/dist/{device-ios-DkHBrmvH.mjs → device-ios-534c14fz.mjs} +288 -28
- package/dist/{device-lease-run-ogEeJ62K.mjs → device-lease-run-DwsGfjUN.mjs} +5 -5
- package/dist/{device-pool-BIg8MU8l.mjs → device-pool-BnQqvs6o.mjs} +3 -3
- package/dist/{device-B9FqTBYW.mjs → device-tM41-TUq.mjs} +25 -24
- package/dist/{doctor-A_Nr_fDe.mjs → doctor-Dbx1ZpD2.mjs} +1 -1
- package/dist/{doctor-k3P3PizH.mjs → doctor-DyqE9n1J.mjs} +28 -16
- package/dist/{doctor-Bm8TVpGn.mjs → doctor-F-3VUUyN.mjs} +128 -35
- package/dist/{doctor-fingerprint-zlujA1Gs.mjs → doctor-fingerprint-o7ZI9YLn.mjs} +9 -3
- package/dist/doctor-fingerprint.mjs +1 -1
- package/dist/{doctor-watchman-BovI1y3-.mjs → doctor-watchman-CxDbyrrt.mjs} +5 -5
- package/dist/{eas-build-CyDKNTBP.mjs → eas-build-CjNSWmjo.mjs} +4 -4
- package/dist/eas-fallback-9fqb46kW.mjs +87 -0
- package/dist/{eas-session-ledger-BMCA1gdO.mjs → eas-session-ledger-DrP4OuuM.mjs} +6 -6
- package/dist/{error-diagnostics-B1Mj_-7h.mjs → error-diagnostics-snej9k4j.mjs} +51 -25
- package/dist/{exec-VFRpu1iA.mjs → exec-aULwtNly.mjs} +57 -6
- package/dist/{gc-eaz403W6.mjs → gc-BRwAY3qT.mjs} +2 -2
- package/dist/{gc-B9jcnmIk.mjs → gc-CGZ1Yg88.mjs} +218 -72
- package/dist/{guide-DR0K0xW9.mjs → guide-_rfEh_zM.mjs} +839 -222
- package/dist/{hosted-android-Bvb2-ZxD.mjs → hosted-android-BMKzUNnY.mjs} +4 -4
- package/dist/{hosted-client-rsRqysJc.mjs → hosted-client-D7Pk_Oo1.mjs} +13 -9
- package/dist/{hosted-logs-CWKGYWNX.mjs → hosted-logs-B1gqQuva.mjs} +18 -12
- package/dist/hosted-logs-sync-Dg3qrZmV.mjs +195 -0
- package/dist/{hosted-macos-d0pv9Tth.mjs → hosted-macos-B9w4H8hc.mjs} +6 -6
- package/dist/{hosted-native-BxTizGU2.mjs → hosted-native-CdgaiuyP.mjs} +17 -17
- package/dist/{idle-shutdown-BIyfl0Zj.mjs → idle-shutdown-Cbvo5KEh.mjs} +21 -9
- package/dist/{ios-BRVM8b0P.mjs → ios-B5HlVMhQ.mjs} +138 -55
- package/dist/{ios-Dvt97HgQ.mjs → ios-Bk4mWbtS.mjs} +8 -8
- package/dist/{ios-ENC4sRPA.mjs → ios-CsRVik64.mjs} +7 -1
- package/dist/{ios-BQzvJlzw.mjs → ios-E26qSpkb.mjs} +94 -11
- package/dist/{ios-device-CKSvk0bu.mjs → ios-device-C_QkIf1Z.mjs} +3 -3
- package/dist/{ios-device-B6HK951C.mjs → ios-device-CiBA-er9.mjs} +1 -1
- package/dist/{ios-project-DCUDo06I.mjs → ios-project-D8Jcy_br.mjs} +22 -9
- package/dist/{ios-signing-4c_qXvQm.mjs → ios-signing-BJzvDPfU.mjs} +2 -2
- package/dist/{ios-state-CT9nV5SP.mjs → ios-state-BZ03NFgF.mjs} +1 -1
- package/dist/{js-swap-Z9HbC4cj.mjs → js-swap-Dg2a945i.mjs} +8 -7
- package/dist/{launch-D0lPvFFu.mjs → launch-CRyBeNsA.mjs} +53 -44
- package/dist/lightened-BCsdAGj_.mjs +171 -0
- package/dist/{logs-BsIRre8x.mjs → logs-CC_-ZzEE.mjs} +10 -174
- package/dist/{logs-Crs9y34Z.mjs → logs-aJQb-RDg.mjs} +112 -38
- package/dist/{macos-CcUlJPMu.mjs → macos-BGmTpnv9.mjs} +1 -1
- package/dist/{macos-D477nfzH.mjs → macos-DlCBhMw5.mjs} +73 -39
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +30 -13
- package/dist/{metro-1pJgCX4U.mjs → metro-CvyD-xwe.mjs} +4 -4
- package/dist/{metro-gateway-Bp9gJQAN.mjs → metro-gateway-BnHdqMO_.mjs} +3 -4
- package/dist/{named-ports-BVbn8SvC.mjs → named-ports-BCyMWA6b.mjs} +3 -3
- package/dist/{native-android-BvMizJn1.mjs → native-android-DlpxCyOP.mjs} +17 -18
- package/dist/{native-gradle-artifact-inputs-BJscK4vN.mjs → native-gradle-artifact-inputs-C13qT7R_.mjs} +5 -5
- package/dist/{native-runtime-B9w_Qyz3.mjs → native-runtime-DqaIBO5w.mjs} +9 -9
- package/dist/{native-source-D-4Dh4JU.mjs → native-source-D1AzWiuP.mjs} +1 -1
- package/dist/{native-xcode-inputs-Cv4l-obn.mjs → native-xcode-inputs-B1W8SrxB.mjs} +3 -3
- package/dist/{native-xcode-ios-DGrg90hE.mjs → native-xcode-ios-QPP0Rm68.mjs} +17 -18
- package/dist/{ndjson-CgE_o3Dl.mjs → ndjson-Dy2W4vRa.mjs} +2 -2
- package/dist/offload-worker.d.mts +3 -1
- package/dist/offload-worker.mjs +34 -25
- package/dist/{operation-exec-CUZifp6Z.mjs → operation-exec-Dp4FuIGR.mjs} +1 -1
- package/dist/{ownership-jxxz-19m.mjs → ownership-Bx-0cku-.mjs} +3 -3
- package/dist/{page-CzEA_-5_.mjs → page-CQJlcj3x.mjs} +2 -2
- package/dist/{phone-reverses-CYb7RRAx.mjs → phone-reverses-C9yAaKEv.mjs} +18 -4
- package/dist/{placement-log-DjOXJRIH.mjs → placement-log-BXUbiZM6.mjs} +3 -3
- package/dist/{plan-placement-BqKgKHCi.mjs → plan-placement-UxnQjv5Z.mjs} +36 -10
- package/dist/{ports-DtS1Amb0.mjs → ports-uUrghqWN.mjs} +3 -3
- package/dist/prebuild-BDpToDgR.mjs +1246 -0
- package/dist/{project-BiC68mIp.mjs → project-DYj-HVx6.mjs} +17 -18
- package/dist/{pull-request-CbNlkFok.mjs → pull-request-BzLmzAIQ.mjs} +2 -2
- package/dist/pull-requests.mjs +1 -1
- package/dist/{react-native-android-DRYqoJc4.mjs → react-native-android-DDBccgJw.mjs} +56 -36
- package/dist/{react-native-build-CwZB-agu.mjs → react-native-build-DaK2IFyP.mjs} +9 -9
- package/dist/{react-native-doctor-BCrytK7h.mjs → react-native-doctor-B-Mw6DcR.mjs} +50 -9
- package/dist/{react-native-ios-Cr1buNFo.mjs → react-native-ios-DjYwUF9U.mjs} +45 -25
- package/dist/{recordings-BaoQ0t-J.mjs → recordings-C20iUZfp.mjs} +1 -1
- package/dist/{registration-CN6nlhcD.mjs → registration-BwCe64PH.mjs} +1 -1
- package/dist/{reload-Beftw2X3.mjs → reload-DJBeF_rC.mjs} +1 -1
- package/dist/{reload-FbSgMF8x.mjs → reload-fUdkH2_p.mjs} +16 -16
- package/dist/{remote-BuZj6AyU.mjs → remote-y6n99WMW.mjs} +22 -9
- package/dist/{result-CR2vk2cj.mjs → result-CTqBw2Te.mjs} +32 -21
- package/dist/{run-BtzE09Dl.mjs → run-DaCeNKRm.mjs} +3 -3
- package/dist/{selection-D5cxEl3t.mjs → selection-Bs8phwhN.mjs} +183 -62
- package/dist/{server-bare-CH9X0RLn.mjs → server-bare-BOh-iZEj.mjs} +2 -2
- package/dist/{server-command-CaBbDNU2.mjs → server-command-8CuA51Cv.mjs} +6 -6
- package/dist/{server-expo-Ck8EIidM.mjs → server-expo-ABQs2XFA.mjs} +4 -4
- package/dist/server-expo-Ba_Y21vB.mjs +2 -0
- package/dist/{settings-B5tCoq9N.mjs → settings-BDVI8Ivc.mjs} +331 -62
- package/dist/{settings-DzH9mGQZ.mjs → settings-CMHhQNwI.mjs} +24 -3
- package/dist/settings-payload-cm60Zhib.mjs +257 -0
- package/dist/settings-write-BdNRLlBn.mjs +185 -0
- package/dist/settings.schema.json +84 -39
- package/dist/{simslim-BjxszUAb.mjs → simslim-DCQwzoPy.mjs} +4 -3
- package/dist/{slot-launch-QeuJMlnJ.mjs → slot-launch-0l7RqSpr.mjs} +6 -6
- package/dist/{stage-D8xlRU2D.mjs → stage-F4cAfJGi.mjs} +2 -2
- package/dist/{start-C1JLjkNw.mjs → start-DcqnF9p8.mjs} +1 -1
- package/dist/{start-YMpNwLhh.mjs → start-DrPwER_2.mjs} +27 -23
- package/dist/{state-DMRNP7-4.mjs → state-BX1y5syV.mjs} +4 -5
- package/dist/{state-DPaM3u5K.mjs → state-CZxLyetD.mjs} +2 -3
- package/dist/{stats-CP7STzZw.mjs → stats-GxuCbles.mjs} +5 -5
- package/dist/{stats-report-n2U5plhk.mjs → stats-report-B86Cv7Uc.mjs} +1 -1
- package/dist/{status-Fect2w9R.mjs → status-7ULDEJ1e.mjs} +1 -1
- package/dist/{status-CRLiJ-O_.mjs → status-BfnK9pUd.mjs} +25 -26
- package/dist/{status-cNw6i0_t.mjs → status-Bj7ZYvvc.mjs} +1 -1
- package/dist/{status-watch-Bc2J4TZn.mjs → status-watch-BfabQn03.mjs} +5 -5
- package/dist/status-worker.mjs +1 -1
- package/dist/{stim-desktop-DS0mzR8U.mjs → stim-desktop-CbWo21kb.mjs} +2 -2
- package/dist/{stop-COP6PQqw.mjs → stop-CH79S3IZ.mjs} +5 -6
- package/dist/{stop-Db9Kh-UA.mjs → stop-D-EAr25B.mjs} +25 -22
- package/dist/{stop-Br7LKxBE.mjs → stop-x1Yu3He4.mjs} +2 -2
- package/dist/supervisor-run.d.mts +1 -0
- package/dist/supervisor-run.mjs +17 -18
- package/dist/{support-qKcbgmI5.mjs → support-Be0UeVZU.mjs} +10 -10
- package/dist/{support-Cxj9CmII.mjs → support-CNg_YsOk.mjs} +6 -6
- package/dist/{swiftpm-artifact-inputs-iY9fsmOc.mjs → swiftpm-artifact-inputs-uPqYvGBv.mjs} +4 -4
- package/dist/{swiftpm-macos-Bp_sn9P4.mjs → swiftpm-macos-Ch4YjY_A.mjs} +11 -12
- package/dist/toolchain-CbCG6C5Z.mjs +2413 -0
- package/dist/toolchain-JYAOquPg.mjs +2 -0
- package/dist/{trigger-CBMe2YLH.mjs → trigger-DMou-X7j.mjs} +3 -3
- package/dist/trigger-qp2ji5wE.mjs +2 -0
- package/dist/{warm-progress-BV3ZPmcY.mjs → warm-progress-C0RsbngN.mjs} +731 -728
- package/dist/{web-B4Yjyt1G.mjs → web-Cq_AQ4DK.mjs} +9 -10
- package/dist/web-Je6abcpz.mjs +2 -0
- package/dist/web-run.mjs +9 -9
- package/dist/windows-report.mjs +1 -1
- package/dist/{workspace-state-CPSp3mav.mjs → workspace-state-BjqdjnJR.mjs} +46 -8
- package/dist/{workspaces-C9w4aeXF.mjs → workspaces-DFbj07jp.mjs} +1801 -76
- package/dist/{worktree-CclFIe1Z.mjs → worktree-COAJ3-OD.mjs} +934 -511
- package/dist/{worktree-Ct9Gk3KL.mjs → worktree-JGUd_53L.mjs} +1 -1
- package/package.json +8 -8
- package/dist/ccache-h1FKhZeg.mjs +0 -143
- package/dist/created-devices-D2Aca-xu.mjs +0 -52
- package/dist/eas-fallback-gaZi-dJL.mjs +0 -381
- package/dist/hosted-ios-RtVcJH3u.mjs +0 -15
- package/dist/native-run-D5OJsGwA.mjs +0 -276
- package/dist/paths-DQtTgsBf.mjs +0 -42
- package/dist/prebuild-JUaqOLpc.mjs +0 -501
- package/dist/server-expo-C16Zf2k7.mjs +0 -2
- package/dist/settings-write-n0zwfohx.mjs +0 -360
- package/dist/toolchain-DB1aeqxO.mjs +0 -2
- package/dist/toolchain-VzLJzZ7O.mjs +0 -908
- package/dist/trigger-BLsHgAGR.mjs +0 -2
- package/dist/web-DS4UDWvf.mjs +0 -2
- package/dist/xcode-CiIIDnuD.mjs +0 -910
|
@@ -1,39 +1,77 @@
|
|
|
1
|
-
import { D as ownership_claim_exports, E as debugLog, S as process_identity_exports, b as operationState, c as throwIfCancelled, d as workspaceProcessLockError, l as WorkspaceProcessCleanupError, n as isTimeoutError, o as cancellableSleep, s as cancelledError, t as getExecutor, u as withWorkspaceProcessLock, y as isTermination } from "./exec-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { D as ownership_claim_exports, E as debugLog, S as process_identity_exports, b as operationState, c as throwIfCancelled, d as workspaceProcessLockError, l as WorkspaceProcessCleanupError, n as isTimeoutError, o as cancellableSleep, s as cancelledError, t as getExecutor, u as withWorkspaceProcessLock, y as isTermination } from "./exec-aULwtNly.mjs";
|
|
2
|
+
import { D as workspaceId$1, E as workspaceDir, M as withDirLock$1, b as sharedCcache$1, d as writeWorkspaceState, j as workspaceStateFile$1, k as workspaceLogsDir$1, l as withWorkspaceStateLockAsync, r as readWorkspaceState$1, t as clearWorkspaceStateKey, y as sharedBuildCache } from "./workspace-state-BjqdjnJR.mjs";
|
|
3
|
+
import { F as isOnMountedVolume, G as projectDeviceSlots, H as deviceSlotPlatforms, L as measuredDirectorySizeAsync, M as directorySize, N as directorySizeAsync, O as withConfigLockAsync$1, P as formatBytes, R as volumeRootFor, _ as loadConfig$1, a as clearDevice, d as getConfigDir, o as clearSupervisor, p as getProject } from "./config-Cn94Jc0g.mjs";
|
|
4
4
|
import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
|
|
5
|
-
import { a as formatElapsed, l as phaseLine, o as formatLongDuration, s as isAppLaunchError, u as plural } from "./command-output-
|
|
6
|
-
import { a as killOnAbort, n as runOperationFileQuiet, r as childEnvironment, t as runOperationFile } from "./operation-exec-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { i as
|
|
5
|
+
import { a as formatElapsed, l as phaseLine, o as formatLongDuration, s as isAppLaunchError, u as plural } from "./command-output-Dj-WT4BP.mjs";
|
|
6
|
+
import { a as killOnAbort, n as runOperationFileQuiet, r as childEnvironment, t as runOperationFile } from "./operation-exec-Dp4FuIGR.mjs";
|
|
7
|
+
import { Z as resolveProjectSettingsAsync, d as androidLayoutSetting, ft as planMetroReach, m as defaultAndroidLayout } from "./settings-BDVI8Ivc.mjs";
|
|
8
|
+
import { C as resolvePackageJson, M as readMetroTunnel, N as readPidFile, P as readRemoteSession, i as findProjectRoot$1, j as clearWorkspaceSupervisor, k as clearRemoteSession, s as ownedDeviceLabel, v as detectIsExpo } from "./project-DYj-HVx6.mjs";
|
|
9
|
+
import { F as listAvdsAsync, G as ownedAvdSerialResolverAsync, I as listInstalledSystemImages, J as parseAvdSystemImage, V as ownedAvdDirectory, d as androidToolPath, dt as isStimOwnedSim, m as avdIniPaths, mt as dropParked, o as androidHome, q as parseAvdDeviceProfile, ut as isStimOwnedAvd, v as avdStorageRoots, yt as readParked } from "./android-DriNoAVy.mjs";
|
|
10
|
+
import { a as listeningPidsAsync, c as pidExists, d as resolveProjectMetro, h as isMetroRunning, r as killMetroTreeAsync, u as processCwds } from "./metro-CvyD-xwe.mjs";
|
|
11
|
+
import { c as readNdjsonGenerations$1, i as createNdjsonWriter, r as createNdjsonTail } from "./ndjson-Dy2W4vRa.mjs";
|
|
12
|
+
import { C as environmentState, a as removeEasSessionClaim, d as parseWatchRoots, f as parseWatchmanClients, i as recordEasSessionClaim, l as parseSubscriberNames, n as easMachineStateRoot$1, o as removeEasSessionClaimAsync, p as parseWatchmanPid, r as readEasSessionLedger$1, s as compareStimVersions, t as assertEasMachineRootWritable, u as parseTriggerCount, w as formatSpace, y as capacity } from "./eas-session-ledger-DrP4OuuM.mjs";
|
|
13
|
+
import { i as registeredCaches, r as register } from "./cache-manifest-DEjqGGat.mjs";
|
|
14
|
+
import { A as collectIdleDevicesAsync, Ct as createGcResults, Et as mapLimited, I as shutDownIdleDevices, L as workspaceBuildInProgress, M as collectOwnedDeviceActivityAsync, Ot as sizeConcurrency, P as idleShutdownCandidates, St as GC_OUTPUT, _ as withIdleWorkspace, _t as measureDu, b as resolveSupervisorTarget, bt as listBuildSlots, ct as eraseParkedIosSim, ft as teardownOwnedIosSim, gt as canonical$1, ht as probePublicHttp, i as clearWorkspaceOutputs, mt as teardownParkedIosSim, o as collectWorkspaceOutputs, pt as teardownParkedAvd, st as eraseParkedAvd, ut as teardownOwnedAvd, vt as writeUsageCache } from "./workspaces-DFbj07jp.mjs";
|
|
15
15
|
import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { D as sanitizeDeviceLabel, H as deviceHoldsApk, U as deviceHoldsBundle, b as parseSimctlList, f as listAllIosSimsAsync, g as listUserApps, k as uninstallIosApp, p as listIosDeviceTypesAsync, u as iosSimulatorFailureAdvice, y as parseRuntimeVersion } from "./ios-BQzvJlzw.mjs";
|
|
16
|
+
import { lt as claimForEmptying, ot as runCancellationSignal, rt as nativeRunWaitNotice } from "./toolchain-CbCG6C5Z.mjs";
|
|
17
|
+
import { N as listBuildLocks, b as leaseIsExpired, g as workspaceActivity, o as envDir, p as readHostProcessTableAsync, x as listLeaseFiles } from "./activity-Cd-ysFes.mjs";
|
|
18
|
+
import { l as expoConfigContents } from "./build-cache-gBJ-WKzA.mjs";
|
|
19
|
+
import { G as deviceHoldsBundle, O as sanitizeDeviceLabel, W as deviceHoldsApk, b as parseSimctlList, f as listAllIosSimsAsync, g as listUserApps, j as uninstallIosApp, p as listIosDeviceTypesAsync, u as iosSimulatorFailureAdvice, y as parseRuntimeVersion } from "./ios-E26qSpkb.mjs";
|
|
21
20
|
import { n as supervisorError } from "./errors-DHm_U5gv.mjs";
|
|
22
|
-
import { c as findBinUpward, n as expoBinFromPackage, r as expoBinPath, s as expoTelemetryEnv } from "./server-expo-
|
|
23
|
-
import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-
|
|
21
|
+
import { c as findBinUpward, n as expoBinFromPackage, r as expoBinPath, s as expoTelemetryEnv } from "./server-expo-ABQs2XFA.mjs";
|
|
22
|
+
import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-CiBA-er9.mjs";
|
|
23
|
+
import { t as resolveMaintenanceSettings } from "./settings-Djl-mpjX.mjs";
|
|
24
24
|
import { createRequire } from "node:module";
|
|
25
|
-
import { randomUUID } from "node:crypto";
|
|
26
|
-
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, statfsSync, writeFileSync } from "node:fs";
|
|
25
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
26
|
+
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, statfsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
27
27
|
import { homedir, platform, totalmem } from "node:os";
|
|
28
28
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
29
|
-
import { LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, ambientContext, cacheDirRefusal, compiledHelper, configDir, withAmbientContext } from "@stim-cli/core";
|
|
30
|
-
import {
|
|
29
|
+
import { LOG_ROTATE_BYTES, METRO_NAMED_CACHE_LAYOUT, ambientContext, cacheDirRefusal, compiledHelper, configDir, ensurePrivateDir, rotatedLogPath, withAmbientContext, withDirLock } from "@stim-cli/core";
|
|
30
|
+
import { DEV_SERVER_STOP_REQUEST_KEY, MACHINE_OWNER_KINDS, MAINTENANCE_LOG_NAME, budgetSweepFile, budgetSweepLock, buildWorkerRoot, gcLogFile, isJsonObject, loadConfig, machineCacheUsageFile, maintenanceNdjsonFile, readDevServerStop, readDevServerStopRequest, readJsonObject, readMachineCacheUsage, runId, settingDefinition, settingValueError, workspaceLogsDir } from "@stim-cli/core/state";
|
|
31
31
|
import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1 } from "path";
|
|
32
32
|
import { fileURLToPath } from "node:url";
|
|
33
33
|
import chalk from "chalk";
|
|
34
34
|
import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1 } from "fs";
|
|
35
35
|
import { access, lstat, readFile, readdir, rm, stat, statfs } from "node:fs/promises";
|
|
36
36
|
import { homedir as homedir$1, tmpdir as tmpdir$1 } from "os";
|
|
37
|
+
//#region src/budget-sweep.ts
|
|
38
|
+
const EMPTY_SWEEP_WINDOW_MS = 3e5;
|
|
39
|
+
function sweepMarker(caches, olderThanDays) {
|
|
40
|
+
const hash = createHash("sha256").update(String(olderThanDays));
|
|
41
|
+
for (const line of caches.map((cache) => `${cache.name}\0${cache.dir}`).toSorted()) hash.update("\n").update(line);
|
|
42
|
+
return hash.digest("hex");
|
|
43
|
+
}
|
|
44
|
+
function canSkipEmptySweep(recorded, now) {
|
|
45
|
+
if (!recorded || recorded.marker !== now.marker) return false;
|
|
46
|
+
const age = now.at - recorded.at;
|
|
47
|
+
return age >= 0 && age < 3e5 && recorded.freeMb - now.freeMb <= 1024;
|
|
48
|
+
}
|
|
49
|
+
function readEmptySweep() {
|
|
50
|
+
const value = readJsonObject(budgetSweepFile());
|
|
51
|
+
if (!value) return null;
|
|
52
|
+
const { at, freeMb, marker } = value;
|
|
53
|
+
return typeof at === "number" && Number.isFinite(at) && typeof freeMb === "number" && Number.isFinite(freeMb) && typeof marker === "string" ? {
|
|
54
|
+
at,
|
|
55
|
+
freeMb,
|
|
56
|
+
marker
|
|
57
|
+
} : null;
|
|
58
|
+
}
|
|
59
|
+
function writeEmptySweep(sweep) {
|
|
60
|
+
const file = budgetSweepFile();
|
|
61
|
+
try {
|
|
62
|
+
mkdirSync(dirname(file), {
|
|
63
|
+
recursive: true,
|
|
64
|
+
mode: 448
|
|
65
|
+
});
|
|
66
|
+
withDirLock$1(budgetSweepLock(), () => {
|
|
67
|
+
if (!sweep) return rmSync(file, { force: true });
|
|
68
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
69
|
+
writeFileSync(tmp, JSON.stringify(sweep), { mode: 384 });
|
|
70
|
+
renameSync(tmp, file);
|
|
71
|
+
});
|
|
72
|
+
} catch {}
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
37
75
|
//#region src/cache/caches.ts
|
|
38
76
|
function xcodeDerivedDataRoot(env) {
|
|
39
77
|
return join$1(env.HOME || env.USERPROFILE || homedir$1(), "Library", "Developer", "Xcode", "DerivedData");
|
|
@@ -204,17 +242,15 @@ function canonicalCacheDir(dir) {
|
|
|
204
242
|
}
|
|
205
243
|
const CACHE_SIZE_TIMEOUT_MS = 6e4;
|
|
206
244
|
async function sizeCaches(caches, operation) {
|
|
207
|
-
|
|
208
|
-
for (const cache of caches) {
|
|
245
|
+
return mapLimited(caches, sizeConcurrency(operation), async (cache) => {
|
|
209
246
|
operation?.signal.throwIfAborted();
|
|
210
247
|
const bytes = cache.bytes ?? await measuredDirectorySizeAsync(cache.dir, {
|
|
211
248
|
timeoutMs: CACHE_SIZE_TIMEOUT_MS,
|
|
212
249
|
operation,
|
|
213
250
|
signal: operation?.signal
|
|
214
251
|
});
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
return sized;
|
|
252
|
+
return Object.assign({}, cache, bytes === null ? { sizeError: "Size unavailable: measurement failed or exceeded 60 seconds." } : { bytes });
|
|
253
|
+
});
|
|
218
254
|
}
|
|
219
255
|
function pruneCache(cache, { olderThanDays, now = Date.now(), protect, evictBytes, byMtime = false } = {}) {
|
|
220
256
|
const cutoff = now - olderThanDays * 24 * 60 * 60 * 1e3;
|
|
@@ -296,18 +332,22 @@ async function pruneCacheAsync(cache, { olderThanDays, now = Date.now(), signal,
|
|
|
296
332
|
};
|
|
297
333
|
const cutoff = now - olderThanDays * 24 * 60 * 60 * 1e3;
|
|
298
334
|
let entries = cache.files ?? [cache.dir];
|
|
335
|
+
let unlisted = 0;
|
|
299
336
|
for (let depth = 0; !cache.files && depth < (cache.entriesDepth ?? 1); depth++) {
|
|
300
337
|
const next = [];
|
|
301
338
|
for (const parent of entries) {
|
|
302
339
|
signal?.throwIfAborted();
|
|
303
|
-
const names = await readdir(parent).catch(() =>
|
|
340
|
+
const names = await readdir(parent).catch((error) => {
|
|
341
|
+
if (error.code !== "ENOENT" && error.code !== "ENOTDIR") unlisted++;
|
|
342
|
+
return [];
|
|
343
|
+
});
|
|
304
344
|
next.push(...names.map((name) => join$1(parent, name)));
|
|
305
345
|
}
|
|
306
346
|
entries = next;
|
|
307
347
|
}
|
|
308
348
|
let removed = 0;
|
|
309
349
|
let bytes = 0;
|
|
310
|
-
let failed =
|
|
350
|
+
let failed = unlisted;
|
|
311
351
|
for (const entry of entries) {
|
|
312
352
|
signal?.throwIfAborted();
|
|
313
353
|
try {
|
|
@@ -2983,9 +3023,32 @@ async function launchedIosAppAfterNoHandle(error, udid, bundleId, exec) {
|
|
|
2983
3023
|
}
|
|
2984
3024
|
async function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null, devMenuParams = false, consolePaths }, { exec = null } = {}) {
|
|
2985
3025
|
const e = exec || getExecutor();
|
|
2986
|
-
const running = await iosAppProcess(udid, bundleId, { exec: e });
|
|
2987
|
-
const stateUnknown = running.state === "unknown";
|
|
2988
3026
|
const launchRestarts = metroPort === null || !devClientScheme || Boolean(consolePaths);
|
|
3027
|
+
const writeJsLocation = async (port) => {
|
|
3028
|
+
try {
|
|
3029
|
+
await e.runFileAsync("xcrun", [
|
|
3030
|
+
"simctl",
|
|
3031
|
+
"spawn",
|
|
3032
|
+
udid,
|
|
3033
|
+
"defaults",
|
|
3034
|
+
"write",
|
|
3035
|
+
bundleId,
|
|
3036
|
+
"RCT_jsLocation",
|
|
3037
|
+
jsLocationValue(port)
|
|
3038
|
+
], { timeoutMs: 6e4 });
|
|
3039
|
+
return null;
|
|
3040
|
+
} catch (err) {
|
|
3041
|
+
return {
|
|
3042
|
+
failed: true,
|
|
3043
|
+
code: LAUNCH_ERROR,
|
|
3044
|
+
reason: `Could not point ${bundleId} at Metro port ${port} (defaults write RCT_jsLocation): ${await describeIosSimulatorFailure(err, e)}`
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
};
|
|
3048
|
+
const runningProbe = iosAppProcess(udid, bundleId, { exec: e });
|
|
3049
|
+
const earlyWrite = metroPort !== null && launchRestarts ? writeJsLocation(metroPort) : null;
|
|
3050
|
+
const running = await runningProbe;
|
|
3051
|
+
const stateUnknown = running.state === "unknown";
|
|
2989
3052
|
const launchArgs = [
|
|
2990
3053
|
"simctl",
|
|
2991
3054
|
"launch",
|
|
@@ -3014,24 +3077,8 @@ async function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null,
|
|
|
3014
3077
|
restart.restartedPid = running.pid;
|
|
3015
3078
|
}
|
|
3016
3079
|
if (metroPort !== null) {
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
"simctl",
|
|
3020
|
-
"spawn",
|
|
3021
|
-
udid,
|
|
3022
|
-
"defaults",
|
|
3023
|
-
"write",
|
|
3024
|
-
bundleId,
|
|
3025
|
-
"RCT_jsLocation",
|
|
3026
|
-
jsLocationValue(metroPort)
|
|
3027
|
-
], { timeoutMs: 6e4 });
|
|
3028
|
-
} catch (err) {
|
|
3029
|
-
return {
|
|
3030
|
-
failed: true,
|
|
3031
|
-
code: LAUNCH_ERROR,
|
|
3032
|
-
reason: `Could not point ${bundleId} at Metro port ${metroPort} (defaults write RCT_jsLocation): ${await describeIosSimulatorFailure(err, e)}`
|
|
3033
|
-
};
|
|
3034
|
-
}
|
|
3080
|
+
const writeFailure = await (earlyWrite ?? writeJsLocation(metroPort));
|
|
3081
|
+
if (writeFailure) return writeFailure;
|
|
3035
3082
|
if (devClientScheme) {
|
|
3036
3083
|
const url = devClientUrl(devClientScheme, metroPort, "localhost", { devMenuParams });
|
|
3037
3084
|
const viaInitialUrl = Boolean(consolePaths) || stateUnknown;
|
|
@@ -3684,6 +3731,7 @@ const MANIFEST_VERIFY_TIMEOUT_MS = 6e4;
|
|
|
3684
3731
|
const STABILITY_WINDOW_MS = 3e3;
|
|
3685
3732
|
const JS_RUNNING_SETTLE_MS = 500;
|
|
3686
3733
|
const VERIFY_POLL_MS = 500;
|
|
3734
|
+
const DEVICE_LOG_LAG_LIMIT_MS = 1e4;
|
|
3687
3735
|
const BUNDLE_EVENTS = /* @__PURE__ */ new Set([
|
|
3688
3736
|
"bundle_build_started",
|
|
3689
3737
|
"bundle_build_done",
|
|
@@ -3737,6 +3785,43 @@ function jsRunningFields(jsRunningAt) {
|
|
|
3737
3785
|
function expoBundleLine(msg) {
|
|
3738
3786
|
return /\bBundl(?:ing|ed)\b/.test(msg);
|
|
3739
3787
|
}
|
|
3788
|
+
function createCrashProbe({ firstAt, everyMs, now, run }) {
|
|
3789
|
+
let nextAt = firstAt;
|
|
3790
|
+
let pending = null;
|
|
3791
|
+
let outcome = null;
|
|
3792
|
+
const consume = () => {
|
|
3793
|
+
const done = outcome;
|
|
3794
|
+
if (!done) return null;
|
|
3795
|
+
pending = null;
|
|
3796
|
+
outcome = null;
|
|
3797
|
+
if ("error" in done) throw done.error;
|
|
3798
|
+
return done.result;
|
|
3799
|
+
};
|
|
3800
|
+
return {
|
|
3801
|
+
get pending() {
|
|
3802
|
+
return pending;
|
|
3803
|
+
},
|
|
3804
|
+
poll() {
|
|
3805
|
+
const found = consume();
|
|
3806
|
+
if (found) return found;
|
|
3807
|
+
if (!pending && now() >= nextAt) {
|
|
3808
|
+
nextAt = now() + everyMs;
|
|
3809
|
+
pending = (async () => {
|
|
3810
|
+
try {
|
|
3811
|
+
outcome = { result: await run() };
|
|
3812
|
+
} catch (error) {
|
|
3813
|
+
outcome = { error };
|
|
3814
|
+
}
|
|
3815
|
+
})();
|
|
3816
|
+
}
|
|
3817
|
+
return null;
|
|
3818
|
+
},
|
|
3819
|
+
async settle() {
|
|
3820
|
+
await pending;
|
|
3821
|
+
return consume();
|
|
3822
|
+
}
|
|
3823
|
+
};
|
|
3824
|
+
}
|
|
3740
3825
|
async function nativeLaunchFailure({ readCrashes, since, platform, processAlive, mode, waitedMs }) {
|
|
3741
3826
|
if (!readCrashes) return null;
|
|
3742
3827
|
const crashes = (await readCrashes()).filter((record) => record.event === "native_crash" && after(record, since) && recordCouldBelongToPlatform(record, platform));
|
|
@@ -3762,15 +3847,22 @@ function manifestDeadline(records, { startedAt, timeoutMs }) {
|
|
|
3762
3847
|
if (open.size > 0) return cap;
|
|
3763
3848
|
return servedAt === null ? base : Math.min(cap, Math.max(base, servedAt + MANIFEST_GRACE_MS));
|
|
3764
3849
|
}
|
|
3765
|
-
async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metroPort = null, platform = null, mode = null, requireBundleResponse, timeoutMs = VERIFY_TIMEOUT_MS, stabilityMs = STABILITY_WINDOW_MS, pollMs = VERIFY_POLL_MS, readRecords = null, readDeviceRecords = null, readClientRecords = null, readNativeCrashes = null, processAlive = null, onReadinessPending = null, onActivity, now = Date.now, sleep = (ms) =>
|
|
3850
|
+
async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metroPort = null, platform = null, mode = null, requireBundleResponse, timeoutMs = VERIFY_TIMEOUT_MS, stabilityMs = STABILITY_WINDOW_MS, pollMs = VERIFY_POLL_MS, readRecords = null, readDeviceRecords = null, readClientRecords = null, readNativeCrashes = null, processAlive = null, onReadinessPending = null, onActivity, deviceLogsThrough, now = Date.now, signal, sleep = (ms) => cancellableSleep(ms, {
|
|
3851
|
+
signal,
|
|
3852
|
+
what: "launch readiness check"
|
|
3853
|
+
}) } = {}) {
|
|
3766
3854
|
const delivered = (record) => deliveryOwner(record, {
|
|
3767
3855
|
slot,
|
|
3768
3856
|
appPid,
|
|
3769
3857
|
platformShared
|
|
3770
3858
|
}) === "this";
|
|
3771
|
-
const read = readRecords || (
|
|
3772
|
-
const readDevice = readDeviceRecords || (
|
|
3773
|
-
const readClient = readClientRecords || (
|
|
3859
|
+
const read = readRecords || tailNdjson(logsDir, "metro.ndjson");
|
|
3860
|
+
const readDevice = readDeviceRecords || tailNdjson(logsDir, "device.ndjson");
|
|
3861
|
+
const readClient = readClientRecords || tailNdjson(logsDir, "client.ndjson");
|
|
3862
|
+
const deviceNow = () => {
|
|
3863
|
+
const at = now();
|
|
3864
|
+
return deviceLogsThrough ? Math.max(Math.min(at, deviceLogsThrough() ?? -Infinity), at - DEVICE_LOG_LAG_LIMIT_MS) : at;
|
|
3865
|
+
};
|
|
3774
3866
|
const startedAt = now();
|
|
3775
3867
|
const baseTimeoutMs = Math.max(0, timeoutMs);
|
|
3776
3868
|
let bundleDeadline = startedAt + baseTimeoutMs;
|
|
@@ -3781,7 +3873,19 @@ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metr
|
|
|
3781
3873
|
let deliveryId = null;
|
|
3782
3874
|
let runtimeLoadingAt = null;
|
|
3783
3875
|
let runtimeStartedAt = null;
|
|
3784
|
-
|
|
3876
|
+
const crashProbe = createCrashProbe({
|
|
3877
|
+
firstAt: startedAt + 1e3,
|
|
3878
|
+
everyMs: 2e3,
|
|
3879
|
+
now,
|
|
3880
|
+
run: () => nativeLaunchFailure({
|
|
3881
|
+
readCrashes: readNativeCrashes,
|
|
3882
|
+
since,
|
|
3883
|
+
platform,
|
|
3884
|
+
processAlive,
|
|
3885
|
+
mode,
|
|
3886
|
+
waitedMs: 0
|
|
3887
|
+
})
|
|
3888
|
+
});
|
|
3785
3889
|
let bundlingAt = null;
|
|
3786
3890
|
let reported = null;
|
|
3787
3891
|
const report = (name, at) => {
|
|
@@ -3789,131 +3893,149 @@ async function verifyLaunch({ slot, appPid, platformShared, logsDir, since, metr
|
|
|
3789
3893
|
reported = name;
|
|
3790
3894
|
onActivity?.(name, at);
|
|
3791
3895
|
};
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
if (now() >= nextCrashCheck) {
|
|
3802
|
-
nextCrashCheck = now() + 2e3;
|
|
3803
|
-
const crash = await nativeLaunchFailure({
|
|
3804
|
-
readCrashes: readNativeCrashes,
|
|
3805
|
-
since,
|
|
3806
|
-
platform,
|
|
3807
|
-
processAlive,
|
|
3808
|
-
mode,
|
|
3809
|
-
waitedMs: now() - startedAt
|
|
3896
|
+
const loop = async () => {
|
|
3897
|
+
while (true) {
|
|
3898
|
+
const metroRecords = read().filter((record) => after(record, since));
|
|
3899
|
+
const bundleRecords = metroRecords.filter((record) => (!requireBundleResponse || String(record.event).startsWith("bundle_response_")) && delivered(record));
|
|
3900
|
+
const deviceRecords = readDevice().filter((record) => after(record, since) && (slot === void 0 || (record.slot ?? "default") === slot));
|
|
3901
|
+
const clientRecords = readClient().filter((record) => after(record, since) && !platformShared);
|
|
3902
|
+
bundleDeadline = manifestDeadline(metroRecords.filter((record) => String(record.event).startsWith("manifest_request_") && (!platform || record.platform === platform)), {
|
|
3903
|
+
startedAt,
|
|
3904
|
+
timeoutMs: baseTimeoutMs
|
|
3810
3905
|
});
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3906
|
+
const crash = crashProbe.poll();
|
|
3907
|
+
if (crash) return {
|
|
3908
|
+
...crash,
|
|
3909
|
+
waitedMs: now() - startedAt
|
|
3910
|
+
};
|
|
3911
|
+
if (deliveryId === null) {
|
|
3912
|
+
const request = bundleRecords.find((record) => record.event === "bundle_response_started" && typeof record.requestId === "string" && isBundleProof(record, since, platform));
|
|
3913
|
+
if (request) {
|
|
3914
|
+
deliveryId = request.requestId;
|
|
3915
|
+
bundlingAt = request;
|
|
3916
|
+
proof = null;
|
|
3917
|
+
stabilityDeadline = null;
|
|
3918
|
+
}
|
|
3820
3919
|
}
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3920
|
+
for (const record of bundleRecords) {
|
|
3921
|
+
if (isBundleProof(record, since, platform)) activity = record;
|
|
3922
|
+
const completed = deliveryId === null ? isBundleReadyProof(record, since, platform) : record.event === "bundle_response_finished" && record.requestId === deliveryId && isBundleProof(record, since, platform);
|
|
3923
|
+
if (!proof && completed) {
|
|
3924
|
+
proof = record;
|
|
3925
|
+
stabilityDeadline = Number(record.ts) + Math.max(0, stabilityMs);
|
|
3926
|
+
}
|
|
3828
3927
|
}
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
if (loading) runtimeLoadingAt = Number(loading.ts);
|
|
3834
|
-
}
|
|
3835
|
-
if (runtimeLoadingAt !== null && runtimeStartedAt === null) {
|
|
3836
|
-
const executing = signals.find((record) => record.src === "device" && record.platform === "android" && Number(record.ts) >= runtimeLoadingAt && (/^ReactNativeJS\(\d+\)$/.test(String(record.proc)) || appReadinessSignal(record, platform) !== null));
|
|
3837
|
-
if (executing) runtimeStartedAt = Number(executing.ts);
|
|
3838
|
-
}
|
|
3839
|
-
const runtimeWaiting = runtimeLoadingAt !== null && runtimeStartedAt === null;
|
|
3840
|
-
const completedAt = proof ? Math.max(Number(proof.ts), runtimeStartedAt ?? 0) : null;
|
|
3841
|
-
if (completedAt !== null) stabilityDeadline = completedAt + Math.max(0, stabilityMs);
|
|
3842
|
-
const jsRunningAt = jsRunningSince(signals, completedAt, runtimeWaiting, platform);
|
|
3843
|
-
const windowEnd = settledWindowEnd(stabilityDeadline, jsRunningAt);
|
|
3844
|
-
const readinessDeadline = completedAt !== null ? completedAt + APP_READINESS_TIMEOUT_MS : bundleDeadline;
|
|
3845
|
-
if (pendingAt === null) {
|
|
3846
|
-
const pending = signals.find((record) => appReadinessSignal(record, platform) === "pending" && (runtimeWaiting || stabilityDeadline === null || Number(record.ts) <= stabilityDeadline));
|
|
3847
|
-
if (pending) {
|
|
3848
|
-
pendingAt = Number(pending.ts);
|
|
3849
|
-
onReadinessPending?.();
|
|
3928
|
+
const signals = deviceRecords.filter((record) => Number(record.ts) <= now()).toSorted((a, b) => Number(a.ts) - Number(b.ts));
|
|
3929
|
+
if (platform === "android" && runtimeLoadingAt === null) {
|
|
3930
|
+
const loading = signals.find((record) => record.src === "device" && record.platform === "android" && /^(?:unknown:)?BridgelessReact\(\d+\)$/.test(String(record.proc)) && /^ReactHost\{\d+\}\.getOrCreateReactInstanceTask\(\): Loading JS Bundle$/.test(String(record.msg)) && (stabilityDeadline === null || Number(record.ts) <= stabilityDeadline));
|
|
3931
|
+
if (loading) runtimeLoadingAt = Number(loading.ts);
|
|
3850
3932
|
}
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
const
|
|
3857
|
-
|
|
3858
|
-
const
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3933
|
+
if (runtimeLoadingAt !== null && runtimeStartedAt === null) {
|
|
3934
|
+
const executing = signals.find((record) => record.src === "device" && record.platform === "android" && Number(record.ts) >= runtimeLoadingAt && (/^ReactNativeJS\(\d+\)$/.test(String(record.proc)) || appReadinessSignal(record, platform) !== null));
|
|
3935
|
+
if (executing) runtimeStartedAt = Number(executing.ts);
|
|
3936
|
+
}
|
|
3937
|
+
const runtimeWaiting = runtimeLoadingAt !== null && runtimeStartedAt === null;
|
|
3938
|
+
const completedAt = proof ? Math.max(Number(proof.ts), runtimeStartedAt ?? 0) : null;
|
|
3939
|
+
if (completedAt !== null) stabilityDeadline = completedAt + Math.max(0, stabilityMs);
|
|
3940
|
+
const jsRunningAt = jsRunningSince(signals, completedAt, runtimeWaiting, platform);
|
|
3941
|
+
const windowEnd = settledWindowEnd(stabilityDeadline, jsRunningAt);
|
|
3942
|
+
const readinessDeadline = completedAt !== null ? completedAt + APP_READINESS_TIMEOUT_MS : bundleDeadline;
|
|
3943
|
+
if (pendingAt === null) {
|
|
3944
|
+
const pending = signals.find((record) => appReadinessSignal(record, platform) === "pending" && (runtimeWaiting || stabilityDeadline === null || Number(record.ts) <= stabilityDeadline));
|
|
3945
|
+
if (pending) {
|
|
3946
|
+
pendingAt = Number(pending.ts);
|
|
3947
|
+
onReadinessPending?.();
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
report(...launchActivity(pendingAt, proof, bundlingAt));
|
|
3951
|
+
const ready = pendingAt !== null && signals.some((record) => Number(record.ts) >= pendingAt && Number(record.ts) <= readinessDeadline && appReadinessSignal(record, platform) === "ready");
|
|
3952
|
+
const bundleErrors = bundleRecords.filter((record) => isFatalLaunchError(record, platform) || deliveryId !== null && record.event === "bundle_response_failed" && record.requestId === deliveryId && isBundleProof(record, since, platform));
|
|
3953
|
+
if (bundleErrors.length) {
|
|
3954
|
+
const alive = processAlive ? await processAlive() : null;
|
|
3955
|
+
const fatalRecord = bundleErrors[bundleErrors.length - 1];
|
|
3956
|
+
const fatalAt = Number(fatalRecord?.ts ?? since ?? 0);
|
|
3957
|
+
return {
|
|
3958
|
+
verified: false,
|
|
3959
|
+
fatal: true,
|
|
3960
|
+
errors: metroRecords.filter((record) => after(record, fatalAt) && recordCouldBelongToPlatform(record, platform) && isLaunchError(record, platform)),
|
|
3961
|
+
processAlive: alive,
|
|
3962
|
+
record: fatalRecord,
|
|
3963
|
+
mode,
|
|
3964
|
+
waitedMs: now() - startedAt,
|
|
3965
|
+
...pendingAt !== null ? { readiness: "error" } : {}
|
|
3966
|
+
};
|
|
3967
|
+
}
|
|
3968
|
+
if (proof && windowEnd !== null && (pendingAt !== null || deviceNow() >= windowEnd)) {
|
|
3969
|
+
const errorSince = pendingAt === null ? Number(proof.ts ?? since ?? 0) : Number(since ?? 0);
|
|
3970
|
+
const errors = [
|
|
3971
|
+
...metroRecords.filter((record) => after(record, errorSince) && recordCouldBelongToPlatform(record, platform)),
|
|
3972
|
+
...deviceRecords.filter((record) => after(record, errorSince) && recordCouldBelongToPlatform(record, platform)),
|
|
3973
|
+
...clientRecords.filter((record) => after(record, errorSince) && recordCouldBelongToPlatform(record, platform))
|
|
3974
|
+
].filter((record) => isLaunchError(record, platform));
|
|
3975
|
+
const alive = processAlive ? await processAlive() : null;
|
|
3976
|
+
const waitedMs = now() - startedAt;
|
|
3977
|
+
if (alive === false) return {
|
|
3978
|
+
verified: false,
|
|
3979
|
+
fatal: true,
|
|
3980
|
+
errors,
|
|
3981
|
+
processAlive: alive,
|
|
3982
|
+
record: proof,
|
|
3983
|
+
mode,
|
|
3984
|
+
waitedMs,
|
|
3985
|
+
...pendingAt !== null ? { readiness: "error" } : {}
|
|
3986
|
+
};
|
|
3987
|
+
const actionableErrors = errors.filter((record) => !isIosConnectionRefusal(record, platform));
|
|
3988
|
+
const appErrors = actionableErrors.some(isAppLaunchError);
|
|
3989
|
+
if (!runtimeWaiting && pendingAt === null || appErrors || ready || deviceNow() >= readinessDeadline) return {
|
|
3990
|
+
verified: true,
|
|
3991
|
+
record: proof,
|
|
3992
|
+
errors: actionableErrors,
|
|
3993
|
+
processAlive: alive,
|
|
3994
|
+
mode,
|
|
3995
|
+
waitedMs,
|
|
3996
|
+
...pendingAt !== null ? { readiness: appErrors ? "error" : ready ? "ready" : "timed-out" } : {},
|
|
3997
|
+
...jsRunningFields(jsRunningAt)
|
|
3998
|
+
};
|
|
3999
|
+
}
|
|
4000
|
+
if ((!proof || runtimeWaiting) && now() >= bundleDeadline) return await bundleTimeoutOutcome({
|
|
4001
|
+
requested: findBundleRequest(deviceRecords, since, metroPort, platform) ?? activity,
|
|
4002
|
+
unattributed: metroRecords.find((record) => record.event === "bundle_response_finished" && deliveryOwner(record, {
|
|
4003
|
+
slot,
|
|
4004
|
+
appPid,
|
|
4005
|
+
platformShared
|
|
4006
|
+
}) === "unknown" && isBundleProof(record, since, platform)) ?? null,
|
|
4007
|
+
processAlive,
|
|
4008
|
+
deviceRecords,
|
|
4009
|
+
platform,
|
|
3896
4010
|
mode,
|
|
3897
|
-
waitedMs
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
4011
|
+
waitedMs: now() - startedAt
|
|
4012
|
+
});
|
|
4013
|
+
const nap = sleep(Math.min(pollMs, Math.max(0, (runtimeWaiting ? bundleDeadline : proof && pendingAt !== null ? readinessDeadline : windowEnd ?? bundleDeadline) - deviceNow())));
|
|
4014
|
+
await (crashProbe.pending ? Promise.race([nap, crashProbe.pending]) : nap);
|
|
3901
4015
|
}
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
processAlive,
|
|
3910
|
-
deviceRecords,
|
|
3911
|
-
platform,
|
|
3912
|
-
mode,
|
|
3913
|
-
waitedMs: now() - startedAt
|
|
3914
|
-
});
|
|
3915
|
-
await sleep(Math.min(pollMs, Math.max(0, (runtimeWaiting ? bundleDeadline : proof && pendingAt !== null ? readinessDeadline : windowEnd ?? bundleDeadline) - now())));
|
|
4016
|
+
};
|
|
4017
|
+
let result;
|
|
4018
|
+
try {
|
|
4019
|
+
result = await loop();
|
|
4020
|
+
} catch (error) {
|
|
4021
|
+
await crashProbe.settle().catch(() => {});
|
|
4022
|
+
throw error;
|
|
3916
4023
|
}
|
|
4024
|
+
const probed = crashProbe.pending !== null;
|
|
4025
|
+
const late = await crashProbe.settle();
|
|
4026
|
+
if (late) return {
|
|
4027
|
+
...late,
|
|
4028
|
+
waitedMs: now() - startedAt
|
|
4029
|
+
};
|
|
4030
|
+
if (probed && result.verified && await processAlive?.() === false) return {
|
|
4031
|
+
...result,
|
|
4032
|
+
verified: false,
|
|
4033
|
+
fatal: true,
|
|
4034
|
+
processAlive: false,
|
|
4035
|
+
waitedMs: now() - startedAt,
|
|
4036
|
+
...result.readiness ? { readiness: "error" } : {}
|
|
4037
|
+
};
|
|
4038
|
+
return result;
|
|
3917
4039
|
}
|
|
3918
4040
|
function launchActivity(pendingAt, proof, bundling) {
|
|
3919
4041
|
if (pendingAt !== null) return ["waiting-ready", pendingAt];
|
|
@@ -4007,6 +4129,9 @@ function readCollectorRecords(logsDir) {
|
|
|
4007
4129
|
function readNdjson(logsDir, name) {
|
|
4008
4130
|
return logsDir ? readNdjsonGenerations$1(join(logsDir, name)) : [];
|
|
4009
4131
|
}
|
|
4132
|
+
function tailNdjson(logsDir, name) {
|
|
4133
|
+
return logsDir ? createNdjsonTail(join(logsDir, name)) : () => [];
|
|
4134
|
+
}
|
|
4010
4135
|
function unattributedLaunchLines({ platform, metroPort, slot = "default", siblings }) {
|
|
4011
4136
|
const others = siblings.length === 1 ? `Slot ${siblings[0]} also runs` : `Slots ${siblings.join(", ")} also run`;
|
|
4012
4137
|
return [
|
|
@@ -6209,11 +6334,11 @@ function directories(dir, notices) {
|
|
|
6209
6334
|
}
|
|
6210
6335
|
function scopedOutside(gradleHome, env) {
|
|
6211
6336
|
if (!deviceSweepIsScoped(env)) return false;
|
|
6212
|
-
const rel = relative(canonical(getConfigDir()), gradleHome);
|
|
6337
|
+
const rel = relative(canonical$1(getConfigDir()), gradleHome);
|
|
6213
6338
|
return rel === "" || rel.startsWith("..") || isAbsolute(rel);
|
|
6214
6339
|
}
|
|
6215
6340
|
function gradleUserHome(env, cwd) {
|
|
6216
|
-
return canonical(envDir("GRADLE_USER_HOME", env, cwd) ?? join(env?.HOME || env?.USERPROFILE || homedir(), ".gradle"));
|
|
6341
|
+
return canonical$1(envDir("GRADLE_USER_HOME", env, cwd) ?? join(env?.HOME || env?.USERPROFILE || homedir(), ".gradle"));
|
|
6217
6342
|
}
|
|
6218
6343
|
/** Each Gradle version's `caches/<version>` and `wrapper/dists/gradle-<version>-*` directories under `gradleHome`. */
|
|
6219
6344
|
function gradleVersionDirs(gradleHome, notices) {
|
|
@@ -7122,7 +7247,7 @@ async function emptyCache(cache, signal, operation) {
|
|
|
7122
7247
|
}
|
|
7123
7248
|
function reportFailures(cache, failed, { log, record, fail }) {
|
|
7124
7249
|
if (!failed) return false;
|
|
7125
|
-
const message = `${failed} entr${failed === 1 ? "y" : "ies"} in ${cache.dir} could not be removed`;
|
|
7250
|
+
const message = `${failed} entr${failed === 1 ? "y" : "ies"} in ${cache.dir} could not be read or removed`;
|
|
7126
7251
|
log(chalk.red(`${cache.name}: ${message}`));
|
|
7127
7252
|
record("cache", "failed", cache.name, {
|
|
7128
7253
|
id: cache.dir,
|
|
@@ -7136,6 +7261,7 @@ async function trimCaches(caches, olderThan, output = GC_OUTPUT, signal, operati
|
|
|
7136
7261
|
let cacheBytes = 0;
|
|
7137
7262
|
let failures = 0;
|
|
7138
7263
|
const trimmed = [];
|
|
7264
|
+
let unchanged = 0;
|
|
7139
7265
|
for (const c of caches) {
|
|
7140
7266
|
signal?.throwIfAborted();
|
|
7141
7267
|
if (c.machineGlobal) {
|
|
@@ -7165,9 +7291,10 @@ async function trimCaches(caches, olderThan, output = GC_OUTPUT, signal, operati
|
|
|
7165
7291
|
bytes: r.bytes
|
|
7166
7292
|
});
|
|
7167
7293
|
log(chalk.green(`Trimmed ${c.name}: ${r.removed} entr${r.removed === 1 ? "y" : "ies"} (${formatBytes(r.bytes)})`));
|
|
7168
|
-
} else if (!r.failed)
|
|
7294
|
+
} else if (!r.failed) unchanged++;
|
|
7169
7295
|
if (reportFailures(c, r.failed, output)) failures++;
|
|
7170
7296
|
}
|
|
7297
|
+
if (unchanged) log(chalk.dim(`${unchanged} cache${unchanged === 1 ? "" : "s"}: nothing older than ${olderThan}d`));
|
|
7171
7298
|
if (cacheBytes) log(chalk.dim(`Trimmed ${formatBytes(cacheBytes)} of shared cache. The next build that wanted those entries pays to rebuild them.`));
|
|
7172
7299
|
return {
|
|
7173
7300
|
trimmed,
|
|
@@ -7177,6 +7304,7 @@ async function trimCaches(caches, olderThan, output = GC_OUTPUT, signal, operati
|
|
|
7177
7304
|
async function emptyCaches(caches, output = GC_OUTPUT, signal, operation) {
|
|
7178
7305
|
const { log, record } = output;
|
|
7179
7306
|
let cacheBytes = 0;
|
|
7307
|
+
let failures = 0;
|
|
7180
7308
|
for (const c of caches) {
|
|
7181
7309
|
signal?.throwIfAborted();
|
|
7182
7310
|
if (!c.willEmpty) {
|
|
@@ -7202,1355 +7330,188 @@ async function emptyCaches(caches, output = GC_OUTPUT, signal, operation) {
|
|
|
7202
7330
|
});
|
|
7203
7331
|
log(chalk.green(`Emptied ${c.name}: ${r.removed} entr${r.removed === 1 ? "y" : "ies"} (${formatBytes(r.bytes)})`));
|
|
7204
7332
|
} else if (!r.failed) log(chalk.dim(`${c.name}: already empty`));
|
|
7205
|
-
reportFailures(c, r.failed, output)
|
|
7333
|
+
if (reportFailures(c, r.failed, output)) failures++;
|
|
7206
7334
|
}
|
|
7207
7335
|
if (cacheBytes) log(chalk.dim(`Emptied ${formatBytes(cacheBytes)} of shared cache. Every build that wanted any of it now pays to rebuild it.`));
|
|
7336
|
+
return failures;
|
|
7208
7337
|
}
|
|
7209
7338
|
//#endregion
|
|
7210
|
-
//#region src/
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
}
|
|
7219
|
-
function updateStats(record, run, now) {
|
|
7220
|
-
const at = new Date(now).toISOString();
|
|
7221
|
-
const durationMs = wholeMs(run.durationMs);
|
|
7222
|
-
const phases = {
|
|
7223
|
-
coldBuildMs: wholeMs(run.coldBuildMs),
|
|
7224
|
-
podsMs: wholeMs(run.podsMs)
|
|
7225
|
-
};
|
|
7226
|
-
const projects = { ...record.projects };
|
|
7227
|
-
const scope = { ...projects[run.projectKey] };
|
|
7228
|
-
const machine = { ...record.machine };
|
|
7229
|
-
const before = scope[run.platform] ?? null;
|
|
7230
|
-
const credit = creditMs(before, run, durationMs);
|
|
7231
|
-
scope[run.platform] = applyRun(before, run, {
|
|
7232
|
-
at,
|
|
7233
|
-
durationMs,
|
|
7234
|
-
credit,
|
|
7235
|
-
phases
|
|
7236
|
-
});
|
|
7237
|
-
projects[run.projectKey] = scope;
|
|
7238
|
-
machine[run.platform] = applyRun(machine[run.platform] ?? null, run, {
|
|
7239
|
-
at,
|
|
7240
|
-
durationMs,
|
|
7241
|
-
credit,
|
|
7242
|
-
phases
|
|
7243
|
-
});
|
|
7244
|
-
const history = { ...record.history };
|
|
7245
|
-
if (run.phases && !run.failed && !run.waitedForBuild && !run.offloadedTo) {
|
|
7246
|
-
const outcome = isHit(run.cacheHit) ? "hit" : "cold";
|
|
7247
|
-
const project = { ...history[run.projectKey] };
|
|
7248
|
-
const lists = { ...project[run.platform] };
|
|
7249
|
-
const sample = {
|
|
7250
|
-
at,
|
|
7251
|
-
durationMs,
|
|
7252
|
-
phases: wholePhases(run.phases),
|
|
7253
|
-
...run.deviceSetup === void 0 ? {} : { deviceSetup: run.deviceSetup }
|
|
7254
|
-
};
|
|
7255
|
-
lists[outcome] = trimSamples([...lists[outcome] ?? [], sample]);
|
|
7256
|
-
project[run.platform] = lists;
|
|
7257
|
-
history[run.projectKey] = project;
|
|
7258
|
-
}
|
|
7259
|
-
let placements = record.placements;
|
|
7260
|
-
let buildMachines = record.buildMachines;
|
|
7261
|
-
if (run.placement) {
|
|
7262
|
-
const placement = buildPlacement(run, before, at);
|
|
7263
|
-
placements = trimPlacements([...placements ?? [], placement], now);
|
|
7264
|
-
if (placement.machine && placement.decision !== "here") buildMachines = {
|
|
7265
|
-
...buildMachines,
|
|
7266
|
-
[placement.machine]: applyPlacement(buildMachines?.[placement.machine], placement)
|
|
7267
|
-
};
|
|
7268
|
-
}
|
|
7269
|
-
const capacityRefusals = trimCapacityRefusals(record.capacityRefusals ?? [], now);
|
|
7270
|
-
const capacityWaits = trimCapacityWaits(record.capacityWaits ?? [], now);
|
|
7271
|
-
return {
|
|
7272
|
-
version: STATS_VERSION,
|
|
7273
|
-
machine,
|
|
7274
|
-
projects,
|
|
7275
|
-
...Object.keys(history).length ? { history } : {},
|
|
7276
|
-
...placements?.length ? { placements } : {},
|
|
7277
|
-
...capacityRefusals.length ? { capacityRefusals } : {},
|
|
7278
|
-
...capacityWaits.length ? { capacityWaits } : {},
|
|
7279
|
-
...buildMachines && Object.keys(buildMachines).length ? { buildMachines } : {}
|
|
7280
|
-
};
|
|
7281
|
-
}
|
|
7282
|
-
function buildPlacement(run, before, at) {
|
|
7283
|
-
const placement = run.placement;
|
|
7284
|
-
const buildMs = wholeMs(placement.decision === "offloaded" ? placement.buildMs : run.coldBuildMs);
|
|
7285
|
-
const localEstimateMs = wholeMs(before?.lastColdBuildMs);
|
|
7286
|
-
const slotWaitMs = wholeMs(placement.slotWaitMs);
|
|
7287
|
-
const deviceSlotWaitMs = wholeMs(placement.deviceSlotWaitMs);
|
|
7288
|
-
return {
|
|
7289
|
-
at,
|
|
7290
|
-
project: run.projectKey,
|
|
7291
|
-
platform: run.platform,
|
|
7292
|
-
decision: placement.decision,
|
|
7293
|
-
reason: placement.reason,
|
|
7294
|
-
...placement.machine ? { machine: placement.machine } : {},
|
|
7295
|
-
...buildMs > 0 ? { buildMs } : {},
|
|
7296
|
-
...slotWaitMs > 0 ? { slotWaitMs } : {},
|
|
7297
|
-
...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {},
|
|
7298
|
-
...localEstimateMs > 0 ? { localEstimateMs } : {},
|
|
7299
|
-
...run.failed ? { failed: true } : {}
|
|
7300
|
-
};
|
|
7301
|
-
}
|
|
7302
|
-
function applyPlacement(totals, placement) {
|
|
7303
|
-
const next = totals ? { ...totals } : {
|
|
7304
|
-
offloaded: 0,
|
|
7305
|
-
offloadedMs: 0,
|
|
7306
|
-
savedMs: 0,
|
|
7307
|
-
fallbacks: 0
|
|
7308
|
-
};
|
|
7309
|
-
if (placement.decision === "fell-back") {
|
|
7310
|
-
next.fallbacks += 1;
|
|
7311
|
-
next.lastFallbackAt = placement.at;
|
|
7312
|
-
return next;
|
|
7313
|
-
}
|
|
7314
|
-
next.offloaded += 1;
|
|
7315
|
-
next.offloadedMs += placement.buildMs ?? 0;
|
|
7316
|
-
if (placement.localEstimateMs && placement.buildMs) next.savedMs += placement.localEstimateMs - placement.buildMs;
|
|
7317
|
-
next.lastOffloadAt = placement.at;
|
|
7318
|
-
return next;
|
|
7319
|
-
}
|
|
7320
|
-
function trimPlacements(placements, now) {
|
|
7321
|
-
return placements.filter((each) => now - Date.parse(each.at) <= PLACEMENT_MAX_AGE_MS).slice(-100);
|
|
7322
|
-
}
|
|
7323
|
-
function recordRunStats(run, now) {
|
|
7324
|
-
return withConfigLock$1(() => {
|
|
7325
|
-
const path = statsFile();
|
|
7326
|
-
const loaded = loadForUpdate(path, now);
|
|
7327
|
-
if (loaded.newerVersion !== null) return {
|
|
7328
|
-
recorded: false,
|
|
7329
|
-
note: `Run statistics at ${path} are version ${loaded.newerVersion}, which this Stim does not understand, so this run was not recorded.`
|
|
7330
|
-
};
|
|
7331
|
-
writeStats(path, updateStats(loaded.record, run, now));
|
|
7332
|
-
return {
|
|
7333
|
-
recorded: true,
|
|
7334
|
-
note: loaded.note
|
|
7335
|
-
};
|
|
7339
|
+
//#region src/maintenance/log.ts
|
|
7340
|
+
function openRetainedLog(file, settings) {
|
|
7341
|
+
ensurePrivateDir(dirname(file));
|
|
7342
|
+
const rotated = rotatedLogPath(file);
|
|
7343
|
+
withDirLock(`${file}.lock`, () => {
|
|
7344
|
+
try {
|
|
7345
|
+
if (Date.now() - statSync(rotated).mtimeMs > settings.logRetentionDays * 864e5) unlinkSync(rotated);
|
|
7346
|
+
} catch {}
|
|
7336
7347
|
});
|
|
7348
|
+
return createNdjsonWriter(file, { maxBytes: settings.logMaxMb * 1024 ** 2 });
|
|
7337
7349
|
}
|
|
7338
|
-
function
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
const path = statsFile();
|
|
7342
|
-
const loaded = loadForUpdate(path, now, false);
|
|
7343
|
-
if (!loaded.record || loaded.newerVersion !== null) return;
|
|
7344
|
-
const capacityRefusals = trimCapacityRefusals([...loaded.record.capacityRefusals ?? [], {
|
|
7345
|
-
...event,
|
|
7346
|
-
at: new Date(now).toISOString(),
|
|
7347
|
-
kind: "device"
|
|
7348
|
-
}], now);
|
|
7349
|
-
writeStats(path, {
|
|
7350
|
-
...loaded.record,
|
|
7351
|
-
capacityRefusals
|
|
7352
|
-
});
|
|
7353
|
-
});
|
|
7354
|
-
} catch {}
|
|
7355
|
-
}
|
|
7356
|
-
function recordCapacityWait(event, now) {
|
|
7357
|
-
try {
|
|
7358
|
-
withConfigLock$1(() => {
|
|
7359
|
-
const path = statsFile();
|
|
7360
|
-
const loaded = loadForUpdate(path, now, false);
|
|
7361
|
-
if (!loaded.record || loaded.newerVersion !== null) return;
|
|
7362
|
-
const capacityWaits = trimCapacityWaits([...loaded.record.capacityWaits ?? [], {
|
|
7363
|
-
platform: event.platform,
|
|
7364
|
-
max: event.max,
|
|
7365
|
-
workspace: event.workspace,
|
|
7366
|
-
ms: wholeMs(event.ms),
|
|
7367
|
-
...event.reclaimed && Number.isInteger(event.reclaimed) && event.reclaimed > 0 ? { reclaimed: event.reclaimed } : {},
|
|
7368
|
-
at: new Date(now).toISOString(),
|
|
7369
|
-
kind: "device-wait"
|
|
7370
|
-
}], now);
|
|
7371
|
-
writeStats(path, {
|
|
7372
|
-
...loaded.record,
|
|
7373
|
-
capacityWaits
|
|
7374
|
-
});
|
|
7375
|
-
});
|
|
7376
|
-
} catch {}
|
|
7377
|
-
}
|
|
7378
|
-
function createRunRecorder({ platform, write, now, note, phases, deviceSetup }) {
|
|
7379
|
-
let projectKey = null;
|
|
7380
|
-
let cacheKey = null;
|
|
7381
|
-
let coldBuildMs = 0;
|
|
7382
|
-
let podsMs = 0;
|
|
7383
|
-
let placement = null;
|
|
7384
|
-
let deviceSlotWaitMs = 0;
|
|
7385
|
-
let recorded = false;
|
|
7386
|
-
return {
|
|
7387
|
-
setProject(key) {
|
|
7388
|
-
projectKey = key;
|
|
7389
|
-
},
|
|
7390
|
-
setCacheKey(key) {
|
|
7391
|
-
cacheKey = key;
|
|
7392
|
-
},
|
|
7393
|
-
setBuildMs(ms) {
|
|
7394
|
-
coldBuildMs = wholeMs(ms);
|
|
7395
|
-
},
|
|
7396
|
-
setPodsMs(ms) {
|
|
7397
|
-
podsMs = wholeMs(ms);
|
|
7398
|
-
},
|
|
7399
|
-
addDeviceSlotWaitMs(ms) {
|
|
7400
|
-
deviceSlotWaitMs += wholeMs(ms);
|
|
7401
|
-
},
|
|
7402
|
-
deviceSlotWaitMs() {
|
|
7403
|
-
return deviceSlotWaitMs || void 0;
|
|
7404
|
-
},
|
|
7405
|
-
setPlacement(next) {
|
|
7406
|
-
placement = next;
|
|
7407
|
-
},
|
|
7408
|
-
record({ failed, cacheHit = false, waited = null, durationMs, offloadedTo = null }) {
|
|
7409
|
-
if (!projectKey || !cacheKey || recorded) return;
|
|
7410
|
-
recorded = true;
|
|
7411
|
-
const ran = failed ? {} : phases?.() ?? {};
|
|
7412
|
-
try {
|
|
7413
|
-
const outcome = write({
|
|
7414
|
-
platform,
|
|
7415
|
-
projectKey,
|
|
7416
|
-
failed,
|
|
7417
|
-
cacheHit,
|
|
7418
|
-
waitedForBuild: Boolean(waited),
|
|
7419
|
-
durationMs,
|
|
7420
|
-
...offloadedTo ? { offloadedTo } : {},
|
|
7421
|
-
...coldBuildMs > 0 ? { coldBuildMs } : {},
|
|
7422
|
-
...podsMs > 0 ? { podsMs } : {},
|
|
7423
|
-
...Object.keys(ran).length ? { phases: ran } : {},
|
|
7424
|
-
...failed || deviceSetup?.() === void 0 ? {} : { deviceSetup: deviceSetup() },
|
|
7425
|
-
...placement ? { placement: {
|
|
7426
|
-
...placement,
|
|
7427
|
-
...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {}
|
|
7428
|
-
} } : {}
|
|
7429
|
-
}, now());
|
|
7430
|
-
if (outcome?.note) note(outcome.note);
|
|
7431
|
-
} catch (error) {
|
|
7432
|
-
note(`Run statistics could not be recorded: ${error?.message || error}`);
|
|
7433
|
-
}
|
|
7434
|
-
}
|
|
7435
|
-
};
|
|
7436
|
-
}
|
|
7437
|
-
function loadForUpdate(path, now, recoverCorrupt = true) {
|
|
7438
|
-
let text;
|
|
7439
|
-
try {
|
|
7440
|
-
text = readFileSync(path, "utf-8");
|
|
7441
|
-
} catch {
|
|
7442
|
-
return {
|
|
7443
|
-
record: emptyStats(),
|
|
7444
|
-
note: null,
|
|
7445
|
-
newerVersion: null
|
|
7446
|
-
};
|
|
7447
|
-
}
|
|
7448
|
-
const parsed = decodeStats(text);
|
|
7449
|
-
if (!parsed.record && parsed.newerVersion === null) {
|
|
7450
|
-
if (!recoverCorrupt) return {
|
|
7451
|
-
record: null,
|
|
7452
|
-
note: null,
|
|
7453
|
-
newerVersion: null
|
|
7454
|
-
};
|
|
7455
|
-
const aside = `${path}.corrupt-${now}`;
|
|
7456
|
-
renameSync(path, aside);
|
|
7457
|
-
return {
|
|
7458
|
-
record: emptyStats(),
|
|
7459
|
-
note: `Run statistics at ${path} could not be read, so they were moved to ${aside} and a new file was started.`,
|
|
7460
|
-
newerVersion: null
|
|
7461
|
-
};
|
|
7462
|
-
}
|
|
7463
|
-
if (parsed.newerVersion !== null) return {
|
|
7464
|
-
record: emptyStats(),
|
|
7465
|
-
note: null,
|
|
7466
|
-
newerVersion: parsed.newerVersion
|
|
7467
|
-
};
|
|
7468
|
-
return {
|
|
7469
|
-
record: parsed.record,
|
|
7470
|
-
note: null,
|
|
7471
|
-
newerVersion: null
|
|
7472
|
-
};
|
|
7473
|
-
}
|
|
7474
|
-
function writeStats(path, record) {
|
|
7475
|
-
const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
7476
|
-
writeFileSync(tmp, `${JSON.stringify(record)}\n`);
|
|
7477
|
-
try {
|
|
7478
|
-
renameSync(tmp, path);
|
|
7479
|
-
} catch (error) {
|
|
7480
|
-
rmSync(tmp, { force: true });
|
|
7481
|
-
throw error;
|
|
7482
|
-
}
|
|
7483
|
-
}
|
|
7484
|
-
function applyRun(bucket, run, { at, durationMs, credit, phases }) {
|
|
7485
|
-
const next = bucket ? { ...bucket } : {
|
|
7486
|
-
runs: 0,
|
|
7487
|
-
failed: 0,
|
|
7488
|
-
hits: 0,
|
|
7489
|
-
misses: 0,
|
|
7490
|
-
coldRuns: 0,
|
|
7491
|
-
coldRunMs: 0,
|
|
7492
|
-
hitRuns: 0,
|
|
7493
|
-
hitRunMs: 0,
|
|
7494
|
-
timeSavedMs: 0,
|
|
7495
|
-
firstRunAt: at,
|
|
7496
|
-
lastRunAt: at
|
|
7497
|
-
};
|
|
7498
|
-
next.runs += 1;
|
|
7499
|
-
next.lastRunAt = at;
|
|
7500
|
-
if (phases.coldBuildMs > 0) next.lastColdBuildMs = phases.coldBuildMs;
|
|
7501
|
-
if (phases.podsMs > 0) next.lastPodsMs = phases.podsMs;
|
|
7502
|
-
if (run.failed) {
|
|
7503
|
-
next.failed += 1;
|
|
7504
|
-
return next;
|
|
7505
|
-
}
|
|
7506
|
-
if (isHit(run.cacheHit)) {
|
|
7507
|
-
next.hits += 1;
|
|
7508
|
-
if (!run.waitedForBuild) {
|
|
7509
|
-
next.hitRuns += 1;
|
|
7510
|
-
next.hitRunMs += durationMs;
|
|
7511
|
-
next.timeSavedMs += credit;
|
|
7512
|
-
}
|
|
7513
|
-
return next;
|
|
7514
|
-
}
|
|
7515
|
-
next.misses += 1;
|
|
7516
|
-
if (run.offloadedTo) {
|
|
7517
|
-
next.offloadedRuns = (next.offloadedRuns ?? 0) + 1;
|
|
7518
|
-
next.offloadedRunMs = (next.offloadedRunMs ?? 0) + durationMs;
|
|
7519
|
-
next.lastOffloadHost = run.offloadedTo;
|
|
7520
|
-
return next;
|
|
7521
|
-
}
|
|
7522
|
-
next.coldRuns += 1;
|
|
7523
|
-
next.coldRunMs += durationMs;
|
|
7524
|
-
return next;
|
|
7525
|
-
}
|
|
7526
|
-
function creditMs(bucket, run, durationMs) {
|
|
7527
|
-
if (run.failed || !isHit(run.cacheHit) || run.waitedForBuild) return 0;
|
|
7528
|
-
if (!bucket || bucket.coldRuns <= 0) return 0;
|
|
7529
|
-
return Math.max(0, Math.round(bucket.coldRunMs / bucket.coldRuns) - durationMs);
|
|
7530
|
-
}
|
|
7531
|
-
function isHit(cacheHit) {
|
|
7532
|
-
return cacheHit === "local" || cacheHit === "remote";
|
|
7533
|
-
}
|
|
7534
|
-
function wholeMs(value) {
|
|
7535
|
-
const ms = Number(value);
|
|
7536
|
-
return Number.isFinite(ms) && ms > 0 ? Math.round(ms) : 0;
|
|
7537
|
-
}
|
|
7538
|
-
//#endregion
|
|
7539
|
-
//#region src/engine/build-detail.ts
|
|
7540
|
-
const LINE_MAX = 160;
|
|
7541
|
-
const TARGET_GRAPH = /^note: Target dependency graph \((\d+) targets?\)/;
|
|
7542
|
-
const XCODE_ACTION = /^([A-Z][A-Za-z]+)\s(.*)\s\(in target '([^']+)' from project '([^']+)'\)$/;
|
|
7543
|
-
const XCODE_CONFIGURE = /^(ComputeTargetDependencyGraph|CreateBuildDescription|CreateBuildRequest|Resolve Package Graph|Prepare packages)$/;
|
|
7544
|
-
const GRADLE_TASK = /^> Task (:\S+)/;
|
|
7545
|
-
/**
|
|
7546
|
-
* xcodebuild actions that end a target's work: a clean build touches each product last, and an incremental build
|
|
7547
|
-
* that touches nothing still signs framework products last. Targets that end any other way are not counted.
|
|
7548
|
-
*/
|
|
7549
|
-
const XCODE_TARGET_DONE = /^(Touch|RegisterExecutionPolicyException|CodeSign)$/;
|
|
7550
|
-
const GRADLE_CONFIGURE = /^> Configure project /;
|
|
7551
|
-
/**
|
|
7552
|
-
* SwiftPM prints `[done / total] name` once it plans the build (with U+2009 thin spaces around the slash in Swift 6.4
|
|
7553
|
-
* output), `[done/total] Compiling ...` in older toolchains; Swift 6.4 names the target being worked on, and
|
|
7554
|
-
* `<product>-product` is the link of a product.
|
|
7555
|
-
*/
|
|
7556
|
-
const SWIFTPM_PROGRESS = /^\[(\d+)\s*\/\s*(\d+)\](?:\s+(.*))?$/;
|
|
7557
|
-
const SWIFTPM_CONFIGURE = /^(Fetching|Fetched|Computing version|Computed|Creating working copy|Working copy of)\b|^\[(Pre-planning|Planning|Using on-disk description)/;
|
|
7558
|
-
const XCODE_STEPS = [
|
|
7559
|
-
[/^(CpResource|CopyPNGFile|CopyStringsFile|CompileAssetCatalog\w*|CompileStoryboard|CompileXIB|LinkStoryboards|ProcessInfoPlistFile)$/, "resources"],
|
|
7560
|
-
[/^(Compile\w*|Swift\w*|ScanDependencies|Precompile\w*)$/, "compile"],
|
|
7561
|
-
[/^(Ld|Libtool|CreateUniversalBinary|GenerateDSYMFile)$/, "link"],
|
|
7562
|
-
[/^PhaseScriptExecution$/, "script"],
|
|
7563
|
-
[/^CodeSign$/, "sign"]
|
|
7564
|
-
];
|
|
7565
|
-
const GRADLE_STEPS = [
|
|
7566
|
-
[/[Dd]ex/, "dex"],
|
|
7567
|
-
[/^(createBundle\w*JsAndAssets|generateCodegen\w*)$/, "script"],
|
|
7568
|
-
[/(Resources?|Assets|Manifest|ResValues|RFile|JavaRes)$/, "resources"],
|
|
7569
|
-
[/^(compile|kapt|ksp|javaPreCompile|buildCMake|configureCMake|externalNativeBuild)/, "compile"],
|
|
7570
|
-
[/^(package|assemble|install|zipalign|validateSigning|merge\w*NativeLibs|strip\w*Symbols)/, "package"]
|
|
7571
|
-
];
|
|
7572
|
-
function stepOf(name, table) {
|
|
7573
|
-
return table.find(([pattern]) => pattern.test(name))?.[1] ?? null;
|
|
7574
|
-
}
|
|
7575
|
-
function clip(text) {
|
|
7576
|
-
return text.length > LINE_MAX ? `${text.slice(0, 157)}...` : text;
|
|
7577
|
-
}
|
|
7578
|
-
function unescape(token) {
|
|
7579
|
-
return token.replace(/\\(.)/g, "$1");
|
|
7580
|
-
}
|
|
7581
|
-
function baseName(path) {
|
|
7582
|
-
return path.split("/").findLast(Boolean) ?? path;
|
|
7583
|
-
}
|
|
7584
|
-
/**
|
|
7585
|
-
* An xcodebuild action line in short form: the action, the file it works on and its target, as in
|
|
7586
|
-
* `CompileC sqlite3.c (sqlite3)`. The file is the last absolute path in the arguments, which xcodebuild prints
|
|
7587
|
-
* as the source for compile, copy and plist steps and as the product for link and sign steps; a script phase
|
|
7588
|
-
* shows its name instead.
|
|
7589
|
-
*/
|
|
7590
|
-
function shortXcodeAction(action, args, target) {
|
|
7591
|
-
const tokens = args.match(/(?:\\.|\S)+/g) ?? [];
|
|
7592
|
-
const subject = action === "PhaseScriptExecution" ? unescape(tokens[0] ?? "") : baseName(unescape(tokens.findLast((token) => token.startsWith("/")) ?? ""));
|
|
7593
|
-
return clip(`${action}${subject ? ` ${subject}` : ""} (${target})`);
|
|
7594
|
-
}
|
|
7595
|
-
function swiftpmStep(text) {
|
|
7596
|
-
return /^Linking\b|-product$/.test(text) ? "link" : "compile";
|
|
7597
|
-
}
|
|
7598
|
-
/** What one line of xcodebuild, Gradle or SwiftPM output says about the build's progress, or null for any other line. */
|
|
7599
|
-
function parseBuildToolLine(msg) {
|
|
7600
|
-
const counted = SWIFTPM_PROGRESS.exec(msg);
|
|
7601
|
-
if (counted) {
|
|
7602
|
-
const text = counted[3]?.trim() ?? "";
|
|
7603
|
-
return {
|
|
7604
|
-
kind: "count",
|
|
7605
|
-
done: Number(counted[1]),
|
|
7606
|
-
total: Number(counted[2]),
|
|
7607
|
-
step: swiftpmStep(text),
|
|
7608
|
-
line: text ? clip(text) : null
|
|
7609
|
-
};
|
|
7610
|
-
}
|
|
7611
|
-
if (SWIFTPM_CONFIGURE.test(msg)) return { kind: "configure" };
|
|
7612
|
-
const graph = TARGET_GRAPH.exec(msg);
|
|
7613
|
-
if (graph) return {
|
|
7614
|
-
kind: "total",
|
|
7615
|
-
unit: "targets",
|
|
7616
|
-
total: Number(graph[1])
|
|
7617
|
-
};
|
|
7618
|
-
if (XCODE_CONFIGURE.test(msg) || GRADLE_CONFIGURE.test(msg)) return { kind: "configure" };
|
|
7619
|
-
const action = XCODE_ACTION.exec(msg);
|
|
7620
|
-
if (action) {
|
|
7621
|
-
const [, name, args, target, project] = action;
|
|
7622
|
-
const step = stepOf(name, XCODE_STEPS);
|
|
7623
|
-
return {
|
|
7624
|
-
kind: "unit",
|
|
7625
|
-
unit: "targets",
|
|
7626
|
-
id: `${project}/${target}`,
|
|
7627
|
-
step,
|
|
7628
|
-
line: step ? shortXcodeAction(name, args, target) : null,
|
|
7629
|
-
finished: XCODE_TARGET_DONE.test(name)
|
|
7630
|
-
};
|
|
7631
|
-
}
|
|
7632
|
-
const task = GRADLE_TASK.exec(msg);
|
|
7633
|
-
if (task) {
|
|
7634
|
-
const path = task[1];
|
|
7635
|
-
return {
|
|
7636
|
-
kind: "unit",
|
|
7637
|
-
unit: "tasks",
|
|
7638
|
-
id: path,
|
|
7639
|
-
step: stepOf(path.slice(path.lastIndexOf(":") + 1), GRADLE_STEPS),
|
|
7640
|
-
line: clip(`> Task ${path}`),
|
|
7641
|
-
finished: false
|
|
7642
|
-
};
|
|
7643
|
-
}
|
|
7644
|
-
return null;
|
|
7645
|
-
}
|
|
7646
|
-
/**
|
|
7647
|
-
* Accumulates a build's tool output into its detail: xcodebuild counts the distinct targets it finished against the
|
|
7648
|
-
* total its dependency graph note gives; Gradle counts the task lines it printed and has no total; SwiftPM reports
|
|
7649
|
-
* its own `[done / total]` counts, which the parser passes through.
|
|
7650
|
-
*/
|
|
7651
|
-
function createBuildDetailParser() {
|
|
7652
|
-
let seen = false;
|
|
7653
|
-
let step = null;
|
|
7654
|
-
let unit = null;
|
|
7655
|
-
let total = null;
|
|
7656
|
-
let line = null;
|
|
7657
|
-
let tasks = 0;
|
|
7658
|
-
let counted = null;
|
|
7659
|
-
const targets = /* @__PURE__ */ new Set();
|
|
7350
|
+
function maintenanceLogger(settings, pass, trigger) {
|
|
7351
|
+
const file = maintenanceNdjsonFile();
|
|
7352
|
+
const writer = openRetainedLog(file, settings);
|
|
7660
7353
|
return {
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
}
|
|
7674
|
-
if (
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7354
|
+
write(event, level, msg, fields = {}) {
|
|
7355
|
+
if (level === "debug" && !settings.logChecks) return null;
|
|
7356
|
+
const record = {
|
|
7357
|
+
...fields,
|
|
7358
|
+
ts: Date.now(),
|
|
7359
|
+
src: "maintenance",
|
|
7360
|
+
level,
|
|
7361
|
+
msg,
|
|
7362
|
+
event,
|
|
7363
|
+
pass,
|
|
7364
|
+
trigger,
|
|
7365
|
+
mode: settings.mode === "on" ? "on" : "report"
|
|
7366
|
+
};
|
|
7367
|
+
if (!writer.write(record)) throw writer.lastError ?? /* @__PURE__ */ new Error(`Could not append ${file}`);
|
|
7368
|
+
if (typeof fields.workspace === "string" && [
|
|
7369
|
+
"maintenance_action",
|
|
7370
|
+
"maintenance_failure",
|
|
7371
|
+
"maintenance_skip"
|
|
7372
|
+
].includes(event)) {
|
|
7373
|
+
const workspace = createNdjsonWriter(join(workspaceLogsDir(fields.workspace), MAINTENANCE_LOG_NAME), { maxBytes: LOG_ROTATE_BYTES });
|
|
7374
|
+
try {
|
|
7375
|
+
if (!workspace.write(record)) throw workspace.lastError ?? /* @__PURE__ */ new Error("Could not append workspace maintenance log");
|
|
7376
|
+
} finally {
|
|
7377
|
+
workspace.close();
|
|
7378
|
+
}
|
|
7683
7379
|
}
|
|
7684
|
-
|
|
7685
|
-
if (parsed.unit === "tasks") tasks += 1;
|
|
7686
|
-
else if (parsed.finished) targets.add(parsed.id);
|
|
7687
|
-
if (parsed.step) step = parsed.step;
|
|
7688
|
-
if (parsed.line) line = parsed.line;
|
|
7689
|
-
return true;
|
|
7380
|
+
return record;
|
|
7690
7381
|
},
|
|
7691
|
-
|
|
7692
|
-
if (!seen) return null;
|
|
7693
|
-
if (unit === "steps" && counted) return {
|
|
7694
|
-
step,
|
|
7695
|
-
unit,
|
|
7696
|
-
done: Math.min(counted.done, counted.total),
|
|
7697
|
-
total: counted.total,
|
|
7698
|
-
line,
|
|
7699
|
-
updatedAt
|
|
7700
|
-
};
|
|
7701
|
-
const done = unit === "tasks" ? tasks : unit === "targets" ? targets.size : null;
|
|
7702
|
-
return {
|
|
7703
|
-
step,
|
|
7704
|
-
unit,
|
|
7705
|
-
done: done !== null && total !== null ? Math.min(done, total) : done,
|
|
7706
|
-
total: unit === "tasks" ? null : total,
|
|
7707
|
-
line,
|
|
7708
|
-
updatedAt
|
|
7709
|
-
};
|
|
7710
|
-
}
|
|
7382
|
+
close: () => writer.close()
|
|
7711
7383
|
};
|
|
7712
7384
|
}
|
|
7713
7385
|
//#endregion
|
|
7714
|
-
//#region src/
|
|
7715
|
-
const
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
estimate: () => {},
|
|
7720
|
-
miss: () => {},
|
|
7721
|
-
hit: () => {},
|
|
7722
|
-
deviceSetup: () => {},
|
|
7723
|
-
deviceSetupKnown: () => void 0,
|
|
7724
|
-
place: () => {},
|
|
7725
|
-
waitingOn: () => {},
|
|
7726
|
-
waitingFor: () => {},
|
|
7727
|
-
output: () => {},
|
|
7728
|
-
durations: () => ({}),
|
|
7729
|
-
phase: () => null,
|
|
7730
|
-
steps: () => null,
|
|
7731
|
-
clear: () => {}
|
|
7386
|
+
//#region src/commands/gc/log.ts
|
|
7387
|
+
const VERBS = {
|
|
7388
|
+
done: "Cleared",
|
|
7389
|
+
kept: "Kept",
|
|
7390
|
+
failed: "Failed to clear"
|
|
7732
7391
|
};
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7392
|
+
function gcLogRecord(run, result, ts) {
|
|
7393
|
+
const path = [result.id, result.label].find((value) => value !== null && isAbsolute(value)) ?? null;
|
|
7394
|
+
const size = result.bytes ? ` (${formatBytes(result.bytes)})` : "";
|
|
7395
|
+
const why = result.detail ? `: ${result.detail}` : "";
|
|
7736
7396
|
return {
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
event: "run_failed",
|
|
7761
|
-
...code ? { code } : {},
|
|
7762
|
-
...phase ? { phase } : {},
|
|
7763
|
-
msg: [code, message].filter(Boolean).join(": ") || "the run failed"
|
|
7764
|
-
};
|
|
7765
|
-
}
|
|
7766
|
-
function thrownRunFailureRecord(error, phase) {
|
|
7767
|
-
return runFailureRecord({
|
|
7768
|
-
code: typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : void 0,
|
|
7769
|
-
message: error instanceof Error ? error.message : String(error),
|
|
7770
|
-
phase
|
|
7771
|
-
});
|
|
7772
|
-
}
|
|
7773
|
-
const DETAIL_WRITE_MS = 2e3;
|
|
7774
|
-
function toolLine(record) {
|
|
7775
|
-
if (!record || typeof record !== "object") return null;
|
|
7776
|
-
const { src, level, msg } = record;
|
|
7777
|
-
return src === "build" && level === "debug" && typeof msg === "string" ? msg : null;
|
|
7778
|
-
}
|
|
7779
|
-
function writeBuildDetail(root, claimId, detail) {
|
|
7780
|
-
const file = workspaceBuildDetailFile(root);
|
|
7781
|
-
const tmp = `${file}.tmp-${process.pid}`;
|
|
7782
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
7783
|
-
writeFileSync(tmp, JSON.stringify({
|
|
7784
|
-
claimId,
|
|
7785
|
-
detail
|
|
7786
|
-
}));
|
|
7787
|
-
renameSync(tmp, file);
|
|
7788
|
-
}
|
|
7789
|
-
const COLD_PHASES = [
|
|
7790
|
-
"prebuild",
|
|
7791
|
-
"pods",
|
|
7792
|
-
"compile"
|
|
7793
|
-
];
|
|
7794
|
-
const HIT_PHASES = ["install", "launch"];
|
|
7795
|
-
function settledOutcome(phase, entered) {
|
|
7796
|
-
if (COLD_PHASES.includes(phase)) return "cold";
|
|
7797
|
-
if (phase === "device") return entered.some((entry) => entry.phase === "cache-lookup") ? "hit" : null;
|
|
7798
|
-
return HIT_PHASES.includes(phase) ? "hit" : null;
|
|
7799
|
-
}
|
|
7800
|
-
function projectHistory(projectKey) {
|
|
7801
|
-
try {
|
|
7802
|
-
return readStats$1().record?.history?.[projectKey];
|
|
7803
|
-
} catch {
|
|
7804
|
-
return;
|
|
7805
|
-
}
|
|
7806
|
-
}
|
|
7807
|
-
function startBuildProgress({ root, platform, slot, claim, now = Date.now, note = () => {} }) {
|
|
7808
|
-
const startedAt = new Date(now()).toISOString();
|
|
7809
|
-
const record = {
|
|
7810
|
-
platform,
|
|
7811
|
-
slot,
|
|
7812
|
-
startedAt,
|
|
7813
|
-
phase: "prepare",
|
|
7814
|
-
phaseStartedAt: startedAt,
|
|
7815
|
-
phases: [{
|
|
7816
|
-
phase: "prepare",
|
|
7817
|
-
startedAt
|
|
7818
|
-
}],
|
|
7819
|
-
claim: {
|
|
7820
|
-
root: claim.root,
|
|
7821
|
-
path: claim.path,
|
|
7822
|
-
claimId: claim.claimId,
|
|
7823
|
-
pid: claim.owner.pid
|
|
7824
|
-
}
|
|
7825
|
-
};
|
|
7826
|
-
let warned = false;
|
|
7827
|
-
const guard = (fn) => {
|
|
7397
|
+
ts,
|
|
7398
|
+
src: "gc",
|
|
7399
|
+
level: result.status === "failed" ? "error" : "info",
|
|
7400
|
+
msg: `${VERBS[result.status]} ${result.kind} ${result.label}${size}${why}`,
|
|
7401
|
+
event: "gc_item",
|
|
7402
|
+
runId: run.runId ?? runId(),
|
|
7403
|
+
trigger: run.trigger,
|
|
7404
|
+
...run.via === void 0 ? {} : { via: run.via },
|
|
7405
|
+
...run.options === void 0 ? {} : { options: run.options },
|
|
7406
|
+
kind: result.kind,
|
|
7407
|
+
status: result.status,
|
|
7408
|
+
label: result.label,
|
|
7409
|
+
id: result.id,
|
|
7410
|
+
path,
|
|
7411
|
+
bytes: result.bytes,
|
|
7412
|
+
detail: result.detail
|
|
7413
|
+
};
|
|
7414
|
+
}
|
|
7415
|
+
function openGcLog(run) {
|
|
7416
|
+
let failed = false;
|
|
7417
|
+
let acted = run.holdKept !== true;
|
|
7418
|
+
const held = [];
|
|
7419
|
+
const append = (record) => {
|
|
7828
7420
|
try {
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
}
|
|
7835
|
-
};
|
|
7836
|
-
const write = (before = (state) => state) => guard(() => updateWorkspaceState(root, (state) => ({
|
|
7837
|
-
...before(state),
|
|
7838
|
-
[ACTIVE_BUILD_KEY]: record
|
|
7839
|
-
})));
|
|
7840
|
-
write(withInterruptedBuild);
|
|
7841
|
-
let projectKey = null;
|
|
7842
|
-
const parser = createBuildDetailParser();
|
|
7843
|
-
let detailWrittenAt = -Infinity;
|
|
7844
|
-
let detailTimer = null;
|
|
7845
|
-
const flushDetail = () => {
|
|
7846
|
-
detailTimer = null;
|
|
7847
|
-
detailWrittenAt = now();
|
|
7848
|
-
const detail = parser.detail(new Date(detailWrittenAt).toISOString());
|
|
7849
|
-
if (detail) guard(() => writeBuildDetail(root, record.claim.claimId, detail));
|
|
7850
|
-
};
|
|
7851
|
-
const settle = (outcome) => {
|
|
7852
|
-
record.outcome = outcome;
|
|
7853
|
-
if (projectKey && platform !== "macos") record.estimate = estimateBuild(projectHistory(projectKey), platform, outcome, record.deviceSetup);
|
|
7854
|
-
};
|
|
7855
|
-
const waits = /* @__PURE__ */ new Map();
|
|
7856
|
-
return {
|
|
7857
|
-
step(phase) {
|
|
7858
|
-
if (phase === record.phase) return;
|
|
7859
|
-
const at = new Date(now()).toISOString();
|
|
7860
|
-
record.phase = phase;
|
|
7861
|
-
record.phaseStartedAt = at;
|
|
7862
|
-
record.phases.push({
|
|
7863
|
-
phase,
|
|
7864
|
-
startedAt: at
|
|
7865
|
-
});
|
|
7866
|
-
if (phase !== "wait") delete record.waitingOn;
|
|
7867
|
-
delete record.activity;
|
|
7868
|
-
const outcome = record.outcome || platform === "macos" ? null : settledOutcome(phase, record.phases);
|
|
7869
|
-
if (outcome) settle(outcome);
|
|
7870
|
-
write();
|
|
7871
|
-
},
|
|
7872
|
-
activity(name, at) {
|
|
7873
|
-
if ((record.activity?.name ?? null) === name) return;
|
|
7874
|
-
if (name) record.activity = {
|
|
7875
|
-
name,
|
|
7876
|
-
startedAt: new Date(at ?? now()).toISOString()
|
|
7877
|
-
};
|
|
7878
|
-
else delete record.activity;
|
|
7879
|
-
write();
|
|
7880
|
-
},
|
|
7881
|
-
estimate(key) {
|
|
7882
|
-
if (platform === "macos") return;
|
|
7883
|
-
projectKey = key;
|
|
7884
|
-
record.estimate = estimateBuild(projectHistory(key), platform, record.outcome ?? null, record.outcome ? record.deviceSetup : void 0);
|
|
7885
|
-
write();
|
|
7886
|
-
},
|
|
7887
|
-
miss(reason, provisional = false) {
|
|
7888
|
-
record.missReason = reason;
|
|
7889
|
-
settle("cold");
|
|
7890
|
-
if (provisional) record.missProvisional = true;
|
|
7891
|
-
else delete record.missProvisional;
|
|
7892
|
-
write();
|
|
7893
|
-
},
|
|
7894
|
-
hit() {
|
|
7895
|
-
delete record.missReason;
|
|
7896
|
-
delete record.missProvisional;
|
|
7897
|
-
settle("hit");
|
|
7898
|
-
write();
|
|
7899
|
-
},
|
|
7900
|
-
deviceSetup(setup) {
|
|
7901
|
-
if (setup === void 0) return;
|
|
7902
|
-
record.deviceSetup = setup;
|
|
7903
|
-
write();
|
|
7904
|
-
},
|
|
7905
|
-
deviceSetupKnown() {
|
|
7906
|
-
return record.deviceSetup;
|
|
7907
|
-
},
|
|
7908
|
-
place(remote) {
|
|
7909
|
-
const current = record.placement;
|
|
7910
|
-
if (!remote) {
|
|
7911
|
-
if (!current) return;
|
|
7912
|
-
delete record.placement;
|
|
7913
|
-
return write();
|
|
7914
|
-
}
|
|
7915
|
-
if (current?.host === remote.host && current.phase === remote.phase) return;
|
|
7916
|
-
const at = new Date(now()).toISOString();
|
|
7917
|
-
record.placement = {
|
|
7918
|
-
host: remote.host,
|
|
7919
|
-
phase: remote.phase,
|
|
7920
|
-
startedAt: current?.host === remote.host ? current.startedAt : at,
|
|
7921
|
-
phaseStartedAt: at
|
|
7922
|
-
};
|
|
7923
|
-
write();
|
|
7924
|
-
},
|
|
7925
|
-
waitingFor(info, kind) {
|
|
7926
|
-
if (info) waits.set(info.kind, info);
|
|
7927
|
-
else if (kind) waits.delete(kind);
|
|
7928
|
-
else waits.clear();
|
|
7929
|
-
const first = [...waits.values()].toSorted((a, b) => Date.parse(a.since) - Date.parse(b.since))[0];
|
|
7930
|
-
if (first) record.waitingFor = first;
|
|
7931
|
-
else delete record.waitingFor;
|
|
7932
|
-
write();
|
|
7933
|
-
},
|
|
7934
|
-
waitingOn(holder) {
|
|
7935
|
-
if (holder === null) {
|
|
7936
|
-
if (!record.waitingOn) return;
|
|
7937
|
-
delete record.waitingOn;
|
|
7938
|
-
} else {
|
|
7939
|
-
if (record.waitingOn?.path === holder) return;
|
|
7940
|
-
record.waitingOn = { path: holder };
|
|
7421
|
+
const writer = openRetainedLog(gcLogFile(), resolveMaintenanceSettings(loadConfig$1(), run.env));
|
|
7422
|
+
try {
|
|
7423
|
+
if (!writer.write(record)) throw writer.lastError ?? /* @__PURE__ */ new Error("write failed");
|
|
7424
|
+
} finally {
|
|
7425
|
+
writer.close();
|
|
7941
7426
|
}
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
if (msg === null || !parser.push(msg) || detailTimer) return;
|
|
7947
|
-
const wait = detailWrittenAt + DETAIL_WRITE_MS - now();
|
|
7948
|
-
if (wait <= 0) return flushDetail();
|
|
7949
|
-
detailTimer = setTimeout(flushDetail, wait);
|
|
7950
|
-
detailTimer.unref?.();
|
|
7951
|
-
},
|
|
7952
|
-
durations() {
|
|
7953
|
-
return phaseDurations(record.phases, now());
|
|
7954
|
-
},
|
|
7955
|
-
phase() {
|
|
7956
|
-
return record.phase;
|
|
7957
|
-
},
|
|
7958
|
-
steps() {
|
|
7959
|
-
const detail = parser.detail("");
|
|
7960
|
-
return detail?.unit === "steps" ? detail.total : null;
|
|
7961
|
-
},
|
|
7962
|
-
clear() {
|
|
7963
|
-
if (detailTimer) clearTimeout(detailTimer);
|
|
7964
|
-
detailTimer = null;
|
|
7965
|
-
guard(() => rmSync(workspaceBuildDetailFile(root), { force: true }));
|
|
7966
|
-
guard(() => {
|
|
7967
|
-
clearWorkspaceStateKey(root, ACTIVE_BUILD_KEY, (value) => parseActiveBuild(value)?.claim.claimId === record.claim.claimId);
|
|
7968
|
-
});
|
|
7969
|
-
}
|
|
7970
|
-
};
|
|
7971
|
-
}
|
|
7972
|
-
function phaseDurations(phases, now) {
|
|
7973
|
-
const out = {};
|
|
7974
|
-
phases.forEach(({ phase, startedAt }, index) => {
|
|
7975
|
-
const start = Date.parse(startedAt);
|
|
7976
|
-
const next = phases[index + 1];
|
|
7977
|
-
const end = next ? Date.parse(next.startedAt) : now;
|
|
7978
|
-
if (!Number.isFinite(start) || !Number.isFinite(end)) return;
|
|
7979
|
-
out[phase] = (out[phase] ?? 0) + Math.max(0, end - start);
|
|
7980
|
-
});
|
|
7981
|
-
return out;
|
|
7982
|
-
}
|
|
7983
|
-
function completedPhaseDurations(phases) {
|
|
7984
|
-
if (phases.length < 2) return void 0;
|
|
7985
|
-
const durations = phaseDurations(phases.slice(0, -1), Date.parse(phases.at(-1).startedAt));
|
|
7986
|
-
return Object.keys(durations).length ? durations : void 0;
|
|
7987
|
-
}
|
|
7988
|
-
const HISTORY_FIELDS = [
|
|
7989
|
-
"devicePlacement",
|
|
7990
|
-
"platform",
|
|
7991
|
-
"status",
|
|
7992
|
-
"configuration",
|
|
7993
|
-
"fingerprint",
|
|
7994
|
-
"cacheKey",
|
|
7995
|
-
"cacheHit",
|
|
7996
|
-
"cacheSkipped",
|
|
7997
|
-
"durationMs",
|
|
7998
|
-
"startedAt",
|
|
7999
|
-
"errorCode",
|
|
8000
|
-
"missReason",
|
|
8001
|
-
"buildMachine",
|
|
8002
|
-
"builtOn",
|
|
8003
|
-
"offloadedTo",
|
|
8004
|
-
"offloadFallback",
|
|
8005
|
-
"diagnostics",
|
|
8006
|
-
"compileSteps"
|
|
8007
|
-
];
|
|
8008
|
-
function withHistoryEntry(state, platform, entry) {
|
|
8009
|
-
const saved = state[BUILD_HISTORY_KEY];
|
|
8010
|
-
const history = saved && typeof saved === "object" && !Array.isArray(saved) ? saved : {};
|
|
8011
|
-
const list = Array.isArray(history[platform]) ? history[platform] : [];
|
|
8012
|
-
return {
|
|
8013
|
-
...state,
|
|
8014
|
-
[BUILD_HISTORY_KEY]: {
|
|
8015
|
-
...history,
|
|
8016
|
-
[platform]: [entry, ...list].slice(0, BUILD_HISTORY_LIMIT)
|
|
7427
|
+
} catch (error) {
|
|
7428
|
+
if (failed) return;
|
|
7429
|
+
failed = true;
|
|
7430
|
+
console.error(`Could not write the gc log ${gcLogFile()}: ${error instanceof Error ? error.message : error}`);
|
|
8017
7431
|
}
|
|
8018
7432
|
};
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
function recordFinishedBuild(root, record, { update = updateWorkspaceState, now = Date.now, artifactOnly = false } = {}) {
|
|
8025
|
-
const platform = record.platform;
|
|
8026
|
-
update(root, (state) => {
|
|
8027
|
-
const active = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
|
|
8028
|
-
const own = active?.platform === platform ? active : null;
|
|
8029
|
-
const entry = {
|
|
8030
|
-
...Object.fromEntries(HISTORY_FIELDS.filter((key) => key in record).map((key) => [key, record[key]])),
|
|
8031
|
-
result: finishedResult(record),
|
|
8032
|
-
slot: own?.slot ?? "default",
|
|
8033
|
-
phases: own ? phaseDurations(own.phases, now()) : {}
|
|
8034
|
-
};
|
|
8035
|
-
if (artifactOnly || platform === "macos") return withHistoryEntry(state, platform, entry);
|
|
8036
|
-
const slot = own?.slot ?? "default";
|
|
8037
|
-
const slots = isJsonObject(state.deviceSlots) ? state.deviceSlots : {};
|
|
8038
|
-
const savedSlot = isJsonObject(slots[slot]) ? slots[slot] : {};
|
|
8039
|
-
const savedDevice = slot === "default" ? state[platform] : savedSlot[platform];
|
|
8040
|
-
if (record.devicePlacement || isJsonObject(savedDevice)) {
|
|
8041
|
-
const device = isJsonObject(savedDevice) ? { ...savedDevice } : {};
|
|
8042
|
-
if (record.devicePlacement) device.devicePlacement = record.devicePlacement;
|
|
8043
|
-
else delete device.devicePlacement;
|
|
8044
|
-
state = slot === "default" ? {
|
|
8045
|
-
...state,
|
|
8046
|
-
[platform]: device
|
|
8047
|
-
} : {
|
|
8048
|
-
...state,
|
|
8049
|
-
deviceSlots: {
|
|
8050
|
-
...slots,
|
|
8051
|
-
[slot]: {
|
|
8052
|
-
...savedSlot,
|
|
8053
|
-
[platform]: device
|
|
8054
|
-
}
|
|
8055
|
-
}
|
|
8056
|
-
};
|
|
8057
|
-
}
|
|
8058
|
-
return withHistoryEntry({
|
|
8059
|
-
...state,
|
|
8060
|
-
lastBuild: record,
|
|
8061
|
-
[LAST_BUILD_KEYS[platform]]: record
|
|
8062
|
-
}, platform, entry);
|
|
8063
|
-
});
|
|
8064
|
-
}
|
|
8065
|
-
/** Adds one phase's duration to the recorded run of `platform` that started at `startedAt`. */
|
|
8066
|
-
function recordBuildPhase(root, platform, startedAt, phase, ms) {
|
|
8067
|
-
updateWorkspaceState(root, (state) => {
|
|
8068
|
-
const saved = state[BUILD_HISTORY_KEY];
|
|
8069
|
-
const list = isJsonObject(saved) && Array.isArray(saved[platform]) ? saved[platform] : [];
|
|
8070
|
-
const index = list.findIndex((entry) => isJsonObject(entry) && entry.startedAt === startedAt);
|
|
8071
|
-
const entry = list[index];
|
|
8072
|
-
if (!isJsonObject(entry)) return state;
|
|
8073
|
-
const phases = isJsonObject(entry.phases) ? entry.phases : {};
|
|
8074
|
-
const next = [...list];
|
|
8075
|
-
next[index] = {
|
|
8076
|
-
...entry,
|
|
8077
|
-
phases: {
|
|
8078
|
-
...phases,
|
|
8079
|
-
[phase]: Math.round(ms)
|
|
8080
|
-
}
|
|
8081
|
-
};
|
|
8082
|
-
return {
|
|
8083
|
-
...state,
|
|
8084
|
-
[BUILD_HISTORY_KEY]: {
|
|
8085
|
-
...saved,
|
|
8086
|
-
[platform]: next
|
|
8087
|
-
}
|
|
8088
|
-
};
|
|
8089
|
-
});
|
|
8090
|
-
}
|
|
8091
|
-
function withInterruptedBuild(state) {
|
|
8092
|
-
const left = parseActiveBuild(state[ACTIVE_BUILD_KEY]);
|
|
8093
|
-
if (!left) return state;
|
|
8094
|
-
const last = state[BUILD_HISTORY_KEY]?.[left.platform]?.[0];
|
|
8095
|
-
if (Date.parse(String(last?.startedAt)) >= Date.parse(left.startedAt)) return state;
|
|
8096
|
-
return withHistoryEntry(state, left.platform, {
|
|
8097
|
-
platform: left.platform,
|
|
8098
|
-
status: "failed",
|
|
8099
|
-
result: "interrupted",
|
|
8100
|
-
slot: left.slot,
|
|
8101
|
-
configuration: null,
|
|
8102
|
-
fingerprint: null,
|
|
8103
|
-
cacheKey: null,
|
|
8104
|
-
cacheHit: false,
|
|
8105
|
-
cacheSkipped: false,
|
|
8106
|
-
durationMs: null,
|
|
8107
|
-
startedAt: left.startedAt,
|
|
8108
|
-
phases: {
|
|
8109
|
-
...phaseDurations(left.phases, Date.parse(left.phaseStartedAt)),
|
|
8110
|
-
[left.phase]: 0
|
|
7433
|
+
return { record(result) {
|
|
7434
|
+
const record = gcLogRecord(run, result, Date.now());
|
|
7435
|
+
if (!acted && result.status === "kept") {
|
|
7436
|
+
held.push(record);
|
|
7437
|
+
return;
|
|
8111
7438
|
}
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
8116
|
-
const record = value;
|
|
8117
|
-
const claim = record.claim;
|
|
8118
|
-
if (record.platform !== "ios" && record.platform !== "android" && record.platform !== "macos") return null;
|
|
8119
|
-
if (!isPhase(record.phase)) return null;
|
|
8120
|
-
if (typeof record.startedAt !== "string" || typeof record.phaseStartedAt !== "string") return null;
|
|
8121
|
-
if (!claim || typeof claim.root !== "string" || typeof claim.claimId !== "string") return null;
|
|
8122
|
-
const phases = Array.isArray(record.phases) ? record.phases.filter((entry) => isPhase(entry?.phase) && typeof entry?.startedAt === "string") : [];
|
|
8123
|
-
const missReason = parseMissReason(record.missReason);
|
|
8124
|
-
const placement = parsePlacement(record.placement);
|
|
8125
|
-
const waitingOn = parseWaitingOn(record.waitingOn);
|
|
8126
|
-
const waitingFor = parseWaitingFor(record.waitingFor);
|
|
8127
|
-
const estimate = parseEstimate(record.estimate);
|
|
8128
|
-
const activity = parseActivity(record.activity);
|
|
8129
|
-
return {
|
|
8130
|
-
platform: record.platform,
|
|
8131
|
-
slot: typeof record.slot === "string" ? record.slot : "default",
|
|
8132
|
-
startedAt: record.startedAt,
|
|
8133
|
-
phase: record.phase,
|
|
8134
|
-
phaseStartedAt: record.phaseStartedAt,
|
|
8135
|
-
phases,
|
|
8136
|
-
...missReason ? { missReason } : {},
|
|
8137
|
-
...missReason && record.missProvisional === true ? { missProvisional: true } : {},
|
|
8138
|
-
...placement ? { placement } : {},
|
|
8139
|
-
...waitingOn ? { waitingOn } : {},
|
|
8140
|
-
...waitingFor ? { waitingFor } : {},
|
|
8141
|
-
...typeof record.deviceSetup === "boolean" ? { deviceSetup: record.deviceSetup } : {},
|
|
8142
|
-
...record.outcome === "hit" || record.outcome === "cold" ? { outcome: record.outcome } : {},
|
|
8143
|
-
...estimate ? { estimate } : {},
|
|
8144
|
-
...activity ? { activity } : {},
|
|
8145
|
-
claim: {
|
|
8146
|
-
root: claim.root,
|
|
8147
|
-
path: typeof claim.path === "string" ? claim.path : "",
|
|
8148
|
-
claimId: claim.claimId,
|
|
8149
|
-
pid: typeof claim.pid === "number" ? claim.pid : 0
|
|
7439
|
+
if (!acted) {
|
|
7440
|
+
acted = true;
|
|
7441
|
+
for (const earlier of held.splice(0)) append(earlier);
|
|
8150
7442
|
}
|
|
8151
|
-
|
|
8152
|
-
}
|
|
8153
|
-
function parsePlacement(value) {
|
|
8154
|
-
if (!value || typeof value !== "object") return null;
|
|
8155
|
-
const { host, phase, startedAt, phaseStartedAt } = value;
|
|
8156
|
-
if ([
|
|
8157
|
-
host,
|
|
8158
|
-
phase,
|
|
8159
|
-
startedAt,
|
|
8160
|
-
phaseStartedAt
|
|
8161
|
-
].some((field) => typeof field !== "string")) return null;
|
|
8162
|
-
return {
|
|
8163
|
-
host,
|
|
8164
|
-
phase,
|
|
8165
|
-
startedAt,
|
|
8166
|
-
phaseStartedAt
|
|
8167
|
-
};
|
|
7443
|
+
append(record);
|
|
7444
|
+
} };
|
|
8168
7445
|
}
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
7446
|
+
const MAINTENANCE_KINDS = {
|
|
7447
|
+
"clear-outputs": "workspaceOutputs",
|
|
7448
|
+
"trim-cache": "cache",
|
|
7449
|
+
"empty-cache": "cache",
|
|
7450
|
+
"unregister-cache": "cache",
|
|
7451
|
+
"remove-worktree": "worktree",
|
|
7452
|
+
"remove-orphan": "workspaceDirectory",
|
|
7453
|
+
"delete-parked-device": "parkedDevice",
|
|
7454
|
+
"delete-devices": "device",
|
|
7455
|
+
"stop-workspace": "device",
|
|
7456
|
+
"shutdown-device": "idleDevice",
|
|
7457
|
+
"delete-temp-leftovers": "tempLeftover",
|
|
7458
|
+
"stop-gradle-daemons": "gradleDaemon",
|
|
7459
|
+
"delete-gradle-version": "gradleVersion",
|
|
7460
|
+
"clear-build-dirs": "buildDirectory",
|
|
7461
|
+
"delete-dependencies": "dependencies"
|
|
7462
|
+
};
|
|
7463
|
+
function maintenanceItem(action, outcome) {
|
|
7464
|
+
const name = action.kind.replace(/^would-/, "");
|
|
7465
|
+
const done = outcome.status === "done";
|
|
8175
7466
|
return {
|
|
8176
|
-
kind,
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
7467
|
+
kind: MAINTENANCE_KINDS[name] ?? name,
|
|
7468
|
+
status: outcome.status,
|
|
7469
|
+
label: action.target,
|
|
7470
|
+
id: action.dir ?? action.workspace ?? null,
|
|
7471
|
+
bytes: done && outcome.bytes ? outcome.bytes : null,
|
|
7472
|
+
detail: done ? outcome.detail ? `${action.reason} (${outcome.detail})` : action.reason : outcome.detail
|
|
8180
7473
|
};
|
|
8181
7474
|
}
|
|
8182
|
-
function
|
|
8183
|
-
if (!value || typeof value !== "object") return null;
|
|
8184
|
-
const { name, startedAt } = value;
|
|
8185
|
-
if (name !== "booting" && name !== "bundling" && name !== "waiting-ready") return null;
|
|
8186
|
-
return typeof startedAt === "string" ? {
|
|
8187
|
-
name,
|
|
8188
|
-
startedAt
|
|
8189
|
-
} : null;
|
|
8190
|
-
}
|
|
8191
|
-
function parseWaitingOn(value) {
|
|
8192
|
-
const path = value?.path;
|
|
8193
|
-
return typeof path === "string" && path ? { path } : null;
|
|
8194
|
-
}
|
|
8195
|
-
function parseEstimate(value) {
|
|
8196
|
-
if (!value || typeof value !== "object") return null;
|
|
8197
|
-
const { outcome, expectedMs, basis, phaseMs, planned } = value;
|
|
8198
|
-
if (outcome !== null && outcome !== "hit" && outcome !== "cold") return null;
|
|
8199
|
-
if (expectedMs !== null && typeof expectedMs !== "number") return null;
|
|
8200
|
-
if (typeof basis !== "number" || !Array.isArray(planned) || !phaseMs || typeof phaseMs !== "object") return null;
|
|
8201
|
-
const durations = Object.entries(phaseMs).filter((entry) => isPhase(entry[0]) && typeof entry[1] === "number");
|
|
7475
|
+
function gcOptionsOf(opts) {
|
|
8202
7476
|
return {
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
};
|
|
8209
|
-
}
|
|
8210
|
-
function isPhase(value) {
|
|
8211
|
-
return BUILD_PHASES.includes(value);
|
|
8212
|
-
}
|
|
8213
|
-
function activeBuildState(claim, survey = (0, ownership_claim_exports.readClaimSet)(claim.root)) {
|
|
8214
|
-
if (survey.live.some((holder) => holder.claimId === claim.claimId)) return "running";
|
|
8215
|
-
if (survey.dead.some((holder) => holder.claimId === claim.claimId)) return "stale";
|
|
8216
|
-
return survey.unresolved.length ? "unknown" : "stale";
|
|
8217
|
-
}
|
|
8218
|
-
function median(values) {
|
|
8219
|
-
if (!values.length) return null;
|
|
8220
|
-
const sorted = values.toSorted((a, b) => a - b);
|
|
8221
|
-
const mid = Math.floor(sorted.length / 2);
|
|
8222
|
-
return sorted.length % 2 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
|
|
8223
|
-
}
|
|
8224
|
-
function estimateBuild(history, platform, known, deviceSetup) {
|
|
8225
|
-
const lists = platform === "macos" ? void 0 : history?.[platform];
|
|
8226
|
-
const outcome = known ?? latestOutcome(lists);
|
|
8227
|
-
const samples = matchDeviceSetup(outcome && lists?.[outcome] || [], deviceSetup);
|
|
8228
|
-
const phaseMs = {};
|
|
8229
|
-
const planned = [];
|
|
8230
|
-
for (const phase of BUILD_PHASES) {
|
|
8231
|
-
const durations = samples.flatMap((sample) => phase in sample.phases ? [sample.phases[phase]] : []);
|
|
8232
|
-
const ms = median(durations);
|
|
8233
|
-
if (ms === null) continue;
|
|
8234
|
-
phaseMs[phase] = ms;
|
|
8235
|
-
if (durations.length * 2 >= samples.length) planned.push(phase);
|
|
8236
|
-
}
|
|
8237
|
-
return {
|
|
8238
|
-
outcome,
|
|
8239
|
-
expectedMs: median(samples.map((sample) => sample.durationMs)),
|
|
8240
|
-
basis: samples.length,
|
|
8241
|
-
phaseMs,
|
|
8242
|
-
planned
|
|
8243
|
-
};
|
|
8244
|
-
}
|
|
8245
|
-
const MIN_TAGGED_SAMPLES = 3;
|
|
8246
|
-
function matchDeviceSetup(samples, deviceSetup) {
|
|
8247
|
-
if (deviceSetup === void 0) return samples;
|
|
8248
|
-
const tagged = samples.filter((sample) => sample.deviceSetup === deviceSetup);
|
|
8249
|
-
if (deviceSetup || tagged.length >= MIN_TAGGED_SAMPLES) return tagged;
|
|
8250
|
-
return samples.filter((sample) => sample.deviceSetup !== true);
|
|
8251
|
-
}
|
|
8252
|
-
function latestOutcome(lists) {
|
|
8253
|
-
let latest = null;
|
|
8254
|
-
for (const outcome of ["hit", "cold"]) {
|
|
8255
|
-
const last = lists?.[outcome]?.at(-1);
|
|
8256
|
-
const at = last ? Date.parse(last.at) : NaN;
|
|
8257
|
-
if (Number.isFinite(at) && (!latest || at > latest.at)) latest = {
|
|
8258
|
-
outcome,
|
|
8259
|
-
at
|
|
8260
|
-
};
|
|
8261
|
-
}
|
|
8262
|
-
return latest?.outcome ?? null;
|
|
8263
|
-
}
|
|
8264
|
-
function buildReport(record, { state, history }) {
|
|
8265
|
-
const estimate = record.estimate ?? estimateBuild(history, record.platform, record.outcome ?? null, record.outcome ? record.deviceSetup : void 0);
|
|
8266
|
-
const plannedPhases = estimate.planned.flatMap((phase) => {
|
|
8267
|
-
const expectedMs = estimate.phaseMs[phase];
|
|
8268
|
-
return expectedMs === void 0 ? [] : [{
|
|
8269
|
-
phase,
|
|
8270
|
-
expectedMs
|
|
8271
|
-
}];
|
|
8272
|
-
});
|
|
8273
|
-
const completedPhaseMs = completedPhaseDurations(record.phases);
|
|
8274
|
-
return {
|
|
8275
|
-
platform: record.platform,
|
|
8276
|
-
slot: record.slot,
|
|
8277
|
-
state,
|
|
8278
|
-
phase: record.phase,
|
|
8279
|
-
startedAt: record.startedAt,
|
|
8280
|
-
phaseStartedAt: record.phaseStartedAt,
|
|
8281
|
-
outcome: estimate.outcome,
|
|
8282
|
-
outcomeKnown: record.outcome !== void 0,
|
|
8283
|
-
...record.outcome && record.phases.some(({ phase }) => phase === "cache-lookup") ? { cacheLookupOutcome: record.outcome === "hit" ? "hit" : "miss" } : {},
|
|
8284
|
-
expectedMs: estimate.expectedMs,
|
|
8285
|
-
expectedPhaseMs: estimate.phaseMs[record.phase] ?? null,
|
|
8286
|
-
...completedPhaseMs ? { completedPhaseMs } : {},
|
|
8287
|
-
basis: estimate.basis,
|
|
8288
|
-
plannedPhases: plannedPhases.length ? plannedPhases : null,
|
|
8289
|
-
...record.missReason ? { missReason: record.missReason } : {},
|
|
8290
|
-
...record.missReason && record.missProvisional ? { missProvisional: true } : {},
|
|
8291
|
-
placement: record.placement ?? "local",
|
|
8292
|
-
...record.waitingOn ? { waitingOn: record.waitingOn } : {},
|
|
8293
|
-
...record.waitingFor ? { waitingFor: record.waitingFor } : {},
|
|
8294
|
-
...record.activity ? { activity: { ...record.activity } } : {}
|
|
7477
|
+
...opts.delete ? { delete: true } : {},
|
|
7478
|
+
...opts.worktrees ? { worktrees: true } : {},
|
|
7479
|
+
...opts.olderThan === void 0 ? {} : { olderThan: opts.olderThan },
|
|
7480
|
+
...opts.cache === void 0 ? {} : { cache: opts.cache },
|
|
7481
|
+
...opts.idle === void 0 ? {} : { idleMs: opts.idle }
|
|
8295
7482
|
};
|
|
8296
7483
|
}
|
|
7484
|
+
//#endregion
|
|
7485
|
+
//#region src/maintenance/pressure.ts
|
|
8297
7486
|
/**
|
|
8298
|
-
* The
|
|
8299
|
-
*
|
|
7487
|
+
* The free-disk floor of each level in MiB. Level 2 has no floor of its own: it runs when level 1 left free disk
|
|
7488
|
+
* under the budget floor, and stops once free disk is back above it. Its urgent threshold only sets the reported level.
|
|
8300
7489
|
*/
|
|
8301
|
-
function
|
|
8302
|
-
|
|
8303
|
-
if (bundle.platform !== platform || bundle.startedAt !== activity.startedAt) return activity;
|
|
8304
|
-
return {
|
|
8305
|
-
...activity,
|
|
8306
|
-
percent: bundle.percent
|
|
8307
|
-
};
|
|
8308
|
-
}
|
|
8309
|
-
function remainingText(remainingMs) {
|
|
8310
|
-
return remainingMs < 6e4 ? "under a minute left" : `about ${Math.ceil(remainingMs / 6e4)} min left`;
|
|
8311
|
-
}
|
|
8312
|
-
function activityText({ name, percent, startedAt }, now) {
|
|
8313
|
-
return `${name === "booting" ? "booting" : name === "waiting-ready" ? "waiting for app ready" : percent === void 0 ? "bundling JS" : `bundling JS ${percent}%`}, ${formatElapsed(Math.max(0, now - Date.parse(startedAt)))}`;
|
|
8314
|
-
}
|
|
8315
|
-
function buildStatusLine(report, now) {
|
|
8316
|
-
const slot = report.slot === "default" ? "" : ` [${report.slot}]`;
|
|
8317
|
-
if (report.state === "stale") return `build: stale ${report.platform}${slot} record from ${report.startedAt} (its run is gone; the next run replaces it)`;
|
|
8318
|
-
const elapsedMs = Math.max(0, now - Date.parse(report.startedAt));
|
|
8319
|
-
const remote = typeof report.placement === "object" ? ` on ${report.placement.host} (${report.placement.phase}, ${formatElapsed(Math.max(0, now - Date.parse(report.placement.phaseStartedAt)))})` : "";
|
|
8320
|
-
const waiting = report.waitingOn ? ` on ${report.waitingOn.path}` : "";
|
|
8321
|
-
const activity = report.activity ? ` (${activityText(report.activity, now)})` : "";
|
|
8322
|
-
const head = `build: ${report.platform}${slot} ${report.phase}${activity}${waiting}${remote}, ${formatElapsed(elapsedMs)} elapsed`;
|
|
8323
|
-
if (report.state === "unknown") return `${head} (its native-run claim cannot be resolved, so it may not be running)`;
|
|
8324
|
-
if (report.expectedMs === null) return head;
|
|
8325
|
-
const basis = `median of ${plural(report.basis, `${report.outcome} run`)}`;
|
|
8326
|
-
const remainingMs = report.expectedMs - elapsedMs;
|
|
8327
|
-
return remainingMs > 0 ? `${head} -- ${remainingText(remainingMs)} (${basis})` : `${head} (usually ~${formatElapsed(report.expectedMs)}, ${basis})`;
|
|
8328
|
-
}
|
|
8329
|
-
//#endregion
|
|
8330
|
-
//#region src/commands/gc/idle.ts
|
|
8331
|
-
function findOwnedDeviceActivity({ config, sims, androidSerial, readActivity, deadProjects = [] }) {
|
|
8332
|
-
const booted = new Map(sims.filter((sim) => sim.state === "Booted").map((sim) => [sim.udid, sim.name]));
|
|
8333
|
-
const dead = new Set(deadProjects);
|
|
8334
|
-
const found = [];
|
|
8335
|
-
for (const [project, record] of Object.entries(config?.projects ?? {})) {
|
|
8336
|
-
if (dead.has(project)) continue;
|
|
8337
|
-
for (const { slot, platforms } of projectDeviceSlots(record)) {
|
|
8338
|
-
const ios = platforms.ios;
|
|
8339
|
-
if (ios?.owned && ios.deviceUdid && booted.has(ios.deviceUdid)) found.push({
|
|
8340
|
-
kind: "ios",
|
|
8341
|
-
id: ios.deviceUdid,
|
|
8342
|
-
name: booted.get(ios.deviceUdid) ?? ios.deviceUdid,
|
|
8343
|
-
project,
|
|
8344
|
-
slot,
|
|
8345
|
-
activity: readActivity({
|
|
8346
|
-
platform: "ios",
|
|
8347
|
-
id: ios.deviceUdid,
|
|
8348
|
-
slot,
|
|
8349
|
-
workspace: project
|
|
8350
|
-
})
|
|
8351
|
-
});
|
|
8352
|
-
const android = platforms.android;
|
|
8353
|
-
const serial = android?.owned && android.avdName ? androidSerial(android.avdName) : null;
|
|
8354
|
-
if (android?.avdName && serial) found.push({
|
|
8355
|
-
kind: "android",
|
|
8356
|
-
id: android.avdName,
|
|
8357
|
-
name: android.avdName,
|
|
8358
|
-
project,
|
|
8359
|
-
slot,
|
|
8360
|
-
activity: readActivity({
|
|
8361
|
-
platform: "android",
|
|
8362
|
-
id: serial,
|
|
8363
|
-
slot,
|
|
8364
|
-
workspace: project
|
|
8365
|
-
})
|
|
8366
|
-
});
|
|
8367
|
-
}
|
|
8368
|
-
}
|
|
8369
|
-
return found;
|
|
8370
|
-
}
|
|
8371
|
-
function findIdleDevices({ buildInProgress, now, ...inputs }) {
|
|
8372
|
-
return idleDevicesFromActivity(findOwnedDeviceActivity(inputs), buildInProgress, now);
|
|
8373
|
-
}
|
|
8374
|
-
function idleDevicesFromActivity(devices, buildInProgress, now) {
|
|
8375
|
-
return devices.filter((device) => device.activity.state === "idle").map(({ kind, id, name, project, slot, activity }) => ({
|
|
8376
|
-
kind,
|
|
8377
|
-
id,
|
|
8378
|
-
name,
|
|
8379
|
-
project,
|
|
8380
|
-
slot,
|
|
8381
|
-
lastActivityAt: activity.lastActivityAt ?? null,
|
|
8382
|
-
idleForMs: idleForMs(activity, now),
|
|
8383
|
-
buildInProgress: buildInProgress(project)
|
|
8384
|
-
}));
|
|
8385
|
-
}
|
|
8386
|
-
function idleShutdownCandidates(devices, idleMs) {
|
|
8387
|
-
return devices.filter((d) => !d.buildInProgress && d.idleForMs !== null && d.idleForMs >= idleMs);
|
|
8388
|
-
}
|
|
8389
|
-
function parseIdleDuration(value) {
|
|
8390
|
-
const match = /^([1-9][0-9]*)(m|h|d)$/.exec(value.trim());
|
|
8391
|
-
if (!match) return null;
|
|
8392
|
-
const unit = {
|
|
8393
|
-
m: 6e4,
|
|
8394
|
-
h: 36e5,
|
|
8395
|
-
d: 864e5
|
|
8396
|
-
}[match[2]];
|
|
8397
|
-
return Number(match[1]) * unit;
|
|
8398
|
-
}
|
|
8399
|
-
function workspaceBuildInProgress(project) {
|
|
8400
|
-
const record = parseActiveBuild(readWorkspaceState$1(project)?.[ACTIVE_BUILD_KEY]);
|
|
8401
|
-
if (!record) return false;
|
|
8402
|
-
try {
|
|
8403
|
-
return activeBuildState(record.claim) !== "stale";
|
|
8404
|
-
} catch {
|
|
8405
|
-
return true;
|
|
8406
|
-
}
|
|
8407
|
-
}
|
|
8408
|
-
function deviceActivityInputs(config, sims, now, env) {
|
|
8409
|
-
const resolve = ownedAvdSerialResolver({ timeoutMs: 5e3 });
|
|
7490
|
+
function levelFloors(budget, settings) {
|
|
7491
|
+
const floor = Math.max(budget.minFreeDiskMb, budget.hardFloorDiskMb);
|
|
8410
7492
|
return {
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
env
|
|
8416
|
-
}),
|
|
8417
|
-
androidSerial: (avdName) => {
|
|
8418
|
-
try {
|
|
8419
|
-
return resolve(avdName).serial ?? null;
|
|
8420
|
-
} catch {
|
|
8421
|
-
return null;
|
|
8422
|
-
}
|
|
8423
|
-
}
|
|
7493
|
+
1: floor,
|
|
7494
|
+
2: floor,
|
|
7495
|
+
3: Math.max(settings.criticalFreeDiskGb * 1024, budget.hardFloorDiskMb),
|
|
7496
|
+
urgent: settings.urgentFreeDiskGb * 1024
|
|
8424
7497
|
};
|
|
8425
7498
|
}
|
|
8426
|
-
function
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
return
|
|
8431
|
-
...deviceActivityInputs(config, sims, now, env),
|
|
8432
|
-
deadProjects,
|
|
8433
|
-
now,
|
|
8434
|
-
buildInProgress: workspaceBuildInProgress
|
|
8435
|
-
});
|
|
7499
|
+
function diskPressureLevel(freeMb, budget, settings) {
|
|
7500
|
+
const floors = levelFloors(budget, settings);
|
|
7501
|
+
if (freeMb < floors[3]) return 3;
|
|
7502
|
+
if (freeMb < floors.urgent) return 2;
|
|
7503
|
+
return freeMb < floors[1] ? 1 : 0;
|
|
8436
7504
|
}
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
timeoutMs: 5e3,
|
|
8440
|
-
signal,
|
|
8441
|
-
operation
|
|
8442
|
-
});
|
|
8443
|
-
const serials = /* @__PURE__ */ new Map();
|
|
8444
|
-
for (const [project, record] of Object.entries(config?.projects ?? {})) {
|
|
8445
|
-
signal?.throwIfAborted();
|
|
8446
|
-
if (deadProjects.includes(project)) continue;
|
|
8447
|
-
for (const { platforms } of projectDeviceSlots(record)) {
|
|
8448
|
-
const android = platforms.android;
|
|
8449
|
-
if (!android?.owned || !android.avdName || serials.has(android.avdName)) continue;
|
|
8450
|
-
try {
|
|
8451
|
-
serials.set(android.avdName, (await resolve(android.avdName)).serial ?? null);
|
|
8452
|
-
} catch (error) {
|
|
8453
|
-
if (error instanceof WorkspaceProcessCleanupError) throw error;
|
|
8454
|
-
signal?.throwIfAborted();
|
|
8455
|
-
serials.set(android.avdName, null);
|
|
8456
|
-
}
|
|
8457
|
-
}
|
|
8458
|
-
}
|
|
8459
|
-
return {
|
|
8460
|
-
config,
|
|
8461
|
-
sims,
|
|
8462
|
-
readActivity: createActivityReaderAsync({
|
|
8463
|
-
now,
|
|
8464
|
-
env,
|
|
8465
|
-
signal,
|
|
8466
|
-
operation
|
|
8467
|
-
}),
|
|
8468
|
-
androidSerial: (name) => serials.get(name) ?? null
|
|
8469
|
-
};
|
|
7505
|
+
function lowestFree(disk) {
|
|
7506
|
+
return disk.length ? Math.min(...disk.map((volume) => volume.freeMb)) : Infinity;
|
|
8470
7507
|
}
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
return
|
|
7508
|
+
/** Whether an action planned at a pressure level may still run with this much free disk. */
|
|
7509
|
+
function levelStillShort(action, freeMb, budget, settings) {
|
|
7510
|
+
return action.level === void 0 || freeMb < levelFloors(budget, settings)[action.level];
|
|
8474
7511
|
}
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
deadProjects
|
|
8479
|
-
});
|
|
8480
|
-
return idleDevicesFromActivity(await Promise.all(pending.map(async (device) => Object.assign({}, device, { activity: await device.activity }))), workspaceBuildInProgress, now);
|
|
8481
|
-
}
|
|
8482
|
-
function idleDeviceLines(devices) {
|
|
8483
|
-
if (devices.length === 0) return [];
|
|
8484
|
-
return [`Idle owned devices (${devices.length}) - booted with no driver, claim, or recent activity:`, ...devices.map((d) => {
|
|
8485
|
-
const slot = d.slot === "default" ? "" : ` [${d.slot}]`;
|
|
8486
|
-
const idle = d.idleForMs === null ? "idle for an unknown time" : `idle ${formatLongDuration(d.idleForMs)}`;
|
|
8487
|
-
const build = d.buildInProgress ? ", build in progress" : "";
|
|
8488
|
-
return ` ${d.kind}${slot} ${d.name} (${d.project}) -- ${idle}${build}`;
|
|
8489
|
-
})];
|
|
8490
|
-
}
|
|
8491
|
-
async function shutDownIdleDevices(devices, idleMs, recollect, { log, record } = GC_OUTPUT, signal, operation) {
|
|
8492
|
-
signal?.throwIfAborted();
|
|
8493
|
-
const candidates = idleShutdownCandidates(devices, idleMs);
|
|
8494
|
-
const shutDown = [];
|
|
8495
|
-
if (candidates.length === 0) {
|
|
8496
|
-
log(chalk.dim(`No owned device has been idle for ${formatLongDuration(idleMs)} or more.`));
|
|
8497
|
-
return {
|
|
8498
|
-
failures: 0,
|
|
8499
|
-
shutDown
|
|
8500
|
-
};
|
|
8501
|
-
}
|
|
8502
|
-
const fresh = idleShutdownCandidates(await recollect(), idleMs);
|
|
8503
|
-
signal?.throwIfAborted();
|
|
8504
|
-
let failures = 0;
|
|
8505
|
-
for (const device of candidates) {
|
|
8506
|
-
signal?.throwIfAborted();
|
|
8507
|
-
const what = `${device.kind} ${device.name}`;
|
|
8508
|
-
const current = fresh.find((d) => d.kind === device.kind && d.id === device.id && d.project === device.project && d.slot === device.slot);
|
|
8509
|
-
if (!current) {
|
|
8510
|
-
log(chalk.dim(`Kept ${what}: it is no longer idle for ${formatLongDuration(idleMs)}.`));
|
|
8511
|
-
record("idleDevice", "kept", device.name, {
|
|
8512
|
-
id: device.id,
|
|
8513
|
-
detail: `it is no longer idle for ${formatLongDuration(idleMs)}`
|
|
8514
|
-
});
|
|
8515
|
-
continue;
|
|
8516
|
-
}
|
|
8517
|
-
const outcome = device.kind === "ios" ? await teardownOwnedIosSim(device.id, {
|
|
8518
|
-
label: device.name,
|
|
8519
|
-
operation
|
|
8520
|
-
}) : await teardownOwnedAvd(device.id, {
|
|
8521
|
-
owner: {
|
|
8522
|
-
projectPath: device.project,
|
|
8523
|
-
slot: device.slot
|
|
8524
|
-
},
|
|
8525
|
-
operation
|
|
8526
|
-
});
|
|
8527
|
-
if (outcome.status === "torn-down") {
|
|
8528
|
-
shutDown.push(device);
|
|
8529
|
-
log(chalk.green(`Shut down ${what}, idle ${formatLongDuration(current.idleForMs)}`));
|
|
8530
|
-
record("idleDevice", "done", device.name, {
|
|
8531
|
-
id: device.id,
|
|
8532
|
-
detail: `idle ${formatLongDuration(current.idleForMs)}`
|
|
8533
|
-
});
|
|
8534
|
-
} else if (outcome.status === "missing") log(chalk.dim(`${what} is already gone; nothing to shut down.`));
|
|
8535
|
-
else if (outcome.status === "skipped") {
|
|
8536
|
-
log(chalk.yellow(`Skipped ${what}: ${outcome.reason}`));
|
|
8537
|
-
record("idleDevice", "kept", device.name, {
|
|
8538
|
-
id: device.id,
|
|
8539
|
-
detail: outcome.reason
|
|
8540
|
-
});
|
|
8541
|
-
} else {
|
|
8542
|
-
failures++;
|
|
8543
|
-
log(chalk.red(`Failed to shut down ${what}: ${outcome.reason}`));
|
|
8544
|
-
record("idleDevice", "failed", device.name, {
|
|
8545
|
-
id: device.id,
|
|
8546
|
-
detail: outcome.reason
|
|
8547
|
-
});
|
|
8548
|
-
}
|
|
8549
|
-
}
|
|
8550
|
-
return {
|
|
8551
|
-
failures,
|
|
8552
|
-
shutDown
|
|
8553
|
-
};
|
|
7512
|
+
/** The protection window in milliseconds: protectRecentHours, or maintenance.pressureProtectMinutes for actions of level 2 and 3. */
|
|
7513
|
+
function protectWindowMs(action, settings) {
|
|
7514
|
+
return action.level === void 0 ? settings.protectRecentHours * 36e5 : settings.pressureProtectMinutes * 6e4;
|
|
8554
7515
|
}
|
|
8555
7516
|
//#endregion
|
|
8556
7517
|
//#region src/supervisor/stop-cause.ts
|
|
@@ -8929,7 +7890,7 @@ function isOtherWorkspace(root) {
|
|
|
8929
7890
|
function deviceLabel(device) {
|
|
8930
7891
|
return `${device.kind} ${device.name} in ${device.project}`;
|
|
8931
7892
|
}
|
|
8932
|
-
async function reclaimIdleDevices({ root, dryRun, note, now, env, signal, operation }) {
|
|
7893
|
+
async function reclaimIdleDevices({ root, dryRun, note, record, now, env, signal, operation }) {
|
|
8933
7894
|
if (deviceSweepIsScoped(env)) {
|
|
8934
7895
|
note(chalk.dim(phaseLine("budget", "idle devices left alone: STIM_HOME scopes this config, devices are global")));
|
|
8935
7896
|
return {
|
|
@@ -8949,7 +7910,7 @@ async function reclaimIdleDevices({ root, dryRun, note, now, env, signal, operat
|
|
|
8949
7910
|
targets: idle.map(deviceLabel),
|
|
8950
7911
|
failures: 0
|
|
8951
7912
|
};
|
|
8952
|
-
const { failures, shutDown } = await shutDownIdleDevices(idle, 0, () => collect(Date.now()), stepOutput(note), signal, operation);
|
|
7913
|
+
const { failures, shutDown } = await shutDownIdleDevices(idle, 0, () => collect(Date.now()), stepOutput(note, record), signal, operation);
|
|
8953
7914
|
return {
|
|
8954
7915
|
targets: shutDown.map(deviceLabel),
|
|
8955
7916
|
failures
|
|
@@ -8960,7 +7921,7 @@ function idleSince(path, now) {
|
|
|
8960
7921
|
const at = Date.parse(activity.lastActivityAt ?? "");
|
|
8961
7922
|
return activity.state === "idle" && Number.isFinite(at) ? at : null;
|
|
8962
7923
|
}
|
|
8963
|
-
async function reclaimIdleDevServers({ root, dryRun, note, now, env, signal, operation }) {
|
|
7924
|
+
async function reclaimIdleDevServers({ root, dryRun, note, record, now, env, signal, operation }) {
|
|
8964
7925
|
const config = loadConfig$1();
|
|
8965
7926
|
const other = isOtherWorkspace(root);
|
|
8966
7927
|
const serving = Object.entries(config?.projects ?? {}).flatMap(([path, project]) => {
|
|
@@ -9029,22 +7990,27 @@ async function reclaimIdleDevServers({ root, dryRun, note, now, env, signal, ope
|
|
|
9029
7990
|
signal?.throwIfAborted();
|
|
9030
7991
|
failures++;
|
|
9031
7992
|
note(chalk.red(`Could not stop the dev server of ${path}: ${error?.message || error}`));
|
|
7993
|
+
record?.("devServer", "failed", path, { detail: error instanceof Error ? error.message : String(error) });
|
|
9032
7994
|
continue;
|
|
9033
7995
|
}
|
|
9034
7996
|
if (!run.ran) {
|
|
9035
7997
|
note(chalk.yellow(`Kept the dev server of ${path}: ${run.reasons.join("; ")}`));
|
|
7998
|
+
record?.("devServer", "kept", path, { detail: run.reasons.join("; ") });
|
|
9036
7999
|
continue;
|
|
9037
8000
|
}
|
|
9038
8001
|
const stopped = run.value;
|
|
9039
8002
|
if (stopped === "busy" || stopped === "starting") {
|
|
9040
8003
|
const why = stopped === "busy" ? "it is no longer idle" : "a stim start holds its metro-start lock";
|
|
9041
8004
|
note(chalk.dim(`Kept the dev server of ${path}: ${why}`));
|
|
8005
|
+
record?.("devServer", "kept", path, { detail: why });
|
|
9042
8006
|
} else if (stopped.status === "stopped") {
|
|
9043
8007
|
targets.push(path);
|
|
9044
8008
|
note(chalk.green(`Stopped the idle dev server of ${path}`));
|
|
8009
|
+
record?.("devServer", "done", path);
|
|
9045
8010
|
} else if ("reason" in stopped) {
|
|
9046
8011
|
if (stopped.status === "stuck") failures++;
|
|
9047
8012
|
note(chalk.yellow(`Kept the dev server of ${path}: ${stopped.reason}`));
|
|
8013
|
+
record?.("devServer", stopped.status === "stuck" ? "failed" : "kept", path, { detail: stopped.reason });
|
|
9048
8014
|
}
|
|
9049
8015
|
}
|
|
9050
8016
|
return {
|
|
@@ -9052,7 +8018,7 @@ async function reclaimIdleDevServers({ root, dryRun, note, now, env, signal, ope
|
|
|
9052
8018
|
failures
|
|
9053
8019
|
};
|
|
9054
8020
|
}
|
|
9055
|
-
async function reclaimWorkspaceOutputs({ root, dryRun, now, note, diskRecovered, signal, operation }) {
|
|
8021
|
+
async function reclaimWorkspaceOutputs({ root, dryRun, now, note, record, diskRecovered, signal, operation }) {
|
|
9056
8022
|
const other = isOtherWorkspace(root);
|
|
9057
8023
|
const report = await collectWorkspaceOutputs({
|
|
9058
8024
|
olderThan: null,
|
|
@@ -9084,7 +8050,7 @@ async function reclaimWorkspaceOutputs({ root, dryRun, now, note, diskRecovered,
|
|
|
9084
8050
|
now,
|
|
9085
8051
|
signal,
|
|
9086
8052
|
operation
|
|
9087
|
-
}, stepOutput(note));
|
|
8053
|
+
}, stepOutput(note, record));
|
|
9088
8054
|
failures += result.failures;
|
|
9089
8055
|
targets.push(...result.cleared);
|
|
9090
8056
|
if (await diskRecovered()) break;
|
|
@@ -9100,23 +8066,36 @@ function cacheLabel(cache) {
|
|
|
9100
8066
|
function trimmableCaches(env = process.env, cwd) {
|
|
9101
8067
|
return planCacheEmptying(discoverCaches(env, cwd), false, env).filter((cache) => cache.prune !== "report-only" && cache.prune !== "atomic" && !cache.machineGlobal);
|
|
9102
8068
|
}
|
|
9103
|
-
async function reclaimStaleCacheEntries({ dryRun, note, env, cwd, signal }) {
|
|
8069
|
+
async function reclaimStaleCacheEntries({ dryRun, note, record, env, cwd, now, freeMb, signal }) {
|
|
9104
8070
|
const caches = trimmableCaches(env, cwd);
|
|
9105
8071
|
if (dryRun) return {
|
|
9106
8072
|
targets: caches.map(cacheLabel),
|
|
9107
8073
|
failures: 0
|
|
9108
8074
|
};
|
|
9109
|
-
const
|
|
8075
|
+
const current = {
|
|
8076
|
+
at: now,
|
|
8077
|
+
freeMb,
|
|
8078
|
+
marker: sweepMarker(caches, 14)
|
|
8079
|
+
};
|
|
8080
|
+
if (canSkipEmptySweep(readEmptySweep(), current)) {
|
|
8081
|
+
note(chalk.dim(phaseLine("budget", `cache trim skipped: the last one, under ${EMPTY_SWEEP_WINDOW_MS / 6e4} minutes ago with the same caches and about the same free disk, found nothing older than 14d`)));
|
|
8082
|
+
return {
|
|
8083
|
+
targets: [],
|
|
8084
|
+
failures: 0
|
|
8085
|
+
};
|
|
8086
|
+
}
|
|
8087
|
+
const { trimmed, failures } = await trimCaches(caches, 14, stepOutput(note, record), signal);
|
|
8088
|
+
writeEmptySweep(trimmed.length === 0 && failures === 0 ? current : null);
|
|
9110
8089
|
return {
|
|
9111
8090
|
targets: trimmed.map(cacheLabel),
|
|
9112
8091
|
failures
|
|
9113
8092
|
};
|
|
9114
8093
|
}
|
|
9115
|
-
function stepOutput(note) {
|
|
8094
|
+
function stepOutput(note, record = () => {}) {
|
|
9116
8095
|
return {
|
|
9117
8096
|
log: note,
|
|
9118
8097
|
error: note,
|
|
9119
|
-
record
|
|
8098
|
+
record,
|
|
9120
8099
|
fail: () => {}
|
|
9121
8100
|
};
|
|
9122
8101
|
}
|
|
@@ -9154,23 +8133,22 @@ async function spaceUsers(env = process.env, signal, operation) {
|
|
|
9154
8133
|
["Android emulators", join(home, ".android", "avd")]
|
|
9155
8134
|
];
|
|
9156
8135
|
const measured = /* @__PURE__ */ new Set();
|
|
9157
|
-
const
|
|
8136
|
+
const targets = [];
|
|
9158
8137
|
for (const [label, path] of candidates) {
|
|
9159
8138
|
const canonical = canonicalPath(path);
|
|
9160
8139
|
if (measured.has(canonical) || [...measured].some((dir) => canonical.startsWith(`${dir}${sep}`))) continue;
|
|
9161
8140
|
measured.add(canonical);
|
|
9162
|
-
if (
|
|
9163
|
-
const bytes = await measuredDirectorySizeAsync(path, {
|
|
9164
|
-
timeoutMs: USAGE_TIMEOUT_MS,
|
|
9165
|
-
signal,
|
|
9166
|
-
operation
|
|
9167
|
-
});
|
|
9168
|
-
if (bytes) users.push({
|
|
9169
|
-
label: `${label} ${path}`,
|
|
9170
|
-
bytes
|
|
9171
|
-
});
|
|
8141
|
+
if (existsSync(path)) targets.push([label, path]);
|
|
9172
8142
|
}
|
|
9173
|
-
|
|
8143
|
+
const sizes = await Promise.all(targets.map(([, path]) => measuredDirectorySizeAsync(path, {
|
|
8144
|
+
timeoutMs: USAGE_TIMEOUT_MS,
|
|
8145
|
+
signal,
|
|
8146
|
+
operation
|
|
8147
|
+
})));
|
|
8148
|
+
return targets.flatMap(([label, path], index) => sizes[index] ? [{
|
|
8149
|
+
label: `${label} ${path}`,
|
|
8150
|
+
bytes: sizes[index]
|
|
8151
|
+
}] : []).toSorted((a, b) => b.bytes - a.bytes).map(({ label, bytes }) => `${label}: ${formatBytes(bytes)}`);
|
|
9174
8152
|
}
|
|
9175
8153
|
const DEFAULT_DEPS = {
|
|
9176
8154
|
volumes: readVolumeSpace,
|
|
@@ -9216,6 +8194,12 @@ async function enforceBudget({ root, note, dryRun = false, budget: resolved, env
|
|
|
9216
8194
|
const reclaimed = [];
|
|
9217
8195
|
const plan = reclaimPlan(short);
|
|
9218
8196
|
if (plan.length) note(chalk.yellow(phaseLine("budget", `${describeShortfall(budget, measure, short).join("; ")}; ${dryRun ? "would reclaim" : "reclaiming"}`)));
|
|
8197
|
+
const gcLog = dryRun ? null : openGcLog({
|
|
8198
|
+
trigger: "budget",
|
|
8199
|
+
holdKept: true,
|
|
8200
|
+
env
|
|
8201
|
+
});
|
|
8202
|
+
const gcResults = gcLog && createGcResults(gcLog.record);
|
|
9219
8203
|
for (const step of plan) {
|
|
9220
8204
|
signal?.throwIfAborted();
|
|
9221
8205
|
if (!dryRun && (!overBudget(short) || DISK_ONLY.includes(step) && short.disk.length === 0)) break;
|
|
@@ -9226,7 +8210,9 @@ async function enforceBudget({ root, note, dryRun = false, budget: resolved, env
|
|
|
9226
8210
|
env,
|
|
9227
8211
|
dryRun,
|
|
9228
8212
|
note,
|
|
8213
|
+
record: gcResults?.record,
|
|
9229
8214
|
now: deps.now(),
|
|
8215
|
+
freeMb: lowestFree(measure.volumes),
|
|
9230
8216
|
diskRecovered: async () => budgetShortfalls(budget, {
|
|
9231
8217
|
volumes: await (deps.volumesAsync?.(paths) ?? deps.volumes(paths)),
|
|
9232
8218
|
memory: null
|
|
@@ -9383,5 +8369,139 @@ function budgetLine(report) {
|
|
|
9383
8369
|
const { budget } = report;
|
|
9384
8370
|
return `${report.volumes.length ? `${report.volumes.map((v) => `${v.freeGb} GB free on ${v.volume}`).join(", ")} (reclaims below ${Math.max(budget.minFreeDiskGb, budget.hardFloorDiskGb)} GB, ${budget.hardFloorDiskGb ? `refuses below ${budget.hardFloorDiskGb} GB` : "never refuses"})` : "disk budget off"}; ${report.memory ? `roughly ${report.memory.committedGb} GB of a ${budget.maxCommittedMemoryGb} GB memory budget committed` : "memory budget off"}`;
|
|
9385
8371
|
}
|
|
8372
|
+
function ccacheInstallCommand(platform = process.platform) {
|
|
8373
|
+
return platform === "darwin" ? "brew install ccache" : platform === "linux" ? "sudo apt install ccache" : "install ccache";
|
|
8374
|
+
}
|
|
8375
|
+
const CCACHE_SLOPPINESS = "pch_defines,time_macros";
|
|
8376
|
+
const STATS_LOG_FILE = "ccache-stats.log";
|
|
8377
|
+
const CCACHE_UNAVAILABLE = {
|
|
8378
|
+
status: "unavailable",
|
|
8379
|
+
hits: null,
|
|
8380
|
+
misses: null,
|
|
8381
|
+
hitRatePercent: null
|
|
8382
|
+
};
|
|
8383
|
+
const CCACHE_NOT_RUN = {
|
|
8384
|
+
status: "not-run",
|
|
8385
|
+
hits: null,
|
|
8386
|
+
misses: null,
|
|
8387
|
+
hitRatePercent: null
|
|
8388
|
+
};
|
|
8389
|
+
function ccacheStatsLog(root) {
|
|
8390
|
+
return join(workspaceLogsDir$1(root), STATS_LOG_FILE);
|
|
8391
|
+
}
|
|
8392
|
+
function ccacheMaxSize(config = loadConfig$1(), env = process.env) {
|
|
8393
|
+
const { value, error } = machineNumber("caches.ccacheMaxGb", config, env);
|
|
8394
|
+
return error || value === void 0 ? "5G" : `${value}G`;
|
|
8395
|
+
}
|
|
8396
|
+
function ccacheEnvironment({ binary, dir, workspaceRoot, statsLog, maxSize = "5G" }) {
|
|
8397
|
+
return {
|
|
8398
|
+
CMAKE_C_COMPILER_LAUNCHER: binary,
|
|
8399
|
+
CMAKE_CXX_COMPILER_LAUNCHER: binary,
|
|
8400
|
+
CCACHE_DIR: dir,
|
|
8401
|
+
CCACHE_BASEDIR: workspaceRoot,
|
|
8402
|
+
CCACHE_NOHASHDIR: "true",
|
|
8403
|
+
CCACHE_SLOPPINESS,
|
|
8404
|
+
CCACHE_MAXSIZE: maxSize,
|
|
8405
|
+
CCACHE_STATSLOG: statsLog
|
|
8406
|
+
};
|
|
8407
|
+
}
|
|
8408
|
+
function parseCcacheBinary(output) {
|
|
8409
|
+
const first = String(output ?? "").split("\n")[0]?.trim();
|
|
8410
|
+
if (!first || !isAbsolute(first)) return null;
|
|
8411
|
+
return first;
|
|
8412
|
+
}
|
|
8413
|
+
const CMAKE_LAUNCHER = /CMAKE_(C|CXX)_COMPILER_LAUNCHER\b/;
|
|
8414
|
+
function projectCmakeLauncher(source) {
|
|
8415
|
+
if (typeof source !== "string") return null;
|
|
8416
|
+
const match = CMAKE_LAUNCHER.exec(source);
|
|
8417
|
+
return match ? `CMAKE_${match[1]}_COMPILER_LAUNCHER` : null;
|
|
8418
|
+
}
|
|
8419
|
+
const HIT_COUNTERS = /* @__PURE__ */ new Set(["direct_cache_hit", "preprocessed_cache_hit"]);
|
|
8420
|
+
function parseCcacheStatsLog(text) {
|
|
8421
|
+
if (typeof text !== "string") return null;
|
|
8422
|
+
let hits = 0;
|
|
8423
|
+
let misses = 0;
|
|
8424
|
+
for (const raw of text.split("\n")) {
|
|
8425
|
+
const line = raw.trim();
|
|
8426
|
+
if (HIT_COUNTERS.has(line)) hits += 1;
|
|
8427
|
+
else if (line === "cache_miss") misses += 1;
|
|
8428
|
+
}
|
|
8429
|
+
const total = hits + misses;
|
|
8430
|
+
if (total === 0) return null;
|
|
8431
|
+
return {
|
|
8432
|
+
status: "reported",
|
|
8433
|
+
hits,
|
|
8434
|
+
misses,
|
|
8435
|
+
hitRatePercent: Math.round(hits / total * 1e3) / 10
|
|
8436
|
+
};
|
|
8437
|
+
}
|
|
8438
|
+
function readCcacheActivity(statsLog) {
|
|
8439
|
+
let text;
|
|
8440
|
+
try {
|
|
8441
|
+
text = readFileSync(statsLog, "utf-8");
|
|
8442
|
+
} catch {
|
|
8443
|
+
return CCACHE_UNAVAILABLE;
|
|
8444
|
+
}
|
|
8445
|
+
return parseCcacheStatsLog(text) ?? CCACHE_UNAVAILABLE;
|
|
8446
|
+
}
|
|
8447
|
+
function ccacheActivityLine(activity) {
|
|
8448
|
+
if (activity.status === "reported") return `${activity.hits} hits / ${activity.misses} misses (${activity.hitRatePercent}%)`;
|
|
8449
|
+
if (activity.status === "not-run") return "not run; artifact cache supplied the app";
|
|
8450
|
+
return "unavailable; no C++ compile went through ccache";
|
|
8451
|
+
}
|
|
8452
|
+
function lookupCcache() {
|
|
8453
|
+
try {
|
|
8454
|
+
return parseCcacheBinary(getExecutor().findExecutable("ccache"));
|
|
8455
|
+
} catch {
|
|
8456
|
+
return null;
|
|
8457
|
+
}
|
|
8458
|
+
}
|
|
8459
|
+
function readOrNull(file) {
|
|
8460
|
+
try {
|
|
8461
|
+
return readFileSync(file, "utf-8");
|
|
8462
|
+
} catch {
|
|
8463
|
+
return null;
|
|
8464
|
+
}
|
|
8465
|
+
}
|
|
8466
|
+
function canonical(root) {
|
|
8467
|
+
try {
|
|
8468
|
+
return realpathSync(root);
|
|
8469
|
+
} catch {
|
|
8470
|
+
return root;
|
|
8471
|
+
}
|
|
8472
|
+
}
|
|
8473
|
+
function resolveCcache({ root, layout = defaultAndroidLayout(root), dir = sharedCcache$1(), lookup = lookupCcache, env = process.env, onNote = (line) => console.error(line) }) {
|
|
8474
|
+
const binary = lookup();
|
|
8475
|
+
if (!binary) {
|
|
8476
|
+
onNote(chalk.dim(phaseLine("cache", `ccache off (not installed; ${ccacheInstallCommand()})`)));
|
|
8477
|
+
return null;
|
|
8478
|
+
}
|
|
8479
|
+
const { moduleDir } = layout;
|
|
8480
|
+
const declared = projectCmakeLauncher(readOrNull(join(moduleDir, "build.gradle")) ?? readOrNull(join(moduleDir, "build.gradle.kts")));
|
|
8481
|
+
if (declared) {
|
|
8482
|
+
onNote(chalk.dim(phaseLine("cache", `ccache off (${join(relative(root, moduleDir), "build.gradle")} sets ${declared} itself)`)));
|
|
8483
|
+
return null;
|
|
8484
|
+
}
|
|
8485
|
+
const statsLog = ccacheStatsLog(root);
|
|
8486
|
+
register({
|
|
8487
|
+
dir,
|
|
8488
|
+
registeredBy: root,
|
|
8489
|
+
name: "ccache",
|
|
8490
|
+
prune: "atomic",
|
|
8491
|
+
note: "ccache keeps itself under CCACHE_MAXSIZE, so it is emptied whole or not at all"
|
|
8492
|
+
});
|
|
8493
|
+
onNote(chalk.dim(phaseLine("cache", `ccache on (${dir})`)));
|
|
8494
|
+
return {
|
|
8495
|
+
dir,
|
|
8496
|
+
statsLog,
|
|
8497
|
+
env: ccacheEnvironment({
|
|
8498
|
+
binary,
|
|
8499
|
+
dir,
|
|
8500
|
+
workspaceRoot: canonical(root),
|
|
8501
|
+
statsLog,
|
|
8502
|
+
maxSize: ccacheMaxSize(loadConfig$1(), env)
|
|
8503
|
+
})
|
|
8504
|
+
};
|
|
8505
|
+
}
|
|
9386
8506
|
//#endregion
|
|
9387
|
-
export {
|
|
8507
|
+
export { gradleVersionLines as $, memoryCacheKind as $n, INSTALL_ERROR as $t, diskPressureLevel as A, checkEasAuth as An, ensureRemoteBootOwned as At, includesArchives as B, bundleInvocation as Bn, RELEASE_VERIFY_WAIT_MS as Bt, devServerStopLevel as C, gateMetroOrigin as Cn, describeError as Ct, requestDevServerStop as D, RESOLVE_TIMEOUT_MS as Dn, bundleEntryPoint as Dt, metroLastStop as E, runProcessOperation as En, binOnPath as Et, gcOptionsOf as F, providerFromConfig as Fn, withEasProjectLock as Ft, planCacheEmptying as G, easCliSupport as Gn, unattributedLaunchLines as Gt, includesRecordings as H, remoteCommand as Hn, isBundleProof as Ht, maintenanceItem as I, readProjectConfig as In, LAUNCH_BUNDLING as It, selectsBeyondCaches as J, parseArchiveSelector as Jn, verifyLaunch as Jt, previewScopedEmptying as K, easCliUpgradeRemedy as Kn, unverifiedLaunchLines as Kt, openGcLog as L, resolveEasCliBin as Ln, LAUNCH_FATAL as Lt, levelStillShort as M, isEasAuthFailureText as Mn, remoteAndroidDeps as Mt, lowestFree as N, loadProjectProvider as Nn, remoteIosDeps as Nt, vanishedSupervisorMessage as O, UPLOAD_TIMEOUT_MS as On, endRecordedSession as Ot, protectWindowMs as P, ownerFromConfig as Pn, resolveRemoteContext as Pt, deleteGradleVersions as Q, inspectWatchmanMemory as Qn, DEFAULT_METRO_PORT as Qt, maintenanceLogger as R, resolveRemote as Rn, LAUNCH_UNVERIFIED as Rt, describeMetroLastStop as S, readRemoteSimulatorArch as Sn, deleteEasSessions as St, logVanishedSupervisor as T, processContext as Tn, REMOTE_SESSION_ERROR as Tt, includesWorkspaceOutputs as U, MIN_EAS_CLI_DEVICE_VERSION as Un, readCollectorRecords as Ut, includesParkedDevices as V, remoteCliInvocation as Vn, VERIFY_TIMEOUT_MS as Vt, isWorkspacesScope as W, MIN_EAS_CLI_SIMULATOR_VERSION as Wn, readMetroRecords as Wt, collectGradleVersions as X, WATCHMAN_KIND as Xn, APP_READINESS_TIMEOUT_MS as Xt, trimCaches as Y, GRADLE_DAEMONS_KIND as Yn, verifyReleaseLaunch as Yt, deleteGradleVersion as Z, collectMemoryReport as Zn, ADB_INSTALL_TIMEOUT_MS as Zt, resolveBudget as _, reverseMetroPorts as _n, findStaleDeviceRecords as _t, projectCmakeLauncher as a, devClientUrl as an, scopedMemoryReport as ar, DEVICE_LIST_TIMEOUT_MS$1 as at, stopOwnedMetroForReset as b, readBundleSchemes as bn, withAndroidAvdSizes as bt, budgetGate as c, hasMetroReverse as cn, attributeMachineUsage as cr, collectParkedSims as ct, enforceBudget as d, installIosApp as dn, pruneCache as dr, deleteProjectDevices as dt, IOS_DEV_MENU_OFF_DEFAULTS_PLIST as en, memoryLines as er, gradleVersionsPending as et, inspectBudget as f, iosAppProcess as fn, sizeCaches as fr, describeParkedSims as ft, readVolumeSpaceAsync as g, restartedAppNote as gn, findOrphanedDevices as gt, readVolumeSpace as h, launchIosApp as hn, eraseParkedDevices as ht, ccacheInstallCommand as i, clearOtherUserApps as in, reclaimMemory as ir, collectInventory as it, levelFloors as j, easAuthNote as jn, readInstalledEasCliVersionAsync as jt, withdrawDevServerStopRequest as k, cacheLevel as kn, ensureMetroReachable as kt, budgetLine as l, installAndroidApp as ln, readFootprints as lr, deleteParkedAvds as lt, peekBudget as m, launchAndroidReleaseApp as mn, deviceSweepIsScoped as mt, CCACHE_UNAVAILABLE as n, androidDevClientUrl as nn, memorySweepIsScoped as nr, waitForGradleExit as nt, readCcacheActivity as o, deviceShellArg as on, stopIdleGradleDaemons as or, collectDeviceLeases as ot, machineNumber as p, launchAndroidApp as pn, describeUnverifiableDevices as pt, selectCaches as q, ownedSessionName as qn, verifyAndroidReleaseLaunch as qt, ccacheActivityLine as r, appProcessFromPid as rn, memoryWorkPending as rr, getMachineCacheReport as rt, resolveCcache as s, ensureMetroReverse as sn, phase as sr, collectParkedAvds as st, CCACHE_NOT_RUN as t, androidAppProcess as tn, memoryScope as tr, includesGradleVersions as tt, cacheLabel as u, installConflictKind as un, discoverCaches as ur, deleteParkedSims as ut, trimmableCaches as v, writeDebugHttpHost as vn, findStaleProjectDevices as vt, devServerStopRecord as w, exitAfterFlush as wn, withRemoteSessionGcLocks as wt, describeDevServerStop as x, schemesFromInfoPlist as xn, collectEasSessionSweep as xt, stopOwnedMetro as y, pickDevClientScheme as yn, unverifiedDeviceCommand as yt, emptyCaches as z, uploadRemote as zn, MANIFEST_VERIFY_TIMEOUT_MS as zt };
|