Unverified Commit 9c0f2399 authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

Put shaders under a 'shaders' section in the manifest (#106752)

parent 02f0b2dd
...@@ -63,9 +63,17 @@ abstract class AssetBundleFactory { ...@@ -63,9 +63,17 @@ abstract class AssetBundleFactory {
AssetBundle createBundle(); AssetBundle createBundle();
} }
enum AssetKind {
regular,
font,
shader,
}
abstract class AssetBundle { abstract class AssetBundle {
Map<String, DevFSContent> get entries; Map<String, DevFSContent> get entries;
Map<String, AssetKind> get entryKinds;
/// The files that were specified under the deferred components assets sections /// The files that were specified under the deferred components assets sections
/// in pubspec. /// in pubspec.
Map<String, Map<String, DevFSContent>> get deferredComponentsEntries; Map<String, Map<String, DevFSContent>> get deferredComponentsEntries;
...@@ -135,6 +143,9 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -135,6 +143,9 @@ class ManifestAssetBundle implements AssetBundle {
@override @override
final Map<String, DevFSContent> entries = <String, DevFSContent>{}; final Map<String, DevFSContent> entries = <String, DevFSContent>{};
@override
final Map<String, AssetKind> entryKinds = <String, AssetKind>{};
@override @override
final Map<String, Map<String, DevFSContent>> deferredComponentsEntries = <String, Map<String, DevFSContent>>{}; final Map<String, Map<String, DevFSContent>> deferredComponentsEntries = <String, Map<String, DevFSContent>>{};
...@@ -218,6 +229,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -218,6 +229,7 @@ class ManifestAssetBundle implements AssetBundle {
_lastBuildTimestamp = DateTime.now(); _lastBuildTimestamp = DateTime.now();
if (flutterManifest.isEmpty) { if (flutterManifest.isEmpty) {
entries[_kAssetManifestJson] = DevFSStringContent('{}'); entries[_kAssetManifestJson] = DevFSStringContent('{}');
entryKinds[_kAssetManifestJson] = AssetKind.regular;
return 0; return 0;
} }
...@@ -370,6 +382,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -370,6 +382,7 @@ class ManifestAssetBundle implements AssetBundle {
inputFiles.add(variantFile); inputFiles.add(variantFile);
assert(variantFile.existsSync()); assert(variantFile.existsSync());
entries[variant.entryUri.path] ??= DevFSFileContent(variantFile); entries[variant.entryUri.path] ??= DevFSFileContent(variantFile);
entryKinds[variant.entryUri.path] ??= variant.assetKind;
} }
} }
// Save the contents of each deferred component image, image variant, and font // Save the contents of each deferred component image, image variant, and font
...@@ -418,6 +431,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -418,6 +431,7 @@ class ManifestAssetBundle implements AssetBundle {
final File assetFile = asset.lookupAssetFile(_fileSystem); final File assetFile = asset.lookupAssetFile(_fileSystem);
assert(assetFile.existsSync(), 'Missing ${assetFile.path}'); assert(assetFile.existsSync(), 'Missing ${assetFile.path}');
entries[asset.entryUri.path] ??= DevFSFileContent(assetFile); entries[asset.entryUri.path] ??= DevFSFileContent(assetFile);
entryKinds[asset.entryUri.path] ??= asset.assetKind;
} }
// Update wildcard directories we can detect changes in them. // Update wildcard directories we can detect changes in them.
...@@ -449,8 +463,8 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -449,8 +463,8 @@ class ManifestAssetBundle implements AssetBundle {
_fileSystem.file('DOES_NOT_EXIST_RERUN_FOR_WILDCARD$suffix').absolute); _fileSystem.file('DOES_NOT_EXIST_RERUN_FOR_WILDCARD$suffix').absolute);
} }
_setIfChanged(_kAssetManifestJson, assetManifest); _setIfChanged(_kAssetManifestJson, assetManifest, AssetKind.regular);
_setIfChanged(kFontManifestJson, fontManifest); _setIfChanged(kFontManifestJson, fontManifest, AssetKind.regular);
_setLicenseIfChanged(licenseResult.combinedLicenses, targetPlatform); _setLicenseIfChanged(licenseResult.combinedLicenses, targetPlatform);
return 0; return 0;
} }
...@@ -458,14 +472,16 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -458,14 +472,16 @@ class ManifestAssetBundle implements AssetBundle {
@override @override
List<File> additionalDependencies = <File>[]; List<File> additionalDependencies = <File>[];
void _setIfChanged(String key, DevFSStringContent content) { void _setIfChanged(String key, DevFSStringContent content, AssetKind assetKind) {
if (!entries.containsKey(key)) { if (!entries.containsKey(key)) {
entries[key] = content; entries[key] = content;
entryKinds[key] = assetKind;
return; return;
} }
final DevFSStringContent? oldContent = entries[key] as DevFSStringContent?; final DevFSStringContent? oldContent = entries[key] as DevFSStringContent?;
if (oldContent?.string != content.string) { if (oldContent?.string != content.string) {
entries[key] = content; entries[key] = content;
entryKinds[key] = assetKind;
} }
} }
...@@ -477,7 +493,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -477,7 +493,7 @@ class ManifestAssetBundle implements AssetBundle {
// dart:io to decompress it. So use the standard _setIfChanged to check if // dart:io to decompress it. So use the standard _setIfChanged to check if
// the strings still match. // the strings still match.
if (targetPlatform == TargetPlatform.web_javascript) { if (targetPlatform == TargetPlatform.web_javascript) {
_setIfChanged(_kNoticeFile, DevFSStringContent(combinedLicenses)); _setIfChanged(_kNoticeFile, DevFSStringContent(combinedLicenses), AssetKind.regular);
return; return;
} }
...@@ -495,6 +511,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -495,6 +511,7 @@ class ManifestAssetBundle implements AssetBundle {
// common English words with domain specific words like copyright. // common English words with domain specific words like copyright.
hintString: 'copyrightsoftwaretothisinandorofthe', hintString: 'copyrightsoftwaretothisinandorofthe',
); );
entryKinds[_kNoticeZippedFile] = AssetKind.regular;
} }
} }
...@@ -519,6 +536,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -519,6 +536,7 @@ class ManifestAssetBundle implements AssetBundle {
relativeUri: Uri(path: entryUri.pathSegments.last), relativeUri: Uri(path: entryUri.pathSegments.last),
entryUri: entryUri, entryUri: entryUri,
package: null, package: null,
assetKind: AssetKind.font,
)); ));
} }
} }
...@@ -546,6 +564,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -546,6 +564,7 @@ class ManifestAssetBundle implements AssetBundle {
relativeUri: Uri(path: entryUri.pathSegments.last), relativeUri: Uri(path: entryUri.pathSegments.last),
entryUri: entryUri, entryUri: entryUri,
package: null, package: null,
assetKind: AssetKind.shader,
)); ));
} }
...@@ -745,6 +764,21 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -745,6 +764,21 @@ class ManifestAssetBundle implements AssetBundle {
} }
} }
for (final Uri shaderUri in flutterManifest.shaders) {
_parseAssetFromFile(
packageConfig,
flutterManifest,
assetBase,
cache,
result,
shaderUri,
excludeDirs: excludeDirs,
packageName: packageName,
attributedPackage: attributedPackage,
assetKind: AssetKind.shader,
);
}
// Add assets referenced in the fonts section of the manifest. // Add assets referenced in the fonts section of the manifest.
for (final Font font in flutterManifest.fonts) { for (final Font font in flutterManifest.fonts) {
for (final FontAsset fontAsset in font.fontAssets) { for (final FontAsset fontAsset in font.fontAssets) {
...@@ -754,6 +788,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -754,6 +788,7 @@ class ManifestAssetBundle implements AssetBundle {
fontAsset.assetUri, fontAsset.assetUri,
packageName, packageName,
attributedPackage, attributedPackage,
assetKind: AssetKind.font,
); );
final File baseAssetFile = baseAsset.lookupAssetFile(_fileSystem); final File baseAssetFile = baseAsset.lookupAssetFile(_fileSystem);
if (!baseAssetFile.existsSync()) { if (!baseAssetFile.existsSync()) {
...@@ -816,6 +851,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -816,6 +851,7 @@ class ManifestAssetBundle implements AssetBundle {
List<String> excludeDirs = const <String>[], List<String> excludeDirs = const <String>[],
String? packageName, String? packageName,
Package? attributedPackage, Package? attributedPackage,
AssetKind assetKind = AssetKind.regular,
}) { }) {
final _Asset asset = _resolveAsset( final _Asset asset = _resolveAsset(
packageConfig, packageConfig,
...@@ -823,6 +859,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -823,6 +859,7 @@ class ManifestAssetBundle implements AssetBundle {
assetUri, assetUri,
packageName, packageName,
attributedPackage, attributedPackage,
assetKind: assetKind,
); );
final List<_Asset> variants = <_Asset>[]; final List<_Asset> variants = <_Asset>[];
final File assetFile = asset.lookupAssetFile(_fileSystem); final File assetFile = asset.lookupAssetFile(_fileSystem);
...@@ -839,6 +876,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -839,6 +876,7 @@ class ManifestAssetBundle implements AssetBundle {
entryUri: entryUri, entryUri: entryUri,
relativeUri: relativeUri, relativeUri: relativeUri,
package: attributedPackage, package: attributedPackage,
assetKind: assetKind,
), ),
); );
} }
...@@ -852,8 +890,9 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -852,8 +890,9 @@ class ManifestAssetBundle implements AssetBundle {
String assetsBaseDir, String assetsBaseDir,
Uri assetUri, Uri assetUri,
String? packageName, String? packageName,
Package? attributedPackage, Package? attributedPackage, {
) { AssetKind assetKind = AssetKind.regular,
}) {
final String assetPath = _fileSystem.path.fromUri(assetUri); final String assetPath = _fileSystem.path.fromUri(assetUri);
if (assetUri.pathSegments.first == 'packages' if (assetUri.pathSegments.first == 'packages'
&& !_fileSystem.isFileSync(_fileSystem.path.join(assetsBaseDir, assetPath))) { && !_fileSystem.isFileSync(_fileSystem.path.join(assetsBaseDir, assetPath))) {
...@@ -863,6 +902,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -863,6 +902,7 @@ class ManifestAssetBundle implements AssetBundle {
assetUri, assetUri,
packageConfig, packageConfig,
attributedPackage, attributedPackage,
assetKind: assetKind,
); );
if (packageAsset != null) { if (packageAsset != null) {
return packageAsset; return packageAsset;
...@@ -876,10 +916,16 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -876,10 +916,16 @@ class ManifestAssetBundle implements AssetBundle {
: Uri(pathSegments: <String>['packages', packageName, ...assetUri.pathSegments]), // Asset from, and declared in $packageName. : Uri(pathSegments: <String>['packages', packageName, ...assetUri.pathSegments]), // Asset from, and declared in $packageName.
relativeUri: assetUri, relativeUri: assetUri,
package: attributedPackage, package: attributedPackage,
assetKind: assetKind,
); );
} }
_Asset? _resolvePackageAsset(Uri assetUri, PackageConfig packageConfig, Package? attributedPackage) { _Asset? _resolvePackageAsset(
Uri assetUri,
PackageConfig packageConfig,
Package? attributedPackage, {
AssetKind assetKind = AssetKind.regular,
}) {
assert(assetUri.pathSegments.first == 'packages'); assert(assetUri.pathSegments.first == 'packages');
if (assetUri.pathSegments.length > 1) { if (assetUri.pathSegments.length > 1) {
final String packageName = assetUri.pathSegments[1]; final String packageName = assetUri.pathSegments[1];
...@@ -891,6 +937,7 @@ class ManifestAssetBundle implements AssetBundle { ...@@ -891,6 +937,7 @@ class ManifestAssetBundle implements AssetBundle {
entryUri: assetUri, entryUri: assetUri,
relativeUri: Uri(pathSegments: assetUri.pathSegments.sublist(2)), relativeUri: Uri(pathSegments: assetUri.pathSegments.sublist(2)),
package: attributedPackage, package: attributedPackage,
assetKind: assetKind,
); );
} }
} }
...@@ -910,6 +957,7 @@ class _Asset { ...@@ -910,6 +957,7 @@ class _Asset {
required this.relativeUri, required this.relativeUri,
required this.entryUri, required this.entryUri,
required this.package, required this.package,
this.assetKind = AssetKind.regular,
}); });
final String baseDir; final String baseDir;
...@@ -923,6 +971,8 @@ class _Asset { ...@@ -923,6 +971,8 @@ class _Asset {
/// A platform-independent URL representing the entry for the asset manifest. /// A platform-independent URL representing the entry for the asset manifest.
final Uri entryUri; final Uri entryUri;
final AssetKind assetKind;
File lookupAssetFile(FileSystem fileSystem) { File lookupAssetFile(FileSystem fileSystem) {
return fileSystem.file(fileSystem.path.join(baseDir, fileSystem.path.fromUri(relativeUri))); return fileSystem.file(fileSystem.path.join(baseDir, fileSystem.path.fromUri(relativeUri)));
} }
...@@ -951,7 +1001,8 @@ class _Asset { ...@@ -951,7 +1001,8 @@ class _Asset {
return other is _Asset return other is _Asset
&& other.baseDir == baseDir && other.baseDir == baseDir
&& other.relativeUri == relativeUri && other.relativeUri == relativeUri
&& other.entryUri == entryUri; && other.entryUri == entryUri
&& other.assetKind == assetKind;
} }
@override @override
......
...@@ -88,6 +88,9 @@ Future<Depfile> copyAssets( ...@@ -88,6 +88,9 @@ Future<Depfile> copyAssets(
if (skslBundle != null) if (skslBundle != null)
kSkSLShaderBundlePath: skslBundle, kSkSLShaderBundlePath: skslBundle,
}; };
final Map<String, AssetKind> entryKinds = <String, AssetKind>{
...assetBundle.entryKinds,
};
await Future.wait<void>( await Future.wait<void>(
assetEntries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async { assetEntries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
...@@ -100,19 +103,31 @@ Future<Depfile> copyAssets( ...@@ -100,19 +103,31 @@ Future<Depfile> copyAssets(
// and the native APIs will look for files this way. // and the native APIs will look for files this way.
final File file = environment.fileSystem.file( final File file = environment.fileSystem.file(
environment.fileSystem.path.join(outputDirectory.path, entry.key)); environment.fileSystem.path.join(outputDirectory.path, entry.key));
final AssetKind assetKind = entryKinds[entry.key] ?? AssetKind.regular;
outputs.add(file); outputs.add(file);
file.parent.createSync(recursive: true); file.parent.createSync(recursive: true);
final DevFSContent content = entry.value; final DevFSContent content = entry.value;
if (content is DevFSFileContent && content.file is File) { if (content is DevFSFileContent && content.file is File) {
inputs.add(content.file as File); inputs.add(content.file as File);
if (!await iconTreeShaker.subsetFont( bool doCopy = true;
input: content.file as File, switch (assetKind) {
outputPath: file.path, case AssetKind.regular:
relativePath: entry.key, break;
) && !await shaderCompiler.compileShader( case AssetKind.font:
input: content.file as File, doCopy = !await iconTreeShaker.subsetFont(
outputPath: file.path, input: content.file as File,
)) { outputPath: file.path,
relativePath: entry.key,
);
break;
case AssetKind.shader:
doCopy = !await shaderCompiler.compileShader(
input: content.file as File,
outputPath: file.path,
);
break;
}
if (doCopy) {
await (content.file as File).copy(file.path); await (content.file as File).copy(file.path);
} }
} else { } else {
...@@ -127,8 +142,8 @@ Future<Depfile> copyAssets( ...@@ -127,8 +142,8 @@ Future<Depfile> copyAssets(
// The assets are included in assetBundle.entries as a normal asset when // The assets are included in assetBundle.entries as a normal asset when
// building as debug. // building as debug.
if (environment.defines[kDeferredComponents] == 'true' && buildMode != null) { if (environment.defines[kDeferredComponents] == 'true' && buildMode != null) {
await Future.wait<void>( await Future.wait<void>(assetBundle.deferredComponentsEntries.entries.map<Future<void>>(
assetBundle.deferredComponentsEntries.entries.map<Future<void>>((MapEntry<String, Map<String, DevFSContent>> componentEntries) async { (MapEntry<String, Map<String, DevFSContent>> componentEntries) async {
final Directory componentOutputDir = final Directory componentOutputDir =
environment.projectDir environment.projectDir
.childDirectory('build') .childDirectory('build')
......
...@@ -134,6 +134,7 @@ Future<AssetBundle?> buildAssets({ ...@@ -134,6 +134,7 @@ Future<AssetBundle?> buildAssets({
Future<void> writeBundle( Future<void> writeBundle(
Directory bundleDir, Directory bundleDir,
Map<String, DevFSContent> assetEntries, Map<String, DevFSContent> assetEntries,
Map<String, AssetKind> entryKinds,
{ Logger? loggerOverride } { Logger? loggerOverride }
) async { ) async {
loggerOverride ??= globals.logger; loggerOverride ??= globals.logger;
......
...@@ -477,7 +477,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { ...@@ -477,7 +477,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
} }
if (_needRebuild(assetBundle.entries)) { if (_needRebuild(assetBundle.entries)) {
await writeBundle(globals.fs.directory(globals.fs.path.join('build', 'unit_test_assets')), await writeBundle(globals.fs.directory(globals.fs.path.join('build', 'unit_test_assets')),
assetBundle.entries); assetBundle.entries, assetBundle.entryKinds);
} }
} }
......
...@@ -370,6 +370,33 @@ class FlutterManifest { ...@@ -370,6 +370,33 @@ class FlutterManifest {
return fonts; return fonts;
} }
late final List<Uri> shaders = _extractShaders();
List<Uri> _extractShaders() {
if (!_flutterDescriptor.containsKey('shaders')) {
return <Uri>[];
}
final List<Object?>? shaders = _flutterDescriptor['shaders'] as List<Object?>?;
if (shaders == null) {
return const <Uri>[];
}
final List<Uri> results = <Uri>[];
for (final Object? shader in shaders) {
if (shader is! String || shader == null || shader == '') {
_logger.printError('Shader manifest contains a null or empty uri.');
continue;
}
try {
results.add(Uri(pathSegments: shader.split('/')));
} on FormatException {
_logger.printError('Shader manifest contains invalid uri: $shader.');
}
}
return results;
}
/// Whether a synthetic flutter_gen package should be generated. /// Whether a synthetic flutter_gen package should be generated.
/// ///
/// This can be provided to the [Pub] interface to inject a new entry /// This can be provided to the [Pub] interface to inject a new entry
...@@ -498,7 +525,17 @@ void _validateFlutter(YamlMap? yaml, List<String> errors) { ...@@ -498,7 +525,17 @@ void _validateFlutter(YamlMap? yaml, List<String> errors) {
break; break;
case 'assets': case 'assets':
if (yamlValue is! YamlList) { if (yamlValue is! YamlList) {
errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).');
} else if (yamlValue.isEmpty) {
break;
} else if (yamlValue[0] is! String) {
errors.add(
'Expected "$yamlKey" to be a list of strings, but the first element is $yamlValue (${yamlValue.runtimeType}).',
);
}
break;
case 'shaders':
if (yamlValue is! YamlList) {
errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).'); errors.add('Expected "$yamlKey" to be a list, but got $yamlValue (${yamlValue.runtimeType}).');
} else if (yamlValue.isEmpty) { } else if (yamlValue.isEmpty) {
break; break;
......
...@@ -124,9 +124,10 @@ Future<void> _buildAssets( ...@@ -124,9 +124,10 @@ Future<void> _buildAssets(
throwToolExit('Unable to find assets.', exitCode: 1); throwToolExit('Unable to find assets.', exitCode: 1);
} }
final Map<String, DevFSContent> assetEntries = final Map<String, DevFSContent> assetEntries = Map<String, DevFSContent>.of(
Map<String, DevFSContent>.of(assets.entries); assets.entries,
await writeBundle(globals.fs.directory(assetDir), assetEntries); );
await writeBundle(globals.fs.directory(assetDir), assetEntries, assets.entryKinds);
final String appName = fuchsiaProject.project.manifest.appName; final String appName = fuchsiaProject.project.manifest.appName;
final String outDir = getFuchsiaBuildDirectory(); final String outDir = getFuchsiaBuildDirectory();
......
...@@ -843,6 +843,7 @@ class WebDevFS implements DevFS { ...@@ -843,6 +843,7 @@ class WebDevFS implements DevFS {
await writeBundle( await writeBundle(
globals.fs.directory(getAssetBuildDirectory()), globals.fs.directory(getAssetBuildDirectory()),
bundle.entries, bundle.entries,
bundle.entryKinds,
); );
} }
} }
......
...@@ -308,7 +308,12 @@ flutter: ...@@ -308,7 +308,12 @@ flutter:
..createSync(); ..createSync();
handler.addError(directory, FileSystemOp.delete, const FileSystemException('Expected Error Text')); handler.addError(directory, FileSystemOp.delete, const FileSystemException('Expected Error Text'));
await writeBundle(directory, <String, DevFSContent>{}, loggerOverride: testLogger); await writeBundle(
directory,
<String, DevFSContent>{},
<String, AssetKind>{},
loggerOverride: testLogger,
);
expect(testLogger.warningText, contains('Expected Error Text')); expect(testLogger.warningText, contains('Expected Error Text'));
}); });
...@@ -415,14 +420,19 @@ flutter: ...@@ -415,14 +420,19 @@ flutter:
..writeAsStringSync(r''' ..writeAsStringSync(r'''
name: example name: example
flutter: flutter:
assets: shaders:
- assets/shader.frag - assets/shader.frag
'''); ''');
final AssetBundle bundle = AssetBundleFactory.instance.createBundle(); final AssetBundle bundle = AssetBundleFactory.instance.createBundle();
expect(await bundle.build(packagesPath: '.packages'), 0); expect(await bundle.build(packagesPath: '.packages'), 0);
await writeBundle(output, bundle.entries, loggerOverride: testLogger); await writeBundle(
output,
bundle.entries,
bundle.entryKinds,
loggerOverride: testLogger,
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Artifacts: () => artifacts, Artifacts: () => artifacts,
......
...@@ -632,6 +632,9 @@ class FakeBundle extends AssetBundle { ...@@ -632,6 +632,9 @@ class FakeBundle extends AssetBundle {
@override @override
Map<String, DevFSContent> get entries => <String, DevFSContent>{}; Map<String, DevFSContent> get entries => <String, DevFSContent>{};
@override
Map<String, AssetKind> get entryKinds => <String, AssetKind>{};
@override @override
List<File> get inputFiles => <File>[]; List<File> get inputFiles => <File>[];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment