From 3b6d84b083956df5652b2fe34c68287579e9b73d Mon Sep 17 00:00:00 2001 From: Yegor Date: Fri, 16 Jun 2017 12:58:23 -0700 Subject: [PATCH] modernize iOS device lookup in driver (#10780) --- .../flutter_tools/lib/src/commands/drive.dart | 58 ++------- .../flutter_tools/lib/src/ios/simulators.dart | 113 ------------------ .../test/commands/drive_test.dart | 64 +++------- 3 files changed, 25 insertions(+), 210 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart index bdc0b9f4dcf..0bb14a0e74d 100644 --- a/packages/flutter_tools/lib/src/commands/drive.dart +++ b/packages/flutter_tools/lib/src/commands/drive.dart @@ -4,11 +4,9 @@ import 'dart:async'; -import '../android/android_device.dart' show AndroidDevice; import '../application_package.dart'; import '../base/common.dart'; import '../base/file_system.dart'; -import '../base/platform.dart'; import '../base/process.dart'; import '../build_info.dart'; import '../cache.dart'; @@ -16,7 +14,6 @@ import '../dart/package_map.dart'; import '../dart/sdk.dart'; import '../device.dart'; import '../globals.dart'; -import '../ios/simulators.dart' show SimControl, IOSSimulatorUtils; import '../resident_runner.dart'; import 'run.dart'; @@ -198,56 +195,15 @@ Future findTargetDevice() async { return devices.first; } - - if (platform.isMacOS) { - // On Mac we look for the iOS Simulator. If available, we use that. Then - // we look for an Android device. If there's one, we use that. Otherwise, - // we launch a new iOS Simulator. - Device reusableDevice; - for (Device device in devices) { - if (await device.isLocalEmulator) { - reusableDevice = device; - break; - } - } - if (reusableDevice == null) { - for (Device device in devices) { - if (device is AndroidDevice) { - reusableDevice = device; - break; - } - } - } - - if (reusableDevice != null) { - printStatus('Found connected ${await reusableDevice.isLocalEmulator ? "emulator" : "device"} "${reusableDevice.name}"; will reuse it.'); - return reusableDevice; - } - - // No running emulator found. Attempt to start one. - printStatus('Starting iOS Simulator, because did not find existing connected devices.'); - final bool started = await SimControl.instance.boot(); - if (started) { - return IOSSimulatorUtils.instance.getAttachedDevices().first; - } else { - printError('Failed to start iOS Simulator.'); - return null; - } - } else if (platform.isLinux || platform.isWindows) { - // On Linux and Windows, for now, we just grab the first connected device we can find. - if (devices.isEmpty) { - printError('No devices found.'); - return null; - } else if (devices.length > 1) { - printStatus('Found multiple connected devices:'); - printStatus(devices.map((Device d) => ' - ${d.name}\n').join('')); - } - printStatus('Using device ${devices.first.name}.'); - return devices.first; - } else { - printError('The operating system on this computer is not supported.'); + if (devices.isEmpty) { + printError('No devices found.'); return null; + } else if (devices.length > 1) { + printStatus('Found multiple connected devices:'); + printStatus(devices.map((Device d) => ' - ${d.name}\n').join('')); } + printStatus('Using device ${devices.first.name}.'); + return devices.first; } /// Starts the application on the device given command configuration. diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index 5a57b382dbe..697be3bac64 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart @@ -59,117 +59,6 @@ class SimControl { /// Returns [SimControl] active in the current app context (i.e. zone). static SimControl get instance => context[SimControl]; - Future boot({ String deviceName }) async { - if (_isAnyConnected()) - return true; - - if (deviceName == null) { - final SimDevice testDevice = _createTestDevice(); - if (testDevice == null) { - return false; - } - deviceName = testDevice.name; - } - - // `xcrun instruments` requires a template (-t). @yjbanov has no idea what - // "template" is but the built-in 'Blank' seems to work. -l causes xcrun to - // quit after a time limit without killing the simulator. We quit after - // 1 second. - final List args = [_xcrunPath, 'instruments', '-w', deviceName, '-t', 'Blank', '-l', '1']; - printTrace(args.join(' ')); - runDetached(args); - printStatus('Waiting for iOS Simulator to boot...'); - - bool connected = false; - int attempted = 0; - while (!connected && attempted < 20) { - connected = _isAnyConnected(); - if (!connected) { - printStatus('Still waiting for iOS Simulator to boot...'); - await new Future.delayed(const Duration(seconds: 1)); - } - attempted++; - } - - if (connected) { - printStatus('Connected to iOS Simulator.'); - return true; - } else { - printStatus('Timed out waiting for iOS Simulator to boot.'); - return false; - } - } - - SimDevice _createTestDevice() { - final SimDeviceType deviceType = _findSuitableDeviceType(); - if (deviceType == null) - return null; - - final String runtime = _findSuitableRuntime(); - if (runtime == null) - return null; - - // Delete any old test devices - getDevices() - .where((SimDevice d) => d.name.endsWith(_kFlutterTestDeviceSuffix)) - .forEach(_deleteDevice); - - // Create new device - final String deviceName = '${deviceType.name} $_kFlutterTestDeviceSuffix'; - final List args = [_xcrunPath, 'simctl', 'create', deviceName, deviceType.identifier, runtime]; - printTrace(args.join(' ')); - runCheckedSync(args); - - return getDevices().firstWhere((SimDevice d) => d.name == deviceName); - } - - SimDeviceType _findSuitableDeviceType() { - final List> allTypes = _list(SimControlListSection.devicetypes); - final List> usableTypes = allTypes - .where((Map info) => info['name'].startsWith('iPhone')) - .toList() - ..sort((Map r1, Map r2) => -compareIphoneVersions(r1['identifier'], r2['identifier'])); - - if (usableTypes.isEmpty) { - printError( - 'No suitable device type found.\n' - 'You may launch an iOS Simulator manually and Flutter will attempt to use it.' - ); - } - - return new SimDeviceType( - usableTypes.first['name'], - usableTypes.first['identifier'] - ); - } - - String _findSuitableRuntime() { - final List> allRuntimes = _list(SimControlListSection.runtimes); - final List> usableRuntimes = allRuntimes - .where((Map info) => info['name'].startsWith('iOS')) - .toList() - ..sort((Map r1, Map r2) => -compareIosVersions(r1['version'], r2['version'])); - - if (usableRuntimes.isEmpty) { - printError( - 'No suitable iOS runtime found.\n' - 'You may launch an iOS Simulator manually and Flutter will attempt to use it.' - ); - } - - return usableRuntimes.first['identifier']; - } - - void _deleteDevice(SimDevice device) { - try { - final List args = [_xcrunPath, 'simctl', 'delete', device.name]; - printTrace(args.join(' ')); - runCheckedSync(args); - } catch(e) { - printError(e); - } - } - /// Runs `simctl list --json` and returns the JSON of the corresponding /// [section]. /// @@ -226,8 +115,6 @@ class SimControl { return getDevices().where((SimDevice device) => device.isBooted).toList(); } - bool _isAnyConnected() => getConnectedDevices().isNotEmpty; - Future isInstalled(String deviceId, String appId) { return exitsHappyAsync([ _xcrunPath, diff --git a/packages/flutter_tools/test/commands/drive_test.dart b/packages/flutter_tools/test/commands/drive_test.dart index beef6861c54..aac769599d4 100644 --- a/packages/flutter_tools/test/commands/drive_test.dart +++ b/packages/flutter_tools/test/commands/drive_test.dart @@ -13,7 +13,6 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/drive.dart'; import 'package:flutter_tools/src/device.dart'; -import 'package:flutter_tools/src/ios/simulators.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; @@ -238,52 +237,7 @@ void main() { }); }); - group('findTargetDevice on iOS', () { - Platform macOsPlatform() => new FakePlatform(operatingSystem: 'macos'); - - testUsingContext('uses existing emulator', () async { - withMockDevice(); - when(mockDevice.name).thenReturn('mock-simulator'); - when(mockDevice.isLocalEmulator).thenReturn(new Future.value(true)); - - final Device device = await findTargetDevice(); - expect(device.name, 'mock-simulator'); - }, overrides: { - FileSystem: () => fs, - Platform: macOsPlatform, - }); - - testUsingContext('uses existing Android device if and there are no simulators', () async { - mockDevice = new MockAndroidDevice(); - when(mockDevice.name).thenReturn('mock-android-device'); - when(mockDevice.isLocalEmulator).thenReturn(new Future.value(false)); - withMockDevice(mockDevice); - - final Device device = await findTargetDevice(); - expect(device.name, 'mock-android-device'); - }, overrides: { - FileSystem: () => fs, - Platform: macOsPlatform, - }); - - testUsingContext('launches emulator', () async { - when(SimControl.instance.boot()).thenReturn(true); - final Device emulator = new MockDevice(); - when(emulator.name).thenReturn('new-simulator'); - when(IOSSimulatorUtils.instance.getAttachedDevices()) - .thenReturn([emulator]); - - final Device device = await findTargetDevice(); - expect(device.name, 'new-simulator'); - }, overrides: { - FileSystem: () => fs, - Platform: macOsPlatform, - }); - }); - void findTargetDeviceOnOperatingSystem(String operatingSystem) { - assert(operatingSystem == 'windows' || operatingSystem == 'linux'); - Platform platform() => new FakePlatform(operatingSystem: operatingSystem); testUsingContext('returns null if no devices found', () async { @@ -313,6 +267,24 @@ void main() { group('findTargetDevice on Windows', () { findTargetDeviceOnOperatingSystem('windows'); }); + + group('findTargetDevice on macOS', () { + findTargetDeviceOnOperatingSystem('macos'); + + Platform macOsPlatform() => new FakePlatform(operatingSystem: 'macos'); + + testUsingContext('uses existing simulator', () async { + withMockDevice(); + when(mockDevice.name).thenReturn('mock-simulator'); + when(mockDevice.isLocalEmulator).thenReturn(new Future.value(true)); + + final Device device = await findTargetDevice(); + expect(device.name, 'mock-simulator'); + }, overrides: { + FileSystem: () => fs, + Platform: macOsPlatform, + }); + }); }); }