@expo/build-tools 1.0.194 → 1.0.196
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/steps/easFunctions.js +2 -0
- package/dist/steps/easFunctions.js.map +1 -1
- package/dist/steps/functions/internalMaestroTest.d.ts +10 -0
- package/dist/steps/functions/internalMaestroTest.js +385 -0
- package/dist/steps/functions/internalMaestroTest.js.map +1 -0
- package/dist/steps/functions/startAndroidEmulator.js +22 -142
- package/dist/steps/functions/startAndroidEmulator.js.map +1 -1
- package/dist/steps/functions/startIosSimulator.js +35 -72
- package/dist/steps/functions/startIosSimulator.js.map +1 -1
- package/dist/utils/AndroidEmulatorUtils.d.ts +63 -0
- package/dist/utils/AndroidEmulatorUtils.js +260 -0
- package/dist/utils/AndroidEmulatorUtils.js.map +1 -0
- package/dist/utils/IosSimulatorUtils.d.ts +68 -0
- package/dist/utils/IosSimulatorUtils.js +122 -0
- package/dist/utils/IosSimulatorUtils.js.map +1 -0
- package/package.json +6 -4
|
@@ -4,13 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createStartAndroidEmulatorBuildFunction = void 0;
|
|
7
|
-
const assert_1 = __importDefault(require("assert"));
|
|
8
|
-
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
-
const logger_1 = require("@expo/logger");
|
|
10
7
|
const steps_1 = require("@expo/steps");
|
|
11
8
|
const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
|
|
12
9
|
const retry_1 = require("../../utils/retry");
|
|
13
|
-
const
|
|
10
|
+
const AndroidEmulatorUtils_1 = require("../../utils/AndroidEmulatorUtils");
|
|
14
11
|
function createStartAndroidEmulatorBuildFunction() {
|
|
15
12
|
return new steps_1.BuildFunction({
|
|
16
13
|
namespace: 'eas',
|
|
@@ -31,7 +28,7 @@ function createStartAndroidEmulatorBuildFunction() {
|
|
|
31
28
|
steps_1.BuildStepInput.createProvider({
|
|
32
29
|
id: 'system_image_package',
|
|
33
30
|
required: false,
|
|
34
|
-
defaultValue: defaultSystemImagePackage,
|
|
31
|
+
defaultValue: AndroidEmulatorUtils_1.AndroidEmulatorUtils.defaultSystemImagePackage,
|
|
35
32
|
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
36
33
|
}),
|
|
37
34
|
steps_1.BuildStepInput.createProvider({
|
|
@@ -42,9 +39,9 @@ function createStartAndroidEmulatorBuildFunction() {
|
|
|
42
39
|
}),
|
|
43
40
|
],
|
|
44
41
|
fn: async ({ logger }, { inputs, env }) => {
|
|
45
|
-
var _a
|
|
42
|
+
var _a;
|
|
46
43
|
try {
|
|
47
|
-
const availableDevices = await
|
|
44
|
+
const availableDevices = await AndroidEmulatorUtils_1.AndroidEmulatorUtils.getAvailableDevicesAsync({ env });
|
|
48
45
|
logger.info(`Available Android devices:\n- ${availableDevices.join(`\n- `)}`);
|
|
49
46
|
}
|
|
50
47
|
catch (error) {
|
|
@@ -71,35 +68,23 @@ function createStartAndroidEmulatorBuildFunction() {
|
|
|
71
68
|
},
|
|
72
69
|
});
|
|
73
70
|
logger.info('Creating emulator device');
|
|
74
|
-
|
|
75
|
-
'create',
|
|
76
|
-
'avd',
|
|
77
|
-
'--name',
|
|
71
|
+
await AndroidEmulatorUtils_1.AndroidEmulatorUtils.createAsync({
|
|
78
72
|
deviceName,
|
|
79
|
-
'--package',
|
|
80
73
|
systemImagePackage,
|
|
81
|
-
|
|
82
|
-
...(deviceIdentifier ? ['--device', deviceIdentifier] : []),
|
|
83
|
-
], {
|
|
74
|
+
deviceIdentifier: deviceIdentifier !== null && deviceIdentifier !== void 0 ? deviceIdentifier : null,
|
|
84
75
|
env,
|
|
85
|
-
stdio: 'pipe',
|
|
86
76
|
});
|
|
87
|
-
// `avdmanager create` always asks about creating a custom hardware profile.
|
|
88
|
-
// > Do you wish to create a custom hardware profile? [no]
|
|
89
|
-
// We answer "no".
|
|
90
|
-
(_a = avdManager.child.stdin) === null || _a === void 0 ? void 0 : _a.write('no');
|
|
91
|
-
(_b = avdManager.child.stdin) === null || _b === void 0 ? void 0 : _b.end();
|
|
92
|
-
await avdManager;
|
|
93
77
|
logger.info('Starting emulator device');
|
|
94
|
-
const { emulatorPromise } = await
|
|
95
|
-
logger.info('Waiting for emulator to become ready');
|
|
96
|
-
const { serialId } = await ensureEmulatorIsReadyAsync({
|
|
78
|
+
const { emulatorPromise, serialId } = await AndroidEmulatorUtils_1.AndroidEmulatorUtils.startAsync({
|
|
97
79
|
deviceName,
|
|
98
80
|
env,
|
|
99
|
-
|
|
81
|
+
});
|
|
82
|
+
await AndroidEmulatorUtils_1.AndroidEmulatorUtils.waitForReadyAsync({
|
|
83
|
+
env,
|
|
84
|
+
serialId,
|
|
100
85
|
});
|
|
101
86
|
logger.info(`${deviceName} is ready.`);
|
|
102
|
-
const count = Number((
|
|
87
|
+
const count = Number((_a = inputs.count.value) !== null && _a !== void 0 ? _a : 1);
|
|
103
88
|
if (count > 1) {
|
|
104
89
|
logger.info(`Requested ${count} emulators, shutting down ${deviceName} for cloning.`);
|
|
105
90
|
await (0, turtle_spawn_1.default)('adb', ['-s', serialId, 'shell', 'reboot', '-p'], {
|
|
@@ -111,39 +96,20 @@ function createStartAndroidEmulatorBuildFunction() {
|
|
|
111
96
|
for (let i = 0; i < count; i++) {
|
|
112
97
|
const cloneIdentifier = `eas-simulator-${i + 1}`;
|
|
113
98
|
logger.info(`Cloning ${deviceName} to ${cloneIdentifier}...`);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
119
|
-
await promises_1.default.rm(cloneIniFile, { force: true });
|
|
120
|
-
await promises_1.default.cp(`${process.env.HOME}/.android/avd/${deviceName}.avd`, `${process.env.HOME}/.android/avd/${cloneIdentifier}.avd`, { recursive: true, verbatimSymlinks: true, force: true });
|
|
121
|
-
await promises_1.default.cp(`${process.env.HOME}/.android/avd/${deviceName}.ini`, cloneIniFile, {
|
|
122
|
-
verbatimSymlinks: true,
|
|
123
|
-
force: true,
|
|
99
|
+
await AndroidEmulatorUtils_1.AndroidEmulatorUtils.cloneAsync({
|
|
100
|
+
sourceDeviceName: deviceName,
|
|
101
|
+
destinationDeviceName: cloneIdentifier,
|
|
102
|
+
env,
|
|
124
103
|
});
|
|
125
|
-
const filesToReplaceDeviceNameIn = (await (0, steps_1.spawnAsync)('grep', [
|
|
126
|
-
'--binary-files=without-match',
|
|
127
|
-
'--recursive',
|
|
128
|
-
'--files-with-matches',
|
|
129
|
-
`${deviceName}`,
|
|
130
|
-
`${process.env.HOME}/.android/avd/${cloneIdentifier}.avd`,
|
|
131
|
-
])).stdout
|
|
132
|
-
.split('\n')
|
|
133
|
-
.filter((file) => file !== '');
|
|
134
|
-
for (const file of [...filesToReplaceDeviceNameIn, cloneIniFile]) {
|
|
135
|
-
const txtFile = await promises_1.default.readFile(file, 'utf-8');
|
|
136
|
-
const replaceRegex = new RegExp(`${deviceName}`, 'g');
|
|
137
|
-
const updatedTxtFile = txtFile.replace(replaceRegex, cloneIdentifier);
|
|
138
|
-
await promises_1.default.writeFile(file, updatedTxtFile);
|
|
139
|
-
}
|
|
140
104
|
logger.info('Starting emulator device');
|
|
141
|
-
|
|
142
|
-
logger.info('Waiting for emulator to become ready');
|
|
143
|
-
await ensureEmulatorIsReadyAsync({
|
|
105
|
+
const { serialId } = await AndroidEmulatorUtils_1.AndroidEmulatorUtils.startAsync({
|
|
144
106
|
deviceName: cloneIdentifier,
|
|
145
107
|
env,
|
|
146
|
-
|
|
108
|
+
});
|
|
109
|
+
logger.info('Waiting for emulator to become ready');
|
|
110
|
+
await AndroidEmulatorUtils_1.AndroidEmulatorUtils.waitForReadyAsync({
|
|
111
|
+
serialId,
|
|
112
|
+
env,
|
|
147
113
|
});
|
|
148
114
|
logger.info(`${cloneIdentifier} is ready.`);
|
|
149
115
|
}
|
|
@@ -152,90 +118,4 @@ function createStartAndroidEmulatorBuildFunction() {
|
|
|
152
118
|
});
|
|
153
119
|
}
|
|
154
120
|
exports.createStartAndroidEmulatorBuildFunction = createStartAndroidEmulatorBuildFunction;
|
|
155
|
-
async function startAndroidSimulator({ deviceName, env, }) {
|
|
156
|
-
const emulatorPromise = (0, turtle_spawn_1.default)(`${process.env.ANDROID_HOME}/emulator/emulator`, [
|
|
157
|
-
'-no-window',
|
|
158
|
-
'-no-boot-anim',
|
|
159
|
-
'-writable-system',
|
|
160
|
-
'-noaudio',
|
|
161
|
-
'-memory',
|
|
162
|
-
'8192',
|
|
163
|
-
'-no-snapshot-save',
|
|
164
|
-
'-avd',
|
|
165
|
-
deviceName,
|
|
166
|
-
], {
|
|
167
|
-
detached: true,
|
|
168
|
-
stdio: 'inherit',
|
|
169
|
-
env,
|
|
170
|
-
});
|
|
171
|
-
// If emulator fails to start, throw its error.
|
|
172
|
-
if (!emulatorPromise.child.pid) {
|
|
173
|
-
await emulatorPromise;
|
|
174
|
-
}
|
|
175
|
-
emulatorPromise.child.unref();
|
|
176
|
-
// We don't want to await the SpawnPromise here.
|
|
177
|
-
// eslint-disable-next-line @typescript-eslint/return-await
|
|
178
|
-
return { emulatorPromise };
|
|
179
|
-
}
|
|
180
|
-
async function getEmulatorSerialId({ deviceName, env, }) {
|
|
181
|
-
const adbDevices = await (0, turtle_spawn_1.default)('adb', ['devices'], { mode: logger_1.PipeMode.COMBINED, env });
|
|
182
|
-
for (const adbDeviceLine of adbDevices.stdout.split('\n')) {
|
|
183
|
-
if (!adbDeviceLine.startsWith('emulator')) {
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
const matches = adbDeviceLine.match(/^(\S+)/);
|
|
187
|
-
if (!matches) {
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
const [, serialId] = matches;
|
|
191
|
-
// Previously we were using `qemu.uuid` to identify the emulator,
|
|
192
|
-
// but this does not work for newer emulators, because there is
|
|
193
|
-
// a limit on properties and custom properties get ignored.
|
|
194
|
-
// See https://stackoverflow.com/questions/2214377/how-to-get-serial-number-or-id-of-android-emulator-after-it-runs#comment98259121_42038655
|
|
195
|
-
const adbEmuAvdName = await (0, turtle_spawn_1.default)('adb', ['-s', serialId, 'emu', 'avd', 'name'], {
|
|
196
|
-
mode: logger_1.PipeMode.COMBINED,
|
|
197
|
-
env,
|
|
198
|
-
});
|
|
199
|
-
if (adbEmuAvdName.stdout.replace(/\r\n/g, '\n').split('\n')[0] === deviceName) {
|
|
200
|
-
return serialId;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
return null;
|
|
204
|
-
}
|
|
205
|
-
async function ensureEmulatorIsReadyAsync({ deviceName, env, logger, }) {
|
|
206
|
-
const serialId = await (0, retry_1.retryAsync)(async () => {
|
|
207
|
-
const serialId = await getEmulatorSerialId({ deviceName, env });
|
|
208
|
-
(0, assert_1.default)(serialId, `Failed to configure emulator (${deviceName}): emulator with required ID not found.`);
|
|
209
|
-
return serialId;
|
|
210
|
-
}, {
|
|
211
|
-
logger,
|
|
212
|
-
retryOptions: {
|
|
213
|
-
retries: 3 * 60,
|
|
214
|
-
retryIntervalMs: 1000,
|
|
215
|
-
},
|
|
216
|
-
});
|
|
217
|
-
await (0, retry_1.retryAsync)(async () => {
|
|
218
|
-
const { stdout } = await (0, turtle_spawn_1.default)('adb', ['-s', serialId, 'shell', 'getprop', 'sys.boot_completed'], {
|
|
219
|
-
env,
|
|
220
|
-
mode: logger_1.PipeMode.COMBINED,
|
|
221
|
-
});
|
|
222
|
-
if (!stdout.startsWith('1')) {
|
|
223
|
-
throw new Error(`Emulator (${deviceName}) boot has not completed.`);
|
|
224
|
-
}
|
|
225
|
-
}, {
|
|
226
|
-
// Retry every second for 3 minutes.
|
|
227
|
-
retryOptions: {
|
|
228
|
-
retries: 3 * 60,
|
|
229
|
-
retryIntervalMs: 1000,
|
|
230
|
-
},
|
|
231
|
-
});
|
|
232
|
-
return { serialId };
|
|
233
|
-
}
|
|
234
|
-
async function getAvailableEmulatorDevices({ env }) {
|
|
235
|
-
const result = await (0, turtle_spawn_1.default)('avdmanager', ['list', 'device', '--compact', '--null'], {
|
|
236
|
-
env,
|
|
237
|
-
mode: logger_1.PipeMode.COMBINED_AS_STDOUT,
|
|
238
|
-
});
|
|
239
|
-
return result.stdout.split('\0').filter((line) => line !== '');
|
|
240
|
-
}
|
|
241
121
|
//# sourceMappingURL=startAndroidEmulator.js.map
|
|
@@ -1 +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';\nimport fs from 'fs/promises';\n\nimport { PipeMode, bunyan } from '@expo/logger';\nimport {\n BuildFunction,\n BuildStepEnv,\n BuildStepInput,\n BuildStepInputValueTypeName,\n spawnAsync,\n} from '@expo/steps';\nimport spawn, { SpawnPromise, SpawnResult } from '@expo/turtle-spawn';\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: 'device_identifier',\n required: false,\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 BuildStepInput.createProvider({\n id: 'count',\n required: false,\n defaultValue: 1,\n allowedValueTypeName: BuildStepInputValueTypeName.NUMBER,\n }),\n ],\n fn: async ({ logger }, { inputs, env }) => {\n try {\n const availableDevices = await getAvailableEmulatorDevices({ env });\n logger.info(`Available Android devices:\\n- ${availableDevices.join(`\\n- `)}`);\n } catch (error) {\n logger.info('Failed to list available Android devices.', error);\n } finally {\n logger.info('');\n }\n\n const deviceName = `${inputs.device_name.value}`;\n const systemImagePackage = `${inputs.system_image_package.value}`;\n // We can cast because allowedValueTypeName validated this is a string.\n const deviceIdentifier = inputs.device_identifier.value as string | undefined;\n\n logger.info('Making sure system image is installed');\n await retryAsync(\n async () => {\n await spawn('sdkmanager', [systemImagePackage], {\n env,\n logger,\n });\n },\n {\n logger,\n retryOptions: {\n retries: 3, // Retry 3 times\n retryIntervalMs: 1_000,\n },\n }\n );\n\n logger.info('Creating emulator device');\n const avdManager = spawn(\n 'avdmanager',\n [\n 'create',\n 'avd',\n '--name',\n deviceName,\n '--package',\n systemImagePackage,\n '--force',\n ...(deviceIdentifier ? ['--device', deviceIdentifier] : []),\n ],\n {\n env,\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 logger.info('Starting emulator device');\n const { emulatorPromise } = await startAndroidSimulator({ deviceName, env });\n\n logger.info('Waiting for emulator to become ready');\n const { serialId } = await ensureEmulatorIsReadyAsync({\n deviceName,\n env,\n logger,\n });\n\n logger.info(`${deviceName} is ready.`);\n\n const count = Number(inputs.count.value ?? 1);\n if (count > 1) {\n logger.info(`Requested ${count} emulators, shutting down ${deviceName} for cloning.`);\n await spawn('adb', ['-s', serialId, 'shell', 'reboot', '-p'], {\n logger,\n env,\n });\n // Waiting for source emulator to shutdown.\n await emulatorPromise;\n\n for (let i = 0; i < count; i++) {\n const cloneIdentifier = `eas-simulator-${i + 1}`;\n logger.info(`Cloning ${deviceName} to ${cloneIdentifier}...`);\n const cloneIniFile = `${process.env.HOME}/.android/avd/${cloneIdentifier}.ini`;\n\n await fs.rm(`${process.env.HOME}/.android/avd/${cloneIdentifier}.avd`, {\n recursive: true,\n force: true,\n });\n await fs.rm(cloneIniFile, { force: true });\n\n await fs.cp(\n `${process.env.HOME}/.android/avd/${deviceName}.avd`,\n `${process.env.HOME}/.android/avd/${cloneIdentifier}.avd`,\n { recursive: true, verbatimSymlinks: true, force: true }\n );\n\n await fs.cp(`${process.env.HOME}/.android/avd/${deviceName}.ini`, cloneIniFile, {\n verbatimSymlinks: true,\n force: true,\n });\n\n const filesToReplaceDeviceNameIn = (\n await spawnAsync('grep', [\n '--binary-files=without-match',\n '--recursive',\n '--files-with-matches',\n `${deviceName}`,\n `${process.env.HOME}/.android/avd/${cloneIdentifier}.avd`,\n ])\n ).stdout\n .split('\\n')\n .filter((file) => file !== '');\n\n for (const file of [...filesToReplaceDeviceNameIn, cloneIniFile]) {\n const txtFile = await fs.readFile(file, 'utf-8');\n const replaceRegex = new RegExp(`${deviceName}`, 'g');\n const updatedTxtFile = txtFile.replace(replaceRegex, cloneIdentifier);\n await fs.writeFile(file, updatedTxtFile);\n }\n\n logger.info('Starting emulator device');\n await startAndroidSimulator({ deviceName: cloneIdentifier, env });\n\n logger.info('Waiting for emulator to become ready');\n await ensureEmulatorIsReadyAsync({\n deviceName: cloneIdentifier,\n env,\n logger,\n });\n\n logger.info(`${cloneIdentifier} is ready.`);\n }\n }\n },\n });\n}\n\nasync function startAndroidSimulator({\n deviceName,\n env,\n}: {\n deviceName: string;\n env: BuildStepEnv;\n}): Promise<{ emulatorPromise: SpawnPromise<SpawnResult> }> {\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 '-memory',\n '8192',\n '-no-snapshot-save',\n '-avd',\n deviceName,\n ],\n {\n detached: true,\n stdio: 'inherit',\n env,\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 // We don't want to await the SpawnPromise here.\n // eslint-disable-next-line @typescript-eslint/return-await\n return { emulatorPromise };\n}\n\nasync function getEmulatorSerialId({\n deviceName,\n env,\n}: {\n deviceName: string;\n env: BuildStepEnv;\n}): Promise<string | null> {\n const adbDevices = await spawn('adb', ['devices'], { mode: PipeMode.COMBINED, env });\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 // Previously we were using `qemu.uuid` to identify the emulator,\n // but this does not work for newer emulators, because there is\n // a limit on properties and custom properties get ignored.\n // See https://stackoverflow.com/questions/2214377/how-to-get-serial-number-or-id-of-android-emulator-after-it-runs#comment98259121_42038655\n const adbEmuAvdName = await spawn('adb', ['-s', serialId, 'emu', 'avd', 'name'], {\n mode: PipeMode.COMBINED,\n env,\n });\n if (adbEmuAvdName.stdout.replace(/\\r\\n/g, '\\n').split('\\n')[0] === deviceName) {\n return serialId;\n }\n }\n\n return null;\n}\n\nasync function ensureEmulatorIsReadyAsync({\n deviceName,\n env,\n logger,\n}: {\n deviceName: string;\n env: BuildStepEnv;\n logger: bunyan;\n}): Promise<{ serialId: string }> {\n const serialId = await retryAsync(\n async () => {\n const serialId = await getEmulatorSerialId({ deviceName, env });\n assert(\n serialId,\n `Failed to configure emulator (${deviceName}): emulator with required ID not found.`\n );\n return serialId;\n },\n {\n logger,\n retryOptions: {\n retries: 3 * 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 env,\n mode: PipeMode.COMBINED,\n }\n );\n\n if (!stdout.startsWith('1')) {\n throw new Error(`Emulator (${deviceName}) 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 return { serialId };\n}\n\nasync function getAvailableEmulatorDevices({ env }: { env: BuildStepEnv }): Promise<string[]> {\n const result = await spawn('avdmanager', ['list', 'device', '--compact', '--null'], {\n env,\n mode: PipeMode.COMBINED_AS_STDOUT,\n });\n return result.stdout.split('\\0').filter((line) => line !== '');\n}\n"]}
|
|
1
|
+
{"version":3,"file":"startAndroidEmulator.js","sourceRoot":"","sources":["../../../src/steps/functions/startAndroidEmulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { BuildFunction, BuildStepInput, BuildStepInputValueTypeName } from '@expo/steps';\nimport spawn from '@expo/turtle-spawn';\n\nimport { retryAsync } from '../../utils/retry';\nimport {\n AndroidDeviceName,\n AndroidEmulatorUtils,\n AndroidVirtualDeviceName,\n} from '../../utils/AndroidEmulatorUtils';\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: 'device_identifier',\n required: false,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n BuildStepInput.createProvider({\n id: 'system_image_package',\n required: false,\n defaultValue: AndroidEmulatorUtils.defaultSystemImagePackage,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n BuildStepInput.createProvider({\n id: 'count',\n required: false,\n defaultValue: 1,\n allowedValueTypeName: BuildStepInputValueTypeName.NUMBER,\n }),\n ],\n fn: async ({ logger }, { inputs, env }) => {\n try {\n const availableDevices = await AndroidEmulatorUtils.getAvailableDevicesAsync({ env });\n logger.info(`Available Android devices:\\n- ${availableDevices.join(`\\n- `)}`);\n } catch (error) {\n logger.info('Failed to list available Android devices.', error);\n } finally {\n logger.info('');\n }\n\n const deviceName = `${inputs.device_name.value}` as AndroidVirtualDeviceName;\n const systemImagePackage = `${inputs.system_image_package.value}`;\n // We can cast because allowedValueTypeName validated this is a string.\n const deviceIdentifier = inputs.device_identifier.value as AndroidDeviceName | undefined;\n\n logger.info('Making sure system image is installed');\n await retryAsync(\n async () => {\n await spawn('sdkmanager', [systemImagePackage], {\n env,\n logger,\n });\n },\n {\n logger,\n retryOptions: {\n retries: 3, // Retry 3 times\n retryIntervalMs: 1_000,\n },\n }\n );\n\n logger.info('Creating emulator device');\n await AndroidEmulatorUtils.createAsync({\n deviceName,\n systemImagePackage,\n deviceIdentifier: deviceIdentifier ?? null,\n env,\n });\n\n logger.info('Starting emulator device');\n const { emulatorPromise, serialId } = await AndroidEmulatorUtils.startAsync({\n deviceName,\n env,\n });\n await AndroidEmulatorUtils.waitForReadyAsync({\n env,\n serialId,\n });\n logger.info(`${deviceName} is ready.`);\n\n const count = Number(inputs.count.value ?? 1);\n if (count > 1) {\n logger.info(`Requested ${count} emulators, shutting down ${deviceName} for cloning.`);\n await spawn('adb', ['-s', serialId, 'shell', 'reboot', '-p'], {\n logger,\n env,\n });\n // Waiting for source emulator to shutdown.\n await emulatorPromise;\n\n for (let i = 0; i < count; i++) {\n const cloneIdentifier = `eas-simulator-${i + 1}` as AndroidVirtualDeviceName;\n logger.info(`Cloning ${deviceName} to ${cloneIdentifier}...`);\n await AndroidEmulatorUtils.cloneAsync({\n sourceDeviceName: deviceName,\n destinationDeviceName: cloneIdentifier,\n env,\n });\n\n logger.info('Starting emulator device');\n const { serialId } = await AndroidEmulatorUtils.startAsync({\n deviceName: cloneIdentifier,\n env,\n });\n\n logger.info('Waiting for emulator to become ready');\n await AndroidEmulatorUtils.waitForReadyAsync({\n serialId,\n env,\n });\n\n logger.info(`${cloneIdentifier} is ready.`);\n }\n }\n },\n });\n}\n"]}
|
|
@@ -4,11 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createStartIosSimulatorBuildFunction = void 0;
|
|
7
|
-
const logger_1 = require("@expo/logger");
|
|
8
7
|
const steps_1 = require("@expo/steps");
|
|
9
8
|
const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
|
|
10
9
|
const lodash_1 = require("lodash");
|
|
11
|
-
const
|
|
10
|
+
const IosSimulatorUtils_1 = require("../../utils/IosSimulatorUtils");
|
|
12
11
|
function createStartIosSimulatorBuildFunction() {
|
|
13
12
|
return new steps_1.BuildFunction({
|
|
14
13
|
namespace: 'eas',
|
|
@@ -28,11 +27,14 @@ function createStartIosSimulatorBuildFunction() {
|
|
|
28
27
|
}),
|
|
29
28
|
],
|
|
30
29
|
fn: async ({ logger }, { inputs, env }) => {
|
|
31
|
-
var _a, _b, _c
|
|
30
|
+
var _a, _b, _c;
|
|
32
31
|
try {
|
|
33
|
-
const availableDevices = await
|
|
32
|
+
const availableDevices = await IosSimulatorUtils_1.IosSimulatorUtils.getAvailableDevicesAsync({
|
|
33
|
+
env,
|
|
34
|
+
filter: 'available',
|
|
35
|
+
});
|
|
34
36
|
logger.info(`Available Simulator devices:\n- ${availableDevices
|
|
35
|
-
.map(
|
|
37
|
+
.map((device) => device.displayName)
|
|
36
38
|
.join(`\n- `)}`);
|
|
37
39
|
}
|
|
38
40
|
catch (error) {
|
|
@@ -41,60 +43,44 @@ function createStartIosSimulatorBuildFunction() {
|
|
|
41
43
|
finally {
|
|
42
44
|
logger.info('');
|
|
43
45
|
}
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
+
const deviceIdentifierInput = (_a = inputs.device_identifier.value) === null || _a === void 0 ? void 0 : _a.toString();
|
|
47
|
+
const originalDeviceIdentifier = deviceIdentifierInput !== null && deviceIdentifierInput !== void 0 ? deviceIdentifierInput : (await findMostGenericIphoneUuidAsync({ env }));
|
|
48
|
+
if (!originalDeviceIdentifier) {
|
|
46
49
|
throw new Error('Could not find an iPhone among available simulator devices.');
|
|
47
50
|
}
|
|
48
|
-
const
|
|
49
|
-
|
|
51
|
+
const { udid } = await IosSimulatorUtils_1.IosSimulatorUtils.startAsync({
|
|
52
|
+
deviceIdentifier: originalDeviceIdentifier,
|
|
50
53
|
env,
|
|
51
54
|
});
|
|
52
|
-
await (
|
|
53
|
-
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'io', deviceIdentifier, 'screenshot', '/dev/null'], {
|
|
54
|
-
env,
|
|
55
|
-
});
|
|
56
|
-
}, {
|
|
57
|
-
retryOptions: {
|
|
58
|
-
// There's 30 * 60 seconds in 30 minutes, which is the timeout.
|
|
59
|
-
retries: 30 * 60,
|
|
60
|
-
retryIntervalMs: 1000,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
55
|
+
await IosSimulatorUtils_1.IosSimulatorUtils.waitForReadyAsync({ udid, env });
|
|
63
56
|
logger.info('');
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const formattedDevice = device ? formatSimulatorDevice(device) : deviceIdentifier;
|
|
57
|
+
const device = await IosSimulatorUtils_1.IosSimulatorUtils.getDeviceAsync({ udid, env });
|
|
58
|
+
const formattedDevice = (_b = device === null || device === void 0 ? void 0 : device.displayName) !== null && _b !== void 0 ? _b : originalDeviceIdentifier;
|
|
67
59
|
logger.info(`${formattedDevice} is ready.`);
|
|
68
|
-
const count = Number((
|
|
60
|
+
const count = Number((_c = inputs.count.value) !== null && _c !== void 0 ? _c : 1);
|
|
69
61
|
if (count > 1) {
|
|
70
62
|
logger.info(`Requested ${count} Simulators, shutting down ${formattedDevice} for cloning.`);
|
|
71
|
-
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'shutdown',
|
|
63
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'shutdown', originalDeviceIdentifier], {
|
|
72
64
|
logger,
|
|
73
65
|
env,
|
|
74
66
|
});
|
|
75
67
|
for (let i = 0; i < count; i++) {
|
|
76
|
-
const
|
|
77
|
-
logger.info(`Cloning ${formattedDevice} to ${
|
|
78
|
-
await
|
|
79
|
-
|
|
68
|
+
const cloneDeviceName = `eas-simulator-${i + 1}`;
|
|
69
|
+
logger.info(`Cloning ${formattedDevice} to ${cloneDeviceName}...`);
|
|
70
|
+
await IosSimulatorUtils_1.IosSimulatorUtils.cloneAsync({
|
|
71
|
+
sourceDeviceIdentifier: originalDeviceIdentifier,
|
|
72
|
+
destinationDeviceName: cloneDeviceName,
|
|
80
73
|
env,
|
|
81
74
|
});
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
const { udid: cloneUdid } = await IosSimulatorUtils_1.IosSimulatorUtils.startAsync({
|
|
76
|
+
deviceIdentifier: cloneDeviceName,
|
|
84
77
|
env,
|
|
85
78
|
});
|
|
86
|
-
await
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
});
|
|
90
|
-
}, {
|
|
91
|
-
retryOptions: {
|
|
92
|
-
// There's 30 * 60 seconds in 30 minutes, which is the timeout.
|
|
93
|
-
retries: 30 * 60,
|
|
94
|
-
retryIntervalMs: 1000,
|
|
95
|
-
},
|
|
79
|
+
await IosSimulatorUtils_1.IosSimulatorUtils.waitForReadyAsync({
|
|
80
|
+
udid: cloneUdid,
|
|
81
|
+
env,
|
|
96
82
|
});
|
|
97
|
-
logger.info(`${
|
|
83
|
+
logger.info(`${cloneDeviceName} is ready.`);
|
|
98
84
|
logger.info('');
|
|
99
85
|
}
|
|
100
86
|
}
|
|
@@ -102,38 +88,15 @@ function createStartIosSimulatorBuildFunction() {
|
|
|
102
88
|
});
|
|
103
89
|
}
|
|
104
90
|
exports.createStartIosSimulatorBuildFunction = createStartIosSimulatorBuildFunction;
|
|
105
|
-
async function
|
|
106
|
-
const availableSimulatorDevices = await getAvailableSimulatorDevices({ env });
|
|
107
|
-
const availableIphones = availableSimulatorDevices.filter((device) => device.name.startsWith('iPhone'));
|
|
108
|
-
// It's funny, but it works.
|
|
109
|
-
const iphoneWithShortestName = (0, lodash_1.minBy)(availableIphones, (device) => device.name.length);
|
|
110
|
-
return iphoneWithShortestName !== null && iphoneWithShortestName !== void 0 ? iphoneWithShortestName : null;
|
|
111
|
-
}
|
|
112
|
-
function formatSimulatorDevice(device) {
|
|
113
|
-
return `${device.name} (${device.udid}) on ${device.runtime}`;
|
|
114
|
-
}
|
|
115
|
-
function parseUdidFromBootstatusStdout(stdout) {
|
|
116
|
-
const matches = stdout.match(/^Monitoring boot status for .+ \((.+)\)\.$/m);
|
|
117
|
-
if (!matches) {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
return matches[1];
|
|
121
|
-
}
|
|
122
|
-
async function getSimulatorDevice({ udid, env, }) {
|
|
91
|
+
async function findMostGenericIphoneUuidAsync({ env, }) {
|
|
123
92
|
var _a;
|
|
124
|
-
const
|
|
125
|
-
return (_a = devices.find((device) => device.udid === udid)) !== null && _a !== void 0 ? _a : null;
|
|
126
|
-
}
|
|
127
|
-
async function getAvailableSimulatorDevices({ env, }) {
|
|
128
|
-
const result = await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'list', 'devices', '--json', '--no-escape-slashes', 'available'], {
|
|
93
|
+
const availableSimulatorDevices = await IosSimulatorUtils_1.IosSimulatorUtils.getAvailableDevicesAsync({
|
|
129
94
|
env,
|
|
130
|
-
|
|
95
|
+
filter: 'available',
|
|
131
96
|
});
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
return allAvailableDevices;
|
|
97
|
+
const availableIphones = availableSimulatorDevices.filter((device) => device.name.startsWith('iPhone'));
|
|
98
|
+
// It's funny, but it works.
|
|
99
|
+
const iphoneWithShortestName = (0, lodash_1.minBy)(availableIphones, (device) => device.name.length);
|
|
100
|
+
return (_a = iphoneWithShortestName === null || iphoneWithShortestName === void 0 ? void 0 : iphoneWithShortestName.udid) !== null && _a !== void 0 ? _a : null;
|
|
138
101
|
}
|
|
139
102
|
//# sourceMappingURL=startIosSimulator.js.map
|
|
@@ -1 +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 {\n BuildFunction,\n BuildStepEnv,\n BuildStepInput,\n BuildStepInputValueTypeName,\n} 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 BuildStepInput.createProvider({\n id: 'count',\n required: false,\n defaultValue: 1,\n allowedValueTypeName: BuildStepInputValueTypeName.NUMBER,\n }),\n ],\n fn: async ({ logger }, { inputs, env }) => {\n try {\n const availableDevices = await getAvailableSimulatorDevices({ env });\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({ env }))?.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 env,\n }\n );\n\n await retryAsync(\n async () => {\n await spawn('xcrun', ['simctl', 'io', deviceIdentifier, 'screenshot', '/dev/null'], {\n env,\n });\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, env }) : null;\n const formattedDevice = device ? formatSimulatorDevice(device) : deviceIdentifier;\n logger.info(`${formattedDevice} is ready.`);\n\n const count = Number(inputs.count.value ?? 1);\n if (count > 1) {\n logger.info(`Requested ${count} Simulators, shutting down ${formattedDevice} for cloning.`);\n await spawn('xcrun', ['simctl', 'shutdown', deviceIdentifier], {\n logger,\n env,\n });\n\n for (let i = 0; i < count; i++) {\n const cloneIdentifier = `eas-simulator-${i + 1}`;\n logger.info(`Cloning ${formattedDevice} to ${cloneIdentifier}...`);\n\n await spawn('xcrun', ['simctl', 'clone', deviceIdentifier, cloneIdentifier], {\n logger,\n env,\n });\n\n await spawn('xcrun', ['simctl', 'bootstatus', cloneIdentifier, '-b'], {\n logger,\n env,\n });\n\n await retryAsync(\n async () => {\n await spawn('xcrun', ['simctl', 'io', cloneIdentifier, 'screenshot', '/dev/null'], {\n env,\n });\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(`${cloneIdentifier} is ready.`);\n logger.info('');\n }\n }\n },\n });\n}\n\nasync function findMostGenericIphone({\n env,\n}: {\n env: BuildStepEnv;\n}): Promise<AvailableXcrunSimctlDevice | null> {\n const availableSimulatorDevices = await getAvailableSimulatorDevices({ env });\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({\n udid,\n env,\n}: {\n udid: string;\n env: BuildStepEnv;\n}): Promise<SimulatorDevice | null> {\n const devices = await getAvailableSimulatorDevices({ env });\n return devices.find((device) => device.udid === udid) ?? null;\n}\n\nasync function getAvailableSimulatorDevices({\n env,\n}: {\n env: BuildStepEnv;\n}): Promise<SimulatorDevice[]> {\n const result = await spawn(\n 'xcrun',\n ['simctl', 'list', 'devices', '--json', '--no-escape-slashes', 'available'],\n {\n env,\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"]}
|
|
1
|
+
{"version":3,"file":"startIosSimulator.js","sourceRoot":"","sources":["../../../src/steps/functions/startIosSimulator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BuildFunction,\n BuildStepEnv,\n BuildStepInput,\n BuildStepInputValueTypeName,\n} from '@expo/steps';\nimport spawn from '@expo/turtle-spawn';\nimport { minBy } from 'lodash';\n\nimport {\n IosSimulatorName,\n IosSimulatorUtils,\n IosSimulatorUuid,\n} from '../../utils/IosSimulatorUtils';\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 BuildStepInput.createProvider({\n id: 'count',\n required: false,\n defaultValue: 1,\n allowedValueTypeName: BuildStepInputValueTypeName.NUMBER,\n }),\n ],\n fn: async ({ logger }, { inputs, env }) => {\n try {\n const availableDevices = await IosSimulatorUtils.getAvailableDevicesAsync({\n env,\n filter: 'available',\n });\n logger.info(\n `Available Simulator devices:\\n- ${availableDevices\n .map((device) => device.displayName)\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 deviceIdentifierInput = inputs.device_identifier.value?.toString() as\n | IosSimulatorUuid\n | IosSimulatorName\n | undefined;\n const originalDeviceIdentifier =\n deviceIdentifierInput ?? (await findMostGenericIphoneUuidAsync({ env }));\n\n if (!originalDeviceIdentifier) {\n throw new Error('Could not find an iPhone among available simulator devices.');\n }\n\n const { udid } = await IosSimulatorUtils.startAsync({\n deviceIdentifier: originalDeviceIdentifier,\n env,\n });\n\n await IosSimulatorUtils.waitForReadyAsync({ udid, env });\n\n logger.info('');\n\n const device = await IosSimulatorUtils.getDeviceAsync({ udid, env });\n const formattedDevice = device?.displayName ?? originalDeviceIdentifier;\n logger.info(`${formattedDevice} is ready.`);\n\n const count = Number(inputs.count.value ?? 1);\n if (count > 1) {\n logger.info(`Requested ${count} Simulators, shutting down ${formattedDevice} for cloning.`);\n await spawn('xcrun', ['simctl', 'shutdown', originalDeviceIdentifier], {\n logger,\n env,\n });\n\n for (let i = 0; i < count; i++) {\n const cloneDeviceName = `eas-simulator-${i + 1}` as IosSimulatorName;\n logger.info(`Cloning ${formattedDevice} to ${cloneDeviceName}...`);\n\n await IosSimulatorUtils.cloneAsync({\n sourceDeviceIdentifier: originalDeviceIdentifier,\n destinationDeviceName: cloneDeviceName,\n env,\n });\n\n const { udid: cloneUdid } = await IosSimulatorUtils.startAsync({\n deviceIdentifier: cloneDeviceName,\n env,\n });\n\n await IosSimulatorUtils.waitForReadyAsync({\n udid: cloneUdid,\n env,\n });\n\n logger.info(`${cloneDeviceName} is ready.`);\n logger.info('');\n }\n }\n },\n });\n}\n\nasync function findMostGenericIphoneUuidAsync({\n env,\n}: {\n env: BuildStepEnv;\n}): Promise<IosSimulatorUuid | null> {\n const availableSimulatorDevices = await IosSimulatorUtils.getAvailableDevicesAsync({\n env,\n filter: 'available',\n });\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?.udid ?? null;\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { SpawnPromise, SpawnResult } from '@expo/turtle-spawn';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
/** Android Virtual Device is the device we run. */
|
|
5
|
+
export type AndroidVirtualDeviceName = string & z.BRAND<'AndroidVirtualDeviceName'>;
|
|
6
|
+
/** Android device is configuration for the AVD -- screen size, etc. */
|
|
7
|
+
export type AndroidDeviceName = string & z.BRAND<'AndroidDeviceName'>;
|
|
8
|
+
export type AndroidDeviceSerialId = string & z.BRAND<'AndroidDeviceSerialId'>;
|
|
9
|
+
export declare namespace AndroidEmulatorUtils {
|
|
10
|
+
const defaultSystemImagePackage: string;
|
|
11
|
+
function getAvailableDevicesAsync({ env, }: {
|
|
12
|
+
env: NodeJS.ProcessEnv;
|
|
13
|
+
}): Promise<AndroidDeviceName[]>;
|
|
14
|
+
function getAttachedDevicesAsync({ env, }: {
|
|
15
|
+
env: NodeJS.ProcessEnv;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
serialId: AndroidDeviceSerialId;
|
|
18
|
+
state: 'offline' | 'device';
|
|
19
|
+
}[]>;
|
|
20
|
+
function getSerialIdAsync({ deviceName, env, }: {
|
|
21
|
+
deviceName: AndroidVirtualDeviceName;
|
|
22
|
+
env: NodeJS.ProcessEnv;
|
|
23
|
+
}): Promise<AndroidDeviceSerialId | null>;
|
|
24
|
+
function createAsync({ deviceName, systemImagePackage, deviceIdentifier, env, }: {
|
|
25
|
+
deviceName: AndroidVirtualDeviceName;
|
|
26
|
+
systemImagePackage: string;
|
|
27
|
+
deviceIdentifier: AndroidDeviceName | null;
|
|
28
|
+
env: NodeJS.ProcessEnv;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
function cloneAsync({ sourceDeviceName, destinationDeviceName, env, }: {
|
|
31
|
+
sourceDeviceName: AndroidVirtualDeviceName;
|
|
32
|
+
destinationDeviceName: AndroidVirtualDeviceName;
|
|
33
|
+
env: NodeJS.ProcessEnv;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
function startAsync({ deviceName, env, }: {
|
|
36
|
+
deviceName: AndroidVirtualDeviceName;
|
|
37
|
+
env: NodeJS.ProcessEnv;
|
|
38
|
+
}): Promise<{
|
|
39
|
+
emulatorPromise: SpawnPromise<SpawnResult>;
|
|
40
|
+
serialId: AndroidDeviceSerialId;
|
|
41
|
+
}>;
|
|
42
|
+
function waitForReadyAsync({ serialId, env, }: {
|
|
43
|
+
serialId: AndroidDeviceSerialId;
|
|
44
|
+
env: NodeJS.ProcessEnv;
|
|
45
|
+
}): Promise<void>;
|
|
46
|
+
function deleteAsync({ serialId, env, }: {
|
|
47
|
+
serialId: AndroidDeviceSerialId;
|
|
48
|
+
env: NodeJS.ProcessEnv;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
function startScreenRecordingAsync({ serialId, env, }: {
|
|
51
|
+
serialId: AndroidDeviceSerialId;
|
|
52
|
+
env: NodeJS.ProcessEnv;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
recordingSpawn: SpawnPromise<SpawnResult>;
|
|
55
|
+
}>;
|
|
56
|
+
function stopScreenRecordingAsync({ serialId, recordingSpawn, env, }: {
|
|
57
|
+
serialId: AndroidDeviceSerialId;
|
|
58
|
+
recordingSpawn: SpawnPromise<SpawnResult>;
|
|
59
|
+
env: NodeJS.ProcessEnv;
|
|
60
|
+
}): Promise<{
|
|
61
|
+
outputPath: string;
|
|
62
|
+
}>;
|
|
63
|
+
}
|