stim 1.10.1 → 1.12.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/dist/{build-progress-BXx-ZBe4.mjs → activity-CCZJs__P.mjs} +9 -182
- package/dist/{android-787HhP5w.mjs → android-75Sk2rIR.mjs} +81 -19
- package/dist/{android-Bu4mbDzc.mjs → android-B7X-8H7h.mjs} +426 -106
- package/dist/{android-DPov-fv2.mjs → android-BQiKJYK0.mjs} +1 -1
- package/dist/{android-cas-CITmIeWY.mjs → android-cas-DzLPXiEn.mjs} +7 -7
- package/dist/{app-install-Cfmqr3TQ.mjs → app-install-CsZi0SAT.mjs} +1 -1
- package/dist/{workspaces-wrH6dXfu.mjs → budget-DbzW5VTD.mjs} +651 -32
- package/dist/{dev-client-DExzPiOa.mjs → build-plan-CqntbR7b.mjs} +514 -38
- package/dist/build-progress-h60GPV27.mjs +179 -0
- package/dist/{cache-manifest-Pubfp8wV.mjs → cache-manifest-DWPF4RKJ.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +16 -16
- package/dist/collector-run.mjs +4 -4
- package/dist/{command-output-D5z2_bcF.mjs → command-output-BWCj5Vh-.mjs} +1 -1
- package/dist/{config-BEq0Qw_a.mjs → config-0jCcMM0E.mjs} +10 -1
- package/dist/{dependency-state-r9UesA9a.mjs → dependency-state-DNN0yfx6.mjs} +1 -1
- package/dist/{deps-DP4eWqea.mjs → deps-CO-_7UOm.mjs} +2 -2
- package/dist/{device-Czh5kO8A.mjs → device-9r9xRYDa.mjs} +49 -11
- package/dist/{device-lease-CbEaIk7b.mjs → device-lease-B9LAXIUH.mjs} +55 -55
- package/dist/{device-pool-BBWLAr55.mjs → device-pool-BoezJd-c.mjs} +4 -4
- package/dist/{device-remote-powUHdbK.mjs → device-remote-C0_o-tJH.mjs} +254 -579
- package/dist/{doctor-CmqK1LcQ.mjs → doctor-LfDlbR-N.mjs} +20 -19
- package/dist/{error-diagnostics-xxWKNO3-.mjs → error-diagnostics-CCxjn31V.mjs} +7 -7
- package/dist/{gc-zCDpmdHU.mjs → gc-C4nQFcTX.mjs} +220 -282
- package/dist/{guide-DwmaD_Wa.mjs → guide-BPBlh9ML.mjs} +512 -73
- package/dist/{guide-status-CWvti2Lg.mjs → guide-status-i9ogHt4v.mjs} +2 -2
- package/dist/{idle--jn7pBNe.mjs → idle-S3tFZ53_.mjs} +7 -6
- package/dist/{in-use-CNIWU-r-.mjs → in-use-D9XYEgFD.mjs} +7 -7
- package/dist/{ios-CbdqTqOc.mjs → ios-CDzWL1mj.mjs} +302 -88
- package/dist/{ios-COGcGEcN.mjs → ios-CZWOHTTc.mjs} +24 -19
- package/dist/{ios-device-DNjPXBnb.mjs → ios-device-D9cLxVr5.mjs} +1 -1
- package/dist/{launch-verify-BhgkYAws.mjs → launch-verify-B2oR_kFN.mjs} +2 -2
- package/dist/logs-SzuYudOj.mjs +485 -0
- package/dist/merge-state-ytFQCeh4.mjs +262 -0
- package/dist/{metro-BWLOJ_Wr.mjs → metro-Dzo30hvJ.mjs} +1 -1
- package/dist/{named-ports-DiTfSz6p.mjs → named-ports-Dn1o61D9.mjs} +3 -3
- package/dist/{ownership-BfPNRf3-.mjs → ownership-B8d4kXBx.mjs} +49 -16
- package/dist/{ownership-D2xbLVoz.mjs → ownership-Dqnrjrio.mjs} +2 -2
- package/dist/{ports-CLSSFOuz.mjs → ports-Dp_QTwTC.mjs} +3 -3
- package/dist/{project-BXZzOABt.mjs → project-B8rbutVC.mjs} +4 -72
- package/dist/{reload-CymyF6Kk.mjs → reload-nocmx8KB.mjs} +9 -9
- package/dist/remote-cache-BRsRZru5.mjs +526 -0
- package/dist/{server-bare-DVbb7kXH.mjs → server-bare-Gn3ssSdK.mjs} +1 -1
- package/dist/{server-expo-BvOCeakp.mjs → server-expo-CeT1nIIk.mjs} +2 -2
- package/dist/server-expo-eWi9Coof.mjs +2 -0
- package/dist/{settings-DOugPlPz.mjs → settings-BlyDn2Oz.mjs} +14 -5
- package/dist/{settings-EWYNwe72.mjs → settings-bE-Gu3Ti.mjs} +23 -11
- package/dist/settings.schema.json +73 -1
- package/dist/{simslim-DZUxzsjq.mjs → simslim-COtEEP7x.mjs} +152 -96
- package/dist/{slot-launch-Dk4oTREM.mjs → slot-launch-DIACGEfH.mjs} +4 -4
- package/dist/{spawn-claims-CUleC2cM.mjs → spawn-claims-PT8aQpCa.mjs} +25 -2
- package/dist/{start-qWapeB4W.mjs → start-BFstVBlx.mjs} +1 -1
- package/dist/{start-RbmFPeZ7.mjs → start-BboE1HIS.mjs} +108 -17
- package/dist/{state-WGdIbi_d.mjs → state-DcDgzfu3.mjs} +15 -3
- package/dist/{stats-BAgJaLA4.mjs → stats-D8rUTPHd.mjs} +1 -1
- package/dist/{stats-DBYJ5bxL.mjs → stats-DiCtmluY.mjs} +4 -4
- package/dist/{status-Dr4fRkym.mjs → status-BUASYyy_.mjs} +92 -33
- package/dist/{status-Zp8kvexe.mjs → status-DI9Tjo7T.mjs} +255 -38
- package/dist/stim-desktop-D0xhpZt8.mjs +29 -0
- package/dist/stop-BI7QY76M.mjs +3 -0
- package/dist/{stop-DcEv5sk-.mjs → stop-Bn6v-GvS.mjs} +205 -37
- package/dist/supervisor-run.mjs +11 -11
- package/dist/{workspace-process-lock-BXA96myD.mjs → workspace-process-lock-BvvJTfo_.mjs} +10 -5
- package/dist/{worktree-DEG2o9F8.mjs → worktree-B5sTRskL.mjs} +1 -1
- package/dist/{worktree-Bd4dRvx7.mjs → worktree-ChDL5fO1.mjs} +17 -16
- package/dist/{worktree-BlizKDpZ.mjs → worktree-DeBQSVtR.mjs} +3 -1
- package/dist/{xcode-B2tBkf0m.mjs → xcode-BzplpQzc.mjs} +7 -7
- package/package.json +5 -5
- package/dist/budget-nDCEwtJv.mjs +0 -620
- package/dist/logs-MARIy6m9.mjs +0 -209
- package/dist/server-expo-DBVTdult.mjs +0 -2
- package/dist/stop-DI4BG4Os.mjs +0 -3
|
@@ -1,36 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as ownership_claim_exports, B as deviceSlotPlatforms, C as setDevice, E as withConfigLock$1, G as validateDeviceSlot, H as parseDeviceSlotOption, R as deviceSlotFileKey, S as saveConfig, T as upsertProject, _ as loadConfig$1, p as getProject, u as getConcurrencyLimits, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
|
|
2
2
|
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
3
3
|
import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
|
|
4
|
-
import { O as workspaceDir, b as emulatorLogFile, c as signalProcessTree, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState, s as resolveProjectMetro, y as writeWorkspaceState } from "./metro-
|
|
5
|
-
import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BXA96myD.mjs";
|
|
4
|
+
import { O as workspaceDir, b as emulatorLogFile, c as signalProcessTree, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState$1, s as resolveProjectMetro, y as writeWorkspaceState } from "./metro-Dzo30hvJ.mjs";
|
|
5
|
+
import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
|
|
6
|
+
import { i as findProjectRoot, n as appProjectProblem, r as detectIsExpo, s as projectShortcut, t as NO_PROJECT_REFUSAL } from "./project-B8rbutVC.mjs";
|
|
7
|
+
import { m as writeWorkspaceLaunch, n as MODE_EXPO, t as MODE_BARE } from "./state-DcDgzfu3.mjs";
|
|
9
8
|
import { r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
|
|
10
|
-
import { _ as stepTimer, c as launchErrorReport, f as refuseNoProject, g as stepClock, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-
|
|
11
|
-
import { A as resolveBuild, C as
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { a as acquireBuildSlot, s as releaseBuildSlot } from "./in-use-
|
|
17
|
-
import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-
|
|
18
|
-
import { t as cleanLine } from "./server-expo-
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { d as
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import { t as
|
|
26
|
-
import { f as
|
|
27
|
-
import {
|
|
28
|
-
import { a as
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
9
|
+
import { _ as stepTimer, c as launchErrorReport, f as refuseNoProject, g as stepClock, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-BWCj5Vh-.mjs";
|
|
10
|
+
import { A as resolveBuild, C as filesystemBuildCapability, D as providerDownloadPath, E as prepareProviderDownloadDir, F as untrackedNativeFiles, I as assetDiffReason, L as captureAssetManifest, M as storedAssetManifest, O as providerUploadOutcome, P as untrackedMissLine, R as compareAssetManifests, T as fingerprintProject, _ as waitForBuild, b as buildCacheKey, g as releaseBuildLock, j as storeBuild, k as refingerprintAfterMutation, m as acquireBuildLock, v as waitForSharedBuild, w as fingerprintDiffRecord, z as readAssetManifest } from "./device-lease-B9LAXIUH.mjs";
|
|
11
|
+
import { B as pickDefaultSystemImage, D as listAvdDeviceProfiles, E as listAdbDevices, G as resolvePhysicalDevice, H as profileNeedsFoldFeature, J as systemImageSupportsFold, N as ownedAvdDeviceProfile, O as listAvds, P as ownedAvdDirectory, R as ownedAvdSystemImage, S as findBuildTool, U as resetAdoptedAvd, V as probeEmulatorSerial, W as resolveOwnedAvdSerial, X as waitForBoot, a as androidHome, b as emulatorFailureRemedy, c as androidSystemImageAbi, i as androidDeviceAbi, j as memoizeEmulatorProbe, k as listInstalledSystemImages, l as androidToolCwd, o as androidPoolCandidates, r as androidBuildToolName, s as androidPoolNoCandidatesRefusal, t as DEFAULT_AVD_DEVICE_PROFILE, tt as configuredAndroidEmulatorApp, w as hostSystemImageArch, x as extractEmulatorFailure, y as emulatorDiskSpaceRemedy, z as physicalDeviceModel } from "./android-75Sk2rIR.mjs";
|
|
12
|
+
import { A as resolveCacheProviderConfig, E as publicUrlSetting, H as compilerCacheFallbackMessage, I as tunnelModeSetting, L as unknownSettingKeys, M as settingFile, O as remoteAndroidSetting, P as settingShapeErrors, S as metroWarmupUrlSetting, U as optimizationBuildProfile, V as artifactCachePolicy, W as resolveOptimizations, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, j as resolveSettings, r as REMOTE_DEVICE_BACKENDS, s as androidAvdConfigSettingError, u as androidDataPartitionSizeGbSettingError, z as detectProviders } from "./settings-BlyDn2Oz.mjs";
|
|
13
|
+
import { y as parkedMaxSetting } from "./ownership-B8d4kXBx.mjs";
|
|
14
|
+
import { c as startBuildProgress, n as NO_BUILD_PROGRESS } from "./build-progress-h60GPV27.mjs";
|
|
15
|
+
import { a as acquireBuildSlot, s as releaseBuildSlot } from "./in-use-D9XYEgFD.mjs";
|
|
16
|
+
import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-Dqnrjrio.mjs";
|
|
17
|
+
import { t as cleanLine } from "./server-expo-CeT1nIIk.mjs";
|
|
18
|
+
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-BRsRZru5.mjs";
|
|
19
|
+
import { F as ownedSessionName, S as withNativeBuildRun, a as ensureMetroReachable, c as remoteAndroidDeps, m as cancelledFailure, n as binOnPath, o as ensureRemoteBootOwned, u as resolveRemoteContext, x as runCancellation } from "./device-remote-C0_o-tJH.mjs";
|
|
20
|
+
import { _ as launchAndroidReleaseApp, d as deviceShellArg, f as installAndroidApp, g as launchAndroidApp, o as androidAppProcess, p as installConflictKind, r as DEFAULT_METRO_PORT, s as androidDevClientUrl, t as ADB_INSTALL_TIMEOUT_MS } from "./app-install-CsZi0SAT.mjs";
|
|
21
|
+
import { a as VERIFY_TIMEOUT_MS, d as verifyLaunch, i as RELEASE_VERIFY_WAIT_MS, l as unverifiedLaunchLines, n as LAUNCH_FATAL, r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING, u as verifyAndroidReleaseLaunch } from "./launch-verify-B2oR_kFN.mjs";
|
|
22
|
+
import { f as isEasBuildFailure, m as resolveEasDevelopmentBuild, o as unknownAndroidDeviceProfileRefusal, p as planEasDevelopmentBuild, r as checkDeviceCapacity, s as unknownAndroidSystemImageRefusal } from "./simslim-COtEEP7x.mjs";
|
|
23
|
+
import { f as spawnEntry, m as detectAppIds, p as detectAndroidPackage, s as startDevServer } from "./start-BboE1HIS.mjs";
|
|
24
|
+
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-BoezJd-c.mjs";
|
|
25
|
+
import { C as ensureDevServer, E as launchOutcomeRecord, O as warmMetro, T as isPhysicalDeviceRequest, _ as staleNativeDirRefusal, a as refusePlan, b as AvdBootError, c as skippedMissReason, f as detectEntryFile, g as runPrebuild, h as recordPrebuild, i as printPlan, l as devClientScheme, m as planPrebuild, n as planFlagRefusal, o as explainBuildMiss, r as planPayload, s as fingerprintErrorMissReason, t as planCachedBuild, u as pickDevClientScheme, v as ensureBooted, w as ensureWorkspaceStorageSafely, x as AvdRecoveryError, y as ensureOwnedDevice } from "./build-plan-CqntbR7b.mjs";
|
|
26
|
+
import { t as budgetGate } from "./budget-DbzW5VTD.mjs";
|
|
27
|
+
import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-D8rUTPHd.mjs";
|
|
28
|
+
import { a as buildAndroid, c as CCACHE_NOT_RUN, f as resolveCcache, l as CCACHE_UNAVAILABLE, n as resolveAndroidCas, o as productFlavorRefusal, p as formatDiagnostic, r as resolveAndroidCompilerCache, s as readProductFlavors, u as ccacheActivityLine } from "./android-cas-DzLPXiEn.mjs";
|
|
29
|
+
import { d as startBuildHeartbeat, f as tailLines, n as HEARTBEAT_INTERVAL_MS } from "./xcode-BzplpQzc.mjs";
|
|
30
|
+
import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-DIACGEfH.mjs";
|
|
31
|
+
import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-CCxjn31V.mjs";
|
|
32
32
|
import { constants, copyFileSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync } from "node:fs";
|
|
33
33
|
import { InvalidArgumentError } from "commander";
|
|
34
|
+
import { LAST_BUILD_KEYS } from "@stim-cli/core/state";
|
|
34
35
|
import { basename, dirname, isAbsolute, join, relative } from "node:path";
|
|
35
36
|
import chalk from "chalk";
|
|
36
37
|
import { createWarnOnce, loadCacheProvider, resolveTieredBuild, storeTieredBuild } from "@stim-cli/cache";
|
|
@@ -436,6 +437,51 @@ function systemImageRefusal({ slot, flag, resolved, physical, remoteBackend, lis
|
|
|
436
437
|
remedy: refusal.remedy
|
|
437
438
|
} : null;
|
|
438
439
|
}
|
|
440
|
+
function resolveDeviceProfile(flag, settings) {
|
|
441
|
+
const fromFlag = typeof flag === "string" && flag.trim() !== "" ? flag.trim() : null;
|
|
442
|
+
const android = settings?.["android"];
|
|
443
|
+
const raw = android && typeof android === "object" && !Array.isArray(android) ? android["deviceProfile"] : void 0;
|
|
444
|
+
return fromFlag || (typeof raw === "string" && raw.trim() !== "" ? raw.trim() : null);
|
|
445
|
+
}
|
|
446
|
+
function deviceProfileRefusal({ flag, resolved, physical, remoteBackend, listProfiles }) {
|
|
447
|
+
if (typeof flag === "string" && flag.trim() === "") return {
|
|
448
|
+
code: "STIM_BAD_ARG",
|
|
449
|
+
message: "--device-profile was given an empty id.",
|
|
450
|
+
remedy: "Pass `--device-profile <id>` with an id `avdmanager list device -c` prints, e.g. \"pixel_fold\"."
|
|
451
|
+
};
|
|
452
|
+
if (physical || remoteBackend || !resolved) return null;
|
|
453
|
+
let profiles;
|
|
454
|
+
try {
|
|
455
|
+
profiles = listProfiles();
|
|
456
|
+
} catch (error) {
|
|
457
|
+
return {
|
|
458
|
+
code: NO_DEVICE,
|
|
459
|
+
message: `Could not list the Android hardware profiles with avdmanager: ${error?.message || error}`,
|
|
460
|
+
remedy: "Check that JAVA_HOME and ANDROID_HOME are set and the SDK command-line tools are installed, then try again."
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
const refusal = unknownAndroidDeviceProfileRefusal(resolved, profiles);
|
|
464
|
+
return refusal ? {
|
|
465
|
+
code: "STIM_BAD_ARG",
|
|
466
|
+
message: refusal.message,
|
|
467
|
+
remedy: refusal.remedy
|
|
468
|
+
} : null;
|
|
469
|
+
}
|
|
470
|
+
function foldableImageRefusal({ profile, image, avdName, images, supportsFold }) {
|
|
471
|
+
if (!profileNeedsFoldFeature(profile) || !image || supportsFold(image)) return null;
|
|
472
|
+
const compatible = pickDefaultSystemImage(images().filter((candidate) => supportsFold(candidate.pkg)))?.pkg;
|
|
473
|
+
const message = `${avdName ? `This workspace's emulator ${avdName} uses device profile ${profile} on ${image}` : `Device profile ${profile} with system image ${image}`}, which the emulator refuses to boot: ${profile} needs a system image with foldable support (SupportPixelFold in its advancedFeatures.ini).`;
|
|
474
|
+
if (!compatible) return {
|
|
475
|
+
code: "STIM_BAD_ARG",
|
|
476
|
+
message,
|
|
477
|
+
remedy: `Install an image with foldable support, e.g. \`sdkmanager "system-images;android-36;google_apis;${hostSystemImageArch()}"\`, then pass it with \`--system-image\`, or pick another \`--device-profile\`.`
|
|
478
|
+
};
|
|
479
|
+
return {
|
|
480
|
+
code: "STIM_BAD_ARG",
|
|
481
|
+
message,
|
|
482
|
+
remedy: avdName ? `Pass \`--system-image "${compatible}"\`: it replaces ${avdName} if that emulator never finished a boot. Otherwise add \`--slot <name>\` to create the foldable beside it.` : `Pass \`--system-image "${compatible}"\` (or set android.systemImage to it), or pick another \`--device-profile\`.`
|
|
483
|
+
};
|
|
484
|
+
}
|
|
439
485
|
function isReleaseVariant(variant) {
|
|
440
486
|
return typeof variant === "string" && /release$/i.test(variant.trim());
|
|
441
487
|
}
|
|
@@ -723,11 +769,16 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
723
769
|
hash = computed?.hash ?? "";
|
|
724
770
|
fingerprintSources = computed?.sources ?? [];
|
|
725
771
|
} catch (err) {
|
|
726
|
-
|
|
772
|
+
const message = String(err?.message || err);
|
|
773
|
+
record.cacheSkipped = !useBuildCache;
|
|
774
|
+
record.missReason = fingerprintErrorMissReason(message);
|
|
775
|
+
phaseFailure = fail$1(NO_FINGERPRINT, `@expo/fingerprint could not fingerprint ${root}: ${message}`, "Fix the @expo/fingerprint error above, then retry.", { lastBuildStatus: true });
|
|
727
776
|
return false;
|
|
728
777
|
}
|
|
729
778
|
if (!hash) {
|
|
730
|
-
|
|
779
|
+
record.cacheSkipped = !useBuildCache;
|
|
780
|
+
record.missReason = fingerprintErrorMissReason("no hash");
|
|
781
|
+
phaseFailure = fail$1(NO_FINGERPRINT, `@expo/fingerprint returned no hash for ${root}, so the build cache cannot be addressed.`, "Check the project native inputs and the @expo/fingerprint error above, then retry.", { lastBuildStatus: true });
|
|
731
782
|
return false;
|
|
732
783
|
}
|
|
733
784
|
record.fingerprint = hash;
|
|
@@ -757,29 +808,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
757
808
|
const cached = found?.tier === "local" ? found.path : null;
|
|
758
809
|
record.cacheHit = cached ? "local" : false;
|
|
759
810
|
record.cacheSkipped = !useBuildCache;
|
|
760
|
-
|
|
761
|
-
let missUntracked = null;
|
|
762
|
-
if (!cached) {
|
|
763
|
-
const lastBuild = readState(root)?.lastBuild ?? null;
|
|
764
|
-
const miss = describeFingerprintMiss({
|
|
765
|
-
platform: PLATFORM,
|
|
766
|
-
current: {
|
|
767
|
-
hash,
|
|
768
|
-
sources: fingerprintSources
|
|
769
|
-
},
|
|
770
|
-
lastBuild
|
|
771
|
-
});
|
|
772
|
-
if (miss) {
|
|
773
|
-
missDiff = fingerprintDiffSuffix(miss.changed);
|
|
774
|
-
writer.write(fingerprintDiffRecord({
|
|
775
|
-
changed: miss.changed,
|
|
776
|
-
previousHash: miss.previousHash,
|
|
777
|
-
hash
|
|
778
|
-
}));
|
|
779
|
-
} else if (useBuildCache) missUntracked = untrackedMissLine(untracked({ projectRoot: root }));
|
|
780
|
-
}
|
|
781
|
-
phase("fingerprint", `${shortHash(hash)} ${cached ? "hit" : "miss"}${useBuildCache ? "" : !requestedBuildCache ? " (--no-build-cache)" : " (cache reuse off in config)"} ${fingerprintTimer()}${missDiff}`);
|
|
782
|
-
if (missUntracked) phase("fingerprint", chalk.dim(missUntracked));
|
|
811
|
+
phase("fingerprint", `${shortHash(hash)} ${cached ? "hit" : "miss"}${useBuildCache ? "" : !requestedBuildCache ? " (--no-build-cache)" : " (cache reuse off in config)"} ${fingerprintTimer()}`);
|
|
783
812
|
if (found?.tier === "provider") {
|
|
784
813
|
record.cacheHit = "remote";
|
|
785
814
|
providerName = found.providerName ?? null;
|
|
@@ -909,6 +938,34 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
909
938
|
}
|
|
910
939
|
}
|
|
911
940
|
}
|
|
941
|
+
function explainMiss(rekeyedBy) {
|
|
942
|
+
if (swapFellBack) record.missReason = skippedMissReason("the cached APK could not be reused, so this run built it fresh");
|
|
943
|
+
else if (!useBuildCache) record.missReason = skippedMissReason(requestedBuildCache ? "cache reuse off in config" : "cache reuse turned off by --no-build-cache");
|
|
944
|
+
else {
|
|
945
|
+
const current = {
|
|
946
|
+
hash: storeHash,
|
|
947
|
+
sources: storeSources
|
|
948
|
+
};
|
|
949
|
+
const explained = explainBuildMiss({
|
|
950
|
+
root,
|
|
951
|
+
platform: PLATFORM,
|
|
952
|
+
current,
|
|
953
|
+
rekeyedBy,
|
|
954
|
+
baselineDeps: { readState }
|
|
955
|
+
});
|
|
956
|
+
record.missReason = explained.reason;
|
|
957
|
+
if (explained.previousHash && explained.changedNames.length) writer.write(fingerprintDiffRecord({
|
|
958
|
+
changed: explained.changedNames,
|
|
959
|
+
previousHash: explained.previousHash,
|
|
960
|
+
hash: current.hash
|
|
961
|
+
}));
|
|
962
|
+
}
|
|
963
|
+
phase("cache", `miss: ${record.missReason.summary}`);
|
|
964
|
+
if (record.missReason.kind === "no-baseline") {
|
|
965
|
+
const line = untrackedMissLine(untracked({ projectRoot: root }));
|
|
966
|
+
if (line) phase("fingerprint", chalk.dim(line));
|
|
967
|
+
}
|
|
968
|
+
}
|
|
912
969
|
async function buildArtifact() {
|
|
913
970
|
if (!apkPath) try {
|
|
914
971
|
if (maxBuilds) try {
|
|
@@ -926,6 +983,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
926
983
|
}
|
|
927
984
|
phase("build", chalk.yellow(`could not take a build slot: ${err?.message || err}; building anyway`));
|
|
928
985
|
}
|
|
986
|
+
const rekeyedBy = [];
|
|
929
987
|
const prebuildPlan = planPrebuildFor(root, PLATFORM, {
|
|
930
988
|
isExpo,
|
|
931
989
|
fingerprint: hash,
|
|
@@ -962,6 +1020,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
962
1020
|
});
|
|
963
1021
|
if (after) recordPrebuild(root, PLATFORM, after.hash);
|
|
964
1022
|
if (after?.moved) {
|
|
1023
|
+
rekeyedBy.push("prebuild");
|
|
965
1024
|
storeHash = after.hash;
|
|
966
1025
|
storeSources = after.sources;
|
|
967
1026
|
storeKey = buildCacheKey(PLATFORM, after.hash, buildRunOptions);
|
|
@@ -984,6 +1043,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
|
|
|
984
1043
|
}
|
|
985
1044
|
}
|
|
986
1045
|
if (!apkPath) {
|
|
1046
|
+
explainMiss(rekeyedBy);
|
|
987
1047
|
step("compile");
|
|
988
1048
|
phase("build", `compiling ${variant || "debug"} with Gradle`);
|
|
989
1049
|
const built = await build({
|
|
@@ -1115,7 +1175,7 @@ function tail(lines, n = FALLBACK_LINES) {
|
|
|
1115
1175
|
}
|
|
1116
1176
|
//#endregion
|
|
1117
1177
|
//#region src/commands/android/result.ts
|
|
1118
|
-
function androidFacts({ slot, serial, avdName = null, deviceName = null, systemImage = null, fingerprint, cacheKey = null, variant = null, metroPort = null, cacheHit, cacheSkipped = false, waitedForBuild = null, appPath, bundleId, installSkipped = false, launched, ccache = CCACHE_UNAVAILABLE, logs, debugHttpHost = null, debugHttpHostNote = null, devClientUrl = null, durationMs, lease, devServer = null }) {
|
|
1178
|
+
function androidFacts({ slot, serial, avdName = null, deviceName = null, systemImage = null, deviceProfile = null, fingerprint, cacheKey = null, variant = null, metroPort = null, cacheHit, cacheSkipped = false, waitedForBuild = null, appPath, bundleId, installSkipped = false, launched, ccache = CCACHE_UNAVAILABLE, logs, debugHttpHost = null, debugHttpHostNote = null, devClientUrl = null, durationMs, lease, devServer = null }) {
|
|
1119
1179
|
return {
|
|
1120
1180
|
platform: PLATFORM,
|
|
1121
1181
|
...slot && slot !== "default" ? { slot } : {},
|
|
@@ -1123,6 +1183,7 @@ function androidFacts({ slot, serial, avdName = null, deviceName = null, systemI
|
|
|
1123
1183
|
avdName: avdName ?? null,
|
|
1124
1184
|
deviceName: deviceName ?? avdName ?? null,
|
|
1125
1185
|
systemImage: systemImage ?? null,
|
|
1186
|
+
deviceProfile: deviceProfile ?? null,
|
|
1126
1187
|
fingerprint: fingerprint ?? null,
|
|
1127
1188
|
cacheKey: cacheKey ?? null,
|
|
1128
1189
|
variant: variant ?? null,
|
|
@@ -1147,7 +1208,7 @@ function androidFacts({ slot, serial, avdName = null, deviceName = null, systemI
|
|
|
1147
1208
|
...devServer ? { devServer } : {}
|
|
1148
1209
|
};
|
|
1149
1210
|
}
|
|
1150
|
-
function lastBuildRecord({ fingerprint, cacheKey, cacheHit, cacheSkipped = false, durationMs, appPath, bundleId, startedAt, status, errorCode = null, avdName = null, deviceName = null }) {
|
|
1211
|
+
function lastBuildRecord({ fingerprint, cacheKey, cacheHit, cacheSkipped = false, durationMs, appPath, bundleId, startedAt, status, errorCode = null, avdName = null, deviceName = null, missReason = null }) {
|
|
1151
1212
|
const record = {
|
|
1152
1213
|
platform: PLATFORM,
|
|
1153
1214
|
avdName: avdName ?? null,
|
|
@@ -1163,6 +1224,7 @@ function lastBuildRecord({ fingerprint, cacheKey, cacheHit, cacheSkipped = false
|
|
|
1163
1224
|
status
|
|
1164
1225
|
};
|
|
1165
1226
|
if (errorCode) record.errorCode = errorCode;
|
|
1227
|
+
if (missReason && !cacheLevel(cacheHit)) record.missReason = missReason;
|
|
1166
1228
|
return record;
|
|
1167
1229
|
}
|
|
1168
1230
|
async function finishAndroidUpload(uploadPending, remote, phase) {
|
|
@@ -1195,6 +1257,7 @@ function reportAndroidResult({ slot, json, useBuildCache, variant, release, metr
|
|
|
1195
1257
|
avdName: record.avdName,
|
|
1196
1258
|
deviceName: record.deviceName,
|
|
1197
1259
|
systemImage: record.systemImage,
|
|
1260
|
+
deviceProfile: record.deviceProfile,
|
|
1198
1261
|
debugHttpHost: launched.debugHttpHost ?? null,
|
|
1199
1262
|
debugHttpHostNote: launched.debugHttpHostNote ?? null,
|
|
1200
1263
|
devClientUrl: launched.devClientUrl ?? null,
|
|
@@ -1252,7 +1315,10 @@ function persistLastBuild({ writeState, root, record, startedAt, durationMs, sta
|
|
|
1252
1315
|
errorCode
|
|
1253
1316
|
});
|
|
1254
1317
|
try {
|
|
1255
|
-
writeState(root, {
|
|
1318
|
+
writeState(root, {
|
|
1319
|
+
lastBuild,
|
|
1320
|
+
[LAST_BUILD_KEYS[PLATFORM]]: lastBuild
|
|
1321
|
+
});
|
|
1256
1322
|
} catch (err) {
|
|
1257
1323
|
out(phaseLine("state", chalk.yellow(`could not record lastBuild: ${err?.message || err}`)));
|
|
1258
1324
|
}
|
|
@@ -1471,8 +1537,8 @@ async function resolveInstallSerial({ root, slot, device, physical, remoteDevice
|
|
|
1471
1537
|
phase("device", `reopen agent-device on ${resolved.serial}`);
|
|
1472
1538
|
}
|
|
1473
1539
|
const consolePort = Number(resolved.serial.replace(/^emulator-/, ""));
|
|
1474
|
-
withConfigLock(() => {
|
|
1475
|
-
const current = deviceSlotPlatforms(loadConfig()?.projects?.[root], slot)?.android;
|
|
1540
|
+
withConfigLock$1(() => {
|
|
1541
|
+
const current = deviceSlotPlatforms(loadConfig$1()?.projects?.[root], slot)?.android;
|
|
1476
1542
|
if (!current?.owned || current.avdName !== device.avdName) throw new Error("The owned emulator assignment changed before installation.");
|
|
1477
1543
|
if (current.consolePort !== consolePort) setDevice(root, PLATFORM, {
|
|
1478
1544
|
...current,
|
|
@@ -1558,8 +1624,8 @@ async function finishAndroidRun({ lease, releaseLease, root, slot, json, metroCh
|
|
|
1558
1624
|
return fail(installed.code || "STIM_INSTALL_FAILED", installed.reason, installRemedy, { lastBuildStatus: true });
|
|
1559
1625
|
}
|
|
1560
1626
|
if (adopting) try {
|
|
1561
|
-
withConfigLock(() => {
|
|
1562
|
-
const config = loadConfig();
|
|
1627
|
+
withConfigLock$1(() => {
|
|
1628
|
+
const config = loadConfig$1();
|
|
1563
1629
|
const current = deviceSlotPlatforms(config?.projects?.[root], slot)?.android;
|
|
1564
1630
|
if (!config || !current || current.avdName !== device.avdName) throw new Error("The adopted emulator assignment changed during installation.");
|
|
1565
1631
|
delete current.adoptionPending;
|
|
@@ -1817,6 +1883,16 @@ function diagnoseBootFailure(booted, logFile, runCommand, physical) {
|
|
|
1817
1883
|
}
|
|
1818
1884
|
//#endregion
|
|
1819
1885
|
//#region src/commands/android/plan.ts
|
|
1886
|
+
function slotOwnedAvd(projectPath, slot) {
|
|
1887
|
+
const android = deviceSlotPlatforms(getProject(projectPath), slot)?.android;
|
|
1888
|
+
if (!android?.owned || !android.avdName || android.setupIncomplete) return null;
|
|
1889
|
+
const systemImage = ownedAvdSystemImage(android.avdName);
|
|
1890
|
+
return systemImage ? {
|
|
1891
|
+
avdName: android.avdName,
|
|
1892
|
+
systemImage,
|
|
1893
|
+
deviceProfile: ownedAvdDeviceProfile(android.avdName)
|
|
1894
|
+
} : null;
|
|
1895
|
+
}
|
|
1820
1896
|
function fail(code, message, remedy, { lines = [] } = {}) {
|
|
1821
1897
|
return {
|
|
1822
1898
|
ok: false,
|
|
@@ -1850,7 +1926,7 @@ function androidCompilerCache({ root, optimizations, settingsContext }) {
|
|
|
1850
1926
|
})}`
|
|
1851
1927
|
};
|
|
1852
1928
|
}
|
|
1853
|
-
function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, variant: variantFlag, systemImage: systemImageFlag, device: deviceFlag, wait: waitFlag, waitConflict, remote: commandRemoteBackend, buildCache: requestedBuildCache }, { warn, resolveCompilerCache = androidCompilerCache, resolveCacheProvider = resolveCacheProviderConfig, validateAvdConfig = androidAvdConfigSettingError, readFlavors = readProductFlavors, detectExpo = detectIsExpo, listSystemImages = listInstalledSystemImages, parkedLimit = parkedMaxSetting }) {
|
|
1929
|
+
function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, variant: variantFlag, systemImage: systemImageFlag, deviceProfile: deviceProfileFlag, device: deviceFlag, wait: waitFlag, waitConflict, remote: commandRemoteBackend, buildCache: requestedBuildCache }, { warn, resolveCompilerCache = androidCompilerCache, resolveCacheProvider = resolveCacheProviderConfig, validateAvdConfig = androidAvdConfigSettingError, readFlavors = readProductFlavors, detectExpo = detectIsExpo, listSystemImages = listInstalledSystemImages, listDeviceProfiles = listAvdDeviceProfiles, parkedLimit = parkedMaxSetting, supportsFold = systemImageSupportsFold, ownedAvd = slotOwnedAvd }) {
|
|
1854
1930
|
const root = settingsContext.projectPath;
|
|
1855
1931
|
const [shapeError, ...moreShapeErrors] = [parkedLimit("android").error, ...settingShapeErrors(settings)].filter((error) => Boolean(error));
|
|
1856
1932
|
if (shapeError) return fail("STIM_BAD_ARG", shapeError, SETTING_SHAPE_REMEDY, { lines: moreShapeErrors });
|
|
@@ -1878,6 +1954,7 @@ function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, va
|
|
|
1878
1954
|
const avdConfigError = validateAvdConfig(settings, root);
|
|
1879
1955
|
if (avdConfigError) return fail("STIM_BAD_ARG", avdConfigError, "Use only documented android.avdConfig keys, or an android.avdConfigFile fragment contained by the app directory.");
|
|
1880
1956
|
const systemImage = resolveSystemImage(systemImageFlag, settings);
|
|
1957
|
+
const deviceProfile = resolveDeviceProfile(deviceProfileFlag, settings);
|
|
1881
1958
|
const variant = easProfile !== void 0 ? "debug" : resolveVariant(variantFlag, settings);
|
|
1882
1959
|
const flavorRefusal = productFlavorRefusal({
|
|
1883
1960
|
flavors: readFlavors(root),
|
|
@@ -1907,6 +1984,29 @@ function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, va
|
|
|
1907
1984
|
listImages: listSystemImages
|
|
1908
1985
|
});
|
|
1909
1986
|
if (imageRefusal) return fail(imageRefusal.code, imageRefusal.message, imageRefusal.remedy);
|
|
1987
|
+
const profileRefusal = deviceProfileRefusal({
|
|
1988
|
+
flag: deviceProfileFlag,
|
|
1989
|
+
resolved: deviceProfile,
|
|
1990
|
+
physical,
|
|
1991
|
+
remoteBackend,
|
|
1992
|
+
listProfiles: listDeviceProfiles
|
|
1993
|
+
});
|
|
1994
|
+
if (profileRefusal) return fail(profileRefusal.code, profileRefusal.message, profileRefusal.remedy);
|
|
1995
|
+
if (!physical && !remoteBackend) {
|
|
1996
|
+
const flagImage = typeof systemImageFlag === "string" && systemImageFlag.trim() ? systemImageFlag.trim() : null;
|
|
1997
|
+
const existing = ownedAvd(root, slot);
|
|
1998
|
+
const profile = deviceProfile ?? existing?.deviceProfile ?? DEFAULT_AVD_DEVICE_PROFILE;
|
|
1999
|
+
const image = () => flagImage ?? existing?.systemImage ?? systemImage ?? pickDefaultSystemImage(listSystemImages())?.pkg ?? null;
|
|
2000
|
+
const checked = profileNeedsFoldFeature(profile) ? image() : null;
|
|
2001
|
+
const foldRefusal = checked !== null && foldableImageRefusal({
|
|
2002
|
+
profile,
|
|
2003
|
+
image: checked,
|
|
2004
|
+
avdName: existing && existing.systemImage === checked && existing.deviceProfile === profile ? existing.avdName : null,
|
|
2005
|
+
images: listSystemImages,
|
|
2006
|
+
supportsFold
|
|
2007
|
+
});
|
|
2008
|
+
if (foldRefusal) return fail(foldRefusal.code, foldRefusal.message, foldRefusal.remedy);
|
|
2009
|
+
}
|
|
1910
2010
|
const target = physical ? {
|
|
1911
2011
|
kind: "physical",
|
|
1912
2012
|
serial: typeof deviceFlag === "string" ? deviceFlag : null,
|
|
@@ -1917,10 +2017,12 @@ function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, va
|
|
|
1917
2017
|
} : remoteBackend ? {
|
|
1918
2018
|
kind: "remote",
|
|
1919
2019
|
backend: remoteBackend,
|
|
1920
|
-
systemImage
|
|
2020
|
+
systemImage,
|
|
2021
|
+
deviceProfile
|
|
1921
2022
|
} : {
|
|
1922
2023
|
kind: "emulator",
|
|
1923
|
-
systemImage
|
|
2024
|
+
systemImage,
|
|
2025
|
+
deviceProfile
|
|
1924
2026
|
};
|
|
1925
2027
|
return {
|
|
1926
2028
|
ok: true,
|
|
@@ -1944,21 +2046,213 @@ function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, va
|
|
|
1944
2046
|
};
|
|
1945
2047
|
}
|
|
1946
2048
|
//#endregion
|
|
2049
|
+
//#region src/commands/android/next-build.ts
|
|
2050
|
+
const DEFAULT_PLAN_DEPS = {
|
|
2051
|
+
findRoot: findProjectRoot,
|
|
2052
|
+
fingerprint: fingerprintProject,
|
|
2053
|
+
listSystemImages: listInstalledSystemImages,
|
|
2054
|
+
avdSystemImage: ownedAvdSystemImage,
|
|
2055
|
+
avdDirectory: ownedAvdDirectory,
|
|
2056
|
+
listAvds,
|
|
2057
|
+
loadCacheProvider,
|
|
2058
|
+
loadProjectProvider,
|
|
2059
|
+
checkEasAuth,
|
|
2060
|
+
resolveRemote,
|
|
2061
|
+
planPrebuild
|
|
2062
|
+
};
|
|
2063
|
+
function note(line) {
|
|
2064
|
+
console.error(line);
|
|
2065
|
+
}
|
|
2066
|
+
function runOnlyFlag(opts) {
|
|
2067
|
+
if (isPhysicalDeviceRequest(opts.device)) return "--device";
|
|
2068
|
+
if (opts.remote) return "--remote";
|
|
2069
|
+
if (opts.wait !== void 0) return opts.wait === false ? "--no-wait" : "--wait";
|
|
2070
|
+
if (opts.metroCheck === false) return "--no-metro-check";
|
|
2071
|
+
return null;
|
|
2072
|
+
}
|
|
2073
|
+
function emulatorImage(root, slot, requested, deps) {
|
|
2074
|
+
const record = deviceSlotPlatforms(getProject(root), slot)?.android;
|
|
2075
|
+
if (record?.avdName && !record.setupIncomplete) {
|
|
2076
|
+
if (record.owned && deps.avdDirectory(record.avdName)) return { systemImage: deps.avdSystemImage(record.avdName) };
|
|
2077
|
+
if (!record.owned && avdListed(record.avdName, deps.listAvds)) return { systemImage: null };
|
|
2078
|
+
}
|
|
2079
|
+
let images;
|
|
2080
|
+
try {
|
|
2081
|
+
images = deps.listSystemImages();
|
|
2082
|
+
} catch (error) {
|
|
2083
|
+
return { refusal: {
|
|
2084
|
+
code: NO_DEVICE,
|
|
2085
|
+
message: `Could not read the installed Android system images: ${error?.message || error}`,
|
|
2086
|
+
remedy: "Check that ANDROID_HOME points at a readable SDK, then try again."
|
|
2087
|
+
} };
|
|
2088
|
+
}
|
|
2089
|
+
const picked = pickDefaultSystemImage(images, requested ? { systemImage: requested } : {});
|
|
2090
|
+
if (picked) return { systemImage: picked.pkg };
|
|
2091
|
+
const arch = hostSystemImageArch();
|
|
2092
|
+
return { refusal: {
|
|
2093
|
+
code: NO_DEVICE,
|
|
2094
|
+
message: `No ${arch} Android system image is installed, so the emulator build's ABI and cache key are unknown.`,
|
|
2095
|
+
remedy: `Install one, e.g.: sdkmanager "system-images;android-36;google_apis;${arch}", then try again.`
|
|
2096
|
+
} };
|
|
2097
|
+
}
|
|
2098
|
+
function avdListed(avdName, list) {
|
|
2099
|
+
try {
|
|
2100
|
+
return list({ timeoutMs: 1e4 }).includes(avdName);
|
|
2101
|
+
} catch {
|
|
2102
|
+
return false;
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
async function planAndroid(opts, overrides = {}) {
|
|
2106
|
+
const deps = {
|
|
2107
|
+
...DEFAULT_PLAN_DEPS,
|
|
2108
|
+
...overrides
|
|
2109
|
+
};
|
|
2110
|
+
const json = Boolean(opts.json);
|
|
2111
|
+
const refuse = (refusal, lines = []) => refusePlan(refusal, json, lines);
|
|
2112
|
+
const flag = runOnlyFlag(opts);
|
|
2113
|
+
if (flag) return refuse(planFlagRefusal(flag));
|
|
2114
|
+
const root = deps.findRoot(process.cwd());
|
|
2115
|
+
if (!root) return refuse(NO_PROJECT_REFUSAL);
|
|
2116
|
+
const projectProblem = appProjectProblem(root);
|
|
2117
|
+
if (projectProblem) return refuse({
|
|
2118
|
+
code: "STIM_NO_PROJECT",
|
|
2119
|
+
...projectProblem
|
|
2120
|
+
});
|
|
2121
|
+
const slot = validateDeviceSlot(opts.slot);
|
|
2122
|
+
const settingsContext = {
|
|
2123
|
+
projectPath: root,
|
|
2124
|
+
gitCommonDir: gitCommonDir(root),
|
|
2125
|
+
repoRoot: repoRoot(root)
|
|
2126
|
+
};
|
|
2127
|
+
const planned = resolveAndroidRunPlan({
|
|
2128
|
+
settings: resolveSettings(settingsContext),
|
|
2129
|
+
settingsContext,
|
|
2130
|
+
slot,
|
|
2131
|
+
easProfile: opts.easProfile,
|
|
2132
|
+
variant: opts.variant ?? null,
|
|
2133
|
+
systemImage: opts.systemImage ?? null,
|
|
2134
|
+
device: null,
|
|
2135
|
+
wait: void 0,
|
|
2136
|
+
waitConflict: false,
|
|
2137
|
+
remote: null,
|
|
2138
|
+
buildCache: opts.buildCache !== false
|
|
2139
|
+
}, {
|
|
2140
|
+
warn: (label, message) => note(phaseLine(label, chalk.yellow(message))),
|
|
2141
|
+
resolveCompilerCache: ({ optimizations }) => ({
|
|
2142
|
+
cas: null,
|
|
2143
|
+
optimizations,
|
|
2144
|
+
warning: null
|
|
2145
|
+
}),
|
|
2146
|
+
listSystemImages: deps.listSystemImages
|
|
2147
|
+
});
|
|
2148
|
+
if (!planned.ok) return refuse(planned, planned.lines);
|
|
2149
|
+
const { build, target, isExpo, cacheProviderConfig } = planned.plan;
|
|
2150
|
+
const planTarget = {
|
|
2151
|
+
platform: PLATFORM,
|
|
2152
|
+
slot,
|
|
2153
|
+
root,
|
|
2154
|
+
projectKey: statsProjectKey({
|
|
2155
|
+
root,
|
|
2156
|
+
commonDir: settingsContext.gitCommonDir,
|
|
2157
|
+
repoRoot: settingsContext.repoRoot
|
|
2158
|
+
})
|
|
2159
|
+
};
|
|
2160
|
+
if (opts.easProfile !== void 0) {
|
|
2161
|
+
const eas = await planEasDevelopmentBuild({
|
|
2162
|
+
root,
|
|
2163
|
+
platform: PLATFORM,
|
|
2164
|
+
profile: opts.easProfile,
|
|
2165
|
+
note,
|
|
2166
|
+
isExpo,
|
|
2167
|
+
selectors: [opts.variant],
|
|
2168
|
+
buildCache: opts.buildCache
|
|
2169
|
+
});
|
|
2170
|
+
if (!eas.ok) return refuse(eas);
|
|
2171
|
+
return printPlan(planPayload(planTarget, {
|
|
2172
|
+
fingerprint: eas.fingerprint,
|
|
2173
|
+
cacheKey: eas.cacheKey,
|
|
2174
|
+
cacheHit: eas.buildId ? "remote" : false,
|
|
2175
|
+
provider: "eas",
|
|
2176
|
+
cacheSkipped: false,
|
|
2177
|
+
prebuild: null,
|
|
2178
|
+
refusal: eas.missing
|
|
2179
|
+
}), json);
|
|
2180
|
+
}
|
|
2181
|
+
if (target.kind !== "emulator") {
|
|
2182
|
+
if (target.kind === "physical") return refuse(planFlagRefusal("--device"));
|
|
2183
|
+
return refuse({
|
|
2184
|
+
code: "STIM_BAD_ARG",
|
|
2185
|
+
message: `android.remote routes this workspace's runs to a ${target.backend} device, whose ABI --plan cannot read without a session.`,
|
|
2186
|
+
remedy: "Run `stim android` to build for the remote device, or unset android.remote to plan the owned emulator."
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
if (build.compilerCache === "cas") return refuse({
|
|
2190
|
+
code: "STIM_BAD_ARG",
|
|
2191
|
+
message: "The experimental Android compiler CAS keys builds by a toolchain Stim sets up, which --plan does not.",
|
|
2192
|
+
remedy: "Run `stim android` to build with the CAS, or set optimizations.android.compilerCache to ccache."
|
|
2193
|
+
});
|
|
2194
|
+
const image = build.targetAbiOnly && !build.release ? emulatorImage(root, slot, target.systemImage, deps) : { systemImage: null };
|
|
2195
|
+
if ("refusal" in image) return refuse(image.refusal);
|
|
2196
|
+
const { abi, runOptions, remoteRunOptions } = androidBuildOptions({
|
|
2197
|
+
release: build.release,
|
|
2198
|
+
physical: false,
|
|
2199
|
+
device: { systemImage: image.systemImage },
|
|
2200
|
+
variant: build.variant,
|
|
2201
|
+
deviceAbi: () => null,
|
|
2202
|
+
buildProfile: build.profile,
|
|
2203
|
+
targetAbiOnly: build.targetAbiOnly
|
|
2204
|
+
});
|
|
2205
|
+
let fingerprint;
|
|
2206
|
+
try {
|
|
2207
|
+
fingerprint = await deps.fingerprint(root, { platform: PLATFORM });
|
|
2208
|
+
} catch (error) {
|
|
2209
|
+
return refuse({
|
|
2210
|
+
code: NO_FINGERPRINT,
|
|
2211
|
+
message: `@expo/fingerprint could not fingerprint ${root}: ${error?.message || error}`,
|
|
2212
|
+
remedy: "Fix the @expo/fingerprint error above, then retry."
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
if (!fingerprint?.hash) return refuse({
|
|
2216
|
+
code: NO_FINGERPRINT,
|
|
2217
|
+
message: `@expo/fingerprint returned no hash for ${root}, so the build cache cannot be addressed.`,
|
|
2218
|
+
remedy: "Check the project native inputs and the @expo/fingerprint error above, then retry."
|
|
2219
|
+
});
|
|
2220
|
+
const plan = await planCachedBuild({
|
|
2221
|
+
...planTarget,
|
|
2222
|
+
isExpo,
|
|
2223
|
+
fingerprint: fingerprint.hash,
|
|
2224
|
+
sources: fingerprint.sources ?? [],
|
|
2225
|
+
cacheKey: buildCacheKey(PLATFORM, fingerprint.hash, runOptions),
|
|
2226
|
+
cachePolicy: build.cache,
|
|
2227
|
+
providerConfig: cacheProviderConfig,
|
|
2228
|
+
expoRemote: abi || build.profile || !build.cache.remote ? null : { runOptions: remoteRunOptions }
|
|
2229
|
+
}, {
|
|
2230
|
+
...deps,
|
|
2231
|
+
note
|
|
2232
|
+
});
|
|
2233
|
+
printPlan(plan, json);
|
|
2234
|
+
}
|
|
2235
|
+
//#endregion
|
|
1947
2236
|
//#region src/commands/android.ts
|
|
1948
2237
|
function androidCommand(program) {
|
|
1949
2238
|
registerAndroid(program);
|
|
1950
2239
|
}
|
|
1951
2240
|
function registerAndroid(program) {
|
|
1952
|
-
program.command("android").description("Build (or install from the shared cache), install and launch this workspace's Android app on its owned emulator, 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("--no-metro-check", "Skip the reserved-port Metro health check and do not start it (the app will load no bundle unless something else serves it)").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("--variant <name>", "Gradle variant to assemble and install (e.g. productionDebug on a flavored project); overrides the android.variant setting. A variant ending in Release embeds the JS bundle and skips Metro entirely. Default: debug").option("--system-image <id>", "Android system image to create this workspace's owned AVD from, as the sdkmanager package id (e.g. \"system-images;android-36;google_apis;arm64-v8a\"). Overrides the android.systemImage setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the installed images.").option("--device [serial]", "Install and launch on a connected physical device instead of this workspace's owned emulator. With no serial, the first connected device this workspace can lease is used. 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) => {
|
|
2241
|
+
program.command("android").description("Build (or install from the shared cache), install and launch this workspace's Android app on its owned emulator, 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("--no-metro-check", "Skip the reserved-port Metro health check and do not start it (the app will load no bundle unless something else serves it)").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("--variant <name>", "Gradle variant to assemble and install (e.g. productionDebug on a flavored project); overrides the android.variant setting. A variant ending in Release embeds the JS bundle and skips Metro entirely. Default: debug").option("--system-image <id>", "Android system image to create this workspace's owned AVD from, as the sdkmanager package id (e.g. \"system-images;android-36;google_apis;arm64-v8a\"). Overrides the android.systemImage setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the installed images.").option("--device-profile <id>", "Hardware profile to create this workspace's owned AVD with, as an `avdmanager list device -c` id (e.g. \"pixel_fold\", \"pixel_tablet\"). Overrides the android.deviceProfile setting for this invocation. An unknown id refuses with STIM_BAD_ARG and prints the available ids.").option("--device [serial]", "Install and launch on a connected physical device instead of this workspace's owned emulator. With no serial, the first connected device this workspace can lease is used. 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) => {
|
|
1953
2242
|
if (REMOTE_DEVICE_BACKENDS.includes(value)) return value;
|
|
1954
2243
|
throw new InvalidArgumentError(`expected one of: ${REMOTE_DEVICE_BACKENDS.join(", ")}`);
|
|
1955
2244
|
}).option("--wait <seconds>", "How long to wait for another workspace to release the device it leases, before refusing with STIM_DEVICE_BUSY (default 60, 0 refuses at once). Only with --device.").option("--no-wait", "Install on a device 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) => {
|
|
2245
|
+
if (opts.plan) return planAndroid(opts);
|
|
1956
2246
|
const root = findProjectRoot(process.cwd());
|
|
1957
2247
|
if (!root) {
|
|
1958
2248
|
refuseNoProject({ json: Boolean(opts.json) });
|
|
1959
2249
|
return;
|
|
1960
2250
|
}
|
|
1961
|
-
if (!(await
|
|
2251
|
+
if (!(await withNativeBuildRun(root, {
|
|
2252
|
+
command: "android",
|
|
2253
|
+
platform: "android",
|
|
2254
|
+
slot: opts.slot ?? "default"
|
|
2255
|
+
}, async (claim) => {
|
|
1962
2256
|
recordWorkspaceUse(root);
|
|
1963
2257
|
const progress = startBuildProgress({
|
|
1964
2258
|
root,
|
|
@@ -1977,6 +2271,7 @@ function registerAndroid(program) {
|
|
|
1977
2271
|
useBuildCache: opts.buildCache !== false,
|
|
1978
2272
|
variant: opts.variant ?? null,
|
|
1979
2273
|
systemImage: opts.systemImage ?? null,
|
|
2274
|
+
deviceProfile: opts.deviceProfile ?? null,
|
|
1980
2275
|
remoteDevice: opts.remote ?? null,
|
|
1981
2276
|
device: opts.device ?? null,
|
|
1982
2277
|
wait: opts.wait,
|
|
@@ -1986,14 +2281,10 @@ function registerAndroid(program) {
|
|
|
1986
2281
|
} finally {
|
|
1987
2282
|
progress.clear();
|
|
1988
2283
|
}
|
|
1989
|
-
}, {
|
|
1990
|
-
external: true,
|
|
1991
|
-
waitMs: 18e5,
|
|
1992
|
-
declareSpawns: true
|
|
1993
|
-
})).ok) process.exit(1);
|
|
2284
|
+
}, { write: (line) => console.error(chalk.dim(phaseLine("lock", line))) })).ok) process.exit(runCancellation() ? 130 : 1);
|
|
1994
2285
|
});
|
|
1995
2286
|
}
|
|
1996
|
-
function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRemoteBackend = null, resolveSettingsFor = resolveSettings, resolveRemoteDeviceContext = resolveRemoteContext, remoteDeviceDeps: makeRemoteDeviceDeps = remoteAndroidDeps, resolveEasBin = resolveEasCliBin, ensureMetroReachable: ensureRemoteMetro = ensureMetroReachable, ensureRemoteBootOwned: ensureRemoteOwned = ensureRemoteBootOwned, detectRemoteProviders = detectProviders, metroCheck = true, useBuildCache = true, easProfile, resolveEasDevelopmentBuild: resolveEasBuild = resolveEasDevelopmentBuild, variant: variantFlag = null, systemImage: systemImageFlag = null, device: deviceFlag = null, wait: waitFlag = void 0, waitConflict = false, acquireLease = acquireRunLease, makeRunLease = runLease, selectPool = selectFromPool, onLeaseSignal = releaseLeaseOnSignal, listDevices = listAdbDevices, deviceModel = physicalDeviceModel, deviceAbi = androidDeviceAbi, isEmulatorDevice = probeEmulatorSerial, readApkPackage = (apkPath) => apkPackage(dumpApkManifest(apkPath)), getLimits = getConcurrencyLimits, checkCapacity = checkDeviceCapacity, acquireSlot = acquireBuildSlot, releaseSlot = releaseBuildSlot, ensureDevice = ensureOwnedDevice, listSystemImages = listInstalledSystemImages, ensureDeviceBooted = ensureBooted, resolveAvdSerial = resolveOwnedAvdSerial, waitForDeviceBoot = waitForBoot, resolveMetro = resolveProjectMetro, warmMetro: prewarmMetro = warmMetro, startServer = startDevServer, readState = readWorkspaceState, pidAlive = pidExists, verifyCollector = verifyCollectorOwnership, verifyLaunched = verifyLaunch, ensureStorage = ensureWorkspaceStorageSafely, fingerprint = fingerprintProject, untracked = untrackedNativeFiles, resolveCached = resolveBuild, storeCached = storeBuild, storedAssets = storedAssetManifest, captureAssets = captureAssetManifest, acquireLock = acquireBuildLock, releaseLock = releaseBuildLock, waitForBuild: waitForBuild$1 = waitForBuild, loadProvider = loadProjectProvider, easAuth = checkEasAuth, resolveRemoteBuild = resolveRemote, uploadRemoteBuild = uploadRemote, resolveCacheProvider = resolveCacheProviderConfig, loadCacheProviderModule = loadCacheProvider, planPrebuildFor = planPrebuild, prebuild = runPrebuild, build = buildAndroid, ccacheFor = resolveCcache, install = installAndroidApp, launch = launchAndroidApp, launchRelease = launchAndroidReleaseApp, verifyReleaseLaunched = verifyAndroidReleaseLaunch, swapApk = swapApkBundle, resolveDevClientScheme = androidDevClientScheme, spawn = (cmd, args, opts) => getExecutor().spawn(cmd, args, opts), kill = (pid, signal) => process.kill(pid, signal), createWriter = createNdjsonWriter, writeLaunch = writeWorkspaceLaunch, writeState = writeWorkspaceState, recordStats = recordRunStats, readEstimates = readRunEstimates, now = Date.now, out = (line) => console.error(line), emit = (line) => console.log(line) } = {}) {
|
|
2287
|
+
function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRemoteBackend = null, resolveSettingsFor = resolveSettings, resolveRemoteDeviceContext = resolveRemoteContext, remoteDeviceDeps: makeRemoteDeviceDeps = remoteAndroidDeps, resolveEasBin = resolveEasCliBin, ensureMetroReachable: ensureRemoteMetro = ensureMetroReachable, ensureRemoteBootOwned: ensureRemoteOwned = ensureRemoteBootOwned, detectRemoteProviders = detectProviders, metroCheck = true, useBuildCache = true, easProfile, resolveEasDevelopmentBuild: resolveEasBuild = resolveEasDevelopmentBuild, variant: variantFlag = null, systemImage: systemImageFlag = null, deviceProfile: deviceProfileFlag, device: deviceFlag = null, wait: waitFlag = void 0, waitConflict = false, acquireLease = acquireRunLease, makeRunLease = runLease, selectPool = selectFromPool, onLeaseSignal = releaseLeaseOnSignal, listDevices = listAdbDevices, deviceModel = physicalDeviceModel, deviceAbi = androidDeviceAbi, isEmulatorDevice = probeEmulatorSerial, readApkPackage = (apkPath) => apkPackage(dumpApkManifest(apkPath)), getLimits = getConcurrencyLimits, checkCapacity = checkDeviceCapacity, acquireSlot = acquireBuildSlot, releaseSlot = releaseBuildSlot, ensureDevice = ensureOwnedDevice, listSystemImages = listInstalledSystemImages, listDeviceProfiles, ensureDeviceBooted = ensureBooted, resolveAvdSerial = resolveOwnedAvdSerial, waitForDeviceBoot = waitForBoot, resolveMetro = resolveProjectMetro, warmMetro: prewarmMetro = warmMetro, startServer = startDevServer, readState = readWorkspaceState$1, pidAlive = pidExists, verifyCollector = verifyCollectorOwnership, verifyLaunched = verifyLaunch, ensureStorage = ensureWorkspaceStorageSafely, fingerprint = fingerprintProject, untracked = untrackedNativeFiles, resolveCached = resolveBuild, storeCached = storeBuild, storedAssets = storedAssetManifest, captureAssets = captureAssetManifest, acquireLock = acquireBuildLock, releaseLock = releaseBuildLock, waitForBuild: waitForBuild$1 = waitForBuild, loadProvider = loadProjectProvider, easAuth = checkEasAuth, resolveRemoteBuild = resolveRemote, uploadRemoteBuild = uploadRemote, resolveCacheProvider = resolveCacheProviderConfig, loadCacheProviderModule = loadCacheProvider, planPrebuildFor = planPrebuild, prebuild = runPrebuild, build = buildAndroid, ccacheFor = resolveCcache, install = installAndroidApp, launch = launchAndroidApp, launchRelease = launchAndroidReleaseApp, verifyReleaseLaunched = verifyAndroidReleaseLaunch, swapApk = swapApkBundle, resolveDevClientScheme = androidDevClientScheme, spawn = (cmd, args, opts) => getExecutor().spawn(cmd, args, opts), kill = (pid, signal) => process.kill(pid, signal), createWriter = createNdjsonWriter, writeLaunch = writeWorkspaceLaunch, writeState = writeWorkspaceState, recordStats = recordRunStats, readEstimates = readRunEstimates, now = Date.now, out = (line) => console.error(line), emit = (line) => console.log(line) } = {}) {
|
|
1997
2288
|
return {
|
|
1998
2289
|
root,
|
|
1999
2290
|
json,
|
|
@@ -2011,6 +2302,7 @@ function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRem
|
|
|
2011
2302
|
resolveEasBuild,
|
|
2012
2303
|
variantFlag,
|
|
2013
2304
|
systemImageFlag,
|
|
2305
|
+
deviceProfileFlag,
|
|
2014
2306
|
deviceFlag,
|
|
2015
2307
|
waitFlag,
|
|
2016
2308
|
waitConflict,
|
|
@@ -2029,6 +2321,7 @@ function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRem
|
|
|
2029
2321
|
releaseSlot,
|
|
2030
2322
|
ensureDevice,
|
|
2031
2323
|
listSystemImages,
|
|
2324
|
+
listDeviceProfiles,
|
|
2032
2325
|
ensureDeviceBooted,
|
|
2033
2326
|
resolveAvdSerial,
|
|
2034
2327
|
waitForDeviceBoot,
|
|
@@ -2130,7 +2423,7 @@ function avdSetupFailure(error, root, logFile) {
|
|
|
2130
2423
|
};
|
|
2131
2424
|
}
|
|
2132
2425
|
async function runAndroid(options = {}) {
|
|
2133
|
-
let { root, json, commandRemoteBackend, resolveSettingsFor, resolveRemoteDeviceContext, makeRemoteDeviceDeps, resolveEasBin, ensureRemoteMetro, ensureRemoteOwned, detectRemoteProviders, metroCheck, useBuildCache: requestedBuildCache, easProfile, resolveEasBuild, variantFlag, systemImageFlag, deviceFlag, waitFlag, waitConflict, acquireLease, makeRunLease, selectPool, onLeaseSignal, listDevices, deviceModel, deviceAbi, isEmulatorDevice, readApkPackage, getLimits, checkCapacity, acquireSlot, releaseSlot, ensureDevice, listSystemImages, ensureDeviceBooted, resolveAvdSerial, waitForDeviceBoot, resolveMetro, prewarmMetro, startServer, readState, pidAlive, verifyCollector, verifyLaunched, ensureStorage, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, resolveCacheProvider, loadCacheProviderModule, planPrebuildFor, prebuild, build, ccacheFor, install, launch, launchRelease, verifyReleaseLaunched, swapApk, resolveDevClientScheme, spawn, kill, createWriter, writeLaunch, writeState, recordStats, readEstimates, now, out, emit } = androidSlotOptions(options);
|
|
2426
|
+
let { root, json, commandRemoteBackend, resolveSettingsFor, resolveRemoteDeviceContext, makeRemoteDeviceDeps, resolveEasBin, ensureRemoteMetro, ensureRemoteOwned, detectRemoteProviders, metroCheck, useBuildCache: requestedBuildCache, easProfile, resolveEasBuild, variantFlag, systemImageFlag, deviceProfileFlag, deviceFlag, waitFlag, waitConflict, acquireLease, makeRunLease, selectPool, onLeaseSignal, listDevices, deviceModel, deviceAbi, isEmulatorDevice, readApkPackage, getLimits, checkCapacity, acquireSlot, releaseSlot, ensureDevice, listSystemImages, listDeviceProfiles, ensureDeviceBooted, resolveAvdSerial, waitForDeviceBoot, resolveMetro, prewarmMetro, startServer, readState, pidAlive, verifyCollector, verifyLaunched, ensureStorage, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, resolveCacheProvider, loadCacheProviderModule, planPrebuildFor, prebuild, build, ccacheFor, install, launch, launchRelease, verifyReleaseLaunched, swapApk, resolveDevClientScheme, spawn, kill, createWriter, writeLaunch, writeState, recordStats, readEstimates, now, out, emit } = androidSlotOptions(options);
|
|
2134
2427
|
const progress = options.progress ?? NO_BUILD_PROGRESS;
|
|
2135
2428
|
const slot = validateDeviceSlot(options.slot);
|
|
2136
2429
|
const started = now();
|
|
@@ -2203,6 +2496,11 @@ async function runAndroid(options = {}) {
|
|
|
2203
2496
|
let ccacheActivity = CCACHE_NOT_RUN;
|
|
2204
2497
|
let reclaimed = [];
|
|
2205
2498
|
const fail = (code, message, remedy, { lastBuildStatus = false, diagnostics = [], lines = [], logPath = null, lease } = {}) => {
|
|
2499
|
+
const cancellation = cancelledFailure(PLATFORM, {
|
|
2500
|
+
code,
|
|
2501
|
+
message
|
|
2502
|
+
});
|
|
2503
|
+
if (cancellation) ({code, message, remedy, lines} = cancellation);
|
|
2206
2504
|
if (lastBuildStatus) persistLastBuild({
|
|
2207
2505
|
writeState,
|
|
2208
2506
|
root,
|
|
@@ -2266,6 +2564,7 @@ async function runAndroid(options = {}) {
|
|
|
2266
2564
|
easProfile,
|
|
2267
2565
|
variant: variantFlag,
|
|
2268
2566
|
systemImage: systemImageFlag,
|
|
2567
|
+
deviceProfile: deviceProfileFlag,
|
|
2269
2568
|
device: deviceFlag,
|
|
2270
2569
|
wait: waitFlag,
|
|
2271
2570
|
waitConflict,
|
|
@@ -2274,6 +2573,7 @@ async function runAndroid(options = {}) {
|
|
|
2274
2573
|
}, {
|
|
2275
2574
|
resolveCacheProvider,
|
|
2276
2575
|
listSystemImages,
|
|
2576
|
+
listDeviceProfiles,
|
|
2277
2577
|
warn: (label, message) => out(phaseLine(label, chalk.yellow(message)))
|
|
2278
2578
|
});
|
|
2279
2579
|
if (!planned.ok) return fail(planned.code, planned.message, planned.remedy, { lines: planned.lines });
|
|
@@ -2307,10 +2607,11 @@ async function runAndroid(options = {}) {
|
|
|
2307
2607
|
buildCache: requestedBuildCache
|
|
2308
2608
|
});
|
|
2309
2609
|
if (isEasBuildFailure(easBuild)) return fail(easBuild.code, easBuild.message, easBuild.remedy);
|
|
2310
|
-
|
|
2610
|
+
const appIds = detectAppIds(root);
|
|
2611
|
+
let androidPackage = appIds.androidPackage;
|
|
2311
2612
|
record.bundleId = androidPackage;
|
|
2312
2613
|
const registerProject = () => upsertProject(root, {
|
|
2313
|
-
bundleId:
|
|
2614
|
+
bundleId: appIds.bundleId ?? void 0,
|
|
2314
2615
|
androidPackage: androidPackage ?? void 0,
|
|
2315
2616
|
isExpo
|
|
2316
2617
|
});
|
|
@@ -2373,6 +2674,7 @@ async function runAndroid(options = {}) {
|
|
|
2373
2674
|
let device;
|
|
2374
2675
|
let bootDuration = "";
|
|
2375
2676
|
let bootPromise;
|
|
2677
|
+
let startRemoteBoot = null;
|
|
2376
2678
|
if (target.kind === "physical" && !target.serial) {
|
|
2377
2679
|
const pooled = await pooledAndroidDevice({
|
|
2378
2680
|
root,
|
|
@@ -2404,6 +2706,11 @@ async function runAndroid(options = {}) {
|
|
|
2404
2706
|
serial: resolved.serial
|
|
2405
2707
|
});
|
|
2406
2708
|
} else {
|
|
2709
|
+
if (!remoteDevice) try {
|
|
2710
|
+
configuredAndroidEmulatorApp();
|
|
2711
|
+
} catch (err) {
|
|
2712
|
+
return fail("STIM_BAD_ARG", err.message, "Run `stim settings set androidEmulatorApp emulator` or `stim settings set androidEmulatorApp stim-desktop`.");
|
|
2713
|
+
}
|
|
2407
2714
|
const capacity = checkCapacity({
|
|
2408
2715
|
platform: PLATFORM,
|
|
2409
2716
|
project,
|
|
@@ -2418,7 +2725,11 @@ async function runAndroid(options = {}) {
|
|
|
2418
2725
|
projectPath: root,
|
|
2419
2726
|
settingsRoot,
|
|
2420
2727
|
settings,
|
|
2421
|
-
flags: {
|
|
2728
|
+
flags: {
|
|
2729
|
+
systemImage: target.systemImage,
|
|
2730
|
+
systemImageFlag: systemImageFlag?.trim() || null,
|
|
2731
|
+
deviceProfile: target.deviceProfile
|
|
2732
|
+
},
|
|
2422
2733
|
note: out,
|
|
2423
2734
|
out,
|
|
2424
2735
|
logFile: emuLog
|
|
@@ -2429,7 +2740,6 @@ async function runAndroid(options = {}) {
|
|
|
2429
2740
|
}
|
|
2430
2741
|
const prepareMs = prepare();
|
|
2431
2742
|
if (device.created || prepareMs >= 2e3) phase("device", `${device.avdName || device.deviceName || label} ${device.created ? "created" : "prepared"} (${formatDuration(prepareMs)})`);
|
|
2432
|
-
const bootTimer = stepTimer(now);
|
|
2433
2743
|
const boot = () => Promise.resolve(ensureDeviceBooted({
|
|
2434
2744
|
platform: PLATFORM,
|
|
2435
2745
|
device,
|
|
@@ -2441,41 +2751,32 @@ async function runAndroid(options = {}) {
|
|
|
2441
2751
|
reason: String(e?.message || e),
|
|
2442
2752
|
serial: void 0
|
|
2443
2753
|
}));
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
const booted = await bootPromise;
|
|
2462
|
-
if (booted.failed) {
|
|
2463
|
-
if (booted.code) return fail(booted.code, booted.reason ?? "The remote device did not boot.", booted.remedy ?? null);
|
|
2464
|
-
const diag = noDeviceDiagnostic({
|
|
2465
|
-
reason: booted.reason ?? "The remote device did not boot.",
|
|
2466
|
-
logFile: emuLog,
|
|
2467
|
-
remedy: "Run `stim status` to inspect the remote device, then retry the command.",
|
|
2468
|
-
localEmulator: false
|
|
2469
|
-
});
|
|
2470
|
-
return fail(NO_DEVICE, diag.message, diag.remedy, {
|
|
2471
|
-
lines: diag.lines,
|
|
2472
|
-
logPath: diag.logPath ? displayPath(root, diag.logPath) : null
|
|
2754
|
+
const startBoot = () => {
|
|
2755
|
+
const bootTimer = stepTimer(now);
|
|
2756
|
+
return (remoteDevice?.ctx.backend === "eas" ? ensureRemoteOwned({
|
|
2757
|
+
root,
|
|
2758
|
+
platform: PLATFORM,
|
|
2759
|
+
sessionName: ownedSessionName(remoteDevice.ctx.label),
|
|
2760
|
+
startedAt: new Date(now()).toISOString(),
|
|
2761
|
+
boot,
|
|
2762
|
+
createdSessionId: remoteDevice.createdSessionId,
|
|
2763
|
+
abandonCreatedSession: remoteDevice.abandonCreatedSession,
|
|
2764
|
+
webPreviewUrl: remoteDevice.webPreviewUrl,
|
|
2765
|
+
writeState,
|
|
2766
|
+
register: registerProject,
|
|
2767
|
+
notice: (line) => out(chalk.dim(phaseLine("lock", line)))
|
|
2768
|
+
}) : boot()).then((result) => {
|
|
2769
|
+
bootDuration = bootTimer();
|
|
2770
|
+
return result;
|
|
2473
2771
|
});
|
|
2474
|
-
}
|
|
2772
|
+
};
|
|
2773
|
+
if (remoteDevice) startRemoteBoot = startBoot;
|
|
2774
|
+
else bootPromise = startBoot();
|
|
2475
2775
|
}
|
|
2476
2776
|
record.avdName = device.avdName ?? null;
|
|
2477
2777
|
record.deviceName = device.deviceName ?? device.avdName ?? null;
|
|
2478
2778
|
record.systemImage = device.systemImage;
|
|
2779
|
+
record.deviceProfile = device.deviceProfile;
|
|
2479
2780
|
const runFromFingerprint = async () => {
|
|
2480
2781
|
if (metroCheck && metroPort !== null && plan.metroWarmup) prewarmMetro({
|
|
2481
2782
|
port: metroPort,
|
|
@@ -2542,6 +2843,25 @@ async function runAndroid(options = {}) {
|
|
|
2542
2843
|
ccacheActivity = artifact.ccache;
|
|
2543
2844
|
androidPackage = artifact.androidPackage;
|
|
2544
2845
|
record.appPath = apkPath;
|
|
2846
|
+
if (runCancellation()) return fail("STIM_CANCELLED", "before install");
|
|
2847
|
+
if (startRemoteBoot) {
|
|
2848
|
+
progress.step("install");
|
|
2849
|
+
bootPromise = startRemoteBoot();
|
|
2850
|
+
const booted = await bootPromise;
|
|
2851
|
+
if (booted.failed) {
|
|
2852
|
+
if (booted.code) return fail(booted.code, booted.reason ?? "The remote device did not boot.", booted.remedy ?? null);
|
|
2853
|
+
const diag = noDeviceDiagnostic({
|
|
2854
|
+
reason: booted.reason ?? "The remote device did not boot.",
|
|
2855
|
+
logFile: emuLog,
|
|
2856
|
+
remedy: "Run `stim status` to inspect the remote device, then retry the command.",
|
|
2857
|
+
localEmulator: false
|
|
2858
|
+
});
|
|
2859
|
+
return fail(NO_DEVICE, diag.message, diag.remedy, {
|
|
2860
|
+
lines: diag.lines,
|
|
2861
|
+
logPath: diag.logPath ? displayPath(root, diag.logPath) : null
|
|
2862
|
+
});
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2545
2865
|
let leaseHandle = null;
|
|
2546
2866
|
let stopLeaseSignals = null;
|
|
2547
2867
|
const releaseLease = () => {
|