diff --git a/dev/integration_tests/data_asset_app/hook/build.dart b/dev/integration_tests/data_asset_app/hook/build.dart index 25aa7480d17ed..2c92a7e54dff8 100644 --- a/dev/integration_tests/data_asset_app/hook/build.dart +++ b/dev/integration_tests/data_asset_app/hook/build.dart @@ -17,6 +17,7 @@ void main(List args) async { file: input.packageRoot.resolve('data/$id'), ), ); + output.dependencies.add(input.packageRoot.resolve('data/$id')); } } }); diff --git a/dev/integration_tests/data_asset_app/pubspec.yaml b/dev/integration_tests/data_asset_app/pubspec.yaml index 905d6be746144..a05bb29bd5e94 100644 --- a/dev/integration_tests/data_asset_app/pubspec.yaml +++ b/dev/integration_tests/data_asset_app/pubspec.yaml @@ -12,8 +12,8 @@ resolution: workspace dependencies: flutter: sdk: flutter - hooks: ^1.0.2 - data_assets: ^0.19.6 + hooks: ^2.0.0 + data_assets: ^0.20.0 data_asset_package: path: ../data_asset_package @@ -24,4 +24,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: jl85h +# PUBSPEC CHECKSUM: 9jmf6j diff --git a/dev/integration_tests/data_asset_package/.gitignore b/dev/integration_tests/data_asset_package/.gitignore index dd5eb98951f29..f966f4da52b56 100644 --- a/dev/integration_tests/data_asset_package/.gitignore +++ b/dev/integration_tests/data_asset_package/.gitignore @@ -29,3 +29,6 @@ migrate_working_dir/ .flutter-plugins-dependencies /build/ /coverage/ + +# Generated test file. +data/generated.txt diff --git a/dev/integration_tests/data_asset_package/hook/build.dart b/dev/integration_tests/data_asset_package/hook/build.dart index 25aa7480d17ed..bc16610c7cd90 100644 --- a/dev/integration_tests/data_asset_package/hook/build.dart +++ b/dev/integration_tests/data_asset_package/hook/build.dart @@ -2,6 +2,8 @@ // 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:data_assets/data_assets.dart'; import 'package:hooks/hooks.dart'; @@ -17,7 +19,28 @@ void main(List args) async { file: input.packageRoot.resolve('data/$id'), ), ); + // If the file is modified, the hook needs to be rerun. (Technically, we + // don't need to rerun because we'd output the exact same thing. But the + // hook could be doing other things based on the input file.) + output.dependencies.add(input.packageRoot.resolve('data/$id')); + } + + // Generate a data asset in the hook. + // It is better to generate to outputDirectoryShared, but users might do + // this instead and then delete the file manually. + final Uri generatedUri = input.packageRoot.resolve('data/generated.txt'); + final file = File(generatedUri.toFilePath()); + if (!file.parent.existsSync()) { + file.parent.createSync(recursive: true); } + file.writeAsStringSync('generated content'); + output.assets.data.add( + DataAsset( + package: input.packageName, + name: 'data/generated.txt', + file: generatedUri, + ), + ); } }); } diff --git a/dev/integration_tests/data_asset_package/pubspec.yaml b/dev/integration_tests/data_asset_package/pubspec.yaml index 2fa645acffd85..9e4421c759c07 100644 --- a/dev/integration_tests/data_asset_package/pubspec.yaml +++ b/dev/integration_tests/data_asset_package/pubspec.yaml @@ -12,8 +12,8 @@ resolution: workspace dependencies: flutter: sdk: flutter - hooks: ^1.0.2 - data_assets: ^0.19.6 + hooks: ^2.0.0 + data_assets: ^0.20.0 dev_dependencies: flutter_test: @@ -22,4 +22,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2g5j7i +# PUBSPEC CHECKSUM: 6cfeb0 diff --git a/dev/integration_tests/hook_user_defines/pubspec.yaml b/dev/integration_tests/hook_user_defines/pubspec.yaml index 2e4a3869b7740..b620a7dc63e14 100644 --- a/dev/integration_tests/hook_user_defines/pubspec.yaml +++ b/dev/integration_tests/hook_user_defines/pubspec.yaml @@ -15,11 +15,11 @@ hooks: magic_value: 1000 dependencies: - hooks: 1.0.3 + hooks: 2.0.0 logging: 1.3.0 - native_toolchain_c: 0.17.6 + native_toolchain_c: 0.19.0 dev_dependencies: test: 1.29.0 -# PUBSPEC CHECKSUM: 30ohqf +# PUBSPEC CHECKSUM: jmsrr2 diff --git a/dev/integration_tests/record_use_test_package/pubspec.yaml b/dev/integration_tests/record_use_test_package/pubspec.yaml index 1248355fba1c9..d1d6efbe2e9fc 100644 --- a/dev/integration_tests/record_use_test_package/pubspec.yaml +++ b/dev/integration_tests/record_use_test_package/pubspec.yaml @@ -11,8 +11,8 @@ environment: dependencies: flutter: sdk: flutter - hooks: ^1.0.2 - data_assets: ^0.19.6 + hooks: ^2.0.0 + data_assets: ^0.20.0 record_use: 0.6.0 meta: 1.18.2 @@ -23,4 +23,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4e6oin +# PUBSPEC CHECKSUM: gl7kb7 diff --git a/packages/flutter_tools/lib/src/build_system/targets/hook_runner_native.dart b/packages/flutter_tools/lib/src/build_system/targets/hook_runner_native.dart index e3e835b7b89f3..eb8c192dd453b 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/hook_runner_native.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/hook_runner_native.dart @@ -37,7 +37,7 @@ class FlutterHookRunnerNative implements FlutterHookRunner { environment, ); - final DartHooksResult dartHooksResult = await runFlutterSpecificHooks( + final (:DartHooksResult buildResult, results: _) = await runFlutterSpecificBuildHooks( environmentDefines: environment.defines, buildRunner: buildRunner, targetPlatform: targetPlatform, @@ -45,10 +45,9 @@ class FlutterHookRunnerNative implements FlutterHookRunner { fileSystem: environment.fileSystem, buildCodeAssets: null, buildDataAssets: true, - recordedUsesFile: null, ); - final FlutterHookResult flutterHookResult = dartHooksResult.asFlutterResult; + final FlutterHookResult flutterHookResult = buildResult.asFlutterResult; _flutterHookResult = flutterHookResult; logger?.printTrace('runHooks() - done'); return flutterHookResult; diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index 40aacae6c3973..3a3fb42e3190b 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -57,8 +57,8 @@ class BuildHooks extends Target { final FlutterNativeAssetsBuildRunner buildRunner = _buildRunner ?? await createFlutterNativeAssetsBuildRunner(environment); final ( - results: SerializedBuildResults results, - dependencies: List dependencies, + :SerializedBuildResults results, + :DartHooksResult buildResult, ) = await runFlutterSpecificBuildHooks( environmentDefines: environment.defines, buildRunner: buildRunner, @@ -74,11 +74,20 @@ class BuildHooks extends Target { dartBuildOutputJsonFile.parent.createSync(recursive: true); } - dartBuildOutputJsonFile.writeAsStringSync(json.encode(results)); + final String encodedResults = json.encode(results); + if (!dartBuildOutputJsonFile.existsSync() || + dartBuildOutputJsonFile.readAsStringSync() != encodedResults) { + dartBuildOutputJsonFile.writeAsStringSync(encodedResults); + } + final Set buildDependencies = buildResult.dependencies.toSet(); final depfile = Depfile( - [for (final Uri dependency in dependencies) fileSystem.file(dependency)], - [fileSystem.file(dartBuildOutputJsonFile)], + [for (final Uri dependency in buildResult.dependencies) fileSystem.file(dependency)], + [ + fileSystem.file(dartBuildOutputJsonFile), + for (final Uri uri in buildResult.filesToBeBundled) + if (!buildDependencies.contains(uri)) fileSystem.file(uri), + ], ); final File outputDepfile = environment.buildDir.childFile(depFilename); if (!outputDepfile.parent.existsSync()) { @@ -98,7 +107,6 @@ class BuildHooks extends Target { // If different packages are resolved, different native assets might need to // be built. Source.pattern('{WORKSPACE_DIR}/.dart_tool/package_config.json'), - // TODO(mosuem): Should consume resources.json. https://github.com/flutter/flutter/issues/146263 ]; @override @@ -197,6 +205,8 @@ class LinkHooks extends Target { final buildMode = BuildMode.fromCliName(buildModeEnvironment); final File? recordedUsesFileToPass = getRecordedUsesFile(environment, buildMode); + final linkingEnabled = buildMode != BuildMode.debug; + // Read the result of BuildHooks. final File dartBuildOutputJsonFile = environment.buildDir.childFile(BuildHooks.resultFilename); if (!dartBuildOutputJsonFile.existsSync()) { @@ -207,29 +217,52 @@ class LinkHooks extends Target { final Map> buildResults = serializedBuildResults .cast>(); - final DartHooksResult result = await runFlutterSpecificLinkHooks( + final DartHooksResult linkResult; + if (linkingEnabled) { + linkResult = await runFlutterSpecificLinkHooks( + environmentDefines: environment.defines, + buildRunner: buildRunner, + targetPlatform: targetPlatform, + projectUri: projectUri, + fileSystem: fileSystem, + buildCodeAssets: BuildCodeAssetsOptions(appBuildDirectory: environment.outputDir), + buildDataAssets: true, + buildResults: buildResults, + recordedUsesFile: recordedUsesFileToPass, + ); + } else { + linkResult = DartHooksResult.empty(); + } + + final DartHooksResult combinedResult = combineBuildAndLinkResults( environmentDefines: environment.defines, - buildRunner: buildRunner, targetPlatform: targetPlatform, - projectUri: projectUri, fileSystem: fileSystem, buildCodeAssets: BuildCodeAssetsOptions(appBuildDirectory: environment.outputDir), buildDataAssets: true, buildResults: buildResults, - recordedUsesFile: recordedUsesFileToPass, + linkResult: linkResult, ); final File dartHookResultJsonFile = environment.buildDir.childFile(resultFilename); if (!dartHookResultJsonFile.parent.existsSync()) { dartHookResultJsonFile.parent.createSync(recursive: true); } - dartHookResultJsonFile.writeAsStringSync(json.encode(result.toJson())); - + // TODO(dcharkes): The build system uses file hashing to determine if + // targets need to be rerun. Because combinedResult.toJson() includes + // transient build_start and build_end times, this file is rewritten on + // every build causing downstream targets to rerun. We should remove + // build_start and build_end from the JSON representation entirely in a + // future PR. + dartHookResultJsonFile.writeAsStringSync(json.encode(combinedResult.toJson())); + final Set linkDependencies = linkResult.dependencies.toSet(); final depfile = Depfile( - [for (final Uri dependency in result.dependencies) fileSystem.file(dependency)], + [for (final Uri dependency in linkResult.dependencies) fileSystem.file(dependency)], [ fileSystem.file(dartHookResultJsonFile), - for (final Uri uri in result.filesToBeBundled) fileSystem.file(uri), + if (linkingEnabled) + for (final Uri uri in linkResult.filesToBeBundled) + if (!linkDependencies.contains(uri)) fileSystem.file(uri), ], ); final File outputDepfile = environment.buildDir.childFile(depFilename); @@ -278,8 +311,8 @@ class InstallCodeAssets extends Target { final FileSystem fileSystem = environment.fileSystem; final TargetPlatform targetPlatform = _getTargetPlatformFromEnvironment(environment, name); - // We fetch the result from the [LinkHooks]. - final DartHooksResult dartHookResult = await LinkHooks.loadHookResult(environment); + // We fetch the combined result from the [LinkHooks]. + final DartHooksResult combinedResult = await LinkHooks.loadHookResult(environment); // And install/copy the code assets to the right place and create a // native_asset.yaml that can be used by the final AOT compilation. @@ -293,7 +326,7 @@ class InstallCodeAssets extends Target { } final List installedFiles = await installCodeAssets( - dartHookResult: dartHookResult, + dartHookResult: combinedResult, environmentDefines: environment.defines, targetPlatform: targetPlatform, projectUri: projectUri, @@ -304,7 +337,7 @@ class InstallCodeAssets extends Target { assert(fileSystem.file(nativeAssetsFileUri).existsSync()); final depfile = Depfile([ - for (final Uri file in dartHookResult.filesToBeBundled) fileSystem.file(file), + for (final Uri file in combinedResult.filesToBeBundled) fileSystem.file(file), ], installedFiles); final File outputDepfile = environment.buildDir.childFile(depFilename); environment.depFileService.writeToFile(depfile, outputDepfile); diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart index ab02077c618f9..3e0ec38639659 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart @@ -87,10 +87,7 @@ Future runFlutterSpecificHooks({ final buildStart = DateTime.now(); - final ( - results: SerializedBuildResults results, - dependencies: List dependencies, - ) = await runFlutterSpecificBuildHooks( + final (:SerializedBuildResults results, buildResult: _) = await runFlutterSpecificBuildHooks( environmentDefines: environmentDefines, buildRunner: buildRunner, targetPlatform: targetPlatform, @@ -100,24 +97,44 @@ Future runFlutterSpecificHooks({ buildDataAssets: buildDataAssets, ); - final DartHooksResult linkResult = await runFlutterSpecificLinkHooks( + final BuildMode buildMode = _getBuildMode( + environmentDefines, + targetPlatform == TargetPlatform.tester, + ); + final bool linkingEnabled = _nativeAssetsLinkingEnabled(buildMode); + final DartHooksResult linkResult; + if (linkingEnabled) { + linkResult = await runFlutterSpecificLinkHooks( + environmentDefines: environmentDefines, + buildRunner: buildRunner, + targetPlatform: targetPlatform, + projectUri: projectUri, + fileSystem: fileSystem, + buildCodeAssets: buildCodeAssets, + buildDataAssets: buildDataAssets, + buildResults: results, + recordedUsesFile: recordedUsesFile, + ); + } else { + linkResult = DartHooksResult.empty(); + } + + final DartHooksResult combinedResult = combineBuildAndLinkResults( environmentDefines: environmentDefines, - buildRunner: buildRunner, targetPlatform: targetPlatform, - projectUri: projectUri, fileSystem: fileSystem, buildCodeAssets: buildCodeAssets, buildDataAssets: buildDataAssets, buildResults: results, - recordedUsesFile: recordedUsesFile, + linkResult: linkResult, ); return DartHooksResult( buildStart: buildStart, - buildEnd: linkResult.buildEnd, - codeAssets: linkResult.codeAssets, - dataAssets: linkResult.dataAssets, - dependencies: {...dependencies, ...linkResult.dependencies}.toList(), + buildEnd: combinedResult.buildEnd, + codeAssets: combinedResult.codeAssets, + dataAssets: combinedResult.dataAssets, + dependencies: combinedResult.dependencies, ); } @@ -125,7 +142,8 @@ Future runFlutterSpecificHooks({ /// /// Returns the serialized build results per target and the list of dependencies /// collected during the build stage. -Future<({SerializedBuildResults results, List dependencies})> runFlutterSpecificBuildHooks({ +Future<({SerializedBuildResults results, DartHooksResult buildResult})> +runFlutterSpecificBuildHooks({ required Map environmentDefines, required FlutterNativeAssetsBuildRunner buildRunner, required TargetPlatform targetPlatform, @@ -135,9 +153,11 @@ Future<({SerializedBuildResults results, List dependencies})> runFlutterSpe required bool buildDataAssets, }) async { if (!await _hookRunRequired(buildRunner)) { - return (results: const >{}, dependencies: const []); + return (results: const >{}, buildResult: DartHooksResult.empty()); } + final buildStart = DateTime.now(); + final ( targets: List targets, buildMode: BuildMode buildMode, @@ -158,6 +178,9 @@ Future<({SerializedBuildResults results, List dependencies})> runFlutterSpe final results = >{}; final dependencies = {}; + final codeAssets = []; + final dataAssets = []; + for (var i = 0; i < targets.length; i++) { final AssetBuildTarget target = targets[i]; // Only run non-code extensions (like data assets) for the first target, @@ -168,9 +191,25 @@ Future<({SerializedBuildResults results, List dependencies})> runFlutterSpe final BuildResult buildResult = await _build(buildRunner, extensions, linkingEnabled); results[target.targetString] = buildResult.toJson(); dependencies.addAll(buildResult.dependencies); + _decodeAssets( + encodedAssets: buildResult.encodedAssets, + target: target, + codeAssetsAccumulator: codeAssets, + dataAssetsAccumulator: dataAssets, + ); } + _checkForDuplicateAssets(codeAssets: codeAssets, dataAssets: dataAssets, targets: targets); globals.logger.printTrace('Running build hooks for $targetString done.'); - return (results: results, dependencies: dependencies.toList()); + return ( + results: results, + buildResult: DartHooksResult( + buildStart: buildStart, + buildEnd: DateTime.now(), + codeAssets: codeAssets, + dataAssets: dataAssets, + dependencies: dependencies.toList(), + ), + ); } List _getTargets({ @@ -241,11 +280,8 @@ Future<({List targets, BuildMode buildMode, bool linkingEnable /// Invokes the link hooks of all transitive Dart package hooks. /// -/// It takes the [buildResults] produced by [runFlutterSpecificBuildHooks] and -/// returns a [DartHooksResult] containing the aggregated assets from both the -/// build results and the link hooks. -/// /// The returned dependencies only include those collected during the link stage. +/// The returned assets only include those produced during the link stage. Future runFlutterSpecificLinkHooks({ required Map environmentDefines, required FlutterNativeAssetsBuildRunner buildRunner, @@ -297,54 +333,25 @@ Future runFlutterSpecificLinkHooks({ } final buildResult = BuildResult.fromJson(buildResultJson); - LinkResult? linkResult; if (linkingEnabled) { - linkResult = await _link(buildRunner, extensions, buildResult, recordedUsesFile); - - if (target is CodeAssetTarget) { - codeAssets - ..addAll( - _filterCodeAssets( - linkResult.encodedAssets, - Target.fromArchitectureAndOS(target.architecture, target.os), - ), - ) - ..addAll( - _filterCodeAssets( - buildResult.encodedAssets, - Target.fromArchitectureAndOS(target.architecture, target.os), - ), - ); - } - dataAssets - ..addAll(_filterDataAssets(linkResult.encodedAssets)) - ..addAll(_filterDataAssets(buildResult.encodedAssets)); + final LinkResult linkResult = await _link( + buildRunner, + extensions, + buildResult, + recordedUsesFile, + ); + + _decodeAssets( + encodedAssets: linkResult.encodedAssets, + target: target, + codeAssetsAccumulator: codeAssets, + dataAssetsAccumulator: dataAssets, + ); dependencies.addAll(linkResult.dependencies); - } else { - if (target is CodeAssetTarget) { - codeAssets.addAll( - _filterCodeAssets( - buildResult.encodedAssets, - Target.fromArchitectureAndOS(target.architecture, target.os), - ), - ); - } - dataAssets.addAll(_filterDataAssets(buildResult.encodedAssets)); - dependencies.addAll(buildResult.dependencies); } } - if (dataAssets.map((DataAsset asset) => asset.id).toSet().length != dataAssets.length) { - throwToolExit( - 'Found duplicates in the data assets: ${dataAssets.map((DataAsset e) => e.id).toList()} while compiling for ${targets.map((AssetBuildTarget e) => e.targetString).toList()}.', - ); - } - - if (codeAssets.toSet().length != codeAssets.length) { - throwToolExit( - 'Found duplicates in the code assets: ${codeAssets.map((FlutterCodeAsset e) => e.codeAsset.id).toList()} while compiling for ${targets.map((AssetBuildTarget e) => e.targetString).toList()}.', - ); - } + _checkForDuplicateAssets(codeAssets: codeAssets, dataAssets: dataAssets, targets: targets); globals.logger.printTrace('Running link hooks for $targetString done.'); @@ -357,6 +364,117 @@ Future runFlutterSpecificLinkHooks({ ); } +/// Combines build-stage and link-stage results into a single, combined [DartHooksResult]. +/// +/// The combined result contains all code and data assets from both stages, +/// and the union of all dependencies from both stages. +DartHooksResult combineBuildAndLinkResults({ + required Map environmentDefines, + required TargetPlatform targetPlatform, + required FileSystem fileSystem, + required BuildCodeAssetsOptions? buildCodeAssets, + required bool buildDataAssets, + required SerializedBuildResults buildResults, + required DartHooksResult linkResult, +}) { + final List targets = _getTargets( + environmentDefines: environmentDefines, + targetPlatform: targetPlatform, + fileSystem: fileSystem, + buildCodeAssets: buildCodeAssets, + buildDataAssets: buildDataAssets, + ); + + final codeAssets = [...linkResult.codeAssets]; + final dataAssets = [...linkResult.dataAssets]; + final dependencies = {...linkResult.dependencies}; + + for (final target in targets) { + final Map? buildResultJson = buildResults[target.targetString]; + if (buildResultJson == null) { + continue; + } + final buildResult = BuildResult.fromJson(buildResultJson); + _decodeAssets( + encodedAssets: buildResult.encodedAssets, + target: target, + codeAssetsAccumulator: codeAssets, + dataAssetsAccumulator: dataAssets, + ); + dependencies.addAll(buildResult.dependencies); + } + + _checkForDuplicateAssets(codeAssets: codeAssets, dataAssets: dataAssets, targets: targets); + + return DartHooksResult( + buildStart: linkResult.buildStart, + buildEnd: linkResult.buildEnd, + codeAssets: codeAssets, + dataAssets: dataAssets, + dependencies: dependencies.toList(), + ); +} + +/// Extracts and categorizes code and data assets from [encodedAssets] for the given [target]. +/// +/// The extracted assets are appended to the optional accumulator lists: +/// - [codeAssetsAccumulator]: Collects matching [FlutterCodeAsset]s. +/// - [dataAssetsAccumulator]: Collects matching [DataAsset]s. +void _decodeAssets({ + required Iterable encodedAssets, + required AssetBuildTarget target, + List? codeAssetsAccumulator, + List? dataAssetsAccumulator, +}) { + if (target is CodeAssetTarget) { + final Iterable filteredCode = _filterCodeAssets( + encodedAssets, + Target.fromArchitectureAndOS(target.architecture, target.os), + ); + codeAssetsAccumulator?.addAll(filteredCode); + } + final Iterable filteredData = _filterDataAssets(encodedAssets); + dataAssetsAccumulator?.addAll(filteredData); +} + +void _checkForDuplicateAssets({ + required List codeAssets, + required List dataAssets, + required List targets, +}) { + final List targetStrings = targets.map((AssetBuildTarget e) => e.targetString).toList(); + + final dataAssetIds = {}; + final duplicateDataAssetIds = {}; + for (final asset in dataAssets) { + if (!dataAssetIds.add(asset.id)) { + duplicateDataAssetIds.add(asset.id); + } + } + if (duplicateDataAssetIds.isNotEmpty) { + throwToolExit( + 'Found duplicates in the data assets: ' + '${duplicateDataAssetIds.toList()} while compiling for ' + '$targetStrings.', + ); + } + + final codeAssetIds = <(String, Target)>{}; + final duplicateCodeAssetIds = {}; + for (final asset in codeAssets) { + if (!codeAssetIds.add((asset.codeAsset.id, asset.target))) { + duplicateCodeAssetIds.add(asset.codeAsset.id); + } + } + if (duplicateCodeAssetIds.isNotEmpty) { + throwToolExit( + 'Found duplicates in the code assets: ' + '${duplicateCodeAssetIds.toList()} while compiling for ' + '$targetStrings.', + ); + } +} + Future> installCodeAssets({ required DartHooksResult dartHookResult, required Map environmentDefines, diff --git a/packages/flutter_tools/lib/src/update_packages_pins.dart b/packages/flutter_tools/lib/src/update_packages_pins.dart index 7be7f8d7890ac..19fe93ac62ae3 100644 --- a/packages/flutter_tools/lib/src/update_packages_pins.dart +++ b/packages/flutter_tools/lib/src/update_packages_pins.dart @@ -24,7 +24,7 @@ const kManuallyPinnedDependencies = { 'flutter_gallery_assets': '1.0.2', // Tests depend on the exact version. 'flutter_template_images': '5.0.0', // Must always exactly match flutter_tools template. 'material_color_utilities': '0.13.0', // Keep pinned to latest until 1.0.0. - 'data_assets': '0.19.6', // Keep pinned to latest until 1.0.0. Rolled by @dcharkes. + 'data_assets': '0.20.0', // Keep pinned to latest until 1.0.0. Rolled by @dcharkes. 'record_use': '0.6.0', // Keep pinned to latest until 1.0.0. Rolled by @dcharkes. }; diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 4fdf0966f974e..475cee3f06341 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -57,10 +57,10 @@ dependencies: pubspec_parse: 1.5.0 graphs: 2.3.2 - hooks_runner: 1.2.1 - hooks: 1.0.3 - code_assets: 1.0.0 - data_assets: 0.19.6 + hooks_runner: 1.3.0 + hooks: 2.0.0 + code_assets: 1.1.0 + data_assets: 0.20.0 # We depend on very specific internal implementation details of the # 'test' package, which change between versions, so when upgrading @@ -127,4 +127,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: npmtr8 +# PUBSPEC CHECKSUM: vdpt2u diff --git a/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl b/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl index f9bb68dff1aa7..404f0e8844a0b 100644 --- a/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl +++ b/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl @@ -6,10 +6,10 @@ environment: sdk: {{dartSdkVersionBounds}} dependencies: - code_assets: ^1.0.0 - hooks: ^1.0.0 + code_assets: ^1.1.0 + hooks: ^2.0.0 logging: ^1.3.0 - native_toolchain_c: ^0.17.4 + native_toolchain_c: ^0.19.0 dev_dependencies: ffi: ^2.1.4 diff --git a/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart index 0b973fe35ef27..879276cddb958 100644 --- a/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart @@ -78,8 +78,14 @@ void main() { ]; final buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: ['bar'], - buildResult: FakeFlutterNativeAssetsBuilderResult.fromAssets(codeAssets: codeAssets), - linkResult: FakeFlutterNativeAssetsBuilderResult.fromAssets(codeAssets: codeAssets), + buildResult: buildMode == BuildMode.debug + ? FakeFlutterNativeAssetsBuilderResult.fromAssets(codeAssets: codeAssets) + : FakeFlutterNativeAssetsBuilderResult.fromAssets( + codeAssetsForLinking: >{'package:bar': codeAssets}, + ), + linkResult: buildMode == BuildMode.debug + ? null + : FakeFlutterNativeAssetsBuilderResult.fromAssets(codeAssets: codeAssets), ); final environmentDefines = { kBuildMode: buildMode.cliName, diff --git a/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart index 9b1795cc1eb20..6926e7ece5988 100644 --- a/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart @@ -250,6 +250,44 @@ void main() { }, ); + testUsingContext( + 'Native assets: duplicate assets throws tool exit listing duplicate IDs', + overrides: {ProcessManager: () => FakeProcessManager.empty()}, + () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + + final File directSoFile = environment.projectDir.childFile('direct.so'); + directSoFile.writeAsBytesSync([]); + + CodeAsset makeCodeAsset(String name, Uri file, LinkMode linkMode) => + CodeAsset(package: 'bar', name: name, linkMode: linkMode, file: file); + + expect( + () => runFlutterSpecificHooks( + environmentDefines: {kBuildMode: BuildMode.release.cliName}, + targetPlatform: TargetPlatform.linux_x64, + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeFlutterNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: ['bar'], + buildResult: FakeFlutterNativeAssetsBuilderResult.fromAssets( + codeAssets: [ + makeCodeAsset('direct', directSoFile.uri, DynamicLoadingBundled()), + makeCodeAsset('direct', directSoFile.uri, DynamicLoadingBundled()), + ], + ), + ), + buildCodeAssets: const BuildCodeAssetsOptions(appBuildDirectory: null), + buildDataAssets: true, + recordedUsesFile: null, + ), + throwsToolExit(message: 'Found duplicates in the code assets: [package:bar/direct]'), + ); + }, + ); + testUsingContext( 'unit tests does not require compiler toolchain', overrides: { diff --git a/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart index 22b5ba23cb168..2a9b8e5dc2f94 100644 --- a/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart @@ -86,7 +86,11 @@ void main() { ]; final buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: ['bar'], - buildResult: FakeFlutterNativeAssetsBuilderResult.fromAssets(codeAssets: codeAssets), + buildResult: buildMode == BuildMode.debug + ? FakeFlutterNativeAssetsBuilderResult.fromAssets(codeAssets: codeAssets) + : FakeFlutterNativeAssetsBuilderResult.fromAssets( + codeAssetsForLinking: >{'package:bar': codeAssets}, + ), linkResult: buildMode == BuildMode.debug ? null : FakeFlutterNativeAssetsBuilderResult.fromAssets(codeAssets: codeAssets), diff --git a/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_conflicting_assets_test.dart b/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_conflicting_assets_test.dart index 9f485e15b2d77..d43efccfa3fd5 100644 --- a/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_conflicting_assets_test.dart +++ b/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_conflicting_assets_test.dart @@ -46,7 +46,7 @@ void main() { ..update(['flutter', 'assets'], [assets.keys.first]) ..update( ['dependencies'], - {'hooks': '^1.0.2', 'data_assets': '^0.19.6'}, + {'hooks': '^2.0.0', 'data_assets': '^0.20.0'}, ); }); diff --git a/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_flutter_build_test.dart b/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_flutter_build_test.dart index 5664983cdc9ad..0ca503f8776c6 100644 --- a/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_flutter_build_test.dart +++ b/packages/flutter_tools/test/integration.shard/isolated/dart_data_asset_flutter_build_test.dart @@ -71,6 +71,45 @@ void main() { } } }); + + testWithoutContext( + 'flutter build $target rebuilds when data asset file is deleted', + () async { + final assets = {'id1.txt': 'content1'}; + writeAssets(assets, appRoot); + writeHookLibrary(appRoot, assets, available: ['id1.txt']); + writeHelperLibrary(appRoot, 'version1', assets.keys.toList()); + + ProcessTestResult result = await runFlutter( + ['build', '-v', target], + appRoot.path, + [Barrier.contains('Built build${Platform.pathSeparator}$target')], + ); + if (result.exitCode != 0) { + throw Exception( + 'first flutter build failed: ${result.exitCode}\n${result.stderr}\n${result.stdout}', + ); + } + + final File fileToDelete = dependencyRoot + .childDirectory('data') + .childFile('generated.txt'); + expect(fileToDelete.existsSync(), true); + fileToDelete.deleteSync(); + + // Second build should re-run the build_hooks target and succeed. + result = await runFlutter( + ['build', '-v', target], + appRoot.path, + [Barrier.contains('Built build${Platform.pathSeparator}$target')], + ); + if (result.exitCode != 0) { + throw Exception( + 'second flutter build failed: ${result.exitCode}\n${result.stderr}\n${result.stdout}', + ); + } + }, + ); } }); } diff --git a/pubspec.lock b/pubspec.lock index 01fa65203ef84..e36f442c7e5a8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -150,10 +150,10 @@ packages: dependency: "direct main" description: name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + sha256: dad6bf6b9f4f378b0a69edbf42584d336efd1a9ce15deb1ba591cbb1b5ff440f url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.1.0" code_builder: dependency: transitive description: @@ -255,10 +255,10 @@ packages: dependency: "direct main" description: name: data_assets - sha256: d8b93648a338f471e576e0ba05f6b5d63a4e0fa447ca839a500267421d9245ba + sha256: "8bfdbf25ec8a0f4b5a3c993042c4ab9996ba354f0b03d40f4e360f3730d71cae" url: "https://pub.dev" source: hosted - version: "0.19.6" + version: "0.20.0" dds: dependency: transitive description: @@ -502,18 +502,18 @@ packages: dependency: "direct main" description: name: hooks - sha256: "025f060e86d2d4c3c47b56e33caf7f93bf9283340f26d23424ebcfccf34f621e" + sha256: a41af4e8fc687cd6d33de9751eb936c8c0204ebe2bcb6c15ecf707504bf47f31 url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "2.0.0" hooks_runner: dependency: transitive description: name: hooks_runner - sha256: "248aaf6d687806959888be1bc0ab66bcf616c4f476e97cfc1b02cd97b8e06dd4" + sha256: b2545e50cc62b1cfcf4d94b3939a89776db72af342680d942ccad429720c4eb1 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" html: dependency: "direct main" description: @@ -718,10 +718,10 @@ packages: dependency: "direct main" description: name: native_toolchain_c - sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" + sha256: "49c147aa4a5905ec12028e2b7bfe360eace6cb91fe4cf08a3fe76e309592acae" url: "https://pub.dev" source: hosted - version: "0.17.6" + version: "0.19.0" nested: dependency: "direct main" description: @@ -742,10 +742,10 @@ packages: dependency: transitive description: name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" url: "https://pub.dev" source: hosted - version: "9.3.0" + version: "9.4.1" package_config: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 97b938f8080e8..00ca815783741 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -97,7 +97,7 @@ dependencies: checked_yaml: 2.0.4 cli_config: 0.2.0 clock: ^1.1.2 - code_assets: 1.0.0 + code_assets: 1.1.0 collection: ^1.19.1 convert: 3.1.2 coverage: 1.15.0 @@ -121,8 +121,8 @@ dependencies: google_mobile_ads: 8.0.0 googleapis: 14.0.0 googleapis_auth: 2.3.1 - hooks: 1.0.3 - data_assets: 0.19.6 + hooks: 2.0.0 + data_assets: 0.20.0 record_use: 0.6.0 html: 0.15.6 http: 1.6.0 @@ -142,7 +142,7 @@ dependencies: meta: ^1.18.2 metrics_center: 1.0.15 mime: 2.0.0 - native_toolchain_c: 0.17.6 + native_toolchain_c: 0.19.0 nested: 1.0.0 node_preamble: 2.0.2 package_config: 2.2.0 @@ -224,4 +224,4 @@ dependencies: dev_dependencies: ffigen: 20.1.1 -# PUBSPEC CHECKSUM: ntrh87 +# PUBSPEC CHECKSUM: 82uul6