Use source list from the compiler to track invalidated files for hot reload. (#29693)
* Use source list from the compiler to track invalidated files.
* Revert accidental change
* Fix first-time-seen-the-file logic
* Fix/simplify invalidate logic now that we can rely on compiler to let us know what is the cut-off point for invalidation.
* Update devfs mock to accommodate for new fields
* Fix deleted files case
* Analyzer found missing final
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index a0ba839..c0d1efd 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -352,7 +352,6 @@
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) async {
diff --git a/packages/flutter_tools/lib/src/codegen.dart b/packages/flutter_tools/lib/src/codegen.dart
index 114918e..b843a5b 100644
--- a/packages/flutter_tools/lib/src/codegen.dart
+++ b/packages/flutter_tools/lib/src/codegen.dart
@@ -214,7 +214,7 @@
}
@override
- Future<CompilerOutput> recompile(String mainPath, List<String> invalidatedFiles, {String outputPath, String packagesFilePath}) async {
+ Future<CompilerOutput> recompile(String mainPath, List<Uri> invalidatedFiles, {String outputPath, String packagesFilePath}) async {
if (_codegenDaemon.lastStatus != CodegenStatus.Succeeded && _codegenDaemon.lastStatus != CodegenStatus.Failed) {
await _codegenDaemon.buildResults.firstWhere((CodegenStatus status) {
return status == CodegenStatus.Succeeded || status == CodegenStatus.Failed;
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart
index a485772..0031a4c 100644
--- a/packages/flutter_tools/lib/src/commands/attach.dart
+++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -306,7 +306,6 @@
dillOutputPath: dillOutputPath,
stayResident: stayResident,
ipv6: ipv6,
- flutterProject: flutterProject,
);
}
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index e7b650a..e884b4b 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -19,7 +19,6 @@
import '../device.dart';
import '../emulator.dart';
import '../globals.dart';
-import '../project.dart';
import '../resident_runner.dart';
import '../run_cold.dart';
import '../run_hot.dart';
@@ -342,8 +341,6 @@
if (await device.isLocalEmulator && !options.buildInfo.supportsEmulator) {
throw '${toTitleCase(options.buildInfo.friendlyModeName)} mode is not supported for emulators.';
}
- final FlutterProject flutterProject = await FlutterProject.current();
-
// We change the current working directory for the duration of the `start` command.
final Directory cwd = fs.currentDirectory;
fs.currentDirectory = fs.directory(projectDirectory);
@@ -370,7 +367,6 @@
dillOutputPath: dillOutputPath,
ipv6: ipv6,
hostIsIde: true,
- flutterProject: flutterProject,
);
} else {
runner = ColdRunner(
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 4edaf21..507ea45 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -13,7 +13,6 @@
import '../device.dart';
import '../globals.dart';
import '../ios/mac.dart';
-import '../project.dart';
import '../resident_runner.dart';
import '../run_cold.dart';
import '../run_hot.dart';
@@ -281,7 +280,6 @@
// Enable hot mode by default if `--no-hot` was not passed and we are in
// debug mode.
final bool hotMode = shouldUseHotMode();
- final FlutterProject flutterProject = await FlutterProject.current();
writePidFile(argResults['pid-file']);
@@ -391,7 +389,6 @@
saveCompilationTrace: argResults['train'],
stayResident: stayResident,
ipv6: ipv6,
- flutterProject: flutterProject,
);
} else {
runner = ColdRunner(
diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart
index 630e323..01ee9d4 100644
--- a/packages/flutter_tools/lib/src/compile.dart
+++ b/packages/flutter_tools/lib/src/compile.dart
@@ -354,7 +354,7 @@
) : super(completer);
String mainPath;
- List<String> invalidatedFiles;
+ List<Uri> invalidatedFiles;
String outputPath;
String packagesFilePath;
@@ -450,7 +450,7 @@
/// null is returned.
Future<CompilerOutput> recompile(
String mainPath,
- List<String> invalidatedFiles, {
+ List<Uri> invalidatedFiles, {
@required String outputPath,
String packagesFilePath,
}) async {
@@ -497,9 +497,9 @@
: '';
_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)}');
+ for (Uri fileUri in request.invalidatedFiles) {
+ _server.stdin.writeln(_mapFileUri(fileUri.toString(), packageUriMapper));
+ printTrace('<- ${_mapFileUri(fileUri.toString(), packageUriMapper)}');
}
_server.stdin.writeln(inputKey);
printTrace('<- $inputKey');
diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart
index ea63e73..b4c8293 100644
--- a/packages/flutter_tools/lib/src/devfs.dart
+++ b/packages/flutter_tools/lib/src/devfs.dart
@@ -387,6 +387,8 @@
String _packagesFilePath;
final Map<Uri, DevFSContent> _entries = <Uri, DevFSContent>{};
final Set<String> assetPathsToEvict = <String>{};
+ List<Uri> sources = <Uri>[];
+ DateTime lastCompiled;
Uri _baseUri;
Uri get baseUri => _baseUri;
@@ -439,7 +441,7 @@
bool fullRestart = false,
String projectRootPath,
@required String pathToReload,
- @required List<String> invalidatedFiles,
+ @required List<Uri> invalidatedFiles,
}) async {
assert(trackWidgetCreation != null);
assert(generator != null);
@@ -478,6 +480,7 @@
generator.reset();
}
printTrace('Compiling dart to kernel with ${invalidatedFiles.length} updated files');
+ lastCompiled = DateTime.now();
final CompilerOutput compilerOutput = await generator.recompile(
mainPath,
invalidatedFiles,
@@ -485,6 +488,7 @@
packagesFilePath : _packagesFilePath,
);
// list of sources that needs to be monitored are in [compilerOutput.sources]
+ sources = compilerOutput.sources;
//
// Don't send full kernel file that would overwrite what VM already
// started loading from.
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 608a20f..15ab883 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -286,7 +286,6 @@
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
});
diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
index 9a13ea6..e5ed42e 100644
--- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
@@ -188,7 +188,6 @@
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) => Future<void>.error('unimplemented');
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index 2959a2e..8903b5a 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -235,7 +235,6 @@
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) async {
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index f521871..82f2ecf 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -297,7 +297,6 @@
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) async {
diff --git a/packages/flutter_tools/lib/src/linux/linux_device.dart b/packages/flutter_tools/lib/src/linux/linux_device.dart
index 06c5301..fb88fbf 100644
--- a/packages/flutter_tools/lib/src/linux/linux_device.dart
+++ b/packages/flutter_tools/lib/src/linux/linux_device.dart
@@ -57,7 +57,6 @@
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) {
diff --git a/packages/flutter_tools/lib/src/macos/macos_device.dart b/packages/flutter_tools/lib/src/macos/macos_device.dart
index 8e82cb7..74c11f8 100644
--- a/packages/flutter_tools/lib/src/macos/macos_device.dart
+++ b/packages/flutter_tools/lib/src/macos/macos_device.dart
@@ -63,7 +63,6 @@
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) async {
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 726562d..4cb6e43 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -345,7 +345,6 @@
startEchoingDeviceLog();
// Start the application.
- final bool hasDirtyDependencies = hotRunner.hasDirtyDependencies(this);
final Future<LaunchResult> futureResult = device.startApp(
package,
mainPath: hotRunner.mainPath,
@@ -353,7 +352,6 @@
platformArgs: platformArgs,
route: route,
prebuiltApplication: prebuiltMode,
- applicationNeedsRebuild: shouldBuild || hasDirtyDependencies,
usesTerminalUi: hotRunner.usesTerminalUI,
ipv6: hotRunner.ipv6,
);
@@ -409,7 +407,6 @@
startEchoingDeviceLog();
- final bool hasDirtyDependencies = coldRunner.hasDirtyDependencies(this);
final LaunchResult result = await device.startApp(
package,
mainPath: coldRunner.mainPath,
@@ -417,7 +414,6 @@
platformArgs: platformArgs,
route: route,
prebuiltApplication: prebuiltMode,
- applicationNeedsRebuild: shouldBuild || hasDirtyDependencies,
usesTerminalUi: coldRunner.usesTerminalUI,
ipv6: coldRunner.ipv6,
);
@@ -445,7 +441,7 @@
bool fullRestart = false,
String projectRootPath,
String pathToReload,
- @required List<String> invalidatedFiles,
+ @required List<Uri> invalidatedFiles,
}) async {
final Status devFSStatus = logger.startProgress(
'Syncing files to device ${device.name}...',
@@ -942,26 +938,6 @@
return exitCode;
}
- bool hasDirtyDependencies(FlutterDevice device) {
- if (device.package.packagesFile == null || !device.package.packagesFile.existsSync()) {
- return true;
- }
- // why is this sometimes an APK.
- if (!device.package.packagesFile.path.contains('.packages')) {
- return true;
- }
- // Leave pubspec null to check all dependencies.
- final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(device.package.packagesFile.path, null);
- projectFileInvalidator.findInvalidated();
- final int lastBuildTime = device.package.packagesFile.statSync().modified.millisecondsSinceEpoch;
- for (int updateTime in projectFileInvalidator.updateTime.values) {
- if (updateTime > lastBuildTime) {
- return true;
- }
- }
- return false;
- }
-
Future<void> preStop() async { }
Future<void> stopApp() async {
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index 31de4bd..485ede2 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -7,7 +7,6 @@
import 'package:json_rpc_2/error_code.dart' as rpc_error_code;
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
import 'package:meta/meta.dart';
-import 'package:yaml/yaml.dart';
import 'base/common.dart';
import 'base/context.dart';
@@ -19,11 +18,9 @@
import 'build_info.dart';
import 'compile.dart';
import 'convert.dart';
-import 'dart/package_map.dart';
import 'devfs.dart';
import 'device.dart';
import 'globals.dart';
-import 'project.dart';
import 'resident_runner.dart';
import 'usage.dart';
import 'vmservice.dart';
@@ -70,7 +67,6 @@
bool saveCompilationTrace = false,
bool stayResident = true,
bool ipv6 = false,
- FlutterProject flutterProject,
}) : super(devices,
target: target,
debuggingOptions: debuggingOptions,
@@ -79,19 +75,13 @@
packagesFilePath: packagesFilePath,
saveCompilationTrace: saveCompilationTrace,
stayResident: stayResident,
- ipv6: ipv6) {
- fileInvalidator = ProjectFileInvalidator(
- packagesFilePath ?? fs.path.absolute(PackageMap.globalPackagesPath),
- flutterProject,
- );
- }
+ ipv6: ipv6);
final bool benchmarkMode;
final File applicationBinary;
final bool hostIsIde;
bool _didAttach = false;
final String dillOutputPath;
- ProjectFileInvalidator fileInvalidator;
final Map<String, List<int>> benchmarkData = <String, List<int>>{};
// The initial launch is from a snapshot.
@@ -322,7 +312,12 @@
if (result != 0)
return UpdateFSReport(success: false);
}
- final List<String> invalidatedFiles = fileInvalidator.findInvalidated();
+
+ // Picking up first device's compiler as a source of truth - compilers
+ // for all devices should be in sync.
+ final List<Uri> invalidatedFiles = ProjectFileInvalidator.findInvalidated(
+ lastCompiled: flutterDevices[0].devFS.lastCompiled,
+ urisToMonitor: flutterDevices[0].devFS.sources);
final UpdateFSReport results = UpdateFSReport(success: true);
for (FlutterDevice device in flutterDevices) {
results.incorporateResults(await device.updateDevFS(
@@ -941,104 +936,31 @@
}
class ProjectFileInvalidator {
- ProjectFileInvalidator(this._packagesPath, this._flutterProject) {
- final File packagesFile = fs.file(_packagesPath);
- if (packagesFile.existsSync()) {
- _packagesUpdateTime = packagesFile.statSync().modified.millisecondsSinceEpoch;
- _packageMap = PackageMap(_packagesPath).map;
- } else {
- _packagesUpdateTime = -1;
- _packageMap = const <String, Uri>{};
- }
- _computePackageMap(_packageMap, _flutterProject);
- }
-
- // Used to avoid watching pubspec directories. This will not change even with pub upgrade,
- // because that actually switches the directory and requires a corresponding
- // update to .packages
static const String _pubCachePathLinuxAndWindows = '.pub-cache';
static const String _pubCachePathWindows = 'Pub/Cache';
- Map<String, Uri> _packageMap;
- final String _packagesPath;
- final FlutterProject _flutterProject;
- final Map<String, int> _updateTime = <String, int>{};
- int _packagesUpdateTime;
-
- Map<String, int> get updateTime => _updateTime;
-
- @visibleForTesting
- Map<String, Uri> get packageMap => _packageMap;
-
- static void _computePackageMap(Map<String, Uri> packageMap, FlutterProject flutterProject) {
- if (flutterProject != null && flutterProject.pubspecFile.existsSync()) {
- try {
- final YamlMap pubspec = loadYamlDocument(flutterProject.pubspecFile.readAsStringSync()).contents;
- final YamlMap dependencies = pubspec['dependencies'];
- final Set<String> relevantDependencies = Set<String>.from(dependencies.keys);
- // Remove any packages which were tagged as dev dependenices,
- // But don't remove the app itself!
- for (String packageName in packageMap.keys.toList()) {
- if (!relevantDependencies.contains(packageName) && packageName != flutterProject.manifest.appName) {
- packageMap.remove(packageName);
- continue;
- }
- }
- } catch (err) {
- // If we detect a pubspec formatting problem, fallback to the packages file.
+ static List<Uri> findInvalidated({@required DateTime lastCompiled,
+ @required List<Uri> urisToMonitor}) {
+ final List<Uri> invalidatedFiles = <Uri>[];
+ int scanned = 0;
+ final Stopwatch stopwatch = Stopwatch()..start();
+ for (Uri uri in urisToMonitor) {
+ if ((platform.isWindows && uri.path.contains(_pubCachePathWindows))
+ || uri.path.contains(_pubCachePathLinuxAndWindows)) {
+ // Don't watch pub cache directories to speed things up a little.
+ continue;
+ }
+ final DateTime updatedAt = fs.statSync(
+ uri.toFilePath(windows: platform.isWindows)).modified;
+ scanned++;
+ if (updatedAt == null) {
+ continue;
+ }
+ if (updatedAt.millisecondsSinceEpoch > lastCompiled.millisecondsSinceEpoch) {
+ invalidatedFiles.add(uri);
}
}
- // Remove any packages which are derived from the pub cache.
- for (String packageName in packageMap.keys.toList()) {
- final String path = packageMap[packageName].path;
- if ((platform.isWindows && path.contains(_pubCachePathWindows))
- || path.contains(_pubCachePathLinuxAndWindows)) {
- packageMap.remove(packageName);
- }
- }
- }
-
- List<String> findInvalidated() {
- final File packagesFile = fs.file(_packagesPath);
- if (packagesFile.existsSync()) {
- final int newPackagesUpdateTime = packagesFile.statSync().modified.millisecondsSinceEpoch;
- // Hot reloading with an updated package will often times kill a non-trivial
- // appliction. This _might_ work, given certain application size and package
- // constraints, so instead of exiting we print a warning so that the user has
- // some hint on what went wrong.
- if (newPackagesUpdateTime > _packagesUpdateTime) {
- printError('Warning: updated dependencies detected. The Flutter application will require a restart to safely use new packages.');
- }
- _packagesUpdateTime = newPackagesUpdateTime;
- }
- final List<String> invalidatedFiles = <String>[];
- for (String packageName in _packageMap.keys) {
- final Uri packageUri =_packageMap[packageName];
- _scanDirectory(packageUri, invalidatedFiles);
- }
+ printTrace('Scanned through $scanned files in ${stopwatch.elapsedMilliseconds}ms');
return invalidatedFiles;
}
-
- void _scanDirectory(Uri path, List<String> invalidatedFiles) {
- final Directory directory = fs.directory(path);
- if (!directory.existsSync()) {
- return;
- }
- for (FileSystemEntity entity in directory.listSync(recursive: true)) {
- if (entity.path.endsWith('.dart')) {
- final int oldUpdatedAt = _updateTime[entity.path];
- final int updatedAt = fs.statSync(entity.path).modified.millisecondsSinceEpoch;
- if (oldUpdatedAt == null || updatedAt > oldUpdatedAt) {
- // On windows convert to file uri in expected format.
- if (platform.isWindows) {
- final Uri uri = Uri.file(entity.path, windows: platform.isWindows);
- invalidatedFiles.add(uri.toString());
- } else {
- invalidatedFiles.add(entity.path);
- }
- }
- _updateTime[entity.path] = updatedAt;
- }
- }
- }
-}
+}
\ No newline at end of file
diff --git a/packages/flutter_tools/lib/src/test/flutter_platform.dart b/packages/flutter_tools/lib/src/test/flutter_platform.dart
index d265aac..b50aa652 100644
--- a/packages/flutter_tools/lib/src/test/flutter_platform.dart
+++ b/packages/flutter_tools/lib/src/test/flutter_platform.dart
@@ -311,7 +311,7 @@
suppressOutput = false;
final CompilerOutput compilerOutput = await compiler.recompile(
request.path,
- <String>[request.path],
+ <Uri>[Uri.parse(request.path)],
outputPath: outputDill.path,
);
final String outputPath = compilerOutput?.outputFilename;
diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
index bfa2aeb..d5f5c22 100644
--- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart
+++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
@@ -96,7 +96,6 @@
@required DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) async {
diff --git a/packages/flutter_tools/lib/src/web/web_device.dart b/packages/flutter_tools/lib/src/web/web_device.dart
index 7c23bf4..4b34393 100644
--- a/packages/flutter_tools/lib/src/web/web_device.dart
+++ b/packages/flutter_tools/lib/src/web/web_device.dart
@@ -100,7 +100,6 @@
DebuggingOptions debuggingOptions,
Map<String, Object> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) async {
diff --git a/packages/flutter_tools/lib/src/windows/windows_device.dart b/packages/flutter_tools/lib/src/windows/windows_device.dart
index efe7783..c019581 100644
--- a/packages/flutter_tools/lib/src/windows/windows_device.dart
+++ b/packages/flutter_tools/lib/src/windows/windows_device.dart
@@ -57,7 +57,6 @@
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
bool prebuiltApplication = false,
- bool applicationNeedsRebuild = false,
bool usesTerminalUi = true,
bool ipv6 = false,
}) {