import { promptDeviceAsync } from './promptDevice'; import * as Log from '../../../log'; import { AppleDeviceManager, ensureSimulatorOpenAsync, } from '../../../start/platforms/ios/AppleDeviceManager'; import { assertSystemRequirementsAsync } from '../../../start/platforms/ios/assertSystemRequirements'; import { sortDefaultDeviceToBeginningAsync } from '../../../start/platforms/ios/promptAppleDevice'; import { OSType } from '../../../start/platforms/ios/simctl'; import * as SimControl from '../../../start/platforms/ios/simctl'; import { CommandError } from '../../../utils/errors'; import { profile } from '../../../utils/profile'; import { logDeviceArgument } from '../../hints'; import * as AppleDevice from '../appleDevice/AppleDevice'; type AnyDevice = SimControl.Device | AppleDevice.ConnectedDevice; /** Get a list of devices (called destinations) that are connected to the host machine. Filter by `osType` if defined. */ async function getDevicesAsync({ osType }: { osType?: OSType } = {}): Promise { const connectedDevices = await AppleDevice.getConnectedDevicesAsync(); const simulators = await sortDefaultDeviceToBeginningAsync( await profile(SimControl.getDevicesAsync)(), osType ); const devices = [...connectedDevices, ...simulators]; // If osType is defined, then filter out ineligible simulators. // Only do this inside of the device selection so users who pass the entire device udid can attempt to select any simulator (even if it's invalid). return osType ? filterDevicesForOsType(devices, osType) : devices; } /** @returns a list of devices, filtered by the provided `osType`. */ function filterDevicesForOsType(devices: AnyDevice[], osType: OSType): AnyDevice[] { return devices.filter((device) => !('osType' in device) || device.osType === osType); } /** Given a `device` argument from the CLI, parse and prompt our way to a usable device for building. */ export async function resolveDeviceAsync( device?: string | boolean, { osType }: { osType?: OSType } = {} ): Promise { await assertSystemRequirementsAsync(); if (!device) { /** Finds the first possible device and returns in a booted state. */ const manager = await AppleDeviceManager.resolveAsync({ device: { osType, }, }); Log.debug( `Resolved default device (name: ${manager.device.name}, udid: ${manager.device.udid}, osType: ${osType})` ); return manager.device; } const devices: AnyDevice[] = await getDevicesAsync({ osType, }); const resolved = device === true ? // `--device` (no props after) await promptDeviceAsync(devices) : // `--device ` findDeviceFromSearchValue(devices, device.toLowerCase()); return ensureBootedAsync(resolved); } /** @returns `true` if the given device is a simulator. */ export function isSimulatorDevice(device: AnyDevice): boolean { return ( !('deviceType' in device) || device.deviceType.startsWith('com.apple.CoreSimulator.SimDeviceType.') ); } /** @returns device matching the `searchValue` against name or UDID. */ function findDeviceFromSearchValue(devices: AnyDevice[], searchValue: string): AnyDevice { const device = devices.find( (device) => device.udid.toLowerCase() === searchValue || device.name.toLowerCase() === searchValue ); if (!device) { throw new CommandError('BAD_ARGS', `No device UDID or name matching "${searchValue}"`); } return device; } /** Ensures the device is booted if it's a simulator. */ async function ensureBootedAsync(device: AnyDevice): Promise { // --device with no props after logDeviceArgument(device.udid); if (isSimulatorDevice(device)) { return ensureSimulatorOpenAsync({ udid: device.udid }); } return device; }