From 54becbf3bf350de10dac8daf4552e761fef63332 Mon Sep 17 00:00:00 2001 From: mattijsf Date: Tue, 6 Nov 2018 00:09:39 +0100 Subject: [PATCH] Ignore unreachable iOS devices in IOSDevice.getAttachedDevices (#23776) --- AUTHORS | 1 + .../flutter_tools/lib/src/ios/devices.dart | 11 ++++++++--- packages/flutter_tools/lib/src/ios/mac.dart | 17 +++++++++++++++-- .../flutter_tools/test/ios/devices_test.dart | 19 +++++++++++++++++++ packages/flutter_tools/test/ios/mac_test.dart | 8 ++++++++ 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index fa1be5ae2f..f3edfbee3f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,3 +29,4 @@ Lukasz Piliszczuk Felix Schmidt Artur Rymarz Stefan Mitev +Mattijs Fuijkschot diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index f0e2422c78..d65689f820 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -149,9 +149,14 @@ class IOSDevice extends Device { if (id.isEmpty) continue; - final String deviceName = await iMobileDevice.getInfoForDevice(id, 'DeviceName'); - final String sdkVersion = await iMobileDevice.getInfoForDevice(id, 'ProductVersion'); - devices.add(IOSDevice(id, name: deviceName, sdkVersion: sdkVersion)); + try { + final String deviceName = await iMobileDevice.getInfoForDevice(id, 'DeviceName'); + final String sdkVersion = await iMobileDevice.getInfoForDevice(id, 'ProductVersion'); + devices.add(IOSDevice(id, name: deviceName, sdkVersion: sdkVersion)); + } on IOSDeviceNotFoundError catch (error) { + // Unable to find device with given udid. Possibly a network device. + printTrace('Error getting attached iOS device: $error'); + } } return devices; } diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index a3a2aabbf3..6238ce552c 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -83,6 +83,17 @@ class PropertyList { } } +/// Specialized exception for expected situations where the ideviceinfo +/// tool responds with exit code 255 / 'No device found' message +class IOSDeviceNotFoundError implements Exception { + IOSDeviceNotFoundError(this.message); + + final String message; + + @override + String toString() => message; +} + class IMobileDevice { const IMobileDevice(); @@ -118,11 +129,13 @@ class IMobileDevice { Future getInfoForDevice(String deviceID, String key) async { try { final ProcessResult result = await processManager.run(['ideviceinfo', '-u', deviceID, '-k', key, '--simple']); + if (result.exitCode == 255 && result.stdout != null && result.stdout.contains('No device found')) + throw IOSDeviceNotFoundError('ideviceinfo could not find device:\n${result.stdout}'); if (result.exitCode != 0) - throw ToolExit('idevice_id returned an error:\n${result.stderr}'); + throw ToolExit('ideviceinfo returned an error:\n${result.stderr}'); return result.stdout.trim(); } on ProcessException { - throw ToolExit('Failed to invoke idevice_id. Run flutter doctor.'); + throw ToolExit('Failed to invoke ideviceinfo. Run flutter doctor.'); } } diff --git a/packages/flutter_tools/test/ios/devices_test.dart b/packages/flutter_tools/test/ios/devices_test.dart index ba81bc529d..80b2b49cb5 100644 --- a/packages/flutter_tools/test/ios/devices_test.dart +++ b/packages/flutter_tools/test/ios/devices_test.dart @@ -77,6 +77,25 @@ f577a7903cc54959be2e34bc4f7f80b7009efcf4 }, overrides: { IMobileDevice: () => mockIMobileDevice, }); + + testUsingContext('returns attached devices and ignores devices that cannot be found by ideviceinfo', () async { + when(iMobileDevice.isInstalled).thenReturn(true); + when(iMobileDevice.getAvailableDeviceIDs()) + .thenAnswer((Invocation invocation) => Future.value(''' +98206e7a4afd4aedaff06e687594e089dede3c44 +f577a7903cc54959be2e34bc4f7f80b7009efcf4 +''')); + when(iMobileDevice.getInfoForDevice('98206e7a4afd4aedaff06e687594e089dede3c44', 'DeviceName')) + .thenAnswer((_) => Future.value('La tele me regarde')); + when(iMobileDevice.getInfoForDevice('f577a7903cc54959be2e34bc4f7f80b7009efcf4', 'DeviceName')) + .thenThrow(IOSDeviceNotFoundError('Device not found')); + final List devices = await IOSDevice.getAttachedDevices(); + expect(devices, hasLength(1)); + expect(devices[0].id, '98206e7a4afd4aedaff06e687594e089dede3c44'); + expect(devices[0].name, 'La tele me regarde'); + }, overrides: { + IMobileDevice: () => mockIMobileDevice, + }); }); group('decodeSyslog', () { diff --git a/packages/flutter_tools/test/ios/mac_test.dart b/packages/flutter_tools/test/ios/mac_test.dart index 77aedff31d..715e654ef7 100644 --- a/packages/flutter_tools/test/ios/mac_test.dart +++ b/packages/flutter_tools/test/ios/mac_test.dart @@ -127,6 +127,14 @@ void main() { ProcessManager: () => mockProcessManager, }); + testUsingContext('getInfoForDevice throws IOSDeviceNotFoundError when ideviceinfo returns specific error code and message', () async { + when(mockProcessManager.run(['ideviceinfo', '-u', 'foo', '-k', 'bar', '--simple'])) + .thenAnswer((_) => Future.value(ProcessResult(1, 255, 'No device found with udid foo, is it plugged in?', ''))); + expect(() async => await iMobileDevice.getInfoForDevice('foo', 'bar'), throwsA(isInstanceOf())); + }, overrides: { + ProcessManager: () => mockProcessManager, + }); + group('screenshot', () { final String outputPath = fs.path.join('some', 'test', 'path', 'image.png'); MockProcessManager mockProcessManager;