Skip to content

Commit cbe0cea

Browse files
authored
consolidate AssetBundle::entries and AssetBundle::entryKinds into a new type, AssetBundleEntry (#142029)
Part of work on flutter/flutter#141194 The [`AssetBundle`](https://github.com/flutter/flutter/blob/0833929c997c8a9db11c1e0df9a731ab17b77606/packages/flutter_tools/lib/src/asset.dart#L80) class contains two members, `entries` and `entryKinds`. `entries` contains asset data indexed by asset key. `entryKinds` contains the "kinds" of these assets, again indexed by asset key. **Change.** Rather than have two separate maps, this PR proposes combining these maps into one by wrapping the asset data and kind into a single data type `AssetBundleEntry`. **Purpose.** In flutter/flutter#141194, I am considering associating more information with an asset. In particular, what transformers are meant to be applied to it when copying it to the build output. Rather than adding another map member onto `AssetBundle` (e.g. `entryTransformers`), I decided to make things neater by introducing the `AssetBundleEntry` type.
1 parent 2bd5abf commit cbe0cea

File tree

9 files changed

+127
-104
lines changed

9 files changed

+127
-104
lines changed

packages/flutter_tools/bin/fuchsia_asset_builder.dart

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import 'package:flutter_tools/src/bundle.dart';
1414
import 'package:flutter_tools/src/bundle_builder.dart';
1515
import 'package:flutter_tools/src/cache.dart';
1616
import 'package:flutter_tools/src/context_runner.dart';
17-
import 'package:flutter_tools/src/devfs.dart';
1817
import 'package:flutter_tools/src/globals.dart' as globals;
1918
import 'package:flutter_tools/src/reporting/reporting.dart';
2019

@@ -37,9 +36,9 @@ Future<void> main(List<String> args) {
3736
});
3837
}
3938

