@expo/build-tools 1.0.174 → 1.0.176
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.
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createStartAndroidEmulatorBuildFunction = void 0;
|
|
7
7
|
const assert_1 = __importDefault(require("assert"));
|
|
8
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
9
|
const logger_1 = require("@expo/logger");
|
|
9
10
|
const steps_1 = require("@expo/steps");
|
|
10
11
|
const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
|
|
@@ -29,9 +30,15 @@ function createStartAndroidEmulatorBuildFunction() {
|
|
|
29
30
|
defaultValue: defaultSystemImagePackage,
|
|
30
31
|
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
31
32
|
}),
|
|
33
|
+
steps_1.BuildStepInput.createProvider({
|
|
34
|
+
id: 'count',
|
|
35
|
+
required: false,
|
|
36
|
+
defaultValue: 1,
|
|
37
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.NUMBER,
|
|
38
|
+
}),
|
|
32
39
|
],
|
|
33
40
|
fn: async ({ logger }, { inputs, env }) => {
|
|
34
|
-
var _a, _b;
|
|
41
|
+
var _a, _b, _c;
|
|
35
42
|
const deviceName = `${inputs.device_name.value}`;
|
|
36
43
|
const systemImagePackage = `${inputs.system_image_package.value}`;
|
|
37
44
|
logger.info('Making sure system image is installed');
|
|
@@ -60,36 +67,66 @@ function createStartAndroidEmulatorBuildFunction() {
|
|
|
60
67
|
await avdManager;
|
|
61
68
|
const qemuPropId = (0, uuid_1.v4)();
|
|
62
69
|
logger.info('Starting emulator device');
|
|
63
|
-
await startAndroidSimulator({ deviceName, qemuPropId, env });
|
|
70
|
+
const { emulatorPromise } = await startAndroidSimulator({ deviceName, qemuPropId, env });
|
|
64
71
|
logger.info('Waiting for emulator to become ready');
|
|
65
|
-
const serialId = await (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}, {
|
|
72
|
+
const { serialId } = await ensureEmulatorIsReadyAsync({
|
|
73
|
+
deviceName,
|
|
74
|
+
qemuPropId,
|
|
75
|
+
env,
|
|
70
76
|
logger,
|
|
71
|
-
retryOptions: {
|
|
72
|
-
// Emulators usually take 30 second tops to boot.
|
|
73
|
-
retries: 60,
|
|
74
|
-
retryIntervalMs: 1000,
|
|
75
|
-
},
|
|
76
77
|
});
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
logger.info(`${deviceName} is ready.`);
|
|
79
|
+
const count = Number((_c = inputs.count.value) !== null && _c !== void 0 ? _c : 1);
|
|
80
|
+
if (count > 1) {
|
|
81
|
+
logger.info(`Requested ${count} emulators, shutting down ${deviceName} for cloning.`);
|
|
82
|
+
await (0, turtle_spawn_1.default)('adb', ['-s', serialId, 'shell', 'reboot', '-p'], {
|
|
83
|
+
logger,
|
|
79
84
|
env,
|
|
80
|
-
mode: logger_1.PipeMode.COMBINED,
|
|
81
85
|
});
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
// Waiting for source emulator to shutdown.
|
|
87
|
+
await emulatorPromise;
|
|
88
|
+
for (let i = 0; i < count; i++) {
|
|
89
|
+
const cloneIdentifier = `eas-simulator-${i + 1}`;
|
|
90
|
+
logger.info(`Cloning ${deviceName} to ${cloneIdentifier}...`);
|
|
91
|
+
const cloneIniFile = `${process.env.HOME}/.android/avd/${cloneIdentifier}.ini`;
|
|
92
|
+
await promises_1.default.rm(`${process.env.HOME}/.android/avd/${cloneIdentifier}.avd`, {
|
|
93
|
+
recursive: true,
|
|
94
|
+
force: true,
|
|
95
|
+
});
|
|
96
|
+
await promises_1.default.rm(cloneIniFile, { force: true });
|
|
97
|
+
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 });
|
|
98
|
+
await promises_1.default.cp(`${process.env.HOME}/.android/avd/${deviceName}.ini`, cloneIniFile, {
|
|
99
|
+
verbatimSymlinks: true,
|
|
100
|
+
force: true,
|
|
101
|
+
});
|
|
102
|
+
const filesToReplaceDeviceNameIn = (await (0, steps_1.spawnAsync)('grep', [
|
|
103
|
+
'--binary-files=without-match',
|
|
104
|
+
'--recursive',
|
|
105
|
+
'--files-with-matches',
|
|
106
|
+
`${deviceName}`,
|
|
107
|
+
`${process.env.HOME}/.android/avd/${cloneIdentifier}.avd`,
|
|
108
|
+
])).stdout
|
|
109
|
+
.split('\n')
|
|
110
|
+
.filter((file) => file !== '');
|
|
111
|
+
for (const file of [...filesToReplaceDeviceNameIn, cloneIniFile]) {
|
|
112
|
+
const txtFile = await promises_1.default.readFile(file, 'utf-8');
|
|
113
|
+
const replaceRegex = new RegExp(`${deviceName}`, 'g');
|
|
114
|
+
const updatedTxtFile = txtFile.replace(replaceRegex, cloneIdentifier);
|
|
115
|
+
await promises_1.default.writeFile(file, updatedTxtFile);
|
|
116
|
+
}
|
|
117
|
+
const qemuPropId = (0, uuid_1.v4)();
|
|
118
|
+
logger.info('Starting emulator device');
|
|
119
|
+
await startAndroidSimulator({ deviceName: cloneIdentifier, qemuPropId, env });
|
|
120
|
+
logger.info('Waiting for emulator to become ready');
|
|
121
|
+
await ensureEmulatorIsReadyAsync({
|
|
122
|
+
deviceName: cloneIdentifier,
|
|
123
|
+
qemuPropId,
|
|
124
|
+
env,
|
|
125
|
+
logger,
|
|
126
|
+
});
|
|
127
|
+
logger.info(`${cloneIdentifier} is ready.`);
|
|
84
128
|
}
|
|
85
|
-
}
|
|
86
|
-
// Retry every second for 3 minutes.
|
|
87
|
-
retryOptions: {
|
|
88
|
-
retries: 3 * 60,
|
|
89
|
-
retryIntervalMs: 1000,
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
logger.info(`${deviceName} is ready.`);
|
|
129
|
+
}
|
|
93
130
|
},
|
|
94
131
|
});
|
|
95
132
|
}
|
|
@@ -100,13 +137,16 @@ async function startAndroidSimulator({ deviceName, qemuPropId, env, }) {
|
|
|
100
137
|
'-no-boot-anim',
|
|
101
138
|
'-writable-system',
|
|
102
139
|
'-noaudio',
|
|
140
|
+
'-memory',
|
|
141
|
+
'8192',
|
|
142
|
+
'-no-snapshot-save',
|
|
103
143
|
'-avd',
|
|
104
144
|
deviceName,
|
|
105
145
|
'-prop',
|
|
106
146
|
`qemu.uuid=${qemuPropId}`,
|
|
107
147
|
], {
|
|
108
148
|
detached: true,
|
|
109
|
-
stdio: '
|
|
149
|
+
stdio: 'inherit',
|
|
110
150
|
env,
|
|
111
151
|
});
|
|
112
152
|
// If emulator fails to start, throw its error.
|
|
@@ -114,6 +154,9 @@ async function startAndroidSimulator({ deviceName, qemuPropId, env, }) {
|
|
|
114
154
|
await emulatorPromise;
|
|
115
155
|
}
|
|
116
156
|
emulatorPromise.child.unref();
|
|
157
|
+
// We don't want to await the SpawnPromise here.
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/return-await
|
|
159
|
+
return { emulatorPromise };
|
|
117
160
|
}
|
|
118
161
|
async function getEmulatorSerialId({ qemuPropId, env, }) {
|
|
119
162
|
const adbDevices = await (0, turtle_spawn_1.default)('adb', ['devices'], { mode: logger_1.PipeMode.COMBINED, env });
|
|
@@ -136,4 +179,34 @@ async function getEmulatorSerialId({ qemuPropId, env, }) {
|
|
|
136
179
|
}
|
|
137
180
|
return null;
|
|
138
181
|
}
|
|
182
|
+
async function ensureEmulatorIsReadyAsync({ deviceName, qemuPropId, env, logger, }) {
|
|
183
|
+
const serialId = await (0, retry_1.retryAsync)(async () => {
|
|
184
|
+
const serialId = await getEmulatorSerialId({ qemuPropId, env });
|
|
185
|
+
(0, assert_1.default)(serialId, `Failed to configure emulator (${deviceName}): emulator with required ID not found.`);
|
|
186
|
+
return serialId;
|
|
187
|
+
}, {
|
|
188
|
+
logger,
|
|
189
|
+
retryOptions: {
|
|
190
|
+
// Emulators usually take 30 second tops to boot.
|
|
191
|
+
retries: 60,
|
|
192
|
+
retryIntervalMs: 1000,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
await (0, retry_1.retryAsync)(async () => {
|
|
196
|
+
const { stdout } = await (0, turtle_spawn_1.default)('adb', ['-s', serialId, 'shell', 'getprop', 'sys.boot_completed'], {
|
|
197
|
+
env,
|
|
198
|
+
mode: logger_1.PipeMode.COMBINED,
|
|
199
|
+
});
|
|
200
|
+
if (!stdout.startsWith('1')) {
|
|
201
|
+
throw new Error(`Emulator (${deviceName}) boot has not completed.`);
|
|
202
|
+
}
|
|
203
|
+
}, {
|
|
204
|
+
// Retry every second for 3 minutes.
|
|
205
|
+
retryOptions: {
|
|
206
|
+
retries: 3 * 60,
|
|
207
|
+
retryIntervalMs: 1000,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
return { serialId };
|
|
211
|
+
}
|
|
139
212
|
//# 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';\n\nimport { PipeMode } from '@expo/logger';\nimport {\n BuildFunction,\n BuildStepEnv,\n BuildStepInput,\n BuildStepInputValueTypeName,\n} 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, env }) => {\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 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 ['create', 'avd', '--name', deviceName, '--package', systemImagePackage, '--force'],\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 const qemuPropId = uuidv4();\n\n logger.info('Starting emulator device');\n await startAndroidSimulator({ deviceName, qemuPropId, env });\n\n logger.info('Waiting for emulator to become ready');\n const serialId = await retryAsync(\n async () => {\n const serialId = await getEmulatorSerialId({ qemuPropId, env });\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 env,\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 env,\n}: {\n deviceName: string;\n qemuPropId: string;\n env: BuildStepEnv;\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 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\nasync function getEmulatorSerialId({\n qemuPropId,\n env,\n}: {\n qemuPropId: 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 const getProp = await spawn('adb', ['-s', serialId, 'shell', 'getprop', 'qemu.uuid'], {\n mode: PipeMode.COMBINED,\n env,\n });\n if (getProp.stdout.startsWith(qemuPropId)) {\n return serialId;\n }\n }\n\n return null;\n}\n"]}
|
|
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';\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 BuildStepInput.createProvider({\n id: 'count',\n required: false,\n defaultValue: 1,\n allowedValueTypeName: BuildStepInputValueTypeName.NUMBER,\n }),\n ],\n fn: async ({ logger }, { inputs, env }) => {\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 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 ['create', 'avd', '--name', deviceName, '--package', systemImagePackage, '--force'],\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 const qemuPropId = uuidv4();\n\n logger.info('Starting emulator device');\n const { emulatorPromise } = await startAndroidSimulator({ deviceName, qemuPropId, env });\n\n logger.info('Waiting for emulator to become ready');\n const { serialId } = await ensureEmulatorIsReadyAsync({\n deviceName,\n qemuPropId,\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 const qemuPropId = uuidv4();\n\n logger.info('Starting emulator device');\n await startAndroidSimulator({ deviceName: cloneIdentifier, qemuPropId, env });\n\n logger.info('Waiting for emulator to become ready');\n await ensureEmulatorIsReadyAsync({\n deviceName: cloneIdentifier,\n qemuPropId,\n env,\n logger,\n });\n\n logger.info(`${cloneIdentifier} is ready.`);\n }\n }\n },\n });\n}\n\nasync function startAndroidSimulator({\n deviceName,\n qemuPropId,\n env,\n}: {\n deviceName: string;\n qemuPropId: 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 '-prop',\n `qemu.uuid=${qemuPropId}`,\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 qemuPropId,\n env,\n}: {\n qemuPropId: 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 const getProp = await spawn('adb', ['-s', serialId, 'shell', 'getprop', 'qemu.uuid'], {\n mode: PipeMode.COMBINED,\n env,\n });\n if (getProp.stdout.startsWith(qemuPropId)) {\n return serialId;\n }\n }\n\n return null;\n}\n\nasync function ensureEmulatorIsReadyAsync({\n deviceName,\n qemuPropId,\n env,\n logger,\n}: {\n deviceName: string;\n qemuPropId: string;\n env: BuildStepEnv;\n logger: bunyan;\n}): Promise<{ serialId: string }> {\n const serialId = await retryAsync(\n async () => {\n const serialId = await getEmulatorSerialId({ qemuPropId, 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 // 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 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"]}
|
|
@@ -20,9 +20,15 @@ function createStartIosSimulatorBuildFunction() {
|
|
|
20
20
|
required: false,
|
|
21
21
|
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
22
22
|
}),
|
|
23
|
+
steps_1.BuildStepInput.createProvider({
|
|
24
|
+
id: 'count',
|
|
25
|
+
required: false,
|
|
26
|
+
defaultValue: 1,
|
|
27
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.NUMBER,
|
|
28
|
+
}),
|
|
23
29
|
],
|
|
24
30
|
fn: async ({ logger }, { inputs, env }) => {
|
|
25
|
-
var _a, _b, _c;
|
|
31
|
+
var _a, _b, _c, _d;
|
|
26
32
|
try {
|
|
27
33
|
const availableDevices = await getAvailableSimulatorDevices({ env });
|
|
28
34
|
logger.info(`Available Simulator devices:\n- ${availableDevices
|
|
@@ -57,7 +63,41 @@ function createStartIosSimulatorBuildFunction() {
|
|
|
57
63
|
logger.info('');
|
|
58
64
|
const udid = parseUdidFromBootstatusStdout(bootstatusResult.stdout);
|
|
59
65
|
const device = udid ? await getSimulatorDevice({ udid, env }) : null;
|
|
60
|
-
|
|
66
|
+
const formattedDevice = device ? formatSimulatorDevice(device) : deviceIdentifier;
|
|
67
|
+
logger.info(`${formattedDevice} is ready.`);
|
|
68
|
+
const count = Number((_d = inputs.count.value) !== null && _d !== void 0 ? _d : 1);
|
|
69
|
+
if (count > 1) {
|
|
70
|
+
logger.info(`Requested ${count} Simulators, shutting down ${formattedDevice} for cloning.`);
|
|
71
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'shutdown', deviceIdentifier], {
|
|
72
|
+
logger,
|
|
73
|
+
env,
|
|
74
|
+
});
|
|
75
|
+
for (let i = 0; i < count; i++) {
|
|
76
|
+
const cloneIdentifier = `eas-simulator-${i + 1}`;
|
|
77
|
+
logger.info(`Cloning ${formattedDevice} to ${cloneIdentifier}...`);
|
|
78
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'clone', deviceIdentifier, cloneIdentifier], {
|
|
79
|
+
logger,
|
|
80
|
+
env,
|
|
81
|
+
});
|
|
82
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'bootstatus', cloneIdentifier, '-b'], {
|
|
83
|
+
logger,
|
|
84
|
+
env,
|
|
85
|
+
});
|
|
86
|
+
await (0, retry_1.retryAsync)(async () => {
|
|
87
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'io', cloneIdentifier, 'screenshot', '/dev/null'], {
|
|
88
|
+
env,
|
|
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
|
+
},
|
|
96
|
+
});
|
|
97
|
+
logger.info(`${cloneIdentifier} is ready.`);
|
|
98
|
+
logger.info('');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
61
101
|
},
|
|
62
102
|
});
|
|
63
103
|
}
|
|
@@ -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 ],\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 logger.info(`${device ? formatSimulatorDevice(device) : deviceIdentifier} is ready.`);\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 { 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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/build-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.176",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
"node": "20.14.0",
|
|
76
76
|
"yarn": "1.22.21"
|
|
77
77
|
},
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "986319b035bbb22f05aedfb8d45db27971e46b79"
|
|
79
79
|
}
|