From 88e756d19eee1c9b42f37bd01c0c5cf77ed2ed36 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 24 Jun 2021 18:46:04 -0700 Subject: [PATCH] [flutter_tools] well known device ids (#85184) --- .../src/android/android_device_discovery.dart | 3 ++ .../flutter_tools/lib/src/context_runner.dart | 1 - .../lib/src/custom_devices/custom_device.dart | 3 ++ packages/flutter_tools/lib/src/device.dart | 48 ++++++++++++------- .../lib/src/flutter_device_manager.dart | 3 -- .../lib/src/fuchsia/fuchsia_device.dart | 3 ++ .../flutter_tools/lib/src/ios/devices.dart | 3 ++ .../flutter_tools/lib/src/ios/simulators.dart | 3 ++ .../lib/src/linux/linux_device.dart | 3 ++ .../lib/src/macos/macos_device.dart | 3 ++ .../lib/src/macos/macos_ipad_device.dart | 3 ++ .../lib/src/tester/flutter_tester.dart | 7 ++- .../flutter_tools/lib/src/web/web_device.dart | 3 ++ .../lib/src/windows/windows_device.dart | 3 ++ .../test/general.shard/device_test.dart | 40 ++++++++++++++++ .../linux/linux_device_test.dart | 11 +++++ .../macos/macos_device_test.dart | 16 +++++++ .../tester/flutter_tester_test.dart | 2 - .../test/general.shard/web/devices_test.dart | 15 ++++++ .../windows/windows_device_test.dart | 16 +++++++ .../flutter_tools/test/src/fake_devices.dart | 3 ++ 21 files changed, 166 insertions(+), 26 deletions(-) diff --git a/packages/flutter_tools/lib/src/android/android_device_discovery.dart b/packages/flutter_tools/lib/src/android/android_device_discovery.dart index b712fbdeb3d..fedefe4bbd1 100644 --- a/packages/flutter_tools/lib/src/android/android_device_discovery.dart +++ b/packages/flutter_tools/lib/src/android/android_device_discovery.dart @@ -195,4 +195,7 @@ class AndroidDevices extends PollingDeviceDiscovery { } } } + + @override + List get wellKnownIds => const []; } diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index 8769d1f969a..378ae678029 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -191,7 +191,6 @@ Future runInContext( artifacts: globals.artifacts, flutterVersion: globals.flutterVersion, androidWorkflow: androidWorkflow, - config: globals.config, fuchsiaWorkflow: fuchsiaWorkflow, xcDevice: globals.xcdevice, userMessages: globals.userMessages, diff --git a/packages/flutter_tools/lib/src/custom_devices/custom_device.dart b/packages/flutter_tools/lib/src/custom_devices/custom_device.dart index a8d535e5d1e..b36a4a22089 100644 --- a/packages/flutter_tools/lib/src/custom_devices/custom_device.dart +++ b/packages/flutter_tools/lib/src/custom_devices/custom_device.dart @@ -767,4 +767,7 @@ class CustomDevices extends PollingDeviceDiscovery { @override Future> getDiagnostics() async => const []; + + @override + List get wellKnownIds => const []; } diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 9e7982402ff..14f3b2f4cc5 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -110,29 +110,36 @@ abstract class DeviceManager { // Some discoverers have hard-coded device IDs and return quickly, and others // shell out to other processes and can take longer. + // If an ID was specified, first check if it was a "well-known" device id. + final Set wellKnownIds = _platformDiscoverers + .expand((DeviceDiscovery discovery) => discovery.wellKnownIds) + .toSet(); + final bool hasWellKnownId = hasSpecifiedDeviceId && wellKnownIds.contains(specifiedDeviceId); + // Process discoverers as they can return results, so if an exact match is // found quickly, we don't wait for all the discoverers to complete. final List prefixMatches = []; final Completer exactMatchCompleter = Completer(); final List>> futureDevices = >>[ for (final DeviceDiscovery discoverer in _platformDiscoverers) - discoverer - .devices - .then((List devices) { - for (final Device device in devices) { - if (exactlyMatchesDeviceId(device)) { - exactMatchCompleter.complete(device); - return null; + if (!hasWellKnownId || discoverer.wellKnownIds.contains(specifiedDeviceId)) + discoverer + .devices + .then((List devices) { + for (final Device device in devices) { + if (exactlyMatchesDeviceId(device)) { + exactMatchCompleter.complete(device); + return null; + } + if (startsWithDeviceId(device)) { + prefixMatches.add(device); + } } - if (startsWithDeviceId(device)) { - prefixMatches.add(device); - } - } - return null; - }, onError: (dynamic error, StackTrace stackTrace) { - // Return matches from other discoverers even if one fails. - _logger.printTrace('Ignored error discovering $deviceId: $error'); - }) + return null; + }, onError: (dynamic error, StackTrace stackTrace) { + // Return matches from other discoverers even if one fails. + _logger.printTrace('Ignored error discovering $deviceId: $error'); + }) ]; // Wait for an exact match, or for all discoverers to return results. @@ -336,6 +343,15 @@ abstract class DeviceDiscovery { /// Gets a list of diagnostic messages pertaining to issues with any connected /// devices (will be an empty list if there are no issues). Future> getDiagnostics() => Future>.value([]); + + /// Hard-coded device IDs that the discoverer can produce. + /// + /// These values are used by the device discovery to determine if it can + /// short-circuit the other detectors if a specific ID is provided. If a + /// discoverer has no valid fixed IDs, these should be left empty. + /// + /// For example, 'windows' or 'linux'. + List get wellKnownIds; } /// A [DeviceDiscovery] implementation that uses polling to discover device adds diff --git a/packages/flutter_tools/lib/src/flutter_device_manager.dart b/packages/flutter_tools/lib/src/flutter_device_manager.dart index 7d31a389ebb..fc9a46ce85d 100644 --- a/packages/flutter_tools/lib/src/flutter_device_manager.dart +++ b/packages/flutter_tools/lib/src/flutter_device_manager.dart @@ -11,7 +11,6 @@ import 'android/android_device_discovery.dart'; import 'android/android_sdk.dart'; import 'android/android_workflow.dart'; import 'artifacts.dart'; -import 'base/config.dart'; import 'base/file_system.dart'; import 'base/logger.dart'; import 'base/os.dart'; @@ -55,7 +54,6 @@ class FlutterDeviceManager extends DeviceManager { @required IOSWorkflow iosWorkflow, @required FuchsiaWorkflow fuchsiaWorkflow, @required FlutterVersion flutterVersion, - @required Config config, @required Artifacts artifacts, @required MacOSWorkflow macOSWorkflow, @required UserMessages userMessages, @@ -93,7 +91,6 @@ class FlutterDeviceManager extends DeviceManager { fileSystem: fileSystem, flutterVersion: flutterVersion, processManager: processManager, - config: config, logger: logger, artifacts: artifacts, operatingSystemUtils: operatingSystemUtils, diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart index ad8d4d76f77..f89dd1d246e 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart @@ -231,6 +231,9 @@ class FuchsiaDevices extends PollingDeviceDiscovery { } return FuchsiaDevice(resolvedHost, name: name); } + + @override + List get wellKnownIds => const []; } diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index bc8664d1588..b79ea8093ee 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -133,6 +133,9 @@ class IOSDevices extends PollingDeviceDiscovery { return _xcdevice.getDiagnostics(); } + + @override + List get wellKnownIds => const []; } enum IOSDeviceInterface { diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index ce085ab2649..7de44aef554 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart @@ -48,6 +48,9 @@ class IOSSimulators extends PollingDeviceDiscovery { @override Future> pollingGetDevices({ Duration timeout }) async => _iosSimulatorUtils.getAttachedDevices(); + + @override + List get wellKnownIds => const []; } class IOSSimulatorUtils { diff --git a/packages/flutter_tools/lib/src/linux/linux_device.dart b/packages/flutter_tools/lib/src/linux/linux_device.dart index fab26805d09..1dff8ae1466 100644 --- a/packages/flutter_tools/lib/src/linux/linux_device.dart +++ b/packages/flutter_tools/lib/src/linux/linux_device.dart @@ -135,4 +135,7 @@ class LinuxDevices extends PollingDeviceDiscovery { @override Future> getDiagnostics() async => const []; + + @override + List get wellKnownIds => const ['linux']; } diff --git a/packages/flutter_tools/lib/src/macos/macos_device.dart b/packages/flutter_tools/lib/src/macos/macos_device.dart index 19715a2fed1..dc746a522da 100644 --- a/packages/flutter_tools/lib/src/macos/macos_device.dart +++ b/packages/flutter_tools/lib/src/macos/macos_device.dart @@ -148,4 +148,7 @@ class MacOSDevices extends PollingDeviceDiscovery { @override Future> getDiagnostics() async => const []; + + @override + List get wellKnownIds => const ['macos']; } diff --git a/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart b/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart index ada068b91e4..3b34f451d67 100644 --- a/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart +++ b/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart @@ -144,4 +144,7 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery { @override Future> getDiagnostics() async => const []; + + @override + List get wellKnownIds => const ['designed-for-ipad']; } diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart index 6d4a74ffee1..f9cd32436a0 100644 --- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart +++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart @@ -11,7 +11,6 @@ import 'package:process/process.dart'; import '../application_package.dart'; import '../artifacts.dart'; -import '../base/config.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; @@ -268,9 +267,6 @@ class FlutterTesterDevices extends PollingDeviceDiscovery { @required ProcessManager processManager, @required Logger logger, @required FlutterVersion flutterVersion, - // TODO(jonahwilliams): remove after flutter rolls - // ignore: avoid_unused_constructor_parameters - Config config, @required OperatingSystemUtils operatingSystemUtils, }) : _testerDevice = FlutterTesterDevice( kTesterDeviceId, @@ -299,4 +295,7 @@ class FlutterTesterDevices extends PollingDeviceDiscovery { Future> pollingGetDevices({ Duration timeout }) async { return showFlutterTesterDevice ? [_testerDevice] : []; } + + @override + List get wellKnownIds => const [kTesterDeviceId]; } diff --git a/packages/flutter_tools/lib/src/web/web_device.dart b/packages/flutter_tools/lib/src/web/web_device.dart index 7c214bbf307..da1ea5c8548 100644 --- a/packages/flutter_tools/lib/src/web/web_device.dart +++ b/packages/flutter_tools/lib/src/web/web_device.dart @@ -362,6 +362,9 @@ class WebDevices extends PollingDeviceDiscovery { @override bool get supportsPlatform => _featureFlags.isWebEnabled; + + @override + List get wellKnownIds => const ['chrome', 'web-server', 'edge']; } @visibleForTesting diff --git a/packages/flutter_tools/lib/src/windows/windows_device.dart b/packages/flutter_tools/lib/src/windows/windows_device.dart index 1c59732100a..4aaa77a98b6 100644 --- a/packages/flutter_tools/lib/src/windows/windows_device.dart +++ b/packages/flutter_tools/lib/src/windows/windows_device.dart @@ -454,4 +454,7 @@ class WindowsDevices extends PollingDeviceDiscovery { @override Future> getDiagnostics() async => const []; + + @override + List get wellKnownIds => const ['windows', 'winuwp']; } diff --git a/packages/flutter_tools/test/general.shard/device_test.dart b/packages/flutter_tools/test/general.shard/device_test.dart index 4639107d3d0..c3950c78492 100644 --- a/packages/flutter_tools/test/general.shard/device_test.dart +++ b/packages/flutter_tools/test/general.shard/device_test.dart @@ -71,6 +71,33 @@ void main() { expect(logger.traceText, contains('Ignored error discovering 0553790d0a4e726f')); }); + testWithoutContext('getDeviceById exact matcher with well known ID', () async { + final FakeDevice device1 = FakeDevice('Windows', 'windows'); + final FakeDevice device2 = FakeDevice('Nexus 5X', '01abfc49119c410e'); + final FakeDevice device3 = FakeDevice('iPod touch', '82564b38861a9a5'); + final List devices = [device1, device2, device3]; + final BufferLogger logger = BufferLogger.test(); + + // Because the well known ID will match, no other device discovery will run. + final DeviceManager deviceManager = TestDeviceManager( + devices, + deviceDiscoveryOverrides: [ + ThrowingPollingDeviceDiscovery(), + LongPollingDeviceDiscovery(), + ], + logger: logger, + terminal: Terminal.test(), + wellKnownId: 'windows', + ); + + Future expectDevice(String id, List expected) async { + deviceManager.specifiedDeviceId = id; + expect(await deviceManager.getDevicesById(id), expected); + } + await expectDevice('windows', [device1]); + expect(logger.traceText, isEmpty); + }); + testWithoutContext('getDeviceById prefix matcher', () async { final FakeDevice device1 = FakeDevice('Nexus 5', '0553790d0a4e726f'); final FakeDevice device2 = FakeDevice('Nexus 5X', '01abfc49119c410e'); @@ -467,8 +494,12 @@ class TestDeviceManager extends DeviceManager { List deviceDiscoveryOverrides, @required Logger logger, @required Terminal terminal, + String wellKnownId, }) : super(logger: logger, terminal: terminal, userMessages: UserMessages()) { _fakeDeviceDiscoverer = FakePollingDeviceDiscovery(); + if (wellKnownId != null) { + _fakeDeviceDiscoverer.wellKnownIds.add(wellKnownId); + } _deviceDiscoverers = [ _fakeDeviceDiscoverer, if (deviceDiscoveryOverrides != null) @@ -516,6 +547,9 @@ class MockDeviceDiscovery extends Fake implements DeviceDiscovery { discoverDevicesCalled += 1; return deviceValues; } + + @override + List get wellKnownIds => []; } class FakeFlutterProject extends Fake implements FlutterProject {} @@ -545,6 +579,9 @@ class LongPollingDeviceDiscovery extends PollingDeviceDiscovery { @override bool get canListAnything => true; + + @override + final List wellKnownIds = []; } class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery { @@ -560,6 +597,9 @@ class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery { @override bool get canListAnything => true; + + @override + List get wellKnownIds => []; } class FakeTerminal extends Fake implements Terminal { diff --git a/packages/flutter_tools/test/general.shard/linux/linux_device_test.dart b/packages/flutter_tools/test/general.shard/linux/linux_device_test.dart index ccc5926350d..6ec411a7d8b 100644 --- a/packages/flutter_tools/test/general.shard/linux/linux_device_test.dart +++ b/packages/flutter_tools/test/general.shard/linux/linux_device_test.dart @@ -96,6 +96,17 @@ void main() { ).devices, hasLength(1)); }); + testWithoutContext('LinuxDevice has well known id "linux"', () async { + expect(LinuxDevices( + fileSystem: MemoryFileSystem.test(), + platform: linux, + featureFlags: TestFeatureFlags(isLinuxEnabled: true), + logger: BufferLogger.test(), + processManager: FakeProcessManager.any(), + operatingSystemUtils: FakeOperatingSystemUtils(), + ).wellKnownIds, ['linux']); + }); + testWithoutContext('LinuxDevice: discoverDevices', () async { // Timeout ignored. final List devices = await LinuxDevices( diff --git a/packages/flutter_tools/test/general.shard/macos/macos_device_test.dart b/packages/flutter_tools/test/general.shard/macos/macos_device_test.dart index 4a4a2d7aa4e..1919c1069ed 100644 --- a/packages/flutter_tools/test/general.shard/macos/macos_device_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/macos_device_test.dart @@ -132,6 +132,22 @@ void main() { expect(await macOSDevices.devices, hasLength(1)); }); + testWithoutContext('has a well known device id macos', () async { + final MacOSDevices macOSDevices = MacOSDevices( + fileSystem: MemoryFileSystem.test(), + processManager: FakeProcessManager.any(), + logger: BufferLogger.test(), + platform: macOS, + operatingSystemUtils: FakeOperatingSystemUtils(), + macOSWorkflow: MacOSWorkflow( + featureFlags: TestFeatureFlags(isMacOSEnabled: true), + platform: macOS, + ), + ); + + expect(macOSDevices.wellKnownIds, ['macos']); + }); + testWithoutContext('can discover devices with a provided timeout', () async { final MacOSDevices macOSDevices = MacOSDevices( fileSystem: MemoryFileSystem.test(), diff --git a/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart b/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart index 77d3a8aac0c..93d5ba22436 100644 --- a/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart +++ b/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart @@ -9,7 +9,6 @@ import 'dart:async'; import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/base/config.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; @@ -181,7 +180,6 @@ FlutterTesterDevices setUpFlutterTesterDevices() { artifacts: Artifacts.test(), processManager: FakeProcessManager.any(), fileSystem: MemoryFileSystem.test(), - config: Config.test(), flutterVersion: FakeFlutterVersion(), operatingSystemUtils: FakeOperatingSystemUtils(), ); diff --git a/packages/flutter_tools/test/general.shard/web/devices_test.dart b/packages/flutter_tools/test/general.shard/web/devices_test.dart index 6d4aae643f5..d17f9992d53 100644 --- a/packages/flutter_tools/test/general.shard/web/devices_test.dart +++ b/packages/flutter_tools/test/general.shard/web/devices_test.dart @@ -124,6 +124,21 @@ void main() { contains(isA())); }); + testWithoutContext('Has well known device ids chrome, edge, and web-server', () async { + final WebDevices webDevices = WebDevices( + featureFlags: TestFeatureFlags(isWebEnabled: true), + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), + platform: FakePlatform( + operatingSystem: 'linux', + environment: {} + ), + processManager: FakeProcessManager.any(), + ); + + expect(webDevices.wellKnownIds, ['chrome', 'web-server', 'edge']); + }); + testWithoutContext('Chrome device is not listed when Chrome cannot be run', () async { final FakeProcessManager processManager = FakeProcessManager.empty(); processManager.excludedExecutables = {kLinuxExecutable}; diff --git a/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart b/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart index 1a7f8f9b88f..67f2d113266 100644 --- a/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart +++ b/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart @@ -116,6 +116,22 @@ void main() { ).devices, hasLength(2)); }); + testWithoutContext('WindowsDevices has windows and winuwp well known devices', () async { + final FeatureFlags featureFlags = TestFeatureFlags(isWindowsEnabled: true, isWindowsUwpEnabled: true); + expect(WindowsDevices( + windowsWorkflow: WindowsWorkflow( + featureFlags: featureFlags, + platform: FakePlatform(operatingSystem: 'windows') + ), + operatingSystemUtils: FakeOperatingSystemUtils(), + logger: BufferLogger.test(), + processManager: FakeProcessManager.any(), + fileSystem: MemoryFileSystem.test(), + featureFlags: featureFlags, + uwptool: FakeUwpTool(), + ).wellKnownIds, ['windows', 'winuwp']); + }); + testWithoutContext('WindowsDevices ignores the timeout provided to discoverDevices', () async { final WindowsDevices windowsDevices = WindowsDevices( windowsWorkflow: WindowsWorkflow( diff --git a/packages/flutter_tools/test/src/fake_devices.dart b/packages/flutter_tools/test/src/fake_devices.dart index 5bf0f714c05..ea6685b6119 100644 --- a/packages/flutter_tools/test/src/fake_devices.dart +++ b/packages/flutter_tools/test/src/fake_devices.dart @@ -175,6 +175,9 @@ class FakePollingDeviceDiscovery extends PollingDeviceDiscovery { @override Stream get onRemoved => _onRemovedController.stream; + + @override + List wellKnownIds = []; } /// A fake implementation of the [DeviceLogReader].