Commit 223f4161 authored by Dan Rubel's avatar Dan Rubel Committed by GitHub

Flutter run with machine output (#6645)

* add flutter run --machine flag
* refactor daemon stdin/out command stream/response
* extract daemon startApp method
* refactor flutter run --machine to call daemon.startApp
parent 1c2be027
...@@ -52,31 +52,14 @@ class DaemonCommand extends FlutterCommand { ...@@ -52,31 +52,14 @@ class DaemonCommand extends FlutterCommand {
Cache.releaseLockEarly(); Cache.releaseLockEarly();
return appContext.runInZone(() { return appContext.runInZone(() {
Stream<Map<String, dynamic>> commandStream = stdin Daemon daemon = new Daemon(
.transform(UTF8.decoder) stdinCommandStream, stdoutCommandResponse,
.transform(const LineSplitter()) daemonCommand: this, notifyingLogger: notifyingLogger);
.where((String line) => line.startsWith('[{') && line.endsWith('}]'))
.map((String line) {
line = line.substring(1, line.length - 1);
return JSON.decode(line);
});
Daemon daemon = new Daemon(commandStream, (Map<String, dynamic> command) {
stdout.writeln('[${JSON.encode(command, toEncodable: _jsonEncodeObject)}]');
}, daemonCommand: this, notifyingLogger: notifyingLogger);
return daemon.onExit; return daemon.onExit;
}, onError: _handleError); }, onError: _handleError);
} }
dynamic _jsonEncodeObject(dynamic object) {
if (object is Device)
return _deviceToMap(object);
if (object is OperationResult)
return _operationResultToMap(object);
return object;
}
dynamic _handleError(dynamic error, StackTrace stackTrace) { dynamic _handleError(dynamic error, StackTrace stackTrace) {
printError('Error from flutter daemon: $error', stackTrace); printError('Error from flutter daemon: $error', stackTrace);
return null; return null;
...@@ -306,6 +289,23 @@ class AppDomain extends Domain { ...@@ -306,6 +289,23 @@ class AppDomain extends Domain {
throw "'$projectDirectory' does not exist"; throw "'$projectDirectory' does not exist";
BuildMode buildMode = getBuildModeForName(mode) ?? BuildMode.debug; BuildMode buildMode = getBuildModeForName(mode) ?? BuildMode.debug;
AppInstance app = startApp(
device, projectDirectory, target, route,
buildMode, startPaused, enableHotReload);
return <String, dynamic>{
'appId': app.id,
'deviceId': device.id,
'directory': projectDirectory,
'supportsRestart': isRestartSupported(enableHotReload, device)
};
}
AppInstance startApp(
Device device, String projectDirectory, String target, String route,
BuildMode buildMode, bool startPaused, bool enableHotReload) {
DebuggingOptions options; DebuggingOptions options;
switch (buildMode) { switch (buildMode) {
...@@ -342,14 +342,12 @@ class AppDomain extends Domain { ...@@ -342,14 +342,12 @@ class AppDomain extends Domain {
); );
} }
bool supportsRestart = enableHotReload ? device.supportsHotMode : device.supportsRestart;
AppInstance app = new AppInstance(_getNewAppId(), runner); AppInstance app = new AppInstance(_getNewAppId(), runner);
_apps.add(app); _apps.add(app);
_sendAppEvent(app, 'start', <String, dynamic>{ _sendAppEvent(app, 'start', <String, dynamic>{
'deviceId': deviceId, 'deviceId': device.id,
'directory': projectDirectory, 'directory': projectDirectory,
'supportsRestart': supportsRestart 'supportsRestart': isRestartSupported(enableHotReload, device)
}); });
Completer<DebugConnectionInfo> connectionInfoCompleter; Completer<DebugConnectionInfo> connectionInfoCompleter;
...@@ -375,14 +373,12 @@ class AppDomain extends Domain { ...@@ -375,14 +373,12 @@ class AppDomain extends Domain {
}); });
}); });
return <String, dynamic>{ return app;
'appId': app.id,
'deviceId': deviceId,
'directory': projectDirectory,
'supportsRestart': supportsRestart
};
} }
bool isRestartSupported(bool enableHotReload, Device device) =>
enableHotReload ? device.supportsHotMode : device.supportsRestart;
Future<OperationResult> restart(Map<String, dynamic> args) async { Future<OperationResult> restart(Map<String, dynamic> args) async {
String appId = _getStringArg(args, 'appId', required: true); String appId = _getStringArg(args, 'appId', required: true);
bool fullRestart = _getBoolArg(args, 'fullRestart') ?? false; bool fullRestart = _getBoolArg(args, 'fullRestart') ?? false;
...@@ -561,6 +557,27 @@ class DeviceDomain extends Domain { ...@@ -561,6 +557,27 @@ class DeviceDomain extends Domain {
} }
} }
Stream<Map<String, dynamic>> get stdinCommandStream => stdin
.transform(UTF8.decoder)
.transform(const LineSplitter())
.where((String line) => line.startsWith('[{') && line.endsWith('}]'))
.map((String line) {
line = line.substring(1, line.length - 1);
return JSON.decode(line);
});
void stdoutCommandResponse(Map<String, dynamic> command) {
stdout.writeln('[${JSON.encode(command, toEncodable: _jsonEncodeObject)}]');
}
dynamic _jsonEncodeObject(dynamic object) {
if (object is Device)
return _deviceToMap(object);
if (object is OperationResult)
return _operationResultToMap(object);
return object;
}
Map<String, dynamic> _deviceToMap(Device device) { Map<String, dynamic> _deviceToMap(Device device) {
return <String, dynamic>{ return <String, dynamic>{
'id': device.id, 'id': device.id,
......
...@@ -19,6 +19,7 @@ import '../resident_runner.dart'; ...@@ -19,6 +19,7 @@ import '../resident_runner.dart';
import '../run.dart'; import '../run.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
import 'build_apk.dart'; import 'build_apk.dart';
import 'daemon.dart';
import 'install.dart'; import 'install.dart';
import 'trace.dart'; import 'trace.dart';
...@@ -61,6 +62,10 @@ class RunCommand extends RunCommandBase { ...@@ -61,6 +62,10 @@ class RunCommand extends RunCommandBase {
argParser.addOption('use-application-binary', argParser.addOption('use-application-binary',
hide: !verboseHelp, hide: !verboseHelp,
help: 'Specify a pre-built application binary to use when running.'); help: 'Specify a pre-built application binary to use when running.');
argParser.addFlag('machine',
hide: !verboseHelp,
help: 'Handle machine structured JSON command input\n'
'and provide output and progress in machine friendly format.');
usesPubOption(); usesPubOption();
// Option to enable hot reloading. // Option to enable hot reloading.
...@@ -79,7 +84,6 @@ class RunCommand extends RunCommandBase { ...@@ -79,7 +84,6 @@ class RunCommand extends RunCommandBase {
'and SIGUSR2 to trigger a full restart.' 'and SIGUSR2 to trigger a full restart.'
); );
// Hidden option to enable a benchmarking mode. This will run the given // Hidden option to enable a benchmarking mode. This will run the given
// application, measure the startup time and the app restart time, write the // application, measure the startup time and the app restart time, write the
// results out to 'refresh_benchmark.json', and exit. This flag is intended // results out to 'refresh_benchmark.json', and exit. This flag is intended
...@@ -153,8 +157,23 @@ class RunCommand extends RunCommandBase { ...@@ -153,8 +157,23 @@ class RunCommand extends RunCommandBase {
@override @override
Future<int> runCommand() async { Future<int> runCommand() async {
int debugPort;
Cache.releaseLockEarly();
// Enable hot mode by default if `--no-hot` was not passed and we are in
// debug mode.
final bool hotMode = shouldUseHotMode();
if (argResults['machine']) {
Daemon daemon = new Daemon(stdinCommandStream, stdoutCommandResponse,
notifyingLogger: new NotifyingLogger());
AppInstance app = daemon.appDomain.startApp(
device, Directory.current.path, targetFile, route,
getBuildMode(), argResults['start-paused'], hotMode);
return app.runner.waitForAppToFinish();
}
int debugPort;
if (argResults['debug-port'] != null) { if (argResults['debug-port'] != null) {
try { try {
debugPort = int.parse(argResults['debug-port']); debugPort = int.parse(argResults['debug-port']);
...@@ -181,12 +200,6 @@ class RunCommand extends RunCommandBase { ...@@ -181,12 +200,6 @@ class RunCommand extends RunCommandBase {
); );
} }
Cache.releaseLockEarly();
// Enable hot mode by default if ``--no-hot` was not passed and we are in
// debug mode.
final bool hotMode = shouldUseHotMode();
if (hotMode) { if (hotMode) {
if (!device.supportsHotMode) { if (!device.supportsHotMode) {
printError('Hot mode is not supported by this device. ' printError('Hot mode is not supported by this device. '
...@@ -207,7 +220,7 @@ class RunCommand extends RunCommandBase { ...@@ -207,7 +220,7 @@ class RunCommand extends RunCommandBase {
device, device,
target: targetFile, target: targetFile,
debuggingOptions: options, debuggingOptions: options,
benchmarkMode: argResults['benchmark'], benchmarkMode: argResults['benchmark']
); );
} else { } else {
runner = new RunAndStayResident( runner = new RunAndStayResident(
......
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