@expo/build-tools 1.0.61 → 1.0.63

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.
@@ -16,6 +16,9 @@ const configureIosCredentials_1 = require("./functions/configureIosCredentials")
16
16
  const configureIosVersion_1 = require("./functions/configureIosVersion");
17
17
  const generateGymfileFromTemplate_1 = require("./functions/generateGymfileFromTemplate");
18
18
  const runFastlane_1 = require("./functions/runFastlane");
19
+ const startAndroidEmulator_1 = require("./functions/startAndroidEmulator");
20
+ const startIosSimulator_1 = require("./functions/startIosSimulator");
21
+ const installMaestro_1 = require("./functions/installMaestro");
19
22
  function getEasFunctions(ctx) {
20
23
  return [
21
24
  (0, checkout_1.createCheckoutBuildFunction)(),
@@ -33,6 +36,9 @@ function getEasFunctions(ctx) {
33
36
  (0, configureIosVersion_1.configureIosVersionFunction)(),
34
37
  (0, generateGymfileFromTemplate_1.generateGymfileFromTemplateFunction)(),
35
38
  (0, runFastlane_1.runFastlaneFunction)(),
39
+ (0, startAndroidEmulator_1.createStartAndroidEmulatorBuildFunction)(),
40
+ (0, startIosSimulator_1.createStartIosSimulatorBuildFunction)(),
41
+ (0, installMaestro_1.createInstallMaestroBuildFunction)(),
36
42
  ];
37
43
  }
38
44
  exports.getEasFunctions = getEasFunctions;
@@ -1 +1 @@
1
- {"version":3,"file":"easFunctions.js","sourceRoot":"","sources":["../../src/steps/easFunctions.ts"],"names":[],"mappings":";;;AAIA,+DAA+E;AAC/E,mDAAmE;AACnE,yDAAwE;AACxE,uEAAuF;AACvF,mDAAmE;AACnE,yFAAyG;AACzG,6FAAkG;AAClG,mFAAwF;AACxF,iFAAsF;AACtF,qDAA0D;AAC1D,qGAA0G;AAC1G,iFAAsF;AACtF,yEAA8E;AAC9E,yFAA8F;AAC9F,yDAA8D;AAE9D,SAAgB,eAAe,CAAC,GAAuB;IACrD,OAAO;QACL,IAAA,sCAA2B,GAAE;QAC7B,IAAA,kDAAiC,EAAC,GAAG,CAAC;QACtC,IAAA,2CAA6B,GAAE;QAC/B,IAAA,0DAAqC,GAAE;QACvC,IAAA,sCAA2B,GAAE;QAC7B,IAAA,4EAA8C,EAAC,GAAG,CAAC;QACnD,IAAA,qEAAqC,GAAE;QACvC,IAAA,2DAAgC,GAAE;QAClC,IAAA,yDAA+B,GAAE;QACjC,IAAA,6BAAiB,GAAE;QACnB,IAAA,6EAAyC,GAAE;QAC3C,IAAA,yDAA+B,GAAE;QACjC,IAAA,iDAA2B,GAAE;QAC7B,IAAA,iEAAmC,GAAE;QACrC,IAAA,iCAAmB,GAAE;KACtB,CAAC;AACJ,CAAC;AAlBD,0CAkBC","sourcesContent":["import { BuildFunction } from '@expo/steps';\n\nimport { CustomBuildContext } from '../customBuildContext';\n\nimport { createUploadArtifactBuildFunction } from './functions/uploadArtifact';\nimport { createCheckoutBuildFunction } from './functions/checkout';\nimport { createSetUpNpmrcBuildFunction } from './functions/useNpmToken';\nimport { createInstallNodeModulesBuildFunction } from './functions/installNodeModules';\nimport { createPrebuildBuildFunction } from './functions/prebuild';\nimport { createFindAndUploadBuildArtifactsBuildFunction } from './functions/findAndUploadBuildArtifacts';\nimport { configureEASUpdateIfInstalledFunction } from './functions/configureEASUpdateIfInstalled';\nimport { injectAndroidCredentialsFunction } from './functions/injectAndroidCredentials';\nimport { configureAndroidVersionFunction } from './functions/configureAndroidVersion';\nimport { runGradleFunction } from './functions/runGradle';\nimport { resolveAppleTeamIdFromCredentialsFunction } from './functions/resolveAppleTeamIdFromCredentials';\nimport { configureIosCredentialsFunction } from './functions/configureIosCredentials';\nimport { configureIosVersionFunction } from './functions/configureIosVersion';\nimport { generateGymfileFromTemplateFunction } from './functions/generateGymfileFromTemplate';\nimport { runFastlaneFunction } from './functions/runFastlane';\n\nexport function getEasFunctions(ctx: CustomBuildContext): BuildFunction[] {\n return [\n createCheckoutBuildFunction(),\n createUploadArtifactBuildFunction(ctx),\n createSetUpNpmrcBuildFunction(),\n createInstallNodeModulesBuildFunction(),\n createPrebuildBuildFunction(),\n createFindAndUploadBuildArtifactsBuildFunction(ctx),\n configureEASUpdateIfInstalledFunction(),\n injectAndroidCredentialsFunction(),\n configureAndroidVersionFunction(),\n runGradleFunction(),\n resolveAppleTeamIdFromCredentialsFunction(),\n configureIosCredentialsFunction(),\n configureIosVersionFunction(),\n generateGymfileFromTemplateFunction(),\n runFastlaneFunction(),\n ];\n}\n"]}
1
+ {"version":3,"file":"easFunctions.js","sourceRoot":"","sources":["../../src/steps/easFunctions.ts"],"names":[],"mappings":";;;AAIA,+DAA+E;AAC/E,mDAAmE;AACnE,yDAAwE;AACxE,uEAAuF;AACvF,mDAAmE;AACnE,yFAAyG;AACzG,6FAAkG;AAClG,mFAAwF;AACxF,iFAAsF;AACtF,qDAA0D;AAC1D,qGAA0G;AAC1G,iFAAsF;AACtF,yEAA8E;AAC9E,yFAA8F;AAC9F,yDAA8D;AAC9D,2EAA2F;AAC3F,qEAAqF;AACrF,+DAA+E;AAE/E,SAAgB,eAAe,CAAC,GAAuB;IACrD,OAAO;QACL,IAAA,sCAA2B,GAAE;QAC7B,IAAA,kDAAiC,EAAC,GAAG,CAAC;QACtC,IAAA,2CAA6B,GAAE;QAC/B,IAAA,0DAAqC,GAAE;QACvC,IAAA,sCAA2B,GAAE;QAC7B,IAAA,4EAA8C,EAAC,GAAG,CAAC;QACnD,IAAA,qEAAqC,GAAE;QACvC,IAAA,2DAAgC,GAAE;QAClC,IAAA,yDAA+B,GAAE;QACjC,IAAA,6BAAiB,GAAE;QACnB,IAAA,6EAAyC,GAAE;QAC3C,IAAA,yDAA+B,GAAE;QACjC,IAAA,iDAA2B,GAAE;QAC7B,IAAA,iEAAmC,GAAE;QACrC,IAAA,iCAAmB,GAAE;QACrB,IAAA,8DAAuC,GAAE;QACzC,IAAA,wDAAoC,GAAE;QACtC,IAAA,kDAAiC,GAAE;KACpC,CAAC;AACJ,CAAC;AArBD,0CAqBC","sourcesContent":["import { BuildFunction } from '@expo/steps';\n\nimport { CustomBuildContext } from '../customBuildContext';\n\nimport { createUploadArtifactBuildFunction } from './functions/uploadArtifact';\nimport { createCheckoutBuildFunction } from './functions/checkout';\nimport { createSetUpNpmrcBuildFunction } from './functions/useNpmToken';\nimport { createInstallNodeModulesBuildFunction } from './functions/installNodeModules';\nimport { createPrebuildBuildFunction } from './functions/prebuild';\nimport { createFindAndUploadBuildArtifactsBuildFunction } from './functions/findAndUploadBuildArtifacts';\nimport { configureEASUpdateIfInstalledFunction } from './functions/configureEASUpdateIfInstalled';\nimport { injectAndroidCredentialsFunction } from './functions/injectAndroidCredentials';\nimport { configureAndroidVersionFunction } from './functions/configureAndroidVersion';\nimport { runGradleFunction } from './functions/runGradle';\nimport { resolveAppleTeamIdFromCredentialsFunction } from './functions/resolveAppleTeamIdFromCredentials';\nimport { configureIosCredentialsFunction } from './functions/configureIosCredentials';\nimport { configureIosVersionFunction } from './functions/configureIosVersion';\nimport { generateGymfileFromTemplateFunction } from './functions/generateGymfileFromTemplate';\nimport { runFastlaneFunction } from './functions/runFastlane';\nimport { createStartAndroidEmulatorBuildFunction } from './functions/startAndroidEmulator';\nimport { createStartIosSimulatorBuildFunction } from './functions/startIosSimulator';\nimport { createInstallMaestroBuildFunction } from './functions/installMaestro';\n\nexport function getEasFunctions(ctx: CustomBuildContext): BuildFunction[] {\n return [\n createCheckoutBuildFunction(),\n createUploadArtifactBuildFunction(ctx),\n createSetUpNpmrcBuildFunction(),\n createInstallNodeModulesBuildFunction(),\n createPrebuildBuildFunction(),\n createFindAndUploadBuildArtifactsBuildFunction(ctx),\n configureEASUpdateIfInstalledFunction(),\n injectAndroidCredentialsFunction(),\n configureAndroidVersionFunction(),\n runGradleFunction(),\n resolveAppleTeamIdFromCredentialsFunction(),\n configureIosCredentialsFunction(),\n configureIosVersionFunction(),\n generateGymfileFromTemplateFunction(),\n runFastlaneFunction(),\n createStartAndroidEmulatorBuildFunction(),\n createStartIosSimulatorBuildFunction(),\n createInstallMaestroBuildFunction(),\n ];\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import { BuildFunction } from '@expo/steps';
2
+ export declare function createInstallMaestroBuildFunction(): BuildFunction;
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createInstallMaestroBuildFunction = void 0;
7
+ const assert_1 = __importDefault(require("assert"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const steps_1 = require("@expo/steps");
11
+ const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
12
+ function createInstallMaestroBuildFunction() {
13
+ return new steps_1.BuildFunction({
14
+ namespace: 'eas',
15
+ id: 'install_maestro',
16
+ name: 'Install Maestro',
17
+ inputProviders: [
18
+ steps_1.BuildStepInput.createProvider({
19
+ id: 'maestro_version',
20
+ required: false,
21
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
22
+ }),
23
+ ],
24
+ fn: async ({ logger, global }, { inputs, env }) => {
25
+ const requestedMaestroVersion = inputs.maestro_version.value;
26
+ const currentMaestroVersion = await getMaestroVersion();
27
+ // When not running in EAS Build VM, do not modify local environment.
28
+ if (env.EAS_BUILD_RUNNER !== 'eas-build') {
29
+ const currentIsJavaInstalled = await isJavaInstalled();
30
+ const currentIsIdbInstalled = await isIdbInstalled();
31
+ if (!currentIsJavaInstalled) {
32
+ logger.warn('It seems Java is not installed. It is required to run Maestro. If the job fails, this may be the reason.');
33
+ logger.info('');
34
+ }
35
+ if (!currentIsIdbInstalled) {
36
+ logger.warn('It seems IDB is not installed. Maestro requires it to run flows on iOS Simulator. If the job fails, this may be the reason.');
37
+ logger.info('');
38
+ }
39
+ if (!currentMaestroVersion) {
40
+ logger.warn('It seems Maestro is not installed. Please install Maestro manually and rerun the job.');
41
+ logger.info('');
42
+ }
43
+ // Guide is helpful in these two cases, it doesn't mention Java.
44
+ if (!currentIsIdbInstalled || !currentMaestroVersion) {
45
+ logger.warn('For more info, check out Maestro installation guide: https://maestro.mobile.dev/getting-started/installing-maestro');
46
+ }
47
+ if (currentMaestroVersion) {
48
+ logger.info(`Maestro ${currentMaestroVersion} is ready.`);
49
+ }
50
+ return;
51
+ }
52
+ if (!(await isJavaInstalled())) {
53
+ if (global.runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
54
+ logger.info('Installing Java');
55
+ await installJavaFromGcs({ logger });
56
+ }
57
+ else {
58
+ // We expect Java to be pre-installed on Linux images,
59
+ // so this should only happen when running this step locally.
60
+ // We don't need to support installing Java on local computers.
61
+ throw new Error('Please install Java manually and rerun the job.');
62
+ }
63
+ }
64
+ // IDB is only a requirement on macOS.
65
+ if (global.runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN && !(await isIdbInstalled())) {
66
+ logger.info('Installing IDB');
67
+ await installIdbFromBrew({ global, logger });
68
+ }
69
+ // Skip installing if the input sets a specific Maestro version to install
70
+ // and it is already installed which happens when developing on a local computer.
71
+ if (!currentMaestroVersion || requestedMaestroVersion !== currentMaestroVersion) {
72
+ await installMaestro({
73
+ version: requestedMaestroVersion,
74
+ global,
75
+ logger,
76
+ });
77
+ }
78
+ const maestroVersion = await getMaestroVersion();
79
+ (0, assert_1.default)(maestroVersion, 'Failed to ensure Maestro is installed.');
80
+ logger.info(`Maestro ${maestroVersion} is ready.`);
81
+ },
82
+ });
83
+ }
84
+ exports.createInstallMaestroBuildFunction = createInstallMaestroBuildFunction;
85
+ async function getMaestroVersion() {
86
+ try {
87
+ const maestroVersion = await (0, turtle_spawn_1.default)('maestro', ['--version'], { stdio: 'pipe' });
88
+ return maestroVersion.stdout.trim();
89
+ }
90
+ catch {
91
+ return null;
92
+ }
93
+ }
94
+ async function installMaestro({ global, version, logger, }) {
95
+ logger.info('Fetching install script');
96
+ const tempDirectory = await fs_extra_1.default.mkdtemp('install_maestro');
97
+ try {
98
+ const installMaestroScriptResponse = await fetch('https://get.maestro.mobile.dev');
99
+ const installMaestroScript = await installMaestroScriptResponse.text();
100
+ const installMaestroScriptFilePath = path_1.default.join(tempDirectory, 'install_maestro.sh');
101
+ await fs_extra_1.default.writeFile(installMaestroScriptFilePath, installMaestroScript, {
102
+ mode: 0o777,
103
+ });
104
+ logger.info('Installing Maestro');
105
+ await (0, turtle_spawn_1.default)(installMaestroScriptFilePath, [], {
106
+ logger,
107
+ env: {
108
+ ...global.env,
109
+ MAESTRO_VERSION: version,
110
+ },
111
+ });
112
+ }
113
+ finally {
114
+ await fs_extra_1.default.remove(tempDirectory);
115
+ }
116
+ }
117
+ async function isIdbInstalled() {
118
+ try {
119
+ await (0, turtle_spawn_1.default)('idb', ['-h'], { ignoreStdio: true });
120
+ return true;
121
+ }
122
+ catch {
123
+ return false;
124
+ }
125
+ }
126
+ async function installIdbFromBrew({ global, logger, }) {
127
+ // Unfortunately our Mac images sometimes have two Homebrew
128
+ // installations. We should use the ARM64 one, located in /opt/homebrew.
129
+ const brewPath = '/opt/homebrew/bin/brew';
130
+ const env = {
131
+ ...global.env,
132
+ HOMEBREW_NO_AUTO_UPDATE: '1',
133
+ };
134
+ await (0, turtle_spawn_1.default)(brewPath, ['tap', 'facebook/fb'], {
135
+ env,
136
+ logger,
137
+ });
138
+ await (0, turtle_spawn_1.default)(brewPath, ['install', 'idb-companion'], {
139
+ env,
140
+ logger,
141
+ });
142
+ }
143
+ async function isJavaInstalled() {
144
+ try {
145
+ await (0, turtle_spawn_1.default)('java', ['-version'], { ignoreStdio: true });
146
+ return true;
147
+ }
148
+ catch {
149
+ return false;
150
+ }
151
+ }
152
+ /**
153
+ * Installs Java 11 from a file uploaded manually to GCS as cache.
154
+ * Should not be run outside of EAS Build VMs not to break users' environments.
155
+ */
156
+ async function installJavaFromGcs({ logger }) {
157
+ const downloadUrl = 'https://storage.googleapis.com/turtle-v2/zulu11.68.17-ca-jdk11.0.21-macosx_aarch64.dmg';
158
+ const filename = path_1.default.basename(downloadUrl);
159
+ const tempDirectory = await fs_extra_1.default.mkdtemp('install_java');
160
+ const installerPath = path_1.default.join(tempDirectory, filename);
161
+ const installerMountDirectory = path_1.default.join(tempDirectory, 'mountpoint');
162
+ try {
163
+ logger.info('Downloading Java installer');
164
+ // This is simpler than piping body into a write stream with node-fetch.
165
+ await (0, turtle_spawn_1.default)('curl', ['--output', installerPath, downloadUrl]);
166
+ await fs_extra_1.default.mkdir(installerMountDirectory);
167
+ logger.info('Mounting Java installer');
168
+ await (0, turtle_spawn_1.default)('hdiutil', ['attach', installerPath, '-noverify', '-mountpoint', installerMountDirectory], { logger });
169
+ logger.info('Installing Java');
170
+ await (0, turtle_spawn_1.default)('sudo', [
171
+ 'installer',
172
+ '-pkg',
173
+ path_1.default.join(installerMountDirectory, 'Double-Click to Install Azul Zulu JDK 11.pkg'),
174
+ '-target',
175
+ '/',
176
+ ], { logger });
177
+ }
178
+ finally {
179
+ try {
180
+ // We need to unmount to remove, otherwise we get "resource busy"
181
+ await (0, turtle_spawn_1.default)('hdiutil', ['detach', installerMountDirectory]);
182
+ }
183
+ catch { }
184
+ await fs_extra_1.default.remove(tempDirectory);
185
+ }
186
+ }
187
+ //# sourceMappingURL=installMaestro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installMaestro.js","sourceRoot":"","sources":["../../../src/steps/functions/installMaestro.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'assert';\nimport path from 'path';\n\nimport fs from 'fs-extra';\nimport {\n BuildFunction,\n BuildRuntimePlatform,\n BuildStepGlobalContext,\n BuildStepInput,\n BuildStepInputValueTypeName,\n} from '@expo/steps';\nimport spawn from '@expo/turtle-spawn';\nimport { bunyan } from '@expo/logger';\n\nexport function createInstallMaestroBuildFunction(): BuildFunction {\n return new BuildFunction({\n namespace: 'eas',\n id: 'install_maestro',\n name: 'Install Maestro',\n inputProviders: [\n BuildStepInput.createProvider({\n id: 'maestro_version',\n required: false,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n ],\n fn: async ({ logger, global }, { inputs, env }) => {\n const requestedMaestroVersion = inputs.maestro_version.value as string | undefined;\n const currentMaestroVersion = await getMaestroVersion();\n\n // When not running in EAS Build VM, do not modify local environment.\n if (env.EAS_BUILD_RUNNER !== 'eas-build') {\n const currentIsJavaInstalled = await isJavaInstalled();\n const currentIsIdbInstalled = await isIdbInstalled();\n\n if (!currentIsJavaInstalled) {\n logger.warn(\n 'It seems Java is not installed. It is required to run Maestro. If the job fails, this may be the reason.'\n );\n logger.info('');\n }\n\n if (!currentIsIdbInstalled) {\n logger.warn(\n 'It seems IDB is not installed. Maestro requires it to run flows on iOS Simulator. If the job fails, this may be the reason.'\n );\n logger.info('');\n }\n\n if (!currentMaestroVersion) {\n logger.warn(\n 'It seems Maestro is not installed. Please install Maestro manually and rerun the job.'\n );\n logger.info('');\n }\n\n // Guide is helpful in these two cases, it doesn't mention Java.\n if (!currentIsIdbInstalled || !currentMaestroVersion) {\n logger.warn(\n 'For more info, check out Maestro installation guide: https://maestro.mobile.dev/getting-started/installing-maestro'\n );\n }\n\n if (currentMaestroVersion) {\n logger.info(`Maestro ${currentMaestroVersion} is ready.`);\n }\n\n return;\n }\n\n if (!(await isJavaInstalled())) {\n if (global.runtimePlatform === BuildRuntimePlatform.DARWIN) {\n logger.info('Installing Java');\n await installJavaFromGcs({ logger });\n } else {\n // We expect Java to be pre-installed on Linux images,\n // so this should only happen when running this step locally.\n // We don't need to support installing Java on local computers.\n throw new Error('Please install Java manually and rerun the job.');\n }\n }\n\n // IDB is only a requirement on macOS.\n if (global.runtimePlatform === BuildRuntimePlatform.DARWIN && !(await isIdbInstalled())) {\n logger.info('Installing IDB');\n await installIdbFromBrew({ global, logger });\n }\n\n // Skip installing if the input sets a specific Maestro version to install\n // and it is already installed which happens when developing on a local computer.\n if (!currentMaestroVersion || requestedMaestroVersion !== currentMaestroVersion) {\n await installMaestro({\n version: requestedMaestroVersion,\n global,\n logger,\n });\n }\n\n const maestroVersion = await getMaestroVersion();\n assert(maestroVersion, 'Failed to ensure Maestro is installed.');\n logger.info(`Maestro ${maestroVersion} is ready.`);\n },\n });\n}\n\nasync function getMaestroVersion(): Promise<string | null> {\n try {\n const maestroVersion = await spawn('maestro', ['--version'], { stdio: 'pipe' });\n return maestroVersion.stdout.trim();\n } catch {\n return null;\n }\n}\n\nasync function installMaestro({\n global,\n version,\n logger,\n}: {\n version?: string;\n logger: bunyan;\n global: BuildStepGlobalContext;\n}): Promise<void> {\n logger.info('Fetching install script');\n const tempDirectory = await fs.mkdtemp('install_maestro');\n try {\n const installMaestroScriptResponse = await fetch('https://get.maestro.mobile.dev');\n const installMaestroScript = await installMaestroScriptResponse.text();\n const installMaestroScriptFilePath = path.join(tempDirectory, 'install_maestro.sh');\n await fs.writeFile(installMaestroScriptFilePath, installMaestroScript, {\n mode: 0o777,\n });\n logger.info('Installing Maestro');\n await spawn(installMaestroScriptFilePath, [], {\n logger,\n env: {\n ...global.env,\n MAESTRO_VERSION: version,\n },\n });\n } finally {\n await fs.remove(tempDirectory);\n }\n}\n\nasync function isIdbInstalled(): Promise<boolean> {\n try {\n await spawn('idb', ['-h'], { ignoreStdio: true });\n return true;\n } catch {\n return false;\n }\n}\n\nasync function installIdbFromBrew({\n global,\n logger,\n}: {\n global: BuildStepGlobalContext;\n logger: bunyan;\n}): Promise<void> {\n // Unfortunately our Mac images sometimes have two Homebrew\n // installations. We should use the ARM64 one, located in /opt/homebrew.\n const brewPath = '/opt/homebrew/bin/brew';\n const env = {\n ...global.env,\n HOMEBREW_NO_AUTO_UPDATE: '1',\n };\n\n await spawn(brewPath, ['tap', 'facebook/fb'], {\n env,\n logger,\n });\n await spawn(brewPath, ['install', 'idb-companion'], {\n env,\n logger,\n });\n}\n\nasync function isJavaInstalled(): Promise<boolean> {\n try {\n await spawn('java', ['-version'], { ignoreStdio: true });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Installs Java 11 from a file uploaded manually to GCS as cache.\n * Should not be run outside of EAS Build VMs not to break users' environments.\n */\nasync function installJavaFromGcs({ logger }: { logger: bunyan }): Promise<void> {\n const downloadUrl =\n 'https://storage.googleapis.com/turtle-v2/zulu11.68.17-ca-jdk11.0.21-macosx_aarch64.dmg';\n const filename = path.basename(downloadUrl);\n const tempDirectory = await fs.mkdtemp('install_java');\n const installerPath = path.join(tempDirectory, filename);\n const installerMountDirectory = path.join(tempDirectory, 'mountpoint');\n try {\n logger.info('Downloading Java installer');\n // This is simpler than piping body into a write stream with node-fetch.\n await spawn('curl', ['--output', installerPath, downloadUrl]);\n\n await fs.mkdir(installerMountDirectory);\n logger.info('Mounting Java installer');\n await spawn(\n 'hdiutil',\n ['attach', installerPath, '-noverify', '-mountpoint', installerMountDirectory],\n { logger }\n );\n\n logger.info('Installing Java');\n await spawn(\n 'sudo',\n [\n 'installer',\n '-pkg',\n path.join(installerMountDirectory, 'Double-Click to Install Azul Zulu JDK 11.pkg'),\n '-target',\n '/',\n ],\n { logger }\n );\n } finally {\n try {\n // We need to unmount to remove, otherwise we get \"resource busy\"\n await spawn('hdiutil', ['detach', installerMountDirectory]);\n } catch {}\n\n await fs.remove(tempDirectory);\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import { BuildFunction } from '@expo/steps';
2
+ export declare function createStartAndroidEmulatorBuildFunction(): BuildFunction;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createStartAndroidEmulatorBuildFunction = void 0;
7
+ const assert_1 = __importDefault(require("assert"));
8
+ const logger_1 = require("@expo/logger");
9
+ const steps_1 = require("@expo/steps");
10
+ const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
11
+ const uuid_1 = require("uuid");
12
+ const retry_1 = require("../../utils/retry");
13
+ const defaultSystemImagePackage = `system-images;android-30;default;${process.arch === 'arm64' ? 'arm64-v8a' : 'x86_64'}`;
14
+ function createStartAndroidEmulatorBuildFunction() {
15
+ return new steps_1.BuildFunction({
16
+ namespace: 'eas',
17
+ id: 'start_android_emulator',
18
+ name: 'Start Android Emulator',
19
+ inputProviders: [
20
+ steps_1.BuildStepInput.createProvider({
21
+ id: 'device_name',
22
+ required: false,
23
+ defaultValue: 'EasAndroidDevice01',
24
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
25
+ }),
26
+ steps_1.BuildStepInput.createProvider({
27
+ id: 'system_image_package',
28
+ required: false,
29
+ defaultValue: defaultSystemImagePackage,
30
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
31
+ }),
32
+ ],
33
+ fn: async ({ logger }, { inputs }) => {
34
+ var _a, _b;
35
+ const deviceName = `${inputs.device_name.value}`;
36
+ const systemImagePackage = `${inputs.system_image_package.value}`;
37
+ logger.info('Making sure system image is installed');
38
+ await (0, turtle_spawn_1.default)('sdkmanager', [systemImagePackage], {
39
+ logger,
40
+ });
41
+ logger.info('Creating emulator device');
42
+ const avdManager = (0, turtle_spawn_1.default)('avdmanager', ['create', 'avd', '--name', deviceName, '--package', systemImagePackage, '--force'], {
43
+ stdio: 'pipe',
44
+ });
45
+ // `avdmanager create` always asks about creating a custom hardware profile.
46
+ // > Do you wish to create a custom hardware profile? [no]
47
+ // We answer "no".
48
+ (_a = avdManager.child.stdin) === null || _a === void 0 ? void 0 : _a.write('no');
49
+ (_b = avdManager.child.stdin) === null || _b === void 0 ? void 0 : _b.end();
50
+ await avdManager;
51
+ const qemuPropId = (0, uuid_1.v4)();
52
+ logger.info('Starting emulator device');
53
+ await startAndroidSimulator({ deviceName, qemuPropId });
54
+ logger.info('Waiting for emulator to become ready');
55
+ const serialId = await (0, retry_1.retryAsync)(async () => {
56
+ const serialId = await getEmulatorSerialId({ qemuPropId });
57
+ (0, assert_1.default)(serialId, 'Failed to configure emulator: emulator with required ID not found.');
58
+ return serialId;
59
+ }, {
60
+ logger,
61
+ retryOptions: {
62
+ // Emulators usually take 30 second tops to boot.
63
+ retries: 60,
64
+ retryIntervalMs: 1000,
65
+ },
66
+ });
67
+ await (0, retry_1.retryAsync)(async () => {
68
+ const { stdout } = await (0, turtle_spawn_1.default)('adb', ['-s', serialId, 'shell', 'getprop', 'sys.boot_completed'], {
69
+ mode: logger_1.PipeMode.COMBINED,
70
+ });
71
+ if (!stdout.startsWith('1')) {
72
+ throw new Error('Emulator boot has not completed.');
73
+ }
74
+ }, {
75
+ // Retry every second for 3 minutes.
76
+ retryOptions: {
77
+ retries: 3 * 60,
78
+ retryIntervalMs: 1000,
79
+ },
80
+ });
81
+ logger.info(`${deviceName} is ready.`);
82
+ },
83
+ });
84
+ }
85
+ exports.createStartAndroidEmulatorBuildFunction = createStartAndroidEmulatorBuildFunction;
86
+ async function startAndroidSimulator({ deviceName, qemuPropId, }) {
87
+ const emulatorPromise = (0, turtle_spawn_1.default)(`${process.env.ANDROID_HOME}/emulator/emulator`, [
88
+ '-no-window',
89
+ '-no-boot-anim',
90
+ '-writable-system',
91
+ '-noaudio',
92
+ '-avd',
93
+ deviceName,
94
+ '-prop',
95
+ `qemu.uuid=${qemuPropId}`,
96
+ ], {
97
+ detached: true,
98
+ stdio: 'ignore',
99
+ });
100
+ // If emulator fails to start, throw its error.
101
+ if (!emulatorPromise.child.pid) {
102
+ await emulatorPromise;
103
+ }
104
+ emulatorPromise.child.unref();
105
+ }
106
+ async function getEmulatorSerialId({ qemuPropId }) {
107
+ const adbDevices = await (0, turtle_spawn_1.default)('adb', ['devices'], { mode: logger_1.PipeMode.COMBINED });
108
+ for (const adbDeviceLine of adbDevices.stdout.split('\n')) {
109
+ if (!adbDeviceLine.startsWith('emulator')) {
110
+ continue;
111
+ }
112
+ const matches = adbDeviceLine.match(/^(\S+)/);
113
+ if (!matches) {
114
+ continue;
115
+ }
116
+ const [, serialId] = matches;
117
+ const getProp = await (0, turtle_spawn_1.default)('adb', ['-s', serialId, 'shell', 'getprop', 'qemu.uuid'], {
118
+ mode: logger_1.PipeMode.COMBINED,
119
+ });
120
+ if (getProp.stdout.startsWith(qemuPropId)) {
121
+ return serialId;
122
+ }
123
+ }
124
+ return null;
125
+ }
126
+ //# sourceMappingURL=startAndroidEmulator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startAndroidEmulator.js","sourceRoot":"","sources":["../../../src/steps/functions/startAndroidEmulator.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'assert';\n\nimport { PipeMode } from '@expo/logger';\nimport { BuildFunction, BuildStepInput, BuildStepInputValueTypeName } from '@expo/steps';\nimport spawn from '@expo/turtle-spawn';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { retryAsync } from '../../utils/retry';\n\nconst defaultSystemImagePackage = `system-images;android-30;default;${\n process.arch === 'arm64' ? 'arm64-v8a' : 'x86_64'\n}`;\n\nexport function createStartAndroidEmulatorBuildFunction(): BuildFunction {\n return new BuildFunction({\n namespace: 'eas',\n id: 'start_android_emulator',\n name: 'Start Android Emulator',\n inputProviders: [\n BuildStepInput.createProvider({\n id: 'device_name',\n required: false,\n defaultValue: 'EasAndroidDevice01',\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n BuildStepInput.createProvider({\n id: 'system_image_package',\n required: false,\n defaultValue: defaultSystemImagePackage,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n ],\n fn: async ({ logger }, { inputs }) => {\n const deviceName = `${inputs.device_name.value}`;\n const systemImagePackage = `${inputs.system_image_package.value}`;\n logger.info('Making sure system image is installed');\n await spawn('sdkmanager', [systemImagePackage], {\n logger,\n });\n\n logger.info('Creating emulator device');\n const avdManager = spawn(\n 'avdmanager',\n ['create', 'avd', '--name', deviceName, '--package', systemImagePackage, '--force'],\n {\n stdio: 'pipe',\n }\n );\n // `avdmanager create` always asks about creating a custom hardware profile.\n // > Do you wish to create a custom hardware profile? [no]\n // We answer \"no\".\n avdManager.child.stdin?.write('no');\n avdManager.child.stdin?.end();\n await avdManager;\n\n const qemuPropId = uuidv4();\n\n logger.info('Starting emulator device');\n await startAndroidSimulator({ deviceName, qemuPropId });\n\n logger.info('Waiting for emulator to become ready');\n const serialId = await retryAsync(\n async () => {\n const serialId = await getEmulatorSerialId({ qemuPropId });\n assert(serialId, 'Failed to configure emulator: emulator with required ID not found.');\n return serialId;\n },\n {\n logger,\n retryOptions: {\n // Emulators usually take 30 second tops to boot.\n retries: 60,\n retryIntervalMs: 1_000,\n },\n }\n );\n\n await retryAsync(\n async () => {\n const { stdout } = await spawn(\n 'adb',\n ['-s', serialId, 'shell', 'getprop', 'sys.boot_completed'],\n {\n mode: PipeMode.COMBINED,\n }\n );\n\n if (!stdout.startsWith('1')) {\n throw new Error('Emulator boot has not completed.');\n }\n },\n {\n // Retry every second for 3 minutes.\n retryOptions: {\n retries: 3 * 60,\n retryIntervalMs: 1_000,\n },\n }\n );\n\n logger.info(`${deviceName} is ready.`);\n },\n });\n}\n\nasync function startAndroidSimulator({\n deviceName,\n qemuPropId,\n}: {\n deviceName: string;\n qemuPropId: string;\n}): Promise<void> {\n const emulatorPromise = spawn(\n `${process.env.ANDROID_HOME}/emulator/emulator`,\n [\n '-no-window',\n '-no-boot-anim',\n '-writable-system',\n '-noaudio',\n '-avd',\n deviceName,\n '-prop',\n `qemu.uuid=${qemuPropId}`,\n ],\n {\n detached: true,\n stdio: 'ignore',\n }\n );\n // If emulator fails to start, throw its error.\n if (!emulatorPromise.child.pid) {\n await emulatorPromise;\n }\n emulatorPromise.child.unref();\n}\n\nasync function getEmulatorSerialId({ qemuPropId }: { qemuPropId: string }): Promise<string | null> {\n const adbDevices = await spawn('adb', ['devices'], { mode: PipeMode.COMBINED });\n for (const adbDeviceLine of adbDevices.stdout.split('\\n')) {\n if (!adbDeviceLine.startsWith('emulator')) {\n continue;\n }\n\n const matches = adbDeviceLine.match(/^(\\S+)/);\n if (!matches) {\n continue;\n }\n\n const [, serialId] = matches;\n const getProp = await spawn('adb', ['-s', serialId, 'shell', 'getprop', 'qemu.uuid'], {\n mode: PipeMode.COMBINED,\n });\n if (getProp.stdout.startsWith(qemuPropId)) {\n return serialId;\n }\n }\n\n return null;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import { BuildFunction } from '@expo/steps';
2
+ export declare function createStartIosSimulatorBuildFunction(): BuildFunction;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createStartIosSimulatorBuildFunction = void 0;
7
+ const logger_1 = require("@expo/logger");
8
+ const steps_1 = require("@expo/steps");
9
+ const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
10
+ const lodash_1 = require("lodash");
11
+ const retry_1 = require("../../utils/retry");
12
+ function createStartIosSimulatorBuildFunction() {
13
+ return new steps_1.BuildFunction({
14
+ namespace: 'eas',
15
+ id: 'start_ios_simulator',
16
+ name: 'Start iOS Simulator',
17
+ inputProviders: [
18
+ steps_1.BuildStepInput.createProvider({
19
+ id: 'device_identifier',
20
+ required: false,
21
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
22
+ }),
23
+ ],
24
+ fn: async ({ logger }, { inputs }) => {
25
+ var _a, _b, _c;
26
+ try {
27
+ const availableDevices = await getAvailableSimulatorDevices();
28
+ logger.info(`Available Simulator devices:\n- ${availableDevices
29
+ .map(formatSimulatorDevice)
30
+ .join(`\n- `)}`);
31
+ }
32
+ catch (error) {
33
+ logger.info('Failed to list available Simulator devices.', error);
34
+ }
35
+ finally {
36
+ logger.info('');
37
+ }
38
+ const deviceIdentifier = (_b = (_a = inputs.device_identifier.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : (_c = (await findMostGenericIphone())) === null || _c === void 0 ? void 0 : _c.name;
39
+ if (!deviceIdentifier) {
40
+ throw new Error('Could not find an iPhone among available simulator devices.');
41
+ }
42
+ const bootstatusResult = await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'bootstatus', deviceIdentifier, '-b'], {
43
+ logger,
44
+ });
45
+ await (0, retry_1.retryAsync)(async () => {
46
+ await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'io', deviceIdentifier, 'screenshot', '/dev/null']);
47
+ }, {
48
+ retryOptions: {
49
+ // There's 30 * 60 seconds in 30 minutes, which is the timeout.
50
+ retries: 30 * 60,
51
+ retryIntervalMs: 1000,
52
+ },
53
+ });
54
+ logger.info('');
55
+ const udid = parseUdidFromBootstatusStdout(bootstatusResult.stdout);
56
+ const device = udid ? await getSimulatorDevice(udid) : null;
57
+ logger.info(`${device ? formatSimulatorDevice(device) : deviceIdentifier} is ready.`);
58
+ },
59
+ });
60
+ }
61
+ exports.createStartIosSimulatorBuildFunction = createStartIosSimulatorBuildFunction;
62
+ async function findMostGenericIphone() {
63
+ const availableSimulatorDevices = await getAvailableSimulatorDevices();
64
+ const availableIphones = availableSimulatorDevices.filter((device) => device.name.startsWith('iPhone'));
65
+ // It's funny, but it works.
66
+ const iphoneWithShortestName = (0, lodash_1.minBy)(availableIphones, (device) => device.name.length);
67
+ return iphoneWithShortestName !== null && iphoneWithShortestName !== void 0 ? iphoneWithShortestName : null;
68
+ }
69
+ function formatSimulatorDevice(device) {
70
+ return `${device.name} (${device.udid}) on ${device.runtime}`;
71
+ }
72
+ function parseUdidFromBootstatusStdout(stdout) {
73
+ const matches = stdout.match(/^Monitoring boot status for .+ \((.+)\)\.$/m);
74
+ if (!matches) {
75
+ return null;
76
+ }
77
+ return matches[1];
78
+ }
79
+ async function getSimulatorDevice(udid) {
80
+ var _a;
81
+ const devices = await getAvailableSimulatorDevices();
82
+ return (_a = devices.find((device) => device.udid === udid)) !== null && _a !== void 0 ? _a : null;
83
+ }
84
+ async function getAvailableSimulatorDevices() {
85
+ const result = await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'list', 'devices', '--json', '--no-escape-slashes', 'available'], {
86
+ mode: logger_1.PipeMode.COMBINED_AS_STDOUT,
87
+ });
88
+ const xcrunData = JSON.parse(result.stdout);
89
+ const allAvailableDevices = [];
90
+ for (const [runtime, devices] of Object.entries(xcrunData.devices)) {
91
+ allAvailableDevices.push(...devices.map((device) => ({ ...device, runtime })));
92
+ }
93
+ return allAvailableDevices;
94
+ }
95
+ //# sourceMappingURL=startIosSimulator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startIosSimulator.js","sourceRoot":"","sources":["../../../src/steps/functions/startIosSimulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { PipeMode } from '@expo/logger';\nimport { BuildFunction, BuildStepInput, BuildStepInputValueTypeName } from '@expo/steps';\nimport spawn from '@expo/turtle-spawn';\nimport { minBy } from 'lodash';\n\nimport { retryAsync } from '../../utils/retry';\n\nexport function createStartIosSimulatorBuildFunction(): BuildFunction {\n return new BuildFunction({\n namespace: 'eas',\n id: 'start_ios_simulator',\n name: 'Start iOS Simulator',\n inputProviders: [\n BuildStepInput.createProvider({\n id: 'device_identifier',\n required: false,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n ],\n fn: async ({ logger }, { inputs }) => {\n try {\n const availableDevices = await getAvailableSimulatorDevices();\n logger.info(\n `Available Simulator devices:\\n- ${availableDevices\n .map(formatSimulatorDevice)\n .join(`\\n- `)}`\n );\n } catch (error) {\n logger.info('Failed to list available Simulator devices.', error);\n } finally {\n logger.info('');\n }\n\n const deviceIdentifier =\n inputs.device_identifier.value?.toString() ?? (await findMostGenericIphone())?.name;\n\n if (!deviceIdentifier) {\n throw new Error('Could not find an iPhone among available simulator devices.');\n }\n\n const bootstatusResult = await spawn(\n 'xcrun',\n ['simctl', 'bootstatus', deviceIdentifier, '-b'],\n {\n logger,\n }\n );\n\n await retryAsync(\n async () => {\n await spawn('xcrun', ['simctl', 'io', deviceIdentifier, 'screenshot', '/dev/null']);\n },\n {\n retryOptions: {\n // There's 30 * 60 seconds in 30 minutes, which is the timeout.\n retries: 30 * 60,\n retryIntervalMs: 1_000,\n },\n }\n );\n\n logger.info('');\n\n const udid = parseUdidFromBootstatusStdout(bootstatusResult.stdout);\n const device = udid ? await getSimulatorDevice(udid) : null;\n logger.info(`${device ? formatSimulatorDevice(device) : deviceIdentifier} is ready.`);\n },\n });\n}\n\nasync function findMostGenericIphone(): Promise<AvailableXcrunSimctlDevice | null> {\n const availableSimulatorDevices = await getAvailableSimulatorDevices();\n const availableIphones = availableSimulatorDevices.filter((device) =>\n device.name.startsWith('iPhone')\n );\n // It's funny, but it works.\n const iphoneWithShortestName = minBy(availableIphones, (device) => device.name.length);\n return iphoneWithShortestName ?? null;\n}\n\nfunction formatSimulatorDevice(device: XcrunSimctlDevice & { runtime: string }): string {\n return `${device.name} (${device.udid}) on ${device.runtime}`;\n}\n\nfunction parseUdidFromBootstatusStdout(stdout: string): string | null {\n const matches = stdout.match(/^Monitoring boot status for .+ \\((.+)\\)\\.$/m);\n if (!matches) {\n return null;\n }\n return matches[1];\n}\n\nasync function getSimulatorDevice(udid: string): Promise<SimulatorDevice | null> {\n const devices = await getAvailableSimulatorDevices();\n return devices.find((device) => device.udid === udid) ?? null;\n}\n\nasync function getAvailableSimulatorDevices(): Promise<SimulatorDevice[]> {\n const result = await spawn(\n 'xcrun',\n ['simctl', 'list', 'devices', '--json', '--no-escape-slashes', 'available'],\n {\n mode: PipeMode.COMBINED_AS_STDOUT,\n }\n );\n const xcrunData = JSON.parse(\n result.stdout\n ) as XcrunSimctlListDevicesJsonOutput<AvailableXcrunSimctlDevice>;\n\n const allAvailableDevices: (AvailableXcrunSimctlDevice & { runtime: string })[] = [];\n for (const [runtime, devices] of Object.entries(xcrunData.devices)) {\n allAvailableDevices.push(...devices.map((device) => ({ ...device, runtime })));\n }\n\n return allAvailableDevices;\n}\n\ntype XcrunSimctlDevice = {\n availabilityError?: string;\n /** e.g. /Users/sjchmiela/Library/Developer/CoreSimulator/Devices/8272DEB1-42B5-4F78-AB2D-0BC5F320B822/data */\n dataPath: string;\n /** e.g. 18341888 */\n dataPathSize: number;\n /** e.g. /Users/sjchmiela/Library/Logs/CoreSimulator/8272DEB1-42B5-4F78-AB2D-0BC5F320B822 */\n logPath: string;\n /** e.g. 8272DEB1-42B5-4F78-AB2D-0BC5F320B822 */\n udid: string;\n isAvailable: boolean;\n /** e.g. com.apple.CoreSimulator.SimDeviceType.iPhone-13-mini */\n deviceTypeIdentifier: string;\n state: 'Shutdown' | 'Booted';\n /** e.g. iPhone 15 */\n name: string;\n /** e.g. 2024-01-22T19:28:56Z */\n lastBootedAt?: string;\n};\n\ntype SimulatorDevice = AvailableXcrunSimctlDevice & { runtime: string };\n\ntype AvailableXcrunSimctlDevice = XcrunSimctlDevice & {\n availabilityError?: never;\n isAvailable: true;\n};\n\ntype XcrunSimctlListDevicesJsonOutput<TDevice extends XcrunSimctlDevice = XcrunSimctlDevice> = {\n devices: {\n [runtime: string]: TDevice[];\n };\n};\n"]}
@@ -0,0 +1,11 @@
1
+ /// <reference types="bunyan" />
2
+ import { bunyan } from '@expo/logger';
3
+ export declare function sleepAsync(ms: number): Promise<void>;
4
+ export interface RetryOptions {
5
+ retries: number;
6
+ retryIntervalMs: number;
7
+ }
8
+ export declare function retryAsync<T = void>(fn: (attemptCount: number) => Promise<T>, { retryOptions: { retries, retryIntervalMs }, logger, }: {
9
+ retryOptions: RetryOptions;
10
+ logger?: bunyan;
11
+ }): Promise<T>;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.retryAsync = exports.sleepAsync = void 0;
4
+ async function sleepAsync(ms) {
5
+ await new Promise((res) => setTimeout(res, ms));
6
+ }
7
+ exports.sleepAsync = sleepAsync;
8
+ async function retryAsync(fn, { retryOptions: { retries, retryIntervalMs }, logger, }) {
9
+ let attemptCount = -1;
10
+ for (;;) {
11
+ try {
12
+ attemptCount += 1;
13
+ return await fn(attemptCount);
14
+ }
15
+ catch (err) {
16
+ logger === null || logger === void 0 ? void 0 : logger.debug({ err, stdout: err.stdout, stderr: err.stderr }, `Retry attempt ${attemptCount}`);
17
+ await sleepAsync(retryIntervalMs);
18
+ if (attemptCount === retries) {
19
+ throw err;
20
+ }
21
+ }
22
+ }
23
+ }
24
+ exports.retryAsync = retryAsync;
25
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":";;;AAEO,KAAK,UAAU,UAAU,CAAC,EAAU;IACzC,MAAM,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;AAClD,CAAC;AAFD,gCAEC;AAOM,KAAK,UAAU,UAAU,CAC9B,EAAwC,EACxC,EACE,YAAY,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,EAC1C,MAAM,GAIP;IAED,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IACtB,SAAS,CAAC;QACR,IAAI,CAAC;YACH,YAAY,IAAI,CAAC,CAAC;YAClB,OAAO,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CACX,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAC/C,iBAAiB,YAAY,EAAE,CAChC,CAAC;YACF,MAAM,UAAU,CAAC,eAAe,CAAC,CAAC;YAClC,IAAI,YAAY,KAAK,OAAO,EAAE,CAAC;gBAC7B,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AA1BD,gCA0BC","sourcesContent":["import { bunyan } from '@expo/logger';\n\nexport async function sleepAsync(ms: number): Promise<void> {\n await new Promise((res) => setTimeout(res, ms));\n}\n\nexport interface RetryOptions {\n retries: number;\n retryIntervalMs: number;\n}\n\nexport async function retryAsync<T = void>(\n fn: (attemptCount: number) => Promise<T>,\n {\n retryOptions: { retries, retryIntervalMs },\n logger,\n }: {\n retryOptions: RetryOptions;\n logger?: bunyan;\n }\n): Promise<T> {\n let attemptCount = -1;\n for (;;) {\n try {\n attemptCount += 1;\n return await fn(attemptCount);\n } catch (err: any) {\n logger?.debug(\n { err, stdout: err.stdout, stderr: err.stderr },\n `Retry attempt ${attemptCount}`\n );\n await sleepAsync(retryIntervalMs);\n if (attemptCount === retries) {\n throw err;\n }\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/build-tools",
3
- "version": "1.0.61",
3
+ "version": "1.0.63",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -67,5 +67,5 @@
67
67
  "node": "20.11.0",
68
68
  "yarn": "1.22.21"
69
69
  },
70
- "gitHead": "99ab47c6bcf64abe3f18c905122c95e0ce9c6ea9"
70
+ "gitHead": "ff286ddab1d8777b02185e167844fb25dc0691a4"
71
71
  }