Unverified Commit 88e756d1 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] well known device ids (#85184)

parent c22bedc5
...@@ -195,4 +195,7 @@ class AndroidDevices extends PollingDeviceDiscovery { ...@@ -195,4 +195,7 @@ class AndroidDevices extends PollingDeviceDiscovery {
} }
} }
} }
@override
List<String> get wellKnownIds => const <String>[];
} }
...@@ -191,7 +191,6 @@ Future<T> runInContext<T>( ...@@ -191,7 +191,6 @@ Future<T> runInContext<T>(
artifacts: globals.artifacts, artifacts: globals.artifacts,
flutterVersion: globals.flutterVersion, flutterVersion: globals.flutterVersion,
androidWorkflow: androidWorkflow, androidWorkflow: androidWorkflow,
config: globals.config,
fuchsiaWorkflow: fuchsiaWorkflow, fuchsiaWorkflow: fuchsiaWorkflow,
xcDevice: globals.xcdevice, xcDevice: globals.xcdevice,
userMessages: globals.userMessages, userMessages: globals.userMessages,
......
...@@ -767,4 +767,7 @@ class CustomDevices extends PollingDeviceDiscovery { ...@@ -767,4 +767,7 @@ class CustomDevices extends PollingDeviceDiscovery {
@override @override
Future<List<String>> getDiagnostics() async => const <String>[]; Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>[];
} }
...@@ -110,29 +110,36 @@ abstract class DeviceManager { ...@@ -110,29 +110,36 @@ abstract class DeviceManager {
// Some discoverers have hard-coded device IDs and return quickly, and others // Some discoverers have hard-coded device IDs and return quickly, and others
// shell out to other processes and can take longer. // 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<String> 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 // 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. // found quickly, we don't wait for all the discoverers to complete.
final List<Device> prefixMatches = <Device>[]; final List<Device> prefixMatches = <Device>[];
final Completer<Device> exactMatchCompleter = Completer<Device>(); final Completer<Device> exactMatchCompleter = Completer<Device>();
final List<Future<List<Device>>> futureDevices = <Future<List<Device>>>[ final List<Future<List<Device>>> futureDevices = <Future<List<Device>>>[
for (final DeviceDiscovery discoverer in _platformDiscoverers) for (final DeviceDiscovery discoverer in _platformDiscoverers)
discoverer if (!hasWellKnownId || discoverer.wellKnownIds.contains(specifiedDeviceId))
.devices discoverer
.then((List<Device> devices) { .devices
for (final Device device in devices) { .then((List<Device> devices) {
if (exactlyMatchesDeviceId(device)) { for (final Device device in devices) {
exactMatchCompleter.complete(device); if (exactlyMatchesDeviceId(device)) {
return null; exactMatchCompleter.complete(device);
} return null;
if (startsWithDeviceId(device)) { }
prefixMatches.add(device); if (startsWithDeviceId(device)) {
prefixMatches.add(device);
}
} }
} return null;
return null; }, onError: (dynamic error, StackTrace stackTrace) {
}, onError: (dynamic error, StackTrace stackTrace) { // Return matches from other discoverers even if one fails.
// Return matches from other discoverers even if one fails. _logger.printTrace('Ignored error discovering $deviceId: $error');
_logger.printTrace('Ignored error discovering $deviceId: $error'); })
})
]; ];
// Wait for an exact match, or for all discoverers to return results. // Wait for an exact match, or for all discoverers to return results.
...@@ -336,6 +343,15 @@ abstract class DeviceDiscovery { ...@@ -336,6 +343,15 @@ abstract class DeviceDiscovery {
/// Gets a list of diagnostic messages pertaining to issues with any connected /// Gets a list of diagnostic messages pertaining to issues with any connected
/// devices (will be an empty list if there are no issues). /// devices (will be an empty list if there are no issues).
Future<List<String>> getDiagnostics() => Future<List<String>>.value(<String>[]); Future<List<String>> getDiagnostics() => Future<List<String>>.value(<String>[]);
/// 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<String> get wellKnownIds;
} }
/// A [DeviceDiscovery] implementation that uses polling to discover device adds /// A [DeviceDiscovery] implementation that uses polling to discover device adds
......
...@@ -11,7 +11,6 @@ import 'android/android_device_discovery.dart'; ...@@ -11,7 +11,6 @@ import 'android/android_device_discovery.dart';
import 'android/android_sdk.dart'; import 'android/android_sdk.dart';
import 'android/android_workflow.dart'; import 'android/android_workflow.dart';
import 'artifacts.dart'; import 'artifacts.dart';
import 'base/config.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/logger.dart'; import 'base/logger.dart';
import 'base/os.dart'; import 'base/os.dart';
...@@ -55,7 +54,6 @@ class FlutterDeviceManager extends DeviceManager { ...@@ -55,7 +54,6 @@ class FlutterDeviceManager extends DeviceManager {
@required IOSWorkflow iosWorkflow, @required IOSWorkflow iosWorkflow,
@required FuchsiaWorkflow fuchsiaWorkflow, @required FuchsiaWorkflow fuchsiaWorkflow,
@required FlutterVersion flutterVersion, @required FlutterVersion flutterVersion,
@required Config config,
@required Artifacts artifacts, @required Artifacts artifacts,
@required MacOSWorkflow macOSWorkflow, @required MacOSWorkflow macOSWorkflow,
@required UserMessages userMessages, @required UserMessages userMessages,
...@@ -93,7 +91,6 @@ class FlutterDeviceManager extends DeviceManager { ...@@ -93,7 +91,6 @@ class FlutterDeviceManager extends DeviceManager {
fileSystem: fileSystem, fileSystem: fileSystem,
flutterVersion: flutterVersion, flutterVersion: flutterVersion,
processManager: processManager, processManager: processManager,
config: config,
logger: logger, logger: logger,
artifacts: artifacts, artifacts: artifacts,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
......
...@@ -231,6 +231,9 @@ class FuchsiaDevices extends PollingDeviceDiscovery { ...@@ -231,6 +231,9 @@ class FuchsiaDevices extends PollingDeviceDiscovery {
} }
return FuchsiaDevice(resolvedHost, name: name); return FuchsiaDevice(resolvedHost, name: name);
} }
@override
List<String> get wellKnownIds => const <String>[];
} }
......
...@@ -133,6 +133,9 @@ class IOSDevices extends PollingDeviceDiscovery { ...@@ -133,6 +133,9 @@ class IOSDevices extends PollingDeviceDiscovery {
return _xcdevice.getDiagnostics(); return _xcdevice.getDiagnostics();
} }
@override
List<String> get wellKnownIds => const <String>[];
} }
enum IOSDeviceInterface { enum IOSDeviceInterface {
......
...@@ -48,6 +48,9 @@ class IOSSimulators extends PollingDeviceDiscovery { ...@@ -48,6 +48,9 @@ class IOSSimulators extends PollingDeviceDiscovery {
@override @override
Future<List<Device>> pollingGetDevices({ Duration timeout }) async => _iosSimulatorUtils.getAttachedDevices(); Future<List<Device>> pollingGetDevices({ Duration timeout }) async => _iosSimulatorUtils.getAttachedDevices();
@override
List<String> get wellKnownIds => const <String>[];
} }
class IOSSimulatorUtils { class IOSSimulatorUtils {
......
...@@ -135,4 +135,7 @@ class LinuxDevices extends PollingDeviceDiscovery { ...@@ -135,4 +135,7 @@ class LinuxDevices extends PollingDeviceDiscovery {
@override @override
Future<List<String>> getDiagnostics() async => const <String>[]; Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>['linux'];
} }
...@@ -148,4 +148,7 @@ class MacOSDevices extends PollingDeviceDiscovery { ...@@ -148,4 +148,7 @@ class MacOSDevices extends PollingDeviceDiscovery {
@override @override
Future<List<String>> getDiagnostics() async => const <String>[]; Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>['macos'];
} }
...@@ -144,4 +144,7 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery { ...@@ -144,4 +144,7 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery {
@override @override
Future<List<String>> getDiagnostics() async => const <String>[]; Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>['designed-for-ipad'];
} }
...@@ -11,7 +11,6 @@ import 'package:process/process.dart'; ...@@ -11,7 +11,6 @@ import 'package:process/process.dart';
import '../application_package.dart'; import '../application_package.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/config.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
...@@ -268,9 +267,6 @@ class FlutterTesterDevices extends PollingDeviceDiscovery { ...@@ -268,9 +267,6 @@ class FlutterTesterDevices extends PollingDeviceDiscovery {
@required ProcessManager processManager, @required ProcessManager processManager,
@required Logger logger, @required Logger logger,
@required FlutterVersion flutterVersion, @required FlutterVersion flutterVersion,
// TODO(jonahwilliams): remove after flutter rolls
// ignore: avoid_unused_constructor_parameters
Config config,
@required OperatingSystemUtils operatingSystemUtils, @required OperatingSystemUtils operatingSystemUtils,
}) : _testerDevice = FlutterTesterDevice( }) : _testerDevice = FlutterTesterDevice(
kTesterDeviceId, kTesterDeviceId,
...@@ -299,4 +295,7 @@ class FlutterTesterDevices extends PollingDeviceDiscovery { ...@@ -299,4 +295,7 @@ class FlutterTesterDevices extends PollingDeviceDiscovery {
Future<List<Device>> pollingGetDevices({ Duration timeout }) async { Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
return showFlutterTesterDevice ? <Device>[_testerDevice] : <Device>[]; return showFlutterTesterDevice ? <Device>[_testerDevice] : <Device>[];
} }
@override
List<String> get wellKnownIds => const <String>[kTesterDeviceId];
} }
...@@ -362,6 +362,9 @@ class WebDevices extends PollingDeviceDiscovery { ...@@ -362,6 +362,9 @@ class WebDevices extends PollingDeviceDiscovery {
@override @override
bool get supportsPlatform => _featureFlags.isWebEnabled; bool get supportsPlatform => _featureFlags.isWebEnabled;
@override
List<String> get wellKnownIds => const <String>['chrome', 'web-server', 'edge'];
} }
@visibleForTesting @visibleForTesting
......
...@@ -454,4 +454,7 @@ class WindowsDevices extends PollingDeviceDiscovery { ...@@ -454,4 +454,7 @@ class WindowsDevices extends PollingDeviceDiscovery {
@override @override
Future<List<String>> getDiagnostics() async => const <String>[]; Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>['windows', 'winuwp'];
} }
...@@ -71,6 +71,33 @@ void main() { ...@@ -71,6 +71,33 @@ void main() {
expect(logger.traceText, contains('Ignored error discovering 0553790d0a4e726f')); 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<Device> devices = <Device>[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: <DeviceDiscovery>[
ThrowingPollingDeviceDiscovery(),
LongPollingDeviceDiscovery(),
],
logger: logger,
terminal: Terminal.test(),
wellKnownId: 'windows',
);
Future<void> expectDevice(String id, List<Device> expected) async {
deviceManager.specifiedDeviceId = id;
expect(await deviceManager.getDevicesById(id), expected);
}
await expectDevice('windows', <Device>[device1]);
expect(logger.traceText, isEmpty);
});
testWithoutContext('getDeviceById prefix matcher', () async { testWithoutContext('getDeviceById prefix matcher', () async {
final FakeDevice device1 = FakeDevice('Nexus 5', '0553790d0a4e726f'); final FakeDevice device1 = FakeDevice('Nexus 5', '0553790d0a4e726f');
final FakeDevice device2 = FakeDevice('Nexus 5X', '01abfc49119c410e'); final FakeDevice device2 = FakeDevice('Nexus 5X', '01abfc49119c410e');
...@@ -467,8 +494,12 @@ class TestDeviceManager extends DeviceManager { ...@@ -467,8 +494,12 @@ class TestDeviceManager extends DeviceManager {
List<DeviceDiscovery> deviceDiscoveryOverrides, List<DeviceDiscovery> deviceDiscoveryOverrides,
@required Logger logger, @required Logger logger,
@required Terminal terminal, @required Terminal terminal,
String wellKnownId,
}) : super(logger: logger, terminal: terminal, userMessages: UserMessages()) { }) : super(logger: logger, terminal: terminal, userMessages: UserMessages()) {
_fakeDeviceDiscoverer = FakePollingDeviceDiscovery(); _fakeDeviceDiscoverer = FakePollingDeviceDiscovery();
if (wellKnownId != null) {
_fakeDeviceDiscoverer.wellKnownIds.add(wellKnownId);
}
_deviceDiscoverers = <DeviceDiscovery>[ _deviceDiscoverers = <DeviceDiscovery>[
_fakeDeviceDiscoverer, _fakeDeviceDiscoverer,
if (deviceDiscoveryOverrides != null) if (deviceDiscoveryOverrides != null)
...@@ -516,6 +547,9 @@ class MockDeviceDiscovery extends Fake implements DeviceDiscovery { ...@@ -516,6 +547,9 @@ class MockDeviceDiscovery extends Fake implements DeviceDiscovery {
discoverDevicesCalled += 1; discoverDevicesCalled += 1;
return deviceValues; return deviceValues;
} }
@override
List<String> get wellKnownIds => <String>[];
} }
class FakeFlutterProject extends Fake implements FlutterProject {} class FakeFlutterProject extends Fake implements FlutterProject {}
...@@ -545,6 +579,9 @@ class LongPollingDeviceDiscovery extends PollingDeviceDiscovery { ...@@ -545,6 +579,9 @@ class LongPollingDeviceDiscovery extends PollingDeviceDiscovery {
@override @override
bool get canListAnything => true; bool get canListAnything => true;
@override
final List<String> wellKnownIds = <String>[];
} }
class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery { class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery {
...@@ -560,6 +597,9 @@ class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery { ...@@ -560,6 +597,9 @@ class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery {
@override @override
bool get canListAnything => true; bool get canListAnything => true;
@override
List<String> get wellKnownIds => <String>[];
} }
class FakeTerminal extends Fake implements Terminal { class FakeTerminal extends Fake implements Terminal {
......
...@@ -96,6 +96,17 @@ void main() { ...@@ -96,6 +96,17 @@ void main() {
).devices, hasLength(1)); ).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, <String>['linux']);
});
testWithoutContext('LinuxDevice: discoverDevices', () async { testWithoutContext('LinuxDevice: discoverDevices', () async {
// Timeout ignored. // Timeout ignored.
final List<Device> devices = await LinuxDevices( final List<Device> devices = await LinuxDevices(
......
...@@ -132,6 +132,22 @@ void main() { ...@@ -132,6 +132,22 @@ void main() {
expect(await macOSDevices.devices, hasLength(1)); 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, <String>['macos']);
});
testWithoutContext('can discover devices with a provided timeout', () async { testWithoutContext('can discover devices with a provided timeout', () async {
final MacOSDevices macOSDevices = MacOSDevices( final MacOSDevices macOSDevices = MacOSDevices(
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
......
...@@ -9,7 +9,6 @@ import 'dart:async'; ...@@ -9,7 +9,6 @@ import 'dart:async';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.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/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
...@@ -181,7 +180,6 @@ FlutterTesterDevices setUpFlutterTesterDevices() { ...@@ -181,7 +180,6 @@ FlutterTesterDevices setUpFlutterTesterDevices() {
artifacts: Artifacts.test(), artifacts: Artifacts.test(),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
config: Config.test(),
flutterVersion: FakeFlutterVersion(), flutterVersion: FakeFlutterVersion(),
operatingSystemUtils: FakeOperatingSystemUtils(), operatingSystemUtils: FakeOperatingSystemUtils(),
); );
......
...@@ -124,6 +124,21 @@ void main() { ...@@ -124,6 +124,21 @@ void main() {
contains(isA<GoogleChromeDevice>())); contains(isA<GoogleChromeDevice>()));
}); });
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: <String, String>{}
),
processManager: FakeProcessManager.any(),
);
expect(webDevices.wellKnownIds, <String>['chrome', 'web-server', 'edge']);
});
testWithoutContext('Chrome device is not listed when Chrome cannot be run', () async { testWithoutContext('Chrome device is not listed when Chrome cannot be run', () async {
final FakeProcessManager processManager = FakeProcessManager.empty(); final FakeProcessManager processManager = FakeProcessManager.empty();
processManager.excludedExecutables = <String>{kLinuxExecutable}; processManager.excludedExecutables = <String>{kLinuxExecutable};
......
...@@ -116,6 +116,22 @@ void main() { ...@@ -116,6 +116,22 @@ void main() {
).devices, hasLength(2)); ).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, <String>['windows', 'winuwp']);
});
testWithoutContext('WindowsDevices ignores the timeout provided to discoverDevices', () async { testWithoutContext('WindowsDevices ignores the timeout provided to discoverDevices', () async {
final WindowsDevices windowsDevices = WindowsDevices( final WindowsDevices windowsDevices = WindowsDevices(
windowsWorkflow: WindowsWorkflow( windowsWorkflow: WindowsWorkflow(
......
...@@ -175,6 +175,9 @@ class FakePollingDeviceDiscovery extends PollingDeviceDiscovery { ...@@ -175,6 +175,9 @@ class FakePollingDeviceDiscovery extends PollingDeviceDiscovery {
@override @override
Stream<Device> get onRemoved => _onRemovedController.stream; Stream<Device> get onRemoved => _onRemovedController.stream;
@override
List<String> wellKnownIds = <String>[];
} }
/// A fake implementation of the [DeviceLogReader]. /// A fake implementation of the [DeviceLogReader].
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment