1import spawnAsync from '@expo/spawn-async'; 2import { spawn } from 'child_process'; 3import { Transform, TransformCallback, TransformOptions } from 'stream'; 4 5/** 6 * Starts an arbitrary iOS simulator so that simctl can reference a "booted" simulator. 7 */ 8export async function startSimulatorAsync(): Promise<void> { 9 try { 10 await spawnAsync('xcrun', ['instruments', '-w', 'iPhone X (11.2) [']); 11 } catch (e) { 12 // Instruments exits with an expected error 13 if (!e.stderr.includes('Instruments Usage Error')) { 14 throw e; 15 } 16 } 17} 18 19export async function installSimulatorAppAsync( 20 simulatorId: string, 21 archivePath: string 22): Promise<void> { 23 try { 24 await spawnAsync('xcrun', ['simctl', 'install', simulatorId, archivePath]); 25 } catch (e) { 26 const error = new Error(e.stderr); 27 (error as any).status = e.status; 28 throw error; 29 } 30} 31 32export async function launchSimulatorAppAsync( 33 simulatorId: string, 34 bundleIdentifier: string 35): Promise<void> { 36 try { 37 await spawnAsync('xcrun', ['simctl', 'launch', simulatorId, bundleIdentifier]); 38 } catch (e) { 39 const error = new Error(e.stderr); 40 (error as any).status = e.status; 41 throw error; 42 } 43} 44 45export function getSimulatorLogProcess(simulatorId: string, predicate?: string) { 46 return spawn( 47 'xcrun', 48 [ 49 'simctl', 50 'spawn', 51 simulatorId, 52 'log', 53 'stream', 54 '--style', 55 'json', 56 ...(predicate ? ['--predicate', predicate] : []), 57 ], 58 { 59 stdio: ['ignore', 'pipe', 'inherit'], 60 } 61 ); 62} 63 64export class IOSLogStream extends Transform { 65 constructor(options?: TransformOptions) { 66 super({ ...options, objectMode: true }); 67 } 68 69 _transform(data: Buffer, encoding: string, callback: TransformCallback): void { 70 // In practice, we receive each log entry as a separate chunk and can test if they are valid, 71 // JSON-formatted log entries 72 let entry; 73 try { 74 entry = JSON.parse(data.toString('utf8')); 75 } catch {} 76 77 if (entry?.eventMessage) { 78 this.push(entry); 79 } 80 callback(); 81 } 82} 83