stim 1.19.0 → 1.20.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 +20 -3
- package/dist/{activity-BSw0x84R.mjs → activity-BrGh9EAI.mjs} +3 -3
- package/dist/{agent-device-usage-output-Bjxu_VmX.mjs → agent-device-usage-output-DVyv_hWj.mjs} +7 -7
- package/dist/android-0vv-OruW.mjs +6 -0
- package/dist/android-Brx6EKvJ.mjs +1258 -0
- package/dist/{android-BdQC6zs1.mjs → android-BsYNR81W.mjs} +103 -45
- package/dist/{android-DE5g_5gv.mjs → android-CK3fpEyZ.mjs} +2 -2
- package/dist/{android-cas-C87geAg-.mjs → android-cas-DCAuXryb.mjs} +9 -5
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/api-run.mjs +159 -8
- package/dist/{api-DIf_s86s.mjs → api-zuX3ynYN.mjs} +5 -1
- package/dist/api.d.mts +98 -4
- package/dist/api.mjs +1 -1
- package/dist/{app-install-CFI4ptUL.mjs → app-install-0LgaQRT7.mjs} +9 -8
- package/dist/artifact-CnC0mfov.mjs +807 -0
- package/dist/artifact-DClXJNWx.mjs +772 -0
- package/dist/artifact-lifecycle-DzPpBYvK.mjs +30 -0
- package/dist/{browser-web-CDhqQxhv.mjs → browser-web-CzBmhmgs.mjs} +19 -19
- package/dist/{budget-Dz-kyXLv.mjs → budget-BONq9vXY.mjs} +3101 -3062
- package/dist/build-BixRI6sB.mjs +462 -0
- package/dist/{build-facts-B87vo-Im.d.mts → build-facts-DcLv2HSd.d.mts} +1 -32
- package/dist/build-plan-CP0tckNU.mjs +553 -0
- package/dist/{cache-manifest-DiwKSyv9.mjs → cache-manifest-qA3dT2x2.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{manifest-CX0d1IkZ.mjs → ccache-CjHQ5F8g.mjs} +13 -19
- package/dist/{chrome-BTUOo8p2.mjs → chrome-Dp2lMLBe.mjs} +1 -1
- package/dist/{cli-C9Zvgbdc.mjs → cli-B2R8wH1F.mjs} +20 -20
- package/dist/cli.mjs +1 -1
- package/dist/{client-CuUo8Nvg.mjs → client-BLy1Pw2V.mjs} +89 -307
- package/dist/collector-run.d.mts +4 -0
- package/dist/collector-run.mjs +7 -7
- package/dist/{command-output-Bt8ygHE7.mjs → command-output-BjPN99ZB.mjs} +2 -2
- package/dist/{config-DC5jEtd1.mjs → config-D0LhTY3S.mjs} +8 -12
- package/dist/{created-devices-D0s26Hx5.mjs → created-devices-HU_DAb_Q.mjs} +7 -6
- package/dist/{dependency-state-DKaS1OM9.mjs → dependency-state-B2m8eqsS.mjs} +2 -2
- package/dist/{detached-entry-pB_IPfV4.mjs → detached-entry-BXq4fIl-.mjs} +1 -1
- package/dist/{dev-client-CDY_zAmD.mjs → dev-client-ClATaJoH.mjs} +2 -2
- package/dist/{device-BHw0WlHl.mjs → device-B7lsC0K1.mjs} +8 -8
- package/dist/device-DVCwAFlX.mjs +727 -0
- package/dist/{device-capacity-BoN1jQkO.mjs → device-capacity-Ca_ke1LE.mjs} +13 -14
- package/dist/device-host-worker.mjs +38 -18
- package/dist/device-ios-CRUqPxKw.mjs +413 -0
- package/dist/{device-lease-Cu7PtQpZ.mjs → device-lease-DHOBXGgS.mjs} +135 -22
- package/dist/{device-lease-run-D38SnZtt.mjs → device-lease-run-CvDeHTkG.mjs} +4 -4
- package/dist/{device-pool-CP4rAsHx.mjs → device-pool-L2-5GxMy.mjs} +3 -3
- package/dist/{device-remote-B5GiUifk.mjs → device-remote-Bmg42063.mjs} +17 -68
- package/dist/doctor-C2MSuMMg.mjs +515 -0
- package/dist/{doctor-PRJH94v6.mjs → doctor-DPAqhVCK.mjs} +333 -744
- package/dist/{doctor-watchman-wZhyTdp4.mjs → doctor-watchman-CB4NnVZm.mjs} +13 -12
- package/dist/{simslim-D9LkJxIO.mjs → eas-build-Dw_ec2Km.mjs} +6 -152
- package/dist/{stim-installations-DbmUjsLv.mjs → eas-session-ledger-DZlC-Fq3.mjs} +57 -4
- package/dist/{error-diagnostics--v5HGOU0.mjs → error-diagnostics-Du7I_GuY.mjs} +17 -12
- package/dist/errors-DzkMYh8Q.mjs +205 -0
- package/dist/{exec-i8GDPwq9.mjs → exec-B81Qodjn.mjs} +40 -10
- package/dist/{gc-CyHMcKcn.mjs → gc-PWp34zGb.mjs} +21 -20
- package/dist/{device-ios-B2ruohE-.mjs → gradle-C2OEKCCI.mjs} +21 -650
- package/dist/{guide-dRaQJJk9.mjs → guide-Dai9lphv.mjs} +504 -117
- package/dist/{hosted-android-Bs7fytj7.mjs → hosted-android-DQ-Agsd8.mjs} +5 -5
- package/dist/{hosted-client-C5G4h_OJ.mjs → hosted-client-Io01s5By.mjs} +9 -3
- package/dist/{hosted-ios-Bik035eL.mjs → hosted-ios-DIxFnYp-.mjs} +3 -3
- package/dist/{hosted-logs-CI9Az9a4.mjs → hosted-logs-DP-ABU_M.mjs} +8 -8
- package/dist/{hosted-macos-DABm3ScO.mjs → hosted-macos-Aziw9T_9.mjs} +7 -6
- package/dist/{hosted-native-DbV2aUVw.mjs → hosted-native-BdAQi21M.mjs} +17 -14
- package/dist/{idle-shutdown-DYiMBn34.mjs → idle-shutdown-DdMqoSUB.mjs} +7 -7
- package/dist/{ios-DYUr9LGc.mjs → ios-BZ9dg2Fr.mjs} +8 -7
- package/dist/{ios-BWbHFZVz.mjs → ios-CXLIUxXJ.mjs} +180 -24
- package/dist/ios-CZuv6gRv.mjs +1112 -0
- package/dist/{ios-DCrkgXEM.mjs → ios-VGvNdsv2.mjs} +1 -1
- package/dist/{ios-device-CrW8aMb5.mjs → ios-device-B1B14xND.mjs} +1 -1
- package/dist/{ios-device-CJ_ZOGky.mjs → ios-device-BreZOpM0.mjs} +3 -3
- package/dist/ios-project-B9drt_aY.mjs +197 -0
- package/dist/{ios-state-By0XuLTQ.mjs → ios-state-CjrL2qv-.mjs} +1 -1
- package/dist/js-swap-C8icNYIY.mjs +432 -0
- package/dist/launch-DxH0THLP.mjs +745 -0
- package/dist/{react-native-ios-CSpIxexZ.mjs → launch-YrbqaIFj.mjs} +59 -612
- package/dist/{launch-verify-DCveSE6d.mjs → launch-verify-BzRdbuO1.mjs} +26 -7
- package/dist/{logs-Bao1HOMy.mjs → logs-DHaRNfg7.mjs} +11 -11
- package/dist/macos-C0iljhsN.mjs +2 -0
- package/dist/{macos-ciyBdTY5.mjs → macos-V_3Ui7g4.mjs} +42 -50
- package/dist/macos-run.mjs +1 -1
- package/dist/maintenance-run.mjs +13 -10
- package/dist/{metro-DI2AjPF_.mjs → metro-D_j9sN-B.mjs} +18 -5
- package/dist/{metro-gateway-BxpJLIwh.mjs → metro-gateway-BBJldOdi.mjs} +2 -2
- package/dist/miss-reason-BPAzZS0r.mjs +238 -0
- package/dist/{named-ports-B4iWH4E-.mjs → named-ports-C2lvoPsb.mjs} +3 -3
- package/dist/native-android-lHzaew7r.mjs +226 -0
- package/dist/native-gradle-inputs-BQnIdAlL.mjs +356 -0
- package/dist/{native-runtime-BGxsbfny.mjs → native-runtime-BRmWL7ru.mjs} +9 -8
- package/dist/native-xcode-inputs-eutS19jU.mjs +307 -0
- package/dist/native-xcode-ios-DP3cHLwu.mjs +434 -0
- package/dist/{ndjson-LGZAMsqa.mjs → ndjson-GOnbyvso.mjs} +6 -6
- package/dist/offload-worker.d.mts +41 -7
- package/dist/offload-worker.mjs +409 -74
- package/dist/{ownership-EB0ySdGK.mjs → ownership-DXzMMSx6.mjs} +2 -2
- package/dist/{placement-log-Dxe34rJm.mjs → placement-log-reFbjqEr.mjs} +1 -1
- package/dist/plan-BDk2AeY_.mjs +260 -0
- package/dist/plan-placement-D_YYlE6N.mjs +73 -0
- package/dist/{ports-ByPc0_97.mjs → ports-jzvAJXXL.mjs} +3 -3
- package/dist/{prebuild-BKJ3wJI1.mjs → prebuild-Bw44QxVh.mjs} +4 -4
- package/dist/{preview-BbSottmO.mjs → preview-BaBJ72Al.mjs} +50 -32
- package/dist/project-B8_duAzW.mjs +1067 -0
- package/dist/project-plan-BPwbLwQu.mjs +10 -0
- package/dist/{pull-request-IHNdMnG8.mjs → pull-request-vOhLNmIb.mjs} +1 -1
- package/dist/pull-requests.mjs +1 -1
- package/dist/react-native-android-chm1DMlA.mjs +921 -0
- package/dist/react-native-build-oAw6gQeW.mjs +239 -0
- package/dist/react-native-doctor-DYXoh-6I.mjs +78 -0
- package/dist/react-native-ios-SCTK_CT5.mjs +595 -0
- package/dist/{recordings-Bv8McZN4.mjs → recordings-Bk-VivUV.mjs} +1 -1
- package/dist/{reload-rAPdqeRR.mjs → reload-D34GkY78.mjs} +17 -13
- package/dist/remote-BU9UyhCJ.mjs +192 -0
- package/dist/{remote-cache-N3hAEaAL.mjs → remote-cache-Bsts6f6Y.mjs} +5 -5
- package/dist/result-BDoRk1k3.mjs +186 -0
- package/dist/{run-lAkle1-c.mjs → run-qvff78hv.mjs} +3 -3
- package/dist/{server-bare-CkIjnegq.mjs → server-bare-dWjAarki.mjs} +5 -5
- package/dist/server-command-7XIKlWtO.mjs +69 -0
- package/dist/{server-expo-n3tUi3Em.mjs → server-expo-CsYu2aKL.mjs} +107 -82
- package/dist/server-expo-DV43vep4.mjs +2 -0
- package/dist/{settings-CxgngUZk.mjs → settings-Bbztm4oV.mjs} +179 -129
- package/dist/{settings-2am7TSxp.mjs → settings-CT3E71-i.mjs} +6 -6
- package/dist/{state-lKh8shBp.d.mts → settings-vk3mJGSm.d.mts} +4 -2
- package/dist/settings.schema.json +84 -0
- package/dist/simslim-ChMfe8rg.mjs +149 -0
- package/dist/{slot-launch-HV_KtPIw.mjs → slot-launch-B9hn96wd.mjs} +6 -6
- package/dist/{stage-BgaZJVZY.mjs → stage-BNKKdDNc.mjs} +6 -3
- package/dist/start-CbQCSnXQ.mjs +2 -0
- package/dist/{start-DtxthMfI.mjs → start-CdvcTaXr.mjs} +97 -68
- package/dist/{state-Tp4uImDS.mjs → state-Boo0IMJq.mjs} +1 -1
- package/dist/{state-D2KtnALG.mjs → state-DI84A-uu.mjs} +29 -10
- package/dist/{stats-8EJ5ivFT.mjs → stats-BIIDrjA8.mjs} +5 -5
- package/dist/{status-BEeL6IKz.mjs → status-BDGHwkCs.mjs} +3 -1
- package/dist/{status-BOyp0CUl.mjs → status-DARMkc9q.mjs} +81 -293
- package/dist/status-watch-DvmI3SmN.mjs +296 -0
- package/dist/{stim-desktop-C65jk_q2.mjs → stim-desktop-8GQX2OV8.mjs} +1 -1
- package/dist/{stop-DRipAg-e.mjs → stop-CCZS-C9m.mjs} +2 -2
- package/dist/{stop-D0UIpZuh.mjs → stop-WQPQHLuy.mjs} +5 -5
- package/dist/{stop-zDlknFoz.mjs → stop-iNemHsJC.mjs} +21 -20
- package/dist/supervisor-run.d.mts +7 -2
- package/dist/supervisor-run.mjs +32 -20
- package/dist/{support-DsNaFg6D.mjs → support-CnE_SIjt.mjs} +17 -7
- package/dist/{support-CNqYkV0y.mjs → support-DCco5fut.mjs} +61 -8
- package/dist/{swiftpm-macos-aJzPAj1t.mjs → swiftpm-macos-afeNUExW.mjs} +5 -5
- package/dist/tailnet-CoJUb2tB.mjs +265 -0
- package/dist/toolchain-BIupIro1.mjs +2 -0
- package/dist/{toolchain-C3xSoyUl.mjs → toolchain-DqyDXs30.mjs} +206 -53
- package/dist/{trigger-CAhmG-4s.mjs → trigger-C0MWBi8O.mjs} +2 -2
- package/dist/trigger-SHLOWJ4O.mjs +2 -0
- package/dist/{warm-progress-pFLB2e6P.mjs → warm-progress-C3ASD6z5.mjs} +6 -6
- package/dist/{watchman-BL1IdOtq.mjs → watchman-CQl51YZu.mjs} +6 -6
- package/dist/{web-DbbrPUn0.mjs → web-B3eldHFH.mjs} +9 -13
- package/dist/web-BLXpOe6b.mjs +2 -0
- package/dist/web-run.mjs +10 -10
- package/dist/{workspace-state-CR9X86xJ.mjs → workspace-state-CSIFuuDa.mjs} +33 -33
- package/dist/{workspaces-Djb2gfi9.mjs → workspaces-D2xSHBDY.mjs} +1260 -1258
- package/dist/{worktree-BL4M1rhB.mjs → worktree-BxDqaTev.mjs} +84 -48
- package/dist/worktree-q7_OZNY0.mjs +2 -0
- package/package.json +8 -6
- package/shim/native-android.gradle +101 -0
- package/dist/android-BXc6BmEi.mjs +0 -3732
- package/dist/android-BvV1gGdN.mjs +0 -4
- package/dist/ios-ITYno9rO.mjs +0 -2241
- package/dist/macos-nIOATJmR.mjs +0 -2
- package/dist/metro-store-BAHFcJm6.mjs +0 -106
- package/dist/miss-reason-CjQCOKqq.mjs +0 -1743
- package/dist/plan-placement-BVY59qa8.mjs +0 -290
- package/dist/project-B5eQ1USs.mjs +0 -612
- package/dist/react-native-ios-BMh2i25I.mjs +0 -2
- package/dist/server-expo-DGsdUGX2.mjs +0 -2
- package/dist/start-D8NbxNBb.mjs +0 -2
- package/dist/trigger-CoalsMTV.mjs +0 -2
- package/dist/web-DFpFeZu5.mjs +0 -2
- package/dist/worktree-DV-A0LNL.mjs +0 -2
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
import { n as ownership_claim_exports } from "./process-identity-Biv3arCO.mjs";
|
|
2
|
+
import { A as providerDownloadPath, k as prepareProviderDownloadDir, v as waitForSharedBuild } from "./device-lease-DHOBXGgS.mjs";
|
|
3
|
+
import { x as workspaceDir } from "./workspace-state-CSIFuuDa.mjs";
|
|
4
|
+
import { _ as stepTimer, i as formatDuration, l as phaseLine, m as shortHash } from "./command-output-BjPN99ZB.mjs";
|
|
5
|
+
import { x as runCancellationSignal } from "./tailnet-CoJUb2tB.mjs";
|
|
6
|
+
import { a as easAuthNote, s as isEasAuthFailureText, t as RESOLVE_TIMEOUT_MS } from "./remote-cache-Bsts6f6Y.mjs";
|
|
7
|
+
import { _ as requireLocalBuild, c as offloadPlacement, h as namedBuildMachine, i as closeOffload, l as placementLoad, n as buildPlacementCandidates, o as offloadBuild, p as OffloadRefusal, r as chooseBuildMachine, u as remotePhaseText } from "./client-BLy1Pw2V.mjs";
|
|
8
|
+
import { i as skippedMissReason } from "./miss-reason-BPAzZS0r.mjs";
|
|
9
|
+
import { t as buildPlacementRecord } from "./placement-log-reFbjqEr.mjs";
|
|
10
|
+
import { t as runArtifactLifecycle } from "./artifact-lifecycle-DzPpBYvK.mjs";
|
|
11
|
+
import { n as CCACHE_UNAVAILABLE, r as ccacheActivityLine, t as CCACHE_NOT_RUN } from "./ccache-CjHQ5F8g.mjs";
|
|
12
|
+
import { c as formatDiagnostic } from "./gradle-C2OEKCCI.mjs";
|
|
13
|
+
import { a as PLATFORM, h as displayPath } from "./support-CnE_SIjt.mjs";
|
|
14
|
+
import { i as AndroidRecipeRefusal } from "./plan-BDk2AeY_.mjs";
|
|
15
|
+
import { rmSync } from "node:fs";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { machineCapacity } from "@stim-cli/core/state";
|
|
18
|
+
import { createWarnOnce, resolveTieredBuild, storeTieredBuild } from "@stim-cli/cache";
|
|
19
|
+
import chalk from "chalk";
|
|
20
|
+
//#region src/commands/android/artifact.ts
|
|
21
|
+
const FALLBACK_LINES = 5;
|
|
22
|
+
function fail(code, message, remedy, extra = {}) {
|
|
23
|
+
return {
|
|
24
|
+
code,
|
|
25
|
+
message,
|
|
26
|
+
remedy,
|
|
27
|
+
extra
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function acquireAndroidArtifact({ root, buildLog, writer, recipe, targetOffloadRefusal, buildPlan, cacheProviderConfig, requestedBuildCache, easBuild, androidPackage: initialPackage, record, maxBuilds, progress }, { acquireLock, releaseLock, waitForBuild, easAuth, resolveRemoteBuild, uploadRemoteBuild, loadCacheProviderModule, acquireSlot, releaseSlot, now }) {
|
|
31
|
+
const { phase, out, stats, step, miss, hit: lateHit, place, waitingOn, waitingFor } = progress;
|
|
32
|
+
let fallbackMachine = null;
|
|
33
|
+
let hereReason = "no remote Mac is paired";
|
|
34
|
+
let slotWaitMs;
|
|
35
|
+
const buildMachine = record.buildMachine ?? "auto";
|
|
36
|
+
const fallBack = (reason, line = reason, info = {}) => {
|
|
37
|
+
writer.write(buildPlacementRecord({
|
|
38
|
+
platform: PLATFORM,
|
|
39
|
+
buildMachine,
|
|
40
|
+
candidates: info.candidates,
|
|
41
|
+
event: "placement_fallback",
|
|
42
|
+
fallback: {
|
|
43
|
+
code: info.code ?? "fallback",
|
|
44
|
+
reason,
|
|
45
|
+
machine: info.machine
|
|
46
|
+
}
|
|
47
|
+
}));
|
|
48
|
+
if (namedBuildMachine(buildMachine)) throw new OffloadRefusal(buildMachine, reason);
|
|
49
|
+
requireLocalBuild(buildMachine);
|
|
50
|
+
record.offloadFallback = reason;
|
|
51
|
+
phase("build", `${line} -> building here`);
|
|
52
|
+
};
|
|
53
|
+
const { variant, cache: cachePolicy } = buildPlan;
|
|
54
|
+
const signal = runCancellationSignal() ?? new AbortController().signal;
|
|
55
|
+
const cacheTarget = (key) => ({
|
|
56
|
+
projectRoot: root,
|
|
57
|
+
platform: "android",
|
|
58
|
+
key,
|
|
59
|
+
signal
|
|
60
|
+
});
|
|
61
|
+
let useBuildCache = cachePolicy.read;
|
|
62
|
+
let cacheIneligible = null;
|
|
63
|
+
let androidPackage = initialPackage;
|
|
64
|
+
let ccacheActivity = CCACHE_NOT_RUN;
|
|
65
|
+
let phaseFailure = null;
|
|
66
|
+
let buildLock = null;
|
|
67
|
+
const releaseHeldLock = () => {
|
|
68
|
+
if (!buildLock) return;
|
|
69
|
+
const held = buildLock;
|
|
70
|
+
buildLock = null;
|
|
71
|
+
try {
|
|
72
|
+
releaseLock(held);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
out(phaseLine("build", chalk.dim(`could not release the build lock at ${held.path}: ${err?.message || err}`)));
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
let buildSlot = null;
|
|
78
|
+
const releaseHeldSlot = () => {
|
|
79
|
+
if (!buildSlot) return;
|
|
80
|
+
const held = buildSlot;
|
|
81
|
+
buildSlot = null;
|
|
82
|
+
try {
|
|
83
|
+
releaseSlot(held);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
out(phaseLine("build", chalk.dim(`could not release the build slot: ${err?.message || err}`)));
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
let hash = "";
|
|
89
|
+
let providerUpload = null;
|
|
90
|
+
let providerName = null;
|
|
91
|
+
let providerLoad = null;
|
|
92
|
+
const cacheWarn = createWarnOnce((line) => phase("cache", chalk.yellow(line)));
|
|
93
|
+
const loadTieredProvider = cachePolicy.remote && cacheProviderConfig ? () => providerLoad ??= loadCacheProviderModule({
|
|
94
|
+
projectRoot: root,
|
|
95
|
+
config: cacheProviderConfig
|
|
96
|
+
}) : null;
|
|
97
|
+
let cacheKey = "";
|
|
98
|
+
let storeHash = "";
|
|
99
|
+
let storeKey = "";
|
|
100
|
+
let apkPath = null;
|
|
101
|
+
let handoff = null;
|
|
102
|
+
let swapFellBack = false;
|
|
103
|
+
async function resolveInitialFingerprint() {
|
|
104
|
+
if (easBuild?.ok) {
|
|
105
|
+
hash = storeHash = easBuild.fingerprint;
|
|
106
|
+
cacheKey = storeKey = easBuild.cacheKey;
|
|
107
|
+
apkPath = easBuild.path;
|
|
108
|
+
record.fingerprint = hash;
|
|
109
|
+
record.cacheKey = cacheKey;
|
|
110
|
+
record.cacheHit = easBuild.cacheHit;
|
|
111
|
+
record.cacheSkipped = !useBuildCache;
|
|
112
|
+
providerName = "eas";
|
|
113
|
+
stats.setCacheKey(cacheKey);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
if (useBuildCache) step("cache-lookup");
|
|
117
|
+
const fingerprintTimer = stepTimer(now);
|
|
118
|
+
let computed;
|
|
119
|
+
try {
|
|
120
|
+
computed = await recipe.identity();
|
|
121
|
+
} catch (error) {
|
|
122
|
+
record.cacheSkipped = !useBuildCache;
|
|
123
|
+
if (error instanceof AndroidRecipeRefusal && error.missReason) record.missReason = error.missReason;
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
if ("cacheIneligible" in computed) {
|
|
127
|
+
cacheIneligible = computed.cacheIneligible;
|
|
128
|
+
useBuildCache = false;
|
|
129
|
+
record.fingerprint = null;
|
|
130
|
+
record.cacheKey = null;
|
|
131
|
+
record.cacheHit = false;
|
|
132
|
+
record.cacheSkipped = true;
|
|
133
|
+
phase("fingerprint", `unavailable: ${cacheIneligible}`);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
hash = computed.hash;
|
|
137
|
+
record.fingerprint = hash;
|
|
138
|
+
cacheKey = computed.key;
|
|
139
|
+
stats.setCacheKey(cacheKey);
|
|
140
|
+
record.cacheKey = cacheKey;
|
|
141
|
+
storeHash = hash;
|
|
142
|
+
storeKey = cacheKey;
|
|
143
|
+
const found = await resolveTieredBuild({
|
|
144
|
+
local: recipe.cache(),
|
|
145
|
+
loadProvider: loadTieredProvider,
|
|
146
|
+
target: {
|
|
147
|
+
projectRoot: root,
|
|
148
|
+
platform: PLATFORM,
|
|
149
|
+
key: cacheKey
|
|
150
|
+
},
|
|
151
|
+
destinationDir: providerDownloadPath(workspaceDir(root)),
|
|
152
|
+
ensureDestination: prepareProviderDownloadDir,
|
|
153
|
+
skipRead: !useBuildCache,
|
|
154
|
+
warn: cacheWarn
|
|
155
|
+
});
|
|
156
|
+
const cached = found?.tier === "local" ? found.path : null;
|
|
157
|
+
record.cacheHit = cached ? "local" : false;
|
|
158
|
+
record.cacheSkipped = !useBuildCache;
|
|
159
|
+
phase("fingerprint", `${shortHash(hash)} ${cached ? "hit" : "miss"}${useBuildCache ? "" : !requestedBuildCache ? " (--no-build-cache)" : " (cache reuse off in config)"} ${fingerprintTimer()}`);
|
|
160
|
+
if (found?.tier === "provider") {
|
|
161
|
+
record.cacheHit = "remote";
|
|
162
|
+
providerName = found.providerName ?? null;
|
|
163
|
+
phase("cache", `provider hit (${providerName})${found.storedLocally ? " -> stored locally" : ""}`);
|
|
164
|
+
}
|
|
165
|
+
apkPath = found?.path ?? null;
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
let remote = null;
|
|
169
|
+
let abandonedRemote = false;
|
|
170
|
+
let uploadPending = null;
|
|
171
|
+
async function resolveRemoteArtifact() {
|
|
172
|
+
if (cacheIneligible || !recipe.legacyCache) return;
|
|
173
|
+
if (!apkPath) {
|
|
174
|
+
const loaded = await recipe.legacyCache.load();
|
|
175
|
+
if (loaded?.unavailable) phase("cache", chalk.yellow(`provider not usable: ${loaded.unavailable}`));
|
|
176
|
+
else if (loaded?.provider) remote = loaded;
|
|
177
|
+
if (remote?.name === "eas") {
|
|
178
|
+
const auth = easAuth({
|
|
179
|
+
projectRoot: root,
|
|
180
|
+
owner: loaded?.owner || null
|
|
181
|
+
});
|
|
182
|
+
const authNote = easAuthNote(auth);
|
|
183
|
+
if (authNote) phase("cache", chalk.yellow(authNote));
|
|
184
|
+
if (auth?.code === "logged-out") remote = null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (remote && useBuildCache) {
|
|
188
|
+
const remoteTimer = stepTimer(now);
|
|
189
|
+
const hit = await resolveRemoteBuild({
|
|
190
|
+
logWriter: writer,
|
|
191
|
+
provider: remote.provider,
|
|
192
|
+
platform: PLATFORM,
|
|
193
|
+
projectRoot: root,
|
|
194
|
+
fingerprintHash: hash,
|
|
195
|
+
runOptions: recipe.legacyCache?.runOptions ?? null
|
|
196
|
+
});
|
|
197
|
+
if (hit?.appPath) {
|
|
198
|
+
let stored = null;
|
|
199
|
+
try {
|
|
200
|
+
stored = await recipe.cache().store({
|
|
201
|
+
...cacheTarget(cacheKey),
|
|
202
|
+
sourcePath: hit.appPath,
|
|
203
|
+
overwrite: false
|
|
204
|
+
}) ?? null;
|
|
205
|
+
} catch (err) {
|
|
206
|
+
phase("cache", chalk.yellow(`remote hit could not be stored locally: ${err?.message || err}`));
|
|
207
|
+
}
|
|
208
|
+
apkPath = stored || hit.appPath;
|
|
209
|
+
record.cacheHit = "remote";
|
|
210
|
+
phase("cache", `remote hit (${remote.name})${stored ? " -> stored locally" : ""} ${remoteTimer()}`);
|
|
211
|
+
} else if (hit?.timedOut) {
|
|
212
|
+
abandonedRemote = true;
|
|
213
|
+
phase("cache", chalk.yellow(`${remote.name} did not answer within ${formatDuration(RESOLVE_TIMEOUT_MS)}; building instead`));
|
|
214
|
+
} else if (hit?.failed) {
|
|
215
|
+
const authNote = remote.name === "eas" && isEasAuthFailureText(hit.failed) ? easAuthNote({
|
|
216
|
+
code: "logged-out",
|
|
217
|
+
reason: hit.failed
|
|
218
|
+
}) : null;
|
|
219
|
+
phase("cache", chalk.yellow(authNote || `${remote.name} could not be used: ${hit.failed}; building instead`));
|
|
220
|
+
} else phase("cache", `remote miss (${remote.name}) ${remoteTimer()}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
let waitedForBuild = null;
|
|
224
|
+
let releasedWait = null;
|
|
225
|
+
async function awaitSharedBuild() {
|
|
226
|
+
if (!useBuildCache) return null;
|
|
227
|
+
const shared = await waitForSharedBuild({
|
|
228
|
+
platform: PLATFORM,
|
|
229
|
+
key: cacheKey,
|
|
230
|
+
fingerprint: hash,
|
|
231
|
+
root,
|
|
232
|
+
logFile: buildLog,
|
|
233
|
+
command: "stim android",
|
|
234
|
+
acquire: acquireLock,
|
|
235
|
+
wait: waitForBuild,
|
|
236
|
+
now,
|
|
237
|
+
phase: (text) => {
|
|
238
|
+
step("wait");
|
|
239
|
+
phase("build", text);
|
|
240
|
+
},
|
|
241
|
+
waitingOn,
|
|
242
|
+
warn: (text) => phase("build", chalk.yellow(text)),
|
|
243
|
+
out
|
|
244
|
+
});
|
|
245
|
+
if (shared.refusal) {
|
|
246
|
+
const { code, message, remedy } = shared.refusal;
|
|
247
|
+
phaseFailure = fail(code, message, remedy, { lastBuildStatus: true });
|
|
248
|
+
throw new AndroidRecipeRefusal(phaseFailure);
|
|
249
|
+
}
|
|
250
|
+
buildLock = shared.lock;
|
|
251
|
+
releasedWait = shared.released;
|
|
252
|
+
if (shared.hit) {
|
|
253
|
+
apkPath = shared.hit.path;
|
|
254
|
+
record.cacheHit = "local";
|
|
255
|
+
waitedForBuild = shared.hit.waited;
|
|
256
|
+
}
|
|
257
|
+
return apkPath;
|
|
258
|
+
}
|
|
259
|
+
let swapDir = null;
|
|
260
|
+
const releaseArtifact = () => {
|
|
261
|
+
if (!swapDir) return;
|
|
262
|
+
try {
|
|
263
|
+
rmSync(swapDir, {
|
|
264
|
+
recursive: true,
|
|
265
|
+
force: true
|
|
266
|
+
});
|
|
267
|
+
swapDir = null;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
out(phaseLine("cleanup", chalk.yellow(`could not remove the temporary APK: ${error.message}`)));
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
const installableCachedApk = async (key, cachedPath) => {
|
|
273
|
+
const prepared = await recipe.materialize(key, cachedPath);
|
|
274
|
+
if (!prepared) {
|
|
275
|
+
swapFellBack = true;
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
swapDir = prepared.directory;
|
|
279
|
+
return prepared.apkPath;
|
|
280
|
+
};
|
|
281
|
+
async function prepareCachedArtifact(cachedPath) {
|
|
282
|
+
const prepared = await installableCachedApk(cacheKey, cachedPath);
|
|
283
|
+
if (!prepared) {
|
|
284
|
+
record.cacheHit = false;
|
|
285
|
+
waitedForBuild = null;
|
|
286
|
+
}
|
|
287
|
+
return prepared;
|
|
288
|
+
}
|
|
289
|
+
function reasonForMiss(rekeyedBy) {
|
|
290
|
+
if (swapFellBack) return {
|
|
291
|
+
reason: skippedMissReason("the cached APK could not be reused, so this run built it fresh"),
|
|
292
|
+
diff: null
|
|
293
|
+
};
|
|
294
|
+
if (cacheIneligible) return {
|
|
295
|
+
reason: skippedMissReason(cacheIneligible),
|
|
296
|
+
diff: null
|
|
297
|
+
};
|
|
298
|
+
if (!useBuildCache) return {
|
|
299
|
+
reason: skippedMissReason(requestedBuildCache ? "cache reuse off in config" : "cache reuse turned off by --no-build-cache"),
|
|
300
|
+
diff: null
|
|
301
|
+
};
|
|
302
|
+
return recipe.explain(rekeyedBy);
|
|
303
|
+
}
|
|
304
|
+
function explainMiss(rekeyedBy) {
|
|
305
|
+
const explained = reasonForMiss(rekeyedBy);
|
|
306
|
+
record.missReason = explained.reason;
|
|
307
|
+
if (explained.diff) writer.write(explained.diff);
|
|
308
|
+
miss(record.missReason);
|
|
309
|
+
phase("cache", `miss: ${record.missReason.summary}`);
|
|
310
|
+
if (record.missReason.kind === "no-baseline") {
|
|
311
|
+
const line = recipe.untrackedLine();
|
|
312
|
+
if (line) phase("fingerprint", chalk.dim(line));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async function takeBuildSlot() {
|
|
316
|
+
requireLocalBuild(buildMachine);
|
|
317
|
+
if (!maxBuilds) return true;
|
|
318
|
+
try {
|
|
319
|
+
buildSlot = await acquireSlot({
|
|
320
|
+
automatic: buildMachine === "auto",
|
|
321
|
+
max: maxBuilds,
|
|
322
|
+
root,
|
|
323
|
+
logFile: buildLog,
|
|
324
|
+
out,
|
|
325
|
+
waitingFor: (info) => waitingFor?.(info, "build-slot")
|
|
326
|
+
});
|
|
327
|
+
slotWaitMs = buildSlot.slotWaitMs;
|
|
328
|
+
} catch (err) {
|
|
329
|
+
requireLocalBuild(buildMachine);
|
|
330
|
+
const refusal = (0, ownership_claim_exports.claimFailure)(err, "stim android");
|
|
331
|
+
if (refusal) {
|
|
332
|
+
phaseFailure = fail(refusal.code, refusal.message, refusal.remedy, { lastBuildStatus: true });
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
phase("build", chalk.yellow(`could not take a build slot: ${err?.message || err}; building anyway`));
|
|
336
|
+
}
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
/** Whether this build should leave this Mac, before any machine is asked; null builds here. */
|
|
340
|
+
function placeBuild() {
|
|
341
|
+
if (cacheIneligible && !recipe.offload?.supportsUncachedArtifacts) {
|
|
342
|
+
if (namedBuildMachine(buildMachine)) throw new OffloadRefusal(buildMachine, cacheIneligible);
|
|
343
|
+
hereReason = cacheIneligible;
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const { mode, machines, localEnabled } = buildPlacementCandidates(buildMachine);
|
|
347
|
+
if (localEnabled && machines.length === 0 && !namedBuildMachine(buildMachine) && buildMachine !== "local") return null;
|
|
348
|
+
const unsupported = targetOffloadRefusal ?? (recipe.offload ? recipe.offload.unsupported : "this project integration does not support offloaded builds");
|
|
349
|
+
const here = machineCapacity();
|
|
350
|
+
const placement = offloadPlacement({
|
|
351
|
+
mode,
|
|
352
|
+
localEnabled,
|
|
353
|
+
machines: machines.length,
|
|
354
|
+
here,
|
|
355
|
+
unsupported,
|
|
356
|
+
selected: buildMachine
|
|
357
|
+
});
|
|
358
|
+
if (!placement.offload) {
|
|
359
|
+
hereReason = placement.reason;
|
|
360
|
+
writer.write(buildPlacementRecord({
|
|
361
|
+
platform: PLATFORM,
|
|
362
|
+
buildMachine,
|
|
363
|
+
stays: {
|
|
364
|
+
code: placement.code,
|
|
365
|
+
reason: placement.reason
|
|
366
|
+
}
|
|
367
|
+
}));
|
|
368
|
+
if (mode !== "off") phase("build", `placement: here (${placement.reason})`);
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
mode,
|
|
373
|
+
here,
|
|
374
|
+
code: placement.code,
|
|
375
|
+
reason: placement.reason,
|
|
376
|
+
machines
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
const openOffload = { choice: null };
|
|
380
|
+
/** Asks the paired machines once the post-mutation key is known; null builds here. */
|
|
381
|
+
async function chooseMachine(candidate) {
|
|
382
|
+
let asked = [];
|
|
383
|
+
let target;
|
|
384
|
+
try {
|
|
385
|
+
target = recipe.offload.target();
|
|
386
|
+
} catch (error) {
|
|
387
|
+
fallBack(error.message);
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
const choice = await chooseBuildMachine({
|
|
391
|
+
projectRoot: root,
|
|
392
|
+
target,
|
|
393
|
+
mode: candidate.mode,
|
|
394
|
+
here: candidate.here,
|
|
395
|
+
note: (line) => phase("build", chalk.dim(`offload: ${line}`)),
|
|
396
|
+
machines: candidate.machines,
|
|
397
|
+
selected: buildMachine,
|
|
398
|
+
onCandidates: (each) => asked = each
|
|
399
|
+
});
|
|
400
|
+
if (typeof choice === "string") {
|
|
401
|
+
const only = candidate.machines.length === 1 ? candidate.machines[0].machine : null;
|
|
402
|
+
if (only && choice.startsWith(`${only}: `)) fallbackMachine = only;
|
|
403
|
+
fallBack(choice, choice, {
|
|
404
|
+
code: "no-remote-mac-took-it",
|
|
405
|
+
candidates: asked
|
|
406
|
+
});
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
openOffload.choice = choice;
|
|
410
|
+
writer.write(buildPlacementRecord({
|
|
411
|
+
platform: PLATFORM,
|
|
412
|
+
buildMachine,
|
|
413
|
+
candidates: asked,
|
|
414
|
+
chose: {
|
|
415
|
+
machine: choice.machine,
|
|
416
|
+
reason: `${candidate.reason}${placementLoad(choice)}`
|
|
417
|
+
}
|
|
418
|
+
}));
|
|
419
|
+
phase("build", `placement: ${choice.machine} (${candidate.reason}${placementLoad(choice)})`);
|
|
420
|
+
return choice;
|
|
421
|
+
}
|
|
422
|
+
/** Builds on the chosen machine and stores the APK under the post-mutation key; false builds here instead unless a machine was named. */
|
|
423
|
+
async function compileElsewhere(choice, candidate) {
|
|
424
|
+
const uncached = Boolean(cacheIneligible && recipe.offload?.supportsUncachedArtifacts);
|
|
425
|
+
if ((!storeKey || !storeHash) && !uncached) {
|
|
426
|
+
const reason = "the build fingerprint or cache key is unavailable";
|
|
427
|
+
if (namedBuildMachine(buildMachine)) fallBack(reason, reason, { machine: choice.machine });
|
|
428
|
+
else writer.write(buildPlacementRecord({
|
|
429
|
+
platform: PLATFORM,
|
|
430
|
+
buildMachine,
|
|
431
|
+
event: "placement_fallback",
|
|
432
|
+
fallback: {
|
|
433
|
+
code: "fallback",
|
|
434
|
+
reason,
|
|
435
|
+
machine: choice.machine
|
|
436
|
+
}
|
|
437
|
+
}));
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
const stagingDir = join(workspaceDir(root), "offload", PLATFORM);
|
|
441
|
+
if (uncached) swapDir = stagingDir;
|
|
442
|
+
const outcome = await offloadBuild({
|
|
443
|
+
choice,
|
|
444
|
+
expectedFingerprint: uncached ? null : storeHash,
|
|
445
|
+
request: recipe.offload.request,
|
|
446
|
+
stagingDir,
|
|
447
|
+
onPhase: (name, msg) => phase(name, remotePhaseText(name, msg, choice.machine)),
|
|
448
|
+
onEnter: (name) => {
|
|
449
|
+
if (name === "compile" || name === "build" || name === "prebuild" || name === "pods") record.builtOn = choice.machine;
|
|
450
|
+
place({
|
|
451
|
+
host: choice.machine,
|
|
452
|
+
phase: name
|
|
453
|
+
});
|
|
454
|
+
step(name === "prebuild" ? name : "compile");
|
|
455
|
+
},
|
|
456
|
+
onRecord: (entry) => writer.write({
|
|
457
|
+
...entry,
|
|
458
|
+
offloadedTo: choice.machine
|
|
459
|
+
}),
|
|
460
|
+
note: (line) => phase("build", line)
|
|
461
|
+
});
|
|
462
|
+
place(null);
|
|
463
|
+
let stored = null;
|
|
464
|
+
let reason = outcome.ok ? null : outcome.reason;
|
|
465
|
+
if (outcome.ok) {
|
|
466
|
+
let unchanged = false;
|
|
467
|
+
try {
|
|
468
|
+
unchanged = await recipe.offload.unchanged();
|
|
469
|
+
} catch (error) {
|
|
470
|
+
reason = error.message;
|
|
471
|
+
}
|
|
472
|
+
if (!unchanged) reason ??= "the checkout here changed while it built";
|
|
473
|
+
else if (uncached) {
|
|
474
|
+
if (!outcome.androidPackage) reason = "the worker returned no verified APK package";
|
|
475
|
+
else {
|
|
476
|
+
stored = outcome.artifactPath;
|
|
477
|
+
androidPackage = outcome.androidPackage;
|
|
478
|
+
swapDir = stagingDir;
|
|
479
|
+
}
|
|
480
|
+
} else try {
|
|
481
|
+
stored = await recipe.cache().store({
|
|
482
|
+
...cacheTarget(storeKey),
|
|
483
|
+
sourcePath: outcome.artifactPath,
|
|
484
|
+
overwrite: !useBuildCache
|
|
485
|
+
}) ?? null;
|
|
486
|
+
} catch (err) {
|
|
487
|
+
reason = `could not store the APK: ${err?.message || err}`;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
try {
|
|
491
|
+
if (!uncached || !stored) {
|
|
492
|
+
rmSync(stagingDir, {
|
|
493
|
+
recursive: true,
|
|
494
|
+
force: true
|
|
495
|
+
});
|
|
496
|
+
if (swapDir === stagingDir) swapDir = null;
|
|
497
|
+
}
|
|
498
|
+
} catch {}
|
|
499
|
+
step("compile");
|
|
500
|
+
if (!outcome.ok || !stored) {
|
|
501
|
+
const why = reason ?? "the APK was not stored";
|
|
502
|
+
fallbackMachine = choice.machine;
|
|
503
|
+
fallBack(`${choice.machine}: ${why}`, `offload failed: ${why}`, {
|
|
504
|
+
code: "offload-failed",
|
|
505
|
+
machine: choice.machine
|
|
506
|
+
});
|
|
507
|
+
writer.write({
|
|
508
|
+
src: "build",
|
|
509
|
+
level: "warn",
|
|
510
|
+
event: "offload_failed",
|
|
511
|
+
msg: reason,
|
|
512
|
+
machine: choice.machine
|
|
513
|
+
});
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
const { timings } = outcome;
|
|
517
|
+
apkPath = stored;
|
|
518
|
+
handoff = outcome.handoff ?? null;
|
|
519
|
+
record.builtOn = outcome.machine;
|
|
520
|
+
record.offloadedTo = outcome.machine;
|
|
521
|
+
stats.setPlacement({
|
|
522
|
+
decision: "offloaded",
|
|
523
|
+
machine: outcome.machine,
|
|
524
|
+
reason: `${candidate.reason}${placementLoad(choice)}`,
|
|
525
|
+
buildMs: timings.totalMs
|
|
526
|
+
});
|
|
527
|
+
ccacheActivity = outcome.ccache;
|
|
528
|
+
phase("build", `built on ${outcome.machine} in ${formatDuration(timings.totalMs)}: offer ${formatDuration(timings.offerMs)}, sync ${formatDuration(timings.syncMs)}, build ${formatDuration(timings.workerMs)}, fetch ${formatDuration(timings.fetchMs)}`);
|
|
529
|
+
phase("cache", `compilation cache on ${outcome.machine} ${ccacheActivityLine(ccacheActivity)}`);
|
|
530
|
+
writer.write({
|
|
531
|
+
src: "build",
|
|
532
|
+
level: "info",
|
|
533
|
+
event: "offload_done",
|
|
534
|
+
msg: `built on ${outcome.machine}`,
|
|
535
|
+
timings
|
|
536
|
+
});
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
539
|
+
async function prepareSource() {
|
|
540
|
+
await recipe.prepare(() => miss(reasonForMiss([]).reason, true));
|
|
541
|
+
return recipe.reconcile();
|
|
542
|
+
}
|
|
543
|
+
async function revalidateSource(preparation) {
|
|
544
|
+
const { identity, rekeyedBy } = preparation;
|
|
545
|
+
if (preparation.androidPackage) {
|
|
546
|
+
androidPackage = preparation.androidPackage;
|
|
547
|
+
record.bundleId = androidPackage;
|
|
548
|
+
}
|
|
549
|
+
if (cacheIneligible || !identity) {
|
|
550
|
+
storeHash = "";
|
|
551
|
+
storeKey = "";
|
|
552
|
+
record.fingerprint = null;
|
|
553
|
+
record.cacheKey = null;
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
if (identity.key !== storeKey) {
|
|
557
|
+
storeHash = identity.hash;
|
|
558
|
+
storeKey = identity.key;
|
|
559
|
+
record.fingerprint = storeHash;
|
|
560
|
+
record.cacheKey = storeKey;
|
|
561
|
+
const late = useBuildCache ? await recipe.cache().resolve({
|
|
562
|
+
...cacheTarget(storeKey),
|
|
563
|
+
destinationDir: providerDownloadPath(workspaceDir(root))
|
|
564
|
+
}) : null;
|
|
565
|
+
if (late) {
|
|
566
|
+
const prepared = await installableCachedApk(storeKey, late);
|
|
567
|
+
if (prepared) {
|
|
568
|
+
apkPath = prepared;
|
|
569
|
+
record.cacheHit = "local";
|
|
570
|
+
lateHit();
|
|
571
|
+
phase("cache", `hit ${shortHash(storeHash)} (post-${rekeyedBy.join("/")} key)`);
|
|
572
|
+
if (releasedWait) {
|
|
573
|
+
waitedForBuild = releasedWait.facts;
|
|
574
|
+
phase("build", `waited ${formatDuration(waitedForBuild.ms)} for ${releasedWait.who}'s build -> installed from cache -- stim guide lifecycle concurrency`);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return apkPath ? { ready: apkPath } : null;
|
|
580
|
+
}
|
|
581
|
+
async function acquireRemoteArtifact(offload, { rekeyedBy, cacheRefusal }) {
|
|
582
|
+
explainMiss(rekeyedBy);
|
|
583
|
+
step("compile");
|
|
584
|
+
if (cacheRefusal) fallBack(cacheRefusal, `offload failed: ${cacheRefusal}`);
|
|
585
|
+
else {
|
|
586
|
+
const choice = await chooseMachine(offload);
|
|
587
|
+
if (choice) await compileElsewhere(choice, offload);
|
|
588
|
+
}
|
|
589
|
+
return apkPath ? { ready: apkPath } : null;
|
|
590
|
+
}
|
|
591
|
+
async function compileHere(offload, { rekeyedBy }) {
|
|
592
|
+
if (!offload) {
|
|
593
|
+
explainMiss(rekeyedBy);
|
|
594
|
+
step("compile");
|
|
595
|
+
}
|
|
596
|
+
if (offload) stats.setPlacement({
|
|
597
|
+
decision: "fell-back",
|
|
598
|
+
slotWaitMs,
|
|
599
|
+
deviceSlotWaitMs: stats.deviceSlotWaitMs(),
|
|
600
|
+
reason: record.offloadFallback ?? "offload failed",
|
|
601
|
+
...fallbackMachine ? { machine: fallbackMachine } : {}
|
|
602
|
+
});
|
|
603
|
+
else stats.setPlacement({
|
|
604
|
+
decision: "here",
|
|
605
|
+
reason: hereReason,
|
|
606
|
+
slotWaitMs,
|
|
607
|
+
deviceSlotWaitMs: stats.deviceSlotWaitMs()
|
|
608
|
+
});
|
|
609
|
+
requireLocalBuild(buildMachine);
|
|
610
|
+
record.builtOn = "here";
|
|
611
|
+
phase("build", `compiling ${variant || "debug"} with Gradle`);
|
|
612
|
+
const built = await recipe.compile();
|
|
613
|
+
ccacheActivity = built.ccache ?? CCACHE_UNAVAILABLE;
|
|
614
|
+
phase("cache", `compilation cache ${ccacheActivityLine(ccacheActivity)}`);
|
|
615
|
+
if (!built.ok) {
|
|
616
|
+
const diagnostics = built.diagnostics;
|
|
617
|
+
for (const diag of diagnostics) writer.write({
|
|
618
|
+
src: "build",
|
|
619
|
+
level: "error",
|
|
620
|
+
event: "gradle_diagnostic",
|
|
621
|
+
msg: formatDiagnostic(diag)
|
|
622
|
+
});
|
|
623
|
+
phase("build", chalk.red(`FAILED after ${formatDuration(built.durationMs)}`));
|
|
624
|
+
const extracted = diagnostics.map(formatDiagnostic);
|
|
625
|
+
if (built.truncated > 0) extracted.push(`... and ${built.truncated} more diagnostic(s) in the log`);
|
|
626
|
+
phaseFailure = fail(built.code, built.reason, diagnostics.find((d) => d.remedy)?.remedy || built.remedy || null, {
|
|
627
|
+
lastBuildStatus: true,
|
|
628
|
+
diagnostics: extracted,
|
|
629
|
+
buildDiagnostics: diagnostics,
|
|
630
|
+
lines: extracted.length ? [] : tail(built.lastLines),
|
|
631
|
+
logPath: displayPath(root, buildLog)
|
|
632
|
+
});
|
|
633
|
+
throw new AndroidRecipeRefusal(phaseFailure);
|
|
634
|
+
}
|
|
635
|
+
apkPath = built.apkPath;
|
|
636
|
+
if (built.androidPackage) {
|
|
637
|
+
androidPackage = built.androidPackage;
|
|
638
|
+
record.bundleId = androidPackage;
|
|
639
|
+
}
|
|
640
|
+
stats.setBuildMs(built.durationMs);
|
|
641
|
+
phase("build", `ok (${formatDuration(built.durationMs)})`);
|
|
642
|
+
if (built.apkNote) phase("build", chalk.yellow(built.apkNote));
|
|
643
|
+
return apkPath;
|
|
644
|
+
}
|
|
645
|
+
async function validateCompiled() {
|
|
646
|
+
if (cacheIneligible) return "uncacheable";
|
|
647
|
+
const identity = await recipe.validate();
|
|
648
|
+
if (!identity) {
|
|
649
|
+
record.fingerprint = null;
|
|
650
|
+
record.cacheKey = null;
|
|
651
|
+
return "uncacheable";
|
|
652
|
+
}
|
|
653
|
+
storeHash = identity.hash;
|
|
654
|
+
storeKey = identity.key;
|
|
655
|
+
record.fingerprint = storeHash;
|
|
656
|
+
record.cacheKey = storeKey;
|
|
657
|
+
return "cacheable";
|
|
658
|
+
}
|
|
659
|
+
async function storeArtifact(artifactPath) {
|
|
660
|
+
if (cachePolicy.write) {
|
|
661
|
+
const local = recipe.cache(true);
|
|
662
|
+
try {
|
|
663
|
+
const stored = await storeTieredBuild({
|
|
664
|
+
local,
|
|
665
|
+
loadProvider: loadTieredProvider,
|
|
666
|
+
target: {
|
|
667
|
+
projectRoot: root,
|
|
668
|
+
platform: PLATFORM,
|
|
669
|
+
key: storeKey
|
|
670
|
+
},
|
|
671
|
+
sourcePath: artifactPath,
|
|
672
|
+
overwrite: !useBuildCache || swapFellBack,
|
|
673
|
+
warn: cacheWarn
|
|
674
|
+
});
|
|
675
|
+
providerUpload = stored.providerUpload;
|
|
676
|
+
providerName = stored.providerName ?? providerName;
|
|
677
|
+
} catch (err) {
|
|
678
|
+
phase("cache", chalk.yellow(`could not store the build: ${err?.message || err}`));
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (remote) uploadPending = uploadRemoteBuild({
|
|
682
|
+
logWriter: writer,
|
|
683
|
+
provider: remote.provider,
|
|
684
|
+
platform: PLATFORM,
|
|
685
|
+
projectRoot: root,
|
|
686
|
+
fingerprintHash: storeHash,
|
|
687
|
+
buildPath: artifactPath,
|
|
688
|
+
runOptions: recipe.legacyCache?.runOptions ?? null
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
try {
|
|
692
|
+
apkPath = await runArtifactLifecycle({
|
|
693
|
+
resolve: async () => {
|
|
694
|
+
if (!await resolveInitialFingerprint()) throw new AndroidRecipeRefusal(phaseFailure);
|
|
695
|
+
if (easBuild) return {
|
|
696
|
+
kind: "ready",
|
|
697
|
+
artifact: apkPath
|
|
698
|
+
};
|
|
699
|
+
await resolveRemoteArtifact();
|
|
700
|
+
if (apkPath) return {
|
|
701
|
+
kind: "cached",
|
|
702
|
+
artifact: apkPath
|
|
703
|
+
};
|
|
704
|
+
miss(reasonForMiss([]).reason);
|
|
705
|
+
return { kind: "miss" };
|
|
706
|
+
},
|
|
707
|
+
claim: useBuildCache ? awaitSharedBuild : void 0,
|
|
708
|
+
reuse: async (cached) => {
|
|
709
|
+
apkPath = await prepareCachedArtifact(cached);
|
|
710
|
+
if (apkPath) lateHit();
|
|
711
|
+
else if (swapFellBack) miss(reasonForMiss([]).reason);
|
|
712
|
+
return apkPath;
|
|
713
|
+
},
|
|
714
|
+
build: {
|
|
715
|
+
placement: {
|
|
716
|
+
select: placeBuild,
|
|
717
|
+
acquire: acquireRemoteArtifact
|
|
718
|
+
},
|
|
719
|
+
admit: async () => {
|
|
720
|
+
if (!await takeBuildSlot()) throw new AndroidRecipeRefusal(phaseFailure);
|
|
721
|
+
},
|
|
722
|
+
prepare: prepareSource,
|
|
723
|
+
revalidate: revalidateSource,
|
|
724
|
+
compile: compileHere,
|
|
725
|
+
validate: validateCompiled,
|
|
726
|
+
store: storeArtifact
|
|
727
|
+
},
|
|
728
|
+
release: () => {
|
|
729
|
+
if (openOffload.choice) closeOffload(openOffload.choice);
|
|
730
|
+
releaseHeldLock();
|
|
731
|
+
releaseHeldSlot();
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
} catch (error) {
|
|
735
|
+
releaseArtifact();
|
|
736
|
+
if (error instanceof OffloadRefusal) {
|
|
737
|
+
const { code, message, remedy } = error;
|
|
738
|
+
return {
|
|
739
|
+
ok: false,
|
|
740
|
+
failure: fail(code, message, remedy, { lastBuildStatus: true }),
|
|
741
|
+
ccache: ccacheActivity
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
if (error instanceof AndroidRecipeRefusal) return {
|
|
745
|
+
ok: false,
|
|
746
|
+
failure: error.failure,
|
|
747
|
+
ccache: ccacheActivity
|
|
748
|
+
};
|
|
749
|
+
throw error;
|
|
750
|
+
}
|
|
751
|
+
return {
|
|
752
|
+
ok: true,
|
|
753
|
+
artifact: {
|
|
754
|
+
apkPath,
|
|
755
|
+
handoff,
|
|
756
|
+
androidPackage,
|
|
757
|
+
release: releaseArtifact,
|
|
758
|
+
waitedForBuild,
|
|
759
|
+
ccache: ccacheActivity,
|
|
760
|
+
uploadPending,
|
|
761
|
+
providerUpload,
|
|
762
|
+
providerName,
|
|
763
|
+
remote,
|
|
764
|
+
abandonedRemote
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
function tail(lines, n = FALLBACK_LINES) {
|
|
769
|
+
return (Array.isArray(lines) ? lines : []).slice(-n);
|
|
770
|
+
}
|
|
771
|
+
//#endregion
|
|
772
|
+
export { acquireAndroidArtifact as t };
|