diff --git a/pkgs/code_assets/CHANGELOG.md b/pkgs/code_assets/CHANGELOG.md index b6993de07..ca01fcf76 100644 --- a/pkgs/code_assets/CHANGELOG.md +++ b/pkgs/code_assets/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.19.5-wip +## 0.20.0-wip - Bump `package:hooks` to 0.20.0. diff --git a/pkgs/code_assets/lib/src/code_assets/config.dart b/pkgs/code_assets/lib/src/code_assets/config.dart index 22ef3b237..0a5d158b1 100644 --- a/pkgs/code_assets/lib/src/code_assets/config.dart +++ b/pkgs/code_assets/lib/src/code_assets/config.dart @@ -185,11 +185,19 @@ final class LinkOutputCodeAssetBuilder { LinkOutputCodeAssetBuilder._(this._output); - /// Adds the given [asset] to the link hook output. - void add(CodeAsset asset) => _output.addEncodedAsset(asset.encode()); + /// Adds the given [asset] to the hook output with [routing]. + void add(CodeAsset asset, {LinkAssetRouting routing = const ToAppBundle()}) => + _output.addEncodedAsset(asset.encode(), routing: routing); - /// Adds the given [assets] to the link hook output. - void addAll(Iterable assets) => assets.forEach(add); + /// Adds the given [assets] to the hook output with [routing]. + void addAll( + Iterable assets, { + LinkAssetRouting routing = const ToAppBundle(), + }) { + for (final asset in assets) { + add(asset, routing: routing); + } + } } /// Extension to initialize code specific configuration on link/build inputs. diff --git a/pkgs/code_assets/lib/src/code_assets/validation.dart b/pkgs/code_assets/lib/src/code_assets/validation.dart index 58cba0b67..a62999316 100644 --- a/pkgs/code_assets/lib/src/code_assets/validation.dart +++ b/pkgs/code_assets/lib/src/code_assets/validation.dart @@ -91,8 +91,7 @@ Future validateCodeAssetBuildOutput( output.assets.encodedAssets, [ ...output.assets.encodedAssetsForBuild, - for (final assetList in output.assets.encodedAssetsForLinking.values) - ...assetList, + ...output.assets.encodedAssetsForLinking.values.expand((assets) => assets), ], output, true, @@ -106,7 +105,7 @@ Future validateCodeAssetLinkOutput( input, input.config.code, output.assets.encodedAssets, - [], + output.assets.encodedAssetsForLink.values.expand((assets) => assets), output, false, ); @@ -135,8 +134,8 @@ Future validateCodeAssetInApplication( Future _validateCodeAssetBuildOrLinkOutput( HookInput input, CodeConfig codeConfig, - List encodedAssetsBundled, - List encodedAssetsNotBundled, + Iterable encodedAssetsBundled, + Iterable encodedAssetsNotBundled, HookOutput output, bool isBuild, ) async { diff --git a/pkgs/code_assets/pubspec.yaml b/pkgs/code_assets/pubspec.yaml index 15bba27ca..5b27b9771 100644 --- a/pkgs/code_assets/pubspec.yaml +++ b/pkgs/code_assets/pubspec.yaml @@ -3,7 +3,7 @@ description: >- This library contains the hook protocol specification for bundling native code with Dart packages. -version: 0.19.5-wip +version: 0.20.0-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/code_assets diff --git a/pkgs/code_assets/test/code_assets/config_test.dart b/pkgs/code_assets/test/code_assets/config_test.dart index 335ce4956..b3d622259 100644 --- a/pkgs/code_assets/test/code_assets/config_test.dart +++ b/pkgs/code_assets/test/code_assets/config_test.dart @@ -87,6 +87,17 @@ void main() async { 'extensions': {'code_assets': codeConfig}, if (hookType == 'build') 'linking_enabled': false, }, + if (hookType == 'link') + 'assets_from_linking': [ + { + 'type': 'code_assets/code', + 'encoding': { + 'file': 'not there', + 'id': 'package:my_package/name2', + 'link_mode': {'type': 'dynamic_loading_bundle'}, + }, + }, + ], 'out_dir_shared': outputDirectoryShared.toFilePath(), 'out_file': outFile.toFilePath(), 'package_name': packageName, @@ -168,7 +179,18 @@ void main() async { outputFile: outFile, outputDirectoryShared: outputDirectoryShared, ) - ..setupLink(assets: assets, recordedUsesFile: null) + ..setupLink( + assets: assets, + recordedUsesFile: null, + assetsFromLinking: [ + CodeAsset( + name: 'name2', + package: 'my_package', + file: Uri.file('not there'), + linkMode: DynamicLoadingBundled(), + ).encode(), + ], + ) ..addExtension( CodeAssetExtension( targetOS: OS.android, @@ -286,9 +308,29 @@ void main() async { predicate( (e) => e is FormatException && - e.message.contains( - "No value was provided for 'assets.0.encoding.link_mode'.", - ), + e.message.contains(""" +No value was provided for 'assets.0.encoding.link_mode'."""), + ), + ), + ); + }); + + test('LinkInput.assets_from_linking.0.encoding.key missing', () { + final input = inputJson(hookType: 'link'); + traverseJson>(input, [ + 'assets_from_linking', + 0, + 'encoding', + ]).remove('link_mode'); + expect( + () => + LinkInput(input).assets.assetsFromLinking.first.asCodeAsset.linkMode, + throwsA( + predicate( + (e) => + e is FormatException && + e.message.contains(""" +No value was provided for 'assets_from_linking.0.encoding.link_mode'."""), ), ), ); diff --git a/pkgs/data_assets/CHANGELOG.md b/pkgs/data_assets/CHANGELOG.md index 5d3b33274..7bf91a504 100644 --- a/pkgs/data_assets/CHANGELOG.md +++ b/pkgs/data_assets/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.19.2-wip +## 0.20.0-wip - Bump `package:hooks` to 0.20.0. diff --git a/pkgs/data_assets/lib/src/data_assets/config.dart b/pkgs/data_assets/lib/src/data_assets/config.dart index f8bddcf34..4e72b2f20 100644 --- a/pkgs/data_assets/lib/src/data_assets/config.dart +++ b/pkgs/data_assets/lib/src/data_assets/config.dart @@ -27,10 +27,23 @@ extension BuildOutputBuilderAddDataAssetsDirectories on BuildOutputBuilder { List paths, { required BuildInput input, bool recursive = false, + AssetRouting routing = const ToAppBundle(), }) async { String assetName(Uri assetUri) => assetUri .toFilePath(windows: false) - .substring(input.packageRoot.toFilePath().length); + .substring(input.packageRoot.toFilePath(windows: false).length); + + void addAsset(File file) { + assets.data.add( + DataAsset( + package: input.packageName, + name: assetName(file.uri), + file: file.uri, + ), + routing: routing, + ); + addDependency(file.uri); + } for (final path in paths) { final resolvedUri = input.packageRoot.resolve(path); @@ -45,15 +58,10 @@ extension BuildOutputBuilderAddDataAssetsDirectories on BuildOutputBuilder { followLinks: false, )) { if (entity is File) { - assets.data.add( - DataAsset( - package: input.packageName, - name: assetName(entity.uri), - file: entity.uri, - ), - ); + addAsset(entity); + } else { + addDependency(entity.uri); } - addDependency(entity.uri); } } on FileSystemException catch (e) { throw FileSystemException( @@ -63,14 +71,7 @@ extension BuildOutputBuilderAddDataAssetsDirectories on BuildOutputBuilder { ); } } else if (await file.exists()) { - assets.data.add( - DataAsset( - package: input.packageName, - name: assetName(file.uri), - file: file.uri, - ), - ); - addDependency(file.uri); + addAsset(file); } else { throw FileSystemException( 'Path does not exist', @@ -140,10 +141,18 @@ final class LinkOutputDataAssetsBuilder { LinkOutputDataAssetsBuilder(this._output); /// Adds the given [asset] to the link hook output. - void add(DataAsset asset) => _output.addEncodedAsset(asset.encode()); + void add(DataAsset asset, {LinkAssetRouting routing = const ToAppBundle()}) => + _output.addEncodedAsset(asset.encode(), routing: routing); /// Adds the given [assets] to the link hook output. - void addAll(Iterable assets) => assets.forEach(add); + void addAll( + Iterable assets, { + LinkAssetRouting routing = const ToAppBundle(), + }) { + for (final asset in assets) { + add(asset, routing: routing); + } + } } /// Provides access to [DataAsset]s from a build hook output. diff --git a/pkgs/data_assets/pubspec.yaml b/pkgs/data_assets/pubspec.yaml index 5a98235d1..501acc0ea 100644 --- a/pkgs/data_assets/pubspec.yaml +++ b/pkgs/data_assets/pubspec.yaml @@ -3,7 +3,7 @@ description: >- This library contains the hook protocol specification for bundling data assets with Dart packages. -version: 0.19.2-wip +version: 0.20.0-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/data_assets diff --git a/pkgs/hooks/CHANGELOG.md b/pkgs/hooks/CHANGELOG.md index d21fd8391..2af051d0b 100644 --- a/pkgs/hooks/CHANGELOG.md +++ b/pkgs/hooks/CHANGELOG.md @@ -2,6 +2,8 @@ * **Breaking change** Rename `EncodedAsset.jsonPath` to `EncodedAsset.encodingJsonPath`. This field only governs the `EncodedAsset.encoding` field, not the whole object. +* Enable passing metadata from link hooks of a package to the link hooks in + dependencies, by fixing the link hook execution order. ## 0.19.5 diff --git a/pkgs/hooks/doc/schema/shared/shared_definitions.schema.json b/pkgs/hooks/doc/schema/shared/shared_definitions.schema.json index bb8805c6f..4cc378269 100644 --- a/pkgs/hooks/doc/schema/shared/shared_definitions.schema.json +++ b/pkgs/hooks/doc/schema/shared/shared_definitions.schema.json @@ -92,15 +92,6 @@ "items": { "$ref": "#/definitions/Asset" } - }, - "assets_for_linking": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/definitions/Asset" - } - } } }, "allOf": [ @@ -206,6 +197,15 @@ "$ref": "#/definitions/Asset" } }, + "assets_for_linking": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/Asset" + } + } + }, "dependencies": { "type": "array", "items": { @@ -250,6 +250,12 @@ "$ref": "#/definitions/Asset" } }, + "assets_from_linking": { + "type": "array", + "items": { + "$ref": "#/definitions/Asset" + } + }, "resource_identifiers": { "$ref": "#/definitions/absolutePath" } @@ -261,6 +267,7 @@ ] }, "LinkOutput": { + "type": "object", "allOf": [ { "$ref": "#/definitions/HookOutput" diff --git a/pkgs/hooks/lib/hooks.dart b/pkgs/hooks/lib/hooks.dart index 82bf86dd6..fa0f67da0 100644 --- a/pkgs/hooks/lib/hooks.dart +++ b/pkgs/hooks/lib/hooks.dart @@ -41,6 +41,7 @@ export 'src/config.dart' HookOutputBuilder, HookOutputFailure, InfraError, + LinkAssetRouting, LinkConfig, LinkConfigBuilder, LinkInput, @@ -52,6 +53,7 @@ export 'src/config.dart' LinkOutputBuilder, LinkOutputFailure, LinkOutputMaybeFailure, + LinkOutputMetadataBuilder, PackageMetadata, ToAppBundle, ToBuildHooks, diff --git a/pkgs/hooks/lib/src/config.dart b/pkgs/hooks/lib/src/config.dart index 213e0f537..1bd38906d 100644 --- a/pkgs/hooks/lib/src/config.dart +++ b/pkgs/hooks/lib/src/config.dart @@ -328,10 +328,7 @@ final class BuildConfigBuilder extends HookConfigBuilder { /// The input for a `hook/link.dart`. final class LinkInput extends HookInput { - List get _encodedAssets { - final assets = _syntaxLinkInput.assets; - return EncodedAssetSyntax._fromSyntax(assets); - } + List get _encodedAssets => assets.encodedAssets; /// The file containing recorded usages, if any. Uri? get recordedUsagesFile => _syntaxLinkInput.resourceIdentifiers; @@ -352,6 +349,14 @@ final class LinkInput extends HookInput { /// The assets passed to `hook/link.dart`. LinkInputAssets get assets => LinkInputAssets._(this); + + /// The metadata sent to this link hook by dependent link hooks. + Map get metadata => Map.fromEntries( + assets.assetsFromLinking + .where((e) => e.isMetadataAsset) + .map((e) => e.asMetadataAsset) + .map((e) => MapEntry(e.key, e.value)), + ); } /// The assets in [LinkInput.assets]; @@ -361,7 +366,12 @@ final class LinkInputAssets { LinkInputAssets._(this._input); /// The encoded assets passed to `hook/link.dart`. - List get encodedAssets => _input._encodedAssets; + List get encodedAssets => + EncodedAssetSyntax._fromSyntax(_input._syntaxLinkInput.assets); + + /// The encoded assets from direct dependencies. + List get assetsFromLinking => + EncodedAssetSyntax._fromSyntax(_input._syntaxLinkInput.assetsFromLinking); } /// The builder for [LinkInput]. @@ -372,10 +382,14 @@ final class LinkInputBuilder extends HookInputBuilder { /// Sets up the link input. void setupLink({ required List assets, + required List assetsFromLinking, required Uri? recordedUsesFile, }) { _syntax.setup( assets: [for (final asset in assets) asset.toSyntax()], + assetsFromLinking: [ + for (final asset in assetsFromLinking) asset.toSyntax(), + ], resourceIdentifiers: recordedUsesFile, ); } @@ -461,6 +475,7 @@ sealed class HookOutputBuilder { dependencies: null, status: OutputStatusSyntax.success, failureDetails: null, + assetsForLinking: {}, ); /// The JSON representation of this hook output builder. @@ -607,19 +622,47 @@ final class BuildOutputMetadataBuilder { } } +/// The builder for [LinkOutputBuilder.metadata]. +final class LinkOutputMetadataBuilder { + final LinkOutputBuilder _output; + + LinkOutputMetadataBuilder._(this._output); + + /// Sets the metadata [value] for the given [key] to be sent to [packageName]. + void add(String packageName, String key, Object value) { + _output.assets.addEncodedAsset( + MetadataAsset(key: key, value: value).encode(), + routing: ToLinkHook(packageName), + ); + } + + /// Adds all entries from [metadata] to be sent to [packageName]. + void addAll(String packageName, Map metadata) { + metadata.forEach((key, value) => add(packageName, key, value)); + } +} + /// The destination for assets in the [BuildOutput]. /// /// Currently supported routings: /// * [ToBuildHooks]: From build hook to all dependent builds hooks. /// * [ToLinkHook]: From build hook to a specific link hook. -/// * [ToAppBundle]: From build or link hook to the application Bundle. -sealed class AssetRouting { - const AssetRouting(); -} +/// * [ToAppBundle]: From build hook to the application Bundle. +sealed class AssetRouting {} + +/// The destination for assets in the [LinkOutput]. +/// +/// An asset can be either sent to other link hooks with [ToLinkHook] or +/// directly to the application Bundle with [ToAppBundle]. +/// +/// Currently supported routings: +/// * [ToLinkHook]: From link hook to another depending link hook. +/// * [ToAppBundle]: From link hook to the application Bundle. +sealed class LinkAssetRouting {} -/// Assets with this [AssetRouting] in the [BuildOutput] will be sent to the SDK +/// Assets with this [AssetRouting] in the [HookOutput] will be sent to the SDK /// to be bundled with the app. -final class ToAppBundle extends AssetRouting { +final class ToAppBundle implements AssetRouting, LinkAssetRouting { /// Creates a [ToAppBundle]. const ToAppBundle(); } @@ -638,12 +681,12 @@ final class ToAppBundle extends AssetRouting { /// The receiver will know about sender package (it must be a direct /// dependency), the sender does not know about the receiver. Hence this routing /// is a broadcast with 0-N receivers. -final class ToBuildHooks extends AssetRouting { +final class ToBuildHooks implements AssetRouting { /// Creates a [ToBuildHooks]. const ToBuildHooks(); } -/// Assets with this [AssetRouting] in the [BuildOutput] will be sent to the +/// Assets with this [AssetRouting] in the [HookOutput] will be sent to the /// link hook of [packageName]. /// /// The assets are only available to the link hook of [packageName]. @@ -654,7 +697,7 @@ final class ToBuildHooks extends AssetRouting { /// The receiver will not know about the sender package. The sender knows about /// the receiver package. Hence, the receiver must be specified and there is /// exactly one receiver. -final class ToLinkHook extends AssetRouting { +final class ToLinkHook implements AssetRouting, LinkAssetRouting { /// The name of the package that contains the `hook/link.dart` to which assets /// should be sent. final String packageName; @@ -757,6 +800,20 @@ final class BuildOutputAssetsBuilder { /// /// See [LinkOutputFailure] for failure. final class LinkOutput extends HookOutput implements LinkOutputMaybeFailure { + /// The assets produced by this link hook which are routed to link hooks in + /// other packages. + /// + /// These can only be the packages which are direct dependencies of the + /// current package. + /// Every key in the map is a package name. These assets in the values are not + /// bundled with the application, but are sent to the link hook of the package + /// specified in the key, which can decide what to do with them. + Map> get _encodedAssetsForLink => { + for (final MapEntry(:key, :value) + in (_syntax.assetsForLinking ?? {}).entries) + key: EncodedAssetSyntax._fromSyntax(value), + }; + /// Creates a [LinkOutput] from the given [json]. LinkOutput(super.json) : _syntax = LinkOutputSyntax.fromJson(json), super._(); @@ -775,6 +832,12 @@ final class LinkOutputAssets { /// The assets produced by this build. List get encodedAssets => _output._encodedAssets; + + /// The assets produced by this link hook sent to a specific link hook. + /// + /// The key of the map is the package name of the destination link hook. + Map> get encodedAssetsForLink => + _output._encodedAssetsForLink; } /// The builder for [LinkOutput]. @@ -792,6 +855,9 @@ final class LinkOutputAssets { /// } /// ``` final class LinkOutputBuilder extends HookOutputBuilder { + /// The metadata builder for this link output. + LinkOutputMetadataBuilder get metadata => LinkOutputMetadataBuilder._(this); + /// The assets builder for this link output. LinkOutputAssetsBuilder get assets => LinkOutputAssetsBuilder._(this); @@ -818,10 +884,22 @@ final class LinkOutputAssetsBuilder { /// }); /// } /// ``` - void addEncodedAsset(EncodedAsset asset) { - final list = _syntax.assets ?? []; - list.add(asset.toSyntax()); - _syntax.assets = list; + void addEncodedAsset( + EncodedAsset asset, { + LinkAssetRouting routing = const ToAppBundle(), + }) { + switch (routing) { + case ToAppBundle(): + final assets = _syntax.assets ?? []; + assets.add(asset.toSyntax()); + _syntax.assets = assets; + case ToLinkHook(): + final packageName = routing.packageName; + final assetsForLinking = _syntax.assetsForLinking ?? {}; + assetsForLinking[packageName] ??= []; + assetsForLinking[packageName]!.add(asset.toSyntax()); + _syntax.assetsForLinking = assetsForLinking; + } } /// Adds [EncodedAsset]s produced by this build. @@ -837,12 +915,26 @@ final class LinkOutputAssetsBuilder { /// }); /// } /// ``` - void addEncodedAssets(Iterable assets) { - final list = _syntax.assets ?? []; - for (final asset in assets) { - list.add(asset.toSyntax()); + void addEncodedAssets( + Iterable assets, { + LinkAssetRouting routing = const ToAppBundle(), + }) { + switch (routing) { + case ToAppBundle(): + final list = _syntax.assets ?? []; + for (final asset in assets) { + list.add(asset.toSyntax()); + } + _syntax.assets = list; + case ToLinkHook(): + final linkInPackage = routing.packageName; + final assetsForLinking = _syntax.assetsForLinking ?? {}; + final list = assetsForLinking[linkInPackage] ??= []; + for (final asset in assets) { + list.add(asset.toSyntax()); + } + _syntax.assetsForLinking = assetsForLinking; } - _syntax.assets = list; } LinkOutputSyntax get _syntax => diff --git a/pkgs/hooks/lib/src/hooks/syntax.g.dart b/pkgs/hooks/lib/src/hooks/syntax.g.dart index ab359a241..5869f8376 100644 --- a/pkgs/hooks/lib/src/hooks/syntax.g.dart +++ b/pkgs/hooks/lib/src/hooks/syntax.g.dart @@ -222,7 +222,7 @@ class BuildOutputSyntax extends HookOutputSyntax { BuildOutputSyntax({ required super.assets, required List? assetsForBuild, - required Map>? assetsForLinking, + required super.assetsForLinking, required super.dependencies, required super.failureDetails, required super.status, @@ -230,18 +230,13 @@ class BuildOutputSyntax extends HookOutputSyntax { super.path = const [], }) : super() { this.assetsForBuild = assetsForBuild; - this.assetsForLinking = assetsForLinking; json.sortOnKey(); } /// Setup all fields for [BuildOutputSyntax] that are not in /// [HookOutputSyntax]. - void setup({ - required List? assetsForBuild, - required Map>? assetsForLinking, - }) { + void setup({required List? assetsForBuild}) { this.assetsForBuild = assetsForBuild; - this.assetsForLinking = assetsForLinking; json.sortOnKey(); } @@ -280,60 +275,10 @@ class BuildOutputSyntax extends HookOutputSyntax { return [for (final element in elements) ...element.validate()]; } - Map>? get assetsForLinking { - final jsonValue = _reader.optionalMap('assets_for_linking'); - if (jsonValue == null) { - return null; - } - final result = >{}; - for (final MapEntry(:key, :value) in jsonValue.entries) { - result[key] = [ - for (final (index, item) in (value as List).indexed) - AssetSyntax.fromJson( - item as Map, - path: [...path, key, index], - ), - ]; - } - return result; - } - - set assetsForLinking(Map>? value) { - _checkArgumentMapKeys(value); - if (value == null) { - json.remove('assets_for_linking'); - } else { - json['assets_for_linking'] = { - for (final MapEntry(:key, :value) in value.entries) - key: [for (final item in value) item.json], - }; - } - json.sortOnKey(); - } - - List _validateAssetsForLinking() { - final mapErrors = _reader.validateOptionalMap('assets_for_linking'); - if (mapErrors.isNotEmpty) { - return mapErrors; - } - final jsonValue = _reader.optionalMap('assets_for_linking'); - if (jsonValue == null) { - return []; - } - final result = []; - for (final list in assetsForLinking!.values) { - for (final element in list) { - result.addAll(element.validate()); - } - } - return result; - } - @override List validate() => [ ...super.validate(), ..._validateAssetsForBuild(), - ..._validateAssetsForLinking(), ..._validateExtraRulesBuildOutput(), ]; @@ -584,6 +529,7 @@ class HookOutputSyntax extends JsonObjectSyntax { HookOutputSyntax({ required List? assets, + required Map>? assetsForLinking, required List? dependencies, required FailureSyntax? failureDetails, required OutputStatusSyntax? status, @@ -591,6 +537,7 @@ class HookOutputSyntax extends JsonObjectSyntax { super.path = const [], }) : super() { this.assets = assets; + this.assetsForLinking = assetsForLinking; this.dependencies = dependencies; this.failureDetails = failureDetails; this.status = status; @@ -633,6 +580,55 @@ class HookOutputSyntax extends JsonObjectSyntax { return [for (final element in elements) ...element.validate()]; } + Map>? get assetsForLinking { + final jsonValue = _reader.optionalMap('assets_for_linking'); + if (jsonValue == null) { + return null; + } + final result = >{}; + for (final MapEntry(:key, :value) in jsonValue.entries) { + result[key] = [ + for (final (index, item) in (value as List).indexed) + AssetSyntax.fromJson( + item as Map, + path: [...path, key, index], + ), + ]; + } + return result; + } + + set assetsForLinking(Map>? value) { + _checkArgumentMapKeys(value); + if (value == null) { + json.remove('assets_for_linking'); + } else { + json['assets_for_linking'] = { + for (final MapEntry(:key, :value) in value.entries) + key: [for (final item in value) item.json], + }; + } + json.sortOnKey(); + } + + List _validateAssetsForLinking() { + final mapErrors = _reader.validateOptionalMap('assets_for_linking'); + if (mapErrors.isNotEmpty) { + return mapErrors; + } + final jsonValue = _reader.optionalMap('assets_for_linking'); + if (jsonValue == null) { + return []; + } + final result = []; + for (final list in assetsForLinking!.values) { + for (final element in list) { + result.addAll(element.validate()); + } + } + return result; + } + List? get dependencies => _reader.optionalPathList('dependencies'); set dependencies(List? value) { @@ -693,6 +689,7 @@ class HookOutputSyntax extends JsonObjectSyntax { List validate() => [ ...super.validate(), ..._validateAssets(), + ..._validateAssetsForLinking(), ..._validateDependencies(), ..._validateFailureDetails(), ..._validateStatus(), @@ -755,6 +752,7 @@ class LinkInputSyntax extends HookInputSyntax { LinkInputSyntax({ required List? assets, + required List? assetsFromLinking, required super.config, required super.outDirShared, required super.outFile, @@ -765,6 +763,7 @@ class LinkInputSyntax extends HookInputSyntax { super.path = const [], }) : super() { _assets = assets; + _assetsFromLinking = assetsFromLinking; _resourceIdentifiers = resourceIdentifiers; json.sortOnKey(); } @@ -773,9 +772,11 @@ class LinkInputSyntax extends HookInputSyntax { /// [HookInputSyntax]. void setup({ required List? assets, + required List? assetsFromLinking, required Uri? resourceIdentifiers, }) { _assets = assets; + _assetsFromLinking = assetsFromLinking; _resourceIdentifiers = resourceIdentifiers; json.sortOnKey(); } @@ -814,6 +815,40 @@ class LinkInputSyntax extends HookInputSyntax { return [for (final element in elements) ...element.validate()]; } + List? get assetsFromLinking { + final jsonValue = _reader.optionalList('assets_from_linking'); + if (jsonValue == null) return null; + return [ + for (final (index, element) in jsonValue.indexed) + AssetSyntax.fromJson( + element as Map, + path: [...path, 'assets_from_linking', index], + ), + ]; + } + + set _assetsFromLinking(List? value) { + if (value == null) { + json.remove('assets_from_linking'); + } else { + json['assets_from_linking'] = [for (final item in value) item.json]; + } + } + + List _validateAssetsFromLinking() { + final listErrors = _reader.validateOptionalList>( + 'assets_from_linking', + ); + if (listErrors.isNotEmpty) { + return listErrors; + } + final elements = assetsFromLinking; + if (elements == null) { + return []; + } + return [for (final element in elements) ...element.validate()]; + } + Uri? get resourceIdentifiers => _reader.optionalPath('resource_identifiers'); set _resourceIdentifiers(Uri? value) { @@ -827,6 +862,7 @@ class LinkInputSyntax extends HookInputSyntax { List validate() => [ ...super.validate(), ..._validateAssets(), + ..._validateAssetsFromLinking(), ..._validateResourceIdentifiers(), ]; @@ -839,6 +875,7 @@ class LinkOutputSyntax extends HookOutputSyntax { LinkOutputSyntax({ required super.assets, + required super.assetsForLinking, required super.dependencies, required super.failureDetails, required super.status, diff --git a/pkgs/hooks/pubspec.yaml b/pkgs/hooks/pubspec.yaml index 8a29fed86..e4e218e7d 100644 --- a/pkgs/hooks/pubspec.yaml +++ b/pkgs/hooks/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: dev_dependencies: args: ^2.6.0 - code_assets: ^0.19.5-wip # Used for running tests with real asset types. + code_assets: ^0.20.0-wip # Used for running tests with real asset types. custom_lint: ^0.7.5 dart_flutter_team_lints: ^3.5.2 data_assets: any # Used for running tests with real asset types. diff --git a/pkgs/hooks/test/data/link_input.json b/pkgs/hooks/test/data/link_input.json index 6bcfbc0dd..e525f3d79 100644 --- a/pkgs/hooks/test/data/link_input.json +++ b/pkgs/hooks/test/data/link_input.json @@ -13,6 +13,15 @@ "type": "hooks/metadata" } ], + "assets_from_linking": [ + { + "encoding": { + "key": "foo", + "value": "bar" + }, + "type": "hooks/metadata" + } + ], "config": { "build_asset_types": [ "some_asset_type", diff --git a/pkgs/hooks/test/data/link_output.json b/pkgs/hooks/test/data/link_output.json index f9686b8a7..26af6b19b 100644 --- a/pkgs/hooks/test/data/link_output.json +++ b/pkgs/hooks/test/data/link_output.json @@ -10,6 +10,23 @@ "type": "some_other_asset_type" } ], + "assets_for_linking": { + "package_with_linker": [ + { + "encoding": { + "a_key": "some_value" + }, + "type": "some_asset_type" + }, + { + "encoding": { + "key": "foo", + "value": "bar" + }, + "type": "hooks/metadata" + } + ] + }, "dependencies": [ "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_2.json", "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_3.json" diff --git a/pkgs/hooks/test/link_input_test.dart b/pkgs/hooks/test/link_input_test.dart index 48d6254f0..25925702b 100644 --- a/pkgs/hooks/test/link_input_test.dart +++ b/pkgs/hooks/test/link_input_test.dart @@ -34,6 +34,7 @@ void main() async { 'config': { 'build_asset_types': ['asset-type-1', 'asset-type-2'], }, + 'assets_from_linking': [], 'out_dir_shared': outputDirectoryShared.toFilePath(), 'out_file': outFile.toFilePath(), 'package_name': packageName, @@ -50,7 +51,11 @@ void main() async { outputDirectoryShared: outputDirectoryShared, ) ..config.addBuildAssetTypes(['asset-type-1', 'asset-type-2']) - ..setupLink(assets: assets, recordedUsesFile: null); + ..setupLink( + assets: assets, + recordedUsesFile: null, + assetsFromLinking: [], + ); final input = inputBuilder.build(); expect(input.json, inputJson); diff --git a/pkgs/hooks_runner/CHANGELOG.md b/pkgs/hooks_runner/CHANGELOG.md index 72b5619cd..fcdc76aa8 100644 --- a/pkgs/hooks_runner/CHANGELOG.md +++ b/pkgs/hooks_runner/CHANGELOG.md @@ -1,6 +1,13 @@ -## 0.21.1-wip - -- Bump `package:hooks` to 0.20.0. +## 0.22.0-wip + +* Bump `package:hooks` to 0.20.0. +* Enable passing metadata from link hooks of a package to the link hooks in + depending packages, by fixing the link hook execution order. This brings an + order in which the link hooks are run - reverse to the build hook run order. + Starting at the application link hook, then it's dependencies, and so on. This + enables us to pass information from on link hook to another as + `MetadataAsset`s - but also means that now link hooks must be invoked, + regardless of whether assets are sent to the from a build hook. ## 0.21.0 diff --git a/pkgs/hooks_runner/lib/src/build_runner/build_planner.dart b/pkgs/hooks_runner/lib/src/build_runner/build_planner.dart index 3c8347434..3aba59476 100644 --- a/pkgs/hooks_runner/lib/src/build_runner/build_planner.dart +++ b/pkgs/hooks_runner/lib/src/build_runner/build_planner.dart @@ -112,6 +112,7 @@ class NativeAssetsBuildPlanner { } BuildPlan? _buildHookPlan; + BuildPlan? _linkHookPlan; /// Plans in what order to run build hooks. /// @@ -126,40 +127,84 @@ class NativeAssetsBuildPlanner { /// hooks, the [Result] is a [Failure] containing a /// [HooksRunnerFailure.projectConfig]. Future> makeBuildHookPlan() async => - _timeAsync('BuildPlanner.makeBuildHookPlan', () async { - if (_buildHookPlan != null) return Success(_buildHookPlan!); - final packagesWithNativeAssets = await packagesWithHook(Hook.build); - if (packagesWithNativeAssets.isEmpty) { - // Avoid calculating the package graph if there are no hooks. - return const Success([]); - } - final packageMap = { - for (final package in packagesWithNativeAssets) package.name: package, - }; - final packagesToBuild = packageMap.keys.toSet(); - final stronglyConnectedComponents = packageGraph - .computeStrongComponents(); - final result = []; - for (final stronglyConnectedComponent in stronglyConnectedComponents) { - final stronglyConnectedComponentWithNativeAssets = [ - for (final packageName in stronglyConnectedComponent) - if (packagesToBuild.contains(packageName)) packageName, - ]; - if (stronglyConnectedComponentWithNativeAssets.length > 1) { - logger.severe( - 'Cyclic dependency for native asset builds in the following ' - 'packages: $stronglyConnectedComponentWithNativeAssets.', - ); - return const Failure(HooksRunnerFailure.projectConfig); - } else if (stronglyConnectedComponentWithNativeAssets.length == 1) { - result.add( - packageMap[stronglyConnectedComponentWithNativeAssets.single]!, - ); - } - } - _buildHookPlan = result; - return Success(result); - }); + _timeAsync( + 'BuildPlanner.makeBuildHookPlan', + () async => _makeHookPlan( + hookType: Hook.build, + cachedPlan: _buildHookPlan, + setCachedPlan: (plan) => _buildHookPlan = plan, + reverseOrder: false, + ), + ); + + /// Plans in what order to run link hooks. + /// + /// [PackageLayout.runPackageName] provides the entry-point in the graph. The + /// hooks of packages not in the transitive dependencies of + /// [PackageLayout.runPackageName] will not be run. + /// + /// Returns a [Future] that completes with a [Result]. On success, the + /// [Result] is a [Success] containing the [BuildPlan], which is a list of + /// packages in the order their link hooks should be executed. On failure, if + /// a cyclic dependency is detected among packages with native asset link + /// hooks, the [Result] is a [Failure] containing a + /// [HooksRunnerFailure.projectConfig]. + Future> makeLinkHookPlan() async => + _timeAsync( + 'BuildPlanner.makeLinkHookPlan', + () async => _makeHookPlan( + hookType: Hook.link, + cachedPlan: _linkHookPlan, + setCachedPlan: (plan) => _linkHookPlan = plan, + reverseOrder: true, // Key difference from [makeBuildHookPlan] + ), + ); + + Future> _makeHookPlan({ + required Hook hookType, + required BuildPlan? cachedPlan, + required void Function(BuildPlan) setCachedPlan, + required bool reverseOrder, + }) async { + if (cachedPlan != null) return Success(cachedPlan); + + final packagesWithNativeAssets = await packagesWithHook(hookType); + if (packagesWithNativeAssets.isEmpty) { + return const Success([]); + } + + final packageMap = { + for (final package in packagesWithNativeAssets) package.name: package, + }; + final packagesToProcess = packageMap.keys.toSet(); + + final stronglyConnectedComponents = reverseOrder + ? packageGraph.computeStrongComponents().reversed + : packageGraph.computeStrongComponents(); + + final result = []; + for (final stronglyConnectedComponent in stronglyConnectedComponents) { + final stronglyConnectedComponentWithNativeAssets = [ + for (final packageName in stronglyConnectedComponent) + if (packagesToProcess.contains(packageName)) packageName, + ]; + + if (stronglyConnectedComponentWithNativeAssets.length > 1) { + logger.severe( + 'Cyclic dependency for native asset ${hookType.name}s in the ' + 'following packages: $stronglyConnectedComponentWithNativeAssets.', + ); + return const Failure(HooksRunnerFailure.projectConfig); + } else if (stronglyConnectedComponentWithNativeAssets.length == 1) { + result.add( + packageMap[stronglyConnectedComponentWithNativeAssets.single]!, + ); + } + } + + setCachedPlan(result); + return Success(result); + } Future _timeAsync( String name, @@ -181,9 +226,25 @@ class NativeAssetsBuildPlanner { /// dependencies. class PackageGraph { final Map> map; + late final Map> _inverseMap = _computeInverseMap(map); PackageGraph(this.map); + /// Instead of a map of package -> dependencies, get the map of package -> + /// dependents. + static Map> _computeInverseMap( + Map> graphMap, + ) { + final inverse = >{}; + for (final packageName in graphMap.keys) { + inverse.putIfAbsent(packageName, () => []); + for (final dependency in graphMap[packageName]!) { + inverse.putIfAbsent(dependency, () => []).add(packageName); + } + } + return inverse; + } + factory PackageGraph.fromPackageGraphJsonString( String json, String runPackageName, { @@ -222,6 +283,9 @@ class PackageGraph { Iterable neighborsOf(String vertex) => map[vertex] ?? []; + Iterable inverseNeighborsOf(String vertex) => + _inverseMap[vertex] ?? []; + Iterable get vertices => map.keys; List> computeStrongComponents() => diff --git a/pkgs/hooks_runner/lib/src/build_runner/build_runner.dart b/pkgs/hooks_runner/lib/src/build_runner/build_runner.dart index bd7a9ba7b..270b3670d 100644 --- a/pkgs/hooks_runner/lib/src/build_runner/build_runner.dart +++ b/pkgs/hooks_runner/lib/src/build_runner/build_runner.dart @@ -152,11 +152,11 @@ class NativeAssetsBuildRunner { /// Key is packageName. final globalAssetsForBuild = >{}; for (final package in buildPlan) { - final assetsForBuild = _assetsForBuildForPackage( - packageGraph: packageGraph!, - packageName: package.name, - globalAssetsForBuild: globalAssetsForBuild, - ); + final dependencies = packageGraph!.neighborsOf(package.name).toSet(); + final assetsForBuild = >{ + for (final entry in globalAssetsForBuild.entries) + if (dependencies.contains(entry.key)) entry.key: entry.value, + }; final inputBuilder = BuildInputBuilder(); @@ -248,21 +248,37 @@ class NativeAssetsBuildRunner { Uri? resourceIdentifiers, required BuildResult buildResult, }) async => _timeAsync('BuildRunner.link', () async { - final loadedUserDefines = await _loadedUserDefines; - final hookResultUserDefines = await _checkUserDefines(loadedUserDefines); - if (hookResultUserDefines.isFailure) { - return hookResultUserDefines; - } - var linkResult = hookResultUserDefines.success; - final planResult = await _makePlan( hook: Hook.link, buildResult: buildResult, ); if (planResult.isFailure) return planResult.asFailure; final (buildPlan, packageGraph) = planResult.success; + if (buildPlan.isEmpty) { + // Return eagerly if there are no link hooks at all. + return Success(HookResult()); + } + final loadedUserDefines = await _loadedUserDefines; + final hookResultUserDefines = await _checkUserDefines(loadedUserDefines); + if (hookResultUserDefines.isFailure) { + return hookResultUserDefines; + } + var linkResult = hookResultUserDefines.success; + + /// The key is the package name of the destination package. + final globalAssetsForLink = >>{}; for (final package in buildPlan) { + final dependencies = packageGraph! + .inverseNeighborsOf(package.name) + .toSet(); + + final assetsFromLinking = (globalAssetsForLink[package.name] ?? {}) + .entries + .where((entry) => dependencies.contains(entry.key)) + .expand((e) => e.value) + .toList(); + final inputBuilder = LinkInputBuilder(); for (final e in extensions) { e.setupLinkInput(inputBuilder); @@ -288,9 +304,11 @@ class NativeAssetsBuildRunner { outputDirectoryShared: outDirSharedUri, userDefines: loadedUserDefines?[package.name], ); + inputBuilder.setupLink( assets: buildResult.encodedAssetsForLinking[package.name] ?? [], recordedUsesFile: resourcesFile?.uri, + assetsFromLinking: assetsFromLinking, ); final input = inputBuilder.build(); @@ -299,7 +317,6 @@ class NativeAssetsBuildRunner { for (final e in extensions) ...await e.validateLinkInput(input), ]; if (errors.isNotEmpty) { - print(input.assets.encodedAssets); _printErrors('Link input for ${package.name} contains errors', errors); return const Failure(HooksRunnerFailure.internal); } @@ -318,9 +335,23 @@ class NativeAssetsBuildRunner { buildDirUri, outDirUri, ); - if (result.isFailure) return result.asFailure; + if (result.isFailure) { + return result.asFailure; + } final (hookOutput, hookDeps) = result.success; linkResult = linkResult.copyAdd(hookOutput, hookDeps); + + // Merge the assets into the global asset map. + (hookOutput as LinkOutput).assets.encodedAssetsForLink.forEach( + (packageName, assetsForPackage) => globalAssetsForLink.update( + packageName, + (current) => { + ...current, + ...{package.name: assetsForPackage}, + }, + ifAbsent: () => {package.name: assetsForPackage}, + ), + ); } final errors = [ @@ -784,23 +815,6 @@ ${compileResult.stdout} }, ); - /// Returns only the assets output as assetForBuild by the packages that are - /// the direct dependencies of [packageName]. - Map>? _assetsForBuildForPackage({ - required PackageGraph packageGraph, - required String packageName, - Map>? globalAssetsForBuild, - }) { - if (globalAssetsForBuild == null) { - return null; - } - final dependencies = packageGraph.neighborsOf(packageName).toSet(); - return { - for (final entry in globalAssetsForBuild.entries) - if (dependencies.contains(entry.key)) entry.key: entry.value, - }; - } - Future _validate( HookInput input, HookOutput output, @@ -850,42 +864,25 @@ ${compileResult.stdout} Future< Result<(BuildPlan plan, PackageGraph? dependencyGraph), HooksRunnerFailure> > - _makePlan({required Hook hook, BuildResult? buildResult}) async => _timeAsync( - '_makePlan', - () async { - switch (hook) { - case Hook.build: - final planner = await _planner; - final planResult = await planner.makeBuildHookPlan(); - if (planResult.isFailure) { - return planResult.asFailure; - } - return Success((planResult.success, planner.packageGraph)); - case Hook.link: - // Link hooks are not run in any particular order. - // Link hooks are skipped if no assets for linking are provided. - final buildPlan = []; - final skipped = []; - final encodedAssetsForLinking = buildResult!.encodedAssetsForLinking; - final planner = await _planner; - final packagesWithHook = await planner.packagesWithHook(Hook.link); - for (final package in packagesWithHook) { - if (encodedAssetsForLinking[package.name]?.isNotEmpty ?? false) { - buildPlan.add(package); - } else { - skipped.add(package.name); + _makePlan({required Hook hook, BuildResult? buildResult}) async => + _timeAsync('_makePlan', () async { + switch (hook) { + case Hook.build: + final planner = await _planner; + final planResult = await planner.makeBuildHookPlan(); + if (planResult.isFailure) { + return planResult.asFailure; } - } - if (skipped.isNotEmpty) { - logger.info( - 'Skipping link hooks from ${skipped.join(', ')}' - ' due to no assets provided to link for these link hooks.', - ); - } - return Success((buildPlan, null)); - } - }, - ); + return Success((planResult.success, planner.packageGraph)); + case Hook.link: + final planner = await _planner; + final planResult = await planner.makeLinkHookPlan(); + if (planResult.isFailure) { + return planResult.asFailure; + } + return Success((planResult.success, planner.packageGraph)); + } + }); Future> _readHookOutputFromUri( Hook hook, diff --git a/pkgs/hooks_runner/pubspec.yaml b/pkgs/hooks_runner/pubspec.yaml index a2dc98e05..87bfbec58 100644 --- a/pkgs/hooks_runner/pubspec.yaml +++ b/pkgs/hooks_runner/pubspec.yaml @@ -2,7 +2,7 @@ name: hooks_runner description: >- This package is the backend that invokes build hooks. -version: 0.21.1-wip +version: 0.22.0-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/hooks_runner @@ -12,7 +12,7 @@ environment: sdk: '>=3.9.0-21.0.dev <4.0.0' dependencies: - code_assets: ^0.19.5-wip # Needed for OS for Target for KernelAssets. + code_assets: ^0.20.0-wip # Needed for OS for Target for KernelAssets. collection: ^1.19.1 crypto: ^3.0.6 file: ^7.0.1 diff --git a/pkgs/hooks_runner/test/build_runner/build_runner_cycle_test.dart b/pkgs/hooks_runner/test/build_runner/build_runner_cycle_test.dart index 3d9a0fcfd..3402c7a2a 100644 --- a/pkgs/hooks_runner/test/build_runner/build_runner_cycle_test.dart +++ b/pkgs/hooks_runner/test/build_runner/build_runner_cycle_test.dart @@ -2,6 +2,7 @@ // for details. 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:hooks_runner/src/model/hook_result.dart' show HookResult; import 'package:logging/logging.dart'; import 'package:test/test.dart'; @@ -11,7 +12,7 @@ import 'helpers.dart'; const Timeout longTimeout = Timeout(Duration(minutes: 5)); void main() async { - test('cycle', timeout: longTimeout, () async { + test('build cycle', timeout: longTimeout, () async { await inTempDir((tempUri) async { await copyTestProjects(targetUri: tempUri); final packageUri = tempUri.resolve('cyclic_package_1/'); @@ -38,4 +39,33 @@ void main() async { } }); }); + + test('link cycle', timeout: longTimeout, () async { + await inTempDir((tempUri) async { + await copyTestProjects(targetUri: tempUri); + final packageUri = tempUri.resolve('cyclic_link_package_1/'); + + await runPubGet(workingDirectory: packageUri, logger: logger); + + { + final logMessages = []; + final result = await link( + buildResult: HookResult(), + packageUri, + createCapturingLogger(logMessages, level: Level.SEVERE), + dartExecutable, + buildAssetTypes: [], + ); + final fullLog = logMessages.join('\n'); + expect(result.isFailure, isTrue); + expect( + fullLog, + contains( + 'Cyclic dependency for native asset links in the following ' + 'packages: [cyclic_link_package_1, cyclic_link_package_2]', + ), + ); + } + }); + }); } diff --git a/pkgs/hooks_runner/test/build_runner/link_test.dart b/pkgs/hooks_runner/test/build_runner/link_test.dart index 050f48b03..efe053bc8 100644 --- a/pkgs/hooks_runner/test/build_runner/link_test.dart +++ b/pkgs/hooks_runner/test/build_runner/link_test.dart @@ -7,6 +7,8 @@ import 'dart:io'; import 'package:code_assets/code_assets.dart'; import 'package:data_assets/data_assets.dart'; import 'package:hooks/hooks.dart' hide build, link; +import 'package:hooks_runner/hooks_runner.dart'; +import 'package:hooks_runner/src/model/hook_result.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -103,10 +105,10 @@ void main() async { }); }); - test('no_asset_for_link', timeout: longTimeout, () async { + test('link metadata', timeout: longTimeout, () async { await inTempDir((tempUri) async { await copyTestProjects(targetUri: tempUri); - final packageUri = tempUri.resolve('no_asset_for_link/'); + final packageUri = tempUri.resolve('flag_app/'); // First, run `pub get`, we need pub to resolve our dependencies. await runPubGet(workingDirectory: packageUri, logger: logger); @@ -115,25 +117,53 @@ void main() async { packageUri, linkingEnabled: true, )).success; - expect(buildResult.encodedAssets.length, 0); - expect(buildResult.encodedAssetsForLinking.length, 0); + expect( + _getNames(buildResult.encodedAssetsForLinking['fun_with_flags']!), + unorderedEquals(['assets/ca.txt', 'assets/fr.txt', 'assets/de.txt']), + ); - final logMessages = []; final linkResult = (await link( packageUri, logger, dartExecutable, buildResult: buildResult, - capturedLogs: logMessages, buildAssetTypes: [BuildAssetType.data], )).success; - expect(linkResult.encodedAssets.length, 0); + + expect( + _getNames(linkResult.encodedAssets), + unorderedEquals(['assets/fr.txt', 'assets/de.txt']), + ); + }); + }); + + /// Check that the metadata can't be passed from dependency upwards, so in the + /// wrong direction. This shouldn't work, as there is an ordering to the link + /// hooks. + test('link inverse order', timeout: longTimeout, () async { + await inTempDir((tempUri) async { + await copyTestProjects(targetUri: tempUri); + final packageUri = tempUri.resolve('link_inverse_app/'); + + // First, run `pub get`, we need pub to resolve our dependencies. + await runPubGet(workingDirectory: packageUri, logger: logger); + + final logMessages = []; + final linkResult = await link( + packageUri, + logger, + dartExecutable, + capturedLogs: logMessages, + buildResult: HookResult(), + buildAssetTypes: [BuildAssetType.data], + ); + final fullLog = logMessages.join('\n'); + + expect(linkResult.isFailure, isTrue); + expect(linkResult.asFailure.failure, HooksRunnerFailure.hookRun); expect( - logMessages, - contains( - 'Skipping link hooks from no_asset_for_link due to ' - 'no assets provided to link for these link hooks.', - ), + fullLog, + contains('All good, the metadata cant swim against the current'), ); }); }); diff --git a/pkgs/hooks_runner/test_data/cyclic_link_package_1/hook/link.dart b/pkgs/hooks_runner/test_data/cyclic_link_package_1/hook/link.dart new file mode 100644 index 000000000..2c8f64a0e --- /dev/null +++ b/pkgs/hooks_runner/test_data/cyclic_link_package_1/hook/link.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. 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:hooks/hooks.dart'; + +void main(List arguments) async { + await link(arguments, (input, output) async {}); +} diff --git a/pkgs/hooks_runner/test_data/cyclic_link_package_1/pubspec.yaml b/pkgs/hooks_runner/test_data/cyclic_link_package_1/pubspec.yaml new file mode 100644 index 000000000..5512c6f07 --- /dev/null +++ b/pkgs/hooks_runner/test_data/cyclic_link_package_1/pubspec.yaml @@ -0,0 +1,18 @@ +name: cyclic_link_package_1 +description: Part of two packages with native assets that have a cycle. +version: 0.1.0 + +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.8.0 <4.0.0' + +dependencies: + cyclic_link_package_2: + path: ../cyclic_link_package_2 + hooks: any + +dev_dependencies: + lints: ^6.0.0 diff --git a/pkgs/hooks_runner/test_data/cyclic_link_package_2/hook/link.dart b/pkgs/hooks_runner/test_data/cyclic_link_package_2/hook/link.dart new file mode 100644 index 000000000..2c8f64a0e --- /dev/null +++ b/pkgs/hooks_runner/test_data/cyclic_link_package_2/hook/link.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. 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:hooks/hooks.dart'; + +void main(List arguments) async { + await link(arguments, (input, output) async {}); +} diff --git a/pkgs/hooks_runner/test_data/cyclic_link_package_2/pubspec.yaml b/pkgs/hooks_runner/test_data/cyclic_link_package_2/pubspec.yaml new file mode 100644 index 000000000..ae5deb699 --- /dev/null +++ b/pkgs/hooks_runner/test_data/cyclic_link_package_2/pubspec.yaml @@ -0,0 +1,18 @@ +name: cyclic_link_package_2 +description: Part of two packages with native assets that have a cycle. +version: 0.1.0 + +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.8.0 <4.0.0' + +dependencies: + cyclic_link_package_1: + path: ../cyclic_link_package_1 + hooks: any + +dev_dependencies: + lints: ^6.0.0 diff --git a/pkgs/hooks_runner/test_data/drop_dylib_link/hook/build.dart b/pkgs/hooks_runner/test_data/drop_dylib_link/hook/build.dart index 63738396d..f27ad7244 100644 --- a/pkgs/hooks_runner/test_data/drop_dylib_link/hook/build.dart +++ b/pkgs/hooks_runner/test_data/drop_dylib_link/hook/build.dart @@ -15,7 +15,7 @@ void main(List arguments) async { print('${record.level.name}: ${record.time}: ${record.message}'); }); final routing = input.config.linkingEnabled - ? [ToLinkHook(input.packageName)] + ? [ToLinkHook(input.packageName)] : [const ToAppBundle()]; await CBuilder.library( name: 'add', diff --git a/pkgs/hooks_runner/test_data/flag_app/.gitignore b/pkgs/hooks_runner/test_data/flag_app/.gitignore new file mode 100644 index 000000000..3a8579040 --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_app/.gitignore @@ -0,0 +1,3 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ diff --git a/pkgs/hooks_runner/test_data/flag_app/README.md b/pkgs/hooks_runner/test_data/flag_app/README.md new file mode 100644 index 000000000..8780e56d8 --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_app/README.md @@ -0,0 +1,4 @@ +A sample application using `flag_enthusiast_1` and `flag_enthusiast_2`. + +When compiling as a bundle, this leads to only two flags being bundled, as the +`ca.txt` flag is not used. diff --git a/pkgs/hooks_runner/test_data/flag_app/bin/flag_app.dart b/pkgs/hooks_runner/test_data/flag_app/bin/flag_app.dart new file mode 100644 index 000000000..4cc9cfbfb --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_app/bin/flag_app.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. 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:flag_app/flag_app.dart' as flag_app; + +void main(List arguments) { + print('Hello world: ${flag_app.flagList()}!'); +} diff --git a/pkgs/hooks_runner/test_data/flag_app/lib/flag_app.dart b/pkgs/hooks_runner/test_data/flag_app/lib/flag_app.dart new file mode 100644 index 000000000..f18228b7c --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_app/lib/flag_app.dart @@ -0,0 +1,11 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. 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:flag_enthusiast_1/flag_enthusiast_1.dart'; +import 'package:flag_enthusiast_2/flag_enthusiast_2.dart'; + +String flagList() => [ + SingleFlag.loadFlag('de'), + ...MultiFlag.loadFlags(['fr']), +].join(', '); diff --git a/pkgs/hooks_runner/test_data/flag_app/pubspec.yaml b/pkgs/hooks_runner/test_data/flag_app/pubspec.yaml new file mode 100644 index 000000000..7dfdfc85a --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_app/pubspec.yaml @@ -0,0 +1,15 @@ +name: flag_app +description: A sample application using flags. + +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.8.0 <4.0.0' + +dependencies: + flag_enthusiast_1: + path: ../flag_enthusiast_1 + flag_enthusiast_2: + path: ../flag_enthusiast_2 diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_1/.gitignore b/pkgs/hooks_runner/test_data/flag_enthusiast_1/.gitignore new file mode 100644 index 000000000..3cceda557 --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_1/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_1/README.md b/pkgs/hooks_runner/test_data/flag_enthusiast_1/README.md new file mode 100644 index 000000000..269b520be --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_1/README.md @@ -0,0 +1 @@ +A package with a high-level API to load a single flag. diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_1/hook/link.dart b/pkgs/hooks_runner/test_data/flag_enthusiast_1/hook/link.dart new file mode 100644 index 000000000..d100e95ec --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_1/hook/link.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. 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:fun_with_flags/src/hook.dart'; +import 'package:hooks/hooks.dart'; + +// TODO(mosuem): Actually use the information from the usage recording after +// it lands on stable https://github.com/dart-lang/sdk/issues/61166. +void main(List args) async { + await link(args, (input, output) async { + output.registerCountryUse(input.packageName, ['de']); + }); +} diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_1/lib/flag_enthusiast_1.dart b/pkgs/hooks_runner/test_data/flag_enthusiast_1/lib/flag_enthusiast_1.dart new file mode 100644 index 000000000..5d63224cf --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_1/lib/flag_enthusiast_1.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'src/flag_enthusiast_1_base.dart'; diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_1/lib/src/flag_enthusiast_1_base.dart b/pkgs/hooks_runner/test_data/flag_enthusiast_1/lib/src/flag_enthusiast_1_base.dart new file mode 100644 index 000000000..a7471e9c9 --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_1/lib/src/flag_enthusiast_1_base.dart @@ -0,0 +1,11 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. 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:fun_with_flags/fun_with_flags.dart'; +import 'package:meta/meta.dart' show RecordUse; + +class SingleFlag { + @RecordUse() + static String loadFlag(String country) => FlagLoader.load(country); +} diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_1/pubspec.yaml b/pkgs/hooks_runner/test_data/flag_enthusiast_1/pubspec.yaml new file mode 100644 index 000000000..93bfb8e5e --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_1/pubspec.yaml @@ -0,0 +1,21 @@ +name: flag_enthusiast_1 +description: A package with a high-level API to load a single flag. + +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.8.0 <4.0.0' + +dependencies: + data_assets: any + fun_with_flags: + path: ../fun_with_flags + hooks: any + logging: ^1.3.0 + meta: any + +dev_dependencies: + lints: ^6.0.0 + test: ^1.25.15 diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_2/.gitignore b/pkgs/hooks_runner/test_data/flag_enthusiast_2/.gitignore new file mode 100644 index 000000000..3cceda557 --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_2/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_2/README.md b/pkgs/hooks_runner/test_data/flag_enthusiast_2/README.md new file mode 100644 index 000000000..4300195cb --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_2/README.md @@ -0,0 +1 @@ +A package with a high-level API to load multiple flags. diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_2/hook/link.dart b/pkgs/hooks_runner/test_data/flag_enthusiast_2/hook/link.dart new file mode 100644 index 000000000..487b95d53 --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_2/hook/link.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. 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:fun_with_flags/src/hook.dart'; +import 'package:hooks/hooks.dart'; + +// TODO(mosuem): Actually use the information from the usage recording after +// it lands on stable https://github.com/dart-lang/sdk/issues/61166. +void main(List args) async { + await link(args, (input, output) async { + output.registerCountryUse(input.packageName, ['fr']); + }); +} diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_2/lib/flag_enthusiast_2.dart b/pkgs/hooks_runner/test_data/flag_enthusiast_2/lib/flag_enthusiast_2.dart new file mode 100644 index 000000000..5b7cd277a --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_2/lib/flag_enthusiast_2.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'src/flag_enthusiast_2_base.dart'; diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_2/lib/src/flag_enthusiast_2_base.dart b/pkgs/hooks_runner/test_data/flag_enthusiast_2/lib/src/flag_enthusiast_2_base.dart new file mode 100644 index 000000000..b6a3d7f79 --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_2/lib/src/flag_enthusiast_2_base.dart @@ -0,0 +1,12 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. 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:fun_with_flags/fun_with_flags.dart'; +import 'package:meta/meta.dart' show RecordUse; + +class MultiFlag { + @RecordUse() + static List loadFlags(Iterable countries) => + countries.map(FlagLoader.load).toList(); +} diff --git a/pkgs/hooks_runner/test_data/flag_enthusiast_2/pubspec.yaml b/pkgs/hooks_runner/test_data/flag_enthusiast_2/pubspec.yaml new file mode 100644 index 000000000..9efd3538e --- /dev/null +++ b/pkgs/hooks_runner/test_data/flag_enthusiast_2/pubspec.yaml @@ -0,0 +1,21 @@ +name: flag_enthusiast_2 +description: A package with a high-level API to load multiple flags. + +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.8.0 <4.0.0' + +dependencies: + data_assets: any + fun_with_flags: + path: ../fun_with_flags + hooks: any + logging: ^1.3.0 + meta: any + +dev_dependencies: + lints: ^6.0.0 + test: ^1.25.15 diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/.gitignore b/pkgs/hooks_runner/test_data/fun_with_flags/.gitignore new file mode 100644 index 000000000..3cceda557 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/README.md b/pkgs/hooks_runner/test_data/fun_with_flags/README.md new file mode 100644 index 000000000..ff2fe4028 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/README.md @@ -0,0 +1 @@ +A package bundling flag txt files, with a low-level API to load the flags. diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/assets/ca.txt b/pkgs/hooks_runner/test_data/fun_with_flags/assets/ca.txt new file mode 100644 index 000000000..8eb84e14e --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/assets/ca.txt @@ -0,0 +1 @@ +🇨🇦 diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/assets/de.txt b/pkgs/hooks_runner/test_data/fun_with_flags/assets/de.txt new file mode 100644 index 000000000..89b17ea46 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/assets/de.txt @@ -0,0 +1 @@ +🇩🇪 diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/assets/fr.txt b/pkgs/hooks_runner/test_data/fun_with_flags/assets/fr.txt new file mode 100644 index 000000000..bebcb9af3 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/assets/fr.txt @@ -0,0 +1 @@ +🇫🇷 diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/hook/build.dart b/pkgs/hooks_runner/test_data/fun_with_flags/hook/build.dart new file mode 100644 index 000000000..26c3b11f1 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/hook/build.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. 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:data_assets/data_assets.dart'; +import 'package:hooks/hooks.dart'; + +void main(List args) async { + await build(args, (input, output) async { + await output.addDataAssetDirectories( + ['assets'], + input: input, + routing: input.config.linkingEnabled + ? ToLinkHook(input.packageName) + : const ToAppBundle(), + ); + }); +} diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/hook/link.dart b/pkgs/hooks_runner/test_data/fun_with_flags/hook/link.dart new file mode 100644 index 000000000..4f8b1c9a0 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/hook/link.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. 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:data_assets/data_assets.dart'; +import 'package:fun_with_flags/src/hook.dart'; +import 'package:hooks/hooks.dart'; + +void main(List args) { + link(args, (input, output) async { + final usedFlags = input.fetchUsedCountries + .map((country) => 'package:fun_with_flags/assets/$country.txt') + .toSet(); + + // Got `usedFlags` for linking. Checking against `input.assets.data`` + + final usedFlagAssets = input.assets.data.where( + (flagAsset) => usedFlags.contains(flagAsset.id), + ); + + // After filtering, got `usedFlagAssets` + + output.assets.data.addAll(usedFlagAssets); + }); +} diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/lib/fun_with_flags.dart b/pkgs/hooks_runner/test_data/fun_with_flags/lib/fun_with_flags.dart new file mode 100644 index 000000000..ead97c535 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/lib/fun_with_flags.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'src/fun_with_flags_base.dart'; diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/lib/hook.dart b/pkgs/hooks_runner/test_data/fun_with_flags/lib/hook.dart new file mode 100644 index 000000000..0f9be5935 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/lib/hook.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'src/hook.dart' show FlagsUsedWrite; diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/lib/src/fun_with_flags_base.dart b/pkgs/hooks_runner/test_data/fun_with_flags/lib/src/fun_with_flags_base.dart new file mode 100644 index 000000000..de3b4f439 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/lib/src/fun_with_flags_base.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +class FlagLoader { + // TODO(mosuem): Use the data asset loading mechanism once it is implemented. + // https://github.com/dart-lang/sdk/issues/54003 + static String load(String country) => 'placeholder for flag loading'; +} diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/lib/src/hook.dart b/pkgs/hooks_runner/test_data/fun_with_flags/lib/src/hook.dart new file mode 100644 index 000000000..f5485ad0f --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/lib/src/hook.dart @@ -0,0 +1,24 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. 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:hooks/hooks.dart' show LinkInput, LinkOutputBuilder; + +const _prefix = 'used_flags_'; + +extension FlagsUsedWrite on LinkOutputBuilder { + /// Register a list of flags to be kept from treeshaking. + /// + /// This uses the [callerPackageName] with the [_prefix] to make a unique + /// identifier for this list - that's how we avoid overwriting other + /// packages flags. + void registerCountryUse(String callerPackageName, List countries) => + metadata.add('fun_with_flags', '$_prefix$callerPackageName', countries); +} + +extension FlagsUsedRead on LinkInput { + Iterable get fetchUsedCountries => metadata.entries + .where((entry) => entry.key.startsWith(_prefix)) + .expand((e) => e.value as List) + .map((e) => e as String); +} diff --git a/pkgs/hooks_runner/test_data/fun_with_flags/pubspec.yaml b/pkgs/hooks_runner/test_data/fun_with_flags/pubspec.yaml new file mode 100644 index 000000000..dfeeca720 --- /dev/null +++ b/pkgs/hooks_runner/test_data/fun_with_flags/pubspec.yaml @@ -0,0 +1,18 @@ +name: fun_with_flags +description: Add and retrieve a data asset. + +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.8.0 <4.0.0' + +dependencies: + data_assets: any + hooks: any + logging: ^1.3.0 + +dev_dependencies: + lints: ^6.0.0 + test: ^1.25.15 diff --git a/pkgs/hooks_runner/test_data/link_inverse_app/hook/link.dart b/pkgs/hooks_runner/test_data/link_inverse_app/hook/link.dart new file mode 100644 index 000000000..6797356a4 --- /dev/null +++ b/pkgs/hooks_runner/test_data/link_inverse_app/hook/link.dart @@ -0,0 +1,16 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. 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:hooks/hooks.dart'; + +void main(List arguments) async { + await link(arguments, (input, output) async { + final object = input.metadata['key']; + if (object == null) { + throw ArgumentError( + 'All good, the metadata cant swim against the current', + ); + } + }); +} diff --git a/pkgs/hooks_runner/test_data/link_inverse_app/pubspec.yaml b/pkgs/hooks_runner/test_data/link_inverse_app/pubspec.yaml new file mode 100644 index 000000000..f66c1e307 --- /dev/null +++ b/pkgs/hooks_runner/test_data/link_inverse_app/pubspec.yaml @@ -0,0 +1,19 @@ +name: link_inverse_app +description: Part of two packages with native assets that try to pass assets upstream. +version: 0.1.0 + +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.8.0 <4.0.0' + +dependencies: + data_assets: any + hooks: any + link_inverse_package: + path: ../link_inverse_package + +dev_dependencies: + lints: ^6.0.0 diff --git a/pkgs/hooks_runner/test_data/link_inverse_package/hook/link.dart b/pkgs/hooks_runner/test_data/link_inverse_package/hook/link.dart new file mode 100644 index 000000000..f70d90073 --- /dev/null +++ b/pkgs/hooks_runner/test_data/link_inverse_package/hook/link.dart @@ -0,0 +1,11 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. 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:hooks/hooks.dart'; + +void main(List arguments) async { + await link(arguments, (input, output) async { + output.metadata.add('link_inverse_app', 'key', 'value'); + }); +} diff --git a/pkgs/hooks_runner/test_data/link_inverse_package/pubspec.yaml b/pkgs/hooks_runner/test_data/link_inverse_package/pubspec.yaml new file mode 100644 index 000000000..448fb8a4f --- /dev/null +++ b/pkgs/hooks_runner/test_data/link_inverse_package/pubspec.yaml @@ -0,0 +1,16 @@ +name: link_inverse_package +description: Part of two packages with native assets that try to pass assets upstream. +version: 0.1.0 + +publish_to: none + +resolution: workspace + +environment: + sdk: '>=3.8.0 <4.0.0' + +dependencies: + hooks: any + +dev_dependencies: + lints: ^6.0.0 diff --git a/pkgs/hooks_runner/test_data/manifest.yaml b/pkgs/hooks_runner/test_data/manifest.yaml index 9fa1d3cfd..6fc2ee2af 100644 --- a/pkgs/hooks_runner/test_data/manifest.yaml +++ b/pkgs/hooks_runner/test_data/manifest.yaml @@ -5,17 +5,11 @@ - add_asset_link/hook/build.dart - add_asset_link/hook/link.dart - add_asset_link/lib/add_asset_link.dart -- add_asset_link/lib/src/add_asset_link.dart - add_asset_link/lib/src/add_asset_link_bindings.dart +- add_asset_link/lib/src/add_asset_link.dart - add_asset_link/pubspec.yaml - add_asset_link/src/native_add.c - add_asset_link/src/native_add.h -- complex_link/assets/data_0.json -- complex_link/assets/data_1.json -- complex_link/bin/complex_link.dart -- complex_link/hook/build.dart -- complex_link/hook/link.dart -- complex_link/pubspec.yaml - complex_link_helper/assets/data_helper_0.json - complex_link_helper/assets/data_helper_1.json - complex_link_helper/assets/data_helper_2.json @@ -23,25 +17,39 @@ - complex_link_helper/hook/build.dart - complex_link_helper/lib/complex_link_helper.dart - complex_link_helper/pubspec.yaml +- complex_link/assets/data_0.json +- complex_link/assets/data_1.json +- complex_link/bin/complex_link.dart +- complex_link/hook/build.dart +- complex_link/hook/link.dart +- complex_link/pubspec.yaml +- link_inverse_app/hook/link.dart +- link_inverse_app/pubspec.yaml +- link_inverse_package/hook/link.dart +- link_inverse_package/pubspec.yaml +- cyclic_link_package_1/hook/link.dart +- cyclic_link_package_1/pubspec.yaml +- cyclic_link_package_2/hook/link.dart +- cyclic_link_package_2/pubspec.yaml - cyclic_package_1/hook/build.dart - cyclic_package_1/pubspec.yaml - cyclic_package_2/hook/build.dart - cyclic_package_2/pubspec.yaml - dart_app/bin/dart_app.dart - dart_app/pubspec.yaml +- depend_on_fail_build_app/bin/depend_on_fail_build_app.dart +- depend_on_fail_build_app/pubspec.yaml - depend_on_fail_build/hook/build.dart - depend_on_fail_build/lib/depend_on_fail_build.dart - depend_on_fail_build/pubspec.yaml -- depend_on_fail_build_app/bin/depend_on_fail_build_app.dart -- depend_on_fail_build_app/pubspec.yaml - dev_dependency_with_hook/pubspec.yaml - dev_dependency_with_hook/test/my_test.dart - drop_dylib_link/bin/drop_dylib_link.dart - drop_dylib_link/hook/build.dart - drop_dylib_link/hook/link.dart - drop_dylib_link/lib/drop_dylib_link.dart -- drop_dylib_link/lib/src/drop_dylib_link.dart - drop_dylib_link/lib/src/drop_dylib_link_bindings.dart +- drop_dylib_link/lib/src/drop_dylib_link.dart - drop_dylib_link/pubspec.yaml - drop_dylib_link/src/native_add.c - drop_dylib_link/src/native_add.h @@ -50,44 +58,65 @@ - fail_build/hook/build.dart - fail_build/lib/fail_build.dart - fail_build/pubspec.yaml -- fail_on_os_sdk_version/hook/build.dart -- fail_on_os_sdk_version/pubspec.yaml - fail_on_os_sdk_version_link/assets/data.json - fail_on_os_sdk_version_link/hook/build.dart - fail_on_os_sdk_version_link/pubspec.yaml - fail_on_os_sdk_version_linker/hook/link.dart - fail_on_os_sdk_version_linker/pubspec.yaml +- fail_on_os_sdk_version/hook/build.dart +- fail_on_os_sdk_version/pubspec.yaml +- flag_app/bin/flag_app.dart +- flag_app/lib/flag_app.dart +- flag_app/pubspec.yaml +- flag_enthusiast_1/hook/link.dart +- flag_enthusiast_1/lib/flag_enthusiast_1.dart +- flag_enthusiast_1/lib/src/flag_enthusiast_1_base.dart +- flag_enthusiast_1/pubspec.yaml +- flag_enthusiast_2/hook/link.dart +- flag_enthusiast_2/lib/flag_enthusiast_2.dart +- flag_enthusiast_2/lib/src/flag_enthusiast_2_base.dart +- flag_enthusiast_2/pubspec.yaml +- fun_with_flags/assets/ca.txt +- fun_with_flags/assets/de.txt +- fun_with_flags/assets/fr.txt +- fun_with_flags/hook/build.dart +- fun_with_flags/hook/link.dart +- fun_with_flags/lib/fun_with_flags.dart +- fun_with_flags/lib/hook.dart +- fun_with_flags/lib/src/fun_with_flags_base.dart +- fun_with_flags/lib/src/hook.dart +- fun_with_flags/pubspec.yaml - infra_failure/bin/infra_failure.dart - infra_failure/hook/build.dart - infra_failure/pubspec.yaml -- native_add/ffigen.yaml -- native_add/hook/build.dart -- native_add/lib/native_add.dart -- native_add/lib/src/native_add.dart -- native_add/lib/src/native_add_bindings_generated.dart -- native_add/pubspec.yaml -- native_add/src/native_add.c -- native_add/src/native_add.h -- native_add/test/native_add_test.dart - native_add_duplicate/bin/native_add_duplicate.dart - native_add_duplicate/hook/build.dart - native_add_duplicate/hook/link.dart - native_add_duplicate/pubspec.yaml - native_add_duplicate/src/native_add.c - native_add_duplicate/src/native_add.h +- native_add_version_skew_2/analysis_options.yaml +- native_add_version_skew_2/hook/build.dart +- native_add_version_skew_2/pubspec.yaml - native_add_version_skew/analysis_options.yaml - native_add_version_skew/ffigen.yaml - native_add_version_skew/hook/build.dart - native_add_version_skew/lib/native_add.dart -- native_add_version_skew/lib/src/native_add.dart - native_add_version_skew/lib/src/native_add_bindings_generated.dart +- native_add_version_skew/lib/src/native_add.dart - native_add_version_skew/pubspec.yaml - native_add_version_skew/src/native_add.c - native_add_version_skew/src/native_add.h - native_add_version_skew/test/native_add_test.dart -- native_add_version_skew_2/analysis_options.yaml -- native_add_version_skew_2/hook/build.dart -- native_add_version_skew_2/pubspec.yaml +- native_add/ffigen.yaml +- native_add/hook/build.dart +- native_add/lib/native_add.dart +- native_add/lib/src/native_add_bindings_generated.dart +- native_add/lib/src/native_add.dart +- native_add/pubspec.yaml +- native_add/src/native_add.c +- native_add/src/native_add.h +- native_add/test/native_add_test.dart - native_dynamic_linking/bin/native_dynamic_linking.dart - native_dynamic_linking/ffigen.yaml - native_dynamic_linking/hook/build.dart @@ -103,8 +132,8 @@ - native_subtract/ffigen.yaml - native_subtract/hook/build.dart - native_subtract/lib/native_subtract.dart -- native_subtract/lib/src/native_subtract.dart - native_subtract/lib/src/native_subtract_bindings_generated.dart +- native_subtract/lib/src/native_subtract.dart - native_subtract/pubspec.yaml - native_subtract/src/native_subtract.c - native_subtract/src/native_subtract.h @@ -174,8 +203,8 @@ - treeshaking_native_libs/ffigen.yaml - treeshaking_native_libs/hook/build.dart - treeshaking_native_libs/hook/link.dart -- treeshaking_native_libs/lib/src/treeshaking_native_libs.dart - treeshaking_native_libs/lib/src/treeshaking_native_libs_bindings_generated.dart +- treeshaking_native_libs/lib/src/treeshaking_native_libs.dart - treeshaking_native_libs/lib/treeshaking_native_libs.dart - treeshaking_native_libs/pubspec.yaml - treeshaking_native_libs/src/native_add.c @@ -191,12 +220,12 @@ - user_defines/hook/build.dart - user_defines/pubspec.yaml - user_defines/test/user_defines_test.dart -- wrong_build_output/hook/build.dart -- wrong_build_output/pubspec.yaml - wrong_build_output_2/hook/build.dart - wrong_build_output_2/pubspec.yaml - wrong_build_output_3/hook/build.dart - wrong_build_output_3/pubspec.yaml +- wrong_build_output/hook/build.dart +- wrong_build_output/pubspec.yaml - wrong_linker/hook/build.dart - wrong_linker/pubspec.yaml - wrong_namespace_asset/hook/build.dart diff --git a/pkgs/native_toolchain_c/CHANGELOG.md b/pkgs/native_toolchain_c/CHANGELOG.md index 620a9f0fc..7e1bd7962 100644 --- a/pkgs/native_toolchain_c/CHANGELOG.md +++ b/pkgs/native_toolchain_c/CHANGELOG.md @@ -1,6 +1,7 @@ -## 0.17.1-wip +## 0.18.0-wip - Bump `package:hooks` to 0.20.0. +- Bump `package:hooks` and `package:code_assets`to 0.20.0. ## 0.17.0 diff --git a/pkgs/native_toolchain_c/pubspec.yaml b/pkgs/native_toolchain_c/pubspec.yaml index e347a1ec9..9f91a5465 100644 --- a/pkgs/native_toolchain_c/pubspec.yaml +++ b/pkgs/native_toolchain_c/pubspec.yaml @@ -1,7 +1,7 @@ name: native_toolchain_c description: >- A library to invoke the native C compiler installed on the host machine. -version: 0.17.1-wip +version: 0.18.0-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/native_toolchain_c topics: @@ -17,7 +17,7 @@ environment: sdk: '>=3.9.0-21.0.dev <4.0.0' dependencies: - code_assets: ^0.19.5-wip + code_assets: ^0.20.0-wip glob: ^2.1.1 hooks: ^0.20.0-wip logging: ^1.3.0 diff --git a/pkgs/native_toolchain_c/test/clinker/objects_helper.dart b/pkgs/native_toolchain_c/test/clinker/objects_helper.dart index 22eb9c240..d25eccb42 100644 --- a/pkgs/native_toolchain_c/test/clinker/objects_helper.dart +++ b/pkgs/native_toolchain_c/test/clinker/objects_helper.dart @@ -56,7 +56,7 @@ void runObjectsTests( outputFile: tempUri.resolve('output.json'), outputDirectoryShared: tempUri2, ) - ..setupLink(assets: [], recordedUsesFile: null) + ..setupLink(assets: [], recordedUsesFile: null, assetsFromLinking: []) ..addExtension( CodeAssetExtension( targetOS: targetOS, diff --git a/pkgs/native_toolchain_c/test/clinker/rust_test.dart b/pkgs/native_toolchain_c/test/clinker/rust_test.dart index 2223106eb..119949ee2 100644 --- a/pkgs/native_toolchain_c/test/clinker/rust_test.dart +++ b/pkgs/native_toolchain_c/test/clinker/rust_test.dart @@ -41,7 +41,7 @@ Future main() async { outputFile: tempUri.resolve('output.json'), outputDirectoryShared: tempUri2, ) - ..setupLink(assets: [], recordedUsesFile: null) + ..setupLink(assets: [], recordedUsesFile: null, assetsFromLinking: []) ..addExtension( CodeAssetExtension( targetOS: targetOS, diff --git a/pkgs/native_toolchain_c/test/clinker/treeshake_helper.dart b/pkgs/native_toolchain_c/test/clinker/treeshake_helper.dart index 44c8c765d..d6a671a9a 100644 --- a/pkgs/native_toolchain_c/test/clinker/treeshake_helper.dart +++ b/pkgs/native_toolchain_c/test/clinker/treeshake_helper.dart @@ -91,7 +91,7 @@ void runTreeshakeTests( outputFile: tempUri.resolve('output.json'), outputDirectoryShared: tempUri2, ) - ..setupLink(assets: [], recordedUsesFile: null) + ..setupLink(assets: [], recordedUsesFile: null, assetsFromLinking: []) ..addExtension( CodeAssetExtension( targetOS: targetOS, diff --git a/pkgs/native_toolchain_c/test/clinker/windows_module_definition_helper.dart b/pkgs/native_toolchain_c/test/clinker/windows_module_definition_helper.dart index 3dd8e8f80..f5c35c162 100644 --- a/pkgs/native_toolchain_c/test/clinker/windows_module_definition_helper.dart +++ b/pkgs/native_toolchain_c/test/clinker/windows_module_definition_helper.dart @@ -40,7 +40,7 @@ void runWindowsModuleDefinitionTests(List architectures) { outputFile: tempUri.resolve('output.json'), outputDirectoryShared: tempUri2, ) - ..setupLink(assets: [], recordedUsesFile: null) + ..setupLink(assets: [], recordedUsesFile: null, assetsFromLinking: []) ..addExtension( CodeAssetExtension( targetOS: targetOS, diff --git a/pubspec.yaml b/pubspec.yaml index 876bb7b2c..c13f4b452 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,12 +11,16 @@ workspace: - pkgs/hooks_runner/test_data/add_asset_link - pkgs/hooks_runner/test_data/complex_link - pkgs/hooks_runner/test_data/complex_link_helper + - pkgs/hooks_runner/test_data/cyclic_link_package_1 + - pkgs/hooks_runner/test_data/cyclic_link_package_2 - pkgs/hooks_runner/test_data/cyclic_package_1 - pkgs/hooks_runner/test_data/cyclic_package_2 - pkgs/hooks_runner/test_data/dart_app - pkgs/hooks_runner/test_data/depend_on_fail_build - pkgs/hooks_runner/test_data/depend_on_fail_build_app - pkgs/hooks_runner/test_data/dev_dependency_with_hook + - pkgs/hooks_runner/test_data/link_inverse_app + - pkgs/hooks_runner/test_data/link_inverse_package - pkgs/hooks_runner/test_data/drop_dylib_link - pkgs/hooks_runner/test_data/fail_build - pkgs/hooks_runner/test_data/fail_on_os_sdk_version @@ -35,6 +39,10 @@ workspace: - pkgs/hooks_runner/test_data/reusable_dynamic_library - pkgs/hooks_runner/test_data/reuse_dynamic_library - pkgs/hooks_runner/test_data/simple_data_asset + - pkgs/hooks_runner/test_data/flag_app + - pkgs/hooks_runner/test_data/fun_with_flags + - pkgs/hooks_runner/test_data/flag_enthusiast_1 + - pkgs/hooks_runner/test_data/flag_enthusiast_2 - pkgs/hooks_runner/test_data/simple_link - pkgs/hooks_runner/test_data/some_dev_dep - pkgs/hooks_runner/test_data/system_library