| diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart |
| index 12c0770ab..b7945fd64 100644 |
| --- a/packages/flutter_tools/lib/src/compile.dart |
| +++ b/packages/flutter_tools/lib/src/compile.dart |
| @@ -57,12 +57,15 @@ class TargetModel { |
| } |
| |
| class CompilerOutput { |
| - const CompilerOutput(this.outputFilename, this.errorCount); |
| + const CompilerOutput(this.outputFilename, this.errorCount, this.sources); |
| |
| final String outputFilename; |
| final int errorCount; |
| + final List<Uri> sources; |
| } |
| |
| +enum StdoutState { CollectDiagnostic, CollectDependencies } |
| + |
| /// Handles stdin/stdout communication with the frontend server. |
| class StdoutHandler { |
| StdoutHandler({this.consumer = printError}) { |
| @@ -72,40 +75,71 @@ class StdoutHandler { |
| bool compilerMessageReceived = false; |
| final CompilerMessageConsumer consumer; |
| String boundaryKey; |
| + StdoutState state = StdoutState.CollectDiagnostic; |
| Completer<CompilerOutput> compilerOutput; |
| + final List<Uri> sources = <Uri>[]; |
| |
| bool _suppressCompilerMessages; |
| + bool _expectSources; |
| |
| void handler(String message) { |
| + printTrace('-> $message'); |
| const String kResultPrefix = 'result '; |
| if (boundaryKey == null && message.startsWith(kResultPrefix)) { |
| boundaryKey = message.substring(kResultPrefix.length); |
| - } else if (message.startsWith(boundaryKey)) { |
| + return; |
| + } |
| + if (message.startsWith(boundaryKey)) { |
| + if (_expectSources) { |
| + if (state == StdoutState.CollectDiagnostic) { |
| + state = StdoutState.CollectDependencies; |
| + return; |
| + } |
| + } |
| if (message.length <= boundaryKey.length) { |
| compilerOutput.complete(null); |
| return; |
| } |
| final int spaceDelimiter = message.lastIndexOf(' '); |
| compilerOutput.complete( |
| - CompilerOutput( |
| - message.substring(boundaryKey.length + 1, spaceDelimiter), |
| - int.parse(message.substring(spaceDelimiter + 1).trim()))); |
| - } else if (!_suppressCompilerMessages) { |
| - if (compilerMessageReceived == false) { |
| - consumer('\nCompiler message:'); |
| - compilerMessageReceived = true; |
| + CompilerOutput( |
| + message.substring(boundaryKey.length + 1, spaceDelimiter), |
| + int.parse(message.substring(spaceDelimiter + 1).trim()), |
| + sources)); |
| + return; |
| + } |
| + if (state == StdoutState.CollectDiagnostic) { |
| + if (!_suppressCompilerMessages) { |
| + if (compilerMessageReceived == false) { |
| + consumer('\nCompiler message:'); |
| + compilerMessageReceived = true; |
| + } |
| + consumer(message); |
| + } |
| + } else { |
| + assert(state == StdoutState.CollectDependencies); |
| + switch (message[0]) { |
| + case '+': |
| + sources.add(Uri.parse(message.substring(1))); |
| + break; |
| + case '-': |
| + sources.remove(Uri.parse(message.substring(1))); |
| + break; |
| + default: |
| + printTrace('Unexpected prefix for $message uri - ignoring'); |
| } |
| - consumer(message); |
| } |
| } |
| |
| // This is needed to get ready to process next compilation result output, |
| // with its own boundary key and new completer. |
| - void reset({ bool suppressCompilerMessages = false }) { |
| + void reset({ bool suppressCompilerMessages = false, bool expectSources = true }) { |
| boundaryKey = null; |
| compilerMessageReceived = false; |
| compilerOutput = Completer<CompilerOutput>(); |
| _suppressCompilerMessages = suppressCompilerMessages; |
| + _expectSources = expectSources; |
| + state = StdoutState.CollectDiagnostic; |
| } |
| } |
| |
| @@ -200,7 +234,7 @@ class KernelCompiler { |
| |
| if (await fingerprinter.doesFingerprintMatch()) { |
| printTrace('Skipping kernel compilation. Fingerprint match.'); |
| - return CompilerOutput(outputFilePath, 0); |
| + return CompilerOutput(outputFilePath, 0, /* sources */ null); |
| } |
| } |
| |
| @@ -453,10 +487,13 @@ class ResidentCompiler { |
| ? _mapFilename(request.mainPath, packageUriMapper) + ' ' |
| : ''; |
| _server.stdin.writeln('recompile $mainUri$inputKey'); |
| + printTrace('<- recompile $mainUri$inputKey'); |
| for (String fileUri in request.invalidatedFiles) { |
| _server.stdin.writeln(_mapFileUri(fileUri, packageUriMapper)); |
| + printTrace('<- ${_mapFileUri(fileUri, packageUriMapper)}'); |
| } |
| _server.stdin.writeln(inputKey); |
| + printTrace('<- $inputKey'); |
| |
| return _stdoutHandler.compilerOutput.future; |
| } |
| @@ -545,6 +582,7 @@ class ResidentCompiler { |
| .listen((String message) { printError(message); }); |
| |
| _server.stdin.writeln('compile $scriptUri'); |
| + printTrace('<- compile $scriptUri'); |
| |
| return _stdoutHandler.compilerOutput.future; |
| } |
| @@ -570,7 +608,7 @@ class ResidentCompiler { |
| } |
| |
| Future<CompilerOutput> _compileExpression(_CompileExpressionRequest request) async { |
| - _stdoutHandler.reset(suppressCompilerMessages: true); |
| + _stdoutHandler.reset(suppressCompilerMessages: true, expectSources: false); |
| |
| // 'compile-expression' should be invoked after compiler has been started, |
| // program was compiled. |
| @@ -597,6 +635,7 @@ class ResidentCompiler { |
| void accept() { |
| if (_compileRequestNeedsConfirmation) { |
| _server.stdin.writeln('accept'); |
| + printTrace('<- accept'); |
| } |
| _compileRequestNeedsConfirmation = false; |
| } |
| @@ -620,6 +659,7 @@ class ResidentCompiler { |
| } |
| _stdoutHandler.reset(); |
| _server.stdin.writeln('reject'); |
| + printTrace('<- reject'); |
| _compileRequestNeedsConfirmation = false; |
| return _stdoutHandler.compilerOutput.future; |
| } |
| @@ -629,6 +669,7 @@ class ResidentCompiler { |
| /// kernel file. |
| void reset() { |
| _server?.stdin?.writeln('reset'); |
| + printTrace('<- reset'); |
| } |
| |
| String _mapFilename(String filename, PackageUriMapper packageUriMapper) { |
| diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart |
| index 407a51b12..ea63e73c6 100644 |
| --- a/packages/flutter_tools/lib/src/devfs.dart |
| +++ b/packages/flutter_tools/lib/src/devfs.dart |
| @@ -484,6 +484,8 @@ class DevFS { |
| outputPath: dillOutputPath ?? getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation), |
| packagesFilePath : _packagesFilePath, |
| ); |
| + // list of sources that needs to be monitored are in [compilerOutput.sources] |
| + // |
| // Don't send full kernel file that would overwrite what VM already |
| // started loading from. |
| if (!bundleFirstUpload) { |
| diff --git a/packages/flutter_tools/test/compile_test.dart b/packages/flutter_tools/test/compile_test.dart |
| index b149a2a84..0d920bdbe 100644 |
| --- a/packages/flutter_tools/test/compile_test.dart |
| +++ b/packages/flutter_tools/test/compile_test.dart |
| @@ -78,14 +78,17 @@ example:org-dartlang-app:/ |
| }); |
| }); |
| |
| - test(StdoutHandler, () async { |
| + testUsingContext('StdOutHandler test', () async { |
| final StdoutHandler stdoutHandler = StdoutHandler(); |
| stdoutHandler.handler('result 12345'); |
| expect(stdoutHandler.boundaryKey, '12345'); |
| + stdoutHandler.handler('12345'); |
| stdoutHandler.handler('12345 message 0'); |
| final CompilerOutput output = await stdoutHandler.compilerOutput.future; |
| expect(output.errorCount, 0); |
| expect(output.outputFilename, 'message'); |
| + }, overrides: <Type, Generator>{ |
| + Logger: () => BufferLogger(), |
| }); |
| |
| group('batch compile', () { |
| @@ -115,7 +118,7 @@ example:org-dartlang-app:/ |
| when(mockFrontendServer.stdout) |
| .thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture( |
| Future<List<int>>.value(utf8.encode( |
| - 'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0' |
| + 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0' |
| )) |
| )); |
| final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', |
| @@ -138,7 +141,7 @@ example:org-dartlang-app:/ |
| when(mockFrontendServer.stdout) |
| .thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture( |
| Future<List<int>>.value(utf8.encode( |
| - 'result abc\nline1\nline2\nabc' |
| + 'result abc\nline1\nline2\nabc\nabc' |
| )) |
| )); |
| final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot', |
| @@ -163,7 +166,7 @@ example:org-dartlang-app:/ |
| when(mockFrontendServer.stdout) |
| .thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture( |
| Future<List<int>>.value(utf8.encode( |
| - 'result abc\nline1\nline2\nabc' |
| + 'result abc\nline1\nline2\nabc\nabc' |
| )) |
| )); |
| final CompilerOutput output = await kernelCompiler.compile( |
| @@ -220,7 +223,7 @@ example:org-dartlang-app:/ |
| when(mockFrontendServer.stdout) |
| .thenAnswer((Invocation invocation) => Stream<List<int>>.fromFuture( |
| Future<List<int>>.value(utf8.encode( |
| - 'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0' |
| + 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0' |
| )) |
| )); |
| |
| @@ -264,7 +267,7 @@ example:org-dartlang-app:/ |
| final StreamController<List<int>> streamController = StreamController<List<int>>(); |
| when(mockFrontendServer.stdout) |
| .thenAnswer((Invocation invocation) => streamController.stream); |
| - streamController.add(utf8.encode('result abc\nline0\nline1\nabc /path/to/main.dart.dill 0\n')); |
| + streamController.add(utf8.encode('result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0\n')); |
| await generator.recompile( |
| '/path/to/main.dart', |
| null, /* invalidatedFiles */ |
| @@ -278,14 +281,14 @@ example:org-dartlang-app:/ |
| await _reject(streamController, generator, mockFrontendServerStdIn, '', ''); |
| |
| await _recompile(streamController, generator, mockFrontendServerStdIn, |
| - 'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0\n'); |
| + 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'); |
| |
| await _accept(streamController, generator, mockFrontendServerStdIn, '^accept\\n\$'); |
| |
| await _recompile(streamController, generator, mockFrontendServerStdIn, |
| - 'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0\n'); |
| + 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'); |
| |
| - await _reject(streamController, generator, mockFrontendServerStdIn, 'result abc\nabc\n', |
| + await _reject(streamController, generator, mockFrontendServerStdIn, 'result abc\nabc\nabc\nabc', |
| '^reject\\n\$'); |
| |
| verifyNoMoreInteractions(mockFrontendServerStdIn); |
| @@ -309,15 +312,15 @@ example:org-dartlang-app:/ |
| when(mockFrontendServer.stdout) |
| .thenAnswer((Invocation invocation) => streamController.stream); |
| streamController.add(utf8.encode( |
| - 'result abc\nline0\nline1\nabc /path/to/main.dart.dill 0\n' |
| + 'result abc\nline0\nline1\nabc\nabc /path/to/main.dart.dill 0\n' |
| )); |
| await generator.recompile('/path/to/main.dart', null /* invalidatedFiles */, outputPath: '/build/'); |
| expect(mockFrontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); |
| |
| await _recompile(streamController, generator, mockFrontendServerStdIn, |
| - 'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0\n'); |
| + 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n'); |
| await _recompile(streamController, generator, mockFrontendServerStdIn, |
| - 'result abc\nline2\nline3\nabc /path/to/main.dart.dill 0\n'); |
| + 'result abc\nline2\nline3\nabc\nabc /path/to/main.dart.dill 0\n'); |
| |
| verifyNoMoreInteractions(mockFrontendServerStdIn); |
| expect(mockFrontendServerStdIn.getAndClear(), isEmpty); |
| @@ -389,7 +392,7 @@ example:org-dartlang-app:/ |
| compileExpressionResponseCompleter.future])); |
| |
| compileResponseCompleter.complete(Future<List<int>>.value(utf8.encode( |
| - 'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0\n' |
| + 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n' |
| ))); |
| |
| await generator.recompile( |
| @@ -406,7 +409,7 @@ example:org-dartlang-app:/ |
| |
| compileExpressionResponseCompleter.complete( |
| Future<List<int>>.value(utf8.encode( |
| - 'result def\nline1\nline2\ndef /path/to/main.dart.dill.incremental 0\n' |
| + 'result def\nline1\nline2\ndef\ndef /path/to/main.dart.dill.incremental 0\n' |
| ))); |
| generator.compileExpression( |
| '2+2', null, null, null, null, false).then( |
| @@ -488,7 +491,7 @@ example:org-dartlang-app:/ |
| ); |
| |
| compileResponseCompleter.complete(Future<List<int>>.value(utf8.encode( |
| - 'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0\n' |
| + 'result abc\nline1\nline2\nabc\nabc /path/to/main.dart.dill 0\n' |
| ))); |
| |
| expect(await lastExpressionCompleted.future, isTrue); |
| diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart |
| index 42c9d8f7f..c47b4ff7c 100644 |
| --- a/packages/flutter_tools/test/src/mocks.dart |
| +++ b/packages/flutter_tools/test/src/mocks.dart |
| @@ -490,6 +490,6 @@ class MockResidentCompiler extends BasicMock implements ResidentCompiler { |
| Future<CompilerOutput> recompile(String mainPath, List<String> invalidatedFiles, { String outputPath, String packagesFilePath }) async { |
| fs.file(outputPath).createSync(recursive: true); |
| fs.file(outputPath).writeAsStringSync('compiled_kernel_output'); |
| - return CompilerOutput(outputPath, 0); |
| + return CompilerOutput(outputPath, 0, <Uri>[]); |
| } |
| } |
| diff --git a/packages/flutter_tools/test/tester/flutter_tester_test.dart b/packages/flutter_tools/test/tester/flutter_tester_test.dart |
| index a78f70f4f..b6524bd5d 100644 |
| --- a/packages/flutter_tools/test/tester/flutter_tester_test.dart |
| +++ b/packages/flutter_tools/test/tester/flutter_tester_test.dart |
| @@ -177,7 +177,7 @@ Hello! |
| packagesPath: anyNamed('packagesPath'), |
| )).thenAnswer((_) async { |
| fs.file('$mainPath.dill').createSync(recursive: true); |
| - return CompilerOutput('$mainPath.dill', 0); |
| + return CompilerOutput('$mainPath.dill', 0, <Uri>[]); |
| }); |
| |
| final LaunchResult result = await device.startApp(null, |