1*8a424bebSJames Ideimport { promptDeviceAsync } from './promptDevice'; 2c4ef02aeSEvan Baconimport * as Log from '../../../log'; 3c4ef02aeSEvan Baconimport { 4c4ef02aeSEvan Bacon AppleDeviceManager, 5c4ef02aeSEvan Bacon ensureSimulatorOpenAsync, 6c4ef02aeSEvan Bacon} from '../../../start/platforms/ios/AppleDeviceManager'; 7c4ef02aeSEvan Baconimport { assertSystemRequirementsAsync } from '../../../start/platforms/ios/assertSystemRequirements'; 8c4ef02aeSEvan Baconimport { sortDefaultDeviceToBeginningAsync } from '../../../start/platforms/ios/promptAppleDevice'; 9c4ef02aeSEvan Baconimport { OSType } from '../../../start/platforms/ios/simctl'; 10c4ef02aeSEvan Baconimport * as SimControl from '../../../start/platforms/ios/simctl'; 11c4ef02aeSEvan Baconimport { CommandError } from '../../../utils/errors'; 12c4ef02aeSEvan Baconimport { profile } from '../../../utils/profile'; 13c4ef02aeSEvan Baconimport { logDeviceArgument } from '../../hints'; 14c4ef02aeSEvan Baconimport * as AppleDevice from '../appleDevice/AppleDevice'; 15c4ef02aeSEvan Bacon 16c4ef02aeSEvan Bacontype AnyDevice = SimControl.Device | AppleDevice.ConnectedDevice; 17c4ef02aeSEvan Bacon 18c4ef02aeSEvan Bacon/** Get a list of devices (called destinations) that are connected to the host machine. Filter by `osType` if defined. */ 19c4ef02aeSEvan Baconasync function getDevicesAsync({ osType }: { osType?: OSType } = {}): Promise<AnyDevice[]> { 20c4ef02aeSEvan Bacon const connectedDevices = await AppleDevice.getConnectedDevicesAsync(); 21c4ef02aeSEvan Bacon 22c4ef02aeSEvan Bacon const simulators = await sortDefaultDeviceToBeginningAsync( 23c4ef02aeSEvan Bacon await profile(SimControl.getDevicesAsync)(), 24c4ef02aeSEvan Bacon osType 25c4ef02aeSEvan Bacon ); 26c4ef02aeSEvan Bacon 27c4ef02aeSEvan Bacon const devices = [...connectedDevices, ...simulators]; 28c4ef02aeSEvan Bacon 29c4ef02aeSEvan Bacon // If osType is defined, then filter out ineligible simulators. 30c4ef02aeSEvan Bacon // 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). 31c4ef02aeSEvan Bacon return osType ? filterDevicesForOsType(devices, osType) : devices; 32c4ef02aeSEvan Bacon} 33c4ef02aeSEvan Bacon 34c4ef02aeSEvan Bacon/** @returns a list of devices, filtered by the provided `osType`. */ 35c4ef02aeSEvan Baconfunction filterDevicesForOsType(devices: AnyDevice[], osType: OSType): AnyDevice[] { 36c4ef02aeSEvan Bacon return devices.filter((device) => !('osType' in device) || device.osType === osType); 37c4ef02aeSEvan Bacon} 38c4ef02aeSEvan Bacon 39c4ef02aeSEvan Bacon/** Given a `device` argument from the CLI, parse and prompt our way to a usable device for building. */ 40c4ef02aeSEvan Baconexport async function resolveDeviceAsync( 41c4ef02aeSEvan Bacon device?: string | boolean, 42c4ef02aeSEvan Bacon { osType }: { osType?: OSType } = {} 43c4ef02aeSEvan Bacon): Promise<AnyDevice> { 44c4ef02aeSEvan Bacon await assertSystemRequirementsAsync(); 45c4ef02aeSEvan Bacon 46c4ef02aeSEvan Bacon if (!device) { 47c4ef02aeSEvan Bacon /** Finds the first possible device and returns in a booted state. */ 48c4ef02aeSEvan Bacon const manager = await AppleDeviceManager.resolveAsync({ 49c4ef02aeSEvan Bacon device: { 50c4ef02aeSEvan Bacon osType, 51c4ef02aeSEvan Bacon }, 52c4ef02aeSEvan Bacon }); 53c4ef02aeSEvan Bacon Log.debug( 54c4ef02aeSEvan Bacon `Resolved default device (name: ${manager.device.name}, udid: ${manager.device.udid}, osType: ${osType})` 55c4ef02aeSEvan Bacon ); 56c4ef02aeSEvan Bacon return manager.device; 57c4ef02aeSEvan Bacon } 58c4ef02aeSEvan Bacon 59c4ef02aeSEvan Bacon const devices: AnyDevice[] = await getDevicesAsync({ 60c4ef02aeSEvan Bacon osType, 61c4ef02aeSEvan Bacon }); 62c4ef02aeSEvan Bacon 63c4ef02aeSEvan Bacon const resolved = 64c4ef02aeSEvan Bacon device === true 65c4ef02aeSEvan Bacon ? // `--device` (no props after) 66c4ef02aeSEvan Bacon await promptDeviceAsync(devices) 67c4ef02aeSEvan Bacon : // `--device <name|udid>` 68c4ef02aeSEvan Bacon findDeviceFromSearchValue(devices, device.toLowerCase()); 69c4ef02aeSEvan Bacon 70c4ef02aeSEvan Bacon return ensureBootedAsync(resolved); 71c4ef02aeSEvan Bacon} 72c4ef02aeSEvan Bacon 73c4ef02aeSEvan Bacon/** @returns `true` if the given device is a simulator. */ 74c4ef02aeSEvan Baconexport function isSimulatorDevice(device: AnyDevice): boolean { 75c4ef02aeSEvan Bacon return ( 76c4ef02aeSEvan Bacon !('deviceType' in device) || 77c4ef02aeSEvan Bacon device.deviceType.startsWith('com.apple.CoreSimulator.SimDeviceType.') 78c4ef02aeSEvan Bacon ); 79c4ef02aeSEvan Bacon} 80c4ef02aeSEvan Bacon 81c4ef02aeSEvan Bacon/** @returns device matching the `searchValue` against name or UDID. */ 82c4ef02aeSEvan Baconfunction findDeviceFromSearchValue(devices: AnyDevice[], searchValue: string): AnyDevice { 83c4ef02aeSEvan Bacon const device = devices.find( 84c4ef02aeSEvan Bacon (device) => 85c4ef02aeSEvan Bacon device.udid.toLowerCase() === searchValue || device.name.toLowerCase() === searchValue 86c4ef02aeSEvan Bacon ); 87c4ef02aeSEvan Bacon if (!device) { 88c4ef02aeSEvan Bacon throw new CommandError('BAD_ARGS', `No device UDID or name matching "${searchValue}"`); 89c4ef02aeSEvan Bacon } 90c4ef02aeSEvan Bacon return device; 91c4ef02aeSEvan Bacon} 92c4ef02aeSEvan Bacon 93c4ef02aeSEvan Bacon/** Ensures the device is booted if it's a simulator. */ 94c4ef02aeSEvan Baconasync function ensureBootedAsync(device: AnyDevice): Promise<AnyDevice> { 95c4ef02aeSEvan Bacon // --device with no props after 96c4ef02aeSEvan Bacon logDeviceArgument(device.udid); 97c4ef02aeSEvan Bacon if (isSimulatorDevice(device)) { 98c4ef02aeSEvan Bacon return ensureSimulatorOpenAsync({ udid: device.udid }); 99c4ef02aeSEvan Bacon } 100c4ef02aeSEvan Bacon return device; 101c4ef02aeSEvan Bacon} 102