Watch wildcard directories in addition to asset bundle (#29883)
diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart
index e845551..267be6a 100644
--- a/packages/flutter_tools/lib/src/asset.dart
+++ b/packages/flutter_tools/lib/src/asset.dart
@@ -63,6 +63,10 @@
@override
final Map<String, DevFSContent> entries = <String, DevFSContent>{};
+ // If an asset corresponds to a wildcard directory, then it may have been
+ // updated without changes to the manifest.
+ final Map<Uri, Directory> _wildcardDirectories = <Uri, Directory>{};
+
DateTime _lastBuildTimestamp;
static const String defaultManifestPath = 'pubspec.yaml';
@@ -83,6 +87,12 @@
if (stat.type == FileSystemEntityType.notFound)
return true;
+ for (Directory directory in _wildcardDirectories.values) {
+ if (directory.statSync().modified.isAfter(_lastBuildTimestamp)) {
+ return true;
+ }
+ }
+
return stat.modified.isAfter(_lastBuildTimestamp);
}
@@ -119,6 +129,7 @@
final String assetBasePath = fs.path.dirname(fs.path.absolute(manifestPath));
final PackageMap packageMap = PackageMap(packagesPath);
+ final List<Uri> wildcardDirectories = <Uri>[];
// The _assetVariants map contains an entry for each asset listed
// in the pubspec.yaml file's assets and font and sections. The
@@ -127,12 +138,14 @@
final Map<_Asset, List<_Asset>> assetVariants = _parseAssets(
packageMap,
flutterManifest,
+ wildcardDirectories,
assetBasePath,
excludeDirs: <String>[assetDirPath, getBuildDirectory()],
);
- if (assetVariants == null)
+ if (assetVariants == null) {
return 1;
+ }
final List<Map<String, dynamic>> fonts = _parseFonts(
flutterManifest,
@@ -156,6 +169,7 @@
final Map<_Asset, List<_Asset>> packageAssets = _parseAssets(
packageMap,
packageFlutterManifest,
+ wildcardDirectories,
packageBasePath,
packageName: packageName,
);
@@ -206,6 +220,11 @@
entries[asset.entryUri.path] ??= DevFSFileContent(asset.assetFile);
}
+ // Update wildcard directories we we can detect changes in them.
+ for (Uri uri in wildcardDirectories) {
+ _wildcardDirectories[uri] ??= fs.directory(uri);
+ }
+
entries[_assetManifestJson] = _createAssetManifest(assetVariants);
entries[_fontManifestJson] = DevFSStringContent(json.encode(fonts));
@@ -524,6 +543,7 @@
Map<_Asset, List<_Asset>> _parseAssets(
PackageMap packageMap,
FlutterManifest flutterManifest,
+ List<Uri> wildcardDirectories,
String assetBase, {
List<String> excludeDirs = const <String>[],
String packageName,
@@ -533,6 +553,7 @@
final _AssetDirectoryCache cache = _AssetDirectoryCache(excludeDirs);
for (Uri assetUri in flutterManifest.assets) {
if (assetUri.toString().endsWith('/')) {
+ wildcardDirectories.add(assetUri);
_parseAssetsFromFolder(packageMap, flutterManifest, assetBase,
cache, result, assetUri,
excludeDirs: excludeDirs, packageName: packageName);
diff --git a/packages/flutter_tools/test/asset_bundle_test.dart b/packages/flutter_tools/test/asset_bundle_test.dart
index 7a0bb00..5dc16e3 100644
--- a/packages/flutter_tools/test/asset_bundle_test.dart
+++ b/packages/flutter_tools/test/asset_bundle_test.dart
@@ -56,6 +56,46 @@
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
});
+
+ testUsingContext('wildcard directories are updated when filesystem changes', () async {
+ fs.file('.packages').createSync();
+ fs.file(fs.path.join('assets', 'foo', 'bar.txt')).createSync(recursive: true);
+ fs.file('pubspec.yaml')
+ ..createSync()
+ ..writeAsStringSync(r'''
+name: example
+flutter:
+ assets:
+ - assets/foo/
+''');
+ final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
+ await bundle.build(manifestPath: 'pubspec.yaml');
+ // Expected assets:
+ // - asset manifest
+ // - font manifest
+ // - license file
+ // - assets/foo/bar.txt
+ expect(bundle.entries.length, 4);
+ expect(bundle.needsBuild(manifestPath: 'pubspec.yaml'), false);
+
+ // Adding a file should update the stat of the directory, but instead
+ // we need to fully recreate it.
+ fs.directory(fs.path.join('assets', 'foo')).deleteSync(recursive: true);
+ fs.file(fs.path.join('assets', 'foo', 'fizz.txt')).createSync(recursive: true);
+ fs.file(fs.path.join('assets', 'foo', 'bar.txt')).createSync();
+
+ expect(bundle.needsBuild(manifestPath: 'pubspec.yaml'), true);
+ await bundle.build(manifestPath: 'pubspec.yaml');
+ // Expected assets:
+ // - asset manifest
+ // - font manifest
+ // - license file
+ // - assets/foo/bar.txt
+ // - assets/foo/fizz.txt
+ expect(bundle.entries.length, 5);
+ }, overrides: <Type, Generator>{
+ FileSystem: () => testFileSystem,
+ });
});
}