Improve hot reload performance (#28152)
diff --git a/packages/flutter_tools/bin/fuchsia_attach.dart b/packages/flutter_tools/bin/fuchsia_attach.dart
index eb91c2d..b752efc 100644
--- a/packages/flutter_tools/bin/fuchsia_attach.dart
+++ b/packages/flutter_tools/bin/fuchsia_attach.dart
@@ -15,7 +15,6 @@
import 'package:flutter_tools/src/commands/attach.dart';
import 'package:flutter_tools/src/commands/doctor.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
-import 'package:flutter_tools/src/run_hot.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
final ArgParser parser = ArgParser()
@@ -100,8 +99,7 @@
platformKernelDill: platformKernelDill,
flutterPatchedSdk: flutterPatchedSdk,
),
- HotRunnerConfig: () => HotRunnerConfig()..computeDartDependencies = false,
- },
+ }
);
}
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart
index eb3c4c0..a485772 100644
--- a/packages/flutter_tools/lib/src/commands/attach.dart
+++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -18,6 +18,7 @@
import '../globals.dart';
import '../ios/devices.dart';
import '../ios/simulators.dart';
+import '../project.dart';
import '../protocol_discovery.dart';
import '../resident_runner.dart';
import '../run_cold.dart';
@@ -129,6 +130,7 @@
Future<FlutterCommandResult> runCommand() async {
final String ipv4Loopback = InternetAddress.loopbackIPv4.address;
final String ipv6Loopback = InternetAddress.loopbackIPv6.address;
+ final FlutterProject flutterProject = await FlutterProject.current();
Cache.releaseLockEarly();
@@ -228,6 +230,7 @@
projectRootPath: argResults['project-root'],
dillOutputPath: argResults['output-dill'],
ipv6: usesIpv6,
+ flutterProject: flutterProject,
)
: ColdRunner(
flutterDevices,
@@ -289,6 +292,7 @@
String dillOutputPath,
bool stayResident = true,
bool ipv6 = false,
+ FlutterProject flutterProject,
}) => HotRunner(
devices,
target: target,
@@ -302,6 +306,7 @@
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 074caae..2f93ae5 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -19,6 +19,7 @@
import '../device.dart';
import '../emulator.dart';
import '../globals.dart';
+import '../project.dart';
import '../resident_runner.dart';
import '../run_cold.dart';
import '../run_hot.dart';
@@ -341,6 +342,7 @@
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;
@@ -368,6 +370,7 @@
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 507ea45..4edaf21 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -13,6 +13,7 @@
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';
@@ -280,6 +281,7 @@
// 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']);
@@ -389,6 +391,7 @@
saveCompilationTrace: argResults['train'],
stayResident: stayResident,
ipv6: ipv6,
+ flutterProject: flutterProject,
);
} else {
runner = ColdRunner(
diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart
index 254826a..a019bb8 100644
--- a/packages/flutter_tools/lib/src/commands/update_packages.dart
+++ b/packages/flutter_tools/lib/src/commands/update_packages.dart
@@ -1093,7 +1093,7 @@
/// Generates the File object for the pubspec.yaml file of a given Directory.
File _pubspecFor(Directory directory) {
- return fs.file('${directory.path}/pubspec.yaml');
+ return fs.file(fs.path.join(directory.path, 'pubspec.yaml'));
}
/// Generates the source of a fake pubspec.yaml file given a list of
diff --git a/packages/flutter_tools/lib/src/dart/dependencies.dart b/packages/flutter_tools/lib/src/dart/dependencies.dart
deleted file mode 100644
index 378081a..0000000
--- a/packages/flutter_tools/lib/src/dart/dependencies.dart
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// TODO(dnfield): This will be removed when @jonahwilliams' work on build lands
-// ignore: deprecated_member_use
-import 'package:analyzer/analyzer.dart' as analyzer;
-
-import '../base/file_system.dart';
-import '../dart/package_map.dart';
-
-// List of flutter specific environment configurations.
-// See https://github.com/munificent/dep-interface-libraries/blob/master/Proposal.md
-// We will populate this list as required. Potentially, all of dart:* libraries
-// supported by flutter would end up here.
-final List<String> _configurationConstants = <String>['dart.library.io'];
-
-String _dottedNameToString(analyzer.DottedName dottedName) {
- String result = '';
- for (analyzer.SimpleIdentifier identifier in dottedName.components) {
- if (result.isEmpty) {
- result += identifier.token.lexeme;
- } else {
- result += '.' + identifier.token.lexeme;
- }
- }
- return result;
-}
-
-class DartDependencySetBuilder {
- DartDependencySetBuilder(String mainScriptPath, String packagesFilePath)
- : _mainScriptPath = canonicalizePath(mainScriptPath),
- _mainScriptUri = fs.path.toUri(mainScriptPath),
- _packagesFilePath = canonicalizePath(packagesFilePath);
-
- final String _mainScriptPath;
- final String _packagesFilePath;
-
- final Uri _mainScriptUri;
-
- Set<String> build() {
- final List<String> dependencies = <String>[_mainScriptPath, _packagesFilePath];
- final List<Uri> toProcess = <Uri>[_mainScriptUri];
- final PackageMap packageMap = PackageMap(_packagesFilePath);
-
- while (toProcess.isNotEmpty) {
- final Uri currentUri = toProcess.removeLast();
- final analyzer.CompilationUnit unit = _parse(currentUri.toFilePath());
- for (analyzer.Directive directive in unit.directives) {
- if (!(directive is analyzer.UriBasedDirective))
- continue;
-
- String uriAsString;
- if (directive is analyzer.NamespaceDirective) {
- final analyzer.NamespaceDirective namespaceDirective = directive;
- // If the directive is a conditional import directive, we should
- // select the imported uri based on the condition.
- for (analyzer.Configuration configuration in namespaceDirective.configurations) {
- if (_configurationConstants.contains(_dottedNameToString(configuration.name))) {
- uriAsString = configuration.uri.stringValue;
- break;
- }
- }
- }
- if (uriAsString == null) {
- final analyzer.UriBasedDirective uriBasedDirective = directive;
- uriAsString = uriBasedDirective.uri.stringValue;
- }
-
- Uri uri;
- try {
- uri = Uri.parse(uriAsString);
- } on FormatException {
- throw DartDependencyException('Unable to parse URI: $uriAsString');
- }
- Uri resolvedUri = analyzer.resolveRelativeUri(currentUri, uri);
- if (resolvedUri.scheme.startsWith('dart'))
- continue;
- if (resolvedUri.scheme == 'package') {
- final Uri newResolvedUri = packageMap.uriForPackage(resolvedUri);
- if (newResolvedUri == null) {
- throw DartDependencyException(
- 'The following Dart file:\n'
- ' ${currentUri.toFilePath()}\n'
- '...refers, in an import, to the following library:\n'
- ' $resolvedUri\n'
- 'That library is in a package that is not known. Maybe you forgot to '
- 'mention it in your pubspec.yaml file?'
- );
- }
- resolvedUri = newResolvedUri;
- }
- final String path = canonicalizePath(resolvedUri.toFilePath());
- if (!dependencies.contains(path)) {
- if (!fs.isFileSync(path)) {
- throw DartDependencyException(
- 'The following Dart file:\n'
- ' ${currentUri.toFilePath()}\n'
- '...refers, in an import, to the following library:\n'
- ' $path\n'
- 'Unfortunately, that library does not appear to exist on your file system.'
- );
- }
- dependencies.add(path);
- toProcess.add(resolvedUri);
- }
- }
- }
- return dependencies.toSet();
- }
-
- analyzer.CompilationUnit _parse(String path) {
- String body;
- try {
- body = fs.file(path).readAsStringSync();
- } on FileSystemException catch (error) {
- throw DartDependencyException(
- 'Could not read "$path" when determining Dart dependencies.',
- error,
- );
- }
- try {
- return analyzer.parseDirectives(body, name: path);
- } on analyzer.AnalyzerError catch (error) {
- throw DartDependencyException(
- 'When trying to parse this Dart file to find its dependencies:\n'
- ' $path\n'
- '...the analyzer failed with the following error:\n'
- ' ${error.toString().trimRight()}',
- error,
- );
- } on analyzer.AnalyzerErrorGroup catch (error) {
- throw DartDependencyException(
- 'When trying to parse this Dart file to find its dependencies:\n'
- ' $path\n'
- '...the analyzer failed with the following error:\n'
- ' ${error.toString().trimRight()}',
- error,
- );
- }
- }
-}
-
-class DartDependencyException implements Exception {
- DartDependencyException(this.message, [this.parent]);
- final String message;
- final Exception parent;
- @override
- String toString() => message;
-}
diff --git a/packages/flutter_tools/lib/src/dependency_checker.dart b/packages/flutter_tools/lib/src/dependency_checker.dart
deleted file mode 100644
index 8f0aea7..0000000
--- a/packages/flutter_tools/lib/src/dependency_checker.dart
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'asset.dart';
-import 'base/file_system.dart';
-import 'dart/dependencies.dart';
-import 'globals.dart';
-
-class DependencyChecker {
- DependencyChecker(this.builder, this.assets);
-
- final DartDependencySetBuilder builder;
- final Set<String> _dependencies = <String>{};
- final AssetBundle assets;
-
- /// Returns [true] if any components have been modified after [threshold] or
- /// if it cannot be determined.
- bool check(DateTime threshold) {
- _dependencies.clear();
- // Build the set of Dart dependencies.
- try {
- _dependencies.addAll(builder.build());
- } catch (e, st) {
- printTrace('DependencyChecker: error determining .dart dependencies:\n$e\n$st');
- return true;
- }
- // TODO(johnmccutchan): Extract dependencies from the AssetBundle too.
-
- // Check all dependency modification times.
- for (String path in _dependencies) {
- final File file = fs.file(path);
- final FileStat stat = file.statSync();
- if (stat.type == FileSystemEntityType.notFound) {
- printTrace('DependencyChecker: Error stating $path.');
- return true;
- }
- if (stat.modified.isAfter(threshold)) {
- printTrace('DependencyChecker: $path is newer than $threshold');
- return true;
- }
- }
- printTrace('DependencyChecker: nothing is modified after $threshold.');
- return false;
- }
-}
diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart
index 7940e8b..407a51b 100644
--- a/packages/flutter_tools/lib/src/devfs.dart
+++ b/packages/flutter_tools/lib/src/devfs.dart
@@ -30,8 +30,6 @@
/// Common superclass for content copied to the device.
abstract class DevFSContent {
- bool _exists = true;
-
/// Return true if this is the first time this method is called
/// or if the entry has been modified since this method was last called.
bool get isModified;
@@ -59,13 +57,6 @@
class DevFSFileContent extends DevFSContent {
DevFSFileContent(this.file);
- static DevFSFileContent clone(DevFSFileContent fsFileContent) {
- final DevFSFileContent newFsFileContent = DevFSFileContent(fsFileContent.file);
- newFsFileContent._linkTarget = fsFileContent._linkTarget;
- newFsFileContent._fileStat = fsFileContent._fileStat;
- return newFsFileContent;
- }
-
final FileSystemEntity file;
FileSystemEntity _linkTarget;
FileStat _fileStat;
@@ -218,7 +209,6 @@
Future<Uri> create(String fsName);
Future<dynamic> destroy(String fsName);
Future<dynamic> writeFile(String fsName, Uri deviceUri, DevFSContent content);
- Future<dynamic> deleteFile(String fsName, Uri deviceUri);
}
/// An implementation of [DevFSOperations] that speaks to the
@@ -261,11 +251,6 @@
printTrace('DevFS: Failed to write $deviceUri: $error');
}
}
-
- @override
- Future<dynamic> deleteFile(String fsName, Uri deviceUri) async {
- // TODO(johnmccutchan): Add file deletion to the devFS protocol.
- }
}
class DevFSException implements Exception {
@@ -288,16 +273,14 @@
int _inFlight = 0;
Map<Uri, DevFSContent> _outstanding;
Completer<void> _completer;
- HttpClient _client;
+ final HttpClient _client = HttpClient();
Future<void> write(Map<Uri, DevFSContent> entries) async {
- _client = HttpClient();
_client.maxConnectionsPerHost = kMaxInFlight;
_completer = Completer<void>();
_outstanding = Map<Uri, DevFSContent>.from(entries);
_scheduleWrites();
await _completer.future;
- _client.close();
}
void _scheduleWrites() {
@@ -405,9 +388,6 @@
final Map<Uri, DevFSContent> _entries = <Uri, DevFSContent>{};
final Set<String> assetPathsToEvict = <String>{};
- final List<Future<Map<String, dynamic>>> _pendingOperations =
- <Future<Map<String, dynamic>>>[];
-
Uri _baseUri;
Uri get baseUri => _baseUri;
@@ -453,66 +433,33 @@
DateTime firstBuildTime,
bool bundleFirstUpload = false,
bool bundleDirty = false,
- Set<String> fileFilter,
@required ResidentCompiler generator,
String dillOutputPath,
@required bool trackWidgetCreation,
bool fullRestart = false,
String projectRootPath,
@required String pathToReload,
+ @required List<String> invalidatedFiles,
}) async {
assert(trackWidgetCreation != null);
assert(generator != null);
- // Mark all entries as possibly deleted.
- for (DevFSContent content in _entries.values) {
- content._exists = false;
- }
- // Scan workspace, packages, and assets
- printTrace('DevFS: Starting sync from $rootDirectory');
- logger.printTrace('Scanning project files');
- await _scanDirectory(rootDirectory,
- recursive: true,
- fileFilter: fileFilter);
- if (fs.isFileSync(_packagesFilePath)) {
- printTrace('Scanning package files');
- await _scanPackages(fileFilter);
- }
if (bundle != null) {
printTrace('Scanning asset files');
+ // We write the assets into the AssetBundle working dir so that they
+ // are in the same location in DevFS and the iOS simulator.
+ final String assetDirectory = getAssetBuildDirectory();
bundle.entries.forEach((String archivePath, DevFSContent content) {
- _scanBundleEntry(archivePath, content);
+ final Uri deviceUri = fs.path.toUri(fs.path.join(assetDirectory, archivePath));
+ _entries[deviceUri] = content;
});
}
- // Handle deletions.
- printTrace('Scanning for deleted files');
- final String assetBuildDirPrefix = _asUriPath(getAssetBuildDirectory());
- final List<Uri> toRemove = <Uri>[];
- _entries.forEach((Uri deviceUri, DevFSContent content) {
- if (!content._exists) {
- final Future<Map<String, dynamic>> operation =
- _operations.deleteFile(fsName, deviceUri)
- .then<Map<String, dynamic>>((dynamic v) => v?.cast<String,dynamic>());
- if (operation != null)
- _pendingOperations.add(operation);
- toRemove.add(deviceUri);
- if (deviceUri.path.startsWith(assetBuildDirPrefix)) {
- final String archivePath = deviceUri.path.substring(assetBuildDirPrefix.length);
- assetPathsToEvict.add(archivePath);
- }
- }
- });
- if (toRemove.isNotEmpty) {
- printTrace('Removing deleted files');
- toRemove.forEach(_entries.remove);
- await Future.wait<Map<String, dynamic>>(_pendingOperations);
- _pendingOperations.clear();
- }
-
// Update modified files
- int syncedBytes = 0;
+ final String assetBuildDirPrefix = _asUriPath(getAssetBuildDirectory());
final Map<Uri, DevFSContent> dirtyEntries = <Uri, DevFSContent>{};
+
+ int syncedBytes = 0;
_entries.forEach((Uri deviceUri, DevFSContent content) {
String archivePath;
if (deviceUri.path.startsWith(assetBuildDirPrefix))
@@ -527,30 +474,10 @@
assetPathsToEvict.add(archivePath);
}
});
- // We run generator even if [dirtyEntries] was empty because we want to
- // keep logic of accepting/rejecting generator's output simple: we must
- // accept/reject generator's output after every [update] call. Incremental
- // run with no changes is supposed to be fast (considering that it is
- // initiated by user key press).
- final List<String> invalidatedFiles = <String>[];
- final Set<Uri> filesUris = <Uri>{};
- for (Uri uri in dirtyEntries.keys.toList()) {
- if (!uri.path.startsWith(assetBuildDirPrefix)) {
- final DevFSContent content = dirtyEntries[uri];
- if (content is DevFSFileContent) {
- filesUris.add(uri);
- invalidatedFiles.add(content.file.uri.toString());
- syncedBytes -= content.size;
- }
- }
- }
- // No need to send source files because all compilation is done on the
- // host and result of compilation is single kernel file.
- filesUris.forEach(dirtyEntries.remove);
- printTrace('Compiling dart to kernel with ${invalidatedFiles.length} updated files');
if (fullRestart) {
generator.reset();
}
+ printTrace('Compiling dart to kernel with ${invalidatedFiles.length} updated files');
final CompilerOutput compilerOutput = await generator.recompile(
mainPath,
invalidatedFiles,
@@ -566,228 +493,28 @@
? fs.path.relative(pathToReload, from: projectRootPath)
: pathToReload,
);
- if (!dirtyEntries.containsKey(entryUri)) {
- final DevFSFileContent content = DevFSFileContent(fs.file(compiledBinary));
- dirtyEntries[entryUri] = content;
- syncedBytes += content.size;
- }
+ final DevFSFileContent content = DevFSFileContent(fs.file(compiledBinary));
+ syncedBytes += content.size;
+ dirtyEntries[entryUri] = content;
}
}
+ printTrace('Updating files');
if (dirtyEntries.isNotEmpty) {
- printTrace('Updating files');
- if (_httpWriter != null) {
- try {
- await _httpWriter.write(dirtyEntries);
- } on SocketException catch (socketException, stackTrace) {
- printTrace('DevFS sync failed. Lost connection to device: $socketException');
- throw DevFSException('Lost connection to device.', socketException, stackTrace);
- } catch (exception, stackTrace) {
- printError('Could not update files on device: $exception');
- throw DevFSException('Sync failed', exception, stackTrace);
- }
- } else {
- // Make service protocol requests for each.
- dirtyEntries.forEach((Uri deviceUri, DevFSContent content) {
- final Future<Map<String, dynamic>> operation =
- _operations.writeFile(fsName, deviceUri, content)
- .then<Map<String, dynamic>>((dynamic v) => v?.cast<String, dynamic>());
- if (operation != null)
- _pendingOperations.add(operation);
- });
- await Future.wait<Map<String, dynamic>>(_pendingOperations, eagerError: true);
- _pendingOperations.clear();
+ try {
+ await _httpWriter.write(dirtyEntries);
+ } on SocketException catch (socketException, stackTrace) {
+ printTrace('DevFS sync failed. Lost connection to device: $socketException');
+ throw DevFSException('Lost connection to device.', socketException, stackTrace);
+ } catch (exception, stackTrace) {
+ printError('Could not update files on device: $exception');
+ throw DevFSException('Sync failed', exception, stackTrace);
}
}
-
printTrace('DevFS: Sync finished');
return UpdateFSReport(success: true, syncedBytes: syncedBytes,
- invalidatedSourcesCount: invalidatedFiles.length);
- }
-
- void _scanFile(Uri deviceUri, FileSystemEntity file) {
- final DevFSContent content = _entries.putIfAbsent(deviceUri, () => DevFSFileContent(file));
- content._exists = true;
- }
-
- void _scanBundleEntry(String archivePath, DevFSContent content) {
- // We write the assets into the AssetBundle working dir so that they
- // are in the same location in DevFS and the iOS simulator.
- final Uri deviceUri = fs.path.toUri(fs.path.join(getAssetBuildDirectory(), archivePath));
-
- _entries[deviceUri] = content;
- content._exists = true;
- }
-
- bool _shouldIgnore(Uri deviceUri) {
- final List<String> ignoredUriPrefixes = <String>['android/',
- _asUriPath(getBuildDirectory()),
- 'ios/',
- '.pub/'];
- for (String ignoredUriPrefix in ignoredUriPrefixes) {
- if (deviceUri.path.startsWith(ignoredUriPrefix))
- return true;
- }
- return false;
- }
-
- bool _shouldSkip(
- FileSystemEntity file,
- String relativePath,
- Uri directoryUriOnDevice, {
- bool ignoreDotFiles = true,
- }) {
- if (file is Directory) {
- // Skip non-files.
- return true;
- }
- assert((file is Link) || (file is File));
- final String basename = fs.path.basename(file.path);
- if (ignoreDotFiles && basename.startsWith('.')) {
- // Skip dot files, but not the '.packages' file (even though in dart1
- // mode devfs['.packages'] will be overwritten with synthesized string content).
- return basename != '.packages';
- }
- return false;
- }
-
- Uri _directoryUriOnDevice(Uri directoryUriOnDevice, Directory directory) {
- if (directoryUriOnDevice == null) {
- final String relativeRootPath = fs.path.relative(directory.path, from: rootDirectory.path);
- if (relativeRootPath == '.') {
- directoryUriOnDevice = Uri();
- } else {
- directoryUriOnDevice = fs.path.toUri(relativeRootPath);
- }
- }
- return directoryUriOnDevice;
- }
-
- /// Scan all files from the [fileFilter] that are contained in [directory] and
- /// pass various filters (e.g. ignoreDotFiles).
- Future<bool> _scanFilteredDirectory(
- Set<String> fileFilter,
- Directory directory, {
- Uri directoryUriOnDevice,
- bool ignoreDotFiles = true,
- }) async {
- directoryUriOnDevice =
- _directoryUriOnDevice(directoryUriOnDevice, directory);
- try {
- final String absoluteDirectoryPath = canonicalizePath(directory.path);
- // For each file in the file filter.
- for (String filePath in fileFilter) {
- if (!filePath.startsWith(absoluteDirectoryPath)) {
- // File is not in this directory. Skip.
- continue;
- }
- final String relativePath =
- fs.path.relative(filePath, from: directory.path);
- final FileSystemEntity file = fs.file(filePath);
- if (_shouldSkip(file, relativePath, directoryUriOnDevice, ignoreDotFiles: ignoreDotFiles)) {
- continue;
- }
- final Uri deviceUri = directoryUriOnDevice.resolveUri(fs.path.toUri(relativePath));
- if (!_shouldIgnore(deviceUri))
- _scanFile(deviceUri, file);
- }
- } on FileSystemException catch (e) {
- _printScanDirectoryError(directory.path, e);
- return false;
- }
- return true;
- }
-
- /// Scan all files in [directory] that pass various filters (e.g. ignoreDotFiles).
- Future<bool> _scanDirectory(
- Directory directory, {
- Uri directoryUriOnDevice,
- bool recursive = false,
- bool ignoreDotFiles = true,
- Set<String> fileFilter,
- }) async {
- directoryUriOnDevice = _directoryUriOnDevice(directoryUriOnDevice, directory);
- if ((fileFilter != null) && fileFilter.isNotEmpty) {
- // When the fileFilter isn't empty, we can skip crawling the directory
- // tree and instead use the fileFilter as the source of potential files.
- return _scanFilteredDirectory(fileFilter,
- directory,
- directoryUriOnDevice: directoryUriOnDevice,
- ignoreDotFiles: ignoreDotFiles);
- }
- try {
- final Stream<FileSystemEntity> files =
- directory.list(recursive: recursive, followLinks: false);
- await for (FileSystemEntity file in files) {
- if (!devFSConfig.noDirectorySymlinks && (file is Link)) {
- // Check if this is a symlink to a directory and skip it.
- try {
- final FileSystemEntityType linkType =
- fs.statSync(file.resolveSymbolicLinksSync()).type;
- if (linkType == FileSystemEntityType.directory)
- continue;
- } on FileSystemException catch (e) {
- _printScanDirectoryError(file.path, e);
- continue;
- }
- }
- final String relativePath =
- fs.path.relative(file.path, from: directory.path);
- if (_shouldSkip(file, relativePath, directoryUriOnDevice, ignoreDotFiles: ignoreDotFiles)) {
- continue;
- }
- final Uri deviceUri = directoryUriOnDevice.resolveUri(fs.path.toUri(relativePath));
- if (!_shouldIgnore(deviceUri))
- _scanFile(deviceUri, file);
- }
- } on FileSystemException catch (e) {
- _printScanDirectoryError(directory.path, e);
- return false;
- }
- return true;
- }
-
- void _printScanDirectoryError(String path, Exception e) {
- printError(
- 'Error while scanning $path.\n'
- 'Hot Reload might not work until the following error is resolved:\n'
- '$e\n'
- );
- }
-
- Future<void> _scanPackages(Set<String> fileFilter) async {
- StringBuffer sb;
- final PackageMap packageMap = PackageMap(_packagesFilePath);
-
- for (String packageName in packageMap.map.keys) {
- final Uri packageUri = packageMap.map[packageName];
- final String packagePath = fs.path.fromUri(packageUri);
- final Directory packageDirectory = fs.directory(packageUri);
- Uri directoryUriOnDevice = fs.path.toUri(fs.path.join('packages', packageName) + fs.path.separator);
- bool packageExists = packageDirectory.existsSync();
-
- if (!packageExists) {
- // If the package directory doesn't exist at all, we ignore it.
- continue;
- }
-
- if (fs.path.isWithin(rootDirectory.path, packagePath)) {
- // We already scanned everything under the root directory.
- directoryUriOnDevice = fs.path.toUri(
- fs.path.relative(packagePath, from: rootDirectory.path) + fs.path.separator
- );
- } else {
- packageExists =
- await _scanDirectory(packageDirectory,
- directoryUriOnDevice: directoryUriOnDevice,
- recursive: true,
- fileFilter: fileFilter);
- }
- if (packageExists) {
- sb ??= StringBuffer();
- sb.writeln('$packageName:$directoryUriOnDevice');
- }
- }
+ invalidatedSourcesCount: invalidatedFiles.length);
}
}
+
/// Converts a platform-specific file path to a platform-independent Uri path.
String _asUriPath(String filePath) => fs.path.toUri(filePath).path + '/';
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 703d6d7..88c11d4 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -18,9 +18,7 @@
import 'build_info.dart';
import 'codegen.dart';
import 'compile.dart';
-import 'dart/dependencies.dart';
import 'dart/package_map.dart';
-import 'dependency_checker.dart';
import 'devfs.dart';
import 'device.dart';
import 'globals.dart';
@@ -444,10 +442,10 @@
DateTime firstBuildTime,
bool bundleFirstUpload = false,
bool bundleDirty = false,
- Set<String> fileFilter,
bool fullRestart = false,
String projectRootPath,
String pathToReload,
+ @required List<String> invalidatedFiles,
}) async {
final Status devFSStatus = logger.startProgress(
'Syncing files to device ${device.name}...',
@@ -462,13 +460,13 @@
firstBuildTime: firstBuildTime,
bundleFirstUpload: bundleFirstUpload,
bundleDirty: bundleDirty,
- fileFilter: fileFilter,
generator: generator,
fullRestart: fullRestart,
dillOutputPath: dillOutputPath,
trackWidgetCreation: trackWidgetCreation,
projectRootPath: projectRootPath,
pathToReload: pathToReload,
+ invalidatedFiles: invalidatedFiles,
);
} on DevFSException {
devFSStatus.cancel();
@@ -945,21 +943,19 @@
}
bool hasDirtyDependencies(FlutterDevice device) {
- /// When using the build system, dependency analysis is handled by build
- /// runner instead.
- if (experimentalBuildEnabled) {
- return false;
- }
- final DartDependencySetBuilder dartDependencySetBuilder =
- DartDependencySetBuilder(mainPath, packagesFilePath);
- final DependencyChecker dependencyChecker =
- DependencyChecker(dartDependencySetBuilder, assetBundle);
if (device.package.packagesFile == null || !device.package.packagesFile.existsSync()) {
return true;
}
- final DateTime lastBuildTime = device.package.packagesFile.statSync().modified;
-
- return dependencyChecker.check(lastBuildTime);
+ // 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 { }
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index 53a4f36..e6da33b 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -7,29 +7,28 @@
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';
import 'base/file_system.dart';
import 'base/logger.dart';
+import 'base/platform.dart';
import 'base/terminal.dart';
import 'base/utils.dart';
import 'build_info.dart';
-import 'codegen.dart';
import 'compile.dart';
import 'convert.dart';
-import 'dart/dependencies.dart';
-import 'dart/pub.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';
class HotRunnerConfig {
- /// Should the hot runner compute the minimal Dart dependencies?
- bool computeDartDependencies = true;
/// Should the hot runner assume that the minimal Dart dependencies do not change?
bool stableDartDependencies = false;
/// A hook for implementations to perform any necessary initialization prior
@@ -71,6 +70,7 @@
bool saveCompilationTrace = false,
bool stayResident = true,
bool ipv6 = false,
+ FlutterProject flutterProject,
}) : super(devices,
target: target,
debuggingOptions: debuggingOptions,
@@ -79,14 +79,19 @@
packagesFilePath: packagesFilePath,
saveCompilationTrace: saveCompilationTrace,
stayResident: stayResident,
- ipv6: ipv6);
+ ipv6: ipv6) {
+ fileInvalidator = ProjectFileInvalidator(
+ packagesFilePath ?? fs.path.absolute(PackageMap.globalPackagesPath),
+ flutterProject,
+ );
+ }
final bool benchmarkMode;
final File applicationBinary;
final bool hostIsIde;
bool _didAttach = false;
- Set<String> _dartDependencies;
final String dillOutputPath;
+ ProjectFileInvalidator fileInvalidator;
final Map<String, List<int>> benchmarkData = <String, List<int>>{};
// The initial launch is from a snapshot.
@@ -98,54 +103,8 @@
benchmarkData[name].add(value);
}
- Future<bool> _refreshDartDependencies() async {
- if (!hotRunnerConfig.computeDartDependencies) {
- // Disabled.
- return true;
- }
- if (_dartDependencies != null) {
- // Already computed.
- return true;
- }
-
- try {
- // Will return immediately if pubspec.yaml is up-to-date.
- await pubGet(
- context: PubContext.pubGet,
- directory: projectRootPath,
- );
- } on ToolExit catch (error) {
- printError(
- 'Unable to reload your application because "flutter packages get" failed to update '
- 'package dependencies.\n'
- '$error'
- );
- return false;
- }
-
- /// When using the build system, dependency analysis is handled by build
- /// runner instead.
- if (experimentalBuildEnabled) {
- return true;
- }
- final DartDependencySetBuilder dartDependencySetBuilder = DartDependencySetBuilder(mainPath, packagesFilePath);
- try {
- _dartDependencies = Set<String>.from(dartDependencySetBuilder.build());
- } on DartDependencyException catch (error) {
- printError(
- 'Your application could not be compiled, because its dependencies could not be established.\n'
- '$error'
- );
- return false;
- }
- return true;
- }
-
- Future<void> _reloadSourcesService(
- String isolateId, {
- bool force = false,
- bool pause = false,
- }) async {
+ Future<void> _reloadSourcesService(String isolateId,
+ { bool force = false, bool pause = false }) async {
// TODO(cbernaschina): check that isolateId is the id of the UI isolate.
final OperationResult result = await restart(pauseAfterRestart: pause);
if (!result.isOk) {
@@ -257,7 +216,6 @@
// Measure time to perform a hot restart.
printStatus('Benchmarking hot restart');
await restart(fullRestart: true);
- // TODO(johnmccutchan): Modify script entry point.
printStatus('Benchmarking hot reload');
// Measure time to perform a hot reload.
await restart(fullRestart: false);
@@ -296,12 +254,6 @@
return 1;
}
- // Determine the Dart dependencies eagerly.
- if (!await _refreshDartDependencies()) {
- // Some kind of source level error or missing file in the Dart code.
- return 1;
- }
-
firstBuildTime = DateTime.now();
for (FlutterDevice device in flutterDevices) {
@@ -336,8 +288,6 @@
result = await restart(fullRestart: false);
}
if (!result.isOk) {
- // TODO(johnmccutchan): Attempt to determine the number of errors that
- // occurred and tighten this message.
printStatus('Try again after fixing the above error(s).', emphasis: true);
}
} else if (lower == 'l') {
@@ -364,10 +314,6 @@
}
Future<UpdateFSReport> _updateDevFS({ bool fullRestart = false }) async {
- if (!await _refreshDartDependencies()) {
- // Did not update DevFS because of a Dart source error.
- return UpdateFSReport(success: false);
- }
final bool isFirstUpload = assetBundle.wasBuiltOnce() == false;
final bool rebuildBundle = assetBundle.needsBuild();
if (rebuildBundle) {
@@ -376,7 +322,7 @@
if (result != 0)
return UpdateFSReport(success: false);
}
-
+ final List<String> invalidatedFiles = fileInvalidator.findInvalidated();
final UpdateFSReport results = UpdateFSReport(success: true);
for (FlutterDevice device in flutterDevices) {
results.incorporateResults(await device.updateDevFS(
@@ -386,39 +332,15 @@
firstBuildTime: firstBuildTime,
bundleFirstUpload: isFirstUpload,
bundleDirty: isFirstUpload == false && rebuildBundle,
- fileFilter: _dartDependencies,
fullRestart: fullRestart,
projectRootPath: projectRootPath,
pathToReload: getReloadPath(fullRestart: fullRestart),
+ invalidatedFiles: invalidatedFiles,
));
}
- if (!results.success) {
- return results;
- }
-
- if (!hotRunnerConfig.stableDartDependencies) {
- // Clear the set after the sync so they are recomputed next time.
- _dartDependencies = null;
- }
return results;
}
- Future<void> _evictDirtyAssets() {
- final List<Future<Map<String, dynamic>>> futures = <Future<Map<String, dynamic>>>[];
- for (FlutterDevice device in flutterDevices) {
- if (device.devFS.assetPathsToEvict.isEmpty)
- continue;
- if (device.views.first.uiIsolate == null) {
- printError('Application isolate not found for $device');
- continue;
- }
- for (String assetPath in device.devFS.assetPathsToEvict)
- futures.add(device.views.first.uiIsolate.flutterEvictAsset(assetPath));
- device.devFS.assetPathsToEvict.clear();
- }
- return Future.wait<Map<String, dynamic>>(futures);
- }
-
void _resetDirtyAssets() {
for (FlutterDevice device in flutterDevices)
device.devFS.assetPathsToEvict.clear();
@@ -811,9 +733,9 @@
return OperationResult(OperationResult.ok.code, reloadMessage);
}
}
- assert(reassembleViews.isNotEmpty);
printTrace('Evicting dirty assets');
await _evictDirtyAssets();
+ assert(reassembleViews.isNotEmpty);
printTrace('Reassembling application');
bool failedReassemble = false;
final List<Future<void>> futures = <Future<void>>[];
@@ -886,7 +808,6 @@
// Only report timings if we reloaded a single view without any errors.
if ((reassembleViews.length == 1) && !failedReassemble && shouldReportReloadTime)
flutterUsage.sendTiming('hot', 'reload', reloadDuration);
-
return OperationResult(
failedReassemble ? 1 : OperationResult.ok.code,
reloadMessage,
@@ -965,6 +886,23 @@
}
}
+ Future<void> _evictDirtyAssets() {
+ final List<Future<Map<String, dynamic>>> futures = <Future<Map<String, dynamic>>>[];
+ for (FlutterDevice device in flutterDevices) {
+ if (device.devFS.assetPathsToEvict.isEmpty)
+ continue;
+ if (device.views.first.uiIsolate == null) {
+ printError('Application isolate not found for $device');
+ continue;
+ }
+ for (String assetPath in device.devFS.assetPathsToEvict) {
+ futures.add(device.views.first.uiIsolate.flutterEvictAsset(assetPath));
+ }
+ device.devFS.assetPathsToEvict.clear();
+ }
+ return Future.wait<Map<String, dynamic>>(futures);
+ }
+
@override
Future<void> cleanupAfterSignal() async {
await stopEchoingDeviceLog();
@@ -988,3 +926,106 @@
await stopEchoingDeviceLog();
}
}
+
+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.
+ }
+ }
+ // 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);
+ }
+ 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;
+ }
+ }
+ }
+}
diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml
index 9eae2de..a1d023d 100644
--- a/packages/flutter_tools/pubspec.yaml
+++ b/packages/flutter_tools/pubspec.yaml
@@ -9,7 +9,6 @@
dependencies:
# To update these, use "flutter update-packages --force-upgrade".
- analyzer: 0.35.3
archive: 2.0.8
args: 1.5.1
bsdiff: 0.1.0
@@ -53,6 +52,7 @@
build_modules: 1.0.9
build_daemon: 0.4.2
+ analyzer: 0.35.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
bazel_worker: 0.1.20 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
@@ -100,8 +100,8 @@
collection: 1.14.11
mockito: 4.0.0
file_testing: 2.1.0
- test: 1.5.3
vm_service_lib: 3.14.2
+ test: 1.5.3
build_runner: 1.2.8
build_vm_compilers: 0.1.1+5
build_test: 0.10.6
diff --git a/packages/flutter_tools/test/commands/attach_test.dart b/packages/flutter_tools/test/commands/attach_test.dart
index 693d71e..87dcb92 100644
--- a/packages/flutter_tools/test/commands/attach_test.dart
+++ b/packages/flutter_tools/test/commands/attach_test.dart
@@ -120,6 +120,7 @@
debuggingOptions: anyNamed('debuggingOptions'),
packagesFilePath: anyNamed('packagesFilePath'),
usesTerminalUI: anyNamed('usesTerminalUI'),
+ flutterProject: anyNamed('flutterProject'),
ipv6: false,
),
).thenReturn(mockHotRunner);
@@ -151,6 +152,7 @@
debuggingOptions: anyNamed('debuggingOptions'),
packagesFilePath: anyNamed('packagesFilePath'),
usesTerminalUI: anyNamed('usesTerminalUI'),
+ flutterProject: anyNamed('flutterProject'),
ipv6: false,
),
)..called(1);
@@ -225,6 +227,7 @@
debuggingOptions: anyNamed('debuggingOptions'),
packagesFilePath: anyNamed('packagesFilePath'),
usesTerminalUI: anyNamed('usesTerminalUI'),
+ flutterProject: anyNamed('flutterProject'),
ipv6: false,
)).thenReturn(mockHotRunner);
@@ -254,6 +257,7 @@
debuggingOptions: anyNamed('debuggingOptions'),
packagesFilePath: anyNamed('packagesFilePath'),
usesTerminalUI: anyNamed('usesTerminalUI'),
+ flutterProject: anyNamed('flutterProject'),
ipv6: false,
)).called(1);
}, overrides: <Type, Generator>{
diff --git a/packages/flutter_tools/test/dart_dependencies_test.dart b/packages/flutter_tools/test/dart_dependencies_test.dart
deleted file mode 100644
index dbfdc26..0000000
--- a/packages/flutter_tools/test/dart_dependencies_test.dart
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter_tools/src/dart/dependencies.dart';
-import 'package:flutter_tools/src/base/file_system.dart';
-
-import 'src/common.dart';
-import 'src/context.dart';
-
-void main() {
- group('DartDependencySetBuilder', () {
- final String dataPath = fs.path.join(
- getFlutterRoot(),
- 'packages',
- 'flutter_tools',
- 'test',
- 'data',
- 'dart_dependencies_test',
- );
-
- testUsingContext('good', () {
- final String testPath = fs.path.join(dataPath, 'good');
- final String mainPath = fs.path.join(testPath, 'main.dart');
- final String packagesPath = fs.path.join(testPath, '.packages');
- final DartDependencySetBuilder builder =
- DartDependencySetBuilder(mainPath, packagesPath);
- final Set<String> dependencies = builder.build();
- expect(dependencies.contains(canonicalizePath(mainPath)), isTrue);
- expect(dependencies.contains(canonicalizePath(fs.path.join(testPath, 'foo.dart'))), isTrue);
- });
-
- testUsingContext('syntax_error', () {
- final String testPath = fs.path.join(dataPath, 'syntax_error');
- final String mainPath = fs.path.join(testPath, 'main.dart');
- final String packagesPath = fs.path.join(testPath, '.packages');
- final DartDependencySetBuilder builder =
- DartDependencySetBuilder(mainPath, packagesPath);
- try {
- builder.build();
- fail('expect an exception to be thrown.');
- } on DartDependencyException catch (error) {
- expect(error.toString(), contains('foo.dart: Expected a string literal'));
- }
- });
-
- testUsingContext('bad_path', () {
- final String testPath = fs.path.join(dataPath, 'bad_path');
- final String mainPath = fs.path.join(testPath, 'main.dart');
- final String packagesPath = fs.path.join(testPath, '.packages');
- final DartDependencySetBuilder builder =
- DartDependencySetBuilder(mainPath, packagesPath);
- try {
- builder.build();
- fail('expect an exception to be thrown.');
- } on DartDependencyException catch (error) {
- expect(error.toString(), contains('amaze${fs.path.separator}and${fs.path.separator}astonish.dart'));
- }
- });
-
- testUsingContext('bad_package', () {
- final String testPath = fs.path.join(dataPath, 'bad_package');
- final String mainPath = fs.path.join(testPath, 'main.dart');
- final String packagesPath = fs.path.join(testPath, '.packages');
- final DartDependencySetBuilder builder =
- DartDependencySetBuilder(mainPath, packagesPath);
- try {
- builder.build();
- fail('expect an exception to be thrown.');
- } on DartDependencyException catch (error) {
- expect(error.toString(), contains('rochambeau'));
- expect(error.toString(), contains('pubspec.yaml'));
- }
- });
-
- testUsingContext('does not change ASCII casing of path', () {
- final String testPath = fs.path.join(dataPath, 'asci_casing');
- final String mainPath = fs.path.join(testPath, 'main.dart');
- final String packagesPath = fs.path.join(testPath, '.packages');
- final DartDependencySetBuilder builder = DartDependencySetBuilder(mainPath, packagesPath);
- final Set<String> deps = builder.build();
- expect(deps, contains(endsWith('This_Import_Has_fuNNy_casING.dart')));
- });
-
- testUsingContext('bad_import', () {
- final String testPath = fs.path.join(dataPath, 'bad_import');
- final String mainPath = fs.path.join(testPath, 'main.dart');
- final String packagesPath = fs.path.join(testPath, '.packages');
- final DartDependencySetBuilder builder =
- DartDependencySetBuilder(mainPath, packagesPath);
- try {
- builder.build();
- fail('expect an exception to be thrown.');
- } on DartDependencyException catch (error) {
- expect(error.toString(), contains('Unable to parse URI'));
- }
- });
- });
-}
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/.dartignore b/packages/flutter_tools/test/data/dart_dependencies_test/.dartignore
deleted file mode 100644
index e69de29..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/.dartignore
+++ /dev/null
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/.packages b/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/.packages
deleted file mode 100644
index 453dc36..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/.packages
+++ /dev/null
@@ -1 +0,0 @@
-self:lib/
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/This_Import_Has_fuNNy_casING.dart b/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/This_Import_Has_fuNNy_casING.dart
deleted file mode 100644
index 6081630..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/This_Import_Has_fuNNy_casING.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-String dummy = 'Hello';
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/analysis_options.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/analysis_options.yaml
deleted file mode 100644
index 4c1615a..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/analysis_options.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-analyzer:
- exclude:
- - '**'
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/main.dart b/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/main.dart
deleted file mode 100644
index 176c82d..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/main.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'This_Import_Has_fuNNy_casING.dart';
-
-void main() {
- print(dummy);
-}
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/pubspec.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/pubspec.yaml
deleted file mode 100644
index 99a0109..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/asci_casing/pubspec.yaml
+++ /dev/null
@@ -1 +0,0 @@
-name: self
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/analysis_options.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/analysis_options.yaml
deleted file mode 100644
index 4c1615a..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/analysis_options.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-analyzer:
- exclude:
- - '**'
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/main.dart b/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/main.dart
deleted file mode 100644
index 7f22c90..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/main.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'data://object.dart';
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/pubspec.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/pubspec.yaml
deleted file mode 100644
index 99a0109..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_import/pubspec.yaml
+++ /dev/null
@@ -1 +0,0 @@
-name: self
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/.packages b/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/.packages
deleted file mode 100644
index 453dc36..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/.packages
+++ /dev/null
@@ -1 +0,0 @@
-self:lib/
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/analysis_options.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/analysis_options.yaml
deleted file mode 100644
index 4c1615a..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/analysis_options.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-analyzer:
- exclude:
- - '**'
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/main.dart b/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/main.dart
deleted file mode 100644
index c3b231b..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/main.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:rochambeau/you_have_your_orders_now_go_man_go.dart';
-
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/pubspec.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/pubspec.yaml
deleted file mode 100644
index 99a0109..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_package/pubspec.yaml
+++ /dev/null
@@ -1 +0,0 @@
-name: self
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/.packages b/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/.packages
deleted file mode 100644
index 453dc36..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/.packages
+++ /dev/null
@@ -1 +0,0 @@
-self:lib/
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/analysis_options.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/analysis_options.yaml
deleted file mode 100644
index 4c1615a..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/analysis_options.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-analyzer:
- exclude:
- - '**'
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/main.dart b/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/main.dart
deleted file mode 100644
index 9c9d216..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/main.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'amaze/and/astonish.dart';
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/pubspec.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/pubspec.yaml
deleted file mode 100644
index 99a0109..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/bad_path/pubspec.yaml
+++ /dev/null
@@ -1 +0,0 @@
-name: self
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/.packages b/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/.packages
deleted file mode 100644
index 0b55f79..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/.packages
+++ /dev/null
@@ -1,2 +0,0 @@
-flutter:file:///a/wild/non-existent/directory/has/appeared
-sdk-move-test:lib/
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/lib/main.dart b/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/lib/main.dart
deleted file mode 100644
index bcd11b5..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/lib/main.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// No content
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/pubspec.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/pubspec.yaml
deleted file mode 100644
index 9de2fbe..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/changed_sdk_location/pubspec.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-name: sdk-move-test
-
-environment:
- # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
- sdk: ">=2.0.0-dev.68.0 <3.0.0"
-
-dependencies:
- flutter:
- sdk: flutter
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/good/.packages b/packages/flutter_tools/test/data/dart_dependencies_test/good/.packages
deleted file mode 100644
index 453dc36..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/good/.packages
+++ /dev/null
@@ -1 +0,0 @@
-self:lib/
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/good/analysis_options.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/good/analysis_options.yaml
deleted file mode 100644
index 4c1615a..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/good/analysis_options.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-analyzer:
- exclude:
- - '**'
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/good/foo.dart b/packages/flutter_tools/test/data/dart_dependencies_test/good/foo.dart
deleted file mode 100644
index 6853db7..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/good/foo.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/good/lib/bar.dart b/packages/flutter_tools/test/data/dart_dependencies_test/good/lib/bar.dart
deleted file mode 100644
index 6853db7..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/good/lib/bar.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/good/main.dart b/packages/flutter_tools/test/data/dart_dependencies_test/good/main.dart
deleted file mode 100644
index 659a48d..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/good/main.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'foo.dart';
-import 'package:self/bar.dart';
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/good/pubspec.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/good/pubspec.yaml
deleted file mode 100644
index 99a0109..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/good/pubspec.yaml
+++ /dev/null
@@ -1 +0,0 @@
-name: self
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/.packages b/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/.packages
deleted file mode 100644
index 453dc36..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/.packages
+++ /dev/null
@@ -1 +0,0 @@
-self:lib/
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/analysis_options.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/analysis_options.yaml
deleted file mode 100644
index 4c1615a..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/analysis_options.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-analyzer:
- exclude:
- - '**'
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/foo.dart b/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/foo.dart
deleted file mode 100644
index 6fbabe4..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/foo.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import bad programmer!
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/main.dart b/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/main.dart
deleted file mode 100644
index 43d48c0..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/main.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'foo.dart';
diff --git a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/pubspec.yaml b/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/pubspec.yaml
deleted file mode 100644
index 99a0109..0000000
--- a/packages/flutter_tools/test/data/dart_dependencies_test/syntax_error/pubspec.yaml
+++ /dev/null
@@ -1 +0,0 @@
-name: self
diff --git a/packages/flutter_tools/test/dependency_checker_test.dart b/packages/flutter_tools/test/dependency_checker_test.dart
deleted file mode 100644
index a815ff2..0000000
--- a/packages/flutter_tools/test/dependency_checker_test.dart
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:file/memory.dart';
-import 'package:flutter_tools/src/base/file_system.dart';
-import 'package:flutter_tools/src/cache.dart';
-import 'package:flutter_tools/src/commands/devices.dart';
-import 'package:flutter_tools/src/dart/dependencies.dart';
-import 'package:flutter_tools/src/dependency_checker.dart';
-
-import 'src/common.dart';
-import 'src/context.dart';
-
-void main() {
- group('DependencyChecker', () {
- final String dataPath = fs.path.join(
- getFlutterRoot(),
- 'packages',
- 'flutter_tools',
- 'test',
- 'data',
- 'dart_dependencies_test',
- );
-
- FileSystem testFileSystem;
-
- setUpAll(() {
- Cache.disableLocking();
- });
-
- setUp(() {
- testFileSystem = MemoryFileSystem();
- });
-
- testUsingContext('good', () {
- final String testPath = fs.path.join(dataPath, 'good');
- final String mainPath = fs.path.join(testPath, 'main.dart');
- final String fooPath = fs.path.join(testPath, 'foo.dart');
- final String barPath = fs.path.join(testPath, 'lib', 'bar.dart');
- final String packagesPath = fs.path.join(testPath, '.packages');
- final DartDependencySetBuilder builder =
- DartDependencySetBuilder(mainPath, packagesPath);
- final DependencyChecker dependencyChecker =
- DependencyChecker(builder, null);
-
- // Set file modification time on all dependencies to be in the past.
- final DateTime baseTime = DateTime.now();
- updateFileModificationTime(packagesPath, baseTime, -10);
- updateFileModificationTime(mainPath, baseTime, -10);
- updateFileModificationTime(fooPath, baseTime, -10);
- updateFileModificationTime(barPath, baseTime, -10);
- expect(dependencyChecker.check(baseTime), isFalse);
-
- // Set .packages file modification time to be in the future.
- updateFileModificationTime(packagesPath, baseTime, 20);
- expect(dependencyChecker.check(baseTime), isTrue);
-
- // Reset .packages file modification time.
- updateFileModificationTime(packagesPath, baseTime, 0);
- expect(dependencyChecker.check(baseTime), isFalse);
-
- // Set 'package:self/bar.dart' file modification time to be in the future.
- updateFileModificationTime(barPath, baseTime, 10);
- expect(dependencyChecker.check(baseTime), isTrue);
- });
-
- testUsingContext('syntax error', () {
- final String testPath = fs.path.join(dataPath, 'syntax_error');
- final String mainPath = fs.path.join(testPath, 'main.dart');
- final String fooPath = fs.path.join(testPath, 'foo.dart');
- final String packagesPath = fs.path.join(testPath, '.packages');
-
- final DartDependencySetBuilder builder =
- DartDependencySetBuilder(mainPath, packagesPath);
- final DependencyChecker dependencyChecker =
- DependencyChecker(builder, null);
-
- final DateTime baseTime = DateTime.now();
-
- // Set file modification time on all dependencies to be in the past.
- updateFileModificationTime(packagesPath, baseTime, -10);
- updateFileModificationTime(mainPath, baseTime, -10);
- updateFileModificationTime(fooPath, baseTime, -10);
-
- // Dependencies are considered dirty because there is a syntax error in
- // the .dart file.
- expect(dependencyChecker.check(baseTime), isTrue);
- });
-
- /// Test a flutter tool move.
- ///
- /// Tests that the flutter tool doesn't crash and displays a warning when its own location
- /// changed since it was last referenced to in a package's .packages file.
- testUsingContext('moved flutter sdk', () async {
- final Directory tempDir = fs.systemTempDirectory.createTempSync('flutter_dependency_checker_test.');
-
- // Copy the golden input and let the test run in an isolated temporary in-memory file system.
- const LocalFileSystem localFileSystem = LocalFileSystem();
- final Directory sourcePath = localFileSystem.directory(localFileSystem.path.join(dataPath, 'changed_sdk_location'));
- copyDirectorySync(sourcePath, tempDir);
- fs.currentDirectory = tempDir;
-
- // Doesn't matter what commands we run. Arbitrarily list devices here.
- await createTestCommandRunner(DevicesCommand()).run(<String>['devices']);
- expect(testLogger.errorText, contains('.packages'));
- tryToDelete(tempDir);
- }, overrides: <Type, Generator>{
- FileSystem: () => testFileSystem,
- });
- });
-}
diff --git a/packages/flutter_tools/test/devfs_test.dart b/packages/flutter_tools/test/devfs_test.dart
index 318ed1b..653442b 100644
--- a/packages/flutter_tools/test/devfs_test.dart
+++ b/packages/flutter_tools/test/devfs_test.dart
@@ -7,10 +7,8 @@
import 'package:file/file.dart';
import 'package:file/memory.dart';
-import 'package:flutter_tools/src/asset.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/file_system.dart';
-import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
@@ -22,16 +20,13 @@
void main() {
FileSystem fs;
String filePath;
- String filePath2;
Directory tempDir;
String basePath;
DevFS devFS;
- final AssetBundle assetBundle = AssetBundleFactory.defaultInstance.createBundle();
setUpAll(() {
fs = MemoryFileSystem();
filePath = fs.path.join('lib', 'foo.txt');
- filePath2 = fs.path.join('foo', 'bar.txt');
});
group('DevFSContent', () {
@@ -94,362 +89,6 @@
});
});
- group('devfs local', () {
- final MockDevFSOperations devFSOperations = MockDevFSOperations();
- final MockResidentCompiler residentCompiler = MockResidentCompiler();
-
- setUpAll(() {
- tempDir = _newTempDir(fs);
- basePath = tempDir.path;
- });
- tearDownAll(_cleanupTempDirs);
-
- testUsingContext('create dev file system', () async {
- // simulate workspace
- final File file = fs.file(fs.path.join(basePath, filePath));
- await file.parent.create(recursive: true);
- file.writeAsBytesSync(<int>[1, 2, 3]);
- _packages['my_project'] = fs.path.toUri('lib');
-
- // simulate package
- await _createPackage(fs, 'somepkg', 'somefile.txt');
-
- devFS = DevFS.operations(devFSOperations, 'test', tempDir);
- await devFS.create();
- devFSOperations.expectMessages(<String>['create test']);
- expect(devFS.assetPathsToEvict, isEmpty);
-
- UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
-
- report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: true,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill.track.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
-
- expect(report.syncedBytes, 22);
- expect(report.success, true);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('add new file to local file system', () async {
- final File file = fs.file(fs.path.join(basePath, filePath2));
- await file.parent.create(recursive: true);
- file.writeAsBytesSync(<int>[1, 2, 3, 4, 5, 6, 7]);
- final UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('modify existing file on local file system', () async {
- UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
-
- final File file = fs.file(fs.path.join(basePath, filePath));
- // Set the last modified time to 5 seconds in the past.
- updateFileModificationTime(file.path, DateTime.now(), -5);
- report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
-
- await file.writeAsBytes(<int>[1, 2, 3, 4, 5, 6]);
- report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
-
- // Set the last modified time to 5 seconds in the past.
- updateFileModificationTime(file.path, DateTime.now(), -5);
- report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: true,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill.track.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
-
- await file.writeAsBytes(<int>[1, 2, 3, 4, 5, 6]);
- report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: true,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill.track.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
-
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('delete a file from the local file system', () async {
- final File file = fs.file(fs.path.join(basePath, filePath));
- await file.delete();
- final UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'deleteFile test lib/foo.txt',
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('add new package', () async {
- await _createPackage(fs, 'newpkg', 'anotherfile.txt');
- UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
-
- report = await devFS.update(
- mainPath: 'lib/foo.txt',
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: true,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill.track.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
-
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('add new package with double slashes in URI', () async {
- const String packageName = 'doubleslashpkg';
- await _createPackage(fs, packageName, 'somefile.txt', doubleSlash: true);
-
- final Set<String> fileFilter = <String>{};
- final List<Uri> pkgUris = <Uri>[fs.path.toUri(basePath)]..addAll(_packages.values);
- for (Uri pkgUri in pkgUris) {
- if (!pkgUri.isAbsolute) {
- pkgUri = fs.path.toUri(fs.path.join(basePath, pkgUri.path));
- }
- fileFilter.addAll(fs.directory(pkgUri)
- .listSync(recursive: true)
- .whereType<File>()
- .map<String>((File file) => canonicalizePath(file.path))
- .toList());
- }
- final UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- fileFilter: fileFilter,
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, isEmpty);
- expect(report.syncedBytes, 22);
- expect(report.success, true);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('add an asset bundle', () async {
- assetBundle.entries['a.txt'] = DevFSStringContent('abc');
- final UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- bundle: assetBundle,
- bundleDirty: true,
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test ${_inAssetBuildDirectory(fs, 'a.txt')}',
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, unorderedMatches(<String>['a.txt']));
- devFS.assetPathsToEvict.clear();
- expect(report.syncedBytes, 25);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('add a file to the asset bundle - bundleDirty', () async {
- assetBundle.entries['b.txt'] = DevFSStringContent('abcd');
- final UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- bundle: assetBundle,
- bundleDirty: true,
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- // Expect entire asset bundle written because bundleDirty is true
- devFSOperations.expectMessages(<String>[
- 'writeFile test ${_inAssetBuildDirectory(fs, 'a.txt')}',
- 'writeFile test ${_inAssetBuildDirectory(fs, 'b.txt')}',
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, unorderedMatches(<String>[
- 'a.txt', 'b.txt']));
- devFS.assetPathsToEvict.clear();
- expect(report.syncedBytes, 29);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('add a file to the asset bundle', () async {
- assetBundle.entries['c.txt'] = DevFSStringContent('12');
- final UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- bundle: assetBundle,
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'writeFile test ${_inAssetBuildDirectory(fs, 'c.txt')}',
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, unorderedMatches(<String>[
- 'c.txt']));
- devFS.assetPathsToEvict.clear();
- expect(report.syncedBytes, 24);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('delete a file from the asset bundle', () async {
- assetBundle.entries.remove('c.txt');
- final UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- bundle: assetBundle,
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'deleteFile test ${_inAssetBuildDirectory(fs, 'c.txt')}',
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, unorderedMatches(<String>['c.txt']));
- devFS.assetPathsToEvict.clear();
- expect(report.syncedBytes, 22);
- expect(report.success, true);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('delete all files from the asset bundle', () async {
- assetBundle.entries.clear();
- final UpdateFSReport report = await devFS.update(
- mainPath: 'lib/foo.txt',
- bundle: assetBundle,
- bundleDirty: true,
- generator: residentCompiler,
- pathToReload: 'lib/foo.txt.dill',
- trackWidgetCreation: false,
- );
- devFSOperations.expectMessages(<String>[
- 'deleteFile test ${_inAssetBuildDirectory(fs, 'a.txt')}',
- 'deleteFile test ${_inAssetBuildDirectory(fs, 'b.txt')}',
- 'writeFile test lib/foo.txt.dill build/app.dill',
- ]);
- expect(devFS.assetPathsToEvict, unorderedMatches(<String>[
- 'a.txt', 'b.txt',
- ]));
- devFS.assetPathsToEvict.clear();
- expect(report.syncedBytes, 22);
- expect(report.success, true);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
-
- testUsingContext('delete dev file system', () async {
- await devFS.destroy();
- devFSOperations.expectMessages(<String>['destroy test']);
- expect(devFS.assetPathsToEvict, isEmpty);
- }, overrides: <Type, Generator>{
- FileSystem: () => fs,
- });
- });
-
group('devfs remote', () {
MockVMService vmService;
final MockResidentCompiler residentCompiler = MockResidentCompiler();
@@ -484,6 +123,7 @@
generator: residentCompiler,
pathToReload: 'lib/foo.txt.dill',
trackWidgetCreation: false,
+ invalidatedFiles: <String>[],
);
vmService.expectMessages(<String>[
'writeFile test lib/foo.txt.dill',
@@ -652,6 +292,3 @@
fs.file(fs.path.join(_tempDirs[0].path, '.packages')).writeAsStringSync(sb.toString());
}
-String _inAssetBuildDirectory(FileSystem fs, String filename) {
- return '${fs.path.toUri(getAssetBuildDirectory()).path}/$filename';
-}
diff --git a/packages/flutter_tools/test/hot_test.dart b/packages/flutter_tools/test/hot_test.dart
index a9efb24..be36a3d 100644
--- a/packages/flutter_tools/test/hot_test.dart
+++ b/packages/flutter_tools/test/hot_test.dart
@@ -105,13 +105,13 @@
firstBuildTime: anyNamed('firstBuildTime'),
bundleFirstUpload: anyNamed('bundleFirstUpload'),
bundleDirty: anyNamed('bundleDirty'),
- fileFilter: anyNamed('fileFilter'),
generator: anyNamed('generator'),
fullRestart: anyNamed('fullRestart'),
dillOutputPath: anyNamed('dillOutputPath'),
trackWidgetCreation: anyNamed('trackWidgetCreation'),
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
+ invalidatedFiles: anyNamed('invalidatedFiles'),
)).thenAnswer((Invocation _) => Future<UpdateFSReport>.value(
UpdateFSReport(success: true, syncedBytes: 1000, invalidatedSourcesCount: 1)));
when(mockDevFs.assetPathsToEvict).thenReturn(<String>{});
@@ -122,18 +122,6 @@
when(mockArtifacts.getArtifactPath(Artifact.flutterPatchedSdkPath)).thenReturn('some/path');
});
- testUsingContext('no setup', () async {
- final MockDevice mockDevice = MockDevice();
- when(mockDevice.supportsHotReload).thenReturn(true);
- when(mockDevice.supportsHotRestart).thenReturn(true);
- final List<FlutterDevice> devices = <FlutterDevice>[
- FlutterDevice(mockDevice, generator: residentCompiler, trackWidgetCreation: false),
- ];
- expect((await HotRunner(devices).restart(fullRestart: true)).isOk, false);
- }, overrides: <Type, Generator>{
- Artifacts: () => mockArtifacts,
- });
-
testUsingContext('Does not hot restart when device does not support it', () async {
// Setup mocks
final MockDevice mockDevice = MockDevice();
@@ -149,7 +137,7 @@
expect(result.message, 'hotRestart not supported');
}, overrides: <Type, Generator>{
Artifacts: () => mockArtifacts,
- HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true, computeDartDependencies: false),
+ HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true),
});
testUsingContext('Does not hot restart when one of many devices does not support it', () async {
@@ -171,7 +159,7 @@
expect(result.message, 'hotRestart not supported');
}, overrides: <Type, Generator>{
Artifacts: () => mockArtifacts,
- HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true, computeDartDependencies: false),
+ HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true),
});
testUsingContext('Does hot restarts when all devices support it', () async {
@@ -193,7 +181,7 @@
expect(result.message, isNot('hotRestart not supported'));
}, overrides: <Type, Generator>{
Artifacts: () => mockArtifacts,
- HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true, computeDartDependencies: false),
+ HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true),
});
testUsingContext('setup function fails', () async {
@@ -226,7 +214,7 @@
expect(result.message, isNot('setupHotRestart failed'));
}, overrides: <Type, Generator>{
Artifacts: () => mockArtifacts,
- HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true, computeDartDependencies: false),
+ HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true),
});
group('shutdown hook tests', () {
@@ -235,7 +223,6 @@
setUp(() {
shutdownTestingConfig = TestHotRunnerConfig(
successfulSetup: true,
- computeDartDependencies: false,
);
});
@@ -283,10 +270,7 @@
}
class TestHotRunnerConfig extends HotRunnerConfig {
- TestHotRunnerConfig({@required this.successfulSetup, bool computeDartDependencies = true}) {
- this.computeDartDependencies = computeDartDependencies;
- }
-
+ TestHotRunnerConfig({@required this.successfulSetup});
bool successfulSetup;
bool shutdownHookCalled = false;
diff --git a/packages/flutter_tools/test/project_file_invalidator_test.dart b/packages/flutter_tools/test/project_file_invalidator_test.dart
new file mode 100644
index 0000000..c38984e
--- /dev/null
+++ b/packages/flutter_tools/test/project_file_invalidator_test.dart
@@ -0,0 +1,234 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+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', () {
+ 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);
+ }, 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,
+ });
+ }, 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 52c5fc9..42c9d8f 100644
--- a/packages/flutter_tools/test/src/mocks.dart
+++ b/packages/flutter_tools/test/src/mocks.dart
@@ -460,12 +460,6 @@
messages.add(message);
devicePathToContent[deviceUri] = content;
}
-
- @override
- Future<dynamic> deleteFile(String fsName, Uri deviceUri) async {
- messages.add('deleteFile $fsName $deviceUri');
- devicePathToContent.remove(deviceUri);
- }
}
class MockResidentCompiler extends BasicMock implements ResidentCompiler {