40-
Future<void> writeFile(libfs.File outputFile, DevFSContent content) async {
39+
Future<void> writeAssetFile(libfs.File outputFile, AssetBundleEntry asset) async {
4140
outputFile.createSync(recursive: true);
42-
final List<int> data = await content.contentsAsBytes();
41+
final List<int> data = await asset.contentsAsBytes();
4342
outputFile.writeAsBytesSync(data);
4443
}
4544

@@ -73,9 +72,9 @@ Future<void> run(List<String> args) async {
7372
}
7473

7574
final List<Future<void>> calls = <Future<void>>[];
76-
assets.entries.forEach((String fileName, DevFSContent content) {
75+
assets.entries.forEach((String fileName, AssetBundleEntry entry) {
7776
final libfs.File outputFile = globals.fs.file(globals.fs.path.join(assetDir, fileName));
78-
calls.add(writeFile(outputFile, content));
77+
calls.add(writeAssetFile(outputFile, entry));
7978
});
8079
await Future.wait<void>(calls);
8180

packages/flutter_tools/lib/src/asset.dart

Lines changed: 69 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,28 @@ enum AssetKind {
7777
model,
7878
}
7979

80-
abstract class AssetBundle {
81-
Map<String, DevFSContent> get entries;
80+
/// Contains all information about an asset needed by tool the to prepare and
81+
/// copy an asset file to the build output.
82+
@immutable
83+
final class AssetBundleEntry {
84+
const AssetBundleEntry(this.content, {
85+
required this.kind,
86+
});
8287

83-
Map<String, AssetKind> get entryKinds;
88+
final DevFSContent content;
89+
final AssetKind kind;
90+
91+
Future<List<int>> contentsAsBytes() => content.contentsAsBytes();
92+
}
93+
94+
abstract class AssetBundle {
95+
/// The files that were specified under the `assets` section in the pubspec,
96+
/// indexed by asset key.
97+
Map<String, AssetBundleEntry> get entries;
8498

8599
/// The files that were specified under the deferred components assets sections
86-
/// in pubspec.
87-
Map<String, Map<String, DevFSContent>> get deferredComponentsEntries;
100+
/// in a pubspec, indexed by component name and asset key.
101+
Map<String, Map<String, AssetBundleEntry>> get deferredComponentsEntries;
88102

89103
/// Additional files that this bundle depends on that are not included in the
90104
/// output result.
@@ -149,13 +163,10 @@ class ManifestAssetBundle implements AssetBundle {
149163
final bool _splitDeferredAssets;
150164

151165
@override
152-
final Map<String, DevFSContent> entries = <String, DevFSContent>{};
153-
154-
@override
155-
final Map<String, AssetKind> entryKinds = <String, AssetKind>{};
166+
final Map<String, AssetBundleEntry> entries = <String, AssetBundleEntry>{};
156167

157168
@override
158-
final Map<String, Map<String, DevFSContent>> deferredComponentsEntries = <String, Map<String, DevFSContent>>{};
169+
final Map<String, Map<String, AssetBundleEntry>> deferredComponentsEntries = <String, Map<String, AssetBundleEntry>>{};
159170

160171
@override
161172
final List<File> inputFiles = <File>[];
@@ -236,17 +247,24 @@ class ManifestAssetBundle implements AssetBundle {
236247
// device.
237248
_lastBuildTimestamp = DateTime.now();
238249
if (flutterManifest.isEmpty) {
239-
entries[_kAssetManifestJsonFilename] = DevFSStringContent('{}');
240-
entryKinds[_kAssetManifestJsonFilename] = AssetKind.regular;
250+
entries[_kAssetManifestJsonFilename] = AssetBundleEntry(
251+
DevFSStringContent('{}'),
252+
kind: AssetKind.regular,
253+
);
241254
final ByteData emptyAssetManifest =
242255
const StandardMessageCodec().encodeMessage(<dynamic, dynamic>{})!;
243-
entries[_kAssetManifestBinFilename] =
244-
DevFSByteContent(emptyAssetManifest.buffer.asUint8List(0, emptyAssetManifest.lengthInBytes));
245-
entryKinds[_kAssetManifestBinFilename] = AssetKind.regular;
256+
entries[_kAssetManifestBinFilename] = AssetBundleEntry(
257+
DevFSByteContent(
258+
emptyAssetManifest.buffer.asUint8List(0, emptyAssetManifest.lengthInBytes),
259+
),
260+
kind: AssetKind.regular,
261+
);
246262
// Create .bin.json on web builds.
247263
if (targetPlatform == TargetPlatform.web_javascript) {
248-
entries[_kAssetManifestBinJsonFilename] = DevFSStringContent('""');
249-
entryKinds[_kAssetManifestBinJsonFilename] = AssetKind.regular;
264+
entries[_kAssetManifestBinJsonFilename] = AssetBundleEntry(
265+
DevFSStringContent('""'),
266+
kind: AssetKind.regular,
267+
);
250268
}
251269
return 0;
252270
}
@@ -388,14 +406,16 @@ class ManifestAssetBundle implements AssetBundle {
388406
final File variantFile = variant.lookupAssetFile(_fileSystem);
389407
inputFiles.add(variantFile);
390408
assert(variantFile.existsSync());
391-
entries[variant.entryUri.path] ??= DevFSFileContent(variantFile);
392-
entryKinds[variant.entryUri.path] ??= variant.assetKind;
409+
entries[variant.entryUri.path] ??= AssetBundleEntry(
410+
DevFSFileContent(variantFile),
411+
kind: variant.kind,
412+
);
393413
}
394414
}
395415
// Save the contents of each deferred component image, image variant, and font
396416
// asset in deferredComponentsEntries.
397417
for (final String componentName in deferredComponentsAssetVariants.keys) {
398-
deferredComponentsEntries[componentName] = <String, DevFSContent>{};
418+
deferredComponentsEntries[componentName] = <String, AssetBundleEntry>{};
399419
final Map<_Asset, List<_Asset>> assetsMap = deferredComponentsAssetVariants[componentName]!;
400420
for (final _Asset asset in assetsMap.keys) {
401421
final File assetFile = asset.lookupAssetFile(_fileSystem);
@@ -419,7 +439,10 @@ class ManifestAssetBundle implements AssetBundle {
419439
for (final _Asset variant in assetsMap[asset]!) {
420440
final File variantFile = variant.lookupAssetFile(_fileSystem);
421441
assert(variantFile.existsSync());
422-
deferredComponentsEntries[componentName]![variant.entryUri.path] ??= DevFSFileContent(variantFile);
442+
deferredComponentsEntries[componentName]![variant.entryUri.path] ??= AssetBundleEntry(
443+
DevFSFileContent(variantFile),
444+
kind: AssetKind.regular,
445+
);
423446
}
424447
}
425448
}
@@ -434,8 +457,7 @@ class ManifestAssetBundle implements AssetBundle {
434457
for (final _Asset asset in materialAssets) {
435458
final File assetFile = asset.lookupAssetFile(_fileSystem);
436459
assert(assetFile.existsSync(), 'Missing ${assetFile.path}');
437-
entries[asset.entryUri.path] ??= DevFSFileContent(assetFile);
438-
entryKinds[asset.entryUri.path] ??= asset.assetKind;
460+
entries[asset.entryUri.path] ??= AssetBundleEntry(DevFSFileContent(assetFile), kind: asset.kind);
439461
}
440462

441463
// Update wildcard directories we can detect changes in them.
@@ -487,16 +509,18 @@ class ManifestAssetBundle implements AssetBundle {
487509
@override
488510
List<File> additionalDependencies = <File>[];
489511
void _setIfChanged(String key, DevFSContent content, AssetKind assetKind) {
490-
final DevFSContent? oldContent = entries[key];
512+
final DevFSContent? oldContent = entries[key]?.content;
491513
// In the case that the content is unchanged, we want to avoid an overwrite
492514
// as the isModified property may be reset to true,
493515
if (oldContent is DevFSByteContent && content is DevFSByteContent &&
494516
_compareIntLists(oldContent.bytes, content.bytes)) {
495517
return;
496518
}
497519

498-
entries[key] = content;
499-
entryKinds[key] = assetKind;
520+
entries[key] = AssetBundleEntry(
521+
content,
522+
kind: assetKind,
523+
);
500524
}
501525

502526
static bool _compareIntLists(List<int> o1, List<int> o2) {
@@ -530,16 +554,18 @@ class ManifestAssetBundle implements AssetBundle {
530554
// the uncompressed strings to not incur decompression/decoding while making
531555
// the comparison.
532556
if (!entries.containsKey(_kNoticeZippedFile) ||
533-
(entries[_kNoticeZippedFile] as DevFSStringCompressingBytesContent?)
557+
(entries[_kNoticeZippedFile]?.content as DevFSStringCompressingBytesContent?)
534558
?.equals(combinedLicenses) != true) {
535-
entries[_kNoticeZippedFile] = DevFSStringCompressingBytesContent(
536-
combinedLicenses,
537-
// A zlib dictionary is a hinting string sequence with the most
538-
// likely string occurrences at the end. This ends up just being
539-
// common English words with domain specific words like copyright.
540-
hintString: 'copyrightsoftwaretothisinandorofthe',
559+
entries[_kNoticeZippedFile] = AssetBundleEntry(
560+
DevFSStringCompressingBytesContent(
561+
combinedLicenses,
562+
// A zlib dictionary is a hinting string sequence with the most
563+
// likely string occurrences at the end. This ends up just being
564+
// common English words with domain specific words like copyright.
565+
hintString: 'copyrightsoftwaretothisinandorofthe',
566+
),
567+
kind: AssetKind.regular,
541568
);
542-
entryKinds[_kNoticeZippedFile] = AssetKind.regular;
543569
}
544570
}
545571

@@ -564,7 +590,7 @@ class ManifestAssetBundle implements AssetBundle {
564590
relativeUri: Uri(path: entryUri.pathSegments.last),
565591
entryUri: entryUri,
566592
package: null,
567-
assetKind: AssetKind.font,
593+
kind: AssetKind.font,
568594
));
569595
}
570596
}
@@ -592,7 +618,7 @@ class ManifestAssetBundle implements AssetBundle {
592618
relativeUri: Uri(path: entryUri.pathSegments.last),
593619
entryUri: entryUri,
594620
package: null,
595-
assetKind: AssetKind.shader,
621+
kind: AssetKind.shader,
596622
));
597623
}
598624

@@ -992,7 +1018,7 @@ class ManifestAssetBundle implements AssetBundle {
9921018
entryUri: entryUri,
9931019
relativeUri: relativeUri,
9941020
package: attributedPackage,
995-
assetKind: assetKind,
1021+
kind: assetKind,
9961022
),
9971023
);
9981024
}
@@ -1105,7 +1131,7 @@ class ManifestAssetBundle implements AssetBundle {
11051131
relativeUri: assetUri,
11061132
package: attributedPackage,
11071133
originUri: originUri,
1108-
assetKind: assetKind,
1134+
kind: assetKind,
11091135
flavors: flavors,
11101136
);
11111137
}
@@ -1129,7 +1155,7 @@ class ManifestAssetBundle implements AssetBundle {
11291155
entryUri: assetUri,
11301156
relativeUri: Uri(pathSegments: assetUri.pathSegments.sublist(2)),
11311157
package: attributedPackage,
1132-
assetKind: assetKind,
1158+
kind: assetKind,
11331159
originUri: originUri,
11341160
flavors: flavors,
11351161
);
@@ -1152,7 +1178,7 @@ class _Asset {
11521178
required this.relativeUri,
11531179
required this.entryUri,
11541180
required this.package,
1155-
this.assetKind = AssetKind.regular,
1181+
this.kind = AssetKind.regular,
11561182
List<String>? flavors,
11571183
}): originUri = originUri ?? entryUri, flavors = flavors ?? const <String>[];
11581184

@@ -1171,7 +1197,7 @@ class _Asset {
11711197
/// A platform-independent URL representing the entry for the asset manifest.
11721198
final Uri entryUri;
11731199

1174-
final AssetKind assetKind;
1200+
final AssetKind kind;
11751201

11761202
final List<String> flavors;
11771203

@@ -1224,7 +1250,7 @@ class _Asset {
12241250
&& other.baseDir == baseDir
12251251
&& other.relativeUri == relativeUri
12261252
&& other.entryUri == entryUri
1227-
&& other.assetKind == assetKind
1253+
&& other.kind == kind
12281254
&& hasEquivalentFlavorsWith(other);
12291255
}
12301256

@@ -1233,7 +1259,7 @@ class _Asset {
12331259
baseDir,
12341260
relativeUri,
12351261
entryUri,
1236-
assetKind,
1262+
kind,
12371263
...flavors,
12381264
]);
12391265
}

packages/flutter_tools/lib/src/build_system/targets/assets.dart

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import 'shader_compiler.dart';
2929
Future<Depfile> copyAssets(
3030
Environment environment,
3131
Directory outputDirectory, {
32-
Map<String, DevFSContent>? additionalContent,
32+
Map<String, DevFSContent> additionalContent = const <String, DevFSContent>{},
3333
required TargetPlatform targetPlatform,
3434
BuildMode? buildMode,
3535
required ShaderTarget shaderTarget,
@@ -75,7 +75,7 @@ Future<Depfile> copyAssets(
7575

7676
final IconTreeShaker iconTreeShaker = IconTreeShaker(
7777
environment,
78-
assetBundle.entries[kFontManifestJson] as DevFSStringContent?,
78+
assetBundle.entries[kFontManifestJson]?.content as DevFSStringContent?,
7979
processManager: environment.processManager,
8080
logger: environment.logger,
8181
fileSystem: environment.fileSystem,
@@ -95,18 +95,23 @@ Future<Depfile> copyAssets(
9595
artifacts: environment.artifacts,
9696
);
9797

98-
final Map<String, DevFSContent> assetEntries = <String, DevFSContent>{
98+
final Map<String, AssetBundleEntry> assetEntries = <String, AssetBundleEntry>{
9999
...assetBundle.entries,
100-
...?additionalContent,
100+
...additionalContent.map((String key, DevFSContent value) {
101+
return MapEntry<String, AssetBundleEntry>(
102+
key,
103+
AssetBundleEntry(value, kind: AssetKind.regular),
104+
);
105+
}),
101106
if (skslBundle != null)
102-
kSkSLShaderBundlePath: skslBundle,
103-
};
104-
final Map<String, AssetKind> entryKinds = <String, AssetKind>{
105-
...assetBundle.entryKinds,
107+
kSkSLShaderBundlePath: AssetBundleEntry(
108+
skslBundle,
109+
kind: AssetKind.regular,
110+
),
106111
};
107112

108113
await Future.wait<void>(
109-
assetEntries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
114+
assetEntries.entries.map<Future<void>>((MapEntry<String, AssetBundleEntry> entry) async {
110115
final PoolResource resource = await pool.request();
111116
try {
112117
// This will result in strange looking files, for example files with `/`
@@ -116,14 +121,13 @@ Future<Depfile> copyAssets(
116121
// and the native APIs will look for files this way.
117122
final File file = environment.fileSystem.file(
118123
environment.fileSystem.path.join(outputDirectory.path, entry.key));
119-
final AssetKind assetKind = entryKinds[entry.key] ?? AssetKind.regular;
120124
outputs.add(file);
121125
file.parent.createSync(recursive: true);
122-
final DevFSContent content = entry.value;
126+
final DevFSContent content = entry.value.content;
123127
if (content is DevFSFileContent && content.file is File) {
124128
inputs.add(content.file as File);
125129
bool doCopy = true;
126-
switch (assetKind) {
130+
switch (entry.value.kind) {
127131
case AssetKind.regular:
128132
break;
129133
case AssetKind.font:
@@ -149,7 +153,7 @@ Future<Depfile> copyAssets(
149153
await (content.file as File).copy(file.path);
150154
}
151155
} else {
152-
await file.writeAsBytes(await entry.value.contentsAsBytes());
156+
await file.writeAsBytes(await entry.value.content.contentsAsBytes());
153157
}
154158
} finally {
155159
resource.release();
@@ -161,15 +165,15 @@ Future<Depfile> copyAssets(
161165
// building as debug.
162166
if (environment.defines[kDeferredComponents] == 'true' && buildMode != null) {
163167
await Future.wait<void>(assetBundle.deferredComponentsEntries.entries.map<Future<void>>(
164-
(MapEntry<String, Map<String, DevFSContent>> componentEntries) async {
168+
(MapEntry<String, Map<String, AssetBundleEntry>> componentEntries) async {
165169
final Directory componentOutputDir =
166170
environment.projectDir
167171
.childDirectory('build')
168172
.childDirectory(componentEntries.key)
169173
.childDirectory('intermediates')
170174
.childDirectory('flutter');
171175
await Future.wait<void>(
172-
componentEntries.value.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
176+
componentEntries.value.entries.map<Future<void>>((MapEntry<String, AssetBundleEntry> entry) async {
173177
final PoolResource resource = await pool.request();
174178
try {
175179
// This will result in strange looking files, for example files with `/`
@@ -186,7 +190,7 @@ Future<Depfile> copyAssets(
186190
environment.fileSystem.path.join(outputDirectory.path, entry.key));
187191
outputs.add(file);
188192
file.parent.createSync(recursive: true);
189-
final DevFSContent content = entry.value;
193+
final DevFSContent content = entry.value.content;
190194
if (content is DevFSFileContent && content.file is File) {
191195
inputs.add(content.file as File);
192196
if (!await iconTreeShaker.subsetFont(

0 commit comments

Comments
 (0)