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

refactor commands to move out re-usable functionality

parent 5776c6e3
......@@ -302,7 +302,7 @@ class ApkCommand extends FlutterCommand {
await downloadToolchain();
// Find the path to the main Dart file.
String mainPath = StartCommandBase.findMainDartFile(argResults['target']);
String mainPath = findMainDartFile(argResults['target']);
// Build the FLX.
int result;
......
......@@ -11,10 +11,12 @@ import '../base/logging.dart';
import '../device.dart';
import '../runner/flutter_command.dart';
import 'start.dart';
import 'stop.dart';
import 'stop.dart' as stop;
const String protocolVersion = '0.0.2';
// TODO(devoncarew): Pass logging data back to the client.
/// A server process command. This command will start up a long-lived server.
/// It reads JSON-RPC based commands from stdin, executes them, and returns
/// JSON-RPC based responses and events to stdout.
......@@ -132,6 +134,8 @@ abstract class Domain {
_handlers[name] = handler;
}
FlutterCommand get command => daemon.daemonCommand;
String toString() => name;
void handleCommand(String name, dynamic id, dynamic args) {
......@@ -190,17 +194,23 @@ class AppDomain extends Domain {
registerHandler('stopAll', stopAll);
}
Future<dynamic> start(dynamic args) {
Future<dynamic> start(dynamic args) async {
// TODO: Add the ability to pass args: target, http, checked
StartCommand startComand = new StartCommand();
startComand.inheritFromParent(daemon.daemonCommand);
return startComand.runInProject().then((_) => null);
await Future.wait([
command.downloadToolchain(),
command.downloadApplicationPackagesAndConnectToDevices(),
], eagerError: true);
return startApp(
command.devices,
command.applicationPackages,
command.toolchain
).then((int result) => null);
}
Future<bool> stopAll(dynamic args) {
StopCommand stopCommand = new StopCommand();
stopCommand.inheritFromParent(daemon.daemonCommand);
return stopCommand.stop();
return stop.stopAll(command.devices, command.applicationPackages);
}
}
......
......@@ -13,30 +13,38 @@ class InstallCommand extends FlutterCommand {
final String description = 'Install Flutter apps on attached devices.';
InstallCommand() {
argParser.addFlag('boot',
help: 'Boot the iOS Simulator if it isn\'t already running.');
argParser.addFlag('boot', help: 'Boot the iOS Simulator if it isn\'t already running.');
}
@override
Future<int> runInProject() async {
await downloadApplicationPackagesAndConnectToDevices();
return install(boot: argResults['boot']) ? 0 : 2;
bool installedAny = installApp(
devices,
applicationPackages,
boot: argResults['boot']
);
return installedAny ? 0 : 2;
}
}
bool install({ bool boot: false }) {
if (boot)
devices.iOSSimulator?.boot();
bool installedSomewhere = false;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected() || device.isAppInstalled(package))
continue;
if (device.installApp(package))
installedSomewhere = true;
}
return installedSomewhere;
bool installApp(
DeviceStore devices,
ApplicationPackageStore applicationPackages, {
bool boot: false
}) {
if (boot)
devices.iOSSimulator?.boot();
bool installedSomewhere = false;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected() || device.isAppInstalled(package))
continue;
if (device.installApp(package))
installedSomewhere = true;
}
return installedSomewhere;
}
......@@ -18,6 +18,8 @@ class ListCommand extends FlutterCommand {
help: 'Log additional details about attached devices.');
}
bool get requiresProjectRoot => false;
@override
Future<int> runInProject() async {
connectToDevices();
......
......@@ -34,7 +34,17 @@ class ListenCommand extends StartCommandBase {
bool firstTime = true;
do {
logging.info('Updating running Flutter apps...');
result = await startApp(install: firstTime, stop: true);
result = await startApp(
devices,
applicationPackages,
toolchain,
target: argResults['target'],
install: firstTime,
stop: true,
checked: argResults['checked'],
traceStartup: argResults['trace-startup'],
route: argResults['route']
);
firstTime = false;
} while (!singleRun && result == 0 && _watchDirectory(watchCommand));
return 0;
......
......@@ -154,7 +154,7 @@ class RunMojoCommand extends FlutterCommand {
if (bundlePath == null) {
bundlePath = _kDefaultBundlePath;
String mainPath = StartCommandBase.findMainDartFile(argResults['target']);
String mainPath = findMainDartFile(argResults['target']);
int result = await flx.build(
toolchain,
......
......@@ -13,9 +13,23 @@ import '../build_configuration.dart';
import '../device.dart';
import '../flx.dart' as flx;
import '../runner/flutter_command.dart';
import '../toolchain.dart';
import 'install.dart';
import 'stop.dart';
/// Given the value of the --target option, return the path of the Dart file
/// where the app's main function should be.
String findMainDartFile([String target]) {
if (target == null)
target = '';
String targetPath = path.absolute(target);
if (FileSystemEntity.isDirectorySync(targetPath)) {
return path.join(targetPath, 'lib', 'main.dart');
} else {
return targetPath;
}
}
// We don't yet support iOS here. https://github.com/flutter/flutter/issues/1036
abstract class StartCommandBase extends FlutterCommand {
......@@ -29,101 +43,11 @@ abstract class StartCommandBase extends FlutterCommand {
defaultsTo: false,
help: 'Start tracing during startup.');
argParser.addOption('target',
defaultsTo: '',
abbr: 't',
help: 'Target app path or filename to start.');
argParser.addOption('route',
help: 'Which route to load when starting the app.');
}
/// Given the value of the --target option, return the path of the Dart file
/// where the app's main function should be.
static String findMainDartFile(String target) {
String targetPath = path.absolute(target);
if (FileSystemEntity.isDirectorySync(targetPath)) {
return path.join(targetPath, 'lib', 'main.dart');
} else {
return targetPath;
}
}
Future<int> startApp({
bool stop: true,
bool install: true,
bool poke: false,
bool clearLogs: false
}) async {
String mainPath = findMainDartFile(argResults['target']);
if (!FileSystemEntity.isFileSync(mainPath)) {
String message = 'Tried to run $mainPath, but that file does not exist.';
if (!argResults.wasParsed('target'))
message += '\nConsider using the -t option to specify that Dart file to start.';
logging.severe(message);
return 1;
}
if (stop) {
logging.fine('Running stop command.');
StopCommand stopper = new StopCommand();
stopper.inheritFromParent(this);
stopper.stop();
}
if (install) {
logging.fine('Running install command.');
InstallCommand installer = new InstallCommand();
installer.inheritFromParent(this);
installer.install();
}
bool startedSomething = false;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected())
continue;
logging.fine('Running build command for $device.');
if (device.platform == TargetPlatform.android) {
await flx.buildInTempDir(
toolchain,
mainPath: mainPath,
onBundleAvailable: (String localBundlePath) {
logging.fine('Starting bundle for $device.');
final AndroidDevice androidDevice = device; // https://github.com/flutter/flutter/issues/1035
if (androidDevice.startBundle(package, localBundlePath,
poke: poke,
checked: argResults['checked'],
traceStartup: argResults['trace-startup'],
route: argResults['route'],
clearLogs: clearLogs
)) {
startedSomething = true;
}
}
);
} else {
bool result = await device.startApp(package);
if (!result) {
logging.severe('Could not start \'${package.name}\' on \'${device.id}\'');
} else {
startedSomething = true;
}
}
}
if (!startedSomething) {
if (!devices.all.any((device) => device.isConnected())) {
logging.severe('Unable to run application - no connected devices.');
} else {
logging.severe('Unable to run application.');
}
}
return startedSomething ? 0 : 2;
}
}
class StartCommand extends StartCommandBase {
......@@ -152,10 +76,103 @@ class StartCommand extends StartCommandBase {
bool poke = argResults['poke'];
bool clearLogs = argResults['clear-logs'];
// Only stop and reinstall if the user did not specify a poke
int result = await startApp(stop: !poke, install: !poke, poke: poke, clearLogs: clearLogs);
// Only stop and reinstall if the user did not specify a poke.
int result = await startApp(
devices,
applicationPackages,
toolchain,
target: argResults['target'],
install: !poke,
stop: !poke,
checked: argResults['checked'],
traceStartup: argResults['trace-startup'],
route: argResults['route'],
poke: poke,
clearLogs: clearLogs
);
logging.fine('Finished start command.');
return result;
}
}
Future<int> startApp(
DeviceStore devices,
ApplicationPackageStore applicationPackages,
Toolchain toolchain, {
String target,
bool stop: true,
bool install: true,
bool checked: true,
bool traceStartup: false,
String route,
bool poke: false,
bool clearLogs: false
}) async {
String mainPath = findMainDartFile(target);
if (!FileSystemEntity.isFileSync(mainPath)) {
String message = 'Tried to run $mainPath, but that file does not exist.';
if (target == null)
message += '\nConsider using the -t option to specify the Dart file to start.';
logging.severe(message);
return 1;
}
if (stop) {
logging.fine('Running stop command.');
stopAll(devices, applicationPackages);
}
if (install) {
logging.fine('Running install command.');
installApp(devices, applicationPackages);
}
bool startedSomething = false;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected())
continue;
logging.fine('Running build command for $device.');
if (device.platform == TargetPlatform.android) {
await flx.buildInTempDir(
toolchain,
mainPath: mainPath,
onBundleAvailable: (String localBundlePath) {
logging.fine('Starting bundle for $device.');
final AndroidDevice androidDevice = device; // https://github.com/flutter/flutter/issues/1035
if (androidDevice.startBundle(package, localBundlePath,
poke: poke,
checked: checked,
traceStartup: traceStartup,
route: route,
clearLogs: clearLogs
)) {
startedSomething = true;
}
}
);
} else {
bool result = await device.startApp(package);
if (!result) {
logging.severe('Could not start \'${package.name}\' on \'${device.id}\'');
} else {
startedSomething = true;
}
}
}
if (!startedSomething) {
if (!devices.all.any((device) => device.isConnected())) {
logging.severe('Unable to run application - no connected devices.');
} else {
logging.severe('Unable to run application.');
}
}
return startedSomething ? 0 : 2;
}
......@@ -18,17 +18,19 @@ class StopCommand extends FlutterCommand {
return await stop() ? 0 : 2;
}
Future<bool> stop() async {
bool stoppedSomething = false;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected())
continue;
if (await device.stopApp(package))
stoppedSomething = true;
}
return stoppedSomething;
Future<bool> stop() => stopAll(devices, applicationPackages);
}
Future<bool> stopAll(DeviceStore devices, ApplicationPackageStore applicationPackages) async {
bool stoppedSomething = false;
for (Device device in devices.all) {
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
if (package == null || !device.isConnected())
continue;
if (await device.stopApp(package))
stoppedSomething = true;
}
return stoppedSomething;
}
......@@ -310,7 +310,7 @@ class IOSSimulator extends Device {
String output = runCheckedSync([xcrunPath, 'simctl', 'list', 'devices']);
Match match;
/// iPhone 6s Plus (8AC808E1-6BAE-4153-BBC5-77F83814D414) (Booted)
// iPhone 6s Plus (8AC808E1-6BAE-4153-BBC5-77F83814D414) (Booted)
Iterable<Match> matches = new RegExp(
r'[\W]*(.*) \(([^\)]+)\) \(Booted\)',
multiLine: true
......
......@@ -47,12 +47,6 @@ abstract class FlutterCommand extends Command {
connectToDevices();
}
void inheritFromParent(FlutterCommand other) {
applicationPackages = other.applicationPackages;
toolchain = other.toolchain;
devices = other.devices;
}
Future<int> run() async {
if (requiresProjectRoot && !validateProjectRoot())
return 1;
......
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