Commit 5ad6a570 authored by Devon Carew's avatar Devon Carew

remove some references to DeviceStore

parent 35c5494f
......@@ -29,6 +29,10 @@ abstract class ApplicationPackage {
assert(localPath != null);
assert(id != null);
}
String get displayName => name;
String toString() => displayName;
}
class AndroidApk extends ApplicationPackage {
......@@ -99,6 +103,8 @@ class IOSApp extends ApplicationPackage {
String projectDir = path.join("ios", ".generated");
return new IOSApp(iosProjectDir: projectDir, iosProjectBundleId: value);
}
String get displayName => id;
}
class ApplicationPackageStore {
......
......@@ -422,14 +422,14 @@ Future<int> buildAndroid({
// TODO(mpcomplete): move this to Device?
/// This is currently Android specific.
Future<int> buildAll(
DeviceStore devices,
List<Device> devices,
ApplicationPackageStore applicationPackages,
Toolchain toolchain,
List<BuildConfiguration> configs, {
String enginePath,
String target: ''
}) async {
for (Device device in devices.all) {
for (Device device in devices) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null)
continue;
......@@ -438,14 +438,6 @@ Future<int> buildAll(
if (package != applicationPackages.android)
continue;
// TODO(devoncarew): Remove this warning after a few releases.
if (FileSystemEntity.isDirectorySync('apk') && !FileSystemEntity.isDirectorySync('android')) {
// Tell people the android directory location changed.
printStatus(
"Warning: Flutter now looks for Android resources in the android/ directory; "
"consider renaming your 'apk/' directory to 'android/'.");
}
int result = await build(toolchain, configs, enginePath: enginePath, target: target);
if (result != 0)
return result;
......
......@@ -256,11 +256,11 @@ class AppDomain extends Domain {
try {
await Future.wait([
command.downloadToolchain(),
command.downloadApplicationPackagesAndConnectToDevices(),
command.downloadApplicationPackages(),
], eagerError: true);
int result = await startApp(
command.devices,
device,
command.applicationPackages,
command.toolchain,
command.buildConfigurations,
......
......@@ -30,10 +30,8 @@ class DevicesCommand extends FlutterCommand {
} else {
printStatus('${devices.length} connected ${pluralize('device', devices.length)}:\n');
for (Device device in devices) {
String supportIndicator = device.isSupported() ? '' : ' - unsupported';
printStatus('${device.name} (${device.id})$supportIndicator');
}
for (Device device in devices)
printStatus(device.fullDescription);
}
return 0;
......
......@@ -315,6 +315,6 @@ Future<Null> downloadToolchain(DriveCommand command) async {
printTrace('Downloading toolchain.');
await Future.wait([
command.downloadToolchain(),
command.downloadApplicationPackagesAndConnectToDevices(),
command.downloadApplicationPackages(),
], eagerError: true);
}
......@@ -6,35 +6,34 @@ import 'dart:async';
import '../application_package.dart';
import '../device.dart';
import '../globals.dart';
import '../runner/flutter_command.dart';
class InstallCommand extends FlutterCommand {
final String name = 'install';
final String description = 'Install Flutter apps on attached devices.';
final String description = 'Install a Flutter app on an attached device.';
bool get requiresDevice => true;
@override
Future<int> runInProject() async {
await downloadApplicationPackagesAndConnectToDevices();
bool installedAny = await installApp(devices, applicationPackages);
return installedAny ? 0 : 2;
await downloadApplicationPackages();
Device device = deviceForCommand;
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
printStatus('Installing $package to $device...');
return installApp(device, package) ? 0 : 2;
}
}
Future<bool> installApp(
DeviceStore devices,
ApplicationPackageStore applicationPackages
) async {
bool installedSomewhere = false;
bool installApp(Device device, ApplicationPackage package) {
if (package == null)
return false;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || device.isAppInstalled(package))
continue;
if (device.installApp(package))
installedSomewhere = true;
}
if (device.isAppInstalled(package))
return true;
return installedSomewhere;
return device.installApp(package);
}
......@@ -28,7 +28,7 @@ class ListenCommand extends RunCommandBase {
@override
Future<int> runInProject() async {
await downloadApplicationPackagesAndConnectToDevices();
await downloadApplicationPackages();
await downloadToolchain();
List<String> watchCommand = _constructWatchCommand(() sync* {
......@@ -42,7 +42,7 @@ class ListenCommand extends RunCommandBase {
do {
printStatus('Updating running Flutter apps...');
result = await startApp(
devices,
deviceForCommand,
applicationPackages,
toolchain,
buildConfigurations,
......
......@@ -25,50 +25,28 @@ class LogsCommand extends FlutterCommand {
bool get requiresDevice => true;
Future<int> runInProject() async {
List<Device> devices = await deviceManager.getDevices();
Device device = deviceForCommand;
if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) {
printError("No device found with id '${deviceManager.specifiedDeviceId}'.");
return 1;
} else if (devices.isEmpty) {
printStatus('No connected devices.');
return 0;
}
if (argResults['clear'])
device.clearLogs();
bool clear = argResults['clear'];
DeviceLogReader logReader = device.logReader;
List<DeviceLogReader> readers = new List<DeviceLogReader>();
for (Device device in devices) {
if (clear)
device.clearLogs();
printStatus('Showing $logReader logs:');
readers.add(device.logReader);
}
// Start reading.
if (!logReader.isReading)
await logReader.start();
printStatus('Showing ${readers.join(', ')} logs:');
StreamSubscription subscription = logReader.lines.listen(printStatus);
List<int> results = await Future.wait(readers.map((DeviceLogReader reader) async {
if (!reader.isReading) {
// Start reading.
await reader.start();
}
StreamSubscription subscription = reader.lines.listen((String line) {
if (devices.length > 1) {
// Prefix with the name of the device.
printStatus('[${reader.name}] $line');
} else {
printStatus(line);
}
});
// Wait for the log reader to be finished.
int result = await reader.finished;
subscription.cancel();
if (result != 0)
printError('Error listening to $reader logs.');
return result;
}));
// Wait for the log reader to be finished.
int result = await logReader.finished;
// If all readers failed, return an error.
return results.every((int result) => result != 0) ? 1 : 0;
subscription.cancel();
if (result != 0)
printError('Error listening to $logReader logs.');
return result;
}
}
......@@ -7,6 +7,7 @@ import 'dart:io';
import 'package:path/path.dart' as path;
import '../android/android_device.dart';
import '../globals.dart';
import '../runner/flutter_command.dart';
......@@ -28,14 +29,9 @@ class RefreshCommand extends FlutterCommand {
await Future.wait([
downloadToolchain(),
downloadApplicationPackagesAndConnectToDevices(),
downloadApplicationPackages(),
], eagerError: true);
if (devices.android == null) {
printError('No device connected.');
return 1;
}
Directory tempDir = await Directory.systemTemp.createTemp('flutter_tools');
try {
String snapshotPath = path.join(tempDir.path, 'snapshot_blob.bin');
......@@ -48,11 +44,13 @@ class RefreshCommand extends FlutterCommand {
return result;
}
bool success = await devices.android.refreshSnapshot(
applicationPackages.android, snapshotPath
AndroidDevice device = deviceForCommand;
bool success = await device.refreshSnapshot(
applicationPackages.android, snapshotPath
);
if (!success) {
printError('Error refreshing snapshot on ${devices.android.name}.');
printError('Error refreshing snapshot on $device.');
return 1;
}
......
......@@ -9,7 +9,6 @@ import 'package:path/path.dart' as path;
import '../application_package.dart';
import '../base/common.dart';
import '../base/utils.dart';
import '../build_configuration.dart';
import '../dart/pub.dart';
import '../device.dart';
......@@ -95,7 +94,7 @@ class RunCommand extends RunCommandBase {
await Future.wait([
downloadToolchain(),
downloadApplicationPackagesAndConnectToDevices(),
downloadApplicationPackages(),
], eagerError: true);
bool clearLogs = argResults['clear-logs'];
......@@ -109,9 +108,8 @@ class RunCommand extends RunCommandBase {
return 1;
}
// TODO(devoncarew): Switch this to using [devicesForCommand].
int result = await startApp(
devices,
deviceForCommand,
applicationPackages,
toolchain,
buildConfigurations,
......@@ -132,7 +130,7 @@ class RunCommand extends RunCommandBase {
}
Future<int> startApp(
DeviceStore devices,
Device device,
ApplicationPackageStore applicationPackages,
Toolchain toolchain,
List<BuildConfiguration> configs, {
......@@ -156,10 +154,17 @@ Future<int> startApp(
return 1;
}
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null) {
printError('No application found for ${device.platform}.');
return 1;
}
if (install) {
printTrace('Running build command.');
int result = await buildAll(
devices, applicationPackages, toolchain, configs,
<Device>[device], applicationPackages, toolchain, configs,
enginePath: enginePath,
target: target
);
......@@ -172,16 +177,10 @@ Future<int> startApp(
// plumb a Future through the start command from here, but that seems a little
// messy.
if (stop) {
for (Device device in devices.all) {
if (!device.isSupported())
continue;
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package != null) {
printTrace("Stopping app '${package.name}' on ${device.name}.");
// We don't wait for the stop command to complete.
device.stopApp(package);
}
if (package != null) {
printTrace("Stopping app '${package.name}' on ${device.name}.");
// We don't wait for the stop command to complete.
device.stopApp(package);
}
}
......@@ -190,66 +189,42 @@ Future<int> startApp(
if (install) {
printTrace('Running install command.');
// TODO(devoncarew): This fails for ios devices - we haven't built yet.
await installApp(devices, applicationPackages);
await installApp(device, package);
}
bool startedSomething = false;
int unsupportedCount = 0;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null)
continue;
Map<String, dynamic> platformArgs = <String, dynamic>{};
if (!device.isSupported()) {
printStatus("Skipping unsupported device '${device.name}'. ${device.supportMessage()}");
unsupportedCount++;
continue;
}
if (traceStartup != null)
platformArgs['trace-startup'] = traceStartup;
Map<String, dynamic> platformArgs = <String, dynamic>{};
printStatus('Starting ${_getDisplayPath(mainPath)} on ${device.name}...');
if (traceStartup != null)
platformArgs['trace-startup'] = traceStartup;
bool result = await device.startApp(
package,
toolchain,
mainPath: mainPath,
route: route,
checked: checked,
clearLogs: clearLogs,
startPaused: startPaused,
debugPort: debugPort,
platformArgs: platformArgs
);
printStatus('Starting ${_getDisplayPath(mainPath)} on ${device.name}...');
bool result = await device.startApp(
package,
toolchain,
mainPath: mainPath,
route: route,
checked: checked,
clearLogs: clearLogs,
startPaused: startPaused,
debugPort: debugPort,
platformArgs: platformArgs
);
if (!result) {
printError('Error starting application on ${device.name}.');
} else {
startedSomething = true;
// If the user specified --start-paused (and the device supports it) then
// wait for the observatory port to become available before returning from
// `startApp()`.
if (startPaused && device.supportsStartPaused)
await delayUntilObservatoryAvailable('localhost', debugPort);
}
}
if (!startedSomething) {
String message = 'Unable to run application';
if (devices.all.isEmpty) {
message += ' - no connected devices.';
} else if (unsupportedCount != 0) {
message += ' - $unsupportedCount unsupported ${pluralize('device', unsupportedCount)} connected';
}
if (!result) {
printError('Error starting application on ${device.name}.');
} else {
startedSomething = true;
printError(message);
// If the user specified --start-paused (and the device supports it) then
// wait for the observatory port to become available before returning from
// `startApp()`.
if (startPaused && device.supportsStartPaused)
await delayUntilObservatoryAvailable('localhost', debugPort);
}
return startedSomething ? 0 : 2;
......
......@@ -31,28 +31,24 @@ class TraceCommand extends FlutterCommand {
@override
Future<int> runInProject() async {
await downloadApplicationPackagesAndConnectToDevices();
if (devices.android == null) {
printError('No device connected, so no trace was completed.');
return 1;
}
await downloadApplicationPackages();
ApplicationPackage androidApp = applicationPackages.android;
AndroidDevice device = deviceForCommand;
if ((!argResults['start'] && !argResults['stop']) ||
(argResults['start'] && argResults['stop'])) {
// Setting neither flags or both flags means do both commands and wait
// duration seconds in between.
devices.android.startTracing(androidApp);
device.startTracing(androidApp);
await new Future.delayed(
new Duration(seconds: int.parse(argResults['duration'])),
() => _stopTracing(devices.android, androidApp)
new Duration(seconds: int.parse(argResults['duration'])),
() => _stopTracing(device, androidApp)
);
} else if (argResults['stop']) {
await _stopTracing(devices.android, androidApp);
await _stopTracing(device, androidApp);
} else {
devices.android.startTracing(androidApp);
device.startTracing(androidApp);
}
return 0;
}
......
......@@ -9,7 +9,6 @@ import 'application_package.dart';
import 'base/common.dart';
import 'base/utils.dart';
import 'build_configuration.dart';
import 'globals.dart';
import 'ios/devices.dart';
import 'ios/simulators.dart';
import 'toolchain.dart';
......@@ -39,10 +38,21 @@ class DeviceManager {
Future<Device> getDeviceById(String deviceId) async {
deviceId = deviceId.toLowerCase();
List<Device> devices = await getAllConnectedDevices();
return devices.firstWhere(
Device device = devices.firstWhere(
(Device device) => device.id.toLowerCase() == deviceId,
orElse: () => null
);
if (device != null)
return device;
// Match on a close id / name.
devices = devices.where((Device device) {
return (device.id.toLowerCase().startsWith(deviceId) ||
device.name.toLowerCase().startsWith(deviceId));
});
return devices.length == 1 ? devices.first : null;
}
/// Return the list of connected devices, filtered by any user-specified device id.
......@@ -130,6 +140,11 @@ abstract class Device {
bool get supportsStartPaused => true;
String get fullDescription {
String supportIndicator = isSupported() ? '' : ' - unsupported';
return '$name ($id)$supportIndicator';
}
/// Whether it is an emulated device running on localhost.
bool get isLocalEmulator;
......@@ -186,7 +201,7 @@ abstract class Device {
return id == other.id;
}
String toString() => '$runtimeType $id';
String toString() => name;
}
class ForwardedPort {
......@@ -241,77 +256,3 @@ abstract class DeviceLogReader {
String toString() => name;
}
// TODO(devoncarew): Unify this with [DeviceManager].
class DeviceStore {
DeviceStore({
this.android,
this.iOS,
this.iOSSimulator
});
factory DeviceStore.forConfigs(List<BuildConfiguration> configs) {
AndroidDevice android;
IOSDevice iOS;
IOSSimulator iOSSimulator;
for (BuildConfiguration config in configs) {
switch (config.targetPlatform) {
case TargetPlatform.android:
assert(android == null);
android = _deviceForConfig(config, getAdbDevices());
break;
case TargetPlatform.iOS:
assert(iOS == null);
iOS = _deviceForConfig(config, IOSDevice.getAttachedDevices());
break;
case TargetPlatform.iOSSimulator:
assert(iOSSimulator == null);
iOSSimulator = _deviceForConfig(config, IOSSimulatorUtils.instance.getAttachedDevices());
break;
case TargetPlatform.mac:
case TargetPlatform.linux:
break;
}
}
return new DeviceStore(android: android, iOS: iOS, iOSSimulator: iOSSimulator);
}
final AndroidDevice android;
final IOSDevice iOS;
final IOSSimulator iOSSimulator;
List<Device> get all {
List<Device> result = <Device>[];
if (android != null)
result.add(android);
if (iOS != null)
result.add(iOS);
if (iOSSimulator != null)
result.add(iOSSimulator);
return result;
}
static Device _deviceForConfig(BuildConfiguration config, List<Device> devices) {
Device device;
if (config.deviceId != null) {
// Step 1: If a device identifier is specified, try to find a device
// matching that specific identifier
device = devices.firstWhere(
(Device dev) => (dev.id == config.deviceId),
orElse: () => null);
} else if (devices.length == 1) {
// Step 2: If no identifier is specified and there is only one connected
// device, pick that one.
device = devices[0];
} else if (devices.length > 1) {
// Step 3: D:
printStatus('Multiple devices are connected, but no device ID was specified.');
printStatus('Attempting to launch on all connected devices.');
}
return device;
}
}
......@@ -10,9 +10,9 @@ import 'package:args/command_runner.dart';
import '../application_package.dart';
import '../build_configuration.dart';
import '../device.dart';
import '../flx.dart' as flx;
import '../globals.dart';
import '../toolchain.dart';
import '../flx.dart' as flx;
import 'flutter_command_runner.dart';
typedef bool Validator();
......@@ -39,19 +39,10 @@ abstract class FlutterCommand extends Command {
toolchain ??= await Toolchain.forConfigs(buildConfigurations);
}
Future downloadApplicationPackagesAndConnectToDevices() async {
await downloadApplicationPackages();
_connectToDevices();
}
Future downloadApplicationPackages() async {
applicationPackages ??= await ApplicationPackageStore.forConfigs(buildConfigurations);
}
void _connectToDevices() {
devices ??= new DeviceStore.forConfigs(buildConfigurations);
}
Future<int> run() {
Stopwatch stopwatch = new Stopwatch()..start();
......@@ -91,13 +82,20 @@ abstract class FlutterCommand extends Command {
if (androidOnly)
devices = devices.where((Device device) => device.platform == TargetPlatform.android).toList();
// TODO(devoncarew): Switch this to just supporting one connected device?
if (devices.isEmpty) {
printStatus('No supported devices connected.');
return 1;
} else if (devices.length > 1) {
printStatus("More than one device connected; please specify a device with "
"the '-d <deviceId>' flag.");
printStatus('');
devices = await deviceManager.getAllConnectedDevices();
for (Device device in devices)
printStatus(device.fullDescription);
return 1;
} else {
_deviceForCommand = devices.single;
}
_devicesForCommand = await _getDevicesForCommand();
}
return await runInProject();
......@@ -116,38 +114,13 @@ abstract class FlutterCommand extends Command {
Future<int> runInProject();
List<Device> get devicesForCommand => _devicesForCommand;
Device get deviceForCommand {
// TODO(devoncarew): Switch this to just supporting one connected device?
return devicesForCommand.isNotEmpty ? devicesForCommand.first : null;
}
// This is caculated in run() if the command has [requiresDevice] specified.
List<Device> _devicesForCommand;
Device _deviceForCommand;
Device get deviceForCommand => _deviceForCommand;
ApplicationPackageStore applicationPackages;
Toolchain toolchain;
DeviceStore devices;
Future<List<Device>> _getDevicesForCommand() async {
List<Device> devices = await deviceManager.getDevices();
if (devices.isEmpty)
return null;
if (deviceManager.hasSpecifiedDeviceId) {
Device device = await deviceManager.getDeviceById(deviceManager.specifiedDeviceId);
return device == null ? <Device>[] : <Device>[device];
}
devices = devices.where((Device device) => device.isSupported()).toList();
if (androidOnly)
devices = devices.where((Device device) => device.platform == TargetPlatform.android).toList();
return devices;
}
bool _targetSpecified = false;
......
......@@ -15,18 +15,11 @@ void main() {
testUsingContext('returns 0 when Android is connected and ready for an install', () {
InstallCommand command = new InstallCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
when(mockDevices.android.isAppInstalled(any)).thenReturn(false);
when(mockDevices.android.installApp(any)).thenReturn(true);
when(mockDevices.iOS.isAppInstalled(any)).thenReturn(false);
when(mockDevices.iOS.installApp(any)).thenReturn(false);
when(mockDevices.iOSSimulator.isAppInstalled(any)).thenReturn(false);
when(mockDevices.iOSSimulator.installApp(any)).thenReturn(false);
testDeviceManager.addDevice(mockDevices.android);
MockAndroidDevice device = new MockAndroidDevice();
when(device.isAppInstalled(any)).thenReturn(false);
when(device.installApp(any)).thenReturn(true);
testDeviceManager.addDevice(device);
return createTestCommandRunner(command).run(['install']).then((int code) {
expect(code, equals(0));
......@@ -36,18 +29,11 @@ void main() {
testUsingContext('returns 0 when iOS is connected and ready for an install', () {
InstallCommand command = new InstallCommand();
applyMocksToCommand(command);
MockDeviceStore mockDevices = command.devices;
when(mockDevices.android.isAppInstalled(any)).thenReturn(false);
when(mockDevices.android.installApp(any)).thenReturn(false);
when(mockDevices.iOS.isAppInstalled(any)).thenReturn(false);
when(mockDevices.iOS.installApp(any)).thenReturn(true);
when(mockDevices.iOSSimulator.isAppInstalled(any)).thenReturn(false);
when(mockDevices.iOSSimulator.installApp(any)).thenReturn(false);
testDeviceManager.addDevice(mockDevices.iOS);
MockIOSDevice device = new MockIOSDevice();
when(device.isAppInstalled(any)).thenReturn(false);
when(device.installApp(any)).thenReturn(true);
testDeviceManager.addDevice(device);
return createTestCommandRunner(command).run(['install']).then((int code) {
expect(code, equals(0));
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/build_configuration.dart';
......@@ -45,13 +46,6 @@ class MockIOSSimulator extends Mock implements IOSSimulator {
bool isSupported() => true;
}
class MockDeviceStore extends DeviceStore {
MockDeviceStore() : super(
android: new MockAndroidDevice(),
iOS: new MockIOSDevice(),
iOSSimulator: new MockIOSSimulator());
}
class MockDeviceLogReader extends DeviceLogReader {
String get name => 'MockLogReader';
......@@ -89,6 +83,5 @@ void applyMocksToCommand(FlutterCommand command) {
command
..applicationPackages = new MockApplicationPackageStore()
..toolchain = new MockToolchain()
..devices = new MockDeviceStore()
..projectRootValidator = () => true;
}
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