Reland: don't update last compile time when compilation is rejected. (#41580)

* dont update last compiled time when compilation is rejected

* lets try flushing, thats a neat trick

* windows man

* Update hot_reload_test.dart

* Update hot_reload_test.dart

* Update devfs.dart

* Update hot_reload_test.dart

* Update hot_reload_test.dart

* add test that verifies when compile is good that time is updated

* Update devfs_test.dart
diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart
index 8795c4d..366c698 100644
--- a/packages/flutter_tools/lib/src/devfs.dart
+++ b/packages/flutter_tools/lib/src/devfs.dart
@@ -445,6 +445,7 @@
   }) async {
     assert(trackWidgetCreation != null);
     assert(generator != null);
+    final DateTime candidateCompileTime = DateTime.now();
 
     // Update modified files
     final String assetBuildDirPrefix = _asUriPath(getAssetBuildDirectory());
@@ -476,7 +477,6 @@
       generator.reset();
     }
     printTrace('Compiling dart to kernel with ${invalidatedFiles.length} updated files');
-    lastCompiled = DateTime.now();
     final CompilerOutput compilerOutput = await generator.recompile(
       mainPath,
       invalidatedFiles,
@@ -486,6 +486,8 @@
     if (compilerOutput == null || compilerOutput.errorCount > 0) {
       return UpdateFSReport(success: false);
     }
+    // Only update the last compiled time if we successfully compiled.
+    lastCompiled = candidateCompileTime;
     // list of sources that needs to be monitored are in [compilerOutput.sources]
     sources = compilerOutput.sources;
     //
diff --git a/packages/flutter_tools/test/general.shard/devfs_test.dart b/packages/flutter_tools/test/general.shard/devfs_test.dart
index a892efa..0a49b42 100644
--- a/packages/flutter_tools/test/general.shard/devfs_test.dart
+++ b/packages/flutter_tools/test/general.shard/devfs_test.dart
@@ -247,12 +247,14 @@
     testUsingContext('reports unsuccessful compile when errors are returned', () async {
       devFS = DevFS(vmService, 'test', tempDir);
       await devFS.create();
+      final DateTime previousCompile = devFS.lastCompiled;
 
       final RealMockResidentCompiler residentCompiler = RealMockResidentCompiler();
       when(residentCompiler.recompile(
         any,
         any,
         outputPath: anyNamed('outputPath'),
+        packagesFilePath: anyNamed('packagesFilePath'),
       )).thenAnswer((Invocation invocation) {
         return Future<CompilerOutput>.value(const CompilerOutput('example', 2, <Uri>[]));
       });
@@ -266,6 +268,40 @@
       );
 
       expect(report.success, false);
+      expect(devFS.lastCompiled, previousCompile);
+    }, overrides: <Type, Generator>{
+      FileSystem: () => fs,
+    });
+
+    testUsingContext('correctly updates last compiled time when compilation does not fail', () async {
+      devFS = DevFS(vmService, 'test', tempDir);
+      // simulate package
+      final File sourceFile = await _createPackage(fs, 'somepkg', 'main.dart');
+
+      await devFS.create();
+      final DateTime previousCompile = devFS.lastCompiled;
+
+      final RealMockResidentCompiler residentCompiler = RealMockResidentCompiler();
+      when(residentCompiler.recompile(
+        any,
+        any,
+        outputPath: anyNamed('outputPath'),
+        packagesFilePath: anyNamed('packagesFilePath'),
+      )).thenAnswer((Invocation invocation) {
+        fs.file('example').createSync();
+        return Future<CompilerOutput>.value(CompilerOutput('example', 0, <Uri>[sourceFile.uri]));
+      });
+
+      final UpdateFSReport report = await devFS.update(
+        mainPath: 'lib/main.dart',
+        generator: residentCompiler,
+        pathToReload: 'lib/foo.txt.dill',
+        trackWidgetCreation: false,
+        invalidatedFiles: <Uri>[],
+      );
+
+      expect(report.success, true);
+      expect(devFS.lastCompiled, isNot(previousCompile));
     }, overrides: <Type, Generator>{
       FileSystem: () => fs,
     });
@@ -375,7 +411,7 @@
   }
 }
 
-Future<void> _createPackage(FileSystem fs, String pkgName, String pkgFileName, { bool doubleSlash = false }) async {
+Future<File> _createPackage(FileSystem fs, String pkgName, String pkgFileName, { bool doubleSlash = false }) async {
   final Directory pkgTempDir = _newTempDir(fs);
   String pkgFilePath = fs.path.join(pkgTempDir.path, pkgName, 'lib', pkgFileName);
   if (doubleSlash) {
@@ -391,7 +427,8 @@
   _packages.forEach((String pkgName, Uri pkgUri) {
     sb.writeln('$pkgName:$pkgUri');
   });
-  fs.file(fs.path.join(_tempDirs[0].path, '.packages')).writeAsStringSync(sb.toString());
+  return fs.file(fs.path.join(_tempDirs[0].path, '.packages'))
+    ..writeAsStringSync(sb.toString());
 }
 
 class RealMockVM extends Mock implements VM {
diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart
index 68de1d4..7f155d4 100644
--- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart
+++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart
@@ -24,7 +24,7 @@
   import 'package:flutter/material.dart';
   import 'package:flutter/scheduler.dart';
 
-  void main() => runApp(new MyApp());
+  void main() => runApp(MyApp());
 
   int count = 1;