stim 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/{activity-DfVKZTEB.mjs → activity-B2-kb7k0.mjs} +281 -41
- package/dist/{android-BHfAu2mf.mjs → android-CYmq0jNi.mjs} +2 -2
- package/dist/{android-CD8pr8Q2.mjs → android-Cu_L4RpL.mjs} +524 -412
- package/dist/{android-qx_31wJo.mjs → android-Db2eEMaf.mjs} +152 -65
- package/dist/android-cas-PnKfAdB2.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{app-install-CDFY2nUL.mjs → app-install-CAAplXAt.mjs} +162 -173
- package/dist/{budget-E5o91NR1.mjs → budget-CMiqghig.mjs} +1048 -77
- package/dist/{build-plan-BTa93o_r.mjs → build-plan-aeGMFX7e.mjs} +193 -650
- package/dist/build-progress-C2Jv1AtA.mjs +872 -0
- package/dist/build-slots-Df1ApSuH.mjs +127 -0
- package/dist/{cache-manifest-DWPF4RKJ.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-B5hWgQJS.mjs → chrome-BrcVWQyD.mjs} +4 -4
- package/dist/cli-0cX5s4NM.mjs +45 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-C2IS36Qf.mjs +1333 -0
- package/dist/collector-run.mjs +8 -7
- package/dist/{command-output-BIL7rlX7.mjs → command-output-CliHHn7a.mjs} +1 -1
- package/dist/{config-0jCcMM0E.mjs → config-D0DbpZtM.mjs} +29 -29
- package/dist/{created-devices-Cd558h31.mjs → created-devices-BwVb3liH.mjs} +2 -2
- package/dist/{dependency-state-DNN0yfx6.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
- package/dist/{deps-2Wo81np9.mjs → deps-BFlKbOIp.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CjzLoNs0.mjs +80 -0
- package/dist/{device-Cf7vl-so.mjs → device-BZ1IyS5A.mjs} +7 -7
- package/dist/device-capacity-DMuKC7nx.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +769 -0
- package/dist/device-ios-DMQBUPus.mjs +381 -0
- package/dist/{device-lease-CL9dZf73.mjs → device-lease-W5Pi1q38.mjs} +43 -36
- package/dist/{device-pool-MuoiyRcu.mjs → device-pool-B2r38YjS.mjs} +4 -4
- package/dist/{device-remote-DT9ngZiD.mjs → device-remote-9ulPsdhY.mjs} +68 -162
- package/dist/{doctor-D2iysNNH.mjs → doctor-BcE5xsBn.mjs} +191 -99
- package/dist/{error-diagnostics-BoiOhck8.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-eA-PRBX8.mjs → gc-BuL1Genr.mjs} +430 -102
- package/dist/{android-cas-B9Kv9aIy.mjs → gradle-CmdOBq1d.mjs} +8 -294
- package/dist/{guide-BfZ0OmiP.mjs → guide-cCSGRFd3.mjs} +2052 -240
- package/dist/{guide-status-BaMYu55M.mjs → guide-status-CIoWK6mG.mjs} +3 -3
- package/dist/hosted-macos-DwowNU7W.mjs +447 -0
- package/dist/idle-shutdown-B5LPaNyY.mjs +122 -0
- package/dist/in-use-CndPMilN.mjs +110 -0
- package/dist/{ios-CmEzZiOj.mjs → ios-3CtCRhwr.mjs} +201 -10
- package/dist/{ios-CcfCeZ19.mjs → ios-Chob8ny7.mjs} +560 -259
- package/dist/{ios-device-BW-t_Lkv.mjs → ios-device-DERmMmk-.mjs} +12 -7
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{launch-verify-CuJaBpEa.mjs → launch-verify-CLlofxRt.mjs} +42 -11
- package/dist/{logs-DcSRbC2t.mjs → logs-h9h6MUvE.mjs} +95 -13
- package/dist/machine-usage-D_YYMzfR.mjs +283 -0
- package/dist/machines-CYtOCqcj.mjs +259 -0
- package/dist/macos-BwtbUtTN.mjs +468 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/{merge-state-ytFQCeh4.mjs → merge-state-BnxLNQiM.mjs} +22 -12
- package/dist/{metro-BPeY1YMh.mjs → metro-Di8EN2Tb.mjs} +20 -120
- package/dist/{named-ports-n7tnJsI8.mjs → named-ports-Dj_XBNaL.mjs} +8 -64
- package/dist/native-run-DFDoIRbY.mjs +147 -0
- package/dist/{native-runtime-CiiFHt0e.mjs → native-runtime-i6OkVg-w.mjs} +11 -6
- package/dist/offload-worker.d.mts +121 -0
- package/dist/offload-worker.mjs +601 -0
- package/dist/{ownership-Bz2kETAS.mjs → ownership-BkYxUtuj.mjs} +3 -2
- package/dist/{page-BTu7I60K.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-C5UutqpJ.mjs → ports-DddwttKM.mjs} +3 -3
- package/dist/prebuild-BvxDlD6C.mjs +213 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-DGeclhvO.mjs → project-CV3tDFHl.mjs} +9 -18
- package/dist/pull-request-pxnDCQzn.mjs +322 -0
- package/dist/pull-requests.d.mts +120 -0
- package/dist/pull-requests.mjs +2 -0
- package/dist/recordings-GEXp4iBT.mjs +37 -0
- package/dist/{reload-C-cV5yy_.mjs → reload-ChPiwvot.mjs} +70 -22
- package/dist/{remote-cache--aehr4Pr.mjs → remote-cache-CO2elm_b.mjs} +4 -4
- package/dist/run-B-xqRrsg.mjs +119 -0
- package/dist/{server-bare-Bq8BpSIo.mjs → server-bare-X7PUgizL.mjs} +60 -13
- package/dist/{server-expo-DUCg52-K.mjs → server-expo-DhtX6bom.mjs} +6 -10
- package/dist/server-expo-KJeD109I.mjs +2 -0
- package/dist/{settings-xB0Frkg6.mjs → settings-CduVcoxj.mjs} +77 -26
- package/dist/{settings-ssVBToDR.mjs → settings-DbL6uhH8.mjs} +16 -10
- package/dist/settings.schema.json +357 -2
- package/dist/{simslim-Bbg9UWrt.mjs → simslim-Ciluxlq4.mjs} +8 -132
- package/dist/slot-launch-BY0BrOLh.mjs +65 -0
- package/dist/{spawn-claims-PT8aQpCa.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-DncpJvWL.mjs +16 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CPO4wRg7.mjs +2 -0
- package/dist/{start-BZhItkiL.mjs → start-CUD9nasA.mjs} +108 -61
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/state-BxCgeTQu.mjs +41 -0
- package/dist/{state-DwAU2_-D.mjs → state-CaeaHbDA.mjs} +7 -4
- package/dist/{state-l1pYwOre.mjs → state-DFm77wRn.mjs} +67 -5
- package/dist/stats-DBLLFmKd.mjs +66 -0
- package/dist/{status-TJlL0HWo.mjs → status-DYXxNOT0.mjs} +425 -260
- package/dist/{status-sszP4XKU.mjs → status-l84Gbvp2.mjs} +122 -20
- package/dist/stdout-reader-C8yjre1x.mjs +23 -0
- package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
- package/dist/stim-footprint.swift +32 -0
- package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
- package/dist/{stop-BZ2qMiBP.mjs → stop-Bad61z_2.mjs} +128 -19
- package/dist/stop-Bvf1MflS.mjs +48 -0
- package/dist/{stop-DskDKNTU.mjs → stop-CceYh1yG.mjs} +2 -2
- package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
- package/dist/supervisor-run.d.mts +44 -12
- package/dist/supervisor-run.mjs +276 -33
- package/dist/support-CDQbDkL5.mjs +315 -0
- package/dist/support-WLOzVKUv.mjs +176 -0
- package/dist/teardown-BYuQafiA.mjs +718 -0
- package/dist/{xcode-LM6A8cNZ.mjs → toolchain-DmeYjXD9.mjs} +363 -13
- package/dist/warm-progress-DVHLN4uC.mjs +463 -0
- package/dist/{idle-DxLi5OkN.mjs → watchman-Bx0wceoF.mjs} +55 -8
- package/dist/{web-sWXd5iek.mjs → web-k6w8-HnE.mjs} +39 -22
- package/dist/web-run.mjs +326 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-CL2V2Ons.mjs +371 -0
- package/dist/worktree-BT_uULFx.mjs +2 -0
- package/dist/{worktree-DeBQSVtR.mjs → worktree-C0c5Udwa.mjs} +55 -54
- package/dist/{worktree-D4Do_XiQ.mjs → worktree-qXKzADSC.mjs} +161 -255
- package/package.json +10 -5
- package/shim/bundle-response.cjs +55 -10
- package/shim/bundle-response.d.cts +1 -0
- package/shim/expo-metro-config.cjs +10 -2
- package/dist/build-progress-l7d-X-ZP.mjs +0 -247
- package/dist/in-use-wYEaKQM9.mjs +0 -249
- package/dist/ownership-PUP4Dwai.mjs +0 -1138
- package/dist/server-expo-BeYwP_Xy.mjs +0 -2
- package/dist/slot-launch-BIWEW-wI.mjs +0 -19
- package/dist/start-Rw2GD3nV.mjs +0 -2
- package/dist/stats-CaSwmsSZ.mjs +0 -62
- package/dist/stats-D8rUTPHd.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/worktree-3cBa-bQt.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
|
@@ -1,39 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
import { E as upsertProject, L as deviceSlotFileKey, R as deviceSlotKey, V as parseDeviceSlotOption, W as validateDeviceSlot, p as getProject, u as getConcurrencyLimits, v as recordIosSchemeApprovals } from "./config-D0DbpZtM.mjs";
|
|
3
|
+
import { n as ownership_claim_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
3
4
|
import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-
|
|
6
|
-
import { a as findProjectRoot, n as appProjectProblem, r as detectIsExpo, t as NO_PROJECT_REFUSAL } from "./project-
|
|
7
|
-
import { m as writeWorkspaceLaunch, n as MODE_EXPO, t as MODE_BARE } from "./state-
|
|
8
|
-
import { _ as stepTimer, c as launchErrorReport, g as stepClock, h as shortUdid, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-
|
|
9
|
-
import { A as providerDownloadPath, D as fingerprintProject, E as fingerprintDiffRecord, L as untrackedMissLine, M as refingerprintAfterMutation, N as resolveBuild, O as inputsChangedDuringBuild, P as storeBuild, R as untrackedNativeFiles, S as configInputsChanged, T as filesystemBuildCapability, _ as waitForBuild, b as buildCacheKey, g as releaseBuildLock, j as providerUploadOutcome, k as prepareProviderDownloadDir, m as acquireBuildLock, v as waitForSharedBuild, x as changedDuringBuildLine } from "./device-lease-
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { n as
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { a as
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { a as
|
|
28
|
-
import { n as
|
|
29
|
-
import { a as
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
5
|
+
import { C as workspaceLogsDir, b as workspaceDir, c as writeWorkspaceState, i as recordWorkspaceUse, r as readWorkspaceState$1 } from "./workspace-state-CL2V2Ons.mjs";
|
|
6
|
+
import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-C0c5Udwa.mjs";
|
|
7
|
+
import { a as findProjectRoot$1, n as appProjectProblem, r as detectIsExpo, t as NO_PROJECT_REFUSAL } from "./project-CV3tDFHl.mjs";
|
|
8
|
+
import { m as writeWorkspaceLaunch, n as MODE_EXPO, t as MODE_BARE } from "./state-CaeaHbDA.mjs";
|
|
9
|
+
import { _ as stepTimer, c as launchErrorReport, g as stepClock, h as shortUdid, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-CliHHn7a.mjs";
|
|
10
|
+
import { A as providerDownloadPath, D as fingerprintProject, E as fingerprintDiffRecord, L as untrackedMissLine, M as refingerprintAfterMutation, N as resolveBuild, O as inputsChangedDuringBuild, P as storeBuild, R as untrackedNativeFiles, S as configInputsChanged, T as filesystemBuildCapability, _ as waitForBuild, b as buildCacheKey, g as releaseBuildLock, j as providerUploadOutcome, k as prepareProviderDownloadDir, m as acquireBuildLock, v as waitForSharedBuild, x as changedDuringBuildLine } from "./device-lease-W5Pi1q38.mjs";
|
|
11
|
+
import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Cnz8CPnl.mjs";
|
|
12
|
+
import { at as POOL_SETTING_REMEDY, dt as parkedMaxSetting } from "./android-Db2eEMaf.mjs";
|
|
13
|
+
import { l as resolveProjectMetro, o as pidExists, u as signalProcessTree } from "./metro-Di8EN2Tb.mjs";
|
|
14
|
+
import { B as unknownSettingKeys, I as settingOriginScope, J as optimizationBuildProfile, K as artifactCachePolicy, L as settingShapeErrors, M as resolveCacheProviderConfig, N as resolveSettings, O as publicUrlSetting, R as settingsLayers, S as metroPortSetting, U as detectProviders, Y as resolveOptimizations, _ as iosSigningIdentitySha1Setting, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, g as iosSigningIdentitySettingError, h as iosSigningIdentitySetting, j as remoteIosSetting, m as iosLanHostSettingError, p as iosLanHostSetting, r as REMOTE_DEVICE_BACKENDS, v as iosSigningIdentitySha1SettingError, w as metroWarmupUrlSetting, z as tunnelModeSetting } from "./settings-CduVcoxj.mjs";
|
|
15
|
+
import { p as listIosRuntimes, r as clearIosAppData } from "./ios-3CtCRhwr.mjs";
|
|
16
|
+
import { c as recordFinishedBuild, d as createRunRecorder, f as readRunEstimates, h as statsProjectKey$1, l as startBuildProgress, m as recordRunStats, n as NO_BUILD_PROGRESS, u as tapBuildLog } from "./build-progress-C2Jv1AtA.mjs";
|
|
17
|
+
import { r as releaseBuildSlot, t as acquireBuildSlot } from "./build-slots-Df1ApSuH.mjs";
|
|
18
|
+
import { n as verifyCollectorOwnership } from "./ownership-BkYxUtuj.mjs";
|
|
19
|
+
import { S as restartedAppNote, _ as installIosApp, a as IOS_DEV_MENU_OFF_DEFAULTS_PLIST, d as devClientUrl, l as clearOtherUserApps, r as DEFAULT_METRO_PORT, v as iosAppProcess, x as launchIosApp } from "./app-install-CAAplXAt.mjs";
|
|
20
|
+
import { t as checkDeviceCapacity } from "./device-capacity-DMuKC7nx.mjs";
|
|
21
|
+
import { i as schemesFromInfoPlist, n as devClientTakesDevMenuParams, r as pickDevClientScheme, t as devClientScheme } from "./dev-client-CjzLoNs0.mjs";
|
|
22
|
+
import { S as bundlerPin, _ as readBundleId, c as COMPILATION_CACHE_NOT_RUN, d as buildIos, g as readBundleExecutable, h as discoverXcodeProject, p as compilationCacheActivityLine, r as iosToolchain, v as resolveScheme } from "./toolchain-DmeYjXD9.mjs";
|
|
23
|
+
import { a as offloadBuild, c as placementLoad, d as OffloadRefusal, f as namedBuildMachine, i as closeOffload, l as remotePhaseText, m as resolveBuildPlacement, n as buildPlacementCandidates, p as parseBuildMachineOption, r as chooseBuildMachine, s as offloadPlacement, u as simulatorRuntime } from "./client-C2IS36Qf.mjs";
|
|
24
|
+
import { t as spawnEntry } from "./spawn-entry-DncpJvWL.mjs";
|
|
25
|
+
import { a as runPodInstall, n as podsAreStale, r as readPodState } from "./deps-BFlKbOIp.mjs";
|
|
26
|
+
import { i as staleNativeDirRefusal, n as recordPrebuild, r as runPrebuild, t as planPrebuild } from "./prebuild-BvxDlD6C.mjs";
|
|
27
|
+
import { n as clearIosAdoptionPending } from "./device-ios-DMQBUPus.mjs";
|
|
28
|
+
import { _ as xcodeFailureReport, a as deviceShortName, c as isReleaseConfiguration, d as printDiagnostics, f as resolveConfiguration, g as simulatorBuildArch, h as resolveSimulatorAppFlag, i as deviceModelRefusal, l as ownedSimFailure, m as resolveRuntime, n as buildLogFile, o as iosConfigurationSetting, p as resolveDeviceType, r as deviceLabel, s as iosProviderRunOptions, t as appNameFromPath, u as podAction } from "./support-WLOzVKUv.mjs";
|
|
29
|
+
import { a as easAuthNote, c as loadProjectProvider, f as resolveEasCliBin, i as checkEasAuth, m as uploadRemote, n as UPLOAD_TIMEOUT_MS, o as exitAfterFlush, p as resolveRemote, r as cacheLevel, s as isEasAuthFailureText, t as RESOLVE_TIMEOUT_MS } from "./remote-cache-CO2elm_b.mjs";
|
|
30
|
+
import { O as readRemoteSimulatorArch, a as ensureMetroReachable, k as gateMetroOrigin, l as remoteIosDeps, n as binOnPath, o as ensureRemoteBootOwned, r as bundleEntryPoint, u as resolveRemoteContext, w as ownedSessionName } from "./device-remote-9ulPsdhY.mjs";
|
|
31
|
+
import { c as readMetroRecords, f as verifyLaunch, i as RELEASE_VERIFY_WAIT_MS, l as unattributedLaunchLines, n as LAUNCH_FATAL, o as isBundleProof, p as verifyReleaseLaunch, r as LAUNCH_UNVERIFIED, s as readCollectorRecords, t as LAUNCH_BUNDLING, u as unverifiedLaunchLines } from "./launch-verify-CLlofxRt.mjs";
|
|
32
|
+
import { d as withNativeBuildRun, r as cancelledFailure, u as runCancellation } from "./native-run-DFDoIRbY.mjs";
|
|
33
|
+
import { a as isEasBuildFailure, i as easDeviceBuildRemedy, o as planEasDevelopmentBuild, s as resolveEasDevelopmentBuild } from "./simslim-Ciluxlq4.mjs";
|
|
34
|
+
import { c as startDevServer, h as detectBundleId } from "./start-CUD9nasA.mjs";
|
|
35
|
+
import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-B2r38YjS.mjs";
|
|
36
|
+
import { a as refusePlan, c as skippedMissReason, f as swapJsBundle, h as ensureOwnedDevice, i as printPlan, m as ensureBooted, n as planFlagRefusal, o as explainBuildMiss, p as didSetUpDevice, r as planPayload, s as fingerprintErrorMissReason, t as planCachedBuild, v as warmMetro } from "./build-plan-aeGMFX7e.mjs";
|
|
37
|
+
import { t as budgetGate } from "./budget-CMiqghig.mjs";
|
|
38
|
+
import { a as sleep, i as launchOutcomeRecord, n as ensureWorkspaceStorageSafely, r as isPhysicalDeviceRequest, t as ensureDevServer } from "./native-runtime-i6OkVg-w.mjs";
|
|
39
|
+
import { n as nativeRunCommand, r as siblingPlatformSlots, t as launchSlotScope } from "./slot-launch-BY0BrOLh.mjs";
|
|
40
|
+
import { a as printNativeCrashReport, n as IOS_CRASH_REPORT_RETRY, o as simulatorConsolePaths, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-Cb0P1WLS.mjs";
|
|
41
|
+
import { a as iosPoolCandidates, c as isWirelessIosDevice, f as resolveIosPhysicalDevice, i as iosDeviceProcess, l as listIosDevices, n as installIosDeviceApp, o as iosPoolNoCandidatesRefusal, p as verifyIosDeviceReleaseLaunch, r as iosDeviceBounds, t as awaitIosDeviceLaunch, u as localNetworkPending } from "./ios-device-DERmMmk-.mjs";
|
|
42
|
+
import { X509Certificate } from "node:crypto";
|
|
32
43
|
import { existsSync, mkdirSync, mkdtempSync, openSync, rmSync, writeFileSync } from "node:fs";
|
|
33
|
-
import { InvalidArgumentError } from "commander";
|
|
34
|
-
import { buildDiagnostics } from "@stim-cli/core/state";
|
|
35
44
|
import { basename, join } from "node:path";
|
|
36
|
-
import {
|
|
45
|
+
import { hostSimulatorArch } from "@stim-cli/core";
|
|
46
|
+
import { InvalidArgumentError } from "commander";
|
|
47
|
+
import { buildDiagnostics, machineCapacity } from "@stim-cli/core/state";
|
|
37
48
|
import { networkInterfaces, tmpdir } from "node:os";
|
|
38
49
|
import chalk from "chalk";
|
|
39
50
|
import { createWarnOnce, loadCacheProvider, resolveTieredBuild, storeTieredBuild } from "@stim-cli/cache";
|
|
@@ -111,133 +122,9 @@ function copyAppAside(appPath, { exec = null, mkdtemp = () => makeTemporaryDirec
|
|
|
111
122
|
appPath: copy
|
|
112
123
|
};
|
|
113
124
|
}
|
|
114
|
-
function buildLogFile(root) {
|
|
115
|
-
return join(workspaceLogsDir(root), `build-ios.ndjson`);
|
|
116
|
-
}
|
|
117
|
-
const MAX_PRINTED_DIAGNOSTICS = 6;
|
|
118
|
-
function deviceLabel(device, udid) {
|
|
119
|
-
const name = device?.deviceName || device?.name || null;
|
|
120
|
-
return name ? `${name} (${shortUdid(udid)})` : shortUdid(udid);
|
|
121
|
-
}
|
|
122
|
-
function deviceShortName(device, udid) {
|
|
123
|
-
return device?.deviceName || device?.name || shortUdid(udid);
|
|
124
|
-
}
|
|
125
|
-
function appNameFromPath(appPath) {
|
|
126
|
-
if (typeof appPath !== "string" || appPath.trim() === "") return null;
|
|
127
|
-
const name = basename(appPath).replace(/\.app$/i, "");
|
|
128
|
-
return name === "" ? null : name;
|
|
129
|
-
}
|
|
130
|
-
function iosConfigurationSetting(settings) {
|
|
131
|
-
const ios = settings?.["ios"];
|
|
132
|
-
if (!ios || typeof ios !== "object" || Array.isArray(ios)) return null;
|
|
133
|
-
const raw = ios["configuration"];
|
|
134
|
-
return typeof raw === "string" && raw.trim() !== "" ? raw.trim() : null;
|
|
135
|
-
}
|
|
136
|
-
function resolveConfiguration(flag, settings) {
|
|
137
|
-
return (typeof flag === "string" && flag.trim() !== "" ? flag.trim() : null) || iosConfigurationSetting(settings);
|
|
138
|
-
}
|
|
139
|
-
function iosStringSetting(settings, key) {
|
|
140
|
-
const ios = settings?.["ios"];
|
|
141
|
-
if (!ios || typeof ios !== "object" || Array.isArray(ios)) return null;
|
|
142
|
-
const raw = ios[key];
|
|
143
|
-
return typeof raw === "string" && raw.trim() !== "" ? raw.trim() : null;
|
|
144
|
-
}
|
|
145
|
-
function resolveDeviceType(flag, settings) {
|
|
146
|
-
return (typeof flag === "string" && flag.trim() !== "" ? flag.trim() : null) || iosStringSetting(settings, "deviceType");
|
|
147
|
-
}
|
|
148
|
-
function resolveRuntime(flag, settings) {
|
|
149
|
-
return (typeof flag === "string" && flag.trim() !== "" ? flag.trim() : null) || iosStringSetting(settings, "runtime");
|
|
150
|
-
}
|
|
151
|
-
function resolveSimulatorAppFlag(flag, physical, remoteBackend) {
|
|
152
|
-
if (flag === void 0) return {};
|
|
153
|
-
let simulatorApp;
|
|
154
|
-
try {
|
|
155
|
-
simulatorApp = parseIosSimulatorApp(flag, "--simulator-app");
|
|
156
|
-
} catch (error) {
|
|
157
|
-
return { refusal: {
|
|
158
|
-
code: "STIM_BAD_ARG",
|
|
159
|
-
message: error.message
|
|
160
|
-
} };
|
|
161
|
-
}
|
|
162
|
-
if (physical || remoteBackend) return { refusal: {
|
|
163
|
-
code: "STIM_BAD_ARG",
|
|
164
|
-
message: "--simulator-app only applies to a local owned iOS simulator.",
|
|
165
|
-
remedy: "Drop --simulator-app when using a physical or remote device."
|
|
166
|
-
} };
|
|
167
|
-
return { simulatorApp };
|
|
168
|
-
}
|
|
169
|
-
function deviceModelRefusal({ slot, deviceTypeFlag, runtimeFlag, deviceType, runtime, physical, remoteBackend, listRuntimes }) {
|
|
170
|
-
if (slot && slot !== "default" && remoteBackend) return {
|
|
171
|
-
code: "STIM_BAD_ARG",
|
|
172
|
-
message: "Named slots currently support local simulators and physical devices.",
|
|
173
|
-
remedy: "Use the default slot for a remote session."
|
|
174
|
-
};
|
|
175
|
-
if (typeof deviceTypeFlag === "string" && deviceTypeFlag.trim() === "") return {
|
|
176
|
-
code: "STIM_BAD_ARG",
|
|
177
|
-
message: "--device-type was given an empty name.",
|
|
178
|
-
remedy: "Pass `--device-type <name>` with a model `xcrun simctl list devicetypes` names, e.g. \"iPad Pro 13-inch (M5)\"."
|
|
179
|
-
};
|
|
180
|
-
if (typeof runtimeFlag === "string" && runtimeFlag.trim() === "") return {
|
|
181
|
-
code: "STIM_BAD_ARG",
|
|
182
|
-
message: "--runtime was given an empty version.",
|
|
183
|
-
remedy: "Pass `--runtime <version>` with a runtime `xcrun simctl list runtimes` reports, e.g. \"18.5\"."
|
|
184
|
-
};
|
|
185
|
-
if (physical || remoteBackend) return null;
|
|
186
|
-
if (!deviceType && !runtime) return null;
|
|
187
|
-
let runtimes;
|
|
188
|
-
try {
|
|
189
|
-
runtimes = listRuntimes();
|
|
190
|
-
} catch (error) {
|
|
191
|
-
return {
|
|
192
|
-
code: "STIM_NO_DEVICE",
|
|
193
|
-
message: `Could not read the installed simulator runtimes: ${error?.message || error}`,
|
|
194
|
-
remedy: "Run `stim doctor` to check the simulator toolchain, then try again."
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
const refusal = unknownIosRuntimeRefusal(runtime, runtimes) ?? unknownIosDeviceTypeRefusal(deviceType, runtimes, runtime);
|
|
198
|
-
return refusal ? {
|
|
199
|
-
code: "STIM_BAD_ARG",
|
|
200
|
-
message: refusal.message,
|
|
201
|
-
remedy: refusal.remedy
|
|
202
|
-
} : null;
|
|
203
|
-
}
|
|
204
|
-
function isReleaseConfiguration(configuration) {
|
|
205
|
-
return typeof configuration === "string" && configuration.trim() !== "" && configuration.trim().toLowerCase() !== "debug";
|
|
206
|
-
}
|
|
207
|
-
function podAction(podState, verdict) {
|
|
208
|
-
if (verdict?.stale) return {
|
|
209
|
-
install: true,
|
|
210
|
-
reason: verdict.reason
|
|
211
|
-
};
|
|
212
|
-
if (verdict?.noPods && podState?.hasPodfile) return {
|
|
213
|
-
install: true,
|
|
214
|
-
reason: "ios/Podfile exists but no pods are installed"
|
|
215
|
-
};
|
|
216
|
-
return { install: false };
|
|
217
|
-
}
|
|
218
|
-
function xcodeFailureReport(result, logPath) {
|
|
219
|
-
const diagnostics = result.diagnostics;
|
|
220
|
-
const code = result.exitCode;
|
|
221
|
-
const how = code === null ? "" : ` (exit code ${code})`;
|
|
222
|
-
return {
|
|
223
|
-
message: diagnostics.length ? `\`xcodebuild\` failed${how} with ${diagnostics.length} diagnostic${diagnostics.length === 1 ? "" : "s"}.` : `\`xcodebuild\` failed${how} with no recognizable diagnostic.`,
|
|
224
|
-
remedy: diagnostics.find((d) => d?.remedy)?.remedy || `See ${logPath} for the transcript.`
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
function printDiagnostics(note, result) {
|
|
228
|
-
const diagnostics = result.diagnostics;
|
|
229
|
-
const shown = diagnostics.slice(0, MAX_PRINTED_DIAGNOSTICS);
|
|
230
|
-
for (const diagnostic of shown) note(chalk.red(phaseLine("error", describeDiagnostic(diagnostic))));
|
|
231
|
-
const hidden = diagnostics.length - shown.length + result.truncated;
|
|
232
|
-
if (hidden > 0) note(chalk.dim(phaseLine("error", `... and ${hidden} more diagnostic${hidden === 1 ? "" : "s"} in the log`)));
|
|
233
|
-
if (diagnostics.length === 0) {
|
|
234
|
-
note(chalk.red(phaseLine("error", "xcodebuild failed with no recognizable diagnostic; last lines:")));
|
|
235
|
-
for (const line of result.tail.slice(-5)) note(chalk.dim(phaseLine("", line)));
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
125
|
//#endregion
|
|
239
126
|
//#region src/commands/ios/result.ts
|
|
240
|
-
function lastBuildRecord({ fingerprint = null, cacheKey = null, cacheHit = false, cacheSkipped = false, durationMs = 0, appPath = null, bundleId = null, startedAt, status, errorCode = null, missReason = null, diagnostics = null, configuration = null }) {
|
|
127
|
+
function lastBuildRecord({ fingerprint = null, cacheKey = null, cacheHit = false, cacheSkipped = false, durationMs = 0, appPath = null, bundleId = null, startedAt, status, errorCode = null, missReason = null, diagnostics = null, configuration = null, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null }) {
|
|
241
128
|
const record = {
|
|
242
129
|
platform: "ios",
|
|
243
130
|
fingerprint,
|
|
@@ -252,12 +139,16 @@ function lastBuildRecord({ fingerprint = null, cacheKey = null, cacheHit = false
|
|
|
252
139
|
configuration
|
|
253
140
|
};
|
|
254
141
|
if (errorCode) record.errorCode = errorCode;
|
|
142
|
+
record.buildMachine = buildMachine;
|
|
143
|
+
if (builtOn) record.builtOn = builtOn;
|
|
144
|
+
if (offloadedTo) record.offloadedTo = offloadedTo;
|
|
145
|
+
if (offloadFallback) record.offloadFallback = offloadFallback;
|
|
255
146
|
if (missReason && !cacheLevel(cacheHit)) record.missReason = missReason;
|
|
256
147
|
const recorded = status === "failed" ? buildDiagnostics(diagnostics) : [];
|
|
257
148
|
if (recorded.length) record.diagnostics = recorded;
|
|
258
149
|
return record;
|
|
259
150
|
}
|
|
260
|
-
function iosFacts({ slot, udid, deviceName, deviceType = null, runtime = null, fingerprint, configuration = null, scheme = null, cacheKey, cacheHit, cacheSkipped = false, compilationCache = COMPILATION_CACHE_NOT_RUN, waitedForBuild = null, appPath, bundleId, installSkipped = false, metroPort, logsDir, durationMs, launched = true, webPreviewUrl = null, lease, devServer = null }) {
|
|
151
|
+
function iosFacts({ slot, udid, deviceName, deviceType = null, runtime = null, fingerprint, configuration = null, scheme = null, cacheKey, cacheHit, cacheSkipped = false, compilationCache = COMPILATION_CACHE_NOT_RUN, waitedForBuild = null, appPath, bundleId, installSkipped = false, metroPort, logsDir, durationMs, launched = true, webPreviewUrl = null, lease, devServer = null, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null }) {
|
|
261
152
|
return {
|
|
262
153
|
platform: "ios",
|
|
263
154
|
...slot && slot !== "default" ? { slot } : {},
|
|
@@ -271,6 +162,10 @@ function iosFacts({ slot, udid, deviceName, deviceType = null, runtime = null, f
|
|
|
271
162
|
cacheKey,
|
|
272
163
|
cacheHit: cacheLevel(cacheHit),
|
|
273
164
|
cacheSkipped: Boolean(cacheSkipped),
|
|
165
|
+
buildMachine,
|
|
166
|
+
...builtOn ? { builtOn } : {},
|
|
167
|
+
...offloadedTo ? { offloadedTo } : {},
|
|
168
|
+
...offloadFallback ? { offloadFallback } : {},
|
|
274
169
|
compilationCache,
|
|
275
170
|
waitedForBuild: waitedForBuild ? {
|
|
276
171
|
pid: waitedForBuild.pid ?? null,
|
|
@@ -311,13 +206,14 @@ async function finishIosUpload(uploadPending, remote, phase, note) {
|
|
|
311
206
|
}
|
|
312
207
|
return false;
|
|
313
208
|
}
|
|
314
|
-
function reportIosResult({ slot, root, json, release, configuration, buildScheme = null, metroCheck, metroPort, logsDir, device, udid, appPath, bundleId, installSkipped, elapsed, startedAt, storeHash, storeKey, cacheHit, missReason, compilationCache, useBuildCache, waitedForBuild, launchState, launchWarning, providerName, closeWriter, webPreviewUrl, lease, recordRun, reclaimed = [], devServer = null }) {
|
|
209
|
+
function reportIosResult({ slot, root, json, release, configuration, buildScheme = null, metroCheck, metroPort, logsDir, device, udid, appPath, bundleId, installSkipped, elapsed, startedAt, storeHash, storeKey, cacheHit, missReason, compilationCache, useBuildCache, waitedForBuild, launchState, launchWarning, providerName, buildMachine = "auto", builtOn, offloadedTo = null, offloadFallback = null, closeWriter, webPreviewUrl, lease, recordRun, reclaimed = [], devServer = null, links }) {
|
|
315
210
|
const durationMs = elapsed();
|
|
316
211
|
recordRun({
|
|
317
212
|
failed: false,
|
|
318
213
|
cacheHit,
|
|
319
214
|
waited: waitedForBuild,
|
|
320
|
-
durationMs
|
|
215
|
+
durationMs,
|
|
216
|
+
offloadedTo
|
|
321
217
|
});
|
|
322
218
|
writeLastBuild(root, lastBuildRecord({
|
|
323
219
|
fingerprint: storeHash,
|
|
@@ -330,7 +226,11 @@ function reportIosResult({ slot, root, json, release, configuration, buildScheme
|
|
|
330
226
|
bundleId,
|
|
331
227
|
startedAt,
|
|
332
228
|
status: "ok",
|
|
333
|
-
configuration: configuration ?? "Debug"
|
|
229
|
+
configuration: configuration ?? "Debug",
|
|
230
|
+
buildMachine,
|
|
231
|
+
builtOn,
|
|
232
|
+
offloadedTo,
|
|
233
|
+
offloadFallback
|
|
334
234
|
}));
|
|
335
235
|
closeWriter();
|
|
336
236
|
const facts = iosFacts({
|
|
@@ -356,17 +256,22 @@ function reportIosResult({ slot, root, json, release, configuration, buildScheme
|
|
|
356
256
|
launched: launchState,
|
|
357
257
|
webPreviewUrl,
|
|
358
258
|
lease,
|
|
359
|
-
devServer
|
|
259
|
+
devServer,
|
|
260
|
+
buildMachine,
|
|
261
|
+
builtOn,
|
|
262
|
+
offloadedTo,
|
|
263
|
+
offloadFallback
|
|
360
264
|
});
|
|
361
|
-
if (json) console.log(JSON.stringify(
|
|
265
|
+
if (json) console.log(JSON.stringify({
|
|
362
266
|
...facts,
|
|
363
|
-
|
|
364
|
-
|
|
267
|
+
...links ? { links } : {},
|
|
268
|
+
...reclaimed.length ? { reclaimed } : {}
|
|
269
|
+
}));
|
|
365
270
|
else {
|
|
366
|
-
const summary = `${launchWarning ? "WARNING" : "OK"}: ${bundleId} on ${deviceLabel(device, udid)}, ` + (release ? `${configuration} (embedded JS, no Metro)` : `Metro port ${metroPort}`) + ` (${cacheDescription(cacheHit, providerName)}, ${formatDuration(durationMs)})`;
|
|
271
|
+
const summary = `${launchWarning ? "WARNING" : "OK"}: ${bundleId} on ${deviceLabel(device, udid)}, ` + (release ? `${configuration} (embedded JS, no Metro)` : `Metro port ${metroPort}`) + ` (${cacheDescription(cacheHit, providerName, offloadedTo)}, ${formatDuration(durationMs)})`;
|
|
367
272
|
const outcome = launchWarning ? chalk.yellow(`${summary} -- ${launchWarning}`) : launchState === "unverified" ? chalk.yellow(`${summary} -- launch UNVERIFIED`) : launchState === "bundling" ? chalk.green(`${summary} -- bundle requested, still building`) : chalk.green(summary);
|
|
368
273
|
const deviceName = device?.deviceName ?? device?.name ?? udid;
|
|
369
|
-
const cacheResult = useBuildCache ? cacheDescription(cacheHit, providerName) :
|
|
274
|
+
const cacheResult = useBuildCache ? cacheDescription(cacheHit, providerName, offloadedTo) : `bypassed; ${cacheDescription(false, null, offloadedTo)}`;
|
|
370
275
|
const metroResult = release ? `embedded (${configuration})` : !metroCheck ? `check skipped on port ${metroPort}` : launchState === "unverified" ? `state unverified on port ${metroPort}` : `running on port ${metroPort}${devServer ? ` (started: ${devServer.reason})` : ""}`;
|
|
371
276
|
console.log([
|
|
372
277
|
outcome,
|
|
@@ -378,13 +283,14 @@ function reportIosResult({ slot, root, json, release, configuration, buildScheme
|
|
|
378
283
|
phaseLine("logs", logsDir)
|
|
379
284
|
].join("\n"));
|
|
380
285
|
if (facts.webPreviewUrl) console.error(chalk.dim(`Watch this device: ${facts.webPreviewUrl}`));
|
|
286
|
+
if (links) console.error(chalk.dim(workspaceLinkLine(links)));
|
|
381
287
|
}
|
|
382
288
|
return facts;
|
|
383
289
|
}
|
|
384
|
-
function cacheDescription(cacheHit, providerName = null) {
|
|
290
|
+
function cacheDescription(cacheHit, providerName = null, offloadedTo = null) {
|
|
385
291
|
if (cacheHit === "remote") return `from ${providerName || "the remote cache"}`;
|
|
386
292
|
if (cacheHit === "local") return "from cache";
|
|
387
|
-
return "built";
|
|
293
|
+
return offloadedTo ? `built on ${offloadedTo}` : "built";
|
|
388
294
|
}
|
|
389
295
|
//#endregion
|
|
390
296
|
//#region src/commands/ios/artifact.ts
|
|
@@ -398,15 +304,17 @@ var ArtifactRefusal = class extends Error {
|
|
|
398
304
|
this.failure = failure;
|
|
399
305
|
}
|
|
400
306
|
};
|
|
401
|
-
async function acquireIosArtifact({ root, logFile, udid, remoteDestination, device, configuration, buildScheme, buildProfile, isExpo, optimizations, cache, easBuild, easProfile, maxBuilds, progress }, d) {
|
|
402
|
-
const { phase, note, logWriter, estimates, stats, step } = progress;
|
|
307
|
+
async function acquireIosArtifact({ root, logFile, udid, remoteDestination, simulatorArch, device, configuration, buildScheme, buildProfile, buildMachine = "auto", isExpo, optimizations, cache, easBuild, easProfile, maxBuilds, progress }, d) {
|
|
308
|
+
const { phase, note, logWriter, estimates, stats, step, miss, hit: lateHit, place, waitingOn } = progress;
|
|
403
309
|
const physical = device !== null;
|
|
404
310
|
const keyOptions = {
|
|
405
311
|
scheme: buildScheme,
|
|
406
312
|
...configuration ? { configuration } : {},
|
|
407
313
|
isSimulator: !physical,
|
|
314
|
+
...simulatorArch ? { arch: simulatorArch } : {},
|
|
408
315
|
...buildProfile ? { buildProfile } : {}
|
|
409
316
|
};
|
|
317
|
+
const providerRunOptions = iosProviderRunOptions(configuration, simulatorArch);
|
|
410
318
|
const lanAddress = device?.lanAddress ?? null;
|
|
411
319
|
const metroPort = device?.metroPort ?? null;
|
|
412
320
|
const release = isReleaseConfiguration(configuration);
|
|
@@ -460,6 +368,21 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
460
368
|
let appPath = null;
|
|
461
369
|
let bundleId = null;
|
|
462
370
|
let cacheHit = false;
|
|
371
|
+
let offloadedTo = null;
|
|
372
|
+
let offloadFallback = null;
|
|
373
|
+
let fallbackMachine = null;
|
|
374
|
+
let hereReason = null;
|
|
375
|
+
let builtOn;
|
|
376
|
+
const fallBack = (reason, line = reason) => {
|
|
377
|
+
if (namedBuildMachine(buildMachine)) throw new OffloadRefusal(buildMachine, reason);
|
|
378
|
+
offloadFallback = reason;
|
|
379
|
+
buildFailure = {
|
|
380
|
+
...buildFailure,
|
|
381
|
+
offloadFallback: reason
|
|
382
|
+
};
|
|
383
|
+
phase("build", `${line} -> building here`);
|
|
384
|
+
};
|
|
385
|
+
const openOffload = { choice: null };
|
|
463
386
|
let remote = null;
|
|
464
387
|
let abandonedRemote = false;
|
|
465
388
|
let uploadPending = null;
|
|
@@ -583,7 +506,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
583
506
|
platform: "ios",
|
|
584
507
|
projectRoot: root,
|
|
585
508
|
fingerprintHash: fingerprint,
|
|
586
|
-
runOptions:
|
|
509
|
+
runOptions: providerRunOptions
|
|
587
510
|
});
|
|
588
511
|
if (hit?.appPath) {
|
|
589
512
|
let stored = null;
|
|
@@ -624,6 +547,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
624
547
|
step("wait");
|
|
625
548
|
phase("build", text);
|
|
626
549
|
},
|
|
550
|
+
waitingOn,
|
|
627
551
|
warn: (text) => note(chalk.yellow(phaseLine("build", text))),
|
|
628
552
|
out: note
|
|
629
553
|
});
|
|
@@ -736,32 +660,48 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
736
660
|
}
|
|
737
661
|
}
|
|
738
662
|
}
|
|
739
|
-
function
|
|
740
|
-
if (swapFellBack)
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
663
|
+
function reasonForMiss(rekeyedBy) {
|
|
664
|
+
if (swapFellBack) return {
|
|
665
|
+
reason: skippedMissReason("the cached app could not be reused, so this run built it fresh"),
|
|
666
|
+
diff: null
|
|
667
|
+
};
|
|
668
|
+
if (!useBuildCache) return {
|
|
669
|
+
reason: skippedMissReason(cache.disabledByFlag ? "cache reuse turned off by --no-build-cache" : "cache reuse off in config"),
|
|
670
|
+
diff: null
|
|
671
|
+
};
|
|
672
|
+
const current = {
|
|
673
|
+
hash: storeHash ?? fingerprint,
|
|
674
|
+
sources: storeSources
|
|
675
|
+
};
|
|
676
|
+
const explained = explainBuildMiss({
|
|
677
|
+
root,
|
|
678
|
+
platform: "ios",
|
|
679
|
+
current,
|
|
680
|
+
rekeyedBy,
|
|
681
|
+
baselineDeps: { readState: d.readWorkspaceState }
|
|
682
|
+
});
|
|
683
|
+
return {
|
|
684
|
+
reason: explained.reason,
|
|
685
|
+
diff: explained.previousHash && explained.changedNames.length ? fingerprintDiffRecord({
|
|
756
686
|
changed: explained.changedNames,
|
|
757
687
|
previousHash: explained.previousHash,
|
|
758
688
|
hash: current.hash
|
|
759
|
-
})
|
|
760
|
-
}
|
|
689
|
+
}) : null
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function reportPendingRecheck(prebuild) {
|
|
693
|
+
const pods = d.readPodState(root);
|
|
694
|
+
if ((prebuild === "generate" || prebuild === "regenerate" || podAction(pods, d.podsAreStale(pods.lockText, pods.manifestText)).install) && useBuildCache) miss(reasonForMiss([]).reason, true);
|
|
695
|
+
}
|
|
696
|
+
function explainMiss(rekeyedBy) {
|
|
697
|
+
const explained = reasonForMiss(rekeyedBy);
|
|
698
|
+
missReason = explained.reason;
|
|
699
|
+
if (explained.diff) logWriter().write(explained.diff);
|
|
761
700
|
buildFailure = {
|
|
762
701
|
...buildFailure,
|
|
763
702
|
missReason
|
|
764
703
|
};
|
|
704
|
+
miss(missReason);
|
|
765
705
|
phase("cache", `miss: ${missReason.summary}`);
|
|
766
706
|
if (missReason.kind === "no-baseline") {
|
|
767
707
|
const untracked = untrackedMissLine(d.untrackedNativeFiles({ projectRoot: root }));
|
|
@@ -805,31 +745,194 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
805
745
|
note(chalk.dim(phaseLine("fingerprint", `${shortHash(beforeBuildHash)} -> ${shortHash(storeHash)} (after xcodebuild)`)));
|
|
806
746
|
}
|
|
807
747
|
}
|
|
748
|
+
async function takeBuildSlot() {
|
|
749
|
+
if (!maxBuilds) return;
|
|
750
|
+
try {
|
|
751
|
+
buildSlot = await d.acquireBuildSlot({
|
|
752
|
+
max: maxBuilds,
|
|
753
|
+
root,
|
|
754
|
+
logFile,
|
|
755
|
+
out: note
|
|
756
|
+
});
|
|
757
|
+
} catch (e) {
|
|
758
|
+
const refusal = (0, ownership_claim_exports.claimFailure)(e, "stim ios");
|
|
759
|
+
if (refusal) fail({
|
|
760
|
+
code: refusal.code,
|
|
761
|
+
message: refusal.message,
|
|
762
|
+
remedy: refusal.remedy,
|
|
763
|
+
build: buildFailure
|
|
764
|
+
});
|
|
765
|
+
note(chalk.yellow(phaseLine("build", `could not take a build slot: ${e?.message || e}; building anyway`)));
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
/** Whether this build should leave this Mac, before any machine is asked; null builds here. */
|
|
769
|
+
function placeBuild() {
|
|
770
|
+
const { mode, machines } = buildPlacementCandidates(buildMachine);
|
|
771
|
+
if (machines.length === 0 && !namedBuildMachine(buildMachine) && buildMachine !== "local") return null;
|
|
772
|
+
const runtime = physical || remoteDestination || release ? null : simulatorRuntime(udid);
|
|
773
|
+
const unsupported = physical ? "device builds build here" : remoteDestination ? "--remote builds build here" : release ? `${configuration} builds build here` : !cachePolicy.write ? "the build cache is off" : !runtime ? `the runtime of simulator ${udid} is unknown` : null;
|
|
774
|
+
const here = machineCapacity();
|
|
775
|
+
const placement = offloadPlacement({
|
|
776
|
+
mode,
|
|
777
|
+
machines: machines.length,
|
|
778
|
+
here,
|
|
779
|
+
unsupported,
|
|
780
|
+
selected: buildMachine
|
|
781
|
+
});
|
|
782
|
+
if (!placement.offload) {
|
|
783
|
+
hereReason = placement.reason;
|
|
784
|
+
if (mode !== "off") phase("build", `placement: here (${placement.reason})`);
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
return {
|
|
788
|
+
mode,
|
|
789
|
+
here,
|
|
790
|
+
reason: placement.reason,
|
|
791
|
+
runtime,
|
|
792
|
+
machines
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
/** Asks the paired machines once the post-mutation key is known; null builds here. */
|
|
796
|
+
async function chooseMachine(candidate) {
|
|
797
|
+
const choice = await chooseBuildMachine({
|
|
798
|
+
projectRoot: root,
|
|
799
|
+
target: {
|
|
800
|
+
platform: "ios",
|
|
801
|
+
local: iosToolchain(),
|
|
802
|
+
runtime: candidate.runtime,
|
|
803
|
+
cocoapodsPinned: bundlerPin(root) !== null
|
|
804
|
+
},
|
|
805
|
+
mode: candidate.mode,
|
|
806
|
+
here: candidate.here,
|
|
807
|
+
note: (line) => note(chalk.dim(phaseLine("build", `offload: ${line}`))),
|
|
808
|
+
machines: candidate.machines,
|
|
809
|
+
selected: buildMachine
|
|
810
|
+
});
|
|
811
|
+
if (typeof choice === "string") {
|
|
812
|
+
const only = candidate.machines.length === 1 ? candidate.machines[0].machine : null;
|
|
813
|
+
if (only && choice.startsWith(`${only}: `)) fallbackMachine = only;
|
|
814
|
+
fallBack(choice);
|
|
815
|
+
return null;
|
|
816
|
+
}
|
|
817
|
+
openOffload.choice = choice;
|
|
818
|
+
phase("build", `placement: ${choice.machine} (${candidate.reason}${placementLoad(choice)})`);
|
|
819
|
+
return choice;
|
|
820
|
+
}
|
|
821
|
+
/** Builds on the chosen machine and stores the app under the post-mutation key; false builds here instead unless a machine was named. */
|
|
822
|
+
async function compileElsewhere({ choice, candidate }) {
|
|
823
|
+
const runtime = candidate.runtime;
|
|
824
|
+
if (!storeKey || !storeHash) {
|
|
825
|
+
if (namedBuildMachine(buildMachine)) fallBack("the build fingerprint or cache key is unavailable");
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
const stagingDir = join(workspaceDir(root), "offload", "ios");
|
|
829
|
+
const outcome = await offloadBuild({
|
|
830
|
+
choice,
|
|
831
|
+
expectedFingerprint: storeHash,
|
|
832
|
+
request: {
|
|
833
|
+
platform: "ios",
|
|
834
|
+
runtime,
|
|
835
|
+
configuration,
|
|
836
|
+
scheme: buildScheme ?? null,
|
|
837
|
+
isExpo,
|
|
838
|
+
optimizations
|
|
839
|
+
},
|
|
840
|
+
stagingDir,
|
|
841
|
+
onPhase: (name, msg) => phase(name, remotePhaseText(name, msg, choice.machine)),
|
|
842
|
+
onEnter: (name) => {
|
|
843
|
+
if (name === "compile" || name === "build" || name === "prebuild" || name === "pods") {
|
|
844
|
+
builtOn = choice.machine;
|
|
845
|
+
buildFailure = {
|
|
846
|
+
...buildFailure,
|
|
847
|
+
builtOn
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
place({
|
|
851
|
+
host: choice.machine,
|
|
852
|
+
phase: name
|
|
853
|
+
});
|
|
854
|
+
step(name === "prebuild" || name === "pods" ? name : "compile");
|
|
855
|
+
},
|
|
856
|
+
onRecord: (record) => logWriter().write({
|
|
857
|
+
...record,
|
|
858
|
+
offloadedTo: choice.machine
|
|
859
|
+
}),
|
|
860
|
+
note: (line) => phase("build", line)
|
|
861
|
+
});
|
|
862
|
+
place(null);
|
|
863
|
+
let stored = null;
|
|
864
|
+
let reason = outcome.ok ? null : outcome.reason;
|
|
865
|
+
if (outcome.ok) {
|
|
866
|
+
const settled = await refingerprintAfterMutation({
|
|
867
|
+
projectRoot: root,
|
|
868
|
+
platform: "ios",
|
|
869
|
+
previousHash: storeHash,
|
|
870
|
+
fingerprint: d.fingerprintProject
|
|
871
|
+
});
|
|
872
|
+
if (!settled || settled.moved) reason = "the checkout here changed while it built";
|
|
873
|
+
else try {
|
|
874
|
+
stored = d.storeBuild("ios", storeKey, outcome.artifactPath, {
|
|
875
|
+
sources: storeSources,
|
|
876
|
+
overwrite: !useBuildCache
|
|
877
|
+
});
|
|
878
|
+
} catch (e) {
|
|
879
|
+
reason = `could not store the app: ${e?.message || e}`;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
try {
|
|
883
|
+
rmSync(stagingDir, {
|
|
884
|
+
recursive: true,
|
|
885
|
+
force: true
|
|
886
|
+
});
|
|
887
|
+
} catch {}
|
|
888
|
+
step("compile");
|
|
889
|
+
const prepared = stored ? await installableCachedApp(stored) : null;
|
|
890
|
+
if (!outcome.ok || !prepared) {
|
|
891
|
+
const why = reason ?? "the stored app is not installable";
|
|
892
|
+
fallbackMachine = choice.machine;
|
|
893
|
+
fallBack(`${choice.machine}: ${why}`, `offload failed: ${why}`);
|
|
894
|
+
logWriter().write({
|
|
895
|
+
src: "build",
|
|
896
|
+
level: "warn",
|
|
897
|
+
event: "offload_failed",
|
|
898
|
+
msg: reason,
|
|
899
|
+
machine: choice.machine
|
|
900
|
+
});
|
|
901
|
+
return false;
|
|
902
|
+
}
|
|
903
|
+
const { timings } = outcome;
|
|
904
|
+
appPath = prepared;
|
|
905
|
+
builtOn = outcome.machine;
|
|
906
|
+
offloadedTo = outcome.machine;
|
|
907
|
+
stats.setPlacement({
|
|
908
|
+
decision: "offloaded",
|
|
909
|
+
machine: outcome.machine,
|
|
910
|
+
reason: `${candidate.reason}${placementLoad(choice)}`,
|
|
911
|
+
buildMs: timings.totalMs
|
|
912
|
+
});
|
|
913
|
+
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)}`);
|
|
914
|
+
compilationCache = outcome.compilationCache;
|
|
915
|
+
phase("cache", `compilation cache on ${outcome.machine} ${compilationCacheActivityLine(compilationCache)}`);
|
|
916
|
+
logWriter().write({
|
|
917
|
+
src: "build",
|
|
918
|
+
level: "info",
|
|
919
|
+
event: "offload_done",
|
|
920
|
+
msg: `built on ${outcome.machine}`,
|
|
921
|
+
timings
|
|
922
|
+
});
|
|
923
|
+
return true;
|
|
924
|
+
}
|
|
808
925
|
async function buildArtifact() {
|
|
809
926
|
buildFailure = {
|
|
810
927
|
fingerprint,
|
|
811
928
|
cacheKey,
|
|
812
929
|
cacheHit,
|
|
813
|
-
cacheSkipped: !useBuildCache
|
|
930
|
+
cacheSkipped: !useBuildCache,
|
|
931
|
+
buildMachine
|
|
814
932
|
};
|
|
815
933
|
if (!appPath) {
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
max: maxBuilds,
|
|
819
|
-
root,
|
|
820
|
-
logFile,
|
|
821
|
-
out: note
|
|
822
|
-
});
|
|
823
|
-
} catch (e) {
|
|
824
|
-
const refusal = (0, ownership_claim_exports.claimFailure)(e, "stim ios");
|
|
825
|
-
if (refusal) fail({
|
|
826
|
-
code: refusal.code,
|
|
827
|
-
message: refusal.message,
|
|
828
|
-
remedy: refusal.remedy,
|
|
829
|
-
build: buildFailure
|
|
830
|
-
});
|
|
831
|
-
note(chalk.yellow(phaseLine("build", `could not take a build slot: ${e?.message || e}; building anyway`)));
|
|
832
|
-
}
|
|
934
|
+
const offload = placeBuild();
|
|
935
|
+
if (!offload) await takeBuildSlot();
|
|
833
936
|
const mutatingSteps = [];
|
|
834
937
|
const rekeyedBy = [];
|
|
835
938
|
const prebuild = d.planPrebuild(root, "ios", {
|
|
@@ -841,6 +944,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
841
944
|
...staleNativeDirRefusal("ios"),
|
|
842
945
|
build: buildFailure
|
|
843
946
|
});
|
|
947
|
+
reportPendingRecheck(prebuild);
|
|
844
948
|
if (prebuild === "generate" || prebuild === "regenerate") {
|
|
845
949
|
step("prebuild");
|
|
846
950
|
recordPrebuild(root, "ios", null);
|
|
@@ -871,7 +975,8 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
871
975
|
});
|
|
872
976
|
}
|
|
873
977
|
const podState = d.readPodState(root);
|
|
874
|
-
const
|
|
978
|
+
const verdict = d.podsAreStale(podState.lockText, podState.manifestText);
|
|
979
|
+
const action = podAction(podState, verdict);
|
|
875
980
|
if (action.install) {
|
|
876
981
|
step("pods");
|
|
877
982
|
const result = await d.runPodInstall(root, logWriter(), { estimateMs: estimates().podsMs });
|
|
@@ -927,6 +1032,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
927
1032
|
if (prepared) {
|
|
928
1033
|
appPath = prepared;
|
|
929
1034
|
cacheHit = "local";
|
|
1035
|
+
lateHit();
|
|
930
1036
|
phase("cache", `hit ${shortHash(storeHash)} (post-${mutatingSteps.join("/")} key)`);
|
|
931
1037
|
if (releasedWait) {
|
|
932
1038
|
waitedForBuild = releasedWait.facts;
|
|
@@ -936,15 +1042,40 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
936
1042
|
}
|
|
937
1043
|
}
|
|
938
1044
|
}
|
|
939
|
-
if (!appPath) {
|
|
1045
|
+
if (offload && !appPath) {
|
|
940
1046
|
explainMiss(rekeyedBy);
|
|
941
1047
|
step("compile");
|
|
1048
|
+
if (!storeKey) fallBack("no cache key to store the app under", "offload failed: no cache key to store the app under");
|
|
1049
|
+
const choice = storeKey ? await chooseMachine(offload) : null;
|
|
1050
|
+
if (!choice || !await compileElsewhere({
|
|
1051
|
+
choice,
|
|
1052
|
+
candidate: offload
|
|
1053
|
+
})) await takeBuildSlot();
|
|
1054
|
+
}
|
|
1055
|
+
if (!appPath) {
|
|
1056
|
+
if (!offload) explainMiss(rekeyedBy);
|
|
1057
|
+
step("compile");
|
|
1058
|
+
if (offload) stats.setPlacement({
|
|
1059
|
+
decision: "fell-back",
|
|
1060
|
+
reason: offloadFallback ?? "offload failed",
|
|
1061
|
+
...fallbackMachine ? { machine: fallbackMachine } : {}
|
|
1062
|
+
});
|
|
1063
|
+
else if (hereReason) stats.setPlacement({
|
|
1064
|
+
decision: "here",
|
|
1065
|
+
reason: hereReason
|
|
1066
|
+
});
|
|
1067
|
+
builtOn = "here";
|
|
1068
|
+
buildFailure = {
|
|
1069
|
+
...buildFailure,
|
|
1070
|
+
builtOn
|
|
1071
|
+
};
|
|
942
1072
|
phase("build", `compiling ${configuration || "Debug"} with xcodebuild`);
|
|
943
1073
|
const result = await d.buildIos({
|
|
944
1074
|
root,
|
|
945
1075
|
scheme: buildScheme,
|
|
946
1076
|
udid,
|
|
947
1077
|
destination: remoteDestination ? GENERIC_SIM_DESTINATION : null,
|
|
1078
|
+
arch: remoteDestination ? simulatorArch : null,
|
|
948
1079
|
...physical ? { sdk: IPHONEOS_SDK } : {},
|
|
949
1080
|
logWriter: logWriter(),
|
|
950
1081
|
...configuration ? { configuration } : {},
|
|
@@ -1007,7 +1138,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
1007
1138
|
projectRoot: root,
|
|
1008
1139
|
fingerprintHash: storeHash,
|
|
1009
1140
|
buildPath: appPath,
|
|
1010
|
-
runOptions:
|
|
1141
|
+
runOptions: providerRunOptions
|
|
1011
1142
|
});
|
|
1012
1143
|
}
|
|
1013
1144
|
}
|
|
@@ -1017,8 +1148,11 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
1017
1148
|
await resolveInitialFingerprint();
|
|
1018
1149
|
if (!easBuild) {
|
|
1019
1150
|
remote = await resolveRemoteArtifact();
|
|
1151
|
+
if (!appPath) miss(reasonForMiss([]).reason);
|
|
1020
1152
|
await awaitSharedBuild();
|
|
1021
1153
|
await prepareCachedArtifact();
|
|
1154
|
+
if (appPath) lateHit();
|
|
1155
|
+
else if (swapFellBack) miss(reasonForMiss([]).reason);
|
|
1022
1156
|
await buildArtifact();
|
|
1023
1157
|
}
|
|
1024
1158
|
const artifact = {
|
|
@@ -1031,6 +1165,10 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
1031
1165
|
} : null,
|
|
1032
1166
|
hit: cacheHit,
|
|
1033
1167
|
providerName: remote?.name ?? providerName,
|
|
1168
|
+
buildMachine,
|
|
1169
|
+
...builtOn ? { builtOn } : {},
|
|
1170
|
+
offloadedTo,
|
|
1171
|
+
offloadFallback: offloadedTo ? null : offloadFallback,
|
|
1034
1172
|
readEnabled: useBuildCache,
|
|
1035
1173
|
missReason: cacheHit ? null : missReason,
|
|
1036
1174
|
waitedForBuild,
|
|
@@ -1038,6 +1176,8 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
1038
1176
|
},
|
|
1039
1177
|
failureFields: {
|
|
1040
1178
|
...buildFailure,
|
|
1179
|
+
buildMachine,
|
|
1180
|
+
...builtOn ? { builtOn } : {},
|
|
1041
1181
|
fingerprint: storeHash,
|
|
1042
1182
|
cacheKey: storeKey,
|
|
1043
1183
|
cacheHit,
|
|
@@ -1060,6 +1200,23 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
1060
1200
|
artifact
|
|
1061
1201
|
};
|
|
1062
1202
|
} catch (error) {
|
|
1203
|
+
if (error instanceof OffloadRefusal) {
|
|
1204
|
+
const refusal = error;
|
|
1205
|
+
return {
|
|
1206
|
+
ok: false,
|
|
1207
|
+
failure: {
|
|
1208
|
+
code: refusal.code,
|
|
1209
|
+
message: refusal.message,
|
|
1210
|
+
remedy: refusal.remedy,
|
|
1211
|
+
build: {
|
|
1212
|
+
...buildFailure,
|
|
1213
|
+
buildMachine,
|
|
1214
|
+
...builtOn ? { builtOn } : {}
|
|
1215
|
+
}
|
|
1216
|
+
},
|
|
1217
|
+
compilationCache
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1063
1220
|
if (error instanceof ArtifactRefusal) return {
|
|
1064
1221
|
ok: false,
|
|
1065
1222
|
failure: error.failure,
|
|
@@ -1067,6 +1224,7 @@ async function acquireIosArtifact({ root, logFile, udid, remoteDestination, devi
|
|
|
1067
1224
|
};
|
|
1068
1225
|
throw error;
|
|
1069
1226
|
} finally {
|
|
1227
|
+
if (openOffload.choice) closeOffload(openOffload.choice);
|
|
1070
1228
|
releaseLock();
|
|
1071
1229
|
releaseSlot();
|
|
1072
1230
|
if (!transferred) releaseArtifact();
|
|
@@ -1665,15 +1823,19 @@ async function replaceCollector({ root, slot = "default", udid, bundleId, appNam
|
|
|
1665
1823
|
//#region src/commands/ios/dependencies.ts
|
|
1666
1824
|
const DEFAULT_DEPS = {
|
|
1667
1825
|
resolveEasDevelopmentBuild,
|
|
1668
|
-
findProjectRoot,
|
|
1826
|
+
findProjectRoot: findProjectRoot$1,
|
|
1669
1827
|
resolveSettings,
|
|
1828
|
+
settingsLayers,
|
|
1829
|
+
settingOriginScope,
|
|
1670
1830
|
gitCommonDir,
|
|
1671
1831
|
repoRoot,
|
|
1672
1832
|
detectBundleId,
|
|
1673
1833
|
detectIsExpo,
|
|
1674
1834
|
devClientScheme,
|
|
1835
|
+
devClientTakesDevMenuParams,
|
|
1675
1836
|
getProject,
|
|
1676
1837
|
upsertProject,
|
|
1838
|
+
recordIosSchemeApprovals,
|
|
1677
1839
|
checkDeviceCapacity,
|
|
1678
1840
|
budgetGate,
|
|
1679
1841
|
ensureOwnedDevice,
|
|
@@ -1681,6 +1843,8 @@ const DEFAULT_DEPS = {
|
|
|
1681
1843
|
ensureBooted,
|
|
1682
1844
|
resolveRemoteContext,
|
|
1683
1845
|
remoteIosDeps,
|
|
1846
|
+
readRemoteSimulatorArch,
|
|
1847
|
+
hostSimulatorArch,
|
|
1684
1848
|
ensureMetroReachable,
|
|
1685
1849
|
ensureRemoteBootOwned,
|
|
1686
1850
|
detectProviders,
|
|
@@ -1732,6 +1896,7 @@ const DEFAULT_DEPS = {
|
|
|
1732
1896
|
swapJsBundle,
|
|
1733
1897
|
installIosApp,
|
|
1734
1898
|
clearOtherUserApps,
|
|
1899
|
+
clearIosAppData,
|
|
1735
1900
|
clearIosAdoptionPending,
|
|
1736
1901
|
launchIosApp,
|
|
1737
1902
|
verifyLaunch,
|
|
@@ -1793,9 +1958,12 @@ async function verifyIosRun({ root, slot, appPath, d, release, launched, configu
|
|
|
1793
1958
|
note(chalk.yellow(phaseLine("", "Release readiness was not established. Run `stim logs --errors` for captured crash reports, or `stim logs --source device` for the full device output.")));
|
|
1794
1959
|
return { state: crashes.length || processCheck?.reason === "exited" ? LAUNCH_FATAL : LAUNCH_UNVERIFIED };
|
|
1795
1960
|
}
|
|
1961
|
+
const siblings = metroCheck ? siblingPlatformSlots(root, "ios", slot) : [];
|
|
1796
1962
|
const verification = metroCheck ? await d.verifyLaunch({
|
|
1797
1963
|
requireBundleResponse: true,
|
|
1798
1964
|
slot: launchSlotScope(root, slot),
|
|
1965
|
+
appPid: physical || remoteDevice ? null : launched?.pid,
|
|
1966
|
+
platformShared: siblings.length > 0,
|
|
1799
1967
|
onReadinessPending: () => phase("readiness", "waiting for app readiness (up to 30s after bundle load)"),
|
|
1800
1968
|
logsDir,
|
|
1801
1969
|
since: launchedAt,
|
|
@@ -1860,14 +2028,50 @@ async function verifyIosRun({ root, slot, appPath, d, release, launched, configu
|
|
|
1860
2028
|
note(chalk.dim(phaseLine("", "Nothing to do: `stim logs --source metro` shows the build finishing, usually within a minute.")));
|
|
1861
2029
|
return { state: LAUNCH_BUNDLING };
|
|
1862
2030
|
}
|
|
2031
|
+
return reportUnverified({
|
|
2032
|
+
verification,
|
|
2033
|
+
siblings,
|
|
2034
|
+
slot,
|
|
2035
|
+
phase,
|
|
2036
|
+
note,
|
|
2037
|
+
metroPort,
|
|
2038
|
+
bundleId,
|
|
2039
|
+
udid,
|
|
2040
|
+
scheme,
|
|
2041
|
+
lanAddress,
|
|
2042
|
+
isExpo,
|
|
2043
|
+
remoteDevice,
|
|
2044
|
+
physical,
|
|
2045
|
+
lanOrigin,
|
|
2046
|
+
metroOrigin,
|
|
2047
|
+
logsDir,
|
|
2048
|
+
launchedAt,
|
|
2049
|
+
launched
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
2052
|
+
function reportUnverified({ verification, siblings, slot, phase, note, metroPort, bundleId, udid, scheme, lanAddress, isExpo, remoteDevice, physical, lanOrigin, metroOrigin, logsDir, launchedAt, launched }) {
|
|
2053
|
+
if (verification.unattributed) {
|
|
2054
|
+
const [headline, ...lines] = unattributedLaunchLines({
|
|
2055
|
+
platform: "ios",
|
|
2056
|
+
metroPort,
|
|
2057
|
+
slot,
|
|
2058
|
+
siblings
|
|
2059
|
+
});
|
|
2060
|
+
phase("verify", chalk.yellow(headline));
|
|
2061
|
+
for (const line of lines) note(chalk.yellow(phaseLine("", line)));
|
|
2062
|
+
return {
|
|
2063
|
+
state: LAUNCH_UNVERIFIED,
|
|
2064
|
+
unattributed: true
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
1863
2067
|
phase("verify", chalk.yellow("UNVERIFIED: no bundle request reached this workspace's Metro"));
|
|
1864
2068
|
for (const line of unverifiedLaunchLines({
|
|
1865
2069
|
platform: "ios",
|
|
1866
2070
|
metroPort: metroPort ?? 8081,
|
|
1867
|
-
waitedMs: verification
|
|
2071
|
+
waitedMs: verification.waitedMs,
|
|
1868
2072
|
bundleId,
|
|
1869
2073
|
udid,
|
|
1870
|
-
devClientUrl: scheme ? devClientUrl(scheme, metroPort ?? 8081, lanAddress ?? void 0) : null,
|
|
2074
|
+
devClientUrl: scheme ? launched?.url ?? devClientUrl(scheme, metroPort ?? 8081, lanAddress ?? void 0) : null,
|
|
1871
2075
|
mode: isExpo ? MODE_EXPO : MODE_BARE,
|
|
1872
2076
|
remote: remoteDevice,
|
|
1873
2077
|
physical,
|
|
@@ -1894,20 +2098,30 @@ function installsOverWifi(d, udid, selectedWireless, note) {
|
|
|
1894
2098
|
if (wireless) note(phaseLine("device", `${current?.name ?? udid} is paired over Wi-Fi, so the install and launch go over the network and take longer than over a cable`));
|
|
1895
2099
|
return wireless;
|
|
1896
2100
|
}
|
|
1897
|
-
function cleanAdoptedIosApps({ d,
|
|
2101
|
+
function cleanAdoptedIosApps({ d, udid, bundleId, devClient, phase, note }) {
|
|
1898
2102
|
const swept = d.clearOtherUserApps({
|
|
1899
2103
|
udid,
|
|
1900
2104
|
keep: bundleId
|
|
1901
2105
|
});
|
|
1902
2106
|
if (swept.removed.length) phase("install", `removed ${swept.removed.join(", ")}, left by the previous workspace`);
|
|
1903
2107
|
if (swept.listed && swept.failed.length === 0) {
|
|
1904
|
-
|
|
2108
|
+
if (swept.kept && bundleId) {
|
|
2109
|
+
try {
|
|
2110
|
+
d.clearIosAppData(udid, bundleId, { defaultsPlist: devClient ? IOS_DEV_MENU_OFF_DEFAULTS_PLIST : null });
|
|
2111
|
+
} catch (error) {
|
|
2112
|
+
return `Could not clear the data ${bundleId} kept from the previous workspace: ${String(error?.message || error)}`;
|
|
2113
|
+
}
|
|
2114
|
+
phase("install", `cleared ${bundleId} data left by the previous workspace`);
|
|
2115
|
+
}
|
|
1905
2116
|
return null;
|
|
1906
2117
|
}
|
|
1907
2118
|
if (!swept.listed) return "Could not list apps left by the previous workspace.";
|
|
1908
2119
|
for (const failure of swept.failed) note(chalk.yellow(phaseLine("install", `could not remove ${failure}, left by the previous workspace`)));
|
|
1909
2120
|
return `Could not remove ${swept.failed.join(", ")}, left by the previous workspace.`;
|
|
1910
2121
|
}
|
|
2122
|
+
function installMayBeProven(adopting, parkedCacheKey, storeKey) {
|
|
2123
|
+
return !adopting || !parkedCacheKey || parkedCacheKey === storeKey;
|
|
2124
|
+
}
|
|
1911
2125
|
function resolveRunBundleId(d, root, appPath, bundleId) {
|
|
1912
2126
|
if (!appPath || bundleId) return bundleId;
|
|
1913
2127
|
return d.readBundleId(appPath) || d.detectBundleId(root);
|
|
@@ -1940,7 +2154,7 @@ function launchFailureRemedy(remoteDevice, udid, bundleId, logFile) {
|
|
|
1940
2154
|
}
|
|
1941
2155
|
async function finishIosRun({ artifact, d, root, slot, json, release, configuration, buildScheme, isExpo, metroCheck, metroPort, logsDir, logFile, device, udid, physical, wireless, lanAddress, lanOriginUrl, remoteDevice, bootPromise, bootDuration, fail, phase, note, logWriter, elapsed, startedAt, closeWriter, lease, releaseLease, recordRun, reclaimed, devServer, enterPhase }) {
|
|
1942
2156
|
const { path: appPath, bundleId: initialBundleId, failureFields: buildFailure, cache } = artifact;
|
|
1943
|
-
const { hit: cacheHit, providerName, readEnabled: useBuildCache, missReason, waitedForBuild, compilation: compilationCache } = cache;
|
|
2157
|
+
const { hit: cacheHit, providerName, buildMachine, builtOn, offloadedTo, offloadFallback, readEnabled: useBuildCache, missReason, waitedForBuild, compilation: compilationCache } = cache;
|
|
1944
2158
|
const storeHash = cache.identity?.fingerprint ?? null;
|
|
1945
2159
|
const storeKey = cache.identity?.key ?? null;
|
|
1946
2160
|
const runCommand = nativeRunCommand("ios", slot, {
|
|
@@ -1978,7 +2192,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
1978
2192
|
}
|
|
1979
2193
|
});
|
|
1980
2194
|
if (bundleId) d.upsertProject(root, { bundleId });
|
|
1981
|
-
enterPhase("
|
|
2195
|
+
enterPhase("device");
|
|
1982
2196
|
const booted = await bootPromise;
|
|
1983
2197
|
if (!booted?.ok) return fail({
|
|
1984
2198
|
code: booted?.code || "STIM_NO_DEVICE",
|
|
@@ -1988,11 +2202,12 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
1988
2202
|
const deviceOutcome = physical ? "connected" : `${device?.adopted ? "adopted" : "booted"} ${bootDuration()}`;
|
|
1989
2203
|
phase("device", `${deviceLabel(device, udid)} ${deviceOutcome}`);
|
|
1990
2204
|
const scheme = release ? void 0 : d.devClientScheme(root, appPath);
|
|
2205
|
+
const devMenuParams = d.devClientTakesDevMenuParams(root);
|
|
1991
2206
|
const appName = appNameFromPath(appPath);
|
|
1992
2207
|
const appExecutable = readRunExecutable(d, appPath, note);
|
|
1993
2208
|
const dropSwapDir = artifact.release;
|
|
1994
2209
|
let installSkipped = false;
|
|
1995
|
-
let launched
|
|
2210
|
+
let launched;
|
|
1996
2211
|
let launchedAt = d.now();
|
|
1997
2212
|
if (physical) {
|
|
1998
2213
|
const overWifi = installsOverWifi(d, udid, wireless, note);
|
|
@@ -2003,6 +2218,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2003
2218
|
root,
|
|
2004
2219
|
note
|
|
2005
2220
|
});
|
|
2221
|
+
enterPhase("install");
|
|
2006
2222
|
const installTimer = stepTimer(d.now);
|
|
2007
2223
|
const installed = d.installIosDeviceApp({
|
|
2008
2224
|
udid,
|
|
@@ -2105,9 +2321,9 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2105
2321
|
if (adopting) {
|
|
2106
2322
|
const cleanupFailure = cleanAdoptedIosApps({
|
|
2107
2323
|
d,
|
|
2108
|
-
root,
|
|
2109
2324
|
udid,
|
|
2110
2325
|
bundleId,
|
|
2326
|
+
devClient: Boolean(scheme),
|
|
2111
2327
|
phase,
|
|
2112
2328
|
note
|
|
2113
2329
|
});
|
|
@@ -2122,13 +2338,15 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2122
2338
|
}
|
|
2123
2339
|
});
|
|
2124
2340
|
}
|
|
2341
|
+
enterPhase("install");
|
|
2125
2342
|
const installTimer = stepTimer(d.now);
|
|
2126
2343
|
const installed = d.installIosApp({
|
|
2127
2344
|
udid,
|
|
2128
2345
|
appPath,
|
|
2129
2346
|
bundleId,
|
|
2130
2347
|
devClientScheme: scheme,
|
|
2131
|
-
|
|
2348
|
+
schemeApprovals: device.schemeApprovals,
|
|
2349
|
+
proveInstalled: installMayBeProven(adopting, device?.parkedCacheKey, storeKey)
|
|
2132
2350
|
}, { now: d.now });
|
|
2133
2351
|
if (installed?.failed) return fail({
|
|
2134
2352
|
code: installed.code || "STIM_INSTALL_FAILED",
|
|
@@ -2140,10 +2358,12 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2140
2358
|
bundleId
|
|
2141
2359
|
}
|
|
2142
2360
|
});
|
|
2361
|
+
if (adopting) d.clearIosAdoptionPending(root, slot);
|
|
2143
2362
|
installSkipped = Boolean(installed?.skipped);
|
|
2144
2363
|
const artifactDuration = installed?.artifactDurationMs === void 0 ? installTimer() : `(${formatDuration(installed.artifactDurationMs)})`;
|
|
2145
2364
|
phase("install", installSkipped ? `unchanged (${deviceShortName(device, udid)} already has this build) ${artifactDuration}` : `${basename(appPath)} -> ${deviceLabel(device, udid)} ${artifactDuration}`);
|
|
2146
2365
|
if (!remoteDevice && installed?.devClientPreparationDurationMs !== void 0) phase("install", `dev client prepared (${formatDuration(installed.devClientPreparationDurationMs)})`);
|
|
2366
|
+
if (installed.schemeApprovals) d.recordIosSchemeApprovals(root, udid, installed.schemeApprovals, slot);
|
|
2147
2367
|
dropSwapDir();
|
|
2148
2368
|
if (!remoteDevice) await d.replaceCollector({
|
|
2149
2369
|
root,
|
|
@@ -2175,13 +2395,14 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2175
2395
|
bundleId,
|
|
2176
2396
|
metroPort,
|
|
2177
2397
|
devClientScheme: scheme,
|
|
2398
|
+
devMenuParams,
|
|
2178
2399
|
consolePaths: simulatorConsolePaths({
|
|
2179
2400
|
deviceId: udid,
|
|
2180
2401
|
appId: bundleId,
|
|
2181
2402
|
since: launchedAt
|
|
2182
2403
|
}, true, Boolean(remoteDevice))
|
|
2183
2404
|
});
|
|
2184
|
-
if (launched
|
|
2405
|
+
if (launched.failed) {
|
|
2185
2406
|
printNativeCrashReport({
|
|
2186
2407
|
root,
|
|
2187
2408
|
slot,
|
|
@@ -2202,7 +2423,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2202
2423
|
}
|
|
2203
2424
|
});
|
|
2204
2425
|
}
|
|
2205
|
-
phase("launch", `${bundleId} ${launchTimer()}`);
|
|
2426
|
+
phase("launch", `${bundleId}${restartedAppNote(launched.restartedPid)} ${launchTimer()}`);
|
|
2206
2427
|
}
|
|
2207
2428
|
recordIosReloadTarget({
|
|
2208
2429
|
d,
|
|
@@ -2221,7 +2442,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2221
2442
|
src: "build",
|
|
2222
2443
|
level: "info",
|
|
2223
2444
|
event: "launch",
|
|
2224
|
-
msg: release ? `launched ${bundleId} on ${udid} (${configuration}, embedded JS bundle, no Metro)` : `launched ${bundleId} on ${udid} against Metro ${lanOriginUrl ?? `port ${metroPort}`}` + (launched?.mode === "openurl" || launched?.mode === "payload-url" ? " (expo-dev-client)" : "")
|
|
2445
|
+
msg: release ? `launched ${bundleId} on ${udid} (${configuration}, embedded JS bundle, no Metro)` : `launched ${bundleId} on ${udid} against Metro ${lanOriginUrl ?? `port ${metroPort}`}` + (launched?.mode === "openurl" || launched?.mode === "payload-url" ? " (expo-dev-client)" : "") + restartedAppNote(launched.restartedPid, "; ")
|
|
2225
2446
|
});
|
|
2226
2447
|
if (remoteDevice) logWriter().write({
|
|
2227
2448
|
src: "build",
|
|
@@ -2230,7 +2451,7 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2230
2451
|
msg: `remote session ${udid}: device logs come from agent-device/EAS, so no simctl log stream is attached`
|
|
2231
2452
|
});
|
|
2232
2453
|
if (physical) raiseLeaseFor(release ? RELEASE_VERIFY_WAIT_MS : DEBUG_VERIFY_STEP_MS, false);
|
|
2233
|
-
const { state: launchState, warning: launchWarning } = await verifyIosRun({
|
|
2454
|
+
const { state: launchState, warning: launchWarning, unattributed } = await verifyIosRun({
|
|
2234
2455
|
root,
|
|
2235
2456
|
slot,
|
|
2236
2457
|
appPath,
|
|
@@ -2271,7 +2492,8 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2271
2492
|
release,
|
|
2272
2493
|
bundleId,
|
|
2273
2494
|
configuration,
|
|
2274
|
-
metroPort
|
|
2495
|
+
metroPort,
|
|
2496
|
+
unattributed
|
|
2275
2497
|
}));
|
|
2276
2498
|
const leaseFacts = lease?.facts() ?? null;
|
|
2277
2499
|
releaseLease();
|
|
@@ -2304,12 +2526,20 @@ async function finishIosRun({ artifact, d, root, slot, json, release, configurat
|
|
|
2304
2526
|
launchState,
|
|
2305
2527
|
launchWarning,
|
|
2306
2528
|
providerName,
|
|
2529
|
+
buildMachine,
|
|
2530
|
+
builtOn,
|
|
2531
|
+
offloadedTo,
|
|
2532
|
+
offloadFallback,
|
|
2307
2533
|
closeWriter,
|
|
2308
2534
|
webPreviewUrl: remoteDevice?.webPreviewUrl() ?? null,
|
|
2309
2535
|
lease: physical ? leaseFacts : void 0,
|
|
2310
2536
|
recordRun,
|
|
2311
2537
|
reclaimed,
|
|
2312
|
-
devServer
|
|
2538
|
+
devServer,
|
|
2539
|
+
links: workspaceLinks(root, {
|
|
2540
|
+
platform: "ios",
|
|
2541
|
+
slot
|
|
2542
|
+
})
|
|
2313
2543
|
}),
|
|
2314
2544
|
uploadsAbandoned
|
|
2315
2545
|
};
|
|
@@ -2368,19 +2598,22 @@ async function planIos(opts, d, schemeRefusal) {
|
|
|
2368
2598
|
platform: "ios",
|
|
2369
2599
|
slot,
|
|
2370
2600
|
root,
|
|
2371
|
-
projectKey: statsProjectKey({
|
|
2601
|
+
projectKey: statsProjectKey$1({
|
|
2372
2602
|
root,
|
|
2373
2603
|
commonDir: settingsContext.gitCommonDir,
|
|
2374
2604
|
repoRoot: settingsContext.repoRoot
|
|
2375
2605
|
})
|
|
2376
2606
|
};
|
|
2377
2607
|
const isExpo = d.detectIsExpo(root);
|
|
2608
|
+
const settingsLayersForOrigin = d.settingsLayers(settingsContext);
|
|
2378
2609
|
const modelRefusal = deviceModelRefusal({
|
|
2379
2610
|
slot,
|
|
2380
2611
|
deviceTypeFlag: opts.deviceType,
|
|
2381
2612
|
runtimeFlag: opts.runtime,
|
|
2382
2613
|
deviceType: resolveDeviceType(opts.deviceType, settings),
|
|
2383
2614
|
runtime: resolveRuntime(opts.runtime, settings),
|
|
2615
|
+
deviceTypeOrigin: d.settingOriginScope(settingsLayersForOrigin, "ios.deviceType"),
|
|
2616
|
+
runtimeOrigin: d.settingOriginScope(settingsLayersForOrigin, "ios.runtime"),
|
|
2384
2617
|
physical: false,
|
|
2385
2618
|
remoteBackend: remoteIosSetting(settings),
|
|
2386
2619
|
listRuntimes: d.listIosRuntimes
|
|
@@ -2407,6 +2640,12 @@ async function planIos(opts, d, schemeRefusal) {
|
|
|
2407
2640
|
refusal: eas.missing
|
|
2408
2641
|
}), json);
|
|
2409
2642
|
}
|
|
2643
|
+
const remoteBackend = remoteIosSetting(settings);
|
|
2644
|
+
if (remoteBackend) return refuse({
|
|
2645
|
+
code: "STIM_BAD_ARG",
|
|
2646
|
+
message: `ios.remote routes this workspace's runs to a ${remoteBackend} device, whose architecture --plan cannot read without a session.`,
|
|
2647
|
+
remedy: "Run `stim ios` to build for the remote device, or unset ios.remote to plan the owned simulator."
|
|
2648
|
+
});
|
|
2410
2649
|
const refusal = schemeRefusal(root, opts.scheme, isExpo);
|
|
2411
2650
|
if (refusal) return refuse({
|
|
2412
2651
|
code: refusal.code,
|
|
@@ -2427,10 +2666,17 @@ async function planIos(opts, d, schemeRefusal) {
|
|
|
2427
2666
|
message: `Could not fingerprint ${root}: @expo/fingerprint produced no hash for it.`,
|
|
2428
2667
|
remedy: "Check the project native inputs and the @expo/fingerprint error above, then retry."
|
|
2429
2668
|
});
|
|
2669
|
+
const arch = simulatorBuildArch({
|
|
2670
|
+
physical: false,
|
|
2671
|
+
remoteArch: null,
|
|
2672
|
+
hostArch: d.hostSimulatorArch(),
|
|
2673
|
+
configuration
|
|
2674
|
+
});
|
|
2430
2675
|
const cacheKey = buildCacheKey("ios", fingerprint.hash, {
|
|
2431
2676
|
scheme: opts.scheme,
|
|
2432
2677
|
...configuration ? { configuration } : {},
|
|
2433
2678
|
isSimulator: true,
|
|
2679
|
+
...arch ? { arch } : {},
|
|
2434
2680
|
...buildProfile ? { buildProfile } : {}
|
|
2435
2681
|
});
|
|
2436
2682
|
const plan = await planCachedBuild({
|
|
@@ -2441,7 +2687,7 @@ async function planIos(opts, d, schemeRefusal) {
|
|
|
2441
2687
|
cacheKey,
|
|
2442
2688
|
cachePolicy,
|
|
2443
2689
|
providerConfig: d.resolveCacheProviderConfig(settingsContext),
|
|
2444
|
-
expoRemote: cachePolicy.remote && !buildProfile && !opts.scheme ? { runOptions: configuration
|
|
2690
|
+
expoRemote: cachePolicy.remote && !buildProfile && !opts.scheme ? { runOptions: iosProviderRunOptions(configuration, arch) } : null
|
|
2445
2691
|
}, {
|
|
2446
2692
|
loadCacheProvider: d.loadCacheProvider,
|
|
2447
2693
|
loadProjectProvider: d.loadProjectProvider,
|
|
@@ -2464,7 +2710,7 @@ function iosCommand(program) {
|
|
|
2464
2710
|
registerIos(program);
|
|
2465
2711
|
}
|
|
2466
2712
|
function registerIos(program, deps = {}) {
|
|
2467
|
-
program.command("ios").description("Build (or restore from the fingerprint cache), install and launch this workspace's app on its owned simulator, wired to the reserved Metro port. A Debug run starts the dev server when it is not running.").option("--eas-profile <name>", "Download a matching EAS development build; on a miss, print the build command without running it").option("--slot <name>", "Reusable device slot within this workspace (default: default)", parseDeviceSlotOption).option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--plan", "Predict the next build without building, booting or installing: resolve the fingerprint, check the local then remote cache, and print the expected cache result and duration. Writes no Stim state.").option("--scheme <name>", "Shared Xcode app scheme to build; overrides automatic scheme selection, not the app URL scheme").option("--no-metro-check", "Skip the \"is this workspace's dev server running?\" check: do not start it, and build anyway").option("--no-build-cache", "Build fresh, ignoring cached artifacts (local and the project's build-cache provider); the fresh build still replaces the cache entry").option("--configuration <name>", "Xcode configuration to build (e.g. Release). A non-Debug configuration embeds the JS bundle and skips Metro entirely. Overrides the ios.configuration setting. Default: Debug").option("--device-type <name>", "Simulator model to create this workspace's owned sim as, exactly as `xcrun simctl list devicetypes` names it (e.g. \"iPad Pro 13-inch (M5)\"). Overrides the ios.deviceType setting for this invocation. A model no installed runtime can create refuses with STIM_BAD_ARG and prints the models they do offer.").option("--runtime <version>", "Simulator runtime to create this workspace's owned sim on, as a version (\"18.5\") or a runtime's full name (\"iOS 18.5\"); nothing else matches. Overrides the ios.runtime setting for this invocation. An unknown version refuses with STIM_BAD_ARG and prints the installed runtimes.").option("--simulator-app <app>", "Open the owned simulator in xcode, siniulator, or stim-desktop for this run, overriding the machine iosSimulatorApp setting. Also opens an already running simulator; local simulators only.").option("--device [udid]", "Build the iphoneos slice for a connected iPhone, install it, and launch it, instead of using this workspace's owned simulator. The phone can be cabled or paired over Wi-Fi. With no UDID, the first cabled device this workspace can lease is used, waiting for one that is busy; a Wi-Fi device is used only when no cabled one is connected and ready. In Debug the app is wired to this workspace's Metro over the LAN. Stim never creates, boots, or deletes a physical device.").option("--remote <backend>", "Install and launch on a remote device with proxy or EAS. Builds are local unless --eas-profile selects an existing EAS build.", (value) => {
|
|
2713
|
+
program.command("ios").description("Build (or restore from the fingerprint cache), install and launch this workspace's app on its owned simulator, wired to the reserved Metro port. A Debug run starts the dev server when it is not running.").option("--eas-profile <name>", "Download a matching EAS development build; on a miss, print the build command without running it").option("--slot <name>", "Reusable device slot within this workspace (default: default)", parseDeviceSlotOption).option("--build-machine <value>", "Build on auto, local, or one named machine; a name refuses without fallback", parseBuildMachineOption).option("--json", "Emit the facts as a single JSON line on stdout; every other line goes to stderr").option("--plan", "Predict the next build without building, booting or installing: resolve the fingerprint, check the local then remote cache, and print the expected cache result and duration. Writes no Stim state.").option("--scheme <name>", "Shared Xcode app scheme to build; overrides automatic scheme selection, not the app URL scheme").option("--no-metro-check", "Skip the \"is this workspace's dev server running?\" check: do not start it, and build anyway").option("--no-build-cache", "Build fresh, ignoring cached artifacts (local and the project's build-cache provider); the fresh build still replaces the cache entry").option("--configuration <name>", "Xcode configuration to build (e.g. Release). A non-Debug configuration embeds the JS bundle and skips Metro entirely. Overrides the ios.configuration setting. Default: Debug").option("--device-type <name>", "Simulator model to create this workspace's owned sim as, exactly as `xcrun simctl list devicetypes` names it (e.g. \"iPad Pro 13-inch (M5)\"). Overrides the ios.deviceType setting for this invocation. A model no installed runtime can create refuses with STIM_BAD_ARG and prints the models they do offer.").option("--runtime <version>", "Simulator runtime to create this workspace's owned sim on, as a version (\"18.5\") or a runtime's full name (\"iOS 18.5\"); nothing else matches. Overrides the ios.runtime setting for this invocation. An unknown version refuses with STIM_BAD_ARG and prints the installed runtimes.").option("--simulator-app <app>", "Open the owned simulator in xcode, siniulator, or stim-desktop for this run, overriding the machine iosSimulatorApp setting. Also opens an already running simulator; local simulators only.").option("--device [udid]", "Build the iphoneos slice for a connected iPhone, install it, and launch it, instead of using this workspace's owned simulator. The phone can be cabled or paired over Wi-Fi. With no UDID, the first cabled device this workspace can lease is used, waiting for one that is busy; a Wi-Fi device is used only when no cabled one is connected and ready. In Debug the app is wired to this workspace's Metro over the LAN. Stim never creates, boots, or deletes a physical device.").option("--remote <backend>", "Install and launch on a remote device with proxy or EAS. Builds are local unless --eas-profile selects an existing EAS build.", (value) => {
|
|
2468
2714
|
if (REMOTE_DEVICE_BACKENDS.includes(value)) return value;
|
|
2469
2715
|
throw new InvalidArgumentError(`expected one of: ${REMOTE_DEVICE_BACKENDS.join(", ")}`);
|
|
2470
2716
|
}).option("--wait <seconds>", "How long to wait for another workspace to release the phone it leases, before refusing with STIM_DEVICE_BUSY (default 60, 0 refuses at once). Only with --device.").option("--no-wait", "Install on a phone another workspace leases instead of waiting: this run takes no lease and, when both workspaces build the same app id, the install terminates the holder's running app. Only with --device.").action(async (opts) => {
|
|
@@ -2527,6 +2773,32 @@ function explicitSchemeRefusal(root, scheme, isExpo, d) {
|
|
|
2527
2773
|
if (project.error) return project.error;
|
|
2528
2774
|
return d.resolveScheme(project, { scheme }).error ?? null;
|
|
2529
2775
|
}
|
|
2776
|
+
function resolveIosBuildSetup(flag, settings) {
|
|
2777
|
+
const placement = resolveBuildPlacement(flag);
|
|
2778
|
+
if (placement.failure) return {
|
|
2779
|
+
ok: false,
|
|
2780
|
+
failure: {
|
|
2781
|
+
...placement.failure,
|
|
2782
|
+
setup: true
|
|
2783
|
+
}
|
|
2784
|
+
};
|
|
2785
|
+
try {
|
|
2786
|
+
return {
|
|
2787
|
+
ok: true,
|
|
2788
|
+
buildMachine: placement.selected,
|
|
2789
|
+
optimizations: resolveOptimizations(settings)
|
|
2790
|
+
};
|
|
2791
|
+
} catch (error) {
|
|
2792
|
+
return {
|
|
2793
|
+
ok: false,
|
|
2794
|
+
failure: {
|
|
2795
|
+
code: "STIM_BAD_ARG",
|
|
2796
|
+
message: error.message,
|
|
2797
|
+
remedy: SETTING_SHAPE_REMEDY
|
|
2798
|
+
}
|
|
2799
|
+
};
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2530
2802
|
function iosSlotLogFile(root, slot) {
|
|
2531
2803
|
return slot === "default" ? buildLogFile(root) : join(workspaceLogsDir(root), `build-${deviceSlotFileKey("ios", slot)}.ndjson`);
|
|
2532
2804
|
}
|
|
@@ -2622,7 +2894,13 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2622
2894
|
const logsDir = workspaceLogsDir(root);
|
|
2623
2895
|
const logFile = iosSlotLogFile(root, slot);
|
|
2624
2896
|
let writer = null;
|
|
2625
|
-
const logWriter = () => writer ||= d.createWriter(logFile, {
|
|
2897
|
+
const logWriter = () => writer ||= tapBuildLog(d.createWriter(logFile, {
|
|
2898
|
+
truncate: true,
|
|
2899
|
+
fields: {
|
|
2900
|
+
platform: "ios",
|
|
2901
|
+
slot
|
|
2902
|
+
}
|
|
2903
|
+
}), progress);
|
|
2626
2904
|
let leaseHandle = null;
|
|
2627
2905
|
let stopLeaseSignals = null;
|
|
2628
2906
|
const releaseLease = () => {
|
|
@@ -2642,13 +2920,15 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2642
2920
|
write: (statsRun, at) => d.recordStats(statsRun, at),
|
|
2643
2921
|
now: () => d.now(),
|
|
2644
2922
|
note: (line) => note(chalk.dim(line)),
|
|
2645
|
-
phases: () => progress.durations()
|
|
2923
|
+
phases: () => progress.durations(),
|
|
2924
|
+
deviceSetup: () => progress.deviceSetupKnown()
|
|
2646
2925
|
});
|
|
2647
2926
|
const recordRun = stats.record;
|
|
2648
2927
|
let compilationCache = COMPILATION_CACHE_NOT_RUN;
|
|
2649
2928
|
let reclaimed = [];
|
|
2929
|
+
let buildMachine = "auto";
|
|
2650
2930
|
let builtConfiguration = null;
|
|
2651
|
-
const fail = ({ code, message, remedy = null, lines = [], logPath = null, build = null, lease }) => {
|
|
2931
|
+
const fail = ({ code, message, remedy = null, lines = [], logPath = null, build = null, lease, setup = false }) => {
|
|
2652
2932
|
({code, message, remedy, lines} = cancelledFailure("ios", {
|
|
2653
2933
|
code,
|
|
2654
2934
|
message
|
|
@@ -2664,6 +2944,7 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2664
2944
|
if (remedy) note(chalk.dim(phaseLine("remedy", remedy)));
|
|
2665
2945
|
if (logPath) note(chalk.dim(phaseLine("log", logPath)));
|
|
2666
2946
|
if (build) writeLastBuild(root, lastBuildRecord({
|
|
2947
|
+
buildMachine,
|
|
2667
2948
|
...build,
|
|
2668
2949
|
configuration: builtConfiguration,
|
|
2669
2950
|
startedAt,
|
|
@@ -2672,7 +2953,7 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2672
2953
|
durationMs: elapsed()
|
|
2673
2954
|
}));
|
|
2674
2955
|
note(chalk.red(phaseLine("failed", code)));
|
|
2675
|
-
recordRun({
|
|
2956
|
+
if (!setup) recordRun({
|
|
2676
2957
|
failed: true,
|
|
2677
2958
|
durationMs: elapsed()
|
|
2678
2959
|
});
|
|
@@ -2694,12 +2975,13 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2694
2975
|
gitCommonDir: d.gitCommonDir(root),
|
|
2695
2976
|
repoRoot: settingsRepoRoot
|
|
2696
2977
|
};
|
|
2697
|
-
const projectKey = statsProjectKey({
|
|
2978
|
+
const projectKey = statsProjectKey$1({
|
|
2698
2979
|
root,
|
|
2699
2980
|
commonDir: settingsContext.gitCommonDir,
|
|
2700
2981
|
repoRoot: settingsRepoRoot
|
|
2701
2982
|
});
|
|
2702
2983
|
stats.setProject(projectKey);
|
|
2984
|
+
progress.estimate(projectKey);
|
|
2703
2985
|
let estimatesRead = null;
|
|
2704
2986
|
const estimates = () => estimatesRead ??= d.readEstimates({
|
|
2705
2987
|
projectKey,
|
|
@@ -2713,16 +2995,10 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2713
2995
|
lines: moreShapeErrors,
|
|
2714
2996
|
remedy: SETTING_SHAPE_REMEDY
|
|
2715
2997
|
});
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
}
|
|
2720
|
-
return fail({
|
|
2721
|
-
code: "STIM_BAD_ARG",
|
|
2722
|
-
message: error.message,
|
|
2723
|
-
remedy: SETTING_SHAPE_REMEDY
|
|
2724
|
-
});
|
|
2725
|
-
}
|
|
2998
|
+
const setup = resolveIosBuildSetup(opts.buildMachine, settings);
|
|
2999
|
+
if (!setup.ok) return fail(setup.failure);
|
|
3000
|
+
buildMachine = setup.buildMachine;
|
|
3001
|
+
const { optimizations } = setup;
|
|
2726
3002
|
const buildProfile = optimizationBuildProfile("ios", optimizations);
|
|
2727
3003
|
const cacheProviderConfig = d.resolveCacheProviderConfig(settingsContext);
|
|
2728
3004
|
for (const key of unknownSettingKeys(settings)) note(phaseLine("setting", chalk.yellow(`Warning: setting "${key}" is not read by Stim and will be ignored.`)));
|
|
@@ -2789,12 +3065,15 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2789
3065
|
const viewer = resolveSimulatorAppFlag(opts.simulatorApp, physical, remoteBackend);
|
|
2790
3066
|
if ("refusal" in viewer) return fail(viewer.refusal);
|
|
2791
3067
|
const { simulatorApp } = viewer;
|
|
3068
|
+
const settingsLayersForOrigin = d.settingsLayers(settingsContext);
|
|
2792
3069
|
const modelRefusal = deviceModelRefusal({
|
|
2793
3070
|
slot,
|
|
2794
3071
|
deviceTypeFlag: opts.deviceType,
|
|
2795
3072
|
runtimeFlag: opts.runtime,
|
|
2796
3073
|
deviceType,
|
|
2797
3074
|
runtime,
|
|
3075
|
+
deviceTypeOrigin: d.settingOriginScope(settingsLayersForOrigin, "ios.deviceType"),
|
|
3076
|
+
runtimeOrigin: d.settingOriginScope(settingsLayersForOrigin, "ios.runtime"),
|
|
2798
3077
|
physical,
|
|
2799
3078
|
remoteBackend,
|
|
2800
3079
|
listRuntimes: d.listIosRuntimes
|
|
@@ -2807,11 +3086,13 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2807
3086
|
reclaimed = budget.reclaimed;
|
|
2808
3087
|
if (budget.refusal) return fail(budget.refusal);
|
|
2809
3088
|
let remoteDevice = null;
|
|
3089
|
+
let remoteArch = null;
|
|
2810
3090
|
if (remoteBackend) {
|
|
2811
3091
|
const resolved = await d.resolveRemoteContext({
|
|
2812
3092
|
root,
|
|
2813
3093
|
backend: remoteBackend,
|
|
2814
|
-
easBin: d.resolveEasCliBin(root)?.file ?? null
|
|
3094
|
+
easBin: d.resolveEasCliBin(root)?.file ?? null,
|
|
3095
|
+
deviceType: opts.deviceType?.trim() || null
|
|
2815
3096
|
});
|
|
2816
3097
|
if ("failed" in resolved) return fail({
|
|
2817
3098
|
code: resolved.code ?? "STIM_NO_REMOTE_SESSION",
|
|
@@ -2819,6 +3100,7 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2819
3100
|
remedy: resolved.remedy
|
|
2820
3101
|
});
|
|
2821
3102
|
remoteDevice = d.remoteIosDeps(resolved.ctx);
|
|
3103
|
+
remoteArch = await d.readRemoteSimulatorArch(resolved.ctx.existingDaemon);
|
|
2822
3104
|
d = {
|
|
2823
3105
|
...d,
|
|
2824
3106
|
checkDeviceCapacity: remoteDevice.checkDeviceCapacity,
|
|
@@ -2932,12 +3214,9 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2932
3214
|
out: note
|
|
2933
3215
|
});
|
|
2934
3216
|
} catch (e) {
|
|
2935
|
-
return fail(
|
|
2936
|
-
code: "STIM_NO_DEVICE",
|
|
2937
|
-
message: `Could not ensure an owned iOS simulator: ${e?.message || e}`,
|
|
2938
|
-
remedy: "Run `stim doctor` to check the simulator toolchain, then try again."
|
|
2939
|
-
});
|
|
3217
|
+
return fail(ownedSimFailure(e));
|
|
2940
3218
|
}
|
|
3219
|
+
progress.deviceSetup(didSetUpDevice(device, Boolean(remoteDevice)));
|
|
2941
3220
|
const prepareMs = prepare();
|
|
2942
3221
|
if (device.created || prepareMs >= 2e3) phase("device", `${deviceLabel(device, device.deviceUdid)} ${device.created ? "created" : "prepared"} (${formatDuration(prepareMs)})`);
|
|
2943
3222
|
}
|
|
@@ -2971,9 +3250,18 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2971
3250
|
}
|
|
2972
3251
|
metroPort = gate.port;
|
|
2973
3252
|
devServer = gate.devServer;
|
|
2974
|
-
} else
|
|
2975
|
-
|
|
2976
|
-
|
|
3253
|
+
} else {
|
|
3254
|
+
const pin = metroPortSetting(root);
|
|
3255
|
+
if (pin.error) {
|
|
3256
|
+
fail({
|
|
3257
|
+
code: "STIM_BAD_ARG",
|
|
3258
|
+
message: pin.error,
|
|
3259
|
+
remedy: SETTING_SHAPE_REMEDY
|
|
3260
|
+
});
|
|
3261
|
+
return false;
|
|
3262
|
+
}
|
|
3263
|
+
if (pin.port === null && !metroPort) note(chalk.yellow(`No Metro port is reserved for this workspace; wiring the app to ${DEFAULT_METRO_PORT}.`));
|
|
3264
|
+
metroPort = pin.port ?? metroPort ?? 8081;
|
|
2977
3265
|
}
|
|
2978
3266
|
if (physical && metroPort !== null && !await resolveLanOrigin()) return false;
|
|
2979
3267
|
if (remoteDevice && metroPort !== null) {
|
|
@@ -2983,7 +3271,7 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
2983
3271
|
isExpo,
|
|
2984
3272
|
tunnelMode: tunnelModeSetting(settings) ?? void 0,
|
|
2985
3273
|
publicUrl: publicUrlSetting(settings),
|
|
2986
|
-
available: d.detectProviders(binOnPath)
|
|
3274
|
+
available: d.detectProviders(binOnPath, tunnelModeSetting(settings) ?? "auto")
|
|
2987
3275
|
});
|
|
2988
3276
|
if ("failed" in reachable) {
|
|
2989
3277
|
fail({
|
|
@@ -3062,6 +3350,7 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
3062
3350
|
platform: "ios",
|
|
3063
3351
|
sessionName: ownedSessionName(remoteDevice.ctx.label),
|
|
3064
3352
|
startedAt: new Date(d.now()).toISOString(),
|
|
3353
|
+
deviceType: remoteDevice.ctx.deviceType ?? null,
|
|
3065
3354
|
boot,
|
|
3066
3355
|
createdSessionId: remoteDevice.createdSessionId,
|
|
3067
3356
|
abandonCreatedSession: remoteDevice.abandonCreatedSession,
|
|
@@ -3084,8 +3373,15 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
3084
3373
|
configuration,
|
|
3085
3374
|
buildScheme,
|
|
3086
3375
|
buildProfile,
|
|
3376
|
+
buildMachine,
|
|
3087
3377
|
isExpo,
|
|
3088
3378
|
remoteDestination: Boolean(remoteDevice),
|
|
3379
|
+
simulatorArch: simulatorBuildArch({
|
|
3380
|
+
physical,
|
|
3381
|
+
remoteArch,
|
|
3382
|
+
hostArch: d.hostSimulatorArch(),
|
|
3383
|
+
configuration
|
|
3384
|
+
}),
|
|
3089
3385
|
device: physical ? {
|
|
3090
3386
|
lanAddress,
|
|
3091
3387
|
metroPort,
|
|
@@ -3107,7 +3403,11 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
3107
3403
|
logWriter,
|
|
3108
3404
|
estimates,
|
|
3109
3405
|
stats,
|
|
3110
|
-
step: progress.step
|
|
3406
|
+
step: progress.step,
|
|
3407
|
+
miss: progress.miss,
|
|
3408
|
+
hit: progress.hit,
|
|
3409
|
+
place: progress.place,
|
|
3410
|
+
waitingOn: progress.waitingOn
|
|
3111
3411
|
}
|
|
3112
3412
|
}, d));
|
|
3113
3413
|
if (!acquiredArtifact.ok) {
|
|
@@ -3117,10 +3417,11 @@ async function runIos(opts = {}, overrides = {}, progress = NO_BUILD_PROGRESS) {
|
|
|
3117
3417
|
artifact = acquiredArtifact.artifact;
|
|
3118
3418
|
compilationCache = artifact.cache.compilation;
|
|
3119
3419
|
if (!localBoot) {
|
|
3120
|
-
progress.step("
|
|
3420
|
+
progress.step("device");
|
|
3121
3421
|
udid = await startBoot();
|
|
3122
3422
|
}
|
|
3123
3423
|
if (physicalDevice) {
|
|
3424
|
+
progress.step("device");
|
|
3124
3425
|
const acquired = await d.acquireRunLease({
|
|
3125
3426
|
root,
|
|
3126
3427
|
platform: "ios",
|