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 {
}
}
}
@override
List<String> get wellKnownIds => const <String>[];
}
......@@ -191,7 +191,6 @@ Future<T> runInContext<T>(
artifacts: globals.artifacts,
flutterVersion: globals.flutterVersion,
androidWorkflow: androidWorkflow,
config: globals.config,
fuchsiaWorkflow: fuchsiaWorkflow,
xcDevice: globals.xcdevice,
userMessages: globals.userMessages,
......
......@@ -767,4 +767,7 @@ class CustomDevices extends PollingDeviceDiscovery {
@override
Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>[];
}
......@@ -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<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
// found quickly, we don't wait for all the discoverers to complete.
final List<Device> prefixMatches = <Device>[];
final Completer<Device> exactMatchCompleter = Completer<Device>();
final List<Future<List<Device>>> futureDevices = <Future<List<Device>>>[
for (final DeviceDiscovery discoverer in _platformDiscoverers)
discoverer
.devices
.then((List<Device> devices) {
for (final Device device in devices) {
if (exactlyMatchesDeviceId(device)) {
exactMatchCompleter.complete(device);
return null;
}
if (startsWithDeviceId(device)) {
prefixMatches.add(device);
if (!hasWellKnownId || discoverer.wellKnownIds.contains(specifiedDeviceId))
discoverer
.devices
.then((List<Device> devices) {
for (final Device device in devices) {
if (exactlyMatchesDeviceId(device)) {
exactMatchCompleter.complete(device);
return null;
}
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<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
......
......@@ -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,
......
......@@ -231,6 +231,9 @@ class FuchsiaDevices extends PollingDeviceDiscovery {
}
return FuchsiaDevice(resolvedHost, name: name);
}
@override
List<String> get wellKnownIds => const <String>[];
}
......
......@@ -133,6 +133,9 @@ class IOSDevices extends PollingDeviceDiscovery {
return _xcdevice.getDiagnostics();
}
@override
List<String> get wellKnownIds => const <String>[];
}
enum IOSDeviceInterface {
......
......@@ -48,6 +48,9 @@ class IOSSimulators extends PollingDeviceDiscovery {
@override
Future<List<Device>> pollingGetDevices({ Duration timeout }) async => _iosSimulatorUtils.getAttachedDevices();
@override
List<String> get wellKnownIds => const <String>[];
}
class IOSSimulatorUtils {
......
......@@ -135,4 +135,7 @@ class LinuxDevices extends PollingDeviceDiscovery {
@override
Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>['linux'];
}
......@@ -148,4 +148,7 @@ class MacOSDevices extends PollingDeviceDiscovery {
@override
Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>['macos'];
}
......@@ -144,4 +144,7 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery {
@override
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';
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<List<Device>> pollingGetDevices({ Duration timeout }) async {
return showFlutterTesterDevice ? <Device>[_testerDevice] : <Device>[];
}
@override
List<String> get wellKnownIds => const <String>[kTesterDeviceId];
}
......@@ -362,6 +362,9 @@ class WebDevices extends PollingDeviceDiscovery {
@override
bool get supportsPlatform => _featureFlags.isWebEnabled;
@override
List<String> get wellKnownIds => const <String>['chrome', 'web-server', 'edge'];
}
@visibleForTesting
......
......@@ -454,4 +454,7 @@ class WindowsDevices extends PollingDeviceDiscovery {
@override
Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>['windows', 'winuwp'];
}
......@@ -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<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 {
final FakeDevice device1 = FakeDevice('Nexus 5', '0553790d0a4e726f');
final FakeDevice device2 = FakeDevice('Nexus 5X', '01abfc49119c410e');
......@@ -467,8 +494,12 @@ class TestDeviceManager extends DeviceManager {
List<DeviceDiscovery> 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 = <DeviceDiscovery>[
_fakeDeviceDiscoverer,
if (deviceDiscoveryOverrides != null)
......@@ -516,6 +547,9 @@ class MockDeviceDiscovery extends Fake implements DeviceDiscovery {
discoverDevicesCalled += 1;
return deviceValues;
}
@override
List<String> get wellKnownIds => <String>[];
}
class FakeFlutterProject extends Fake implements FlutterProject {}
......@@ -545,6 +579,9 @@ class LongPollingDeviceDiscovery extends PollingDeviceDiscovery {
@override
bool get canListAnything => true;
@override
final List<String> wellKnownIds = <String>[];
}
class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery {
......@@ -560,6 +597,9 @@ class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery {
@override
bool get canListAnything => true;
@override
List<String> get wellKnownIds => <String>[];
}
class FakeTerminal extends Fake implements Terminal {
......
......@@ -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, <String>['linux']);
});
testWithoutContext('LinuxDevice: discoverDevices', () async {
// Timeout ignored.
final List<Device> devices = await LinuxDevices(
......
......@@ -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, <String>['macos']);
});
testWithoutContext('can discover devices with a provided timeout', () async {
final MacOSDevices macOSDevices = MacOSDevices(
fileSystem: MemoryFileSystem.test(),
......
......@@ -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(),
);
......
......@@ -124,6 +124,21 @@ void main() {
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 {
final FakeProcessManager processManager = FakeProcessManager.empty();
processManager.excludedExecutables = <String>{kLinuxExecutable};
......
......@@ -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, <String>['windows', 'winuwp']);
});
testWithoutContext('WindowsDevices ignores the timeout provided to discoverDevices', () async {
final WindowsDevices windowsDevices = WindowsDevices(
windowsWorkflow: WindowsWorkflow(
......
......@@ -175,6 +175,9 @@ class FakePollingDeviceDiscovery extends PollingDeviceDiscovery {
@override
Stream<Device> get onRemoved => _onRemovedController.stream;
@override
List<String> wellKnownIds = <String>[];
}
/// 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