diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 7c3563513..1023a8ff3 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -81,6 +81,9 @@ jobs: - run: dart pub get -C test_data/native_add_v1_0_0/ if: ${{ matrix.package == 'native_assets_builder' }} + - run: dart pub get -C test_data/native_add_v1_5_0/ + if: ${{ matrix.package == 'native_assets_builder' }} + - run: dart pub get -C test_data/native_add_add_source/ if: ${{ matrix.package == 'native_assets_builder' }} diff --git a/pkgs/native_assets_builder/CHANGELOG.md b/pkgs/native_assets_builder/CHANGELOG.md index 4fbf4e686..61e8f0d0d 100644 --- a/pkgs/native_assets_builder/CHANGELOG.md +++ b/pkgs/native_assets_builder/CHANGELOG.md @@ -4,6 +4,8 @@ `LinkConfig.dependencies` no longer have to specify Dart sources. - `DataAsset` test projects report all assets from `assets/` dir and default the asset names to the path inside the package. +- Test projects now report their dependencies per asset. And added one test + project with the old protocol still reporting flat dependencies. ## 0.8.1 diff --git a/pkgs/native_assets_builder/test/build_runner/v1_0_0_test.dart b/pkgs/native_assets_builder/test/build_runner/v1_0_0_test.dart deleted file mode 100644 index 44a98a3e1..000000000 --- a/pkgs/native_assets_builder/test/build_runner/v1_0_0_test.dart +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:test/test.dart'; - -import '../helpers.dart'; -import 'helpers.dart'; - -const Timeout longTimeout = Timeout(Duration(minutes: 5)); - -void main() async { - test('native_add build', timeout: longTimeout, () async { - await inTempDir((tempUri) async { - await copyTestProjects(targetUri: tempUri); - final packageUri = tempUri.resolve('native_add_v1_0_0/'); - - // First, run `pub get`, we need pub to resolve our dependencies. - await runPubGet( - workingDirectory: packageUri, - logger: logger, - ); - - { - final result = await build( - packageUri, - logger, - dartExecutable, - ); - expect(result.assets.length, 1); - } - }); - }); -} diff --git a/pkgs/native_assets_builder/test/build_runner/version_skew_test.dart b/pkgs/native_assets_builder/test/build_runner/version_skew_test.dart new file mode 100644 index 000000000..56b30bdee --- /dev/null +++ b/pkgs/native_assets_builder/test/build_runner/version_skew_test.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:test/test.dart'; + +import '../helpers.dart'; +import 'helpers.dart'; + +const Timeout longTimeout = Timeout(Duration(minutes: 5)); + +void main() async { + for (final version in ['v1_0_0', 'v1_5_0']) { + test('native_add build $version', timeout: longTimeout, () async { + await inTempDir((tempUri) async { + await copyTestProjects(targetUri: tempUri); + final packageUri = tempUri.resolve('native_add_$version/'); + + // First, run `pub get`, we need pub to resolve our dependencies. + await runPubGet( + workingDirectory: packageUri, + logger: logger, + ); + + { + final result = await build( + packageUri, + logger, + dartExecutable, + ); + expect(result.assets.length, 1); + } + }); + }); + } +} 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 5cea3b1cd..acfeb3e66 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 @@ -7,17 +7,15 @@ 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 NativeCodeAsset; - output - ..addAsset( - NativeCodeAsset( - package: 'add_asset_link', - name: 'dylib_add_link', - linkMode: builtDylib.linkMode, - os: builtDylib.os, - architecture: builtDylib.architecture, - file: builtDylib.file, - ), - ) - ..addDependency(config.packageRoot.resolve('hook/link.dart')); + output.addAsset( + NativeCodeAsset( + package: 'add_asset_link', + name: 'dylib_add_link', + linkMode: builtDylib.linkMode, + os: builtDylib.os, + architecture: builtDylib.architecture, + file: builtDylib.file, + ), + ); }); } 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..c7abbe135 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 @@ -12,7 +12,7 @@ void main(List args) async { final assetDirectory = Directory.fromUri(config.packageRoot.resolve('assets/')); // If assets are added, rerun hook. - output.addDependency(assetDirectory.uri); + output.addAssetTypeDependency(DataAsset.type, assetDirectory.uri); await for (final dataAsset in assetDirectory.list()) { if (dataAsset is! File) { @@ -31,10 +31,8 @@ void main(List args) async { file: dataAsset.uri, ), linkInPackage: config.linkingEnabled ? packageName : null, + dependencies: [dataAsset.uri], ); - // TODO(https://github.com/dart-lang/native/issues/1208): Report - // dependency on asset. - output.addDependency(dataAsset.uri); } }); } 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..ab5734155 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 @@ -12,7 +12,7 @@ void main(List args) async { final assetDirectory = Directory.fromUri(config.packageRoot.resolve('assets/')); // If assets are added, rerun hook. - output.addDependency(assetDirectory.uri); + output.addAssetTypeDependency(DataAsset.type, assetDirectory.uri); await for (final dataAsset in assetDirectory.list()) { if (dataAsset is! File) { @@ -33,10 +33,8 @@ void main(List args) async { ), linkInPackage: forLinking && config.linkingEnabled ? 'complex_link' : null, + dependencies: [dataAsset.uri], ); - // TODO(https://github.com/dart-lang/native/issues/1208): Report - // dependency on asset. - output.addDependency(dataAsset.uri); } }); } 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..2eaef6ef1 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 @@ -13,6 +13,5 @@ Received ${config.assets.length} assets: ${config.assets.map((e) => e.id)}. print(''' Keeping only ${output.assets.map((e) => e.id)}. '''); - output.addDependency(config.packageRoot.resolve('hook/link.dart')); }); } diff --git a/pkgs/native_assets_builder/test_data/manifest.yaml b/pkgs/native_assets_builder/test_data/manifest.yaml index d0fb0830e..eb13053de 100644 --- a/pkgs/native_assets_builder/test_data/manifest.yaml +++ b/pkgs/native_assets_builder/test_data/manifest.yaml @@ -54,6 +54,14 @@ - native_add_v1_0_0/pubspec.yaml - native_add_v1_0_0/src/native_add.c - native_add_v1_0_0/src/native_add.h +- native_add_v1_5_0/ffigen.yaml +- native_add_v1_5_0/hook/build.dart +- native_add_v1_5_0/lib/native_add.dart +- native_add_v1_5_0/lib/src/native_add_bindings_generated.dart +- native_add_v1_5_0/lib/src/native_add.dart +- native_add_v1_5_0/pubspec.yaml +- native_add_v1_5_0/src/native_add.c +- native_add_v1_5_0/src/native_add.h - native_add/ffigen.yaml - native_add/hook/build.dart - native_add/lib/native_add.dart diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/ffigen.yaml b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/ffigen.yaml new file mode 100644 index 000000000..b8716bd2d --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/ffigen.yaml @@ -0,0 +1,20 @@ +# Run with `flutter pub run ffigen --config ffigen.yaml`. +name: NativeAddBindings +description: | + Bindings for `src/native_add.h`. + + Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. +output: "lib/src/native_add_bindings_generated.dart" +headers: + entry-points: + - "src/native_add.h" + include-directives: + - "src/native_add.h" +preamble: | + // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file + // for details. All rights reserved. Use of this source code is governed by a + // BSD-style license that can be found in the LICENSE file. +comments: + style: any + length: full +ffi-native: diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/hook/build.dart b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/hook/build.dart new file mode 100644 index 000000000..320f1d3a8 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/hook/build.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:logging/logging.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; +import 'package:native_toolchain_c/native_toolchain_c.dart'; + +void main(List arguments) async { + await build(arguments, (config, output) async { + final packageName = config.packageName; + final cbuilder = CBuilder.library( + name: packageName, + assetName: 'src/${packageName}_bindings_generated.dart', + sources: [ + 'src/$packageName.c', + ], + ); + await cbuilder.run( + config: config, + output: output, + logger: Logger('') + ..level = Level.ALL + ..onRecord.listen((record) { + print('${record.level.name}: ${record.time}: ${record.message}'); + }), + ); + }); +} diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/native_add.dart b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/native_add.dart new file mode 100644 index 000000000..9eda681ab --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/native_add.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'src/native_add.dart'; diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/src/native_add.dart b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/src/native_add.dart new file mode 100644 index 000000000..9c8a43b9e --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/src/native_add.dart @@ -0,0 +1,7 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'native_add_bindings_generated.dart' as bindings; + +int add(int a, int b) => bindings.add(a, b); diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/src/native_add_bindings_generated.dart b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/src/native_add_bindings_generated.dart new file mode 100644 index 000000000..4d1e803aa --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/lib/src/native_add_bindings_generated.dart @@ -0,0 +1,15 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint +import 'dart:ffi' as ffi; + +@ffi.Native(symbol: 'add') +external int add( + int a, + int b, +); diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/manifest.yaml b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/manifest.yaml new file mode 100644 index 000000000..7f66e87ac --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/manifest.yaml @@ -0,0 +1,9 @@ +- ffigen.yaml +- hook/build.dart +- lib/native_add.dart +- lib/src/native_add_bindings_generated.dart +- lib/src/native_add.dart +- pubspec.yaml +- src/native_add.c +- src/native_add.h +- test/native_add_test.dart diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/pubspec.yaml b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/pubspec.yaml new file mode 100644 index 000000000..9296fc920 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/pubspec.yaml @@ -0,0 +1,20 @@ +name: native_add +description: Sums two numbers with native code. +version: 0.1.0 + +publish_to: none + +environment: + sdk: '>=3.3.0 <4.0.0' + +dependencies: + logging: ^1.1.1 + native_assets_cli: ^0.7.1 + native_toolchain_c: ^0.5.2 + +dev_dependencies: + ffigen: ^8.0.2 + lints: ^3.0.0 + some_dev_dep: + path: ../some_dev_dep/ + test: ^1.23.1 diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/src/native_add.c b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/src/native_add.c new file mode 100644 index 000000000..cf21076d1 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/src/native_add.c @@ -0,0 +1,9 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include "native_add.h" + +int32_t add(int32_t a, int32_t b) { + return a + b; +} diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/src/native_add.h b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/src/native_add.h new file mode 100644 index 000000000..5824f98a7 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/src/native_add.h @@ -0,0 +1,13 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include + +#if _WIN32 +#define MYLIB_EXPORT __declspec(dllexport) +#else +#define MYLIB_EXPORT +#endif + +MYLIB_EXPORT int32_t add(int32_t a, int32_t b); diff --git a/pkgs/native_assets_builder/test_data/native_add_v1_5_0/test/native_add_test.dart b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/test/native_add_test.dart new file mode 100644 index 000000000..7531a6209 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/native_add_v1_5_0/test/native_add_test.dart @@ -0,0 +1,13 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:native_add/native_add.dart'; +import 'package:test/test.dart'; + +void main() { + test('native add test', () { + final result = add(4, 6); + expect(result, equals(10)); + }); +} 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..918928a45 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 @@ -9,8 +9,5 @@ void main(List arguments) async { output.addAssets( config.assets, ); - 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..8c81a3d59 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 @@ -12,7 +12,7 @@ void main(List args) async { final assetDirectory = Directory.fromUri(config.packageRoot.resolve('assets/')); // If assets are added, rerun hook. - output.addDependency(assetDirectory.uri); + output.addAssetTypeDependency(DataAsset.type, assetDirectory.uri); await for (final dataAsset in assetDirectory.list()) { if (dataAsset is! File) { @@ -30,10 +30,8 @@ void main(List args) async { name: name, file: dataAsset.uri, ), + dependencies: [dataAsset.uri], ); - // TODO(https://github.com/dart-lang/native/issues/1208): Report - // dependency on asset. - output.addDependency(dataAsset.uri); } }, ); 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..c7abbe135 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 @@ -12,7 +12,7 @@ void main(List args) async { final assetDirectory = Directory.fromUri(config.packageRoot.resolve('assets/')); // If assets are added, rerun hook. - output.addDependency(assetDirectory.uri); + output.addAssetTypeDependency(DataAsset.type, assetDirectory.uri); await for (final dataAsset in assetDirectory.list()) { if (dataAsset is! File) { @@ -31,10 +31,8 @@ void main(List args) async { file: dataAsset.uri, ), linkInPackage: config.linkingEnabled ? packageName : null, + dependencies: [dataAsset.uri], ); - // TODO(https://github.com/dart-lang/native/issues/1208): Report - // dependency on asset. - output.addDependency(dataAsset.uri); } }); } diff --git a/pkgs/native_assets_cli/CHANGELOG.md b/pkgs/native_assets_cli/CHANGELOG.md index d2f897079..a323ac9e3 100644 --- a/pkgs/native_assets_cli/CHANGELOG.md +++ b/pkgs/native_assets_cli/CHANGELOG.md @@ -1,10 +1,13 @@ -## 0.7.3-wip +## 0.8.0-wip +- **Breaking change** `BuildConfig.dependencies` is now per asset and asset + type instead of a flat list. - Fix some more cases of: `BuildConfig.dependencies` and `LinkConfig.dependencies` no longer have to specify Dart sources. - `DataAsset` examples report all assets from `assets/` dir and default the asset names to the path inside the package. + ## 0.7.2 - Deprecate metadata concept. 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 e074792e1..f9024ca7d 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 @@ -24,22 +24,20 @@ void main(List args) async { if (!config.dryRun) { // Insert code that downloads or builds the asset to `assetPath`. await File.fromUri(assetSourcePath).copy(assetPath.toFilePath()); - - output.addDependencies([ - assetSourcePath, - ]); } output.addAsset( - // TODO: Change to DataAsset once the Dart/Flutter SDK can consume it. - NativeCodeAsset( - package: packageName, - name: 'asset.txt', - file: assetPath, - linkMode: DynamicLoadingBundled(), - os: config.targetOS, - architecture: config.targetArchitecture, - ), - ); + // TODO: Change to DataAsset once the Dart/Flutter SDK can consume it. + NativeCodeAsset( + package: packageName, + name: 'asset.txt', + file: assetPath, + linkMode: DynamicLoadingBundled(), + os: config.targetOS, + architecture: config.targetArchitecture, + ), + dependencies: [ + if (!config.dryRun) assetSourcePath, + ]); }); } 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..c7abbe135 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 @@ -12,7 +12,7 @@ void main(List args) async { final assetDirectory = Directory.fromUri(config.packageRoot.resolve('assets/')); // If assets are added, rerun hook. - output.addDependency(assetDirectory.uri); + output.addAssetTypeDependency(DataAsset.type, assetDirectory.uri); await for (final dataAsset in assetDirectory.list()) { if (dataAsset is! File) { @@ -31,10 +31,8 @@ void main(List args) async { file: dataAsset.uri, ), linkInPackage: config.linkingEnabled ? packageName : null, + dependencies: [dataAsset.uri], ); - // TODO(https://github.com/dart-lang/native/issues/1208): Report - // dependency on asset. - output.addDependency(dataAsset.uri); } }); } diff --git a/pkgs/native_assets_cli/lib/src/api/build.dart b/pkgs/native_assets_cli/lib/src/api/build.dart index 8767cfa35..0f62315c5 100644 --- a/pkgs/native_assets_cli/lib/src/api/build.dart +++ b/pkgs/native_assets_cli/lib/src/api/build.dart @@ -64,7 +64,7 @@ import 'build_output.dart'; /// // Insert code that downloads or builds the asset to `assetPath`. /// await File.fromUri(assetSourcePath).copy(assetPath.toFilePath()); /// -/// output.addDependencies([ +/// output.addAssetTypeDependencies([ /// assetSourcePath, /// ]); /// } 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 a8aa084b9..a383135c8 100644 --- a/pkgs/native_assets_cli/lib/src/api/build_output.dart +++ b/pkgs/native_assets_cli/lib/src/api/build_output.dart @@ -64,25 +64,41 @@ abstract final class BuildOutput { /// the dry run must be provided. Map> get assetsForLinking; - /// The files used by this build. + /// Files and directories used to build an asset by this build. /// - /// If any of the files in [dependencies] are modified after [timestamp], the - /// build will be re-run. + /// Maps [Asset.id]s to a list of absolute uris. + /// + /// If any of the files in [assetDependencies] are modified after [timestamp], + /// the build will be re-run. + /// + /// The (transitive) Dart sources do not have to be added to these + /// dependencies, only non-Dart files. (Note that old Dart and Flutter SDKs do + /// not automatically add the Dart sources. So builds get wrongly cached, try + /// updating to the latest release.) + Map> get assetDependencies; + + /// Files and directories used that if modified could change which assets are + /// built. + /// + /// Maps [Asset] types to a list of absolute uris. + /// + /// If any of the files in [assetTypeDependencies] are modified after + /// [timestamp], the build will be re-run. /// /// The (transitive) Dart sources do not have to be added to these - /// dependencies, only non-Dart files. (Note that old Dart and Flutter SDKs - /// do not automatically add the Dart sources. So builds get wrongly cached, - /// try updating to the latest release.) - Iterable get dependencies; + /// dependencies, only non-Dart files. (Note that old Dart and Flutter SDKs do + /// not automatically add the Dart sources. So builds get wrongly cached, try + /// updating to the latest release.) + Map> get assetTypeDependencies; /// Create a build output. /// - /// The [timestamp] must be before any [dependencies] are read by the build - /// this output belongs to. If the [BuildOutput] object is created at the - /// beginning of the build hook, [timestamp] can be omitted and will default - /// to [DateTime.now]. The [timestamp] is rounded down to whole seconds, - /// because [File.lastModified] is rounded to whole seconds and caching logic - /// compares these timestamps. + /// The [timestamp] must be before any [assetDependencies] and + /// [assetTypeDependencies] are read by the build this output belongs to. If + /// the [BuildOutput] object is created at the beginning of the build hook, + /// [timestamp] can be omitted and will default to [DateTime.now]. The + /// [timestamp] is rounded down to whole seconds, 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 @@ -90,10 +106,11 @@ abstract final class BuildOutput { /// omitted. /// /// The files used by this build must be provided to the constructor as - /// [dependencies], or can be added later with [addDependency] and - /// [addDependencies]. If any of these files are modified after [timestamp], - /// the build will be re-run. Typically these dependencies contain the build - /// hook itself, and the source files used in the build. + /// [assetDependencies] and [assetTypeDependencies], or can be added later + /// with [addAsset] and [addAssetTypeDependencies]. If any of these files are + /// modified after [timestamp], the build will be re-run. Typically these + /// dependencies contain the build hook itself, and the source files used in + /// the build. /// /// Metadata can be passed to build hook invocations of dependent packages. It /// must be provided to the constructor as [metadata], or added later with @@ -102,42 +119,70 @@ abstract final class BuildOutput { factory BuildOutput({ DateTime? timestamp, Iterable? assets, - Iterable? dependencies, + Map>? assetDependencies, + Map>? assetTypeDependencies, @Deprecated(metadataDeprecation) Map? metadata, }) => HookOutputImpl( timestamp: timestamp, assets: assets?.cast().toList(), - dependencies: Dependencies([...?dependencies]), + dependencies: Dependencies( + assetDependencies: {...?assetDependencies}, + assetTypeDependencies: {...?assetTypeDependencies}, + ), metadata: Metadata({...?metadata}), ); /// Adds [Asset]s produced by this build or dry run. /// + /// If provided, [dependencies] adds files used to build this [asset]. If any + /// of the files are modified after [timestamp], the build will be re-run. If + /// omitted, and [Asset.file] is outside the [BuildConfig.outputDirectory], a + /// dependency on the file is added implicitly. + /// /// 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}); + void addAsset( + Asset asset, { + String? linkInPackage, + Iterable? dependencies, + }); /// Adds [Asset]s produced by this build or dry run. /// + /// If provided, [dependencies] adds files used to build these [assets]. If + /// any of the files are modified after [timestamp], the build will be re-run. + /// If omitted, and [Asset.file] is outside the [BuildConfig.outputDirectory], + /// a dependency on the file is added implicitly. + /// /// 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}); + void addAssets( + Iterable assets, { + String? linkInPackage, + Iterable? dependencies, + }); /// Adds file used by this build. /// /// If any of the files are modified after [timestamp], the build will be /// re-run. - void addDependency(Uri dependency); + void addAssetTypeDependency( + String assetType, + Uri dependency, + ); /// Adds files used by this build. /// /// If any of the files are modified after [timestamp], the build will be /// re-run. - void addDependencies(Iterable dependencies); + void addAssetTypeDependencies( + String assetType, + Iterable dependencies, + ); /// Adds metadata to be passed to build hook invocations of dependent /// packages. diff --git a/pkgs/native_assets_cli/lib/src/api/builder.dart b/pkgs/native_assets_cli/lib/src/api/builder.dart index 11b8a6d18..2072d90fb 100644 --- a/pkgs/native_assets_cli/lib/src/api/builder.dart +++ b/pkgs/native_assets_cli/lib/src/api/builder.dart @@ -12,10 +12,11 @@ import 'linker.dart'; /// /// [Builder]s should be used to build native code, download assets, and /// transform assets. A build hook is only rerun when its declared -/// [BuildOutput.dependencies] change. ([Linker]s have access to tree-shaking -/// information in some build modes, and could potentially build or download -/// less assets. However, due to the tree-shaking information being an input to -/// link hooks, link hooks are re-run much more often.) +/// [BuildOutput.assetDependencies] and [BuildOutput.assetTypeDependencies] +/// change. ([Linker]s have access to tree-shaking information in some build +/// modes, and could potentially build or download less assets. However, due to +/// the tree-shaking information being an input to link hooks, link hooks are +/// re-run much more often.) /// /// A package to be used in build hooks should implement this interface. The /// typical pattern of build hooks should be a declarative specification of one diff --git a/pkgs/native_assets_cli/lib/src/api/link.dart b/pkgs/native_assets_cli/lib/src/api/link.dart index c86894a7b..633af1bce 100644 --- a/pkgs/native_assets_cli/lib/src/api/link.dart +++ b/pkgs/native_assets_cli/lib/src/api/link.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import '../../native_assets_cli_internal.dart'; +import 'asset.dart'; import 'build_output.dart'; import 'link_config.dart'; @@ -38,7 +39,13 @@ Future link( final builtAssetsFiles = config.assets.map((asset) => asset.file).whereType().toList(); final linkOutput = HookOutputImpl( - dependencies: Dependencies(builtAssetsFiles), + dependencies: Dependencies( + assetDependencies: {}, + assetTypeDependencies: { + DataAsset.type: builtAssetsFiles, + NativeCodeAsset.type: builtAssetsFiles, + }, + ), ); await linker(config, linkOutput); await linkOutput.writeToFile(config: config); 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 1f569f262..8e66dba78 100644 --- a/pkgs/native_assets_cli/lib/src/api/link_output.dart +++ b/pkgs/native_assets_cli/lib/src/api/link_output.dart @@ -29,29 +29,72 @@ abstract final class LinkOutput { /// the dry run must be provided. Iterable get assets; - /// The files used by this link. + /// Files and directories used to build an asset by this build. /// - /// If any of the files in [dependencies] are modified after [timestamp], the - /// link will be re-run. - Iterable get dependencies; + /// Maps [Asset.id]s to a list of absolute uris. + /// + /// If any of the files in [assetDependencies] are modified after [timestamp], + /// the build will be re-run. + /// + /// The (transitive) Dart sources do not have to be added to these + /// dependencies, only non-Dart files. (Note that old Dart and Flutter SDKs do + /// not automatically add the Dart sources. So builds get wrongly cached, try + /// updating to the latest release.) + Map> get assetDependencies; + + /// Files and directories used that if modified could change which assets are + /// built. + /// + /// Maps [Asset] types to a list of absolute uris. + /// + /// If any of the files in [assetTypeDependencies] are modified after + /// [timestamp], the build will be re-run. + /// + /// The (transitive) Dart sources do not have to be added to these + /// dependencies, only non-Dart files. (Note that old Dart and Flutter SDKs do + /// not automatically add the Dart sources. So builds get wrongly cached, try + /// updating to the latest release.) + Map> get assetTypeDependencies; /// Adds file used by this link. /// /// If any of the files are modified after [timestamp], the link will be /// re-run. - void addDependency(Uri dependency); + void addAssetTypeDependency( + String assetType, + Uri dependency, + ); /// Adds files used by this link. /// /// If any of the files are modified after [timestamp], the link will be /// re-run. - void addDependencies(Iterable dependencies); + void addAssetTypeDependencies( + String assetType, + Iterable dependencies, + ); /// Adds [Asset]s produced by this link or dry run. - void addAsset(Asset asset); + /// + /// If provided, [dependencies] adds files used to build these [asset]. If any + /// of the files are modified after [timestamp], the build will be re-run. If + /// omitted, and [Asset.file] is outside the [BuildConfig.outputDirectory], a + /// dependency on the file is added implicitly. + void addAsset( + Asset asset, { + Iterable? dependencies, + }); /// Adds [Asset]s produced by this link or dry run. - void addAssets(Iterable assets); + /// + /// If provided, [dependencies] adds files used to build these [assets]. If + /// any of the files are modified after [timestamp], the build will be re-run. + /// If omitted, and [Asset.file] is outside the [BuildConfig.outputDirectory], + /// a dependency on the file is added implicitly. + void addAssets( + Iterable assets, { + Iterable? dependencies, + }); factory LinkOutput({ Iterable? assets, diff --git a/pkgs/native_assets_cli/lib/src/api/linker.dart b/pkgs/native_assets_cli/lib/src/api/linker.dart index 1bb080c45..958121f99 100644 --- a/pkgs/native_assets_cli/lib/src/api/linker.dart +++ b/pkgs/native_assets_cli/lib/src/api/linker.dart @@ -14,8 +14,9 @@ import 'link_config.dart'; /// information. [Linker]s have access to tree-shaking information in some build /// modes. However, due to the tree-shaking information being an input to link /// hooks, link hooks are re-run more often than [Builder]s. A link hook is -/// rerun when its declared [BuildOutput.dependencies] or its [LinkConfig] tree -/// shaking information changes. +/// rerun when its declared [LinkOutput.assetDependencies] and +/// [LinkOutput.assetTypeDependencies] or its [LinkConfig] tree shaking +/// information changes. /// /// A package to be used in link hooks should implement this interface. The /// typical pattern of link hooks should be a declarative specification of one diff --git a/pkgs/native_assets_cli/lib/src/model/build_config_CHANGELOG.md b/pkgs/native_assets_cli/lib/src/model/build_config_CHANGELOG.md index 0e4fce0d5..6cd56b273 100644 --- a/pkgs/native_assets_cli/lib/src/model/build_config_CHANGELOG.md +++ b/pkgs/native_assets_cli/lib/src/model/build_config_CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.6.0 + +- No changes, but rev version due to BuildOutput change so that the BuildOuptut + serializer can output the right format. + ## 1.5.0 - No changes, but rev version due to BuildOutput change. diff --git a/pkgs/native_assets_cli/lib/src/model/build_output_CHANGELOG.md b/pkgs/native_assets_cli/lib/src/model/build_output_CHANGELOG.md index 4d825e062..af75ae7b1 100644 --- a/pkgs/native_assets_cli/lib/src/model/build_output_CHANGELOG.md +++ b/pkgs/native_assets_cli/lib/src/model/build_output_CHANGELOG.md @@ -1,3 +1,15 @@ +## 1.6.0 + +- BuildOutput.dependencies is no longer a flat list of uris. Instead it's + two maps with asset dependencies and asset-type dependencies. + Backwards compatibility older SDKs: The serializer will output a flat list of + dependencies. + Backwards compatibiility older hooks: The deserializer will add the flat list + of dependencies to each asset type and each asset. +- Renamed `assetForLinking` to `asset_for_linking` + Backwards compatibility for older SDKs: The serializer will output the old key. + Backwards compatibility for older hooks: try both the old and new key. + ## 1.5.0 - BuildOutput.dependencies no longer have to list Dart dependencies. diff --git a/pkgs/native_assets_cli/lib/src/model/dependencies.dart b/pkgs/native_assets_cli/lib/src/model/dependencies.dart index 51d29c0fb..5d1d7d21d 100644 --- a/pkgs/native_assets_cli/lib/src/model/dependencies.dart +++ b/pkgs/native_assets_cli/lib/src/model/dependencies.dart @@ -6,30 +6,127 @@ import 'dart:convert'; import 'package:collection/collection.dart'; +import '../api/asset.dart'; import '../utils/file.dart'; import '../utils/json.dart'; import '../utils/uri.dart'; class Dependencies { - /// The dependencies a build relied on. - final List dependencies; + /// The dependencies a hook relied on. + /// + /// Combines all dependencies the [assetDependencies] and + /// [assetTypeDependencies]. + List get dependencies => { + for (final dependencies in [ + ...assetDependencies.values, + ...assetTypeDependencies.values, + ]) + for (final dependency in dependencies) dependency, + }.toList() + ..sort(_uriCompare); - const Dependencies(this.dependencies); + int _uriCompare(Uri u1, Uri u2) => u1.toString().compareTo(u2.toString()); - factory Dependencies.fromJson(List? jsonList) => Dependencies([ - if (jsonList != null) - for (final dependency in jsonList) - fileSystemPathToUri(as(dependency)), - ]); + final Map> assetDependencies; - List toJson() => toJsonList(dependencies); + void addAssetDependencies(String assetId, Iterable dependencies) { + assetDependencies[assetId] = [ + ...?assetDependencies[assetId], + ...dependencies, + ]; + } + + void addAssetTypeDependencies(String assetType, Iterable dependencies) { + assetTypeDependencies[assetType] = [ + ...?assetTypeDependencies[assetType], + ...dependencies, + ]; + } + + final Map> assetTypeDependencies; + + Dependencies({ + required this.assetDependencies, + required this.assetTypeDependencies, + }); + + static const _assetDependenciesKey = 'assets'; + static const _assetTypeDependenciesKey = 'asset_types'; + + factory Dependencies.fromJson(Map? jsonMap) { + if (jsonMap == null) { + return Dependencies( + assetDependencies: {}, + assetTypeDependencies: {}, + ); + } + return Dependencies( + assetDependencies: _readDependenciesMap(get( + jsonMap, + _assetDependenciesKey, + )), + assetTypeDependencies: _readDependenciesMap(get( + jsonMap, + _assetTypeDependenciesKey, + )), + ); + } + + static Map> _readDependenciesMap( + Map? assetDependenciesMap) => + { + if (assetDependenciesMap != null) + for (final entry in assetDependenciesMap.entries) + as(entry.key): [ + for (final uri in as>(entry.value)) + fileSystemPathToUri(as(uri)), + ], + }; + + factory Dependencies.fromJsonV1_5( + List? jsonList, + Iterable assetIds, + ) { + final dependencies = [ + if (jsonList != null) + for (final dependency in jsonList) + fileSystemPathToUri(as(dependency)), + ]; + return Dependencies( + assetDependencies: { + for (final assetId in assetIds) assetId: dependencies, + }, + assetTypeDependencies: { + for (final assetType in [NativeCodeAsset.type, DataAsset.type]) + assetType: dependencies, + }, + ); + } + + Map>> toJson() => { + _assetDependenciesKey: { + for (final entry in assetDependencies.entries) + entry.key: toJsonList(entry.value), + }, + _assetTypeDependenciesKey: { + for (final entry in assetTypeDependencies.entries) + entry.key: toJsonList(entry.value), + }, + }; + + List toJsonV1_5() => toJsonList( + assetDependencies.values + .expand((e) => e) + .followedBy(assetTypeDependencies.values.expand((e) => e)) + .toSet(), + ); - static List toJsonList(List dependencies) => [ + static List toJsonList(Iterable dependencies) => [ for (final dependency in dependencies) dependency.toFilePath(), - ]; + ]..sort(); @override - String toString() => const JsonEncoder.withIndent(' ').convert(toJson()); + String toString() => const JsonEncoder.withIndent(' ').convert(toJsonV1_5()); Future lastModified() => dependencies.map((u) => u.fileSystemEntity).lastModified(); 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 f6ce8a1c6..62fc45ea8 100644 --- a/pkgs/native_assets_cli/lib/src/model/hook_config.dart +++ b/pkgs/native_assets_cli/lib/src/model/hook_config.dart @@ -582,5 +582,5 @@ can _only_ depend on OS.'''); /// If we ever were to make breaking changes, it would be useful to give /// proper error messages rather than just fail to parse the JSON /// representation in the protocol. - static Version latestVersion = Version(1, 5, 0); + static Version latestVersion = Version(1, 6, 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 a5bf5982b..22826a1be 100644 --- a/pkgs/native_assets_cli/lib/src/model/hook_output.dart +++ b/pkgs/native_assets_cli/lib/src/model/hook_output.dart @@ -22,9 +22,16 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { Dependencies get dependenciesModel => _dependencies; - @override Iterable get dependencies => _dependencies.dependencies; + @override + Map> get assetDependencies => + _dependencies.assetDependencies; + + @override + Map> get assetTypeDependencies => + _dependencies.assetTypeDependencies; + final Metadata metadata; HookOutputImpl({ @@ -38,22 +45,33 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { ...?assets, ], _assetsForLinking = assetsForLinking ?? {}, - // ignore: prefer_const_constructors - _dependencies = dependencies ?? Dependencies([]), + _dependencies = dependencies ?? + Dependencies( + assetDependencies: {}, + assetTypeDependencies: {}, + ), // ignore: prefer_const_constructors metadata = metadata ?? Metadata({}); @override - void addDependency(Uri dependency) => - _dependencies.dependencies.add(dependency); + void addAssetTypeDependency( + String assetType, + Uri dependency, + ) => + _dependencies.addAssetTypeDependencies(assetType, [dependency]); @override - void addDependencies(Iterable dependencies) => - _dependencies.dependencies.addAll(dependencies); + void addAssetTypeDependencies( + String assetType, + Iterable dependencies, + ) => + _dependencies.addAssetTypeDependencies(assetType, dependencies); static const _assetsKey = 'assets'; - static const _assetsForLinkingKey = 'assetsForLinking'; - static const _dependenciesKey = 'dependencies'; + static const _assetsForLinkingKeyV1_5 = 'assetsForLinking'; + static const _assetsForLinkingKey = 'assets_for_linking'; + static const _dependenciesKeyV1_5 = 'dependencies'; + static const _dependenciesKey = 'dependencies2'; static const _metadataKey = 'metadata'; static const _timestampKey = 'timestamp'; static const _versionKey = 'version'; @@ -86,15 +104,34 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { 'Flutter, please update native_assets_cli.', ); } + final assets = + AssetImpl.listFromJson(get?>(jsonMap, _assetsKey)); + + final Dependencies? dependencies; + final dependenciesMap = + get?>(jsonMap, _dependenciesKey); + final dependenciesMapV1_5 = + get?>(jsonMap, _dependenciesKeyV1_5); + if (dependenciesMap != null) { + dependencies = Dependencies.fromJson(dependenciesMap); + } else if (dependenciesMapV1_5 != null) { + dependencies = Dependencies.fromJsonV1_5( + dependenciesMapV1_5, + assets.map((e) => e.id), + ); + } else { + dependencies = null; + } + return HookOutputImpl( timestamp: DateTime.parse(get(jsonMap, _timestampKey)), - assets: AssetImpl.listFromJson(get?>(jsonMap, _assetsKey)), - assetsForLinking: get?>( - jsonMap, _assetsForLinkingKey) + assets: assets, + assetsForLinking: (get?>( + jsonMap, _assetsForLinkingKey) ?? + get?>(jsonMap, _assetsForLinkingKeyV1_5)) ?.map((packageName, assets) => MapEntry( packageName, AssetImpl.listFromJson(as>(assets)))), - dependencies: - Dependencies.fromJson(get?>(jsonMap, _dependenciesKey)), + dependencies: dependencies, metadata: Metadata.fromJson(get?>(jsonMap, _metadataKey)), ); @@ -131,13 +168,18 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { _timestampKey: timestamp.toString(), if (assets.isNotEmpty) _assetsKey: AssetImpl.listToJson(assets, version), if (version >= linkMinVersion && _assetsForLinking.isNotEmpty) - _assetsForLinkingKey: + version > Version(1, 5, 0) + ? _assetsForLinkingKey + : _assetsForLinkingKeyV1_5: _assetsForLinking.map((packageName, assets) => MapEntry( packageName, AssetImpl.listToJson(assets, version), )), if (_dependencies.dependencies.isNotEmpty) - _dependenciesKey: _dependencies.toJson(), + if (version > Version(1, 5, 0)) + _dependenciesKey: _dependencies.toJson() + else + _dependenciesKeyV1_5: _dependencies.toJsonV1_5(), if (metadata.metadata.isNotEmpty) _metadataKey: metadata.toJson(), _versionKey: version.toString(), }..sortOnKey(); @@ -215,13 +257,29 @@ final class HookOutputImpl implements BuildOutput, LinkOutput { Metadata get metadataModel => metadata; @override - void addAsset(Asset asset, {String? linkInPackage}) { + void addAsset( + Asset asset, { + String? linkInPackage, + Iterable? dependencies, + }) { _getAssetList(linkInPackage).add(asset as AssetImpl); + if (dependencies != null) { + dependenciesModel.addAssetDependencies(asset.id, dependencies); + } } @override - void addAssets(Iterable assets, {String? linkInPackage}) { + void addAssets( + Iterable assets, { + String? linkInPackage, + Iterable? dependencies, + }) { _getAssetList(linkInPackage).addAll(assets.cast()); + if (dependencies != null) { + for (final asset in assets) { + dependenciesModel.addAssetDependencies(asset.id, dependencies); + } + } } List _getAssetList(String? linkInPackage) => linkInPackage == null diff --git a/pkgs/native_assets_cli/pubspec.yaml b/pkgs/native_assets_cli/pubspec.yaml index 1060809d9..4ba017116 100644 --- a/pkgs/native_assets_cli/pubspec.yaml +++ b/pkgs/native_assets_cli/pubspec.yaml @@ -4,7 +4,7 @@ description: >- native assets CLI. # Note: Bump BuildConfig.version and BuildOutput.version on breaking changes! -version: 0.7.3-wip +version: 0.8.0-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/native_assets_cli topics: 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 a8e15d4cd..680cc4136 100644 --- a/pkgs/native_assets_cli/test/api/build_output_test.dart +++ b/pkgs/native_assets_cli/test/api/build_output_test.dart @@ -38,9 +38,9 @@ void main() { architecture: Architecture.x64, ), ], - dependencies: [ - Uri.file('path/to/file.ext'), - ], + assetDependencies: { + 'my_package/foo': [Uri.file('path/to/file.ext')], + }, // ignore: deprecated_member_use_from_same_package metadata: { 'key': 'value', diff --git a/pkgs/native_assets_cli/test/api/build_test.dart b/pkgs/native_assets_cli/test/api/build_test.dart index ce62f8777..6ec488985 100644 --- a/pkgs/native_assets_cli/test/api/build_test.dart +++ b/pkgs/native_assets_cli/test/api/build_test.dart @@ -64,7 +64,10 @@ void main() async { test('build method', () async { await build(['--config', buildConfigUri.toFilePath()], (config, output) async { - output.addDependency(packageRootUri.resolve('foo')); + output.addAssetTypeDependency( + NativeCodeAsset.type, + packageRootUri.resolve('foo'), + ); }); final buildOutputUri = outDirUri.resolve((config1 as BuildConfigImpl).outputName); 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 9d0b27d86..f1e21f131 100644 --- a/pkgs/native_assets_cli/test/model/build_output_test.dart +++ b/pkgs/native_assets_cli/test/model/build_output_test.dart @@ -4,6 +4,7 @@ import 'dart:io'; +import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; @@ -57,6 +58,7 @@ assets: path_type: executable target: android_x64 dependencies: + - path/to/directory/ - path/to/file.ext metadata: key: value @@ -96,7 +98,7 @@ assets: target: android_riscv64 version: 1.0.0'''; - final jsonEncoding = { + final jsonEncodingV1_5_0 = { 'timestamp': '2022-11-10 13:25:01.000', 'assets': [ { @@ -151,9 +153,80 @@ version: 1.0.0'''; ] }, 'dependencies': [ + Uri.directory('path/to/directory/').toFilePath(), Uri.file('path/to/file.ext').toFilePath(), ], 'metadata': {'key': 'value'}, + 'version': '${Version(1, 5, 0)}' + }; + + final jsonEncoding = { + 'timestamp': '2022-11-10 13:25:01.000', + 'assets': [ + { + 'architecture': 'x64', + 'file': Uri.file('path/to/libfoo.so').toFilePath(), + 'id': 'package:my_package/foo', + 'link_mode': {'type': 'dynamic_loading_bundle'}, + 'os': 'android', + 'type': 'native_code' + }, + { + 'architecture': 'x64', + 'id': 'package:my_package/foo2', + 'link_mode': { + 'type': 'dynamic_loading_system', + 'uri': Uri.file('path/to/libfoo2.so').toFilePath(), + }, + 'os': 'android', + 'type': 'native_code' + }, + { + 'architecture': 'x64', + 'id': 'package:my_package/foo3', + 'link_mode': {'type': 'dynamic_loading_process'}, + 'os': 'android', + 'type': 'native_code' + }, + { + 'architecture': 'x64', + 'id': 'package:my_package/foo4', + 'link_mode': {'type': 'dynamic_loading_executable'}, + 'os': 'android', + 'type': 'native_code' + } + ], + 'assets_for_linking': { + 'my_package': [ + { + 'name': 'data', + 'package': 'my_package', + 'file': Uri.file('path/to/data').toFilePath(), + 'type': 'data' + } + ], + 'my_package_2': [ + { + 'name': 'data', + 'package': 'my_package', + 'file': Uri.file('path/to/data2').toFilePath(), + 'type': 'data' + } + ] + }, + 'dependencies2': { + 'assets': { + 'my_package/data': [ + Uri.file('path/to/file.ext').toFilePath(), + ], + }, + 'asset_types': { + 'native_code': [ + Uri.directory('path/to/directory/').toFilePath(), + ], + } + }, + 'metadata': {'key': 'value'}, 'version': '${HookOutputImpl.latestVersion}' }; @@ -167,6 +240,16 @@ version: 1.0.0'''; expect(buildOutput, buildOutput2); }); + test('built info json v1.5.0 keeps working', () { + final buildOutput = getBuildOutput(); + final json = buildOutput.toJson(Version(1, 5, 0)); + expect(json, jsonEncodingV1_5_0); + + final buildOutput2 = HookOutputImpl.fromJson(json); + expect(buildOutput.hashCode, buildOutput2.hashCode); + expect(buildOutput, buildOutput2); + }); + test('built info yaml v1.0.0 parsing keeps working', () { final buildOutput = getBuildOutput(withLinkedAssets: false); final buildOutput2 = HookOutputImpl.fromJsonString(yamlEncodingV1_0_0); @@ -317,7 +400,10 @@ version: 1.0.0'''), test('BuildOutput dependencies can be modified', () { final buildOutput = HookOutputImpl(); expect( - () => buildOutput.addDependencies([Uri.file('path/to/file.ext')]), + () => buildOutput.addAssetTypeDependencies( + NativeCodeAsset.type, + [Uri.file('path/to/file.ext')], + ), returnsNormally, ); }); @@ -340,10 +426,15 @@ version: 1.0.0'''), architecture: ArchitectureImpl.x64, ), ], - dependencies: Dependencies([ - Uri.file('path/to/file.ext'), - Uri.file('path/to/file2.ext'), - ]), + dependencies: Dependencies( + assetDependencies: { + 'my_package/foo': [ + Uri.file('path/to/file.ext'), + Uri.file('path/to/file2.ext'), + ], + }, + assetTypeDependencies: {}, + ), metadata: const Metadata({ 'key': 'value', 'key2': 'value2', @@ -361,6 +452,10 @@ version: 1.0.0'''), os: OSImpl.android, architecture: ArchitectureImpl.x64, ), + dependencies: [ + Uri.file('path/to/file.ext'), + Uri.file('path/to/file2.ext'), + ], ); buildOutput2.addAssets([ NativeCodeAssetImpl( @@ -370,12 +465,6 @@ version: 1.0.0'''), architecture: ArchitectureImpl.x64, ), ]); - buildOutput2.addDependency( - Uri.file('path/to/file.ext'), - ); - buildOutput2.addDependencies([ - Uri.file('path/to/file2.ext'), - ]); buildOutput2.addMetadata({ 'key': 'value', }); @@ -435,9 +524,18 @@ HookOutputImpl getBuildOutput({bool withLinkedAssets = true}) => HookOutputImpl( ] } : null, - dependencies: Dependencies([ - Uri.file('path/to/file.ext'), - ]), + dependencies: Dependencies( + assetDependencies: { + 'my_package/data': [ + Uri.file('path/to/file.ext'), + ], + }, + assetTypeDependencies: { + NativeCodeAsset.type: [ + Uri.directory('path/to/directory/'), + ], + }, + ), metadata: const Metadata({ 'key': 'value', }), diff --git a/pkgs/native_assets_cli/test/model/checksum_test.dart b/pkgs/native_assets_cli/test/model/checksum_test.dart index 35e3c7b58..83e6b53c1 100644 --- a/pkgs/native_assets_cli/test/model/checksum_test.dart +++ b/pkgs/native_assets_cli/test/model/checksum_test.dart @@ -32,7 +32,7 @@ void main() { ); // Using the checksum for a build folder should be stable. - expect(name1, '8780162e48a4539f01ea483fda6c1efc'); + expect(name1, '6348ba63b3aacba6f0e2acf8a53e57b4'); // Build folder different due to metadata. final name2 = HookConfigImpl.checksum( diff --git a/pkgs/native_assets_cli/test/model/dependencies_test.dart b/pkgs/native_assets_cli/test/model/dependencies_test.dart index e11aeb954..12b33aae8 100644 --- a/pkgs/native_assets_cli/test/model/dependencies_test.dart +++ b/pkgs/native_assets_cli/test/model/dependencies_test.dart @@ -18,12 +18,16 @@ void main() { tearDown( () async => await Directory.fromUri(tempUri).delete(recursive: true)); - final dependencies = Dependencies([ - Uri.file('src/bar.c'), - Uri.file('src/baz.c'), - Uri.directory('src/bla/'), - Uri.file('build.dart'), - ]); + final dependencies = Dependencies( + assetDependencies: { + 'my_package/foo': [ + Uri.file('src/bar.c'), + Uri.file('src/baz.c'), + Uri.directory('src/bla/'), + ], + }, + assetTypeDependencies: {}, + ); test('dependencies toString', dependencies.toString); @@ -34,7 +38,12 @@ void main() { final fileUri = tempUri.resolve('bla.c'); final file = File.fromUri(fileUri); await file.writeAsString('dummy contents'); - final dependencies = Dependencies([dirUri, fileUri]); + final dependencies = Dependencies( + assetDependencies: { + 'my_package/foo': [dirUri, fileUri], + }, + assetTypeDependencies: {}, + ); expect(await dependencies.lastModified(), await file.lastModified()); }); @@ -51,7 +60,12 @@ void main() { final someFile = File.fromUri(someFileUri); await someFile.writeAsString('yay!'); - final dependencies = Dependencies([tempUri]); + final dependencies = Dependencies( + assetDependencies: { + 'my_package/foo': [tempUri], + }, + assetTypeDependencies: {}, + ); expect(await dependencies.lastModified(), await someFile.lastModified()); }); @@ -64,10 +78,15 @@ void main() { final now = DateTime.now(); - final dependencies = Dependencies([ - someFileUri, - deletedFileUri, - ]); + final dependencies = Dependencies( + assetDependencies: { + 'my_package/foo': [ + someFileUri, + deletedFileUri, + ], + }, + assetTypeDependencies: {}, + ); final depsLastModified = await dependencies.lastModified(); expect(depsLastModified == now || depsLastModified.isAfter(now), true); }); diff --git a/pkgs/native_toolchain_c/CHANGELOG.md b/pkgs/native_toolchain_c/CHANGELOG.md index 3cb1eb726..435b94171 100644 --- a/pkgs/native_toolchain_c/CHANGELOG.md +++ b/pkgs/native_toolchain_c/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.5.3-wip -- Nothing yet. +- Bump `package:native_assets_cli` to 0.8.0 and report dependencies per asset. ## 0.5.2 diff --git a/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart b/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart index 6a9e3737b..e0e740fda 100644 --- a/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart +++ b/pkgs/native_toolchain_c/lib/src/cbuilder/cbuilder.dart @@ -60,14 +60,14 @@ class CBuilder implements Builder { /// /// Resolved against [BuildConfig.packageRoot]. /// - /// Used to output the [BuildOutput.dependencies]. + /// Used to output the [BuildOutput.assetDependencies]. final List sources; /// Include directories to pass to the compiler. /// /// Resolved against [BuildConfig.packageRoot]. /// - /// Used to output the [BuildOutput.dependencies]. + /// Used to output the [BuildOutput.assetDependencies]. final List includes; /// Frameworks to link. @@ -76,10 +76,10 @@ class CBuilder implements Builder { /// /// Defaults to `['Foundation']`. /// - /// Not used to output the [BuildOutput.dependencies], frameworks can be + /// Not used to output the [BuildOutput.assetDependencies], frameworks can be /// mentioned by name if they are available on the system, so the file path /// is not known. If you're depending on your own frameworks add them to - /// [BuildOutput.dependencies] manually. + /// [BuildOutput.assetDependencies] manually. final List frameworks; static const List _defaultFrameworks = ['Foundation']; @@ -88,7 +88,7 @@ class CBuilder implements Builder { /// /// Resolved against [BuildConfig.packageRoot]. /// - /// Used to output the [BuildOutput.dependencies]. + /// Used to output the [BuildOutput.assetDependencies]. @Deprecated( 'Newer Dart and Flutter SDKs automatically add the Dart hook ' 'sources as dependencies.', @@ -287,21 +287,7 @@ class CBuilder implements Builder { await task.run(); } - if (assetName != null) { - output.addAssets( - [ - NativeCodeAsset( - package: config.packageName, - name: assetName!, - file: libUri, - linkMode: linkMode, - os: config.targetOS, - architecture: config.dryRun ? null : config.targetArchitecture, - ) - ], - linkInPackage: linkInPackage, - ); - } + final Iterable? dependencies; if (!config.dryRun) { final includeFiles = await Stream.fromIterable(includes) .asyncExpand( @@ -312,12 +298,32 @@ class CBuilder implements Builder { ) .toList(); - output.addDependencies({ + dependencies = { // Note: We use a Set here to deduplicate the dependencies. ...sources, ...includeFiles, ...dartBuildFiles, - }); + }; + if (assetName == null) { + output.addAssetTypeDependencies(NativeCodeAsset.type, dependencies); + } + } else { + dependencies = null; + } + + if (assetName != null) { + output.addAsset( + NativeCodeAsset( + package: config.packageName, + name: assetName!, + file: libUri, + linkMode: linkMode, + os: config.targetOS, + architecture: config.dryRun ? null : config.targetArchitecture, + ), + linkInPackage: linkInPackage, + dependencies: dependencies, + ); } } } diff --git a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_test.dart b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_test.dart index 495e6091d..17391ac92 100644 --- a/pkgs/native_toolchain_c/test/cbuilder/cbuilder_test.dart +++ b/pkgs/native_toolchain_c/test/cbuilder/cbuilder_test.dart @@ -305,7 +305,10 @@ void main() { logger: logger, ); - expect(buildOutput.dependencies, contains(includesHUri)); + expect( + buildOutput.assetDependencies[buildOutput.assets.single.id], + contains(includesHUri), + ); final dylibUri = tempUri.resolve(OS.current.dylibFileName(name)); final dylib = openDynamicLibraryForTest(dylibUri.toFilePath());