diff --git a/.github/workflows/native.yaml b/.github/workflows/native.yaml index 693b1220e8..0712c6f791 100644 --- a/.github/workflows/native.yaml +++ b/.github/workflows/native.yaml @@ -102,6 +102,9 @@ jobs: - run: dart pub get -C test_data/native_dynamic_linking/ if: ${{ matrix.package == 'native_assets_builder' }} + - run: dart pub get -C test_data/asset_build_time/ + if: ${{ matrix.package == 'native_assets_builder' }} + - run: dart pub get -C example/build/native_dynamic_linking/ if: ${{ matrix.package == 'native_assets_cli' }} 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 2a1f05a546..e4433f6711 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 @@ -625,6 +625,11 @@ ${result.stdout} for (final error in validateResult.errors) { logger.severe('- $error'); } + + if (success) { + await output.touchAssets(); + } + return (output, success); } on FormatException catch (e) { logger.severe(''' @@ -925,3 +930,21 @@ extension on DateTime { extension on Uri { Uri get parent => File(toFilePath()).parent.uri; } + +extension on api.BuildOutput { + /// Sets the last modified time of all assets to [timestamp]. + /// + /// This ensures that caching mechanisms can use the last modified time of + /// assets to invalidate cached results that depend on assets. + Future touchAssets() async { + await Future.wait( + [...assets, ...assetsForLinking.values] + .map((asset) => switch (asset) { + NativeCodeAssetImpl(:final file) => file!, + DataAssetImpl(:final file) => file, + _ => throw UnsupportedError('Unsupported asset type: $asset'), + }) + .map((file) => File.fromUri(file).setLastModified(timestamp)), + ); + } +} diff --git a/pkgs/native_assets_builder/test/build_runner/build_runner_touch_assets_test.dart b/pkgs/native_assets_builder/test/build_runner/build_runner_touch_assets_test.dart new file mode 100644 index 0000000000..cecb39295e --- /dev/null +++ b/pkgs/native_assets_builder/test/build_runner/build_runner_touch_assets_test.dart @@ -0,0 +1,62 @@ +// 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 'package:native_assets_cli/native_assets_cli.dart' as api; +import 'package:native_assets_cli/native_assets_cli_internal.dart'; +import 'package:test/test.dart'; + +import '../helpers.dart'; +import 'helpers.dart'; + +const Timeout longTimeout = Timeout(Duration(minutes: 5)); + +void main() async { + test( + 'set last modified date of assets to build output timestamp', + timeout: longTimeout, + () async { + await inTempDir((tempUri) async { + await copyTestProjects(targetUri: tempUri); + final packageUri = tempUri.resolve('asset_build_time/'); + + // First, run `pub get`, we need pub to resolve our dependencies. + await runPubGet( + workingDirectory: packageUri, + logger: logger, + ); + + final result = await build( + packageUri, + logger, + dartExecutable, + supportedAssetTypes: [api.NativeCodeAsset.type, api.DataAsset.type], + ); + + expect(result.assets, hasLength(2)); + + final buildTimeLibraryUri = + result.assets.whereType().single.file!; + final buildDirectoryUri = buildTimeLibraryUri.resolve('./'); + + final buildOutputUri = buildDirectoryUri.resolve('build_output.json'); + final buildOutput = HookOutputImpl.fromJsonString( + await File.fromUri(buildOutputUri).readAsString()); + + expect( + File.fromUri(buildTimeLibraryUri).lastModifiedSync(), + buildOutput.timestamp, + ); + + final buildTimeDataAssetUri = + result.assets.whereType().single.file; + expect( + File.fromUri(buildTimeDataAssetUri).lastModifiedSync(), + buildOutput.timestamp, + ); + }); + }, + ); +} diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/build_time b/pkgs/native_assets_builder/test_data/asset_build_time/build_time new file mode 100644 index 0000000000..a03edd7425 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/build_time @@ -0,0 +1 @@ +2024-01-01T00:00:00.000Z \ No newline at end of file diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/ffigen.yaml b/pkgs/native_assets_builder/test_data/asset_build_time/ffigen.yaml new file mode 100644 index 0000000000..dbcc82a6d4 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/ffigen.yaml @@ -0,0 +1,20 @@ +# Run with `flutter pub run ffigen --config ffigen.yaml`. +name: AssetBuildTimeBindings +description: | + Bindings for `src/asset_build_time.h`. + + Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. +output: 'lib/src/asset_build_time_bindings_generated.dart' +headers: + entry-points: + - 'src/asset_build_time.h' + include-directives: + - 'src/asset_build_time.h' +preamble: | + // 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. +comments: + style: any + length: full +ffi-native: diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/hook/build.dart b/pkgs/native_assets_builder/test_data/asset_build_time/hook/build.dart new file mode 100644 index 0000000000..faa86f8b6c --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/hook/build.dart @@ -0,0 +1,63 @@ +// 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 '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 buildTimeFileUri = config.packageRoot.resolve('build_time'); + final buildTime = + DateTime.parse(File.fromUri(buildTimeFileUri).readAsStringSync()); + output.addDependency(buildTimeFileUri); + + final name = config.packageName; + + final cbuilder = CBuilder.library( + name: config.packageName, + assetName: 'src/${name}_bindings_generated.dart', + sources: [ + 'src/$name.c', + ], + defines: { + 'BUILD_TIME': '"${buildTime.toIso8601String()}"', + }, + ); + await cbuilder.run( + config: config, + output: output, + logger: Logger('') + ..level = Level.ALL + ..onRecord.listen((record) { + print('${record.level.name}: ${record.time}: ${record.message}'); + }), + ); + + if (config.supportedAssetTypes.contains(DataAsset.type)) { + final buildTimeDataAssetUri = + config.outputDirectory.resolve('build_time'); + output.addAsset( + DataAsset( + package: config.packageName, + name: 'build_time', + file: buildTimeDataAssetUri, + ), + ); + + if (!config.dryRun) { + File.fromUri(buildTimeDataAssetUri) + .writeAsStringSync(buildTime.toIso8601String()); + } + } + + if (!config.dryRun) { + for (final asset in output.assets) { + File.fromUri(asset.file!).setLastModifiedSync(buildTime); + } + } + }); +} diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/lib/asset_build_time.dart b/pkgs/native_assets_builder/test_data/asset_build_time/lib/asset_build_time.dart new file mode 100644 index 0000000000..6c07d10d04 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/lib/asset_build_time.dart @@ -0,0 +1,5 @@ +// 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. + +export 'src/asset_build_time.dart'; diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/lib/src/asset_build_time.dart b/pkgs/native_assets_builder/test_data/asset_build_time/lib/src/asset_build_time.dart new file mode 100644 index 0000000000..36d7e81652 --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/lib/src/asset_build_time.dart @@ -0,0 +1,10 @@ +// 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:ffi/ffi.dart'; + +import 'asset_build_time_bindings_generated.dart' as bindings; + +DateTime get buildTime => + DateTime.parse(bindings.buildTime.cast().toDartString()); diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/lib/src/asset_build_time_bindings_generated.dart b/pkgs/native_assets_builder/test_data/asset_build_time/lib/src/asset_build_time_bindings_generated.dart new file mode 100644 index 0000000000..905e00eb2a --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/lib/src/asset_build_time_bindings_generated.dart @@ -0,0 +1,12 @@ +// 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. + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +// ignore_for_file: type=lint +import 'dart:ffi' as ffi; + +@ffi.Native>() +external ffi.Pointer buildTime; diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/pubspec.yaml b/pkgs/native_assets_builder/test_data/asset_build_time/pubspec.yaml new file mode 100644 index 0000000000..359c0ba2ca --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/pubspec.yaml @@ -0,0 +1,25 @@ +name: asset_build_time +description: + Embeds a build time into a library and a data asset and sets it as the assets + last modified time. +version: 1.0.0 + +publish_to: none + +environment: + sdk: '>=3.3.0 <4.0.0' + +dependencies: + ffi: ^2.1.3 + logging: ^1.1.1 + # native_assets_cli: ^0.7.3 + native_assets_cli: + path: ../../../native_assets_cli/ + # native_toolchain_c: ^0.5.3 + native_toolchain_c: + path: ../../../native_toolchain_c/ + +dev_dependencies: + ffigen: ^13.0.0 + lints: ^3.0.0 + test: ^1.23.1 diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/src/asset_build_time.c b/pkgs/native_assets_builder/test_data/asset_build_time/src/asset_build_time.c new file mode 100644 index 0000000000..7aa1d92e8f --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/src/asset_build_time.c @@ -0,0 +1,7 @@ +// 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. + +#include "asset_build_time.h" + +char *buildTime = BUILD_TIME; diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/src/asset_build_time.h b/pkgs/native_assets_builder/test_data/asset_build_time/src/asset_build_time.h new file mode 100644 index 0000000000..2ccf2a59cd --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/src/asset_build_time.h @@ -0,0 +1,11 @@ +// 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. + +#if _WIN32 +#define MYLIB_EXPORT __declspec(dllexport) +#else +#define MYLIB_EXPORT +#endif + +MYLIB_EXPORT char* buildTime; diff --git a/pkgs/native_assets_builder/test_data/asset_build_time/test/asset_build_time_test.dart b/pkgs/native_assets_builder/test_data/asset_build_time/test/asset_build_time_test.dart new file mode 100644 index 0000000000..8b630d29bf --- /dev/null +++ b/pkgs/native_assets_builder/test_data/asset_build_time/test/asset_build_time_test.dart @@ -0,0 +1,14 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; + +import 'package:asset_build_time/asset_build_time.dart'; +import 'package:test/test.dart'; + +void main() { + test('library build time test', () { + expect(buildTime, DateTime.parse(File('build_time').readAsStringSync())); + }); +} diff --git a/pkgs/native_assets_builder/test_data/manifest.yaml b/pkgs/native_assets_builder/test_data/manifest.yaml index fd8a5fa9c3..b09bfa96bb 100644 --- a/pkgs/native_assets_builder/test_data/manifest.yaml +++ b/pkgs/native_assets_builder/test_data/manifest.yaml @@ -134,3 +134,13 @@ - native_dynamic_linking/ffigen.yaml - native_dynamic_linking/pubspec.yaml - native_dynamic_linking/README.md +- asset_build_time/build_time +- asset_build_time/ffigen.yaml +- asset_build_time/hook/build.dart +- asset_build_time/lib/asset_build_time.dart +- asset_build_time/lib/src/asset_build_time_bindings_generated.dart +- asset_build_time/lib/src/asset_build_time.dart +- asset_build_time/pubspec.yaml +- asset_build_time/src/asset_build_time.c +- asset_build_time/src/asset_build_time.h +- asset_build_time/test/asset_build_time_test.dart