diff --git a/pkgs/native_assets_builder/CHANGELOG.md b/pkgs/native_assets_builder/CHANGELOG.md index 8909f3e54..50a1b629f 100644 --- a/pkgs/native_assets_builder/CHANGELOG.md +++ b/pkgs/native_assets_builder/CHANGELOG.md @@ -10,7 +10,10 @@ dart-lang/native repository to make it clear those are not intended to be used by end-users. - Remove link-dry-run concept as it's unused by Flutter Tools & Dart SDK -- Bump `native_assets_cli` to `0.9.0` +- Bump `native_assets_cli` to `0.9.0`. +- **Breaking change**: Remove asset-type specific logic from `package:native_assets_builder`. + Bundling tools have to now supply `supportedAssetTypes` and corresponding + validation routines. ## 0.8.3 diff --git a/pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart b/pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart index c2e4df213..c17774f3b 100644 --- a/pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart +++ b/pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart @@ -23,6 +23,25 @@ import 'build_planner.dart'; typedef DependencyMetadata = Map; +typedef _HookValidator = Future Function( + HookConfig config, HookOutputImpl output); + +// A callback that validates the output of a `hook/link.dart` invocation is +// valid (it may valid asset-type specific information). +typedef BuildValidator = Future Function( + BuildConfig config, BuildOutput outup); + +// A callback that validates the output of a `hook/link.dart` invocation is +// valid (it may valid asset-type specific information). +typedef LinkValidator = Future Function( + LinkConfig config, LinkOutput output); + +// A callback that validates assets emitted across all packages are valid / can +// be used together (it may valid asset-type specific information - e.g. that +// there are no classes in shared library filenames). +typedef ApplicationAssetValidator = Future Function( + List assets); + /// The programmatic API to be used by Dart launchers to invoke native builds. /// /// These methods are invoked by launchers such as dartdev (for `dart run`) @@ -58,6 +77,8 @@ class NativeAssetsBuildRunner { required Target target, required Uri workingDirectory, required BuildMode buildMode, + required BuildValidator buildValidator, + required ApplicationAssetValidator applicationAssetValidator, CCompilerConfig? cCompilerConfig, IOSSdk? targetIOSSdk, int? targetIOSVersion, @@ -66,10 +87,14 @@ class NativeAssetsBuildRunner { required bool includeParentEnvironment, PackageLayout? packageLayout, String? runPackageName, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, required bool linkingEnabled, }) async => _run( + validator: (HookConfig config, HookOutputImpl output) => + buildValidator(config as BuildConfig, output as BuildOutput), + applicationAssetValidator: (assets) async => + linkingEnabled ? [] : applicationAssetValidator(assets), hook: Hook.build, linkModePreference: linkModePreference, target: target, @@ -103,6 +128,8 @@ class NativeAssetsBuildRunner { required Target target, required Uri workingDirectory, required BuildMode buildMode, + required LinkValidator linkValidator, + required ApplicationAssetValidator applicationAssetValidator, CCompilerConfig? cCompilerConfig, IOSSdk? targetIOSSdk, int? targetIOSVersion, @@ -112,10 +139,14 @@ class NativeAssetsBuildRunner { PackageLayout? packageLayout, Uri? resourceIdentifiers, String? runPackageName, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, required BuildResult buildResult, }) async => _run( + validator: (HookConfig config, HookOutputImpl output) => + linkValidator(config as LinkConfig, output as LinkOutput), + applicationAssetValidator: (assets) async => + applicationAssetValidator(assets), hook: Hook.link, linkModePreference: linkModePreference, target: target, @@ -141,6 +172,8 @@ class NativeAssetsBuildRunner { required Target target, required Uri workingDirectory, required BuildMode buildMode, + required _HookValidator validator, + required ApplicationAssetValidator applicationAssetValidator, CCompilerConfig? cCompilerConfig, IOSSdk? targetIOSSdk, int? targetIOSVersion, @@ -150,7 +183,7 @@ class NativeAssetsBuildRunner { PackageLayout? packageLayout, Uri? resourceIdentifiers, String? runPackageName, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, BuildResult? buildResult, bool? linkingEnabled, }) async { @@ -236,6 +269,7 @@ class NativeAssetsBuildRunner { final (hookOutput, packageSuccess) = await _runHookForPackageCached( hook, config, + validator, packageLayout.packageConfigUri, workingDirectory, includeParentEnvironment, @@ -246,17 +280,14 @@ class NativeAssetsBuildRunner { metadata[config.packageName] = hookOutput.metadata; } - // Note the caller will need to check whether there are no duplicates - // between the build and link hook. - final validateResult = validateNoDuplicateDylibs(hookResult.assets); - if (validateResult.isNotEmpty) { - for (final error in validateResult) { - logger.severe(error); - } - hookResult = hookResult.copyAdd(HookOutputImpl(), false); - } + final errors = await applicationAssetValidator(hookResult.encodedAssets); + if (errors.isEmpty) return hookResult; - return hookResult; + logger.severe('Application asset verification failed:'); + for (final error in errors) { + logger.severe('- $error'); + } + return HookResult.failure(); } static Future _cliConfig( @@ -272,7 +303,7 @@ class NativeAssetsBuildRunner { int? targetAndroidNdkApi, int? targetIOSVersion, int? targetMacOSVersion, - Iterable? supportedAssetTypes, + Iterable supportedAssetTypes, Hook hook, Uri? resourceIdentifiers, BuildResult? buildResult, @@ -331,7 +362,7 @@ class NativeAssetsBuildRunner { cCompiler: cCompilerConfig, targetAndroidNdkApi: targetAndroidNdkApi, recordedUsagesFile: resourcesFile?.uri, - assets: buildResult!.assetsForLinking[package.name] ?? [], + encodedAssets: buildResult!.encodedAssetsForLinking[package.name] ?? [], supportedAssetTypes: supportedAssetTypes, linkModePreference: linkModePreference, ); @@ -370,9 +401,10 @@ class NativeAssetsBuildRunner { required Uri workingDirectory, required bool includeParentEnvironment, required bool linkingEnabled, + required BuildValidator buildValidator, PackageLayout? packageLayout, String? runPackageName, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, }) async { const hook = Hook.build; packageLayout ??= await PackageLayout.fromRootPackageRoot(workingDirectory); @@ -413,7 +445,7 @@ class NativeAssetsBuildRunner { continue; } // TODO(https://github.com/dart-lang/native/issues/1321): Should dry runs be cached? - var (buildOutput, packageSuccess) = await runUnderDirectoriesLock( + final (buildOutput, packageSuccess) = await runUnderDirectoriesLock( [ Directory.fromUri(config.outputDirectoryShared.parent), Directory.fromUri(config.outputDirectory.parent), @@ -423,6 +455,8 @@ class NativeAssetsBuildRunner { () => _runHookForPackage( hook, config, + (HookConfig config, HookOutputImpl output) => + buildValidator(config as BuildConfig, output as BuildOutput), packageConfigUri, workingDirectory, includeParentEnvironment, @@ -431,38 +465,15 @@ class NativeAssetsBuildRunner { packageLayout!, ), ); - buildOutput = _expandArchsCodeAssets(buildOutput); hookResult = hookResult.copyAdd(buildOutput, packageSuccess); } return hookResult; } - HookOutputImpl _expandArchsCodeAssets(HookOutputImpl buildOutput) { - final assets = []; - for (final asset in buildOutput.assets) { - switch (asset) { - case CodeAsset _: - if (asset.architecture != null) { - // Backwards compatibility, if an architecture is provided use it. - assets.add(asset); - } else { - // Dry run does not report architecture. Dart VM branches on OS - // and Target when looking up assets, so populate assets for all - // architectures. - for (final architecture in asset.os.architectures) { - assets.add(asset.copyWith(architecture: architecture)); - } - } - case DataAsset _: - assets.add(asset); - } - } - return buildOutput.copyWith(assets: assets); - } - Future<_PackageBuildRecord> _runHookForPackageCached( Hook hook, HookConfigImpl config, + _HookValidator validator, Uri packageConfigUri, Uri workingDirectory, bool includeParentEnvironment, @@ -497,25 +508,13 @@ class NativeAssetsBuildRunner { final lastBuilt = hookOutput.timestamp.roundDownToSeconds(); final dependenciesLastChange = await hookOutput.dependenciesModel.lastModified(); - late final DateTime assetsLastChange; - if (hook == Hook.link) { - assetsLastChange = await (config as LinkConfigImpl) - .assets - .map((a) => a.file) - .whereType() - .map((u) => u.fileSystemEntity) - .lastModified(); - } if (lastBuilt.isAfter(dependenciesLastChange) && - lastBuilt.isAfter(hookLastSourceChange) && - (hook == Hook.build || lastBuilt.isAfter(assetsLastChange))) { + lastBuilt.isAfter(hookLastSourceChange)) { logger.info( [ 'Skipping ${hook.name} for ${config.packageName} in $outDir.', 'Last build on $lastBuilt.', 'Last dependencies change on $dependenciesLastChange.', - if (hook == Hook.link) - 'Last assets for linking change on $assetsLastChange.', 'Last hook change on $hookLastSourceChange.', ].join(' '), ); @@ -528,6 +527,7 @@ class NativeAssetsBuildRunner { return await _runHookForPackage( hook, config, + validator, packageConfigUri, workingDirectory, includeParentEnvironment, @@ -542,6 +542,7 @@ class NativeAssetsBuildRunner { Future<_PackageBuildRecord> _runHookForPackage( Hook hook, HookConfigImpl config, + _HookValidator validator, Uri packageConfigUri, Uri workingDirectory, bool includeParentEnvironment, @@ -601,16 +602,12 @@ ${result.stdout} final output = HookOutputImpl.readFromFile(file: config.outputFile) ?? HookOutputImpl(); - final validateResult = await validate( - config, - output, - packageLayout, - ); - success &= validateResult.success; - if (!validateResult.success) { + final errors = await _validate(config, output, packageLayout, validator); + success &= errors.isEmpty; + if (errors.isNotEmpty) { logger.severe('package:${config.packageName}` has invalid output.'); } - for (final error in validateResult.errors) { + for (final error in errors) { logger.severe('- $error'); } return (output, success); @@ -758,7 +755,7 @@ ${compileResult.stdout} required OS targetOS, required LinkModePreference linkMode, required Uri buildParentDir, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, required bool? linkingEnabled, }) async { const hook = Hook.build; @@ -814,32 +811,33 @@ ${compileResult.stdout} }; } - Future validate( + Future _validate( HookConfigImpl config, HookOutputImpl output, PackageLayout packageLayout, + _HookValidator validator, ) async { - var (errors: errors, success: success) = config is BuildConfigImpl - ? await validateBuild(config, output) - : await validateLink(config as LinkConfigImpl, output); + final errors = config is BuildConfigImpl + ? await validateBuildOutput(config, output) + : await validateLinkOutput(config as LinkConfig, output); + errors.addAll(await validator(config, output)); if (config is BuildConfigImpl) { final packagesWithLink = (await packageLayout.packagesWithAssets(Hook.link)) .map((p) => p.name); - for (final targetPackage in output.assetsForLinking.keys) { + for (final targetPackage in output.encodedAssetsForLinking.keys) { if (!packagesWithLink.contains(targetPackage)) { - for (final asset in output.assetsForLinking[targetPackage]!) { - success &= false; + for (final asset in output.encodedAssetsForLinking[targetPackage]!) { errors.add( - 'Asset "${asset.id}" is sent to package "$targetPackage" for' + 'Asset "$asset" is sent to package "$targetPackage" for' ' linking, but that package does not have a link hook.', ); } } } } - return (errors: errors, success: success); + return errors; } Future<(List plan, PackageGraph? dependencyGraph, bool success)> @@ -878,9 +876,9 @@ ${compileResult.stdout} // Link hooks are skipped if no assets for linking are provided. buildPlan = []; final skipped = []; - final assetsForLinking = buildResult?.assetsForLinking; + final encodedAssetsForLinking = buildResult?.encodedAssetsForLinking; for (final package in packagesWithHook) { - if (assetsForLinking![package.name]?.isNotEmpty ?? false) { + if (encodedAssetsForLinking![package.name]?.isNotEmpty ?? false) { buildPlan.add(package); } else { skipped.add(package.name); diff --git a/pkgs/native_assets_builder/lib/src/model/build_dry_run_result.dart b/pkgs/native_assets_builder/lib/src/model/build_dry_run_result.dart index 1379cf244..6a37448c5 100644 --- a/pkgs/native_assets_builder/lib/src/model/build_dry_run_result.dart +++ b/pkgs/native_assets_builder/lib/src/model/build_dry_run_result.dart @@ -10,7 +10,7 @@ import '../../native_assets_builder.dart'; /// the dependency tree of the entry point application. abstract interface class BuildDryRunResult { /// The native assets produced by the hooks, which should be bundled. - List get assets; + List get encodedAssets; /// Whether all hooks completed without errors. /// @@ -18,5 +18,5 @@ abstract interface class BuildDryRunResult { bool get success; /// The native assets produced by the hooks, which should be linked. - Map> get assetsForLinking; + Map> get encodedAssetsForLinking; } diff --git a/pkgs/native_assets_builder/lib/src/model/build_result.dart b/pkgs/native_assets_builder/lib/src/model/build_result.dart index b38680563..96b2aac2d 100644 --- a/pkgs/native_assets_builder/lib/src/model/build_result.dart +++ b/pkgs/native_assets_builder/lib/src/model/build_result.dart @@ -18,8 +18,8 @@ abstract class BuildResult { bool get success; /// The native assets produced by the hooks, which should be bundled. - List get assets; + List get encodedAssets; /// The native assets produced by the hooks, which should be linked. - Map> get assetsForLinking; + Map> get encodedAssetsForLinking; } diff --git a/pkgs/native_assets_builder/lib/src/model/hook_result.dart b/pkgs/native_assets_builder/lib/src/model/hook_result.dart index 3e0644991..52ec4d98f 100644 --- a/pkgs/native_assets_builder/lib/src/model/hook_result.dart +++ b/pkgs/native_assets_builder/lib/src/model/hook_result.dart @@ -10,13 +10,13 @@ import '../../native_assets_builder.dart'; /// The result from a [NativeAssetsBuildRunner.build] or /// [NativeAssetsBuildRunner.link]. final class HookResult implements BuildResult, BuildDryRunResult, LinkResult { - /// The native assets produced by the hooks, which should be bundled. + /// The native encodedAssets produced by the hooks, which should be bundled. @override - final List assets; + final List encodedAssets; - /// The assets produced by the hooks, which should be linked. + /// The encodedAssets produced by the hooks, which should be linked. @override - final Map> assetsForLinking; + final Map> encodedAssetsForLinking; /// The files used by the hooks. @override @@ -29,21 +29,21 @@ final class HookResult implements BuildResult, BuildDryRunResult, LinkResult { final bool success; HookResult._({ - required this.assets, - required this.assetsForLinking, + required this.encodedAssets, + required this.encodedAssetsForLinking, required this.dependencies, required this.success, }); factory HookResult({ - List? assets, - Map>? assetsForLinking, + List? encodedAssets, + Map>? encodedAssetsForLinking, List? dependencies, bool success = true, }) => HookResult._( - assets: assets ?? [], - assetsForLinking: assetsForLinking ?? {}, + encodedAssets: encodedAssets ?? [], + encodedAssetsForLinking: encodedAssetsForLinking ?? {}, dependencies: dependencies ?? [], success: success, ); @@ -51,28 +51,18 @@ final class HookResult implements BuildResult, BuildDryRunResult, LinkResult { factory HookResult.failure() => HookResult(success: false); HookResult copyAdd(HookOutputImpl hookOutput, bool hookSuccess) { - final mergedMaps = mergeMaps( - assetsForLinking, - hookOutput.assetsForLinking, - value: (assets1, assets2) { - final twoInOne = assets1.where((asset) => assets2.contains(asset)); - final oneInTwo = assets2.where((asset) => assets1.contains(asset)); - if (twoInOne.isNotEmpty || oneInTwo.isNotEmpty) { - throw ArgumentError( - 'Found duplicate IDs, ${oneInTwo.map((e) => e.id).toList()}'); - } - return [ - ...assets1, - ...assets2, - ]; - }, - ); + final mergedMaps = + mergeMaps(encodedAssetsForLinking, hookOutput.encodedAssetsForLinking, + value: (encodedAssets1, encodedAssets2) => [ + ...encodedAssets1, + ...encodedAssets2, + ]); return HookResult( - assets: [ - ...assets, - ...hookOutput.assets, + encodedAssets: [ + ...encodedAssets, + ...hookOutput.encodedAssets, ], - assetsForLinking: mergedMaps, + encodedAssetsForLinking: mergedMaps, dependencies: [ ...dependencies, ...hookOutput.dependencies, @@ -82,8 +72,8 @@ final class HookResult implements BuildResult, BuildDryRunResult, LinkResult { } HookResult withSuccess(bool success) => HookResult( - assets: assets, - assetsForLinking: assetsForLinking, + encodedAssets: encodedAssets, + encodedAssetsForLinking: encodedAssetsForLinking, dependencies: dependencies, success: success, ); diff --git a/pkgs/native_assets_builder/lib/src/model/link_result.dart b/pkgs/native_assets_builder/lib/src/model/link_result.dart index e3f6877f7..a717f9618 100644 --- a/pkgs/native_assets_builder/lib/src/model/link_result.dart +++ b/pkgs/native_assets_builder/lib/src/model/link_result.dart @@ -10,7 +10,7 @@ import '../build_runner/build_runner.dart'; /// the dependency tree of the entry point application. abstract interface class LinkResult { /// The native assets produced by the hooks, which should be bundled. - List get assets; + List get encodedAssets; /// The files used by the hooks. List get dependencies; diff --git a/pkgs/native_assets_builder/test/build_runner/build_dependencies_test.dart b/pkgs/native_assets_builder/test/build_runner/build_dependencies_test.dart index 20e5b9509..e5616093b 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_dependencies_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_dependencies_test.dart @@ -26,8 +26,15 @@ void main() async { // Trigger a build, should invoke build for libraries with native assets. { final logMessages = []; - final result = await build(packageUri, logger, dartExecutable, - capturedLogs: logMessages); + final result = await build( + packageUri, + logger, + dartExecutable, + capturedLogs: logMessages, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); expect( logMessages.join('\n'), stringContainsInOrder( @@ -39,7 +46,7 @@ void main() async { ], ), ); - expect(result.assets.length, 2); + expect(result.encodedAssets.length, 2); expect( result.dependencies, [ diff --git a/pkgs/native_assets_builder/test/build_runner/build_planner_test.dart b/pkgs/native_assets_builder/test/build_runner/build_planner_test.dart index b4a03a30d..4eddad787 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_planner_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_planner_test.dart @@ -6,7 +6,6 @@ import 'dart:io'; import 'package:native_assets_builder/native_assets_builder.dart'; import 'package:native_assets_builder/src/build_runner/build_planner.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_asset_id_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_asset_id_test.dart index fdf8273ac..5f75a90ea 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_asset_id_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_asset_id_test.dart @@ -27,6 +27,9 @@ void main() async { packageUri, createCapturingLogger(logMessages, level: Level.SEVERE), dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); final fullLog = logMessages.join('\n'); expect(result.success, false); @@ -59,6 +62,9 @@ void main() async { packageUri, logger, dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); expect(result.success, true); } diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_build_dry_run_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_build_dry_run_test.dart index d91cb8961..9e3fa7c4f 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_build_dry_run_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_build_dry_run_test.dart @@ -5,7 +5,6 @@ import 'dart:io'; import 'package:file_testing/file_testing.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -29,29 +28,39 @@ void main() async { logger, dartExecutable, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, ); - final dryRunAssets = dryRunResult.assets.toList(); - final result = await build( + final buildResult = await build( packageUri, logger, dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); - // Every OS has more than one architecture. - expect(dryRunAssets.length, greaterThan(result.assets.length)); - for (var i = 0; i < dryRunAssets.length; i++) { - final dryRunAsset = dryRunAssets[i]; - final buildAsset = result.assets[0]; - expect(dryRunAsset.id, buildAsset.id); - // The build runner expands CodeAssets to all architectures. - expect(buildAsset.file, isNotNull); - if (dryRunAsset is CodeAsset && buildAsset is CodeAsset) { - expect(dryRunAsset.architecture, isNotNull); - expect(buildAsset.architecture, isNotNull); - expect(dryRunAsset.os, buildAsset.os); - expect(dryRunAsset.linkMode, buildAsset.linkMode); - } - } + expect(dryRunResult.encodedAssets.length, 1); + expect(buildResult.encodedAssets.length, 1); + + final dryRunAsset = dryRunResult.encodedAssets[0]; + expect(dryRunAsset.type, CodeAsset.type); + final dryRunCodeAsset = CodeAsset.fromEncoded(dryRunAsset); + + final buildAsset = buildResult.encodedAssets[0]; + final buildCodeAsset = CodeAsset.fromEncoded(buildAsset); + expect(buildAsset.type, CodeAsset.type); + + // Common across dry-run & build + expect(dryRunCodeAsset.id, buildCodeAsset.id); + expect(dryRunCodeAsset.os, buildCodeAsset.os); + expect(dryRunCodeAsset.linkMode, buildCodeAsset.linkMode); + expect(dryRunCodeAsset.file?.pathSegments.last, + buildCodeAsset.file?.pathSegments.last); + + // Different in dry-run: No architecture + expect(dryRunCodeAsset.architecture, isNull); + expect(buildCodeAsset.architecture, isNotNull); final nativeAssetsBuilderDirectory = packageUri.resolve('.dart_tool/native_assets_builder/'); diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_build_output_format_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_build_output_format_test.dart index e148f16de..827b9d0ea 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_build_output_format_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_build_output_format_test.dart @@ -33,6 +33,9 @@ void main() async { packageUri, createCapturingLogger(logMessages, level: Level.SEVERE), dartExecutable, + supportedAssetTypes: [], + buildValidator: (config, output) async => [], + applicationAssetValidator: validateCodeAssetsInApplication, ); final fullLog = logMessages.join('\n'); expect(result.success, false); diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_caching_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_caching_test.dart index d20862d2a..c3ca4d278 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_caching_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_caching_test.dart @@ -4,7 +4,6 @@ import 'dart:io'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -29,8 +28,15 @@ void main() async { { final logMessages = []; - final result = await build(packageUri, logger, dartExecutable, - capturedLogs: logMessages); + final result = await build( + packageUri, + logger, + dartExecutable, + capturedLogs: logMessages, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); expect( logMessages.join('\n'), contains( @@ -48,8 +54,15 @@ void main() async { { final logMessages = []; - final result = await build(packageUri, logger, dartExecutable, - capturedLogs: logMessages); + final result = await build( + packageUri, + logger, + dartExecutable, + capturedLogs: logMessages, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); expect( logMessages.join('\n'), contains('Skipping build for native_add'), @@ -86,9 +99,17 @@ void main() async { await Future.delayed(const Duration(seconds: 1)); { - final result = await build(packageUri, logger, dartExecutable); + final result = await build( + packageUri, + logger, + dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); await expectSymbols( - asset: result.assets.single as CodeAsset, symbols: ['add']); + asset: CodeAsset.fromEncoded(result.encodedAssets.single), + symbols: ['add']); } await copyTestProjects( @@ -97,9 +118,16 @@ void main() async { ); { - final result = await build(packageUri, logger, dartExecutable); + final result = await build( + packageUri, + logger, + dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); await expectSymbols( - asset: result.assets.single as CodeAsset, + asset: CodeAsset.fromEncoded(result.encodedAssets.single), symbols: ['add', 'subtract'], ); } @@ -124,7 +152,14 @@ void main() async { // cached. await Future.delayed(const Duration(seconds: 1)); - final result = await build(packageUri, logger, dartExecutable); + final result = await build( + packageUri, + logger, + dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); { final compiledHook = logMessages .where((m) => @@ -135,7 +170,7 @@ void main() async { } logMessages.clear(); await expectSymbols( - asset: result.assets.single as CodeAsset, + asset: CodeAsset.fromEncoded(result.encodedAssets.single), symbols: ['add'], ); @@ -144,7 +179,14 @@ void main() async { targetUri: packageUri); { - final result = await build(packageUri, logger, dartExecutable); + final result = await build( + packageUri, + logger, + dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); { final compiledHook = logMessages .where((m) => @@ -155,7 +197,7 @@ void main() async { } logMessages.clear(); await expectSymbols( - asset: result.assets.single as CodeAsset, + asset: CodeAsset.fromEncoded(result.encodedAssets.single), symbols: ['add', 'multiply'], ); } diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_cycle_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_cycle_test.dart index f99251865..746cc2701 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_cycle_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_cycle_test.dart @@ -27,6 +27,8 @@ void main() async { createCapturingLogger(logMessages, level: Level.SEVERE), dartExecutable, linkingEnabled: false, + supportedAssetTypes: [], + buildValidator: (config, output) async => [], ); final fullLog = logMessages.join('\n'); expect(result.success, false); @@ -45,6 +47,9 @@ void main() async { packageUri, createCapturingLogger(logMessages, level: Level.SEVERE), dartExecutable, + supportedAssetTypes: [], + buildValidator: (config, output) async => [], + applicationAssetValidator: (_) async => [], ); final fullLog = logMessages.join('\n'); expect(result.success, false); diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_failure_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_failure_test.dart index d4939bec6..f973b9c90 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_failure_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_failure_test.dart @@ -5,7 +5,6 @@ import 'dart:io'; import 'package:logging/logging.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -25,10 +24,18 @@ void main() async { ); { - final result = await build(packageUri, logger, dartExecutable); - expect(result.assets.length, 1); + final result = await build( + packageUri, + logger, + dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); + expect(result.encodedAssets.length, 1); await expectSymbols( - asset: result.assets.single as CodeAsset, symbols: ['add']); + asset: CodeAsset.fromEncoded(result.encodedAssets.single), + symbols: ['add']); expect( result.dependencies, [ @@ -48,6 +55,9 @@ void main() async { packageUri, createCapturingLogger(logMessages, level: Level.SEVERE), dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); final fullLog = logMessages.join('\n'); expect(result.success, false); @@ -68,10 +78,18 @@ void main() async { ); { - final result = await build(packageUri, logger, dartExecutable); - expect(result.assets.length, 1); + final result = await build( + packageUri, + logger, + dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); + expect(result.encodedAssets.length, 1); await expectSymbols( - asset: result.assets.single as CodeAsset, symbols: ['add']); + asset: CodeAsset.fromEncoded(result.encodedAssets.single), + symbols: ['add']); expect( result.dependencies, [ diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_non_root_package_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_non_root_package_test.dart index 1df7626a3..c34013ae3 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_non_root_package_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_non_root_package_test.dart @@ -30,8 +30,11 @@ void main() async { dartExecutable, capturedLogs: logMessages, runPackageName: 'some_dev_dep', + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); - expect(result.assets, isEmpty); + expect(result.encodedAssets, isEmpty); expect(result.dependencies, isEmpty); } @@ -43,8 +46,11 @@ void main() async { dartExecutable, capturedLogs: logMessages, runPackageName: 'native_add', + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); - expect(result.assets, isNotEmpty); + expect(result.encodedAssets, isNotEmpty); expect( result.dependencies, [ diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_reusability_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_reusability_test.dart index 6568332ab..a19cffb95 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_reusability_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_reusability_test.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:native_assets_builder/src/build_runner/build_runner.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -34,6 +33,8 @@ void main() async { workingDirectory: packageUri, includeParentEnvironment: true, linkingEnabled: false, + supportedAssetTypes: [], + buildValidator: (config, output) async => [], ); await buildRunner.buildDryRun( targetOS: Target.current.os, @@ -41,6 +42,8 @@ void main() async { workingDirectory: packageUri, includeParentEnvironment: true, linkingEnabled: false, + supportedAssetTypes: [], + buildValidator: (config, output) async => [], ); await buildRunner.build( buildMode: BuildMode.release, @@ -49,6 +52,9 @@ void main() async { workingDirectory: packageUri, includeParentEnvironment: true, linkingEnabled: false, + supportedAssetTypes: [], + buildValidator: (config, output) async => [], + applicationAssetValidator: (_) async => [], ); await buildRunner.build( buildMode: BuildMode.release, @@ -57,6 +63,9 @@ void main() async { workingDirectory: packageUri, includeParentEnvironment: true, linkingEnabled: false, + supportedAssetTypes: [], + buildValidator: (config, output) async => [], + applicationAssetValidator: (_) async => [], ); }); }); diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_run_in_isolation_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_run_in_isolation_test.dart index bfb9b738f..e5b0ecf49 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_run_in_isolation_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_run_in_isolation_test.dart @@ -4,7 +4,6 @@ import 'dart:io'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -61,8 +60,11 @@ void main() async { ), // Prevent any other environment variables. includeParentEnvironment: false, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); - expect(result.assets.length, 1); + expect(result.encodedAssets.length, 1); }); }); } diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_test.dart index cdd19fa95..9c635ac51 100644 --- a/pkgs/native_assets_builder/test/build_runner/build_runner_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_test.dart @@ -32,15 +32,22 @@ void main() async { // Trigger a build, should invoke build for libraries with native assets. { final logMessages = []; - final result = await build(packageUri, logger, dartExecutable, - capturedLogs: logMessages); + final result = await build( + packageUri, + logger, + dartExecutable, + capturedLogs: logMessages, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, + ); expect( logMessages.join('\n'), stringContainsInOrder([ 'native_add${Platform.pathSeparator}hook' '${Platform.pathSeparator}build.dart', ])); - expect(result.assets.length, 1); + expect(result.encodedAssets.length, 1); } // Trigger a build, should not invoke anything. @@ -56,6 +63,9 @@ void main() async { dartExecutable, capturedLogs: logMessages, packageLayout: packageLayout, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); expect( false, @@ -64,7 +74,7 @@ void main() async { '${Platform.pathSeparator}build.dart', ), ); - expect(result.assets.length, 1); + expect(result.encodedAssets.length, 1); } }); }); diff --git a/pkgs/native_assets_builder/test/build_runner/concurrency_shared_test.dart b/pkgs/native_assets_builder/test/build_runner/concurrency_shared_test.dart index 1b095e6dd..3dc75b307 100644 --- a/pkgs/native_assets_builder/test/build_runner/concurrency_shared_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/concurrency_shared_test.dart @@ -6,7 +6,6 @@ import 'dart:async'; import 'package:native_assets_builder/src/utils/run_process.dart' show RunProcessResult; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; diff --git a/pkgs/native_assets_builder/test/build_runner/concurrency_shared_test_helper.dart b/pkgs/native_assets_builder/test/build_runner/concurrency_shared_test_helper.dart index 1e127a21b..bafbc2d5e 100644 --- a/pkgs/native_assets_builder/test/build_runner/concurrency_shared_test_helper.dart +++ b/pkgs/native_assets_builder/test/build_runner/concurrency_shared_test_helper.dart @@ -4,7 +4,6 @@ import 'package:logging/logging.dart'; import 'package:native_assets_builder/native_assets_builder.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import '../helpers.dart'; @@ -29,6 +28,9 @@ void main(List args) async { linkingEnabled: false, supportedAssetTypes: [DataAsset.type], targetAndroidNdkApi: target.os == OS.android ? 30 : null, + buildValidator: (config, output) async => + await validateDataAssetBuildOutput(config, output), + applicationAssetValidator: (_) async => [], ); if (!result.success) { throw Error(); diff --git a/pkgs/native_assets_builder/test/build_runner/concurrency_test_helper.dart b/pkgs/native_assets_builder/test/build_runner/concurrency_test_helper.dart index fe37397bb..32ac611a6 100644 --- a/pkgs/native_assets_builder/test/build_runner/concurrency_test_helper.dart +++ b/pkgs/native_assets_builder/test/build_runner/concurrency_test_helper.dart @@ -4,7 +4,6 @@ import 'package:logging/logging.dart'; import 'package:native_assets_builder/native_assets_builder.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import '../helpers.dart'; @@ -31,6 +30,12 @@ void main(List args) async { workingDirectory: packageUri, includeParentEnvironment: true, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type, DataAsset.type], + buildValidator: (config, output) async => [ + ...await validateCodeAssetBuildOutput(config, output), + ...await validateDataAssetBuildOutput(config, output), + ], + applicationAssetValidator: validateCodeAssetsInApplication, ); if (!result.success) { throw Error(); diff --git a/pkgs/native_assets_builder/test/build_runner/conflicting_dylib_test.dart b/pkgs/native_assets_builder/test/build_runner/conflicting_dylib_test.dart index e3e13bc02..ddd48256a 100644 --- a/pkgs/native_assets_builder/test/build_runner/conflicting_dylib_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/conflicting_dylib_test.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:logging/logging.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -28,6 +27,9 @@ void main() async { packageUri, createCapturingLogger(logMessages, level: Level.SEVERE), dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); final fullLog = logMessages.join('\n'); expect(result.success, false); @@ -55,6 +57,9 @@ void main() async { logger, linkingEnabled: true, dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); expect(buildResult.success, isTrue); @@ -63,11 +68,17 @@ void main() async { logger, dartExecutable, buildResult: buildResult, + supportedAssetTypes: [CodeAsset.type], + linkValidator: validateCodeAssetLinkOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); expect(linkResult.success, isTrue); - final allAssets = [...buildResult.assets, ...linkResult.assets]; - final validateResult = validateNoDuplicateDylibs(allAssets); + final allAssets = [ + ...buildResult.encodedAssets, + ...linkResult.encodedAssets + ].where((e) => e.type == CodeAsset.type).toList(); + final validateResult = await validateCodeAssetsInApplication(allAssets); expect(validateResult, isNotEmpty); }); }); diff --git a/pkgs/native_assets_builder/test/build_runner/fail_on_os_sdk_version_test.dart b/pkgs/native_assets_builder/test/build_runner/fail_on_os_sdk_version_test.dart index 0e2055130..021a3d2fd 100644 --- a/pkgs/native_assets_builder/test/build_runner/fail_on_os_sdk_version_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/fail_on_os_sdk_version_test.dart @@ -3,9 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:logging/logging.dart'; -import 'package:native_assets_cli/native_assets_cli.dart' show OS; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - show IOSSdk, Target; import 'package:test/test.dart'; import '../helpers.dart'; @@ -76,6 +73,16 @@ void main() async { packageUri, createCapturingLogger(logMessages, level: Level.SEVERE), dartExecutable, + supportedAssetTypes: [CodeAsset.type, DataAsset.type], + buildValidator: (config, output) async => [ + ...await validateCodeAssetBuildOutput(config, output), + ...await validateDataAssetBuildOutput(config, output), + ], + linkValidator: (config, output) async => [ + ...await validateCodeAssetLinkOutput(config, output), + ...await validateDataAssetLinkOutput(config, output), + ], + applicationAssetValidator: validateCodeAssetsInApplication, ); final fullLog = logMessages.join('\n'); if (hook == 'build') { diff --git a/pkgs/native_assets_builder/test/build_runner/helpers.dart b/pkgs/native_assets_builder/test/build_runner/helpers.dart index ba809a893..daaa8f8b1 100644 --- a/pkgs/native_assets_builder/test/build_runner/helpers.dart +++ b/pkgs/native_assets_builder/test/build_runner/helpers.dart @@ -5,11 +5,9 @@ import 'dart:async'; import 'dart:io'; -import 'package:file_testing/file_testing.dart'; import 'package:logging/logging.dart'; import 'package:native_assets_builder/native_assets_builder.dart'; import 'package:native_assets_builder/src/model/hook_result.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -35,6 +33,8 @@ Future build( Uri packageUri, Logger logger, Uri dartExecutable, { + required BuildValidator buildValidator, + required ApplicationAssetValidator applicationAssetValidator, LinkModePreference linkModePreference = LinkModePreference.dynamic, CCompilerConfig? cCompilerConfig, bool includeParentEnvironment = true, @@ -47,7 +47,7 @@ Future build( int? targetAndroidNdkApi, Target? target, bool linkingEnabled = false, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, }) async => await runWithLog(capturedLogs, () async { final result = await NativeAssetsBuildRunner( @@ -68,12 +68,15 @@ Future build( targetAndroidNdkApi: targetAndroidNdkApi, linkingEnabled: linkingEnabled, supportedAssetTypes: supportedAssetTypes, + buildValidator: buildValidator, + applicationAssetValidator: applicationAssetValidator, ); if (result.success) { - await expectAssetsExist(result.assets); - for (final assetsForLinking in result.assetsForLinking.values) { - await expectAssetsExist(assetsForLinking); + expect(await result.encodedAssets.allExist(), true); + for (final encodedAssetsForLinking + in result.encodedAssetsForLinking.values) { + expect(await encodedAssetsForLinking.allExist(), true); } } @@ -84,6 +87,8 @@ Future link( Uri packageUri, Logger logger, Uri dartExecutable, { + required LinkValidator linkValidator, + required ApplicationAssetValidator applicationAssetValidator, LinkModePreference linkModePreference = LinkModePreference.dynamic, CCompilerConfig? cCompilerConfig, bool includeParentEnvironment = true, @@ -96,7 +101,7 @@ Future link( int? targetMacOSVersion, int? targetAndroidNdkApi, Target? target, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, }) async => await runWithLog(capturedLogs, () async { final result = await NativeAssetsBuildRunner( @@ -117,10 +122,12 @@ Future link( targetMacOSVersion: targetMacOSVersion, targetAndroidNdkApi: targetAndroidNdkApi, supportedAssetTypes: supportedAssetTypes, + linkValidator: linkValidator, + applicationAssetValidator: applicationAssetValidator, ); if (result.success) { - await expectAssetsExist(result.assets); + expect(await result.encodedAssets.allExist(), true); } return result; @@ -132,6 +139,9 @@ Future<(BuildResult, LinkResult)> buildAndLink( Uri dartExecutable, { LinkModePreference linkModePreference = LinkModePreference.dynamic, CCompilerConfig? cCompilerConfig, + required LinkValidator linkValidator, + required BuildValidator buildValidator, + required ApplicationAssetValidator applicationAssetValidator, bool includeParentEnvironment = true, List? capturedLogs, PackageLayout? packageLayout, @@ -142,7 +152,7 @@ Future<(BuildResult, LinkResult)> buildAndLink( int? targetAndroidNdkApi, Target? target, Uri? resourceIdentifiers, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, }) async => await runWithLog(capturedLogs, () async { final buildRunner = NativeAssetsBuildRunner( @@ -164,15 +174,18 @@ Future<(BuildResult, LinkResult)> buildAndLink( targetAndroidNdkApi: targetAndroidNdkApi, linkingEnabled: true, supportedAssetTypes: supportedAssetTypes, + buildValidator: buildValidator, + applicationAssetValidator: applicationAssetValidator, ); if (!buildResult.success) { return (buildResult, HookResult()); } - await expectAssetsExist(buildResult.assets); - for (final assetsForLinking in buildResult.assetsForLinking.values) { - await expectAssetsExist(assetsForLinking); + expect(await buildResult.encodedAssets.allExist(), true); + for (final encodedAssetsForLinking + in buildResult.encodedAssetsForLinking.values) { + expect(await encodedAssetsForLinking.allExist(), true); } final linkResult = await buildRunner.link( @@ -190,10 +203,12 @@ Future<(BuildResult, LinkResult)> buildAndLink( targetMacOSVersion: targetMacOSVersion, targetAndroidNdkApi: targetAndroidNdkApi, supportedAssetTypes: supportedAssetTypes, + linkValidator: linkValidator, + applicationAssetValidator: applicationAssetValidator, ); if (linkResult.success) { - await expectAssetsExist(buildResult.assets); + expect(await buildResult.encodedAssets.allExist(), true); } return (buildResult, linkResult); @@ -222,13 +237,14 @@ Future buildDryRun( Uri packageUri, Logger logger, Uri dartExecutable, { + required BuildValidator buildValidator, LinkModePreference linkModePreference = LinkModePreference.dynamic, CCompilerConfig? cCompilerConfig, bool includeParentEnvironment = true, List? capturedLogs, PackageLayout? packageLayout, required bool linkingEnabled, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, }) async => runWithLog(capturedLogs, () async { final result = await NativeAssetsBuildRunner( @@ -242,16 +258,11 @@ Future buildDryRun( packageLayout: packageLayout, linkingEnabled: linkingEnabled, supportedAssetTypes: supportedAssetTypes, + buildValidator: buildValidator, ); return result; }); -Future expectAssetsExist(List assets) async { - for (final asset in assets) { - expect(File.fromUri(asset.file!), exists); - } -} - Future expectSymbols({ required CodeAsset asset, required List symbols, diff --git a/pkgs/native_assets_builder/test/build_runner/link_caching_test.dart b/pkgs/native_assets_builder/test/build_runner/link_caching_test.dart index 0104ed64c..f43429f8e 100644 --- a/pkgs/native_assets_builder/test/build_runner/link_caching_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/link_caching_test.dart @@ -5,14 +5,12 @@ import 'dart:io'; import 'package:native_assets_builder/native_assets_builder.dart'; -import 'package:native_assets_cli/src/asset.dart'; import 'package:test/test.dart'; import '../helpers.dart'; import 'helpers.dart'; void main() async { - const supportedAssetTypes = [DataAsset.type]; const packageName = 'simple_link'; test('link hook caching', () async { @@ -40,8 +38,10 @@ void main() async { logger, dartExecutable, linkingEnabled: true, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], capturedLogs: logMessages, + buildValidator: validateDataAssetBuildOutput, + applicationAssetValidator: (_) async => [], ); } @@ -52,8 +52,10 @@ void main() async { logger, dartExecutable, buildResult: buildResult, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], capturedLogs: logMessages, + linkValidator: validateDataAssetLinkOutput, + applicationAssetValidator: (_) async => [], ); } diff --git a/pkgs/native_assets_builder/test/build_runner/link_test.dart b/pkgs/native_assets_builder/test/build_runner/link_test.dart index d7cc00e33..2a7d5d76f 100644 --- a/pkgs/native_assets_builder/test/build_runner/link_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/link_test.dart @@ -4,7 +4,6 @@ import 'dart:io'; -import 'package:native_assets_cli/src/asset.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -13,8 +12,6 @@ import 'helpers.dart'; const Timeout longTimeout = Timeout(Duration(minutes: 5)); void main() async { - const supportedAssetTypes = [DataAsset.type]; - test( 'simple_link linking', timeout: longTimeout, @@ -34,27 +31,33 @@ void main() async { logger, dartExecutable, linkingEnabled: true, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], + buildValidator: validateDataAssetBuildOutput, + applicationAssetValidator: (_) async => [], ); - expect(buildResult.assets.length, 0); + expect(buildResult.encodedAssets.length, 0); final linkResult = await link( packageUri, logger, dartExecutable, buildResult: buildResult, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], + linkValidator: validateDataAssetLinkOutput, + applicationAssetValidator: (_) async => [], ); - expect(linkResult.assets.length, 2); + expect(linkResult.encodedAssets.length, 2); final buildNoLinkResult = await build( packageUri, logger, dartExecutable, linkingEnabled: false, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], + buildValidator: validateDataAssetBuildOutput, + applicationAssetValidator: (_) async => [], ); - expect(buildNoLinkResult.assets.length, 4); + expect(buildNoLinkResult.encodedAssets.length, 4); }); }, ); @@ -78,11 +81,11 @@ void main() async { 'assets/data_0.json', 'assets/data_1.json', ]; - final assetsForLinking = [ + final encodedAssetsForLinking = [ ...helperAssetsForLinking, ...mainAssetsForLinking, ]; - final linkedAssets = assetsForLinking.skip(1); + final linkedAssets = encodedAssetsForLinking.skip(1); await copyTestProjects(targetUri: tempUri); final packageUri = tempUri.resolve('complex_link/'); @@ -95,14 +98,16 @@ void main() async { logger, dartExecutable, linkingEnabled: true, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], + buildValidator: validateDataAssetBuildOutput, + applicationAssetValidator: (_) async => [], ); expect(buildResult.success, true); + expect(_getNames(buildResult.encodedAssets), + unorderedEquals(builtHelperAssets)); expect( - _getNames(buildResult.assets), unorderedEquals(builtHelperAssets)); - expect( - _getNames(buildResult.assetsForLinking['complex_link']!), - unorderedEquals(assetsForLinking), + _getNames(buildResult.encodedAssetsForLinking['complex_link']!), + unorderedEquals(encodedAssetsForLinking), ); final linkResult = await link( @@ -110,11 +115,14 @@ void main() async { logger, dartExecutable, buildResult: buildResult, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], + linkValidator: validateDataAssetLinkOutput, + applicationAssetValidator: (_) async => [], ); expect(linkResult.success, true); - expect(_getNames(linkResult.assets), unorderedEquals(linkedAssets)); + expect( + _getNames(linkResult.encodedAssets), unorderedEquals(linkedAssets)); }); }, ); @@ -135,10 +143,12 @@ void main() async { logger, dartExecutable, linkingEnabled: true, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], + buildValidator: validateDataAssetBuildOutput, + applicationAssetValidator: (_) async => [], ); - expect(buildResult.assets.length, 0); - expect(buildResult.assetsForLinking.length, 0); + expect(buildResult.encodedAssets.length, 0); + expect(buildResult.encodedAssetsForLinking.length, 0); final logMessages = []; final linkResult = await link( @@ -147,9 +157,11 @@ void main() async { dartExecutable, buildResult: buildResult, capturedLogs: logMessages, - supportedAssetTypes: supportedAssetTypes, + supportedAssetTypes: [DataAsset.type], + linkValidator: validateDataAssetLinkOutput, + applicationAssetValidator: (_) async => [], ); - expect(linkResult.assets.length, 0); + expect(linkResult.encodedAssets.length, 0); expect( logMessages, contains( @@ -184,9 +196,12 @@ void main() async { logger, dartExecutable, linkingEnabled: true, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); - expect(buildResult.assets.length, 0); - expect(buildResult.assetsForLinking.length, 1); + expect(buildResult.encodedAssets.length, 0); + expect(buildResult.encodedAssetsForLinking.length, 1); final logMessages = []; final linkResult = await link( @@ -195,13 +210,17 @@ void main() async { dartExecutable, buildResult: buildResult, capturedLogs: logMessages, + supportedAssetTypes: [CodeAsset.type], + linkValidator: validateCodeAssetLinkOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); - expect(linkResult.assets.length, 1); - expect(linkResult.assets.first, isA()); + expect(linkResult.encodedAssets.length, 1); + expect(linkResult.encodedAssets.first.type, CodeAsset.type); }); }, ); } -Iterable _getNames(List assets) => - assets.whereType().map((asset) => asset.name); +Iterable _getNames(List assets) => assets + .where((e) => e.type == DataAsset.type) + .map((e) => DataAsset.fromEncoded(e).name); diff --git a/pkgs/native_assets_builder/test/build_runner/metadata_test.dart b/pkgs/native_assets_builder/test/build_runner/metadata_test.dart index d38863533..8fcb39afe 100644 --- a/pkgs/native_assets_builder/test/build_runner/metadata_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/metadata_test.dart @@ -26,8 +26,15 @@ void main() async { // Trigger a build, should invoke build for libraries with native assets. { final logMessages = []; - await build(packageUri, logger, dartExecutable, - capturedLogs: logMessages); + await build( + packageUri, + logger, + dartExecutable, + capturedLogs: logMessages, + supportedAssetTypes: ['foo'], + buildValidator: (config, output) async => [], + applicationAssetValidator: (_) async => [], + ); expect( logMessages.join('\n'), stringContainsInOrder([ diff --git a/pkgs/native_assets_builder/test/build_runner/packaging_preference_test.dart b/pkgs/native_assets_builder/test/build_runner/packaging_preference_test.dart index 2129b4ed5..55b20dba4 100644 --- a/pkgs/native_assets_builder/test/build_runner/packaging_preference_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/packaging_preference_test.dart @@ -2,7 +2,6 @@ // 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:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -27,6 +26,9 @@ void main() async { logger, dartExecutable, linkModePreference: LinkModePreference.dynamic, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); final resultPreferDynamic = await build( @@ -34,6 +36,9 @@ void main() async { logger, dartExecutable, linkModePreference: LinkModePreference.preferDynamic, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); final resultStatic = await build( @@ -41,6 +46,9 @@ void main() async { logger, dartExecutable, linkModePreference: LinkModePreference.static, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); final resultPreferStatic = await build( @@ -48,23 +56,27 @@ void main() async { logger, dartExecutable, linkModePreference: LinkModePreference.preferStatic, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); // This package honors preferences. expect( - (resultDynamic.assets.single as CodeAsset).linkMode, + CodeAsset.fromEncoded(resultDynamic.encodedAssets.single).linkMode, DynamicLoadingBundled(), ); expect( - (resultPreferDynamic.assets.single as CodeAsset).linkMode, + CodeAsset.fromEncoded(resultPreferDynamic.encodedAssets.single) + .linkMode, DynamicLoadingBundled(), ); expect( - (resultStatic.assets.single as CodeAsset).linkMode, + CodeAsset.fromEncoded(resultStatic.encodedAssets.single).linkMode, StaticLinking(), ); expect( - (resultPreferStatic.assets.single as CodeAsset).linkMode, + CodeAsset.fromEncoded(resultPreferStatic.encodedAssets.single).linkMode, StaticLinking(), ); }); diff --git a/pkgs/native_assets_builder/test/build_runner/resources_test.dart b/pkgs/native_assets_builder/test/build_runner/resources_test.dart index a46027f34..14b80af78 100644 --- a/pkgs/native_assets_builder/test/build_runner/resources_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/resources_test.dart @@ -34,6 +34,9 @@ void main() async { logger, dartExecutable, linkingEnabled: true, + supportedAssetTypes: [DataAsset.type], + buildValidator: validateDataAssetBuildOutput, + applicationAssetValidator: (_) async => [], ); Iterable buildFiles() => Directory.fromUri( @@ -49,6 +52,9 @@ void main() async { dartExecutable, buildResult: buildResult, resourceIdentifiers: resourcesUri, + supportedAssetTypes: [DataAsset.type], + linkValidator: validateDataAssetLinkOutput, + applicationAssetValidator: (_) async => [], ); expect(buildFiles(), anyElement(endsWith('resources.json'))); }); diff --git a/pkgs/native_assets_builder/test/build_runner/wrong_linker_test.dart b/pkgs/native_assets_builder/test/build_runner/wrong_linker_test.dart index 1b7f98a6d..01e637f5a 100644 --- a/pkgs/native_assets_builder/test/build_runner/wrong_linker_test.dart +++ b/pkgs/native_assets_builder/test/build_runner/wrong_linker_test.dart @@ -27,6 +27,9 @@ void main() async { packageUri, createCapturingLogger(logMessages, level: Level.SEVERE), dartExecutable, + supportedAssetTypes: [CodeAsset.type], + buildValidator: validateCodeAssetBuildOutput, + applicationAssetValidator: validateCodeAssetsInApplication, ); final fullLog = logMessages.join('\n'); expect(result.success, false); diff --git a/pkgs/native_assets_builder/test/helpers.dart b/pkgs/native_assets_builder/test/helpers.dart index 21d22a538..85759c73b 100644 --- a/pkgs/native_assets_builder/test/helpers.dart +++ b/pkgs/native_assets_builder/test/helpers.dart @@ -13,6 +13,8 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart' as internal; import 'package:test/test.dart'; import 'package:yaml/yaml.dart'; +export 'package:native_assets_cli/native_assets_cli_internal.dart'; + extension UriExtension on Uri { String get name => pathSegments.where((e) => e != '').last; @@ -170,21 +172,24 @@ extension on String { Uri asFileUri() => Uri.file(this); } -extension AssetIterable on Iterable { +extension AssetIterable on Iterable { Future allExist() async { - final allResults = await Future.wait(map((e) => e.exists())); - final missing = allResults.contains(false); - return !missing; - } -} - -extension on Asset { - Future exists() async { - final path_ = file; - return switch (path_) { - null => true, - _ => await path_.fileSystemEntity.exists(), - }; + for (final encodedAsset in this) { + if (encodedAsset.type == DataAsset.type) { + final dataAsset = DataAsset.fromEncoded(encodedAsset); + if (!await dataAsset.file.fileSystemEntity.exists()) { + return false; + } + } else if (encodedAsset.type == CodeAsset.type) { + final codeAsset = CodeAsset.fromEncoded(encodedAsset); + if (!await (codeAsset.file?.fileSystemEntity.exists() ?? true)) { + return false; + } + } else { + throw UnimplementedError('Unknown asset type ${encodedAsset.type}'); + } + } + return true; } } diff --git a/pkgs/native_assets_builder/test/test_data/native_dynamic_linking_test.dart b/pkgs/native_assets_builder/test/test_data/native_dynamic_linking_test.dart index 165a76e44..fbf4947d2 100644 --- a/pkgs/native_assets_builder/test/test_data/native_dynamic_linking_test.dart +++ b/pkgs/native_assets_builder/test/test_data/native_dynamic_linking_test.dart @@ -11,7 +11,6 @@ library; import 'dart:convert'; import 'dart:io'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../helpers.dart'; @@ -46,6 +45,7 @@ void main() async { targetArchitecture: dryRun ? null : Architecture.current, buildMode: dryRun ? null : BuildMode.debug, cCompiler: dryRun ? null : cCompiler, + supportedAssetTypes: [CodeAsset.type], ); final buildConfigUri = testTempUri.resolve('build_config.json'); @@ -70,7 +70,7 @@ void main() async { final buildOutputUri = outputDirectory.resolve('build_output.json'); final buildOutput = HookOutputImpl.fromJsonString( await File.fromUri(buildOutputUri).readAsString()); - final assets = buildOutput.assets; + final assets = buildOutput.encodedAssets; final dependencies = buildOutput.dependencies; if (dryRun) { expect(assets.length, greaterThanOrEqualTo(3)); @@ -88,6 +88,8 @@ void main() async { ); final addLibraryPath = assets + .where((e) => e.type == CodeAsset.type) + .map(CodeAsset.fromEncoded) .firstWhere((asset) => asset.id.endsWith('add.dart')) .file! .toFilePath(); diff --git a/pkgs/native_assets_builder/test/test_data/transformer_test.dart b/pkgs/native_assets_builder/test/test_data/transformer_test.dart index e26c8be5e..334fa8724 100644 --- a/pkgs/native_assets_builder/test/test_data/transformer_test.dart +++ b/pkgs/native_assets_builder/test/test_data/transformer_test.dart @@ -11,7 +11,6 @@ library; import 'dart:convert'; import 'dart:io'; -import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; import '../build_runner/helpers.dart'; @@ -43,7 +42,7 @@ void main() async { final dartUri = Uri.file(Platform.resolvedExecutable); late String stdout; - late HookOutputImpl output; + late BuildOutput output; Future runBuild(Architecture architecture) async { final config = BuildConfigImpl( @@ -95,7 +94,7 @@ void main() async { ]), ); expect( - output.assets, + output.dataAssets.all, contains( DataAsset( file: outputDirectoryShared.resolve('data_transformed0.json'), diff --git a/pkgs/native_assets_builder/test_data/add_asset_link/hook/link.dart b/pkgs/native_assets_builder/test_data/add_asset_link/hook/link.dart index 371081747..ccfbb9775 100644 --- a/pkgs/native_assets_builder/test_data/add_asset_link/hook/link.dart +++ b/pkgs/native_assets_builder/test_data/add_asset_link/hook/link.dart @@ -6,9 +6,9 @@ import 'package:native_assets_cli/native_assets_cli.dart'; void main(List arguments) async { await link(arguments, (config, output) async { - final builtDylib = config.assets.first as CodeAsset; + final builtDylib = config.codeAssets.all.first; output - ..addAsset( + ..codeAssets.add( CodeAsset( package: 'add_asset_link', name: 'dylib_add_link', diff --git a/pkgs/native_assets_builder/test_data/complex_link/hook/build.dart b/pkgs/native_assets_builder/test_data/complex_link/hook/build.dart index 08fa5e4e2..0ac49c85c 100644 --- a/pkgs/native_assets_builder/test_data/complex_link/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/complex_link/hook/build.dart @@ -24,7 +24,7 @@ void main(List args) async { .toFilePath(windows: false) .substring(config.packageRoot.toFilePath(windows: false).length); - output.addAsset( + output.dataAssets.add( DataAsset( package: packageName, name: name, diff --git a/pkgs/native_assets_builder/test_data/complex_link/hook/link.dart b/pkgs/native_assets_builder/test_data/complex_link/hook/link.dart index 8e393e7c2..113586781 100644 --- a/pkgs/native_assets_builder/test_data/complex_link/hook/link.dart +++ b/pkgs/native_assets_builder/test_data/complex_link/hook/link.dart @@ -7,9 +7,10 @@ import 'package:native_assets_cli/native_assets_cli.dart'; void main(List args) async { await link( args, - (config, output) async => output.addAssets(treeshake(config.assets)), + (config, output) async => + output.dataAssets.addAll(treeshake(config.dataAssets.all)), ); } -Iterable treeshake(Iterable assets) => +Iterable treeshake(Iterable assets) => assets.where((asset) => !asset.id.endsWith('assets/data_helper_2.json')); diff --git a/pkgs/native_assets_builder/test_data/complex_link_helper/hook/build.dart b/pkgs/native_assets_builder/test_data/complex_link_helper/hook/build.dart index a4c60e03a..79ff0dfdf 100644 --- a/pkgs/native_assets_builder/test_data/complex_link_helper/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/complex_link_helper/hook/build.dart @@ -25,7 +25,7 @@ void main(List args) async { .substring(config.packageRoot.toFilePath(windows: false).length); final forLinking = name.contains('2') || name.contains('3'); - output.addAsset( + output.dataAssets.add( DataAsset( package: packageName, name: name, diff --git a/pkgs/native_assets_builder/test_data/drop_dylib_link/hook/link.dart b/pkgs/native_assets_builder/test_data/drop_dylib_link/hook/link.dart index b2f15c0d9..b3e266d9b 100644 --- a/pkgs/native_assets_builder/test_data/drop_dylib_link/hook/link.dart +++ b/pkgs/native_assets_builder/test_data/drop_dylib_link/hook/link.dart @@ -7,11 +7,12 @@ import 'package:native_assets_cli/native_assets_cli.dart'; void main(List arguments) async { await link(arguments, (config, output) async { print(''' -Received ${config.assets.length} assets: ${config.assets.map((e) => e.id)}. +Received ${config.codeAssets.all.length} encodedAssets: ${config.codeAssets.all.map((e) => e.id)}. '''); - output.addAssets(config.assets.where((asset) => asset.id.endsWith('add'))); + output.codeAssets.addAll( + config.codeAssets.all.where((asset) => asset.id.endsWith('add'))); print(''' -Keeping only ${output.assets.map((e) => e.id)}. +Keeping only ${output.codeAssets.all.map((e) => e.id)}. '''); output.addDependency(config.packageRoot.resolve('hook/link.dart')); }); diff --git a/pkgs/native_assets_builder/test_data/fail_on_os_sdk_version_link/hook/build.dart b/pkgs/native_assets_builder/test_data/fail_on_os_sdk_version_link/hook/build.dart index 3cece99b0..5ac16fef7 100644 --- a/pkgs/native_assets_builder/test_data/fail_on_os_sdk_version_link/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/fail_on_os_sdk_version_link/hook/build.dart @@ -6,7 +6,7 @@ import 'package:native_assets_cli/native_assets_cli.dart'; void main(List arguments) async { await build(arguments, (config, output) async { - output.addAsset( + output.dataAssets.add( DataAsset( name: 'data', file: config.packageRoot.resolve('assets/data.json'), diff --git a/pkgs/native_assets_builder/test_data/native_add_duplicate/hook/build.dart b/pkgs/native_assets_builder/test_data/native_add_duplicate/hook/build.dart index dc2b2b4c6..aab673ecc 100644 --- a/pkgs/native_assets_builder/test_data/native_add_duplicate/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/native_add_duplicate/hook/build.dart @@ -28,8 +28,8 @@ void main(List arguments) async { print('${record.level.name}: ${record.time}: ${record.message}'); }), ); - output.addAsset( - tempBuildOutput.assets.single, + output.addEncodedAsset( + tempBuildOutput.encodedAssets.single, // Send dylib to linking if linking is enabled. linkInPackage: config.linkingEnabled ? packageName : null, ); diff --git a/pkgs/native_assets_builder/test_data/native_add_duplicate/hook/link.dart b/pkgs/native_assets_builder/test_data/native_add_duplicate/hook/link.dart index 21d879ca6..b69973d47 100644 --- a/pkgs/native_assets_builder/test_data/native_add_duplicate/hook/link.dart +++ b/pkgs/native_assets_builder/test_data/native_add_duplicate/hook/link.dart @@ -7,6 +7,6 @@ import 'package:native_assets_cli/native_assets_cli.dart'; void main(List args) async { await link(args, (config, output) async { // Simply output the dylib in the link hook. - output.addAssets(config.assets); + output.codeAssets.addAll(config.codeAssets.all); }); } diff --git a/pkgs/native_assets_builder/test_data/no_asset_for_link/hook/link.dart b/pkgs/native_assets_builder/test_data/no_asset_for_link/hook/link.dart index d617fa723..e73ad42ea 100644 --- a/pkgs/native_assets_builder/test_data/no_asset_for_link/hook/link.dart +++ b/pkgs/native_assets_builder/test_data/no_asset_for_link/hook/link.dart @@ -6,11 +6,7 @@ import 'package:native_assets_cli/native_assets_cli.dart'; void main(List arguments) async { await link(arguments, (config, output) async { - output.addAssets( - config.assets, - ); - output.addDependency( - config.packageRoot.resolve('hook/link.dart'), - ); + output.addEncodedAssets(config.encodedAssets); + output.addDependency(config.packageRoot.resolve('hook/link.dart')); }); } diff --git a/pkgs/native_assets_builder/test_data/simple_data_asset/hook/build.dart b/pkgs/native_assets_builder/test_data/simple_data_asset/hook/build.dart index 3e18d4c11..e7aed2a3c 100644 --- a/pkgs/native_assets_builder/test_data/simple_data_asset/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/simple_data_asset/hook/build.dart @@ -24,7 +24,7 @@ void main(List args) async { .toFilePath(windows: false) .substring(config.packageRoot.toFilePath(windows: false).length); - output.addAsset( + output.dataAssets.add( DataAsset( package: config.packageName, name: name, diff --git a/pkgs/native_assets_builder/test_data/simple_link/hook/build.dart b/pkgs/native_assets_builder/test_data/simple_link/hook/build.dart index 08fa5e4e2..0ac49c85c 100644 --- a/pkgs/native_assets_builder/test_data/simple_link/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/simple_link/hook/build.dart @@ -24,7 +24,7 @@ void main(List args) async { .toFilePath(windows: false) .substring(config.packageRoot.toFilePath(windows: false).length); - output.addAsset( + output.dataAssets.add( DataAsset( package: packageName, name: name, diff --git a/pkgs/native_assets_builder/test_data/simple_link/hook/link.dart b/pkgs/native_assets_builder/test_data/simple_link/hook/link.dart index 1c019fcee..9e4d9f2ee 100644 --- a/pkgs/native_assets_builder/test_data/simple_link/hook/link.dart +++ b/pkgs/native_assets_builder/test_data/simple_link/hook/link.dart @@ -5,10 +5,16 @@ import 'package:native_assets_cli/native_assets_cli.dart'; void main(List args) async { - await link( - args, - (config, output) async => output.addAssets(shake(config.assets)), - ); + await link(args, (config, output) async { + shake(output, config.dataAssets.all); + }); } -Iterable shake(Iterable assets) => assets.skip(2); +void shake(LinkOutput output, Iterable assets) { + for (final asset in assets.skip(2)) { + output.dataAssets.add(asset); + + // If the file changes we'd like to re-run the linker. + output.addDependency(asset.file); + } +} diff --git a/pkgs/native_assets_builder/test_data/transformer/hook/build.dart b/pkgs/native_assets_builder/test_data/transformer/hook/build.dart index 9b1f2308c..9f5956bed 100644 --- a/pkgs/native_assets_builder/test_data/transformer/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/transformer/hook/build.dart @@ -40,7 +40,7 @@ void main(List arguments) async { } } - output.addAsset( + output.dataAssets.add( DataAsset( package: config.packageName, name: name, diff --git a/pkgs/native_assets_builder/test_data/treeshaking_native_libs/hook/link.dart b/pkgs/native_assets_builder/test_data/treeshaking_native_libs/hook/link.dart index 22d7600f6..07c868d95 100644 --- a/pkgs/native_assets_builder/test_data/treeshaking_native_libs/hook/link.dart +++ b/pkgs/native_assets_builder/test_data/treeshaking_native_libs/hook/link.dart @@ -12,9 +12,9 @@ void main(List arguments) async { (config, output) async { final linker = CLinker.library( name: config.packageName, - assetName: config.assets.single.id.split('/').skip(1).join('/'), + assetName: config.codeAssets.all.single.id.split('/').skip(1).join('/'), linkerOptions: LinkerOptions.treeshake(symbols: ['add']), - sources: [config.assets.single.file!.toFilePath()], + sources: [config.codeAssets.all.single.file!.toFilePath()], ); await linker.run( config: config, diff --git a/pkgs/native_assets_builder/test_data/wrong_build_output/hook/build.dart b/pkgs/native_assets_builder/test_data/wrong_build_output/hook/build.dart index 969f76335..cd8dac2c2 100644 --- a/pkgs/native_assets_builder/test_data/wrong_build_output/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/wrong_build_output/hook/build.dart @@ -13,7 +13,7 @@ void main(List args) async { const _wrongContents = ''' timestamp: 2023-07-28 14:22:45.000 -assets: [] +encodedAssets: [] dependencies: [] metadata: {} version: 9001.0.0 diff --git a/pkgs/native_assets_builder/test_data/wrong_build_output_3/hook/build.dart b/pkgs/native_assets_builder/test_data/wrong_build_output_3/hook/build.dart index c0c95d799..cb50e5731 100644 --- a/pkgs/native_assets_builder/test_data/wrong_build_output_3/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/wrong_build_output_3/hook/build.dart @@ -14,7 +14,7 @@ void main(List args) async { const _rightContents = ''' timestamp: 2023-07-28 14:22:45.000 -assets: [] +encodedAssets: [] dependencies: [] metadata: {} version: 1.0.0 diff --git a/pkgs/native_assets_builder/test_data/wrong_linker/hook/build.dart b/pkgs/native_assets_builder/test_data/wrong_linker/hook/build.dart index b8730f013..8f3c9993c 100644 --- a/pkgs/native_assets_builder/test_data/wrong_linker/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/wrong_linker/hook/build.dart @@ -15,7 +15,7 @@ void main(List arguments) async { await File.fromUri(assetUri).writeAsBytes([1, 2, 3]); } - output.addAsset( + output.codeAssets.add( CodeAsset( package: config.packageName, name: 'foo', diff --git a/pkgs/native_assets_builder/test_data/wrong_namespace_asset/hook/build.dart b/pkgs/native_assets_builder/test_data/wrong_namespace_asset/hook/build.dart index 0cf220b41..66ad30529 100644 --- a/pkgs/native_assets_builder/test_data/wrong_namespace_asset/hook/build.dart +++ b/pkgs/native_assets_builder/test_data/wrong_namespace_asset/hook/build.dart @@ -15,7 +15,7 @@ void main(List arguments) async { await File.fromUri(assetUri).writeAsBytes([1, 2, 3]); } - output.addAsset( + output.codeAssets.add( CodeAsset( package: 'other_package', name: 'foo', diff --git a/pkgs/native_assets_cli/CHANGELOG.md b/pkgs/native_assets_cli/CHANGELOG.md index 3805a1643..71aff12e5 100644 --- a/pkgs/native_assets_cli/CHANGELOG.md +++ b/pkgs/native_assets_cli/CHANGELOG.md @@ -20,6 +20,9 @@ - **Breaking change** Moved some methods to be extension methods. - Some classes in the `BuildConfig` and `BuildOutput` now expose `fromJson` and `toJson`. +- **Breaking change** Removed `Asset` class, removed `{Build,Link}Output.assets*`. + Hook writers should now use e.g. `output.dataAssets.add(DataAsset(...))` + instead of `output.addAsset(DataAsset(...))`. ## 0.8.0 diff --git a/pkgs/native_assets_cli/example/build/local_asset/hook/build.dart b/pkgs/native_assets_cli/example/build/local_asset/hook/build.dart index 19fa40160..280945122 100644 --- a/pkgs/native_assets_cli/example/build/local_asset/hook/build.dart +++ b/pkgs/native_assets_cli/example/build/local_asset/hook/build.dart @@ -30,7 +30,7 @@ Future main(List args) async { ]); } - output.addAsset( + output.codeAssets.add( // TODO: Change to DataAsset once the Dart/Flutter SDK can consume it. CodeAsset( package: packageName, diff --git a/pkgs/native_assets_cli/example/build/local_asset/test/build_test.dart b/pkgs/native_assets_cli/example/build/local_asset/test/build_test.dart index 0befd2e4a..eda5bcd25 100644 --- a/pkgs/native_assets_cli/example/build/local_asset/test/build_test.dart +++ b/pkgs/native_assets_cli/example/build/local_asset/test/build_test.dart @@ -13,12 +13,12 @@ void main() { description: 'test my build hook', mainMethod: build.main, check: (_, output) { - expect(output.assets, isNotEmpty); - expect(output.assets.first, isA()); + expect(output.codeAssets.all, isNotEmpty); expect( - (output.assets.first as CodeAsset).id, + output.codeAssets.all.first.id, 'package:local_asset/asset.txt', ); }, + supportedAssetTypes: [CodeAsset.type], ); } diff --git a/pkgs/native_assets_cli/example/link/package_with_assets/hook/build.dart b/pkgs/native_assets_cli/example/link/package_with_assets/hook/build.dart index 08fa5e4e2..0ac49c85c 100644 --- a/pkgs/native_assets_cli/example/link/package_with_assets/hook/build.dart +++ b/pkgs/native_assets_cli/example/link/package_with_assets/hook/build.dart @@ -24,7 +24,7 @@ void main(List args) async { .toFilePath(windows: false) .substring(config.packageRoot.toFilePath(windows: false).length); - output.addAsset( + output.dataAssets.add( DataAsset( package: packageName, name: name, diff --git a/pkgs/native_assets_cli/example/link/package_with_assets/hook/link.dart b/pkgs/native_assets_cli/example/link/package_with_assets/hook/link.dart index a5cd73bfc..d77ea69bc 100644 --- a/pkgs/native_assets_cli/example/link/package_with_assets/hook/link.dart +++ b/pkgs/native_assets_cli/example/link/package_with_assets/hook/link.dart @@ -20,9 +20,8 @@ void main(List args) async { final usedAssets = (usages.instancesOf(multiplyIdentifier) ?? []).map((e) => (e.instanceConstant.fields.values.first as StringConstant).value); - output.addAssets(config.assets - .whereType() - .where((asset) => usedAssets.contains(asset.name))); + output.dataAssets.addAll(config.dataAssets.all + .where((dataAsset) => usedAssets.contains(dataAsset.name))); }); } diff --git a/pkgs/native_assets_cli/lib/native_assets_cli.dart b/pkgs/native_assets_cli/lib/native_assets_cli.dart index 21bc081b6..8bac2546a 100644 --- a/pkgs/native_assets_cli/lib/native_assets_cli.dart +++ b/pkgs/native_assets_cli/lib/native_assets_cli.dart @@ -15,9 +15,28 @@ export 'src/api/link.dart' show link; export 'src/api/link_config.dart' show LinkConfig; export 'src/api/linker.dart' show Linker; export 'src/architecture.dart' show Architecture; -export 'src/asset.dart' show Asset, CodeAsset, DataAsset, OSLibraryNaming; export 'src/build_mode.dart' show BuildMode; export 'src/c_compiler_config.dart' show CCompilerConfig; +export 'src/code_assets/code_asset.dart' + show + BuildOutputCodeAssets, + CodeAsset, + CodeAssetsBuildOutput, + CodeAssetsLinkConfig, + CodeAssetsLinkOutput, + LinkConfigCodeAssets, + LinkOutputCodeAssets, + OSLibraryNaming; +export 'src/data_assets/data_asset.dart' + show + BuildOutputDataAssets, + DataAsset, + DataAssetsBuildOutput, + DataAssetsLinkConfig, + DataAssetsLinkOutput, + LinkConfigDataAssets, + LinkOutputDataAssets; +export 'src/encoded_asset.dart' show EncodedAsset; export 'src/ios_sdk.dart' show IOSSdk; export 'src/link_mode.dart' show diff --git a/pkgs/native_assets_cli/lib/native_assets_cli_internal.dart b/pkgs/native_assets_cli/lib/native_assets_cli_internal.dart index 2d1b478c9..173e9086e 100644 --- a/pkgs/native_assets_cli/lib/native_assets_cli_internal.dart +++ b/pkgs/native_assets_cli/lib/native_assets_cli_internal.dart @@ -21,11 +21,18 @@ export 'src/api/build_config.dart' show BuildConfigImpl; export 'src/api/build_output.dart' show HookOutputImpl; export 'src/api/hook_config.dart' show HookConfigImpl; export 'src/api/link_config.dart' show LinkConfigImpl; -export 'src/asset.dart' show Asset, CodeAsset, DataAsset; +export 'src/code_assets/validation.dart' + show + validateCodeAssetBuildOutput, + validateCodeAssetLinkOutput, + validateCodeAssetsInApplication; +export 'src/data_assets/validation.dart' + show validateDataAssetBuildOutput, validateDataAssetLinkOutput; +export 'src/encoded_asset.dart' show EncodedAsset; export 'src/model/dependencies.dart'; export 'src/model/hook.dart'; export 'src/model/metadata.dart'; export 'src/model/resource_identifiers.dart'; export 'src/model/target.dart' show Target; -export 'src/validator/validator.dart' - show ValidateResult, validateBuild, validateLink, validateNoDuplicateDylibs; +export 'src/validation.dart' + show ValidationErrors, validateBuildOutput, validateLinkOutput; diff --git a/pkgs/native_assets_cli/lib/src/api/build.dart b/pkgs/native_assets_cli/lib/src/api/build.dart index ef7dfd3fa..b1a0eae93 100644 --- a/pkgs/native_assets_cli/lib/src/api/build.dart +++ b/pkgs/native_assets_cli/lib/src/api/build.dart @@ -2,7 +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 '../validator/validator.dart'; +import '../validation.dart'; import 'build_config.dart'; import 'build_output.dart'; @@ -70,7 +70,7 @@ import 'build_output.dart'; /// ]); /// } /// -/// output.addAsset( +/// output.codeAssets.add( /// // TODO: Change to DataAsset once the Dart/Flutter SDK can consume it. /// CodeAsset( /// package: packageName, @@ -91,13 +91,13 @@ Future build( final config = BuildConfigImpl.fromArguments(arguments); final output = HookOutputImpl(); await builder(config, output); - final validateResult = await validateBuild(config, output); - if (validateResult.success) { + final errors = await validateBuildOutput(config, output); + if (errors.isEmpty) { await output.writeToFile(config: config); } else { final message = [ 'The output contained unsupported output:', - for (final error in validateResult.errors) '- $error', + for (final error in errors) '- $error', ].join('\n'); throw UnsupportedError(message); } diff --git a/pkgs/native_assets_cli/lib/src/api/build_config.dart b/pkgs/native_assets_cli/lib/src/api/build_config.dart index c7d880cfb..08c03389e 100644 --- a/pkgs/native_assets_cli/lib/src/api/build_config.dart +++ b/pkgs/native_assets_cli/lib/src/api/build_config.dart @@ -10,7 +10,6 @@ import 'package:pub_semver/pub_semver.dart'; import '../architecture.dart'; import '../args_parser.dart'; -import '../asset.dart'; import '../build_mode.dart'; import '../c_compiler_config.dart'; import '../ios_sdk.dart'; @@ -48,8 +47,9 @@ abstract final class BuildConfig implements HookConfig { /// Whether link hooks will be run after the build hooks. /// - /// If [linkingEnabled] is true, [BuildOutput.addAsset] may be called with the - /// `linkInPackage` parameter so that assets can be linked in a link hook. + /// If [linkingEnabled] is true, [BuildOutput.addEncodedAsset] may be called + /// with the`linkInPackage` parameter so that assets can be linked in a link + /// hook. /// Linking is enabled in Flutter release builds and Dart AOT configurations. /// These configurations are optimized for app size. /// - `flutter build` @@ -127,7 +127,7 @@ abstract final class BuildConfig implements HookConfig { required LinkModePreference linkModePreference, @Deprecated(metadataDeprecation) Map>? dependencyMetadata, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, required bool linkingEnabled, }) => BuildConfigImpl( @@ -169,7 +169,7 @@ abstract final class BuildConfig implements HookConfig { required OS targetOS, required LinkModePreference linkModePreference, required bool linkingEnabled, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, }) => BuildConfigImpl.dryRun( outputDirectory: outputDirectory, diff --git a/pkgs/native_assets_cli/lib/src/api/build_output.dart b/pkgs/native_assets_cli/lib/src/api/build_output.dart index d15bc4b8e..a435bf066 100644 --- a/pkgs/native_assets_cli/lib/src/api/build_output.dart +++ b/pkgs/native_assets_cli/lib/src/api/build_output.dart @@ -9,7 +9,8 @@ import 'package:collection/collection.dart'; import 'package:pub_semver/pub_semver.dart'; import '../architecture.dart'; -import '../asset.dart'; +import '../encoded_asset.dart'; +import '../json_utils.dart'; import '../model/dependencies.dart'; import '../model/metadata.dart'; import '../os.dart'; @@ -51,7 +52,7 @@ abstract final class BuildOutput { /// /// In dry runs, the assets for all [Architecture]s for the [OS] specified in /// the dry run must be provided. - Iterable get assets; + Iterable get encodedAssets; /// The assets produced by this build which should be linked. /// @@ -61,7 +62,7 @@ abstract final class BuildOutput { /// /// In dry runs, the assets for all [Architecture]s for the [OS] specified in /// the dry run must be provided. - Map> get assetsForLinking; + Map> get encodedAssetsForLinking; /// The files used by this build. /// @@ -83,10 +84,9 @@ abstract final class BuildOutput { /// because [File.lastModified] is rounded to whole seconds and caching logic /// compares these timestamps. /// - /// The [Asset]s produced by this build or dry-run can be provided to the - /// constructor as [assets], or can be added later using [addAsset] and - /// [addAssets]. In dry runs, the [Architecture] for [CodeAsset]s can be - /// omitted. + /// The [EncodedAsset]s produced by this build or dry-run can be provided to + /// the constructor as [encodedAssets], or can be added later using + /// [addEncodedAsset] and [addEncodedAssets]. /// /// The files used by this build must be provided to the constructor as /// [dependencies], or can be added later with [addDependency] and @@ -100,31 +100,55 @@ abstract final class BuildOutput { /// [addMetadatum] and [addMetadata]. factory BuildOutput({ DateTime? timestamp, - Iterable? assets, + Iterable? encodedAssets, Iterable? dependencies, @Deprecated(metadataDeprecation) Map? metadata, }) => HookOutputImpl( timestamp: timestamp, - assets: assets?.cast().toList(), + encodedAssets: encodedAssets?.toList(), dependencies: Dependencies([...?dependencies]), metadata: Metadata({...?metadata}), ); - /// Adds [Asset]s produced by this build or dry run. + /// Adds [EncodedAsset]s produced by this build or dry run. /// /// If the [linkInPackage] argument is specified, the asset will not be /// bundled during the build step, but sent as input to the link hook of the /// specified package, where it can be further processed and possibly bundled. - void addAsset(Asset asset, {String? linkInPackage}); - - /// Adds [Asset]s produced by this build or dry run. + /// + /// Note to hook writers. Prefer using the `.add` method on the extension for + /// the specific asset type being added: + /// + /// ```dart + /// main(List arguments) async { + /// await build((config, output) { + /// output.codeAssets.add(CodeAsset(...)); + /// output.dataAssets.add(DataAsset(...)); + /// }); + /// } + /// ``` + void addEncodedAsset(EncodedAsset asset, {String? linkInPackage}); + + /// Adds [EncodedAsset]s produced by this build or dry run. /// /// If the [linkInPackage] argument is specified, the assets will not be /// bundled during the build step, but sent as input to the link hook of the /// specified package, where they can be further processed and possibly /// bundled. - void addAssets(Iterable assets, {String? linkInPackage}); + /// + /// Note to hook writers. Prefer using the `.addAll` method on the extension + /// for the specific asset type being added: + /// + /// ```dart + /// main(List arguments) async { + /// await build((config, output) { + /// output.codeAssets.addAll([CodeAsset(...), ...]); + /// output.dataAssets.addAll([DataAsset(...), ...]); + /// }); + /// } + /// ``` + void addEncodedAssets(Iterable assets, {String? linkInPackage}); /// Adds file used by this build. /// diff --git a/pkgs/native_assets_cli/lib/src/api/builder.dart b/pkgs/native_assets_cli/lib/src/api/builder.dart index 11b8a6d18..99d21c716 100644 --- a/pkgs/native_assets_cli/lib/src/api/builder.dart +++ b/pkgs/native_assets_cli/lib/src/api/builder.dart @@ -59,11 +59,11 @@ import 'linker.dart'; /// The builder is designed to immediately operate on [BuildOutput]. If a /// builder should output something else than standard, it should be /// configurable through a constructor parameter. For example to send an asset -/// for linking to the output ([BuildOutput.addAsset] with `linkInPackage` set), -/// the builder should have a constructor parameter. (Instead of capturing the -/// BuildOutput as a return value and manually manipulating it in the build -/// hook.) This ensures that builder is in control of what combination of build -/// outputs are valid. +/// for linking to the output ([BuildOutput.addEncodedAsset] with +/// `linkInPackage` set), the builder should have a constructor parameter. +/// (Instead of capturing the BuildOutput as a return value and manually +/// manipulating it in the build hook.) This ensures that builder is in control +/// of what combination of build outputs are valid. abstract interface class Builder { /// Runs this build. /// diff --git a/pkgs/native_assets_cli/lib/src/api/hook_config.dart b/pkgs/native_assets_cli/lib/src/api/hook_config.dart index de31b34a1..f43e62e3a 100644 --- a/pkgs/native_assets_cli/lib/src/api/hook_config.dart +++ b/pkgs/native_assets_cli/lib/src/api/hook_config.dart @@ -10,9 +10,10 @@ import 'package:crypto/crypto.dart'; import 'package:pub_semver/pub_semver.dart'; import '../architecture.dart'; -import '../asset.dart'; import '../build_mode.dart'; import '../c_compiler_config.dart'; +import '../code_assets/code_asset.dart'; +import '../data_assets/data_asset.dart'; import '../ios_sdk.dart'; import '../json_utils.dart'; import '../link_mode.dart'; diff --git a/pkgs/native_assets_cli/lib/src/api/link.dart b/pkgs/native_assets_cli/lib/src/api/link.dart index 82ae3acc2..98edb9e65 100644 --- a/pkgs/native_assets_cli/lib/src/api/link.dart +++ b/pkgs/native_assets_cli/lib/src/api/link.dart @@ -2,8 +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 '../model/dependencies.dart'; -import '../validator/validator.dart'; +import '../validation.dart'; import 'build_output.dart'; import 'link_config.dart'; @@ -13,7 +12,7 @@ import 'link_config.dart'; /// files. Each individual asset is assigned a unique asset ID. /// /// The linking script may receive assets from build scripts, which are accessed -/// through [LinkConfig.assets]. They will only be bundled with the final +/// through [LinkConfig.encodedAssets]. They will only be bundled with the final /// application if included in the [LinkOutput]. /// /// @@ -22,9 +21,9 @@ import 'link_config.dart'; /// /// void main(List args) async { /// await link(args, (config, output) async { -/// final dataAssets = config.assets +/// final dataEncodedAssets = config.assets /// .whereType(); -/// output.addAssets(dataAssets); +/// output.addEncodedAssets(dataEncodedAssets); /// }); /// } /// ``` @@ -34,21 +33,15 @@ Future link( ) async { final config = LinkConfig.fromArguments(arguments) as LinkConfigImpl; - // The built assets are dependencies of linking, as the linking should be - // rerun if they change. - final builtAssetsFiles = - config.assets.map((asset) => asset.file).whereType().toList(); - final output = HookOutputImpl( - dependencies: Dependencies(builtAssetsFiles), - ); + final output = HookOutputImpl(); await linker(config, output); - final validateResult = await validateLink(config, output); - if (validateResult.success) { + final errors = await validateLinkOutput(config, output); + if (errors.isEmpty) { await output.writeToFile(config: config); } else { final message = [ 'The output contained unsupported output:', - for (final error in validateResult.errors) '- $error', + for (final error in errors) '- $error', ].join('\n'); throw UnsupportedError(message); } diff --git a/pkgs/native_assets_cli/lib/src/api/link_config.dart b/pkgs/native_assets_cli/lib/src/api/link_config.dart index 0353d0512..a029a460d 100644 --- a/pkgs/native_assets_cli/lib/src/api/link_config.dart +++ b/pkgs/native_assets_cli/lib/src/api/link_config.dart @@ -10,9 +10,9 @@ import 'package:pub_semver/pub_semver.dart'; import '../architecture.dart'; import '../args_parser.dart'; -import '../asset.dart'; import '../build_mode.dart'; import '../c_compiler_config.dart'; +import '../encoded_asset.dart'; import '../ios_sdk.dart'; import '../json_utils.dart'; import '../link_mode_preference.dart'; @@ -27,11 +27,11 @@ part '../model/link_config.dart'; /// The configuration for a link hook (`hook/link.dart`) invocation. /// /// It consists of a subset of the fields from the [BuildConfig] already passed -/// to the build hook and the [assets] from the build step. +/// to the build hook and the [encodedAssets] from the build step. abstract class LinkConfig implements HookConfig { /// The list of assets to be linked. These are the assets generated by a /// `build.dart` script destined for this packages `link.dart`. - Iterable get assets; + Iterable get encodedAssets; /// The path to the file containing recorded uses after kernel tree-shaking. /// @@ -55,15 +55,15 @@ abstract class LinkConfig implements HookConfig { int? targetMacOSVersion, CCompilerConfig? cCompiler, BuildMode? buildMode, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, int? targetAndroidNdkApi, - required Iterable assets, + required Iterable assets, required LinkModePreference linkModePreference, bool? dryRun, Version? version, }) => LinkConfigImpl( - assets: assets.cast(), + encodedAssets: assets, outputDirectory: outputDirectory, outputDirectoryShared: outputDirectoryShared, packageName: packageName, @@ -88,13 +88,13 @@ abstract class LinkConfig implements HookConfig { required String packageName, required Uri packageRoot, required OS targetOS, - Iterable? supportedAssetTypes, - required Iterable assets, + required Iterable supportedAssetTypes, + required Iterable assets, required LinkModePreference linkModePreference, Version? version, }) => LinkConfigImpl.dryRun( - assets: assets.cast(), + encodedAssets: assets, outputDirectory: outputDirectory, outputDirectoryShared: outputDirectoryShared, packageName: packageName, diff --git a/pkgs/native_assets_cli/lib/src/api/link_output.dart b/pkgs/native_assets_cli/lib/src/api/link_output.dart index 77b7bb030..e90ace891 100644 --- a/pkgs/native_assets_cli/lib/src/api/link_output.dart +++ b/pkgs/native_assets_cli/lib/src/api/link_output.dart @@ -27,7 +27,7 @@ abstract final class LinkOutput { /// /// In dry runs, the assets for all [Architecture]s for the [OS] specified in /// the dry run must be provided. - Iterable get assets; + Iterable get encodedAssets; /// The files used by this link. /// @@ -47,19 +47,19 @@ abstract final class LinkOutput { /// re-run. void addDependencies(Iterable dependencies); - /// Adds [Asset]s produced by this link or dry run. - void addAsset(Asset asset); + /// Adds [EncodedAsset]s produced by this link or dry run. + void addEncodedAsset(EncodedAsset asset); - /// Adds [Asset]s produced by this link or dry run. - void addAssets(Iterable assets); + /// Adds [EncodedAsset]s produced by this link or dry run. + void addEncodedAssets(Iterable assets); factory LinkOutput({ - Iterable? assets, + Iterable? encodedAssets, Dependencies? dependencies, DateTime? timestamp, }) => HookOutputImpl( - assets: assets, + encodedAssets: encodedAssets, dependencies: dependencies, timestamp: timestamp, ); diff --git a/pkgs/native_assets_cli/lib/src/api/test.dart b/pkgs/native_assets_cli/lib/src/api/test.dart index 4efd0dbd0..df1782c15 100644 --- a/pkgs/native_assets_cli/lib/src/api/test.dart +++ b/pkgs/native_assets_cli/lib/src/api/test.dart @@ -9,9 +9,10 @@ import 'package:test/test.dart'; import 'package:yaml/yaml.dart'; import '../architecture.dart'; -import '../asset.dart'; import '../build_mode.dart'; import '../c_compiler_config.dart'; +import '../code_assets/code_asset.dart'; +import '../data_assets/data_asset.dart'; import '../ios_sdk.dart'; import '../link_mode_preference.dart'; import '../os.dart'; @@ -33,7 +34,7 @@ Future testBuildHook({ int? targetAndroidNdkApi, CCompilerConfig? cCompiler, LinkModePreference? linkModePreference, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, bool? linkingEnabled, }) async { test( @@ -69,23 +70,27 @@ Future testBuildHook({ await mainMethod(['--config=${buildConfigUri.toFilePath()}']); - final hookOutput = await _readOutput(buildConfig); + final hookOutput = await _readOutput(buildConfig) as BuildOutput; check(buildConfig, hookOutput); - final allAssets = [ - ...hookOutput.assets, - ...hookOutput.assetsForLinking.values.expand((e) => e) + final allEncodedAssets = [ + ...hookOutput.encodedAssets, + ...hookOutput.encodedAssetsForLinking.values.expand((e) => e) ]; - for (final asset in allAssets.where((asset) => asset.file != null)) { - final file = File.fromUri(asset.file!); - expect(await file.exists(), true); + for (final asset in allEncodedAssets) { + expect(buildConfig.supportedAssetTypes, contains(asset.type)); } - if (allAssets.any((asset) => asset is CodeAsset)) { - expect(buildConfig.supportedAssetTypes, CodeAsset.type); + + for (final asset in hookOutput.dataAssets.all) { + final file = File.fromUri(asset.file); + expect(await file.exists(), true); } - if (allAssets.any((asset) => asset is DataAsset)) { - expect(buildConfig.supportedAssetTypes, DataAsset.type); + for (final asset in hookOutput.codeAssets.all) { + if (asset.file != null) { + final file = File.fromUri(asset.file!); + expect(await file.exists(), true); + } } }, ); diff --git a/pkgs/native_assets_cli/lib/src/asset.dart b/pkgs/native_assets_cli/lib/src/asset.dart deleted file mode 100644 index ef2385bdc..000000000 --- a/pkgs/native_assets_cli/lib/src/asset.dart +++ /dev/null @@ -1,95 +0,0 @@ -// 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 'api/build_config.dart'; -import 'api/build_output.dart'; -import 'architecture.dart'; -import 'json_utils.dart'; -import 'link_mode.dart'; -import 'os.dart'; -import 'utils/map.dart'; - -part 'code_asset.dart'; -part 'data_asset.dart'; - -/// Data or code bundled with a Dart or Flutter application. -/// -/// An asset is data or code which is accessible from a Dart or Flutter -/// application. To access an asset at runtime, the asset [id] is used. -abstract final class Asset { - /// The identifier for this asset. - /// - /// An [Asset] has a string identifier called "asset id". Dart code that uses - /// an asset references the asset using this asset id. - /// - /// An asset identifier consists of two elements, the `package` and `name`, - /// which together make a library uri `package:/`. The package - /// being part of the identifer prevents name collisions between assets of - /// different packages. - /// - /// The default asset id for an asset reference from `lib/src/foo.dart` is - /// `'package:foo/src/foo.dart'`. For example a [CodeAsset] can be accessed - /// via `@Native` with the `assetId` argument omitted: - /// - /// ```dart - /// // file package:foo/src/foo.dart - /// @Native() - /// external int add(int a, int b); - /// ``` - /// - /// This will be then automatically expanded to - /// - /// ```dart - /// // file package:foo/src/foo.dart - /// @Native(assetId: 'package:foo/src/foo.dart') - /// external int add(int a, int b); - /// ``` - String get id; - - /// The file to be bundled with the Dart or Flutter application. - /// - /// How this file is bundled depends on the kind of asset, represented by a - /// concrete subtype of [Asset], and the SDK (Dart or Flutter). - /// - /// The file can be omitted in the [BuildOutput] for [BuildConfig.dryRun]. - /// - /// The file can also be omitted for asset types which refer to an asset - /// already present on the target system or an asset already present in Dart - /// or Flutter. - Uri? get file; - - /// A json representation of this [Asset]. - Map toJson(); - - static List listFromJson(List? list) { - final assets = []; - if (list == null) return assets; - for (var i = 0; i < list.length; ++i) { - final jsonMap = list.mapAt(i); - final type = jsonMap[_typeKey]; - switch (type) { - case CodeAsset.type: - assets.add(CodeAsset.fromJson(jsonMap)); - case DataAsset.type: - assets.add(DataAsset.fromJson(jsonMap)); - default: - // Do nothing, some other launcher might define it's own asset types. - } - } - return assets; - } - - static List> listToJson(Iterable assets) => [ - for (final asset in assets) asset.toJson(), - ]; -} - -const _architectureKey = 'architecture'; -const _fileKey = 'file'; -const _idKey = 'id'; -const _linkModeKey = 'link_mode'; -const _nameKey = 'name'; -const _osKey = 'os'; -const _packageKey = 'package'; -const _typeKey = 'type'; diff --git a/pkgs/native_assets_cli/lib/src/code_asset.dart b/pkgs/native_assets_cli/lib/src/code_assets/code_asset.dart similarity index 71% rename from pkgs/native_assets_cli/lib/src/code_asset.dart rename to pkgs/native_assets_cli/lib/src/code_assets/code_asset.dart index 51789000e..2a13e71ca 100644 --- a/pkgs/native_assets_cli/lib/src/code_asset.dart +++ b/pkgs/native_assets_cli/lib/src/code_assets/code_asset.dart @@ -2,9 +2,18 @@ // 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. -part of 'asset.dart'; +import '../api/build_config.dart'; +import '../api/build_output.dart'; +import '../api/link_config.dart'; +import '../architecture.dart'; +import '../encoded_asset.dart'; +import '../json_utils.dart'; +import '../link_mode.dart'; +import '../os.dart'; +import '../utils/json.dart'; +import '../utils/map.dart'; -/// A code [Asset] which respects the native application binary interface (ABI). +/// A code asset which respects the native application binary interface (ABI). /// /// Typical languages which produce code assets that respect the native ABI /// include C, C++ (with `extern "C"`), Rust (with `extern "C"`), and a subset @@ -45,9 +54,8 @@ part of 'asset.dart'; /// "manually", the Dart or Flutter SDK will take care of copying the asset /// [file] from its specified location on the current system into the /// application bundle. -final class CodeAsset implements Asset { +final class CodeAsset { /// The id of this code asset. - @override final String id; /// The operating system this asset can run on. @@ -73,7 +81,6 @@ final class CodeAsset implements Asset { /// If the [linkMode] is [DynamicLoadingSystem], [LookupInProcess], or /// [LookupInExecutable] the file must be omitted in the [BuildOutput] for /// [BuildConfig.dryRun]. - @override final Uri? file; /// Constructs a native code asset. @@ -101,24 +108,18 @@ final class CodeAsset implements Asset { required this.os, required this.file, required this.architecture, - }) { - if (linkMode is DynamicLoading && - linkMode is! DynamicLoadingBundled && - file != null) { - throw ArgumentError.value( - file, - 'file', - 'Must be null if dynamicLoading is not BundledDylib.', - ); - } - } + }); + + factory CodeAsset.fromEncoded(EncodedAsset asset) { + assert(asset.type == CodeAsset.type); + final jsonMap = asset.encoding; - factory CodeAsset.fromJson(Map jsonMap) { - final linkMode = LinkMode.fromJson(jsonMap.map$(_linkModeKey)); + final linkMode = + LinkMode.fromJson(as>(jsonMap[_linkModeKey])); final fileString = jsonMap.optionalString(_fileKey); final Uri? file; if (fileString != null) { - file = Uri(path: fileString); + file = Uri.file(fileString); } else { file = null; } @@ -176,19 +177,72 @@ final class CodeAsset implements Asset { file, ); - @override - Map toJson() => { + EncodedAsset encode() => EncodedAsset( + CodeAsset.type, + { if (architecture != null) _architectureKey: architecture.toString(), if (file != null) _fileKey: file!.toFilePath(), _idKey: id, _linkModeKey: linkMode.toJson(), _osKey: os.toString(), - _typeKey: CodeAsset.type, - }..sortOnKey(); + }..sortOnKey()); static const String type = 'native_code'; } +/// Build output extension for code assets. +extension CodeAssetsBuildOutput on BuildOutput { + BuildOutputCodeAssets get codeAssets => BuildOutputCodeAssets(this); +} + +extension type BuildOutputCodeAssets(BuildOutput _output) { + void add(CodeAsset asset, {String? linkInPackage}) => + _output.addEncodedAsset(asset.encode(), linkInPackage: linkInPackage); + + void addAll(Iterable assets, {String? linkInPackage}) { + for (final asset in assets) { + add(asset, linkInPackage: linkInPackage); + } + } + + Iterable get all => _output.encodedAssets + .where((e) => e.type == CodeAsset.type) + .map(CodeAsset.fromEncoded); +} + +/// Link output extension for code assets. +extension CodeAssetsLinkConfig on LinkConfig { + LinkConfigCodeAssets get codeAssets => LinkConfigCodeAssets(this); +} + +extension type LinkConfigCodeAssets(LinkConfig _config) { + // Returns the code assets that were sent to this linker. + // + // NOTE: If the linker implementation depends on the contents of the files the + // code assets refer (e.g. looks at static archives and links them) then the + // linker script has to add those files as dependencies via + // [LinkOutput.addDependency] to ensure the linker script will be re-run if + // the content of the files changes. + Iterable get all => _config.encodedAssets + .where((e) => e.type == CodeAsset.type) + .map(CodeAsset.fromEncoded); +} + +/// Link output extension for code assets. +extension CodeAssetsLinkOutput on LinkOutput { + LinkOutputCodeAssets get codeAssets => LinkOutputCodeAssets(this); +} + +extension type LinkOutputCodeAssets(LinkOutput _output) { + void add(CodeAsset asset) => _output.addEncodedAsset(asset.encode()); + + void addAll(Iterable assets) => assets.forEach(add); + + Iterable get all => _output.encodedAssets + .where((e) => e.type == CodeAsset.type) + .map(CodeAsset.fromEncoded); +} + extension OSLibraryNaming on OS { /// The default dynamic library file name on this os. String dylibFileName(String name) { @@ -263,3 +317,9 @@ const _executableExtension = { OS.macOS: '', OS.windows: 'exe', }; + +const _idKey = 'id'; +const _linkModeKey = 'link_mode'; +const _fileKey = 'file'; +const _osKey = 'os'; +const _architectureKey = 'architecture'; diff --git a/pkgs/native_assets_cli/lib/src/code_assets/validation.dart b/pkgs/native_assets_cli/lib/src/code_assets/validation.dart new file mode 100644 index 000000000..4910f2ed6 --- /dev/null +++ b/pkgs/native_assets_cli/lib/src/code_assets/validation.dart @@ -0,0 +1,144 @@ +// 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 'dart:io'; + +import '../../native_assets_cli_internal.dart'; +import '../link_mode.dart'; + +Future validateCodeAssetBuildOutput( + HookConfig config, + BuildOutput output, +) => + _validateCodeAssetBuildOrLinkOutput(config, output as HookOutputImpl, true); + +Future validateCodeAssetLinkOutput( + HookConfig config, + LinkOutput output, +) => + _validateCodeAssetBuildOrLinkOutput( + config, output as HookOutputImpl, false); + +/// Validates that the given code assets can be used together in an application. +/// +/// Some restrictions - e.g. unique shared library names - have to be validated +/// on the entire application build and not on individual `hook/build.dart` +/// invocations. +Future validateCodeAssetsInApplication( + List assets) async { + final fileNameToEncodedAssetId = >{}; + for (final asset in assets) { + if (asset.type != CodeAsset.type) continue; + _groupCodeAssetsByFilename( + CodeAsset.fromEncoded(asset), fileNameToEncodedAssetId); + } + final errors = []; + _validateNoDuplicateDylibNames(errors, fileNameToEncodedAssetId); + return errors; +} + +Future _validateCodeAssetBuildOrLinkOutput( + HookConfig config, + HookOutputImpl output, + bool isBuild, +) async { + final errors = []; + final ids = {}; + final fileNameToEncodedAssetId = >{}; + + for (final asset in output.encodedAssets) { + if (asset.type != CodeAsset.type) continue; + _validateCodeAssets( + config, + config.dryRun, + CodeAsset.fromEncoded(asset), + errors, + ids, + isBuild, + ); + _groupCodeAssetsByFilename( + CodeAsset.fromEncoded(asset), fileNameToEncodedAssetId); + } + _validateNoDuplicateDylibNames(errors, fileNameToEncodedAssetId); + return errors; +} + +void _validateCodeAssets( + HookConfig config, + bool dryRun, + CodeAsset codeAsset, + List errors, + Set ids, + bool isBuild, +) { + final id = codeAsset.id; + final prefix = 'package:${config.packageName}/'; + if (isBuild && !id.startsWith(prefix)) { + errors.add('Code asset "$id" does not start with "$prefix".'); + } + if (!ids.add(id)) { + errors.add('More than one code asset with same "$id" id.'); + } + + final preference = config.linkModePreference; + final linkMode = codeAsset.linkMode; + if ((linkMode is DynamicLoading && preference == LinkModePreference.static) || + (linkMode is StaticLinking && preference == LinkModePreference.dynamic)) { + errors.add('CodeAsset "$id" has a link mode "$linkMode", which ' + 'is not allowed by by the config link mode preference ' + '"$preference".'); + } + + final os = codeAsset.os; + if (config.targetOS != os) { + final error = 'CodeAsset "$id" has a os "$os", which ' + 'is not the target os "${config.targetOS}".'; + errors.add(error); + } + + final architecture = codeAsset.architecture; + if (!dryRun) { + if (architecture == null) { + errors.add('CodeAsset "$id" has no architecture.'); + } else if (architecture != config.targetArchitecture) { + errors.add('CodeAsset "$id" has an architecture "$architecture", which ' + 'is not the target architecture "${config.targetArchitecture}".'); + } + } + + final file = codeAsset.file; + if (file == null && !dryRun) { + errors.add('CodeAsset "$id" has no file.'); + } + if (file != null && !dryRun && !File.fromUri(file).existsSync()) { + errors.add('CodeAsset "$id" has a file "${file.toFilePath()}", which ' + 'does not exist.'); + } +} + +void _groupCodeAssetsByFilename( + CodeAsset codeAsset, + Map> fileNameToEncodedAssetId, +) { + final file = codeAsset.file; + if (file != null) { + final fileName = file.pathSegments.where((s) => s.isNotEmpty).last; + fileNameToEncodedAssetId[fileName] ??= {}; + fileNameToEncodedAssetId[fileName]!.add(codeAsset.id); + } +} + +void _validateNoDuplicateDylibNames( + List errors, Map> fileNameToEncodedAssetId) { + for (final fileName in fileNameToEncodedAssetId.keys) { + final assetIds = fileNameToEncodedAssetId[fileName]!; + if (assetIds.length > 1) { + final assetIdsString = assetIds.map((e) => '"$e"').join(', '); + final error = + 'Duplicate dynamic library file name "$fileName" for the following' + ' asset ids: $assetIdsString.'; + errors.add(error); + } + } +} diff --git a/pkgs/native_assets_cli/lib/src/data_asset.dart b/pkgs/native_assets_cli/lib/src/data_asset.dart deleted file mode 100644 index f8493b875..000000000 --- a/pkgs/native_assets_cli/lib/src/data_asset.dart +++ /dev/null @@ -1,87 +0,0 @@ -// 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. - -part of 'asset.dart'; - -/// Data bundled with a Dart or Flutter application. -/// -/// A data asset is accessible in a Dart or Flutter application. To retrieve an -/// asset at runtime, the [id] is used. This enables access to the asset -/// irrespective of how and where the application is run. -/// -/// An data asset must provide a [Asset.file]. The Dart and Flutter SDK will -/// bundle this code in the final application. -final class DataAsset extends Asset { - /// The file to be bundled with the Dart or Flutter application. - /// - /// The file can be omitted in the [BuildOutput] for [BuildConfig.dryRun]. - /// - /// The file can also be omitted for asset types which refer to an asset - /// already present on the target system or an asset already present in Dart - /// or Flutter. - @override - final Uri file; - - /// The name of this asset, which must be unique for the package. - final String name; - - /// The package which contains this asset. - final String package; - - /// The identifier for this data asset. - /// - /// An [DataAsset] has a string identifier called "asset id". Dart code that - /// uses an asset references the asset using this asset id. - /// - /// An asset identifier consists of two elements, the `package` and `name`, - /// which together make a library uri `package:/`. The package - /// being part of the identifer prevents name collisions between assets of - /// different packages. - @override - String get id => 'package:$package/$name'; - - DataAsset({ - required this.file, - required this.name, - required this.package, - }); - - /// Constructs a [DataAsset] from a json representation obtained via - /// [DataAsset.toJson]. - factory DataAsset.fromJson(Map jsonMap) => DataAsset( - name: jsonMap.string(_nameKey), - package: jsonMap.string(_packageKey), - file: jsonMap.path(_fileKey), - ); - - @override - bool operator ==(Object other) { - if (other is! DataAsset) { - return false; - } - return other.package == package && - other.file.toFilePath() == file.toFilePath() && - other.name == name; - } - - @override - int get hashCode => Object.hash( - package, - name, - file.toFilePath(), - ); - - @override - Map toJson() => { - _nameKey: name, - _packageKey: package, - _fileKey: file.toFilePath(), - _typeKey: DataAsset.type, - }..sortOnKey(); - - @override - String toString() => 'DataAsset(${toJson()})'; - - static const String type = 'data'; -} diff --git a/pkgs/native_assets_cli/lib/src/data_assets/data_asset.dart b/pkgs/native_assets_cli/lib/src/data_assets/data_asset.dart new file mode 100644 index 000000000..9c79b0629 --- /dev/null +++ b/pkgs/native_assets_cli/lib/src/data_assets/data_asset.dart @@ -0,0 +1,150 @@ +// 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 '../api/build_config.dart'; +import '../api/build_output.dart'; +import '../api/link_config.dart'; +import '../encoded_asset.dart'; +import '../json_utils.dart'; +import '../utils/map.dart'; + +/// Data bundled with a Dart or Flutter application. +/// +/// A data asset is accessible in a Dart or Flutter application. To retrieve an +/// asset at runtime, the [id] is used. This enables access to the asset +/// irrespective of how and where the application is run. +/// +/// An data asset must provide a [DataAsset.file]. The Dart and Flutter SDK will +/// bundle this code in the final application. +final class DataAsset { + /// The file to be bundled with the Dart or Flutter application. + /// + /// The file can be omitted in the [BuildOutput] for [BuildConfig.dryRun]. + /// + /// The file can also be omitted for asset types which refer to an asset + /// already present on the target system or an asset already present in Dart + /// or Flutter. + final Uri file; + + /// The name of this asset, which must be unique for the package. + final String name; + + /// The package which contains this asset. + final String package; + + /// The identifier for this data asset. + /// + /// An [DataAsset] has a string identifier called "asset id". Dart code that + /// uses an asset references the asset using this asset id. + /// + /// An asset identifier consists of two elements, the `package` and `name`, + /// which together make a library uri `package:/`. The package + /// being part of the identifer prevents name collisions between assets of + /// different packages. + String get id => 'package:$package/$name'; + + DataAsset({ + required this.file, + required this.name, + required this.package, + }); + + /// Constructs a [DataAsset] from an [EncodedAsset]. + factory DataAsset.fromEncoded(EncodedAsset asset) { + assert(asset.type == DataAsset.type); + final jsonMap = asset.encoding; + return DataAsset( + name: jsonMap.string(_nameKey), + package: jsonMap.string(_packageKey), + file: jsonMap.path(_fileKey), + ); + } + + @override + bool operator ==(Object other) { + if (other is! DataAsset) { + return false; + } + return other.package == package && + other.file.toFilePath() == file.toFilePath() && + other.name == name; + } + + @override + int get hashCode => Object.hash( + package, + name, + file.toFilePath(), + ); + + EncodedAsset encode() => EncodedAsset( + DataAsset.type, + { + _nameKey: name, + _packageKey: package, + _fileKey: file.toFilePath(), + }..sortOnKey()); + + @override + String toString() => 'DataAsset(${encode().encoding})'; + + static const String type = 'data'; +} + +/// Build output extension for data assets. +extension DataAssetsBuildOutput on BuildOutput { + BuildOutputDataAssets get dataAssets => BuildOutputDataAssets(this); +} + +extension type BuildOutputDataAssets(BuildOutput _output) { + void add(DataAsset asset, {String? linkInPackage}) => + _output.addEncodedAsset(asset.encode(), linkInPackage: linkInPackage); + + void addAll(Iterable assets, {String? linkInPackage}) { + for (final asset in assets) { + add(asset, linkInPackage: linkInPackage); + } + } + + Iterable get all => _output.encodedAssets + .where((e) => e.type == DataAsset.type) + .map(DataAsset.fromEncoded); +} + +/// Link output extension for data assets. +extension DataAssetsLinkConfig on LinkConfig { + LinkConfigDataAssets get dataAssets => LinkConfigDataAssets(this); +} + +extension type LinkConfigDataAssets(LinkConfig _config) { + // Returns the data assets that were sent to this linker. + // + // NOTE: If the linker implementation depends on the contents of the files of + // the data assets (e.g. by transforming them, merging with other files, etc) + // then the linker script has to add those files as dependencies via + // [LinkOutput.addDependency] to ensure the linker script will be re-run if + // the content of the files changes. + Iterable get all => _config.encodedAssets + .where((e) => e.type == DataAsset.type) + .map(DataAsset.fromEncoded); +} + +/// Link output extension for data assets. +extension DataAssetsLinkOutput on LinkOutput { + LinkOutputDataAssets get dataAssets => LinkOutputDataAssets(this); +} + +extension type LinkOutputDataAssets(LinkOutput _output) { + void add(DataAsset asset) => _output.addEncodedAsset(asset.encode()); + + void addAll(Iterable assets) => assets.forEach(add); + + Iterable get all => _output.encodedAssets + .where((e) => e.type == DataAsset.type) + .map(DataAsset.fromEncoded); +} + +const _nameKey = 'name'; +const _packageKey = 'package'; +const _fileKey = 'file'; diff --git a/pkgs/native_assets_cli/lib/src/data_assets/validation.dart b/pkgs/native_assets_cli/lib/src/data_assets/validation.dart new file mode 100644 index 000000000..d6dd9de36 --- /dev/null +++ b/pkgs/native_assets_cli/lib/src/data_assets/validation.dart @@ -0,0 +1,58 @@ +// 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 'dart:io'; + +import '../../native_assets_cli_internal.dart'; + +Future validateDataAssetBuildOutput( + HookConfig config, + BuildOutput output, +) => + _validateDataAssetBuildOrLinkOutput(config, output as HookOutputImpl, true); + +Future validateDataAssetLinkOutput( + HookConfig config, + LinkOutput output, +) => + _validateDataAssetBuildOrLinkOutput( + config, output as HookOutputImpl, false); + +Future _validateDataAssetBuildOrLinkOutput( + HookConfig config, + HookOutputImpl output, + bool isBuild, +) async { + final errors = []; + final ids = {}; + + for (final asset in output.encodedAssets) { + if (asset.type != DataAsset.type) continue; + _validateDataAssets(config, config.dryRun, DataAsset.fromEncoded(asset), + errors, ids, isBuild); + } + return errors; +} + +void _validateDataAssets( + HookConfig config, + bool dryRun, + DataAsset dataAsset, + List errors, + Set ids, + bool isBuild, +) { + if (isBuild && dataAsset.package != config.packageName) { + errors.add('Data asset must have package name ${config.packageName}'); + } + if (!ids.add(dataAsset.name)) { + errors.add('More than one code asset with same "${dataAsset.name}" name.'); + } + final file = dataAsset.file; + if (!dryRun && (!File.fromUri(file).existsSync())) { + errors.add( + 'EncodedAsset "${dataAsset.name}" has a file "${file.toFilePath()}", ' + 'which does not exist.'); + } +} diff --git a/pkgs/native_assets_cli/lib/src/encoded_asset.dart b/pkgs/native_assets_cli/lib/src/encoded_asset.dart new file mode 100644 index 000000000..4232bb890 --- /dev/null +++ b/pkgs/native_assets_cli/lib/src/encoded_asset.dart @@ -0,0 +1,46 @@ +// 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:collection/collection.dart'; + +import 'json_utils.dart'; +import 'utils/map.dart'; + +/// An encoding of a particular asset type. +final class EncodedAsset { + /// The type of the asset (e.g. whether it's a code asset, data asset or ...) + final String type; + + /// The json encoding of the asset. + final Map encoding; + + EncodedAsset(this.type, this.encoding); + + /// Decode an [EncodedAsset] from json. + factory EncodedAsset.fromJson(Map json) => + EncodedAsset(json.get(_typeKey), { + for (final key in json.keys) + if (key != _typeKey) key: json[key] + }); + + /// Encode this [EncodedAsset] tojson. + Map toJson() => { + for (final key in encoding.keys) key: encoding[key], + _typeKey: type, + }..sortOnKey(); + + @override + String toString() => 'EncodedAsset($type, $encoding)'; + + @override + int get hashCode => Object.hash(type, const DeepCollectionEquality().hash); + + @override + bool operator ==(Object other) => + other is EncodedAsset && + type == other.type && + const DeepCollectionEquality().equals(encoding, other.encoding); +} + +const String _typeKey = 'type'; diff --git a/pkgs/native_assets_cli/lib/src/json_utils.dart b/pkgs/native_assets_cli/lib/src/json_utils.dart index e177ff4a1..1680a1247 100644 --- a/pkgs/native_assets_cli/lib/src/json_utils.dart +++ b/pkgs/native_assets_cli/lib/src/json_utils.dart @@ -41,6 +41,8 @@ extension MapJsonUtils on Map { return value.cast(); } + List stringList(String key) => get>(key).cast(); + List list(String key) => get>(key); List? optionalList(String key) => getOptional>(key); Map map$(String key) => get>(key); diff --git a/pkgs/native_assets_cli/lib/src/link_mode.dart b/pkgs/native_assets_cli/lib/src/link_mode.dart index 53b3295c7..bd02c1a7d 100644 --- a/pkgs/native_assets_cli/lib/src/link_mode.dart +++ b/pkgs/native_assets_cli/lib/src/link_mode.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'api/build_config.dart'; -import 'asset.dart'; +import 'code_assets/code_asset.dart'; /// The link mode for a [CodeAsset]. /// diff --git a/pkgs/native_assets_cli/lib/src/link_mode_preference.dart b/pkgs/native_assets_cli/lib/src/link_mode_preference.dart index f1d667515..f5a37580b 100644 --- a/pkgs/native_assets_cli/lib/src/link_mode_preference.dart +++ b/pkgs/native_assets_cli/lib/src/link_mode_preference.dart @@ -2,7 +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 'asset.dart'; +import 'code_assets/code_asset.dart'; /// The preferred linkMode method for [CodeAsset]s. final class LinkModePreference { diff --git a/pkgs/native_assets_cli/lib/src/model/build_config.dart b/pkgs/native_assets_cli/lib/src/model/build_config.dart index c7a64f4e5..01b3ca7ce 100644 --- a/pkgs/native_assets_cli/lib/src/model/build_config.dart +++ b/pkgs/native_assets_cli/lib/src/model/build_config.dart @@ -40,11 +40,6 @@ final class BuildConfigImpl extends HookConfigImpl implements BuildConfig { final bool? _linkingEnabled; - static List _supportedAssetTypesBackwardsCompatibility( - Iterable? supportedAssetTypes, - ) => - supportedAssetTypes?.toList() ?? [CodeAsset.type]; - BuildConfigImpl({ required super.outputDirectory, required super.outputDirectoryShared, @@ -53,7 +48,7 @@ final class BuildConfigImpl extends HookConfigImpl implements BuildConfig { Version? version, super.buildMode, super.cCompiler, - Iterable? supportedAssetTypes, + required super.supportedAssetTypes, super.targetAndroidNdkApi, required super.targetArchitecture, super.targetIOSSdk, @@ -69,8 +64,6 @@ final class BuildConfigImpl extends HookConfigImpl implements BuildConfig { super( hook: Hook.build, version: version ?? HookConfigImpl.latestVersion, - supportedAssetTypes: - _supportedAssetTypesBackwardsCompatibility(supportedAssetTypes), ) { if (this.version < Version(1, 4, 0)) { assert(linkingEnabled == null); @@ -87,14 +80,12 @@ final class BuildConfigImpl extends HookConfigImpl implements BuildConfig { required super.targetOS, required super.linkModePreference, required bool? linkingEnabled, - Iterable? supportedAssetTypes, + required super.supportedAssetTypes, }) : _dependencyMetadata = null, _linkingEnabled = linkingEnabled, super.dryRun( hook: Hook.build, version: HookConfigImpl.latestVersion, - supportedAssetTypes: - _supportedAssetTypesBackwardsCompatibility(supportedAssetTypes), ); static BuildConfigImpl fromArguments( @@ -131,7 +122,8 @@ final class BuildConfigImpl extends HookConfigImpl implements BuildConfig { linkingEnabled: parseHasLinkPhase(config), version: HookConfigImpl.parseVersion(config), cCompiler: HookConfigImpl.parseCCompiler(config, dryRun), - supportedAssetTypes: HookConfigImpl.parseSupportedAssetTypes(config), + supportedAssetTypes: + HookConfigImpl.parseSupportedEncodedAssetTypes(config), targetAndroidNdkApi: HookConfigImpl.parseTargetAndroidNdkApi(config, dryRun, targetOS), targetIOSSdk: HookConfigImpl.parseTargetIOSSdk(config, dryRun, targetOS), diff --git a/pkgs/native_assets_cli/lib/src/model/hook_config.dart b/pkgs/native_assets_cli/lib/src/model/hook_config.dart index 5445e76fd..e209ab38c 100644 --- a/pkgs/native_assets_cli/lib/src/model/hook_config.dart +++ b/pkgs/native_assets_cli/lib/src/model/hook_config.dart @@ -182,8 +182,7 @@ abstract class HookConfigImpl implements HookConfig { packageNameConfigKey: packageName, packageRootConfigKey: packageRoot.toFilePath(), _targetOSConfigKey: targetOS.toString(), - if (supportedAssetTypes.isNotEmpty) - supportedAssetTypesKey: supportedAssetTypes, + supportedAssetTypesKey: supportedAssetTypes, _versionKey: version.toString(), if (dryRun) dryRunConfigKey: dryRun, if (!dryRun) ...{ @@ -366,8 +365,9 @@ abstract class HookConfigImpl implements HookConfig { } } - static List parseSupportedAssetTypes(Map config) => - config.optionalStringList(supportedAssetTypesKey) ?? [CodeAsset.type]; + static List parseSupportedEncodedAssetTypes( + Map config) => + config.optionalStringList(supportedAssetTypesKey) ?? []; static CCompilerConfig parseCCompiler( Map config, bool dryRun) { @@ -466,7 +466,7 @@ can _only_ depend on OS.'''); CCompilerConfig? cCompiler, required LinkModePreference linkModePreference, Map? dependencyMetadata, - Iterable? supportedAssetTypes, + required Iterable supportedAssetTypes, Version? version, required Hook hook, required bool? linkingEnabled, @@ -490,7 +490,7 @@ can _only_ depend on OS.'''); entry.key, json.encode(entry.value.toJson()), ], - ...supportedAssetTypes ?? [CodeAsset.type], + ...supportedAssetTypes, hook.name, linkingEnabled, ].join('###'); diff --git a/pkgs/native_assets_cli/lib/src/model/build_output_CHANGELOG.md b/pkgs/native_assets_cli/lib/src/model/hook_config_CHANGELOG.md similarity index 73% rename from pkgs/native_assets_cli/lib/src/model/build_output_CHANGELOG.md rename to pkgs/native_assets_cli/lib/src/model/hook_config_CHANGELOG.md index 43daa84e6..b295f1428 100644 --- a/pkgs/native_assets_cli/lib/src/model/build_output_CHANGELOG.md +++ b/pkgs/native_assets_cli/lib/src/model/hook_config_CHANGELOG.md @@ -1,6 +1,15 @@ ## 1.6.0 - No changes, but rev version due to BuildConfig change. +- **Breaking change** Link hooks now have to explicitly add any file contents + they rely on via `output.addDependency()` to ensure they re-run if the + content of those files changes. (Previously if a linker script obtained code + or data assets, the files referred to by those assets were implicitly added as + a dependency, but adding custom asset types changed this behavior) + NOTE: Newer Dart & Flutter SDKs will no longer add those dependencies + implicitly which may make some older linker implementations that do not add + dependencies explicitly not work correctly anymore: The linker scripts have + to be updated to add those dependencies explicitly. ## 1.5.0 diff --git a/pkgs/native_assets_cli/lib/src/model/hook_output.dart b/pkgs/native_assets_cli/lib/src/model/hook_output.dart index ac8060586..0d48d9fb7 100644 --- a/pkgs/native_assets_cli/lib/src/model/hook_output.dart +++ b/pkgs/native_assets_cli/lib/src/model/hook_output.dart @@ -8,15 +8,16 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { @override final DateTime timestamp; - final List _assets; + final List _assets; @override - Iterable get assets => _assets; + Iterable get encodedAssets => _assets; - final Map> _assetsForLinking; + final Map> _assetsForLinking; @override - Map> get assetsForLinking => _assetsForLinking; + Map> get encodedAssetsForLinking => + _assetsForLinking; final Dependencies _dependencies; @@ -29,15 +30,15 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { HookOutputImpl({ DateTime? timestamp, - Iterable? assets, - Map>? assetsForLinking, + Iterable? encodedAssets, + Map>? encodedAssetsForLinking, Dependencies? dependencies, Metadata? metadata, }) : timestamp = (timestamp ?? DateTime.now()).roundDownToSeconds(), _assets = [ - ...?assets, + ...?encodedAssets, ], - _assetsForLinking = assetsForLinking ?? {}, + _assetsForLinking = encodedAssetsForLinking ?? {}, // ignore: prefer_const_constructors _dependencies = dependencies ?? Dependencies([]), // ignore: prefer_const_constructors @@ -63,7 +64,7 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { return HookOutputImpl.fromJson(as>(json)); } - factory HookOutputImpl.fromJson(Map jsonMap) { + factory HookOutputImpl.fromJson(Map jsonMap) { final outputVersion = Version.parse(get(jsonMap, 'version')); if (outputVersion.major > latestVersion.major) { throw FormatException( @@ -81,11 +82,19 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { } return HookOutputImpl( timestamp: DateTime.parse(get(jsonMap, _timestampKey)), - assets: Asset.listFromJson(get?>(jsonMap, _assetsKey)), - assetsForLinking: - get?>(jsonMap, _assetsForLinkingKey)?.map( - (packageName, assets) => MapEntry( - packageName, Asset.listFromJson(as>(assets)))), + encodedAssets: [ + for (final json in jsonMap.optionalList(_assetsKey) ?? []) + EncodedAsset.fromJson(json as Map), + ], + encodedAssetsForLinking: { + for (final MapEntry(:key, :value) + in (get?>(jsonMap, _assetsForLinkingKey) ?? {}) + .entries) + key: [ + for (final json in value as List) + EncodedAsset.fromJson(json as Map), + ], + }, dependencies: Dependencies.fromJson(get?>(jsonMap, _dependenciesKey)), metadata: @@ -95,13 +104,16 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { Map toJson(Version version) => { _timestampKey: timestamp.toString(), - if (_assets.isNotEmpty) _assetsKey: Asset.listToJson(_assets), + if (_assets.isNotEmpty) + _assetsKey: [ + for (final asset in encodedAssets) asset.toJson(), + ], if (_assetsForLinking.isNotEmpty) - _assetsForLinkingKey: - _assetsForLinking.map((packageName, assets) => MapEntry( - packageName, - Asset.listToJson(assets), - )), + _assetsForLinkingKey: { + for (final MapEntry(:key, :value) + in encodedAssetsForLinking.entries) + key: [for (final asset in value) asset.toJson()], + }, if (_dependencies.dependencies.isNotEmpty) _dependenciesKey: _dependencies.toJson(), if (metadata.metadata.isNotEmpty) _metadataKey: metadata.toJson(), @@ -154,7 +166,7 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { return false; } return other.timestamp == timestamp && - const ListEquality().equals(other._assets, _assets) && + const ListEquality().equals(other._assets, _assets) && other._dependencies == _dependencies && other.metadata == metadata; } @@ -162,7 +174,7 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { @override int get hashCode => Object.hash( timestamp.hashCode, - const ListEquality().hash(_assets), + const ListEquality().hash(_assets), _dependencies, metadata, ); @@ -180,23 +192,26 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { Metadata get metadataModel => metadata; @override - void addAsset(Asset asset, {String? linkInPackage}) { - _getAssetList(linkInPackage).add(asset); + void addEncodedAsset(EncodedAsset asset, {String? linkInPackage}) { + _getEncodedAssetList(linkInPackage).add(asset); } @override - void addAssets(Iterable assets, {String? linkInPackage}) { - _getAssetList(linkInPackage).addAll(assets.cast()); + void addEncodedAssets(Iterable assets, + {String? linkInPackage}) { + _getEncodedAssetList(linkInPackage).addAll(assets.cast()); } - List _getAssetList(String? linkInPackage) => linkInPackage == null - ? _assets - : (_assetsForLinking[linkInPackage] ??= []); + List _getEncodedAssetList(String? linkInPackage) => + linkInPackage == null + ? _assets + : (_assetsForLinking[linkInPackage] ??= []); - HookOutputImpl copyWith({Iterable? assets}) => HookOutputImpl( + HookOutputImpl copyWith({Iterable? encodedAssets}) => + HookOutputImpl( timestamp: timestamp, - assets: assets?.toList() ?? _assets, - assetsForLinking: assetsForLinking, + encodedAssets: encodedAssets?.toList() ?? _assets, + encodedAssetsForLinking: encodedAssetsForLinking, dependencies: _dependencies, metadata: metadata, ); diff --git a/pkgs/native_assets_cli/lib/src/model/link_config.dart b/pkgs/native_assets_cli/lib/src/model/link_config.dart index f3507979a..0f46876a7 100644 --- a/pkgs/native_assets_cli/lib/src/model/link_config.dart +++ b/pkgs/native_assets_cli/lib/src/model/link_config.dart @@ -6,15 +6,15 @@ part of '../api/link_config.dart'; /// The input to the linking script. /// -/// It consists of the fields inherited from the [HookConfig] and the [assets] -/// from the build step. +/// It consists of the fields inherited from the [HookConfig] and the +/// [encodedAssets] from the build step. class LinkConfigImpl extends HookConfigImpl implements LinkConfig { static const resourceIdentifierKey = 'resource_identifiers'; static const assetsKey = 'assets'; @override - final Iterable assets; + final Iterable encodedAssets; // TODO: Placeholder for the resources.json file URL. We don't want to change // native_assets_builder when implementing the parsing. @@ -22,7 +22,7 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { final Uri? recordedUsagesFile; LinkConfigImpl({ - required this.assets, + required this.encodedAssets, this.recordedUsagesFile, required super.outputDirectory, required super.outputDirectoryShared, @@ -31,7 +31,7 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { Version? version, required super.buildMode, super.cCompiler, - Iterable? supportedAssetTypes, + required super.supportedAssetTypes, super.targetAndroidNdkApi, super.targetArchitecture, super.targetIOSSdk, @@ -43,24 +43,22 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { }) : super( hook: Hook.link, version: version ?? HookConfigImpl.latestVersion, - supportedAssetTypes: supportedAssetTypes ?? [CodeAsset.type], ); LinkConfigImpl.dryRun({ - required this.assets, + required this.encodedAssets, this.recordedUsagesFile, required super.outputDirectory, required super.outputDirectoryShared, required super.packageName, required super.packageRoot, Version? version, - Iterable? supportedAssetTypes, + required super.supportedAssetTypes, required super.linkModePreference, required super.targetOS, }) : super.dryRun( hook: Hook.link, version: version ?? HookConfigImpl.latestVersion, - supportedAssetTypes: supportedAssetTypes ?? [CodeAsset.type], ); @override @@ -74,7 +72,10 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { ...hookToJson(), if (recordedUsagesFile != null) resourceIdentifierKey: recordedUsagesFile!.toFilePath(), - assetsKey: Asset.listToJson(assets), + if (encodedAssets.isNotEmpty) + assetsKey: [ + for (final asset in encodedAssets) asset.toJson(), + ], }.sortOnKey(); static LinkConfig fromArguments(List arguments) { @@ -101,7 +102,8 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { linkModePreference: HookConfigImpl.parseLinkModePreference(config), version: HookConfigImpl.parseVersion(config), cCompiler: HookConfigImpl.parseCCompiler(config, dryRun), - supportedAssetTypes: HookConfigImpl.parseSupportedAssetTypes(config), + supportedAssetTypes: + HookConfigImpl.parseSupportedEncodedAssetTypes(config), targetAndroidNdkApi: HookConfigImpl.parseTargetAndroidNdkApi(config, dryRun, targetOS), targetIOSSdk: HookConfigImpl.parseTargetIOSSdk(config, dryRun, targetOS), @@ -109,7 +111,10 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { HookConfigImpl.parseTargetIosVersion(config, dryRun, targetOS), targetMacOSVersion: HookConfigImpl.parseTargetMacOSVersion(config, dryRun, targetOS), - assets: parseAssets(config), + encodedAssets: [ + for (final json in config.optionalList(assetsKey) ?? []) + EncodedAsset.fromJson(json as Map), + ], recordedUsagesFile: parseRecordedUsagesUri(config), dryRun: dryRun, ); @@ -118,9 +123,6 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { static Uri? parseRecordedUsagesUri(Map config) => config.optionalPath(resourceIdentifierKey); - static List parseAssets(Map config) => - Asset.listFromJson(config.optionalList(assetsKey)); - @override bool operator ==(Object other) { if (super != other) { @@ -132,7 +134,8 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { if (other.recordedUsagesFile != recordedUsagesFile) { return false; } - if (!const DeepCollectionEquality().equals(other.assets, assets)) { + if (!const DeepCollectionEquality() + .equals(other.encodedAssets, encodedAssets)) { return false; } return true; @@ -142,7 +145,7 @@ class LinkConfigImpl extends HookConfigImpl implements LinkConfig { int get hashCode => Object.hashAll([ super.hashCode, recordedUsagesFile, - const DeepCollectionEquality().hash(assets), + const DeepCollectionEquality().hash(encodedAssets), ]); @override diff --git a/pkgs/native_assets_cli/lib/src/utils/map.dart b/pkgs/native_assets_cli/lib/src/utils/map.dart index bb767ed99..8948770fb 100644 --- a/pkgs/native_assets_cli/lib/src/utils/map.dart +++ b/pkgs/native_assets_cli/lib/src/utils/map.dart @@ -2,13 +2,12 @@ // 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. -extension MapSorting, V extends Object> on Map { +extension MapSorting, V extends Object?> on Map { Map sortOnKey() { final result = {}; final keysSorted = keys.toList()..sort(); for (final key in keysSorted) { - final value = this[key]!; - result[key] = value; + result[key] = this[key] as V; } return result; } diff --git a/pkgs/native_assets_cli/lib/src/validation.dart b/pkgs/native_assets_cli/lib/src/validation.dart new file mode 100644 index 000000000..5a17dc31f --- /dev/null +++ b/pkgs/native_assets_cli/lib/src/validation.dart @@ -0,0 +1,69 @@ +// 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 '../native_assets_cli_internal.dart'; + +typedef ValidationErrors = List; + +/// Invoked by package:native_assets_builder +Future validateBuildOutput( + BuildConfig config, + BuildOutput output, +) async { + final errors = [ + ..._validateAssetsForLinking(config, output), + ..._validateOutputAssetTypes(config, output.encodedAssets), + ]; + if (config.linkingEnabled) { + for (final assets in output.encodedAssetsForLinking.values) { + errors.addAll(_validateOutputAssetTypes(config, assets)); + } + } + return errors; +} + +/// Invoked by package:native_assets_builder +Future validateLinkOutput( + LinkConfig config, + LinkOutput output, +) async { + final errors = [ + ..._validateOutputAssetTypes(config, output.encodedAssets), + ]; + return errors; +} + +/// Only output asset types that are supported by the embedder. +List _validateOutputAssetTypes( + HookConfig config, + Iterable assets, +) { + final errors = []; + final supportedAssetTypes = config.supportedAssetTypes; + for (final asset in assets) { + if (!supportedAssetTypes.contains(asset.type)) { + final error = + 'Asset with type "${asset.type}" is not a supported asset type ' + '(${supportedAssetTypes.join(' ')} are supported)'; + errors.add(error); + } + } + return errors; +} + +/// EncodedAssetsForLinking should be empty if linking is not supported. +List _validateAssetsForLinking( + BuildConfig config, + BuildOutput output, +) { + final errors = []; + if (!config.linkingEnabled) { + if (output.encodedAssetsForLinking.isNotEmpty) { + const error = 'BuildOutput.assetsForLinking is not empty while ' + 'BuildConfig.linkingEnabled is false'; + errors.add(error); + } + } + return errors; +} diff --git a/pkgs/native_assets_cli/lib/src/validator/validator.dart b/pkgs/native_assets_cli/lib/src/validator/validator.dart deleted file mode 100644 index 1cfc5f2ea..000000000 --- a/pkgs/native_assets_cli/lib/src/validator/validator.dart +++ /dev/null @@ -1,237 +0,0 @@ -// 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 'dart:io'; - -import '../api/build_config.dart'; -import '../api/build_output.dart'; -import '../api/hook_config.dart'; -import '../api/link_config.dart'; -import '../asset.dart'; -import '../link_mode.dart'; -import '../link_mode_preference.dart'; - -typedef ValidateResult = ({ - bool success, - List errors, -}); - -Future validateBuild( - BuildConfig config, - BuildOutput output, -) async { - output as HookOutputImpl; - final errors = [ - ...validateAssetsForLinking(config, output), - ...validateOutputAssetTypes(config, output), - if (!config.dryRun) ...await validateFilesExist(config, output), - ...validateCodeAssets(config, output), - ...validateAssetId(config, output), - if (!config.dryRun) ...validateNoDuplicateAssetIds(output), - ...validateNoDuplicateDylibs(output.assets), - ]; - return ( - success: errors.isEmpty, - errors: errors, - ); -} - -Future validateLink( - LinkConfig config, - LinkOutput output, -) async { - output as HookOutputImpl; - final errors = [ - ...validateOutputAssetTypes(config, output), - if (!config.dryRun) ...await validateFilesExist(config, output), - ...validateCodeAssets(config, output), - if (!config.dryRun) ...validateNoDuplicateAssetIds(output), - ...validateNoDuplicateDylibs(output.assets), - ]; - - return ( - success: errors.isEmpty, - errors: errors, - ); -} - -/// AssetsForLinking should be empty if linking is not supported. -List validateAssetsForLinking( - BuildConfig config, - BuildOutput output, -) { - final errors = []; - if (!config.linkingEnabled) { - if (output.assetsForLinking.isNotEmpty) { - const error = 'BuildOutput.assetsForLinking is not empty while ' - 'BuildConfig.linkingEnabled is false'; - errors.add(error); - } - } - return errors; -} - -/// Only output asset types that are supported by the embedder. -List validateOutputAssetTypes( - HookConfig config, - HookOutputImpl output, -) { - final errors = []; - final supportedAssetTypes = config.supportedAssetTypes; - for (final asset in output.assets) { - if (!supportedAssetTypes.contains(asset.type)) { - final error = - 'Asset "${asset.id}" has asset type "${asset.type}", which is ' - 'not in supportedAssetTypes'; - errors.add(error); - } - } - return errors; -} - -/// Files mentioned in assets must exist. -Future> validateFilesExist( - HookConfig config, - HookOutputImpl output, -) async { - final errors = []; - - await Future.wait(output.allAssets.map((asset) async { - final file = asset.file; - if (file == null && !config.dryRun) { - final error = 'Asset "${asset.id}" has no file.'; - errors.add(error); - } - if (file != null && !config.dryRun && !await File.fromUri(file).exists()) { - final error = - 'Asset "${asset.id}" has a file "${asset.file!.toFilePath()}", which ' - 'does not exist.'; - errors.add(error); - } - })); - - return errors; -} - -extension on Asset { - String get type { - switch (this) { - case CodeAsset _: - return CodeAsset.type; - case DataAsset _: - return DataAsset.type; - } - throw UnsupportedError('Unknown asset type'); - } -} - -extension on HookOutputImpl { - Iterable get allAssets => - [...assets, ...assetsForLinking.values.expand((e) => e)]; -} - -/// Native code assets for bundling should have a supported linking type. -List validateCodeAssets( - HookConfig config, - HookOutputImpl output, -) { - final errors = []; - final linkModePreference = config.linkModePreference; - for (final asset in output.assets.whereType()) { - final linkMode = asset.linkMode; - if ((linkMode is DynamicLoading && - linkModePreference == LinkModePreference.static) || - (linkMode is StaticLinking && - linkModePreference == LinkModePreference.dynamic)) { - final error = 'Asset "${asset.id}" has a link mode "$linkMode", which ' - 'is not allowed by by the config link mode preference ' - '"$linkModePreference".'; - errors.add(error); - } - - final os = asset.os; - if (config.targetOS != os) { - final error = 'Asset "${asset.id}" has a os "$os", which ' - 'is not the target os "${config.targetOS}".'; - errors.add(error); - } - - final architecture = asset.architecture; - if (!config.dryRun) { - if (architecture == null) { - final error = 'Asset "${asset.id}" has no architecture.'; - errors.add(error); - } else if (architecture != config.targetArchitecture) { - final error = - 'Asset "${asset.id}" has an architecture "$architecture", which ' - 'is not the target architecture "${config.targetArchitecture}".'; - errors.add(error); - } - } - } - return errors; -} - -/// Build hooks must only output assets in their own package namespace. -List validateAssetId( - HookConfig config, - BuildOutput output, -) { - final errors = []; - final packageName = config.packageName; - for (final asset in output.assets) { - if (!asset.id.startsWith('package:$packageName/')) { - final error = 'Asset "${asset.id}" does not start with ' - '"package:$packageName/".'; - errors.add(error); - } - } - return errors; -} - -List validateNoDuplicateAssetIds( - BuildOutput output, -) { - final errors = []; - final assetIds = {}; - for (final asset in output.assets) { - if (assetIds.contains(asset.id)) { - final error = 'Duplicate asset id: "${asset.id}".'; - errors.add(error); - } else { - assetIds.add(asset.id); - } - } - return errors; -} - -List validateNoDuplicateDylibs( - Iterable assets, -) { - final errors = []; - final fileNameToAssetId = >{}; - for (final asset in assets.whereType()) { - if (asset.linkMode is! DynamicLoadingBundled) { - continue; - } - final file = asset.file; - if (file == null) { - continue; - } - final fileName = file.pathSegments.where((s) => s.isNotEmpty).last; - fileNameToAssetId[fileName] ??= {}; - fileNameToAssetId[fileName]!.add(asset.id); - } - for (final fileName in fileNameToAssetId.keys) { - final assetIds = fileNameToAssetId[fileName]!; - if (assetIds.length > 1) { - final assetIdsString = assetIds.map((e) => '"$e"').join(', '); - final error = - 'Duplicate dynamic library file name "$fileName" for the following' - ' asset ids: $assetIdsString.'; - errors.add(error); - } - } - return errors; -} diff --git a/pkgs/native_assets_cli/test/api/asset_test.dart b/pkgs/native_assets_cli/test/api/asset_test.dart index 92a6af506..8c260e281 100644 --- a/pkgs/native_assets_cli/test/api/asset_test.dart +++ b/pkgs/native_assets_cli/test/api/asset_test.dart @@ -69,18 +69,4 @@ void main() { LookupInProcess().toString(); LookupInExecutable().toString(); }); - - test('Errors', () { - expect( - () => CodeAsset( - package: 'my_package', - name: 'foo', - file: Uri.file('path/to/libfoo.so'), - linkMode: LookupInExecutable(), - os: OS.android, - architecture: Architecture.x64, - ), - throwsArgumentError, - ); - }); } diff --git a/pkgs/native_assets_cli/test/api/build_config_test.dart b/pkgs/native_assets_cli/test/api/build_config_test.dart index 0480536f7..613c60dce 100644 --- a/pkgs/native_assets_cli/test/api/build_config_test.dart +++ b/pkgs/native_assets_cli/test/api/build_config_test.dart @@ -119,10 +119,12 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final config = { 'build_mode': 'release', + 'supported_asset_types': [CodeAsset.type], 'dry_run': false, 'linking_enabled': false, 'link_mode_preference': 'prefer-static', @@ -154,6 +156,7 @@ void main() async { final config = { 'dry_run': true, + 'supported_asset_types': [CodeAsset.type], 'linking_enabled': true, 'link_mode_preference': 'prefer-static', 'out_dir': outDirUri.toFilePath(), @@ -189,6 +192,7 @@ void main() async { }, }, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final buildConfig2 = BuildConfig.build( @@ -210,6 +214,7 @@ void main() async { }, }, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); expect(buildConfig1, equals(buildConfig1)); @@ -230,6 +235,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: true, + supportedAssetTypes: [CodeAsset.type], ); final buildConfig2 = BuildConfig.build( @@ -242,6 +248,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); expect(buildConfig1, equals(buildConfig1)); @@ -261,6 +268,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final configFileContents = (buildConfig as BuildConfigImpl).toJsonString(); final configUri = tempUri.resolve('config.json'); diff --git a/pkgs/native_assets_cli/test/api/build_output_test.dart b/pkgs/native_assets_cli/test/api/build_output_test.dart index 797703871..9bd10f474 100644 --- a/pkgs/native_assets_cli/test/api/build_output_test.dart +++ b/pkgs/native_assets_cli/test/api/build_output_test.dart @@ -21,7 +21,7 @@ void main() { test('BuildOutput constructor', () { BuildOutput( timestamp: DateTime.parse('2022-11-10 13:25:01.000'), - assets: [ + encodedAssets: [ CodeAsset( package: 'my_package', name: 'foo', @@ -29,14 +29,14 @@ void main() { linkMode: DynamicLoadingBundled(), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), CodeAsset( package: 'my_package', name: 'foo2', linkMode: DynamicLoadingSystem(Uri(path: 'path/to/libfoo2.so')), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), ], dependencies: [ Uri.file('path/to/file.ext'), diff --git a/pkgs/native_assets_cli/test/api/build_test.dart b/pkgs/native_assets_cli/test/api/build_test.dart index 186aa7969..baae8eba6 100644 --- a/pkgs/native_assets_cli/test/api/build_test.dart +++ b/pkgs/native_assets_cli/test/api/build_test.dart @@ -59,6 +59,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferDynamic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final configJson = (config1 as BuildConfigImpl).toJsonString(); buildConfigUri = tempUri.resolve('build_config.json'); diff --git a/pkgs/native_assets_cli/test/api/link_config_test.dart b/pkgs/native_assets_cli/test/api/link_config_test.dart index c4cf243bd..bd739b65b 100644 --- a/pkgs/native_assets_cli/test/api/link_config_test.dart +++ b/pkgs/native_assets_cli/test/api/link_config_test.dart @@ -112,11 +112,13 @@ void main() async { buildMode: BuildMode.release, assets: [], linkModePreference: LinkModePreference.preferStatic, + supportedAssetTypes: [CodeAsset.type], ); final config = { 'build_mode': 'release', 'dry_run': false, + 'supported_asset_types': [CodeAsset.type], 'link_mode_preference': 'prefer-static', 'out_dir': outDirUri.toFilePath(), 'out_dir_shared': outputDirectoryShared.toFilePath(), @@ -147,6 +149,7 @@ void main() async { final config = { 'dry_run': true, + 'supported_asset_types': [CodeAsset.type], 'link_mode_preference': 'prefer-static', 'out_dir': outDirUri.toFilePath(), 'out_dir_shared': outputDirectoryShared.toFilePath(), @@ -173,6 +176,7 @@ void main() async { buildMode: BuildMode.release, assets: [], linkModePreference: LinkModePreference.preferStatic, + supportedAssetTypes: [CodeAsset.type], ); final configFileContents = (linkConfig as LinkConfigImpl).toJsonString(); final configUri = tempUri.resolve('config.json'); diff --git a/pkgs/native_assets_cli/test/example/local_asset_test.dart b/pkgs/native_assets_cli/test/example/local_asset_test.dart index b556a402d..31f15c0a8 100644 --- a/pkgs/native_assets_cli/test/example/local_asset_test.dart +++ b/pkgs/native_assets_cli/test/example/local_asset_test.dart @@ -53,6 +53,7 @@ void main() async { targetArchitecture: dryRun ? null : Architecture.current, buildMode: dryRun ? null : BuildMode.debug, cCompiler: dryRun ? null : cCompiler, + supportedAssetTypes: [CodeAsset.type], ); final buildConfigUri = testTempUri.resolve('build_config.json'); @@ -76,12 +77,13 @@ void main() async { final buildOutputUri = outputDirectory.resolve('build_output.json'); final buildOutput = HookOutputImpl.fromJsonString( - await File.fromUri(buildOutputUri).readAsString()); - final assets = buildOutput.assets; + await File.fromUri(buildOutputUri).readAsString()) as BuildOutput; + final assets = buildOutput.encodedAssets; final dependencies = buildOutput.dependencies; if (dryRun) { + final codeAsset = buildOutput.codeAssets.all.first; expect(assets.length, greaterThanOrEqualTo(1)); - expect(await File.fromUri(assets.first.file!).exists(), false); + expect(await File.fromUri(codeAsset.file!).exists(), false); expect(dependencies, []); } else { expect(assets.length, 1); diff --git a/pkgs/native_assets_cli/test/example/native_add_library_test.dart b/pkgs/native_assets_cli/test/example/native_add_library_test.dart index 8f3fb3cb6..5c82eca99 100644 --- a/pkgs/native_assets_cli/test/example/native_add_library_test.dart +++ b/pkgs/native_assets_cli/test/example/native_add_library_test.dart @@ -53,6 +53,7 @@ void main() async { targetArchitecture: dryRun ? null : Architecture.current, buildMode: dryRun ? null : BuildMode.debug, cCompiler: dryRun ? null : cCompiler, + supportedAssetTypes: [CodeAsset.type], ); final buildConfigUri = testTempUri.resolve('build_config.json'); @@ -77,7 +78,7 @@ void main() async { final buildOutputUri = outputDirectory.resolve('build_output.json'); final buildOutput = HookOutputImpl.fromJsonString( await File.fromUri(buildOutputUri).readAsString()); - final assets = buildOutput.assets; + final assets = buildOutput.encodedAssets; final dependencies = buildOutput.dependencies; if (dryRun) { expect(assets.length, greaterThanOrEqualTo(1)); diff --git a/pkgs/native_assets_cli/test/example/native_dynamic_linking_test.dart b/pkgs/native_assets_cli/test/example/native_dynamic_linking_test.dart index 00b1f706b..4d7ea3feb 100644 --- a/pkgs/native_assets_cli/test/example/native_dynamic_linking_test.dart +++ b/pkgs/native_assets_cli/test/example/native_dynamic_linking_test.dart @@ -62,6 +62,7 @@ void main() async { targetArchitecture: dryRun ? null : Architecture.current, buildMode: dryRun ? null : BuildMode.debug, cCompiler: dryRun ? null : cCompiler, + supportedAssetTypes: [CodeAsset.type], ); final buildConfigUri = testTempUri.resolve('build_config.json'); @@ -86,7 +87,7 @@ void main() async { final buildOutputUri = outputDirectory.resolve('build_output.json'); final buildOutput = HookOutputImpl.fromJsonString( await File.fromUri(buildOutputUri).readAsString()); - final assets = buildOutput.assets; + final assets = buildOutput.encodedAssets; final dependencies = buildOutput.dependencies; if (dryRun) { expect(assets.length, greaterThanOrEqualTo(3)); diff --git a/pkgs/native_assets_cli/test/helpers.dart b/pkgs/native_assets_cli/test/helpers.dart index 36a45c744..6f02de316 100644 --- a/pkgs/native_assets_cli/test/helpers.dart +++ b/pkgs/native_assets_cli/test/helpers.dart @@ -127,21 +127,24 @@ extension on String { Uri asFileUri() => Uri.file(this); } -extension AssetIterable on Iterable { +extension AssetIterable on Iterable { Future allExist() async { - final allResults = await Future.wait(map((e) => e.exists())); - final missing = allResults.contains(false); - return !missing; - } -} - -extension on Asset { - Future exists() async { - final path_ = file; - return switch (path_) { - null => true, - _ => await path_.fileSystemEntity.exists(), - }; + for (final encodedAsset in this) { + if (encodedAsset.type == DataAsset.type) { + final dataAsset = DataAsset.fromEncoded(encodedAsset); + if (!await dataAsset.file.fileSystemEntity.exists()) { + return false; + } + } else if (encodedAsset.type == CodeAsset.type) { + final codeAsset = CodeAsset.fromEncoded(encodedAsset); + if (!await (codeAsset.file?.fileSystemEntity.exists() ?? true)) { + return false; + } + } else { + throw UnimplementedError('Unknown asset type ${encodedAsset.type}'); + } + } + return true; } } diff --git a/pkgs/native_assets_cli/test/model/asset_test.dart b/pkgs/native_assets_cli/test/model/asset_test.dart index 5d3df2fdf..e6d268812 100644 --- a/pkgs/native_assets_cli/test/model/asset_test.dart +++ b/pkgs/native_assets_cli/test/model/asset_test.dart @@ -73,8 +73,8 @@ void main() { ), ]; final assets = [ - ...nativeCodeAssets, - ...dataAssets, + for (final asset in nativeCodeAssets) asset.encode(), + for (final asset in dataAssets) asset.encode(), ]; final assetsJsonEncoding = [ @@ -143,7 +143,7 @@ void main() { test('asset json', () { final json = [for (final item in assets) item.toJson()]; expect(json, assetsJsonEncoding); - final assets2 = Asset.listFromJson(json); + final assets2 = [for (final e in json) EncodedAsset.fromJson(e)]; expect(assets, assets2); }); diff --git a/pkgs/native_assets_cli/test/model/build_config_test.dart b/pkgs/native_assets_cli/test/model/build_config_test.dart index 34dcc89ad..08afdbb0d 100644 --- a/pkgs/native_assets_cli/test/model/build_config_test.dart +++ b/pkgs/native_assets_cli/test/model/build_config_test.dart @@ -66,6 +66,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final config2 = BuildConfigImpl( @@ -79,6 +80,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); expect(config1, equals(config1)); @@ -112,9 +114,11 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final config = { + 'supported_asset_types': [CodeAsset.type], 'build_mode': 'release', 'dry_run': false, 'linking_enabled': false, @@ -142,10 +146,12 @@ void main() async { targetOS: OS.android, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final config = { 'dry_run': true, + 'supported_asset_types': [CodeAsset.type], 'linking_enabled': false, 'link_mode_preference': 'prefer-static', 'out_dir': outDirUri.toFilePath(), @@ -176,6 +182,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final configFile = buildConfig1.toJson(); @@ -204,6 +211,7 @@ void main() async { }), }, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final buildConfig2 = BuildConfigImpl( @@ -225,6 +233,7 @@ void main() async { }), }, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); expect(buildConfig1, equals(buildConfig1)); @@ -259,6 +268,7 @@ void main() async { }), }, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final jsonObject = buildConfig1.toJson(); @@ -313,6 +323,7 @@ void main() async { 'target_os': 'android', 'target_android_ndk_api': 30, 'link_mode_preference': 'prefer-static', + 'supported_asset_types': [CodeAsset.type], }), throwsA(predicate( (e) => @@ -334,6 +345,7 @@ void main() async { 'target_android_ndk_api': 30, 'link_mode_preference': 'prefer-static', 'build_mode': BuildMode.release.name, + 'supported_asset_types': [CodeAsset.type], 'dependency_metadata': { 'bar': {'key': 'value'}, 'foo': [], @@ -358,6 +370,7 @@ void main() async { 'target_architecture': 'arm64', 'target_os': 'android', 'link_mode_preference': 'prefer-static', + 'supported_asset_types': [CodeAsset.type], 'build_mode': BuildMode.release.name, }), throwsA(predicate( @@ -386,6 +399,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); config.toString(); }); @@ -402,6 +416,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.preferStatic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final configFileContents = buildConfig.toJsonString(); final configUri = tempUri.resolve('config.json'); @@ -430,6 +445,7 @@ void main() async { buildMode: BuildMode.release, linkModePreference: LinkModePreference.dynamic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final configFile = buildConfig1.toJson(); @@ -448,6 +464,7 @@ void main() async { 'target_os': 'linux', 'version': version, 'package_name': packageName, + 'supported_asset_types': [CodeAsset.type], 'dry_run': true, }; expect( @@ -473,6 +490,7 @@ void main() async { 'target_os': 'windows', 'target_architecture': 'arm', 'build_mode': 'debug', + 'supported_asset_types': [CodeAsset.type], 'version': HookConfigImpl.latestVersion.toString(), }; expect( @@ -495,6 +513,7 @@ void main() async { 'target_architecture': 'arm64', 'build_mode': 'debug', 'dry_run': true, + 'supported_asset_types': [CodeAsset.type], 'version': HookConfigImpl.latestVersion.toString(), }; expect( @@ -517,6 +536,7 @@ void main() async { 'package_name': packageName, 'package_root': tempUri.toFilePath(), 'target_os': 'android', + 'supported_asset_types': [CodeAsset.type], 'version': HookConfigImpl.latestVersion.toString(), }; final buildConfig = BuildConfigImpl.fromJson(config); @@ -539,6 +559,7 @@ void main() async { 'package_name': packageName, 'package_root': tempUri.toFilePath(), 'target_os': 'windows', + 'supported_asset_types': [CodeAsset.type], 'version': HookConfigImpl.latestVersion.toString(), }; final buildConfig = BuildConfigImpl.fromJson(config); @@ -554,6 +575,7 @@ void main() async { targetOS: OS.windows, linkModePreference: LinkModePreference.dynamic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); buildConfig.toJsonString(); // No crash. @@ -571,6 +593,7 @@ void main() async { 'target_android_ndk_api': 30, 'target_architecture': 'invalid_architecture', 'target_os': 'android', + 'supported_asset_types': [CodeAsset.type], 'version': HookOutputImpl.latestVersion.toString(), }; expect( diff --git a/pkgs/native_assets_cli/test/model/build_output_test.dart b/pkgs/native_assets_cli/test/model/build_output_test.dart index 80c47c4ad..7f28a0ffb 100644 --- a/pkgs/native_assets_cli/test/model/build_output_test.dart +++ b/pkgs/native_assets_cli/test/model/build_output_test.dart @@ -120,6 +120,7 @@ void main() { targetOS: OS.macOS, linkModePreference: LinkModePreference.dynamic, linkingEnabled: false, + supportedAssetTypes: [CodeAsset.type], ); final buildOutput = getBuildOutput(); await buildOutput.writeToFile(config: config); @@ -145,6 +146,7 @@ void main() { linkModePreference: LinkModePreference.dynamic, version: Version(1, 1, 0), linkingEnabled: null, // version < 1.4.0 + supportedAssetTypes: [CodeAsset.type], ); final buildOutput = getBuildOutput(withLinkedAssets: false); await buildOutput.writeToFile(config: config); @@ -184,7 +186,7 @@ void main() { test('BuildOutput setters', () { final buildOutput = HookOutputImpl( timestamp: DateTime.parse('2022-11-10 13:25:01.000'), - assets: [ + encodedAssets: [ CodeAsset( package: 'my_package', name: 'foo', @@ -192,14 +194,14 @@ void main() { linkMode: DynamicLoadingBundled(), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), CodeAsset( package: 'my_package', name: 'foo2', linkMode: DynamicLoadingSystem(Uri(path: 'path/to/libfoo2.so')), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), ], dependencies: Dependencies([ Uri.file('path/to/file.ext'), @@ -214,7 +216,7 @@ void main() { final buildOutput2 = HookOutputImpl( timestamp: DateTime.parse('2022-11-10 13:25:01.000'), ); - buildOutput2.addAsset( + buildOutput2.addEncodedAsset( CodeAsset( package: 'my_package', name: 'foo', @@ -222,16 +224,16 @@ void main() { linkMode: DynamicLoadingBundled(), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), ); - buildOutput2.addAssets([ + buildOutput2.addEncodedAssets([ CodeAsset( package: 'my_package', name: 'foo2', linkMode: DynamicLoadingSystem(Uri(path: 'path/to/libfoo2.so')), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), ]); buildOutput2.addDependency( Uri.file('path/to/file.ext'), @@ -253,7 +255,7 @@ void main() { HookOutputImpl getBuildOutput({bool withLinkedAssets = true}) => HookOutputImpl( timestamp: DateTime.parse('2022-11-10 13:25:01.000'), - assets: [ + encodedAssets: [ CodeAsset( package: 'my_package', name: 'foo', @@ -261,44 +263,44 @@ HookOutputImpl getBuildOutput({bool withLinkedAssets = true}) => HookOutputImpl( linkMode: DynamicLoadingBundled(), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), CodeAsset( package: 'my_package', name: 'foo2', linkMode: DynamicLoadingSystem(Uri(path: 'path/to/libfoo2.so')), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), CodeAsset( package: 'my_package', name: 'foo3', linkMode: LookupInProcess(), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), CodeAsset( package: 'my_package', name: 'foo4', linkMode: LookupInExecutable(), os: OS.android, architecture: Architecture.x64, - ), + ).encode(), ], - assetsForLinking: withLinkedAssets + encodedAssetsForLinking: withLinkedAssets ? { 'my_package': [ DataAsset( file: Uri.file('path/to/data'), name: 'data', package: 'my_package', - ) + ).encode() ], 'my_package_2': [ DataAsset( file: Uri.file('path/to/data2'), name: 'data', package: 'my_package', - ) + ).encode() ] } : null, diff --git a/pkgs/native_assets_cli/test/model/checksum_test.dart b/pkgs/native_assets_cli/test/model/checksum_test.dart index f005c213b..cff247336 100644 --- a/pkgs/native_assets_cli/test/model/checksum_test.dart +++ b/pkgs/native_assets_cli/test/model/checksum_test.dart @@ -41,6 +41,7 @@ void main() { targetOS: OS.linux, buildMode: BuildMode.release, linkModePreference: LinkModePreference.dynamic, + supportedAssetTypes: [CodeAsset.type], dependencyMetadata: { 'foo': const Metadata({'key': 'value'}) }, @@ -59,6 +60,7 @@ void main() { targetOS: OS.linux, buildMode: BuildMode.release, linkModePreference: LinkModePreference.dynamic, + supportedAssetTypes: [CodeAsset.type], cCompiler: CCompilerConfig( compiler: fakeClangUri, ), @@ -77,6 +79,7 @@ void main() { targetOS: OS.linux, buildMode: BuildMode.release, linkModePreference: LinkModePreference.dynamic, + supportedAssetTypes: [CodeAsset.type], cCompiler: CCompilerConfig( compiler: fakeClangUri, ), diff --git a/pkgs/native_assets_cli/test/model/link_config_test.dart b/pkgs/native_assets_cli/test/model/link_config_test.dart index 64fa70f5e..1f07cc4e2 100644 --- a/pkgs/native_assets_cli/test/model/link_config_test.dart +++ b/pkgs/native_assets_cli/test/model/link_config_test.dart @@ -26,7 +26,7 @@ void main() async { package: packageName, name: 'name', file: Uri.file('nonexistent'), - ), + ).encode(), CodeAsset( package: packageName, name: 'name2', @@ -34,7 +34,7 @@ void main() async { os: OS.android, file: Uri.file('not there'), architecture: Architecture.riscv64, - ) + ).encode(), ]; setUp(() async { @@ -69,6 +69,7 @@ void main() async { test('LinkConfig ==', () { final config1 = LinkConfigImpl( + supportedAssetTypes: [CodeAsset.type], outputDirectory: outDirUri, outputDirectoryShared: outputDirectoryShared, packageName: packageName, @@ -82,12 +83,13 @@ void main() async { archiver: fakeAr, ), buildMode: BuildMode.release, - assets: assets, + encodedAssets: assets, recordedUsagesFile: recordedUsagesFile, linkModePreference: LinkModePreference.preferStatic, ); final config2 = LinkConfigImpl( + supportedAssetTypes: [CodeAsset.type], outputDirectory: outDir2Uri, outputDirectoryShared: outputDirectoryShared, packageName: packageName, @@ -96,7 +98,7 @@ void main() async { targetOS: OS.android, targetAndroidNdkApi: 30, buildMode: BuildMode.release, - assets: [], + encodedAssets: [], recordedUsagesFile: null, linkModePreference: LinkModePreference.preferStatic, ); @@ -116,11 +118,12 @@ void main() async { expect(config1.cCompiler.envScriptArgs == config2.cCompiler.envScriptArgs, true); expect(config1.cCompiler != config2.cCompiler, true); - expect(config1.assets != config2.assets, true); + expect(config1.encodedAssets != config2.encodedAssets, true); }); test('LinkConfig fromConfig', () { final buildConfig2 = LinkConfigImpl( + supportedAssetTypes: [CodeAsset.type], outputDirectory: outDirUri, outputDirectoryShared: outputDirectoryShared, packageName: packageName, @@ -129,12 +132,13 @@ void main() async { targetOS: OS.android, targetAndroidNdkApi: 30, buildMode: BuildMode.release, - assets: assets, + encodedAssets: assets, linkModePreference: LinkModePreference.preferStatic, ); final config = { 'build_mode': 'release', + 'supported_asset_types': [CodeAsset.type], 'dry_run': false, 'link_mode_preference': 'prefer-static', 'out_dir': outDirUri.toFilePath(), @@ -145,7 +149,7 @@ void main() async { 'target_architecture': 'arm64', 'target_os': 'android', 'version': HookOutputImpl.latestVersion.toString(), - 'assets': Asset.listToJson(assets), + 'assets': [for (final asset in assets) asset.toJson()], }; final fromConfig = LinkConfigImpl.fromJson(config); @@ -154,17 +158,19 @@ void main() async { test('LinkConfig.dryRun', () { final buildConfig2 = LinkConfigImpl.dryRun( + supportedAssetTypes: [CodeAsset.type], outputDirectory: outDirUri, outputDirectoryShared: outputDirectoryShared, packageName: packageName, packageRoot: packageRootUri, targetOS: OS.android, - assets: [], + encodedAssets: [], linkModePreference: LinkModePreference.preferStatic, ); final config = { 'dry_run': true, + 'supported_asset_types': [CodeAsset.type], 'link_mode_preference': 'prefer-static', 'out_dir': outDirUri.toFilePath(), 'out_dir_shared': outputDirectoryShared.toFilePath(), @@ -181,6 +187,7 @@ void main() async { test('LinkConfig toJson fromConfig', () { final buildConfig1 = LinkConfigImpl( + supportedAssetTypes: [CodeAsset.type], outputDirectory: outDirUri, outputDirectoryShared: outputDirectoryShared, packageName: packageName, @@ -193,7 +200,7 @@ void main() async { linker: fakeLd, ), buildMode: BuildMode.release, - assets: assets, + encodedAssets: assets, linkModePreference: LinkModePreference.preferStatic, ); @@ -205,6 +212,7 @@ void main() async { test('LinkConfig toJson fromJson', () { final outDir = outDirUri; final buildConfig1 = LinkConfigImpl( + supportedAssetTypes: [CodeAsset.type], outputDirectory: outDir, outputDirectoryShared: outputDirectoryShared, packageName: packageName, @@ -217,20 +225,20 @@ void main() async { linker: fakeLd, ), buildMode: BuildMode.release, - assets: assets, + encodedAssets: assets, linkModePreference: LinkModePreference.preferStatic, ); final jsonObject = buildConfig1.toJson(); final expectedJson = { - 'assets': Asset.listToJson(assets), + 'assets': [for (final asset in assets) asset.toJson()], + 'supported_asset_types': [CodeAsset.type], 'build_mode': 'release', 'c_compiler': {'cc': fakeClang.toFilePath(), 'ld': fakeLd.toFilePath()}, 'out_dir': outDir.toFilePath(), 'out_dir_shared': outputDirectoryShared.toFilePath(), 'package_name': packageName, 'package_root': tempUri.toFilePath(), - 'supported_asset_types': [CodeAsset.type], 'target_architecture': 'arm64', 'target_ios_sdk': 'iphoneos', 'target_os': 'ios', @@ -256,6 +264,7 @@ void main() async { expect( () => LinkConfigImpl.fromJson({ 'version': HookConfigImpl.latestVersion.toString(), + 'supported_asset_types': [CodeAsset.type], 'package_name': packageName, 'package_root': packageRootUri.toFilePath(), 'target_architecture': 'arm64', @@ -274,6 +283,7 @@ void main() async { expect( () => LinkConfigImpl.fromJson({ 'version': HookConfigImpl.latestVersion.toString(), + 'supported_asset_types': [CodeAsset.type], 'out_dir': outDirUri.toFilePath(), 'out_dir_shared': outputDirectoryShared.toFilePath(), 'package_name': packageName, @@ -296,6 +306,7 @@ void main() async { ); expect( () => LinkConfigImpl.fromJson({ + 'supported_asset_types': [CodeAsset.type], 'out_dir': outDirUri.toFilePath(), 'out_dir_shared': outputDirectoryShared.toFilePath(), 'version': HookConfigImpl.latestVersion.toString(), @@ -318,6 +329,7 @@ void main() async { test('LinkConfig toString', () { final config = LinkConfigImpl( + supportedAssetTypes: [CodeAsset.type], outputDirectory: outDirUri, outputDirectoryShared: outputDirectoryShared, packageName: packageName, @@ -330,7 +342,7 @@ void main() async { linker: fakeLd, ), buildMode: BuildMode.release, - assets: assets, + encodedAssets: assets, linkModePreference: LinkModePreference.preferStatic, ); expect(config.toString(), isNotEmpty); @@ -338,6 +350,7 @@ void main() async { test('LinkConfig fromArgs', () async { final buildConfig = LinkConfigImpl( + supportedAssetTypes: [CodeAsset.type], outputDirectory: outDirUri, outputDirectoryShared: outputDirectoryShared, packageName: packageName, @@ -346,7 +359,7 @@ void main() async { targetOS: OS.android, targetAndroidNdkApi: 30, buildMode: BuildMode.release, - assets: assets, + encodedAssets: assets, recordedUsagesFile: recordedUsagesFile, linkModePreference: LinkModePreference.preferStatic, ); @@ -432,6 +445,7 @@ void main() async { final outDir = outDirUri; final config = { 'link_mode_preference': 'prefer-static', + 'supported_asset_types': [CodeAsset.type], 'out_dir': outDir.toFilePath(), 'out_dir_shared': outputDirectoryShared.toFilePath(), 'package_name': packageName, @@ -452,6 +466,7 @@ void main() async { test('LinkConfig dry_run target arch', () { final outDir = outDirUri; final config = { + 'supported_asset_types': [CodeAsset.type], 'link_mode_preference': 'prefer-static', 'out_dir': outDir.toFilePath(), 'out_dir_shared': outputDirectoryShared.toFilePath(), @@ -467,12 +482,13 @@ void main() async { test('LinkConfig dry_run toString', () { final buildConfig = LinkConfigImpl.dryRun( + supportedAssetTypes: [CodeAsset.type], packageName: packageName, outputDirectory: outDirUri, outputDirectoryShared: outputDirectoryShared, packageRoot: tempUri, targetOS: OS.windows, - assets: assets, + encodedAssets: assets, linkModePreference: LinkModePreference.preferStatic, ); expect(buildConfig.toJsonString(), isNotEmpty); @@ -480,6 +496,7 @@ void main() async { test('invalid architecture', () { final config = { + 'supported_asset_types': [CodeAsset.type], 'build_mode': 'release', 'dry_run': false, 'link_mode_preference': 'prefer-static', diff --git a/pkgs/native_assets_cli/test/validator/validator_test.dart b/pkgs/native_assets_cli/test/validator/validator_test.dart index fa831a5bd..e37ab9de7 100644 --- a/pkgs/native_assets_cli/test/validator/validator_test.dart +++ b/pkgs/native_assets_cli/test/validator/validator_test.dart @@ -4,8 +4,7 @@ import 'dart:io'; -import 'package:native_assets_cli/native_assets_cli.dart'; -import 'package:native_assets_cli/src/validator/validator.dart'; +import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:test/test.dart'; void main() { @@ -47,7 +46,7 @@ void main() { final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAsset( + output.codeAssets.add( CodeAsset( package: config.packageName, name: 'foo.dart', @@ -58,10 +57,9 @@ void main() { ), linkInPackage: 'bar', ); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateBuildOutput(config, output); expect( - result.errors, + errors, contains(contains('linkingEnabled is false')), ); }); @@ -83,16 +81,15 @@ void main() { final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAsset(DataAsset( + output.dataAssets.add(DataAsset( package: config.packageName, name: 'foo.txt', file: assetFile.uri, )); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateBuildOutput(config, output); expect( - result.errors, - contains(contains('which is not in supportedAssetTypes')), + errors, + contains(contains('"data" is not a supported asset type')), ); }); @@ -112,15 +109,14 @@ void main() { ); final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); - output.addAsset(DataAsset( + output.dataAssets.add(DataAsset( package: config.packageName, name: 'foo.txt', file: assetFile.uri, )); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateDataAssetBuildOutput(config, output); expect( - result.errors, + errors, contains(contains('which does not exist')), ); }); @@ -140,17 +136,16 @@ void main() { linkingEnabled: false, ); final output = BuildOutput(); - output.addAsset(CodeAsset( + output.codeAssets.add(CodeAsset( package: config.packageName, name: 'foo.dylib', architecture: config.targetArchitecture, os: config.targetOS, linkMode: DynamicLoadingBundled(), )); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateCodeAssetBuildOutput(config, output); expect( - result.errors, + errors, contains(contains('has no file')), ); }); @@ -176,7 +171,7 @@ void main() { final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAsset( + output.codeAssets.add( CodeAsset( package: config.packageName, name: 'foo.dart', @@ -186,10 +181,9 @@ void main() { architecture: config.targetArchitecture, ), ); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateCodeAssetBuildOutput(config, output); expect( - result.errors, + errors, contains(contains( 'which is not allowed by by the config link mode preference', )), @@ -214,7 +208,7 @@ void main() { final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAsset( + output.codeAssets.add( CodeAsset( package: config.packageName, name: 'foo.dart', @@ -224,10 +218,9 @@ void main() { architecture: Architecture.x64, ), ); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateCodeAssetBuildOutput(config, output); expect( - result.errors, + errors, contains(contains( 'which is not the target architecture', )), @@ -251,7 +244,7 @@ void main() { final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAsset( + output.codeAssets.add( CodeAsset( package: config.packageName, name: 'foo.dart', @@ -260,10 +253,9 @@ void main() { os: config.targetOS, ), ); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateCodeAssetBuildOutput(config, output); expect( - result.errors, + errors, contains(contains( 'has no architecture', )), @@ -287,7 +279,7 @@ void main() { final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAsset( + output.codeAssets.add( CodeAsset( package: config.packageName, name: 'foo.dart', @@ -297,10 +289,9 @@ void main() { architecture: config.targetArchitecture, ), ); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateCodeAssetBuildOutput(config, output); expect( - result.errors, + errors, contains(contains( 'which is not the target os', )), @@ -324,16 +315,15 @@ void main() { final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAsset(DataAsset( + output.dataAssets.add(DataAsset( package: 'different_package', name: 'foo.txt', file: assetFile.uri, )); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateDataAssetBuildOutput(config, output); expect( - result.errors, - contains(contains('does not start with')), + errors, + contains(contains('Data asset must have package name my_package')), ); }); @@ -354,7 +344,7 @@ void main() { final output = BuildOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAssets([ + output.dataAssets.addAll([ DataAsset( package: config.packageName, name: 'foo.txt', @@ -366,11 +356,10 @@ void main() { file: assetFile.uri, ), ]); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateDataAssetBuildOutput(config, output); expect( - result.errors, - contains(contains('Duplicate asset id')), + errors, + contains(contains('More than one')), ); }); @@ -391,16 +380,15 @@ void main() { final output = LinkOutput(); final assetFile = File.fromUri(outDirUri.resolve('foo.dylib')); await assetFile.writeAsBytes([1, 2, 3]); - output.addAsset(DataAsset( + output.dataAssets.add(DataAsset( package: config.packageName, name: 'foo.txt', file: assetFile.uri, )); - final result = await validateLink(config, output); - expect(result.success, isFalse); + final errors = await validateLinkOutput(config, output); expect( - result.errors, - contains(contains('which is not in supportedAssetTypes')), + errors, + contains(contains('"data" is not a supported asset type')), ); }); @@ -422,7 +410,7 @@ void main() { final fileName = config.targetOS.dylibFileName('foo'); final assetFile = File.fromUri(outDirUri.resolve(fileName)); await assetFile.writeAsBytes([1, 2, 3]); - output.addAssets([ + output.codeAssets.addAll([ CodeAsset( package: config.packageName, name: 'src/foo.dart', @@ -440,10 +428,9 @@ void main() { architecture: config.targetArchitecture, ), ]); - final result = await validateBuild(config, output); - expect(result.success, isFalse); + final errors = await validateCodeAssetBuildOutput(config, output); expect( - result.errors, + errors, contains(contains('Duplicate dynamic library file name')), ); }); diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart index 1f38aa885..34c28ae1e 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart @@ -162,17 +162,15 @@ class CBuilder extends CTool implements Builder { } if (assetName != null) { - output.addAssets( - [ - CodeAsset( - package: config.packageName, - name: assetName!, - file: libUri, - linkMode: linkMode, - os: config.targetOS, - architecture: config.dryRun ? null : config.targetArchitecture, - ) - ], + output.codeAssets.add( + CodeAsset( + package: config.packageName, + name: assetName!, + file: libUri, + linkMode: linkMode, + os: config.targetOS, + architecture: config.dryRun ? null : config.targetArchitecture, + ), linkInPackage: linkInPackage, ); } diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart index 45790535e..3ac153901 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart @@ -89,17 +89,15 @@ class CLinker extends CTool implements Linker { } if (assetName != null) { - output.addAssets( - [ - CodeAsset( - package: config.packageName, - name: assetName!, - file: libUri, - linkMode: linkMode, - os: config.targetOS, - architecture: config.dryRun ? null : config.targetArchitecture, - ) - ], + output.codeAssets.add( + CodeAsset( + package: config.packageName, + name: assetName!, + file: libUri, + linkMode: linkMode, + os: config.targetOS, + architecture: config.dryRun ? null : config.targetArchitecture, + ), ); } if (!config.dryRun) { diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart index e38bdbf7d..3902ea6d0 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/ctool.dart @@ -24,7 +24,7 @@ abstract class CTool { /// Asset identifier. /// - /// Used to output the [LinkConfig.assets]. + /// Used to output the [CodeAsset]. /// /// If omitted, no asset will be added to the build output. final String? assetName; diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_build_failure_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_build_failure_test.dart index e8f9182d1..1d9b85f37 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_build_failure_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_build_failure_test.dart @@ -31,6 +31,7 @@ void main() { const name = 'add'; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart index b00696455..12c0cd713 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart @@ -111,6 +111,7 @@ Future buildLib( await Directory.fromUri(tempUriShared).create(); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUriShared, packageName: name, diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_ios_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_ios_test.dart index 6f4b08599..34afa5f47 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_ios_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_ios_test.dart @@ -64,6 +64,7 @@ void main() { Language() => throw UnimplementedError(), }; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -209,6 +210,7 @@ Future buildLib( const name = 'add'; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_linux_host_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_linux_host_test.dart index 9a3e42769..c659f2f7a 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_linux_host_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_linux_host_test.dart @@ -37,6 +37,7 @@ void main() { const name = 'add'; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_macos_host_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_macos_host_test.dart index 79ad82bd2..a24bd5c7b 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_macos_host_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_macos_host_test.dart @@ -50,6 +50,7 @@ void main() { const name = 'add'; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -139,6 +140,7 @@ Future buildLib( const name = 'add'; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_windows_host_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_windows_host_test.dart index a68fa3ac9..9fe63c0ee 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_windows_host_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_windows_host_test.dart @@ -56,6 +56,7 @@ void main() { const name = 'add'; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_test.dart index 77e35132b..faa0c7ece 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_test.dart @@ -45,6 +45,7 @@ void main() { final logger = createCapturingLogger(logMessages); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -116,6 +117,7 @@ void main() { final buildConfig = dryRun ? BuildConfig.dryRun( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -125,6 +127,7 @@ void main() { linkingEnabled: false, ) : BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -216,6 +219,7 @@ void main() { final logger = createCapturingLogger(logMessages); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -273,6 +277,7 @@ void main() { const name = 'includes'; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -317,6 +322,7 @@ void main() { final logger = createCapturingLogger(logMessages); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -374,6 +380,7 @@ void main() { final logger = createCapturingLogger(logMessages); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], buildMode: BuildMode.release, outputDirectory: tempUri, outputDirectoryShared: tempUri2, @@ -437,6 +444,7 @@ void main() { final logger = createCapturingLogger(logMessages); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], buildMode: BuildMode.release, outputDirectory: tempUri, outputDirectoryShared: tempUri2, @@ -507,6 +515,7 @@ Future testDefines({ const name = 'defines'; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, diff --git a/pkgs/native_toolchain_c/test/cbuilder/compiler_resolver_test.dart b/pkgs/native_toolchain_c/test/cbuilder/compiler_resolver_test.dart index 86be27864..4f1b58e98 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/compiler_resolver_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/compiler_resolver_test.dart @@ -42,6 +42,7 @@ void main() { ...await msvc.vcvars64.defaultResolver!.resolve(logger: logger) ].firstOrNull?.uri; final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: 'dummy', @@ -69,6 +70,7 @@ void main() { final tempUri = await tempDirForTest(); final tempUri2 = await tempDirForTest(); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: 'dummy', diff --git a/pkgs/native_toolchain_c/test/cbuilder/objective_c_test.dart b/pkgs/native_toolchain_c/test/cbuilder/objective_c_test.dart index 50f725994..4d76aaf14 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/objective_c_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/objective_c_test.dart @@ -37,6 +37,7 @@ void main() { final logger = createCapturingLogger(logMessages); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], buildMode: BuildMode.release, outputDirectory: tempUri, outputDirectoryShared: tempUri2, diff --git a/pkgs/native_toolchain_c/test/clinker/build_testfiles.dart b/pkgs/native_toolchain_c/test/clinker/build_testfiles.dart index e215afb44..57f37bbda 100644 --- a/pkgs/native_toolchain_c/test/clinker/build_testfiles.dart +++ b/pkgs/native_toolchain_c/test/clinker/build_testfiles.dart @@ -27,6 +27,7 @@ Future buildTestArchive( final logger = createCapturingLogger(logMessages); final buildConfig = BuildConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: name, @@ -51,5 +52,5 @@ Future buildTestArchive( logger: logger, ); - return buildOutput.assets.first.file!; + return buildOutput.codeAssets.all.first.file!; } diff --git a/pkgs/native_toolchain_c/test/clinker/objects_test.dart b/pkgs/native_toolchain_c/test/clinker/objects_test.dart index 1d9cd47e0..1f9654732 100644 --- a/pkgs/native_toolchain_c/test/clinker/objects_test.dart +++ b/pkgs/native_toolchain_c/test/clinker/objects_test.dart @@ -33,6 +33,7 @@ Future main() async { final uri = await buildTestArchive(tempUri, tempUri2, os, architecture); final linkConfig = LinkConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: 'testpackage', @@ -57,11 +58,11 @@ Future main() async { logger: logger, ); - expect(linkOutput.assets, hasLength(1)); - final asset = linkOutput.assets.first; + expect(linkOutput.codeAssets.all, hasLength(1)); + final asset = linkOutput.codeAssets.all.first; expect(asset, isA()); await expectSymbols( - asset: asset as CodeAsset, + asset: asset, symbols: [ 'my_func', 'my_other_func', diff --git a/pkgs/native_toolchain_c/test/clinker/throws_test.dart b/pkgs/native_toolchain_c/test/clinker/throws_test.dart index e69a39f9c..48e5838aa 100644 --- a/pkgs/native_toolchain_c/test/clinker/throws_test.dart +++ b/pkgs/native_toolchain_c/test/clinker/throws_test.dart @@ -30,6 +30,7 @@ Future main() async { await expectLater( () => cLinker.run( config: LinkConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: 'testpackage', diff --git a/pkgs/native_toolchain_c/test/clinker/treeshake_helper.dart b/pkgs/native_toolchain_c/test/clinker/treeshake_helper.dart index 56eec3a70..6bf1b5d71 100644 --- a/pkgs/native_toolchain_c/test/clinker/treeshake_helper.dart +++ b/pkgs/native_toolchain_c/test/clinker/treeshake_helper.dart @@ -65,6 +65,7 @@ Future runTests(List architectures) async { final linkOutput = LinkOutput(); final config = LinkConfig.build( + supportedAssetTypes: [CodeAsset.type], outputDirectory: tempUri, outputDirectoryShared: tempUri2, packageName: 'testpackage', @@ -84,7 +85,7 @@ Future runTests(List architectures) async { logger: logger, ); - final asset = linkOutput.assets.first as CodeAsset; + final asset = linkOutput.codeAssets.all.first; final filePath = asset.file!.toFilePath(); final machine = await readelfMachine(filePath);