@expo/build-tools 1.0.204 → 1.0.205
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.
|
@@ -87,18 +87,28 @@ var AndroidEmulatorUtils;
|
|
|
87
87
|
AndroidEmulatorUtils.createAsync = createAsync;
|
|
88
88
|
async function cloneAsync({ sourceDeviceName, destinationDeviceName, env, logger, }) {
|
|
89
89
|
const cloneIniFile = `${env.HOME}/.android/avd/${destinationDeviceName}.ini`;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
90
|
+
try {
|
|
91
|
+
// Clean destination device files
|
|
92
|
+
await node_fs_1.default.promises.rm(`${env.HOME}/.android/avd/${destinationDeviceName}.avd`, {
|
|
93
|
+
recursive: true,
|
|
94
|
+
force: true,
|
|
95
|
+
});
|
|
96
|
+
await node_fs_1.default.promises.rm(cloneIniFile, { force: true });
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
logger.warn({ err }, `Failed to remove destination device files ${destinationDeviceName}.`);
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
// Remove lockfiles from source device
|
|
103
|
+
const sourceLockfiles = await (0, fast_glob_1.default)('./**/*.lock', {
|
|
104
|
+
cwd: `${env.HOME}/.android/avd/${sourceDeviceName}.avd`,
|
|
105
|
+
absolute: true,
|
|
106
|
+
});
|
|
107
|
+
await Promise.all(sourceLockfiles.map((lockfile) => node_fs_1.default.promises.rm(lockfile, { force: true })));
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
logger.warn({ err }, `Failed to remove lockfiles from source device ${sourceDeviceName}.`);
|
|
111
|
+
}
|
|
102
112
|
// Copy source to destination
|
|
103
113
|
await node_fs_1.default.promises.cp(`${env.HOME}/.android/avd/${sourceDeviceName}.avd`, `${env.HOME}/.android/avd/${destinationDeviceName}.avd`, { recursive: true, verbatimSymlinks: true, force: true });
|
|
104
114
|
await node_fs_1.default.promises.cp(`${env.HOME}/.android/avd/${sourceDeviceName}.ini`, cloneIniFile, {
|
|
@@ -106,11 +116,16 @@ var AndroidEmulatorUtils;
|
|
|
106
116
|
force: true,
|
|
107
117
|
});
|
|
108
118
|
// Remove lockfiles from destination device
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
try {
|
|
120
|
+
const lockfiles = await (0, fast_glob_1.default)('./**/*.lock', {
|
|
121
|
+
cwd: `${env.HOME}/.android/avd/${destinationDeviceName}.avd`,
|
|
122
|
+
absolute: true,
|
|
123
|
+
});
|
|
124
|
+
await Promise.all(lockfiles.map((lockfile) => node_fs_1.default.promises.rm(lockfile, { force: true })));
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
logger.warn({ err }, `Failed to remove lockfiles from destination device ${destinationDeviceName}.`);
|
|
128
|
+
}
|
|
114
129
|
const filesToReplaceDeviceNameIn = // TODO: Test whether we need to use `spawnAsync` here.
|
|
115
130
|
(await (0, turtle_spawn_1.default)('grep', [
|
|
116
131
|
'--binary-files=without-match',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AndroidEmulatorUtils.js","sourceRoot":"","sources":["../../src/utils/AndroidEmulatorUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'assert';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { setTimeout } from 'node:timers/promises';\nimport path from 'node:path';\n\nimport { bunyan } from '@expo/logger';\nimport spawn, { SpawnPromise, SpawnResult } from '@expo/turtle-spawn';\nimport FastGlob from 'fast-glob';\nimport { z } from 'zod';\n\nimport { retryAsync } from './retry';\n\n/** Android Virtual Device is the device we run. */\nexport type AndroidVirtualDeviceName = string & z.BRAND<'AndroidVirtualDeviceName'>;\n/** Android device is configuration for the AVD -- screen size, etc. */\nexport type AndroidDeviceName = string & z.BRAND<'AndroidDeviceName'>;\nexport type AndroidDeviceSerialId = string & z.BRAND<'AndroidDeviceSerialId'>;\n\nexport namespace AndroidEmulatorUtils {\n export const defaultSystemImagePackage = `system-images;android-30;default;${\n process.arch === 'arm64' ? 'arm64-v8a' : 'x86_64'\n }`;\n\n export async function getAvailableDevicesAsync({\n env,\n }: {\n env: NodeJS.ProcessEnv;\n }): Promise<AndroidDeviceName[]> {\n const result = await spawn('avdmanager', ['list', 'device', '--compact', '--null'], { env });\n return result.stdout.split('\\0').filter((line) => line !== '') as AndroidDeviceName[];\n }\n\n export async function getAttachedDevicesAsync({\n env,\n }: {\n env: NodeJS.ProcessEnv;\n }): Promise<{ serialId: AndroidDeviceSerialId; state: 'offline' | 'device' }[]> {\n const result = await spawn('adb', ['devices', '-l'], {\n env,\n });\n return result.stdout\n .replace(/\\r\\n/g, '\\n')\n .split('\\n')\n .filter((line) => line.startsWith('emulator'))\n .map((line) => {\n const [serialId, state] = line.split(/\\s+/) as [\n AndroidDeviceSerialId,\n 'offline' | 'device',\n ];\n return {\n serialId,\n state,\n };\n });\n }\n\n export async function getSerialIdAsync({\n deviceName,\n env,\n }: {\n deviceName: AndroidVirtualDeviceName;\n env: NodeJS.ProcessEnv;\n }): Promise<AndroidDeviceSerialId | null> {\n const adbDevices = await spawn('adb', ['devices'], { 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 env,\n });\n if (adbEmuAvdName.stdout.replace(/\\r\\n/g, '\\n').split('\\n')[0] === deviceName) {\n return serialId as AndroidDeviceSerialId;\n }\n }\n\n return null;\n }\n\n export async function createAsync({\n deviceName,\n systemImagePackage,\n deviceIdentifier,\n env,\n }: {\n deviceName: AndroidVirtualDeviceName;\n systemImagePackage: string;\n deviceIdentifier: AndroidDeviceName | null;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\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\n export async function cloneAsync({\n sourceDeviceName,\n destinationDeviceName,\n env,\n logger,\n }: {\n sourceDeviceName: AndroidVirtualDeviceName;\n destinationDeviceName: AndroidVirtualDeviceName;\n env: NodeJS.ProcessEnv;\n logger: bunyan;\n }): Promise<void> {\n const cloneIniFile = `${env.HOME}/.android/avd/${destinationDeviceName}.ini`;\n\n // Clean destination device files\n await fs.promises.rm(`${env.HOME}/.android/avd/${destinationDeviceName}.avd`, {\n recursive: true,\n force: true,\n });\n await fs.promises.rm(cloneIniFile, { force: true });\n\n // Remove lockfiles from source device\n const sourceLockfiles = await FastGlob('./**/*.lock', {\n cwd: `${env.HOME}/.android/avd/${destinationDeviceName}.avd`,\n absolute: true,\n });\n await Promise.all(sourceLockfiles.map((lockfile) => fs.promises.rm(lockfile, { force: true })));\n\n // Copy source to destination\n await fs.promises.cp(\n `${env.HOME}/.android/avd/${sourceDeviceName}.avd`,\n `${env.HOME}/.android/avd/${destinationDeviceName}.avd`,\n { recursive: true, verbatimSymlinks: true, force: true }\n );\n\n await fs.promises.cp(`${env.HOME}/.android/avd/${sourceDeviceName}.ini`, cloneIniFile, {\n verbatimSymlinks: true,\n force: true,\n });\n\n // Remove lockfiles from destination device\n const lockfiles = await FastGlob('./**/*.lock', {\n cwd: `${env.HOME}/.android/avd/${destinationDeviceName}.avd`,\n absolute: true,\n });\n\n await Promise.all(lockfiles.map((lockfile) => fs.promises.rm(lockfile, { force: true })));\n\n const filesToReplaceDeviceNameIn = // TODO: Test whether we need to use `spawnAsync` here.\n (\n await spawn('grep', [\n '--binary-files=without-match',\n '--recursive',\n '--files-with-matches',\n `${sourceDeviceName}`,\n `${env.HOME}/.android/avd/${destinationDeviceName}.avd`,\n ])\n ).stdout\n .split('\\n')\n .filter((file) => file !== '');\n\n for (const file of [...filesToReplaceDeviceNameIn, cloneIniFile]) {\n try {\n const txtFile = await fs.promises.readFile(file, 'utf-8');\n const replaceRegex = new RegExp(`${sourceDeviceName}`, 'g');\n const updatedTxtFile = txtFile.replace(replaceRegex, destinationDeviceName);\n await fs.promises.writeFile(file, updatedTxtFile);\n } catch (err) {\n logger.warn({ err }, `Failed to replace device name in ${file}.`);\n }\n }\n }\n\n export async function startAsync({\n deviceName,\n env,\n }: {\n deviceName: AndroidVirtualDeviceName;\n env: NodeJS.ProcessEnv;\n }): Promise<{ emulatorPromise: SpawnPromise<SpawnResult>; serialId: AndroidDeviceSerialId }> {\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 ...env,\n // We don't need to wait for emulator to exit gracefully.\n ANDROID_EMULATOR_WAIT_TIME_BEFORE_KILL: '1',\n },\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 const serialId = await retryAsync(\n async () => {\n const serialId = await getSerialIdAsync({ deviceName, env });\n assert(\n serialId,\n `Failed to configure emulator (${serialId}): emulator with required ID not found.`\n );\n return serialId;\n },\n {\n retryOptions: {\n retries: 3 * 60,\n retryIntervalMs: 1_000,\n },\n }\n );\n\n // We don't want to await the SpawnPromise here.\n // eslint-disable-next-line @typescript-eslint/return-await\n return { emulatorPromise, serialId };\n }\n\n export async function waitForReadyAsync({\n serialId,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n await retryAsync(\n async () => {\n const { stdout } = await spawn(\n 'adb',\n ['-s', serialId, 'shell', 'getprop', 'sys.boot_completed'],\n { env }\n );\n\n if (!stdout.startsWith('1')) {\n throw new Error(`Emulator (${serialId}) 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\n export async function collectLogsAsync({\n serialId,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n env: NodeJS.ProcessEnv;\n }): Promise<{ outputPath: string }> {\n const outputDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'android-emulator-logs-'));\n const outputPath = path.join(outputDir, `${serialId}.log`);\n\n // Pipe adb logcat output directly to the file to avoid loading it all into memory\n await new Promise<void>((resolve, reject) => {\n const { child } = spawn('adb', ['-s', serialId, 'logcat', '-d'], {\n env,\n stdio: ['ignore', 'pipe', 'inherit'],\n });\n\n if (!child.stdout) {\n reject(new Error('\"adb logcat\" did not start correctly.'));\n return;\n }\n\n const writeStream = fs.createWriteStream(outputPath);\n child.stdout.pipe(writeStream);\n child.stdout.on('error', reject);\n\n child.on('error', reject);\n writeStream.on('error', reject);\n\n child.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`\"adb logcat\" exited with code ${code}`));\n }\n });\n });\n\n return { outputPath };\n }\n\n export async function deleteAsync({\n serialId,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n const adbEmuAvdName = await spawn('adb', ['-s', serialId, 'emu', 'avd', 'name'], {\n env,\n });\n const deviceName = adbEmuAvdName.stdout.replace(/\\r\\n/g, '\\n').split('\\n')[0];\n\n await spawn('adb', ['-s', serialId, 'emu', 'kill'], { env });\n\n await retryAsync(\n async () => {\n const devices = await getAttachedDevicesAsync({ env });\n if (devices.some((device) => device.serialId === serialId)) {\n throw new Error(`Emulator (${serialId}) is still attached.`);\n }\n },\n {\n retryOptions: {\n retries: 3 * 60,\n retryIntervalMs: 1_000,\n },\n }\n );\n\n await spawn('avdmanager', ['delete', 'avd', '-n', deviceName], { env });\n }\n\n export async function startScreenRecordingAsync({\n serialId,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n env: NodeJS.ProcessEnv;\n }): Promise<{\n recordingSpawn: SpawnPromise<SpawnResult>;\n }> {\n let isReady = false;\n\n // Ensure /sdcard/ is ready to write to. (If the emulator was just booted, it might not be ready yet.)\n for (let i = 0; i < 30; i++) {\n try {\n await spawn('adb', ['-s', serialId, 'shell', 'touch', '/sdcard/.expo-recording-ready'], {\n env,\n });\n isReady = true;\n break;\n } catch {\n await setTimeout(1000);\n }\n }\n\n if (!isReady) {\n throw new Error(`Emulator (${serialId}) filesystem was not ready in time.`);\n }\n\n const screenrecordArgs = [\n '-s',\n serialId,\n 'shell',\n 'screenrecord',\n '--verbose',\n '/sdcard/expo-recording.mp4',\n ];\n\n const screenrecordHelp = await spawn(\n 'adb',\n ['-s', serialId, 'shell', 'screenrecord', '--help'],\n {\n env,\n }\n );\n\n if (screenrecordHelp.stdout.includes('remove the time limit')) {\n screenrecordArgs.push('--time-limit', '0');\n }\n\n const recordingSpawn = spawn('adb', screenrecordArgs, {\n env,\n stdio: 'pipe',\n });\n recordingSpawn.child.unref();\n\n // We are returning the SpawnPromise here, so we don't await it.\n // eslint-disable-next-line @typescript-eslint/return-await\n return {\n recordingSpawn,\n };\n }\n\n export async function stopScreenRecordingAsync({\n serialId,\n recordingSpawn,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n recordingSpawn: SpawnPromise<SpawnResult>;\n env: NodeJS.ProcessEnv;\n }): Promise<{ outputPath: string }> {\n recordingSpawn.child.kill(1);\n\n try {\n await recordingSpawn;\n } catch {\n // do nothing\n }\n\n let isRecordingBusy = true;\n for (let i = 0; i < 30; i++) {\n const lsof = await spawn(\n 'adb',\n ['-s', serialId, 'shell', 'lsof -t /sdcard/expo-recording.mp4'],\n { env }\n );\n if (lsof.stdout.trim() === '') {\n isRecordingBusy = false;\n break;\n }\n await setTimeout(1000);\n }\n\n if (isRecordingBusy) {\n throw new Error(`Recording file is busy.`);\n }\n\n const outputDir = await fs.promises.mkdtemp(\n path.join(os.tmpdir(), 'android-screen-recording-')\n );\n const outputPath = path.join(outputDir, `${serialId}.mp4`);\n\n await spawn('adb', ['-s', serialId, 'pull', '/sdcard/expo-recording.mp4', outputPath], { env });\n\n return { outputPath };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AndroidEmulatorUtils.js","sourceRoot":"","sources":["../../src/utils/AndroidEmulatorUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'assert';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { setTimeout } from 'node:timers/promises';\nimport path from 'node:path';\n\nimport { bunyan } from '@expo/logger';\nimport spawn, { SpawnPromise, SpawnResult } from '@expo/turtle-spawn';\nimport FastGlob from 'fast-glob';\nimport { z } from 'zod';\n\nimport { retryAsync } from './retry';\n\n/** Android Virtual Device is the device we run. */\nexport type AndroidVirtualDeviceName = string & z.BRAND<'AndroidVirtualDeviceName'>;\n/** Android device is configuration for the AVD -- screen size, etc. */\nexport type AndroidDeviceName = string & z.BRAND<'AndroidDeviceName'>;\nexport type AndroidDeviceSerialId = string & z.BRAND<'AndroidDeviceSerialId'>;\n\nexport namespace AndroidEmulatorUtils {\n export const defaultSystemImagePackage = `system-images;android-30;default;${\n process.arch === 'arm64' ? 'arm64-v8a' : 'x86_64'\n }`;\n\n export async function getAvailableDevicesAsync({\n env,\n }: {\n env: NodeJS.ProcessEnv;\n }): Promise<AndroidDeviceName[]> {\n const result = await spawn('avdmanager', ['list', 'device', '--compact', '--null'], { env });\n return result.stdout.split('\\0').filter((line) => line !== '') as AndroidDeviceName[];\n }\n\n export async function getAttachedDevicesAsync({\n env,\n }: {\n env: NodeJS.ProcessEnv;\n }): Promise<{ serialId: AndroidDeviceSerialId; state: 'offline' | 'device' }[]> {\n const result = await spawn('adb', ['devices', '-l'], {\n env,\n });\n return result.stdout\n .replace(/\\r\\n/g, '\\n')\n .split('\\n')\n .filter((line) => line.startsWith('emulator'))\n .map((line) => {\n const [serialId, state] = line.split(/\\s+/) as [\n AndroidDeviceSerialId,\n 'offline' | 'device',\n ];\n return {\n serialId,\n state,\n };\n });\n }\n\n export async function getSerialIdAsync({\n deviceName,\n env,\n }: {\n deviceName: AndroidVirtualDeviceName;\n env: NodeJS.ProcessEnv;\n }): Promise<AndroidDeviceSerialId | null> {\n const adbDevices = await spawn('adb', ['devices'], { 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 env,\n });\n if (adbEmuAvdName.stdout.replace(/\\r\\n/g, '\\n').split('\\n')[0] === deviceName) {\n return serialId as AndroidDeviceSerialId;\n }\n }\n\n return null;\n }\n\n export async function createAsync({\n deviceName,\n systemImagePackage,\n deviceIdentifier,\n env,\n }: {\n deviceName: AndroidVirtualDeviceName;\n systemImagePackage: string;\n deviceIdentifier: AndroidDeviceName | null;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\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\n export async function cloneAsync({\n sourceDeviceName,\n destinationDeviceName,\n env,\n logger,\n }: {\n sourceDeviceName: AndroidVirtualDeviceName;\n destinationDeviceName: AndroidVirtualDeviceName;\n env: NodeJS.ProcessEnv;\n logger: bunyan;\n }): Promise<void> {\n const cloneIniFile = `${env.HOME}/.android/avd/${destinationDeviceName}.ini`;\n\n try {\n // Clean destination device files\n await fs.promises.rm(`${env.HOME}/.android/avd/${destinationDeviceName}.avd`, {\n recursive: true,\n force: true,\n });\n await fs.promises.rm(cloneIniFile, { force: true });\n } catch (err) {\n logger.warn({ err }, `Failed to remove destination device files ${destinationDeviceName}.`);\n }\n\n try {\n // Remove lockfiles from source device\n const sourceLockfiles = await FastGlob('./**/*.lock', {\n cwd: `${env.HOME}/.android/avd/${sourceDeviceName}.avd`,\n absolute: true,\n });\n await Promise.all(\n sourceLockfiles.map((lockfile) => fs.promises.rm(lockfile, { force: true }))\n );\n } catch (err) {\n logger.warn({ err }, `Failed to remove lockfiles from source device ${sourceDeviceName}.`);\n }\n\n // Copy source to destination\n await fs.promises.cp(\n `${env.HOME}/.android/avd/${sourceDeviceName}.avd`,\n `${env.HOME}/.android/avd/${destinationDeviceName}.avd`,\n { recursive: true, verbatimSymlinks: true, force: true }\n );\n\n await fs.promises.cp(`${env.HOME}/.android/avd/${sourceDeviceName}.ini`, cloneIniFile, {\n verbatimSymlinks: true,\n force: true,\n });\n\n // Remove lockfiles from destination device\n try {\n const lockfiles = await FastGlob('./**/*.lock', {\n cwd: `${env.HOME}/.android/avd/${destinationDeviceName}.avd`,\n absolute: true,\n });\n await Promise.all(lockfiles.map((lockfile) => fs.promises.rm(lockfile, { force: true })));\n } catch (err) {\n logger.warn(\n { err },\n `Failed to remove lockfiles from destination device ${destinationDeviceName}.`\n );\n }\n\n const filesToReplaceDeviceNameIn = // TODO: Test whether we need to use `spawnAsync` here.\n (\n await spawn('grep', [\n '--binary-files=without-match',\n '--recursive',\n '--files-with-matches',\n `${sourceDeviceName}`,\n `${env.HOME}/.android/avd/${destinationDeviceName}.avd`,\n ])\n ).stdout\n .split('\\n')\n .filter((file) => file !== '');\n\n for (const file of [...filesToReplaceDeviceNameIn, cloneIniFile]) {\n try {\n const txtFile = await fs.promises.readFile(file, 'utf-8');\n const replaceRegex = new RegExp(`${sourceDeviceName}`, 'g');\n const updatedTxtFile = txtFile.replace(replaceRegex, destinationDeviceName);\n await fs.promises.writeFile(file, updatedTxtFile);\n } catch (err) {\n logger.warn({ err }, `Failed to replace device name in ${file}.`);\n }\n }\n }\n\n export async function startAsync({\n deviceName,\n env,\n }: {\n deviceName: AndroidVirtualDeviceName;\n env: NodeJS.ProcessEnv;\n }): Promise<{ emulatorPromise: SpawnPromise<SpawnResult>; serialId: AndroidDeviceSerialId }> {\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 ...env,\n // We don't need to wait for emulator to exit gracefully.\n ANDROID_EMULATOR_WAIT_TIME_BEFORE_KILL: '1',\n },\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 const serialId = await retryAsync(\n async () => {\n const serialId = await getSerialIdAsync({ deviceName, env });\n assert(\n serialId,\n `Failed to configure emulator (${serialId}): emulator with required ID not found.`\n );\n return serialId;\n },\n {\n retryOptions: {\n retries: 3 * 60,\n retryIntervalMs: 1_000,\n },\n }\n );\n\n // We don't want to await the SpawnPromise here.\n // eslint-disable-next-line @typescript-eslint/return-await\n return { emulatorPromise, serialId };\n }\n\n export async function waitForReadyAsync({\n serialId,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n await retryAsync(\n async () => {\n const { stdout } = await spawn(\n 'adb',\n ['-s', serialId, 'shell', 'getprop', 'sys.boot_completed'],\n { env }\n );\n\n if (!stdout.startsWith('1')) {\n throw new Error(`Emulator (${serialId}) 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\n export async function collectLogsAsync({\n serialId,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n env: NodeJS.ProcessEnv;\n }): Promise<{ outputPath: string }> {\n const outputDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'android-emulator-logs-'));\n const outputPath = path.join(outputDir, `${serialId}.log`);\n\n // Pipe adb logcat output directly to the file to avoid loading it all into memory\n await new Promise<void>((resolve, reject) => {\n const { child } = spawn('adb', ['-s', serialId, 'logcat', '-d'], {\n env,\n stdio: ['ignore', 'pipe', 'inherit'],\n });\n\n if (!child.stdout) {\n reject(new Error('\"adb logcat\" did not start correctly.'));\n return;\n }\n\n const writeStream = fs.createWriteStream(outputPath);\n child.stdout.pipe(writeStream);\n child.stdout.on('error', reject);\n\n child.on('error', reject);\n writeStream.on('error', reject);\n\n child.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`\"adb logcat\" exited with code ${code}`));\n }\n });\n });\n\n return { outputPath };\n }\n\n export async function deleteAsync({\n serialId,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n const adbEmuAvdName = await spawn('adb', ['-s', serialId, 'emu', 'avd', 'name'], {\n env,\n });\n const deviceName = adbEmuAvdName.stdout.replace(/\\r\\n/g, '\\n').split('\\n')[0];\n\n await spawn('adb', ['-s', serialId, 'emu', 'kill'], { env });\n\n await retryAsync(\n async () => {\n const devices = await getAttachedDevicesAsync({ env });\n if (devices.some((device) => device.serialId === serialId)) {\n throw new Error(`Emulator (${serialId}) is still attached.`);\n }\n },\n {\n retryOptions: {\n retries: 3 * 60,\n retryIntervalMs: 1_000,\n },\n }\n );\n\n await spawn('avdmanager', ['delete', 'avd', '-n', deviceName], { env });\n }\n\n export async function startScreenRecordingAsync({\n serialId,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n env: NodeJS.ProcessEnv;\n }): Promise<{\n recordingSpawn: SpawnPromise<SpawnResult>;\n }> {\n let isReady = false;\n\n // Ensure /sdcard/ is ready to write to. (If the emulator was just booted, it might not be ready yet.)\n for (let i = 0; i < 30; i++) {\n try {\n await spawn('adb', ['-s', serialId, 'shell', 'touch', '/sdcard/.expo-recording-ready'], {\n env,\n });\n isReady = true;\n break;\n } catch {\n await setTimeout(1000);\n }\n }\n\n if (!isReady) {\n throw new Error(`Emulator (${serialId}) filesystem was not ready in time.`);\n }\n\n const screenrecordArgs = [\n '-s',\n serialId,\n 'shell',\n 'screenrecord',\n '--verbose',\n '/sdcard/expo-recording.mp4',\n ];\n\n const screenrecordHelp = await spawn(\n 'adb',\n ['-s', serialId, 'shell', 'screenrecord', '--help'],\n {\n env,\n }\n );\n\n if (screenrecordHelp.stdout.includes('remove the time limit')) {\n screenrecordArgs.push('--time-limit', '0');\n }\n\n const recordingSpawn = spawn('adb', screenrecordArgs, {\n env,\n stdio: 'pipe',\n });\n recordingSpawn.child.unref();\n\n // We are returning the SpawnPromise here, so we don't await it.\n // eslint-disable-next-line @typescript-eslint/return-await\n return {\n recordingSpawn,\n };\n }\n\n export async function stopScreenRecordingAsync({\n serialId,\n recordingSpawn,\n env,\n }: {\n serialId: AndroidDeviceSerialId;\n recordingSpawn: SpawnPromise<SpawnResult>;\n env: NodeJS.ProcessEnv;\n }): Promise<{ outputPath: string }> {\n recordingSpawn.child.kill(1);\n\n try {\n await recordingSpawn;\n } catch {\n // do nothing\n }\n\n let isRecordingBusy = true;\n for (let i = 0; i < 30; i++) {\n const lsof = await spawn(\n 'adb',\n ['-s', serialId, 'shell', 'lsof -t /sdcard/expo-recording.mp4'],\n { env }\n );\n if (lsof.stdout.trim() === '') {\n isRecordingBusy = false;\n break;\n }\n await setTimeout(1000);\n }\n\n if (isRecordingBusy) {\n throw new Error(`Recording file is busy.`);\n }\n\n const outputDir = await fs.promises.mkdtemp(\n path.join(os.tmpdir(), 'android-screen-recording-')\n );\n const outputPath = path.join(outputDir, `${serialId}.mp4`);\n\n await spawn('adb', ['-s', serialId, 'pull', '/sdcard/expo-recording.mp4', outputPath], { env });\n\n return { outputPath };\n }\n}\n"]}
|
|
@@ -70,5 +70,13 @@ export declare namespace IosSimulatorUtils {
|
|
|
70
70
|
export function stopScreenRecordingAsync({ recordingSpawn, }: {
|
|
71
71
|
recordingSpawn: SpawnPromise<SpawnResult>;
|
|
72
72
|
}): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Check if any com.apple.datamigrator processes are running.
|
|
75
|
+
* The existence of these processes indicates that simulators are still booting/migrating data.
|
|
76
|
+
* Based on WebKit's approach: https://trac.webkit.org/changeset/231452/webkit
|
|
77
|
+
*/
|
|
78
|
+
export function isDataMigratorProcessRunning({ env, }: {
|
|
79
|
+
env: NodeJS.ProcessEnv;
|
|
80
|
+
}): Promise<boolean>;
|
|
73
81
|
export {};
|
|
74
82
|
}
|
|
@@ -61,6 +61,19 @@ var IosSimulatorUtils;
|
|
|
61
61
|
retryIntervalMs: 1000,
|
|
62
62
|
},
|
|
63
63
|
});
|
|
64
|
+
// Wait for data migration to complete before declaring the simulator ready
|
|
65
|
+
// Based on WebKit's approach: https://trac.webkit.org/changeset/231452/webkit
|
|
66
|
+
await (0, retry_1.retryAsync)(async () => {
|
|
67
|
+
const isDataMigrating = await isDataMigratorProcessRunning({ env });
|
|
68
|
+
if (isDataMigrating) {
|
|
69
|
+
throw new Error('com.apple.datamigrator still running');
|
|
70
|
+
}
|
|
71
|
+
}, {
|
|
72
|
+
retryOptions: {
|
|
73
|
+
retries: 30 * 60,
|
|
74
|
+
retryIntervalMs: 1000,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
64
77
|
}
|
|
65
78
|
IosSimulatorUtils.waitForReadyAsync = waitForReadyAsync;
|
|
66
79
|
async function collectLogsAsync({ deviceIdentifier, env, }) {
|
|
@@ -120,6 +133,22 @@ var IosSimulatorUtils;
|
|
|
120
133
|
await recordingSpawn;
|
|
121
134
|
}
|
|
122
135
|
IosSimulatorUtils.stopScreenRecordingAsync = stopScreenRecordingAsync;
|
|
136
|
+
/**
|
|
137
|
+
* Check if any com.apple.datamigrator processes are running.
|
|
138
|
+
* The existence of these processes indicates that simulators are still booting/migrating data.
|
|
139
|
+
* Based on WebKit's approach: https://trac.webkit.org/changeset/231452/webkit
|
|
140
|
+
*/
|
|
141
|
+
async function isDataMigratorProcessRunning({ env, }) {
|
|
142
|
+
try {
|
|
143
|
+
const result = await (0, turtle_spawn_1.default)('ps', ['-eo', 'pid,comm'], { env });
|
|
144
|
+
return result.stdout.includes('com.apple.datamigrator');
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// If ps command fails, assume no data migration processes are running
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
IosSimulatorUtils.isDataMigratorProcessRunning = isDataMigratorProcessRunning;
|
|
123
152
|
})(IosSimulatorUtils || (exports.IosSimulatorUtils = IosSimulatorUtils = {}));
|
|
124
153
|
function parseUdidFromBootstatusStdout(stdout) {
|
|
125
154
|
const matches = stdout.match(/^Monitoring boot status for .+ \((.+)\)\.$/m);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IosSimulatorUtils.js","sourceRoot":"","sources":["../../src/utils/IosSimulatorUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\nimport os from 'node:os';\nimport fs from 'node:fs';\nimport { setTimeout } from 'node:timers/promises';\n\nimport spawn, { SpawnPromise, SpawnResult } from '@expo/turtle-spawn';\nimport { z } from 'zod';\n\nimport { retryAsync } from './retry';\n\nexport type IosSimulatorUuid = string & z.BRAND<'IosSimulatorUuid'>;\nexport type IosSimulatorName = string & z.BRAND<'IosSimulatorName'>;\n\nexport namespace IosSimulatorUtils {\n type 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: IosSimulatorUuid;\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: IosSimulatorName;\n /** e.g. 2024-01-22T19:28:56Z */\n lastBootedAt?: string;\n };\n\n type SimulatorDevice = XcrunSimctlDevice & { runtime: string; displayName: string };\n\n type XcrunSimctlListDevicesJsonOutput = {\n devices: {\n [runtime: string]: XcrunSimctlDevice[];\n };\n };\n\n export async function getAvailableDevicesAsync({\n env,\n filter,\n }: {\n env: NodeJS.ProcessEnv;\n filter: 'available' | 'booted';\n }): Promise<SimulatorDevice[]> {\n const result = await spawn(\n 'xcrun',\n ['simctl', 'list', 'devices', '--json', '--no-escape-slashes', filter],\n { env }\n );\n const xcrunData = JSON.parse(result.stdout) as XcrunSimctlListDevicesJsonOutput;\n\n const allAvailableDevices: SimulatorDevice[] = [];\n for (const [runtime, devices] of Object.entries(xcrunData.devices)) {\n allAvailableDevices.push(\n ...devices.map((device) => ({\n ...device,\n runtime,\n displayName: `${device.name} (${device.udid}) on ${runtime}`,\n }))\n );\n }\n\n return allAvailableDevices;\n }\n\n export async function getDeviceAsync({\n udid,\n env,\n }: {\n env: NodeJS.ProcessEnv;\n udid: IosSimulatorUuid;\n }): Promise<SimulatorDevice | null> {\n const devices = await getAvailableDevicesAsync({ env, filter: 'available' });\n return devices.find((device) => device.udid === udid) ?? null;\n }\n\n export async function cloneAsync({\n sourceDeviceIdentifier,\n destinationDeviceName,\n env,\n }: {\n sourceDeviceIdentifier: IosSimulatorName | IosSimulatorUuid;\n destinationDeviceName: IosSimulatorName;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n await spawn('xcrun', ['simctl', 'clone', sourceDeviceIdentifier, destinationDeviceName], {\n env,\n });\n }\n\n export async function startAsync({\n deviceIdentifier,\n env,\n }: {\n deviceIdentifier: IosSimulatorUuid | IosSimulatorName;\n env: NodeJS.ProcessEnv;\n }): Promise<{ udid: IosSimulatorUuid }> {\n const bootstatusResult = await spawn(\n 'xcrun',\n ['simctl', 'bootstatus', deviceIdentifier, '-b'],\n {\n env,\n }\n );\n\n const udid = parseUdidFromBootstatusStdout(bootstatusResult.stdout);\n if (!udid) {\n throw new Error('Failed to parse UDID from bootstatus result.');\n }\n\n return { udid };\n }\n\n export async function waitForReadyAsync({\n udid,\n env,\n }: {\n udid: IosSimulatorUuid;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n await retryAsync(\n async () => {\n await spawn('xcrun', ['simctl', 'io', udid, '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\n export async function collectLogsAsync({\n deviceIdentifier,\n env,\n }: {\n deviceIdentifier: IosSimulatorName | IosSimulatorUuid;\n env: NodeJS.ProcessEnv;\n }): Promise<{ outputPath: string }> {\n const outputDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'ios-simulator-logs-'));\n const outputPath = path.join(outputDir, `${deviceIdentifier}.logarchive`);\n\n await spawn(\n 'xcrun',\n ['simctl', 'spawn', deviceIdentifier, 'log', 'collect', '--output', outputPath],\n {\n env,\n }\n );\n\n return { outputPath };\n }\n\n export async function deleteAsync({\n deviceIdentifier,\n env,\n }: {\n deviceIdentifier: IosSimulatorName | IosSimulatorUuid;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n await spawn('xcrun', ['simctl', 'shutdown', deviceIdentifier], { env });\n await spawn('xcrun', ['simctl', 'delete', deviceIdentifier], { env });\n }\n\n export async function startScreenRecordingAsync({\n deviceIdentifier,\n env,\n }: {\n deviceIdentifier: IosSimulatorUuid | IosSimulatorName;\n env: NodeJS.ProcessEnv;\n }): Promise<{\n recordingSpawn: SpawnPromise<SpawnResult>;\n outputPath: string;\n }> {\n const outputDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'ios-screen-recording-'));\n const outputPath = path.join(outputDir, `${deviceIdentifier}.mov`);\n const recordingSpawn = spawn(\n 'xcrun',\n ['simctl', 'io', deviceIdentifier, 'recordVideo', '-f', outputPath],\n {\n env,\n }\n );\n\n const stdout = recordingSpawn.child.stdout;\n const stderr = recordingSpawn.child.stderr;\n if (!stdout || !stderr) {\n // No stdout/stderr means the process failed to start, so awaiting it will throw an error.\n await recordingSpawn;\n throw new Error('Recording process failed to start.');\n }\n\n let outputAggregated = '';\n\n // Listen to both stdout and stderr since \"Recording started\" might come from either\n stdout.on('data', (data) => {\n const output = data.toString();\n outputAggregated += output;\n });\n\n stderr.on('data', (data) => {\n const output = data.toString();\n outputAggregated += output;\n });\n\n let isRecordingStarted = false;\n for (let i = 0; i < 20; i++) {\n // Check if recording started message appears in either stdout or stderr\n if (outputAggregated.includes('Recording started')) {\n isRecordingStarted = true;\n break;\n }\n await setTimeout(1000);\n }\n\n if (!isRecordingStarted) {\n throw new Error('Recording not started in time.');\n }\n\n return { recordingSpawn, outputPath };\n }\n\n export async function stopScreenRecordingAsync({\n recordingSpawn,\n }: {\n recordingSpawn: SpawnPromise<SpawnResult>;\n }): Promise<void> {\n recordingSpawn.child.kill(2);\n await recordingSpawn;\n }\n}\n\nfunction parseUdidFromBootstatusStdout(stdout: string): IosSimulatorUuid | null {\n const matches = stdout.match(/^Monitoring boot status for .+ \\((.+)\\)\\.$/m);\n if (!matches) {\n return null;\n }\n return matches[1] as IosSimulatorUuid;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"IosSimulatorUtils.js","sourceRoot":"","sources":["../../src/utils/IosSimulatorUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\nimport os from 'node:os';\nimport fs from 'node:fs';\nimport { setTimeout } from 'node:timers/promises';\n\nimport spawn, { SpawnPromise, SpawnResult } from '@expo/turtle-spawn';\nimport { z } from 'zod';\n\nimport { retryAsync } from './retry';\n\nexport type IosSimulatorUuid = string & z.BRAND<'IosSimulatorUuid'>;\nexport type IosSimulatorName = string & z.BRAND<'IosSimulatorName'>;\n\nexport namespace IosSimulatorUtils {\n type 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: IosSimulatorUuid;\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: IosSimulatorName;\n /** e.g. 2024-01-22T19:28:56Z */\n lastBootedAt?: string;\n };\n\n type SimulatorDevice = XcrunSimctlDevice & { runtime: string; displayName: string };\n\n type XcrunSimctlListDevicesJsonOutput = {\n devices: {\n [runtime: string]: XcrunSimctlDevice[];\n };\n };\n\n export async function getAvailableDevicesAsync({\n env,\n filter,\n }: {\n env: NodeJS.ProcessEnv;\n filter: 'available' | 'booted';\n }): Promise<SimulatorDevice[]> {\n const result = await spawn(\n 'xcrun',\n ['simctl', 'list', 'devices', '--json', '--no-escape-slashes', filter],\n { env }\n );\n const xcrunData = JSON.parse(result.stdout) as XcrunSimctlListDevicesJsonOutput;\n\n const allAvailableDevices: SimulatorDevice[] = [];\n for (const [runtime, devices] of Object.entries(xcrunData.devices)) {\n allAvailableDevices.push(\n ...devices.map((device) => ({\n ...device,\n runtime,\n displayName: `${device.name} (${device.udid}) on ${runtime}`,\n }))\n );\n }\n\n return allAvailableDevices;\n }\n\n export async function getDeviceAsync({\n udid,\n env,\n }: {\n env: NodeJS.ProcessEnv;\n udid: IosSimulatorUuid;\n }): Promise<SimulatorDevice | null> {\n const devices = await getAvailableDevicesAsync({ env, filter: 'available' });\n return devices.find((device) => device.udid === udid) ?? null;\n }\n\n export async function cloneAsync({\n sourceDeviceIdentifier,\n destinationDeviceName,\n env,\n }: {\n sourceDeviceIdentifier: IosSimulatorName | IosSimulatorUuid;\n destinationDeviceName: IosSimulatorName;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n await spawn('xcrun', ['simctl', 'clone', sourceDeviceIdentifier, destinationDeviceName], {\n env,\n });\n }\n\n export async function startAsync({\n deviceIdentifier,\n env,\n }: {\n deviceIdentifier: IosSimulatorUuid | IosSimulatorName;\n env: NodeJS.ProcessEnv;\n }): Promise<{ udid: IosSimulatorUuid }> {\n const bootstatusResult = await spawn(\n 'xcrun',\n ['simctl', 'bootstatus', deviceIdentifier, '-b'],\n {\n env,\n }\n );\n\n const udid = parseUdidFromBootstatusStdout(bootstatusResult.stdout);\n if (!udid) {\n throw new Error('Failed to parse UDID from bootstatus result.');\n }\n\n return { udid };\n }\n\n export async function waitForReadyAsync({\n udid,\n env,\n }: {\n udid: IosSimulatorUuid;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n await retryAsync(\n async () => {\n await spawn('xcrun', ['simctl', 'io', udid, '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 // Wait for data migration to complete before declaring the simulator ready\n // Based on WebKit's approach: https://trac.webkit.org/changeset/231452/webkit\n await retryAsync(\n async () => {\n const isDataMigrating = await isDataMigratorProcessRunning({ env });\n if (isDataMigrating) {\n throw new Error('com.apple.datamigrator still running');\n }\n },\n {\n retryOptions: {\n retries: 30 * 60,\n retryIntervalMs: 1_000,\n },\n }\n );\n }\n\n export async function collectLogsAsync({\n deviceIdentifier,\n env,\n }: {\n deviceIdentifier: IosSimulatorName | IosSimulatorUuid;\n env: NodeJS.ProcessEnv;\n }): Promise<{ outputPath: string }> {\n const outputDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'ios-simulator-logs-'));\n const outputPath = path.join(outputDir, `${deviceIdentifier}.logarchive`);\n\n await spawn(\n 'xcrun',\n ['simctl', 'spawn', deviceIdentifier, 'log', 'collect', '--output', outputPath],\n {\n env,\n }\n );\n\n return { outputPath };\n }\n\n export async function deleteAsync({\n deviceIdentifier,\n env,\n }: {\n deviceIdentifier: IosSimulatorName | IosSimulatorUuid;\n env: NodeJS.ProcessEnv;\n }): Promise<void> {\n await spawn('xcrun', ['simctl', 'shutdown', deviceIdentifier], { env });\n await spawn('xcrun', ['simctl', 'delete', deviceIdentifier], { env });\n }\n\n export async function startScreenRecordingAsync({\n deviceIdentifier,\n env,\n }: {\n deviceIdentifier: IosSimulatorUuid | IosSimulatorName;\n env: NodeJS.ProcessEnv;\n }): Promise<{\n recordingSpawn: SpawnPromise<SpawnResult>;\n outputPath: string;\n }> {\n const outputDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'ios-screen-recording-'));\n const outputPath = path.join(outputDir, `${deviceIdentifier}.mov`);\n const recordingSpawn = spawn(\n 'xcrun',\n ['simctl', 'io', deviceIdentifier, 'recordVideo', '-f', outputPath],\n {\n env,\n }\n );\n\n const stdout = recordingSpawn.child.stdout;\n const stderr = recordingSpawn.child.stderr;\n if (!stdout || !stderr) {\n // No stdout/stderr means the process failed to start, so awaiting it will throw an error.\n await recordingSpawn;\n throw new Error('Recording process failed to start.');\n }\n\n let outputAggregated = '';\n\n // Listen to both stdout and stderr since \"Recording started\" might come from either\n stdout.on('data', (data) => {\n const output = data.toString();\n outputAggregated += output;\n });\n\n stderr.on('data', (data) => {\n const output = data.toString();\n outputAggregated += output;\n });\n\n let isRecordingStarted = false;\n for (let i = 0; i < 20; i++) {\n // Check if recording started message appears in either stdout or stderr\n if (outputAggregated.includes('Recording started')) {\n isRecordingStarted = true;\n break;\n }\n await setTimeout(1000);\n }\n\n if (!isRecordingStarted) {\n throw new Error('Recording not started in time.');\n }\n\n return { recordingSpawn, outputPath };\n }\n\n export async function stopScreenRecordingAsync({\n recordingSpawn,\n }: {\n recordingSpawn: SpawnPromise<SpawnResult>;\n }): Promise<void> {\n recordingSpawn.child.kill(2);\n await recordingSpawn;\n }\n\n /**\n * Check if any com.apple.datamigrator processes are running.\n * The existence of these processes indicates that simulators are still booting/migrating data.\n * Based on WebKit's approach: https://trac.webkit.org/changeset/231452/webkit\n */\n export async function isDataMigratorProcessRunning({\n env,\n }: {\n env: NodeJS.ProcessEnv;\n }): Promise<boolean> {\n try {\n const result = await spawn('ps', ['-eo', 'pid,comm'], { env });\n\n return result.stdout.includes('com.apple.datamigrator');\n } catch {\n // If ps command fails, assume no data migration processes are running\n return false;\n }\n }\n}\n\nfunction parseUdidFromBootstatusStdout(stdout: string): IosSimulatorUuid | null {\n const matches = stdout.match(/^Monitoring boot status for .+ \\((.+)\\)\\.$/m);\n if (!matches) {\n return null;\n }\n return matches[1] as IosSimulatorUuid;\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.205",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"node": "20.14.0",
|
|
80
80
|
"yarn": "1.22.21"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "2e23c80a4e87650884c35fd77c1b567ef1578c39"
|
|
83
83
|
}
|