1import spawnAsync from '@expo/spawn-async'; 2import fs from 'fs/promises'; 3 4import * as Log from '../../../log'; 5import { Prerequisite, PrerequisiteCommandError } from '../Prerequisite'; 6 7const ERROR_CODE = 'XCODE_DEVELOPER_DISK_IMAGE'; 8async function getXcodePathAsync(): Promise<string> { 9 try { 10 const { stdout } = await spawnAsync('xcode-select', ['-p']); 11 if (stdout) { 12 return stdout.trim(); 13 } 14 } catch (error: any) { 15 Log.debug(`Could not find Xcode path: %O`, error); 16 } 17 throw new PrerequisiteCommandError(ERROR_CODE, 'Unable to locate Xcode.'); 18} 19 20export class XcodeDeveloperDiskImagePrerequisite extends Prerequisite<string, { version: string }> { 21 static instance = new XcodeDeveloperDiskImagePrerequisite(); 22 23 async assertImplementation({ version }: { version: string }): Promise<string> { 24 const xcodePath = await getXcodePathAsync(); 25 // Like "11.2 (15C107)" 26 const versions = await fs.readdir(`${xcodePath}/Platforms/iPhoneOS.platform/DeviceSupport/`); 27 const prefix = version.match(/\d+\.\d+/); 28 if (prefix === null) { 29 throw new PrerequisiteCommandError(ERROR_CODE, `Invalid iOS version: ${version}`); 30 } 31 for (const directory of versions) { 32 if (directory.includes(prefix[0])) { 33 return `${xcodePath}/Platforms/iPhoneOS.platform/DeviceSupport/${directory}/DeveloperDiskImage.dmg`; 34 } 35 } 36 throw new PrerequisiteCommandError( 37 ERROR_CODE, 38 `Unable to find Developer Disk Image path for SDK ${version}.` 39 ); 40 } 41} 42