Commit 0770c3c1 authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

[flutter_tools] Adds some support for '-d all' (#9585)

parent 9558ac7d
......@@ -353,11 +353,13 @@ class AppDomain extends Domain {
final Directory cwd = fs.currentDirectory;
fs.currentDirectory = fs.directory(projectDirectory);
final FlutterDevice flutterDevice = new FlutterDevice(device);
ResidentRunner runner;
if (enableHotReload) {
runner = new HotRunner(
device,
<FlutterDevice>[flutterDevice],
target: target,
debuggingOptions: options,
usesTerminalUI: false,
......@@ -368,7 +370,7 @@ class AppDomain extends Domain {
);
} else {
runner = new ColdRunner(
device,
<FlutterDevice>[flutterDevice],
target: target,
debuggingOptions: options,
usesTerminalUI: false,
......@@ -448,7 +450,7 @@ class AppDomain extends Domain {
if (app == null)
throw "app '$appId' not found";
final Isolate isolate = app.runner.currentView.uiIsolate;
final Isolate isolate = app.runner.flutterDevices.first.views.first.uiIsolate;
final Map<String, dynamic> result = await isolate.invokeFlutterExtensionRpcRaw(methodName, params: params);
if (result == null)
return new OperationResult(1, 'method not available: $methodName');
......
......@@ -16,6 +16,7 @@ import '../device.dart';
import '../flx.dart' as flx;
import '../fuchsia/fuchsia_device.dart';
import '../globals.dart';
import '../resident_runner.dart';
import '../run_hot.dart';
import '../runner/flutter_command.dart';
import '../vmservice.dart';
......@@ -112,18 +113,21 @@ class FuchsiaReloadCommand extends FlutterCommand {
final List<String> fullAddresses = targetPorts.map(
(int p) => '$_address:$p'
).toList();
final List<Uri> observatoryUris = fullAddresses.map(
(String a) => Uri.parse('http://$a')
).toList();
final FuchsiaDevice device = new FuchsiaDevice(fullAddresses[0]);
final FlutterDevice flutterDevice = new FlutterDevice(device);
flutterDevice.observatoryUris = observatoryUris;
final HotRunner hotRunner = new HotRunner(
device,
<FlutterDevice>[flutterDevice],
debuggingOptions: new DebuggingOptions.enabled(getBuildMode()),
target: _target,
projectRootPath: _fuchsiaProjectPath,
packagesFilePath: _dotPackagesPath
);
final List<Uri> observatoryUris =
fullAddresses.map((String a) => Uri.parse('http://$a')).toList();
printStatus('Connecting to $_binaryName');
await hotRunner.attach(observatoryUris, isolateFilter: isolateName);
await hotRunner.attach(viewFilter: isolateName);
}
// A cache of VMService connections.
......@@ -151,12 +155,12 @@ class FuchsiaReloadCommand extends FlutterCommand {
}
// Find ports where there is a view isolate with the given name
Future<List<int>> _filterPorts(List<int> ports, String isolateFilter) async {
Future<List<int>> _filterPorts(List<int> ports, String viewFilter) async {
final List<int> result = <int>[];
for (FlutterView v in await _getViews(ports)) {
final Uri addr = v.owner.vmService.httpAddress;
printTrace('At $addr, found view: ${v.uiIsolate.name}');
if (v.uiIsolate.name.indexOf(isolateFilter) == 0)
if (v.uiIsolate.name.indexOf(viewFilter) == 0)
result.add(addr.port);
}
return result;
......
......@@ -150,17 +150,20 @@ class RunCommand extends RunCommandBase {
};
}
Device device;
List<Device> devices;
@override
Future<String> get usagePath async {
final String command = shouldUseHotMode() ? 'hotrun' : name;
if (device == null)
if (devices == null)
return command;
// Return 'run/ios'.
return '$command/${getNameForTargetPlatform(await device.targetPlatform)}';
if (devices.length > 1)
return '$command/all';
else
return '$command/${getNameForTargetPlatform(await devices[0].targetPlatform)}';
}
@override
......@@ -199,9 +202,11 @@ class RunCommand extends RunCommandBase {
@override
Future<Null> verifyThenRunCommand() async {
commandValidator();
device = await findTargetDevice();
if (device == null)
devices = await findAllTargetDevices();
if (devices == null)
throwToolExit(null);
if (deviceManager.hasSpecifiedAllDevices && runningWithPrebuiltApplication)
throwToolExit('Using -d all with --use-application-binary is not supported');
return super.verifyThenRunCommand();
}
......@@ -221,7 +226,6 @@ class RunCommand extends RunCommandBase {
@override
Future<Null> runCommand() async {
Cache.releaseLockEarly();
// Enable hot mode by default if `--no-hot` was not passed and we are in
......@@ -229,17 +233,20 @@ class RunCommand extends RunCommandBase {
final bool hotMode = shouldUseHotMode();
if (argResults['machine']) {
if (devices.length > 1)
throwToolExit('--machine does not support -d all.');
final Daemon daemon = new Daemon(stdinCommandStream, stdoutCommandResponse,
notifyingLogger: new NotifyingLogger(), logToStdout: true);
AppInstance app;
try {
app = await daemon.appDomain.startApp(
device, fs.currentDirectory.path, targetFile, route,
devices.first, fs.currentDirectory.path, targetFile, route,
_createDebuggingOptions(), hotMode,
applicationBinary: argResults['use-application-binary'],
projectRootPath: argResults['project-root'],
packagesFilePath: argResults['packages'],
projectAssets: argResults['project-assets']);
projectAssets: argResults['project-assets']
);
} catch (error) {
throwToolExit(error.toString());
}
......@@ -249,12 +256,16 @@ class RunCommand extends RunCommandBase {
return null;
}
if (await device.isLocalEmulator && !isEmulatorBuildMode(getBuildMode()))
throwToolExit('${toTitleCase(getModeName(getBuildMode()))} mode is not supported for emulators.');
for (Device device in devices) {
if (await device.isLocalEmulator && !isEmulatorBuildMode(getBuildMode()))
throwToolExit('${toTitleCase(getModeName(getBuildMode()))} mode is not supported for emulators.');
}
if (hotMode) {
if (!device.supportsHotMode)
throwToolExit('Hot mode is not supported by this device. Run with --no-hot.');
for (Device device in devices) {
if (!device.supportsHotMode)
throwToolExit('Hot mode is not supported by ${device.name}. Run with --no-hot.');
}
}
final String pidFile = argResults['pid-file'];
......@@ -262,11 +273,15 @@ class RunCommand extends RunCommandBase {
// Write our pid to the file.
fs.file(pidFile).writeAsStringSync(pid.toString());
}
ResidentRunner runner;
final List<FlutterDevice> flutterDevices = devices.map((Device device) {
return new FlutterDevice(device);
}).toList();
ResidentRunner runner;
if (hotMode) {
runner = new HotRunner(
device,
flutterDevices,
target: targetFile,
debuggingOptions: _createDebuggingOptions(),
benchmarkMode: argResults['benchmark'],
......@@ -279,7 +294,7 @@ class RunCommand extends RunCommandBase {
);
} else {
runner = new ColdRunner(
device,
flutterDevices,
target: targetFile,
debuggingOptions: _createDebuggingOptions(),
traceStartup: traceStartup,
......
......@@ -32,11 +32,26 @@ class DeviceManager {
final List<DeviceDiscovery> _deviceDiscoverers = <DeviceDiscovery>[];
String _specifiedDeviceId;
/// A user-specified device ID.
String specifiedDeviceId;
String get specifiedDeviceId {
if (_specifiedDeviceId == null || _specifiedDeviceId == 'all')
return null;
return _specifiedDeviceId;
}
set specifiedDeviceId(String id) {
_specifiedDeviceId = id;
}
/// True when the user has specified a single specific device.
bool get hasSpecifiedDeviceId => specifiedDeviceId != null;
/// True when the user has specified all devices by setting
/// specifiedDeviceId = 'all'.
bool get hasSpecifiedAllDevices => _specifiedDeviceId == 'all';
Stream<Device> getDevicesById(String deviceId) async* {
final Stream<Device> devices = getAllConnectedDevices();
deviceId = deviceId.toLowerCase();
......
......@@ -6,10 +6,7 @@ import 'dart:async';
import 'package:meta/meta.dart';
import 'application_package.dart';
import 'base/file_system.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'commands/trace.dart';
import 'device.dart';
import 'globals.dart';
......@@ -17,25 +14,22 @@ import 'resident_runner.dart';
class ColdRunner extends ResidentRunner {
ColdRunner(
Device device, {
List<FlutterDevice> devices, {
String target,
DebuggingOptions debuggingOptions,
bool usesTerminalUI: true,
this.traceStartup: false,
this.applicationBinary,
bool stayResident: true,
}) : super(device,
}) : super(devices,
target: target,
debuggingOptions: debuggingOptions,
usesTerminalUI: usesTerminalUI,
stayResident: stayResident);
LaunchResult _result;
final bool traceStartup;
final String applicationBinary;
bool get prebuiltMode => applicationBinary != null;
@override
Future<int> run({
Completer<DebugConnectionInfo> connectionInfoCompleter,
......@@ -43,6 +37,7 @@ class ColdRunner extends ResidentRunner {
String route,
bool shouldBuild: true
}) async {
final bool prebuiltMode = applicationBinary != null;
if (!prebuiltMode) {
if (!fs.isFileSync(mainPath)) {
String message = 'Tried to run $mainPath, but that file does not exist.';
......@@ -53,79 +48,49 @@ class ColdRunner extends ResidentRunner {
}
}
final String modeName = getModeName(debuggingOptions.buildMode);
if (mainPath == null) {
assert(prebuiltMode);
printStatus('Launching ${package.displayName} on ${device.name} in $modeName mode...');
} else {
printStatus('Launching ${getDisplayPath(mainPath)} on ${device.name} in $modeName mode...');
}
final TargetPlatform targetPlatform = await device.targetPlatform;
package = getApplicationPackageForPlatform(targetPlatform, applicationBinary: applicationBinary);
if (package == null) {
String message = 'No application found for $targetPlatform.';
final String hint = getMissingPackageHintForPlatform(targetPlatform);
if (hint != null)
message += '\n$hint';
printError(message);
return 1;
for (FlutterDevice device in flutterDevices) {
final int result = await device.runCold(
coldRunner: this,
route: route,
shouldBuild: shouldBuild,
);
if (result != 0)
return result;
}
final Stopwatch startTime = new Stopwatch()..start();
Map<String, dynamic> platformArgs;
if (traceStartup != null)
platformArgs = <String, dynamic>{ 'trace-startup': traceStartup };
await startEchoingDeviceLog(package);
_result = await device.startApp(
package,
debuggingOptions.buildMode,
mainPath: mainPath,
debuggingOptions: debuggingOptions,
platformArgs: platformArgs,
route: route,
prebuiltApplication: prebuiltMode,
applicationNeedsRebuild: shouldBuild || hasDirtyDependencies()
);
if (!_result.started) {
printError('Error running application on ${device.name}.');
await stopEchoingDeviceLog();
return 2;
}
startTime.stop();
// Connect to observatory.
if (debuggingOptions.debuggingEnabled)
await connectToServiceProtocol(<Uri>[_result.observatoryUri]);
await connectToServiceProtocol();
if (_result.hasObservatory) {
if (flutterDevices.first.observatoryUris != null) {
// For now, only support one debugger connection.
connectionInfoCompleter?.complete(new DebugConnectionInfo(
httpUri: _result.observatoryUri,
wsUri: vmServices[0].wsAddress,
httpUri: flutterDevices.first.observatoryUris.first,
wsUri: flutterDevices.first.vmServices.first.wsAddress,
));
}
printTrace('Application running.');
if (vmServices != null && vmServices.isNotEmpty) {
device.getLogReader(app: package).appPid = vmServices[0].vm.pid;
await refreshViews();
printTrace('Connected to $currentView.');
for (FlutterDevice device in flutterDevices) {
if (device.vmServices == null)
continue;
device.initLogReader();
await device.refreshViews();
printTrace('Connected to ${device.device.name}');
}
if (vmServices != null && vmServices.isNotEmpty && traceStartup) {
printStatus('Downloading startup trace info...');
try {
await downloadStartupTrace(vmServices[0]);
} catch(error) {
printError(error);
return 2;
if (traceStartup) {
// Only trace startup for the first device.
final FlutterDevice device = flutterDevices.first;
if (device.vmServices != null && device.vmServices.isNotEmpty) {
printStatus('Downloading startup trace info for ${device.device.name}');
try {
await downloadStartupTrace(device.vmServices.first);
} catch (error) {
printError(error);
return 2;
}
}
appFinished();
} else if (stayResident) {
......@@ -158,8 +123,13 @@ class ColdRunner extends ResidentRunner {
@override
void printHelp({ @required bool details }) {
bool haveDetails = false;
if (_result.hasObservatory)
printStatus('The Observatory debugger and profiler is available at: ${_result.observatoryUri}');
for (FlutterDevice device in flutterDevices) {
final String dname = device.device.name;
if (device.observatoryUris != null) {
for (Uri uri in device.observatoryUris)
printStatus('An Observatory debugger and profiler on $dname is available at $uri');
}
}
if (supportsServiceProtocol) {
haveDetails = true;
if (details)
......@@ -174,8 +144,10 @@ class ColdRunner extends ResidentRunner {
@override
Future<Null> preStop() async {
// If we're running in release mode, stop the app using the device logic.
if (vmServices == null || vmServices.isEmpty)
await device.stopApp(package);
for (FlutterDevice device in flutterDevices) {
// If we're running in release mode, stop the app using the device logic.
if (device.vmServices == null || device.vmServices.isEmpty)
await device.device.stopApp(device.package);
}
}
}
This diff is collapsed.
......@@ -154,11 +154,11 @@ abstract class FlutterCommand extends Command<Null> {
/// Subclasses must implement this to execute the command.
Future<Null> runCommand();
/// Find and return the target [Device] based upon currently connected
/// Find and return all target [Device]s based upon currently connected
/// devices and criteria entered by the user on the command line.
/// If a device cannot be found that meets specified criteria,
/// If no device can be found that meets specified criteria,
/// then print an error message and return `null`.
Future<Device> findTargetDevice() async {
Future<List<Device>> findAllTargetDevices() async {
if (!doctor.canLaunchAnything) {
printError("Unable to locate a development device; please run 'flutter doctor' "
"for information about installing additional components.");
......@@ -171,6 +171,9 @@ abstract class FlutterCommand extends Command<Null> {
printStatus("No devices found with name or id "
"matching '${deviceManager.specifiedDeviceId}'");
return null;
} else if (devices.isEmpty && deviceManager.hasSpecifiedAllDevices) {
printStatus("No devices found");
return null;
} else if (devices.isEmpty) {
printNoConnectedDevices();
return null;
......@@ -181,20 +184,39 @@ abstract class FlutterCommand extends Command<Null> {
if (devices.isEmpty) {
printStatus('No supported devices connected.');
return null;
} else if (devices.length > 1) {
} else if (devices.length > 1 && !deviceManager.hasSpecifiedAllDevices) {
if (deviceManager.hasSpecifiedDeviceId) {
printStatus("Found ${devices.length} devices with name or id matching "
"'${deviceManager.specifiedDeviceId}':");
} else {
printStatus("More than one device connected; please specify a device with "
"the '-d <deviceId>' flag.");
"the '-d <deviceId>' flag, or use '-d all' to act on all devices.");
devices = await deviceManager.getAllConnectedDevices().toList();
}
printStatus('');
await Device.printDevices(devices);
return null;
}
return devices.single;
return devices;
}
/// Find and return the target [Device] based upon currently connected
/// devices and criteria entered by the user on the command line.
/// If a device cannot be found that meets specified criteria,
/// then print an error message and return `null`.
Future<Device> findTargetDevice() async {
List<Device> deviceList = await findAllTargetDevices();
if (deviceList == null)
return null;
if (deviceList.length > 1) {
printStatus("More than one device connected; please specify a device with "
"the '-d <deviceId>' flag.");
deviceList = await deviceManager.getAllConnectedDevices().toList();
printStatus('');
await Device.printDevices(deviceList);
return null;
}
return deviceList.single;
}
void printNoConnectedDevices() {
......
......@@ -127,12 +127,28 @@ class MockPortScanner extends PortScanner {
class MockDeviceManager implements DeviceManager {
List<Device> devices = <Device>[];
String _specifiedDeviceId;
@override
String get specifiedDeviceId {
if (_specifiedDeviceId == null || _specifiedDeviceId == 'all')
return null;
return _specifiedDeviceId;
}
@override
String specifiedDeviceId;
set specifiedDeviceId(String id) {
_specifiedDeviceId = id;
}
@override
bool get hasSpecifiedDeviceId => specifiedDeviceId != null;
@override
bool get hasSpecifiedAllDevices {
return _specifiedDeviceId != null && _specifiedDeviceId == 'all';
}
@override
Stream<Device> getAllConnectedDevices() => new Stream<Device>.fromIterable(devices);
......
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