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, }) {
diff --git a/packages/flutter_tools/test/compile_test.dart b/packages/flutter_tools/test/compile_test.dart index 0d920bd..b93f86f 100644 --- a/packages/flutter_tools/test/compile_test.dart +++ b/packages/flutter_tools/test/compile_test.dart
@@ -517,7 +517,7 @@ }); final CompilerOutput output = await generator.recompile( null /* mainPath */, - <String>['/path/to/main.dart'], + <Uri>[Uri.parse('/path/to/main.dart')], outputPath: '/build/', ); expect(output.outputFilename, equals('/path/to/main.dart.dill'));
diff --git a/packages/flutter_tools/test/devfs_test.dart b/packages/flutter_tools/test/devfs_test.dart index 653442b..c27094e 100644 --- a/packages/flutter_tools/test/devfs_test.dart +++ b/packages/flutter_tools/test/devfs_test.dart
@@ -123,7 +123,7 @@ generator: residentCompiler, pathToReload: 'lib/foo.txt.dill', trackWidgetCreation: false, - invalidatedFiles: <String>[], + invalidatedFiles: <Uri>[], ); vmService.expectMessages(<String>[ 'writeFile test lib/foo.txt.dill',
diff --git a/packages/flutter_tools/test/hot_test.dart b/packages/flutter_tools/test/hot_test.dart index 11526d5..8dcc8ad 100644 --- a/packages/flutter_tools/test/hot_test.dart +++ b/packages/flutter_tools/test/hot_test.dart
@@ -116,6 +116,8 @@ UpdateFSReport(success: true, syncedBytes: 1000, invalidatedSourcesCount: 1))); when(mockDevFs.assetPathsToEvict).thenReturn(<String>{}); when(mockDevFs.baseUri).thenReturn(Uri.file('test')); + when(mockDevFs.sources).thenReturn(<Uri>[Uri.file('test')]); + when(mockDevFs.lastCompiled).thenReturn(DateTime.now()); setUp(() { mockArtifacts = MockLocalEngineArtifacts();
diff --git a/packages/flutter_tools/test/project_file_invalidator_test.dart b/packages/flutter_tools/test/project_file_invalidator_test.dart index 859bc70..6beff73 100644 --- a/packages/flutter_tools/test/project_file_invalidator_test.dart +++ b/packages/flutter_tools/test/project_file_invalidator_test.dart
@@ -4,231 +4,30 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/base/platform.dart'; -import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/run_hot.dart'; -import 'package:mockito/mockito.dart'; import 'src/common.dart'; import 'src/context.dart'; void main() { - final Platform windowsPlatform = MockPlatform(); - final Platform notWindowsPlatform = MockPlatform(); - final BufferLogger bufferLogger = BufferLogger(); - when(windowsPlatform.isWindows).thenReturn(true); - when(notWindowsPlatform.isWindows).thenReturn(false); - - group('ProjectFileInvalidator linux/mac', () { + group('ProjectFileInvalidator', () { final MemoryFileSystem memoryFileSystem = MemoryFileSystem(); - final File packagesFile = memoryFileSystem.file('.packages') - ..createSync() - ..writeAsStringSync(r''' -foo:file:///foo/lib/ -bar:file:///.pub-cache/bar/lib/ -baz:file:///baz/lib/ -test_package:file:///lib/ -'''); - final File pubspecFile = memoryFileSystem.file('pubspec.yaml') - ..createSync() - ..writeAsStringSync(r''' -name: test_package - -dependencies: - foo: any - bar: - -dev_dependencies: - baz: any -'''); - final File mainFile = memoryFileSystem.file('lib/main.dart') - ..createSync(recursive: true) - ..writeAsStringSync(r''' -void main() {} -'''); - final File fooFile = memoryFileSystem.file('foo/lib/foo.dart') - ..createSync(recursive: true) - ..writeAsStringSync(''); - memoryFileSystem.file('bar/lib/bar.dart') - ..createSync(recursive: true) - ..writeAsStringSync(''); - final File bazFile = memoryFileSystem.file('baz/lib/baz.dart') - ..createSync(recursive: true) - ..writeAsStringSync(''); - - testUsingContext('No .packages, no pubspec', () async { - // Instead of setting up multiple filesystems, passing a .packages file which does not exist. - final ProjectFileInvalidator invalidator = ProjectFileInvalidator('.packages-wrong', null); - invalidator.findInvalidated(); - expect(invalidator.packageMap, isEmpty); - expect(invalidator.updateTime, isEmpty); + testUsingContext('Empty project', () async { + expect( + ProjectFileInvalidator.findInvalidated(lastCompiled: DateTime.now(), urisToMonitor: <Uri>[]), + isEmpty); }, overrides: <Type, Generator>{ FileSystem: () => memoryFileSystem, - Platform: () => notWindowsPlatform, }); - testUsingContext('.packages only', () async { - final ProjectFileInvalidator invalidator = ProjectFileInvalidator(packagesFile.path, null); - invalidator.findInvalidated(); - expect(invalidator.packageMap, <String, Uri>{ - 'foo': Uri.parse('file:///foo/lib/'), - // Excluded because it is in pub cache. - // 'bar': Uri.parse('file:///.pub-cache/bar/lib/'), - 'baz': Uri.parse('file:///baz/lib/'), - 'test_package': Uri.parse('file:///lib/'), - }); - expect(invalidator.updateTime, <String, int>{ - '/baz/lib/baz.dart': bazFile.statSync().modified.millisecondsSinceEpoch, - '/lib/main.dart': mainFile.statSync().modified.millisecondsSinceEpoch, - '/foo/lib/foo.dart': fooFile.statSync().modified.millisecondsSinceEpoch, - }); + testUsingContext('Non-existent files are ignored', () async { + expect( + ProjectFileInvalidator.findInvalidated( + lastCompiled: DateTime.now(), + urisToMonitor: <Uri>[Uri.parse('/not-there-anymore')]), + isEmpty); }, overrides: <Type, Generator>{ FileSystem: () => memoryFileSystem, - Platform: () => notWindowsPlatform, - }); - - testUsingContext('.packages and pubspec', () async { - final FlutterProject flutterProject = await FlutterProject.fromDirectory(pubspecFile.parent); - final ProjectFileInvalidator invalidator = ProjectFileInvalidator(packagesFile.path, flutterProject); - invalidator.findInvalidated(); - expect(invalidator.packageMap, <String, Uri>{ - 'foo': Uri.parse('file:///foo/lib/'), - // Excluded because it is in pub cache. - // 'bar': Uri.parse('file:///.pub-cache/bar/lib/'), - // Excluded because it is a dev dependency/ - // 'baz': Uri.parse('file:///baz/lib/'), - 'test_package': Uri.parse('file:///lib/'), - }); - expect(invalidator.updateTime, <String, int>{ - '/foo/lib/foo.dart': fooFile.statSync().modified.millisecondsSinceEpoch, - '/lib/main.dart': mainFile.statSync().modified.millisecondsSinceEpoch, - }); - expect(invalidator.findInvalidated(), isEmpty); - - // Invalidate main.dart. - mainFile.writeAsStringSync('void main() { }'); - expect(invalidator.findInvalidated(), <String>['/lib/main.dart']); - }, overrides: <Type, Generator>{ - FileSystem: () => memoryFileSystem, - Platform: () => notWindowsPlatform, - }); - - testUsingContext('update to .packages triggers warning', () async { - final FlutterProject flutterProject = await FlutterProject.fromDirectory(pubspecFile.parent); - final ProjectFileInvalidator invalidator = ProjectFileInvalidator(packagesFile.path, flutterProject); - invalidator.findInvalidated(); - packagesFile.writeAsStringSync(r''' -foo:file:///foo/lib/ -bar:file:///.pub-cache/bar/lib/ -baz:file:///baz/lib/ -new_dep:file:///new_dep/lib/ -test_package:file:///lib/ -'''); - invalidator.findInvalidated(); - expect(bufferLogger.errorText, 'Warning: updated dependencies detected. The Flutter application will require a restart to safely use new packages.\n'); - }, overrides: <Type, Generator>{ - FileSystem: () => memoryFileSystem, - Platform: () => notWindowsPlatform, - Logger: () => bufferLogger, - }); - }); - - group('ProjectFileInvalidator windows', () { - final MemoryFileSystem memoryFileSystem = MemoryFileSystem(style: FileSystemStyle.windows); - // On windows .packages still contains file Uris, albeit ones with the Drive prefix. - final File packagesFile = memoryFileSystem.file(r'C:\.packages') - ..createSync() - ..writeAsStringSync(r''' -foo:file:///C:/foo/lib/ -bar:file:///C:/Pub/Cache/bar/lib/ -baz:file:///C:/baz/lib/ -test_package:file:///C:/lib/ -'''); - memoryFileSystem.file(r'C:\pubspec.yaml') - ..createSync() - ..writeAsStringSync(r''' -name: test_package - -dependencies: - foo: any - bar: - -dev_dependencies: - baz: any -'''); - final File mainFile = memoryFileSystem.file(r'C:\lib\main.dart') - ..createSync(recursive: true) - ..writeAsStringSync(r''' -void main() {} -'''); - final File fooFile = memoryFileSystem.file(r'C:\foo\lib\foo.dart') - ..createSync(recursive: true) - ..writeAsStringSync(''); - memoryFileSystem.file(r'C:\bar\lib\bar.dart') - ..createSync(recursive: true) - ..writeAsStringSync(''); - final File bazFile = memoryFileSystem.file(r'C:\baz\lib\baz.dart') - ..createSync(recursive: true) - ..writeAsStringSync(''); - - testUsingContext('No .packages, no pubspec', () async { - // Instead of setting up multiple filesystems, passing a .packages file which does not exist. - final ProjectFileInvalidator invalidator = ProjectFileInvalidator('.packages-wrong', null); - invalidator.findInvalidated(); - expect(invalidator.packageMap, isEmpty); - expect(invalidator.updateTime, isEmpty); - }, overrides: <Type, Generator>{ - FileSystem: () => memoryFileSystem, - Platform: () => windowsPlatform, - }); - - testUsingContext('.packages only', () async { - final ProjectFileInvalidator invalidator = ProjectFileInvalidator(packagesFile.path, null); - invalidator.findInvalidated(); - expect(invalidator.packageMap, <String, Uri>{ - 'foo': Uri.file(r'C:\foo\lib\', windows: true), - // Excluded because it is in pub cache. - // 'bar': Uri.parse('file:///Pub/Cache/bar/lib/'), - 'baz': Uri.file(r'C:\baz\lib\', windows: true), - 'test_package': Uri.file(r'C:\lib\', windows: true), - }); - expect(invalidator.updateTime, <String, int>{ - r'C:\baz\lib\baz.dart': bazFile.statSync().modified.millisecondsSinceEpoch, - r'C:\lib\main.dart': mainFile.statSync().modified.millisecondsSinceEpoch, - r'C:\foo\lib\foo.dart': fooFile.statSync().modified.millisecondsSinceEpoch, - }); - }, overrides: <Type, Generator>{ - FileSystem: () => memoryFileSystem, - Platform: () => windowsPlatform, - }); - - testUsingContext('.packages and pubspec', () async { - final FlutterProject flutterProject = await FlutterProject.fromDirectory(fs.directory(r'C:\')); - final ProjectFileInvalidator invalidator = ProjectFileInvalidator(packagesFile.path, flutterProject); - invalidator.findInvalidated(); - expect(invalidator.packageMap, <String, Uri>{ - 'foo': Uri.file(r'C:\foo\lib\', windows: true), - // Excluded because it is in pub cache. - // 'bar': Uri.parse('file:///C:/Pub/Cache/bar/lib/'), - // Excluded because it is a dev dependency/ - // 'baz': Uri.parse('file:///baz/lib/'), - 'test_package': Uri.file(r'C:\lib\', windows: true), - }); - expect(invalidator.updateTime, <String, int>{ - r'C:\lib\main.dart': mainFile.statSync().modified.millisecondsSinceEpoch, - r'C:\foo\lib\foo.dart': fooFile.statSync().modified.millisecondsSinceEpoch, - }); - expect(invalidator.findInvalidated(), isEmpty); - - // Invalidate main.dart. - mainFile.writeAsStringSync('void main() { }'); - expect(invalidator.findInvalidated(), <String>['file:///C:/lib/main.dart']); - }, overrides: <Type, Generator>{ - FileSystem: () => memoryFileSystem, - Platform: () => windowsPlatform, }); }); } - -class MockPlatform extends Mock implements Platform {}
diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart index c47b4ff..72410aa 100644 --- a/packages/flutter_tools/test/src/mocks.dart +++ b/packages/flutter_tools/test/src/mocks.dart
@@ -487,7 +487,7 @@ return null; } @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 { fs.file(outputPath).createSync(recursive: true); fs.file(outputPath).writeAsStringSync('compiled_kernel_output'); return CompilerOutput(outputPath, 0, <Uri>[]);