diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index 1996595e887..60eae6dc2ce 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart @@ -677,11 +677,14 @@ Stream> get stdinCommandStream => stdin }); void stdoutCommandResponse(Map command) { - final String encoded = JSON.encode(command, toEncodable: _jsonEncodeObject); - stdout.writeln('[$encoded]'); + stdout.writeln('[${jsonEncodeObject(command)}]'); } -dynamic _jsonEncodeObject(dynamic object) { +String jsonEncodeObject(dynamic object) { + return JSON.encode(object, toEncodable: _toEncodable); +} + +dynamic _toEncodable(dynamic object) { if (object is OperationResult) return _operationResultToMap(object); return object; @@ -697,10 +700,17 @@ Future> _deviceToMap(Device device) async { } Map _operationResultToMap(OperationResult result) { - return { + final Map map = { 'code': result.code, - 'message': result.message + 'message': result.message, }; + + if (result.hintMessage != null) + map['hintMessage'] = result.hintMessage; + if (result.hintId != null) + map['hintId'] = result.hintId; + + return map; } dynamic _toJsonable(dynamic obj) { diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index b56e93f6f28..770ee465527 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -843,11 +843,24 @@ abstract class ResidentRunner { } class OperationResult { - OperationResult(this.code, this.message, { this.hint }); + OperationResult(this.code, this.message, { this.hintMessage, this.hintId }); + /// The result of the operation; a non-zero code indicates a failure. final int code; + + /// A user facing message about the results of the operation. final String message; - final String hint; + + /// An optional hint about the results of the operation. This is used to provide + /// sidecar data about the operation results. For example, this is used when + /// a reload is successful but some changed program elements where not run after a + /// reassemble. + final String hintMessage; + + /// A key used by tools to discriminate between different kinds of operation results. + /// For example, a successful reload might have a [code] of 0 and a [hintId] of + /// `'restartRecommended'`. + final String hintId; bool get isOk => code == 0; diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index f8d227faf84..a4000ada322 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -457,8 +457,8 @@ class HotRunner extends ResidentRunner { status.cancel(); if (result.isOk) printStatus('${result.message} in ${getElapsedAsMilliseconds(timer.elapsed)}.'); - if (result.hint != null) - printStatus('\n${result.hint}'); + if (result.hintMessage != null) + printStatus('\n${result.hintMessage}'); return result; } catch (error) { status.cancel(); @@ -678,7 +678,8 @@ class HotRunner extends ResidentRunner { return new OperationResult( reassembleAndScheduleErrors ? 1 : OperationResult.ok.code, reloadMessage, - hint: unusedElementMessage, + hintMessage: unusedElementMessage, + hintId: unusedElementMessage != null ? 'restartRecommended' : null, ); } diff --git a/packages/flutter_tools/test/commands/daemon_test.dart b/packages/flutter_tools/test/commands/daemon_test.dart index 10a864be927..07962c8b523 100644 --- a/packages/flutter_tools/test/commands/daemon_test.dart +++ b/packages/flutter_tools/test/commands/daemon_test.dart @@ -10,6 +10,7 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/commands/daemon.dart'; import 'package:flutter_tools/src/globals.dart'; import 'package:flutter_tools/src/ios/ios_workflow.dart'; +import 'package:flutter_tools/src/resident_runner.dart'; import 'package:test/test.dart'; import '../src/context.dart'; @@ -267,6 +268,23 @@ void main() { IOSWorkflow: () => new MockIOSWorkflow(), }); }); + + group('daemon serialization', () { + test('OperationResult', () { + expect( + jsonEncodeObject(OperationResult.ok), + '{"code":0,"message":""}' + ); + expect( + jsonEncodeObject(new OperationResult(1, 'foo')), + '{"code":1,"message":"foo"}' + ); + expect( + jsonEncodeObject(new OperationResult(0, 'foo', hintMessage: 'my hint', hintId: 'myId')), + '{"code":0,"message":"foo","hintMessage":"my hint","hintId":"myId"}' + ); + }); + }); } bool _notEvent(Map map) => map['event'] == null;