diff --git a/.github/labeler.yml b/.github/labeler.yml index a6ad7f620776..8e044f9e4505 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -38,6 +38,11 @@ - any-glob-to-any-file: - packages/file_selector/**/* +'p: flutter_hook_config': + - changed-files: + - any-glob-to-any-file: + - packages/flutter_hook_config/**/* + 'p: flutter_lints': - changed-files: - any-glob-to-any-file: diff --git a/README.md b/README.md index b499d7543344..132d16972cd2 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ These are the packages hosted in this repository: | [espresso](./packages/espresso/) | [![pub package](https://img.shields.io/pub/v/espresso.svg)](https://pub.dev/packages/espresso) | [![pub points](https://img.shields.io/pub/points/espresso)](https://pub.dev/packages/espresso/score) | [![downloads](https://img.shields.io/pub/dm/espresso)](https://pub.dev/packages/espresso/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20espresso?label=)](https://github.com/flutter/flutter/labels/p%3A%20espresso) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20espresso?label=)](https://github.com/flutter/packages/labels/p%3A%20espresso) | | [extension\_google\_sign\_in\_as\_googleapis\_auth](./packages/extension_google_sign_in_as_googleapis_auth/) | [![pub package](https://img.shields.io/pub/v/extension_google_sign_in_as_googleapis_auth.svg)](https://pub.dev/packages/extension_google_sign_in_as_googleapis_auth) | [![pub points](https://img.shields.io/pub/points/extension_google_sign_in_as_googleapis_auth)](https://pub.dev/packages/extension_google_sign_in_as_googleapis_auth/score) | [![downloads](https://img.shields.io/pub/dm/extension_google_sign_in_as_googleapis_auth)](https://pub.dev/packages/extension_google_sign_in_as_googleapis_auth/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20extension_google_sign_in_as_googleapis_auth?label=)](https://github.com/flutter/flutter/labels/p%3A%20extension_google_sign_in_as_googleapis_auth) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20extension_google_sign_in_as_googleapis_auth?label=)](https://github.com/flutter/packages/labels/p%3A%20extension_google_sign_in_as_googleapis_auth) | | [file\_selector](./packages/file_selector/) | [![pub package](https://img.shields.io/pub/v/file_selector.svg)](https://pub.dev/packages/file_selector) | [![pub points](https://img.shields.io/pub/points/file_selector)](https://pub.dev/packages/file_selector/score) | [![downloads](https://img.shields.io/pub/dm/file_selector)](https://pub.dev/packages/file_selector/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20file_selector?label=)](https://github.com/flutter/flutter/labels/p%3A%20file_selector) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20file_selector?label=)](https://github.com/flutter/packages/labels/p%3A%20file_selector) | +| [flutter\_hook\_config](./packages/flutter_hook_config/) | [![pub package](https://img.shields.io/pub/v/flutter_hook_config.svg)](https://pub.dev/packages/flutter_hook_config) | [![pub points](https://img.shields.io/pub/points/flutter_hook_config)](https://pub.dev/packages/flutter_hook_config/score) | [![downloads](https://img.shields.io/pub/dm/flutter_hook_config)](https://pub.dev/packages/flutter_hook_config/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20flutter_hook_config?label=)](https://github.com/flutter/flutter/labels/p%3A%20flutter_hook_config) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20flutter_hook_config?label=)](https://github.com/flutter/packages/labels/p%3A%20flutter_hook_config) | | [flutter\_lints](./packages/flutter_lints/) | [![pub package](https://img.shields.io/pub/v/flutter_lints.svg)](https://pub.dev/packages/flutter_lints) | [![pub points](https://img.shields.io/pub/points/flutter_lints)](https://pub.dev/packages/flutter_lints/score) | [![downloads](https://img.shields.io/pub/dm/flutter_lints)](https://pub.dev/packages/flutter_lints/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20flutter_lints?label=)](https://github.com/flutter/flutter/labels/p%3A%20flutter_lints) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20flutter_lints?label=)](https://github.com/flutter/packages/labels/p%3A%20flutter_lints) | | [flutter\_plugin\_android\_lifecycle](./packages/flutter_plugin_android_lifecycle/) | [![pub package](https://img.shields.io/pub/v/flutter_plugin_android_lifecycle.svg)](https://pub.dev/packages/flutter_plugin_android_lifecycle) | [![pub points](https://img.shields.io/pub/points/flutter_plugin_android_lifecycle)](https://pub.dev/packages/flutter_plugin_android_lifecycle/score) | [![downloads](https://img.shields.io/pub/dm/flutter_plugin_android_lifecycle)](https://pub.dev/packages/flutter_plugin_android_lifecycle/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20flutter_plugin_android_lifecycle?label=)](https://github.com/flutter/flutter/labels/p%3A%20flutter_plugin_android_lifecycle) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20flutter_plugin_android_lifecycle?label=)](https://github.com/flutter/packages/labels/p%3A%20flutter_plugin_android_lifecycle) | | [flutter\_svg](./third_party/packages/flutter_svg/) | [![pub package](https://img.shields.io/pub/v/flutter_svg.svg)](https://pub.dev/packages/flutter_svg) | [![pub points](https://img.shields.io/pub/points/flutter_svg)](https://pub.dev/packages/flutter_svg/score) | [![downloads](https://img.shields.io/pub/dm/flutter_svg)](https://pub.dev/packages/flutter_svg/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20flutter_svg?label=)](https://github.com/flutter/flutter/labels/p%3A%20flutter_svg) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/packages/p%3A%20flutter_svg?label=)](https://github.com/flutter/packages/labels/p%3A%20flutter_svg) | diff --git a/SUGGESTED_REVIEWERS.md b/SUGGESTED_REVIEWERS.md index ad9a954e7683..b4d0732111e0 100644 --- a/SUGGESTED_REVIEWERS.md +++ b/SUGGESTED_REVIEWERS.md @@ -38,6 +38,10 @@ reviewed by someone else. - **Web**: @mdebbar - **Windows**: @stuartmorgan-g +`flutter_hook_config`: + - @bdero + - @dcharkes + `flutter_lints`: - @chunhtai diff --git a/packages/flutter_hook_config/.gitignore b/packages/flutter_hook_config/.gitignore new file mode 100644 index 000000000000..9331cd4f4f0a --- /dev/null +++ b/packages/flutter_hook_config/.gitignore @@ -0,0 +1,6 @@ +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/packages/flutter_hook_config/AUTHORS b/packages/flutter_hook_config/AUTHORS new file mode 100644 index 000000000000..557dff97933b --- /dev/null +++ b/packages/flutter_hook_config/AUTHORS @@ -0,0 +1,6 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. diff --git a/packages/flutter_hook_config/CHANGELOG.md b/packages/flutter_hook_config/CHANGELOG.md new file mode 100644 index 000000000000..253adf5216e2 --- /dev/null +++ b/packages/flutter_hook_config/CHANGELOG.md @@ -0,0 +1,6 @@ +## 0.1.0 + +* Initial release of `flutter_hook_config`: a `package:hooks` protocol extension + that lets the Flutter SDK expose engine host-tool paths (`impellerc`, + `libtessellator`) to build and link hooks, including the `--local-engine` + override. diff --git a/packages/flutter_hook_config/LICENSE b/packages/flutter_hook_config/LICENSE new file mode 100644 index 000000000000..29b709dac6c7 --- /dev/null +++ b/packages/flutter_hook_config/LICENSE @@ -0,0 +1,25 @@ +Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/flutter_hook_config/README.md b/packages/flutter_hook_config/README.md new file mode 100644 index 000000000000..1e8f44f4fec7 --- /dev/null +++ b/packages/flutter_hook_config/README.md @@ -0,0 +1,35 @@ +# flutter_hook_config + +A [`package:hooks`](https://pub.dev/packages/hooks) protocol extension that lets +the Flutter SDK pass Flutter-specific configuration to build and link hooks in a +typed way. + +Today it exposes the absolute paths of the engine host tools a hook might need: + +* `impellerc`, the offline shader compiler (used, for example, by + `flutter_gpu_shaders` to compile `.shaderbundle.json` files). +* `libtessellator`, the tessellation library. + +The Flutter SDK (`flutter_tools`) resolves these through the same artifact +lookup it uses for its own build steps, so under `--local-engine` a hook gets +the locally built tools, matching the engine the app is being built against, +instead of the ones in the SDK cache. + +## For hook authors + +Add `flutter_hook_config` to your hook's dependencies and read the config from +the `BuildInput` / `LinkInput` via `input.config.flutter`. Always check +`input.config.buildForFlutter` first: a hook may also be invoked by a plain +`dart` build, or by a Flutter SDK that predates this extension, in which case no +Flutter-specific config is available and you should fall back to your own tool +discovery. + +See the [library documentation](https://pub.dev/documentation/flutter_hook_config/latest/) +for a usage example. + +## For the Flutter SDK + +`flutter_tools` constructs a `FlutterExtension` (populated from +`Artifacts.getHostArtifact(...)`) and passes it to the hook runner alongside the +other protocol extensions (`CodeAssetExtension`, `DataAssetsExtension`), so the +configuration above becomes available to every build and link hook. diff --git a/packages/flutter_hook_config/dart_test.yaml b/packages/flutter_hook_config/dart_test.yaml new file mode 100644 index 000000000000..9929e621be12 --- /dev/null +++ b/packages/flutter_hook_config/dart_test.yaml @@ -0,0 +1,3 @@ +# The tests use `dart:io` to construct absolute file paths, and build hooks +# themselves only run on the Dart VM, so there is no need to run on the web. +test_on: vm diff --git a/packages/flutter_hook_config/lib/flutter_hook_config.dart b/packages/flutter_hook_config/lib/flutter_hook_config.dart new file mode 100644 index 000000000000..002c7002699b --- /dev/null +++ b/packages/flutter_hook_config/lib/flutter_hook_config.dart @@ -0,0 +1,31 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// A `package:hooks` protocol extension that exposes Flutter engine host-tool +/// paths (such as `impellerc` and `libtessellator`) to build and link hooks. +/// +/// Hook authors read the injected configuration via [HookConfigFlutterConfig], +/// checking [HookConfigFlutterConfig.buildForFlutter] first: +/// +/// ```dart +/// import 'package:flutter_hook_config/flutter_hook_config.dart'; +/// import 'package:hooks/hooks.dart'; +/// +/// void main(List args) async { +/// await build(args, (input, output) async { +/// if (input.config.buildForFlutter) { +/// final impellerc = input.config.flutter.impellerc; +/// // ... invoke impellerc ... +/// } +/// }); +/// } +/// ``` +/// +/// The Flutter SDK (`flutter_tools`) populates the configuration by passing a +/// [FlutterExtension] to the hook runner. +library; + +export 'src/config.dart' + show FlutterConfig, HookConfigBuilderFlutterConfig, HookConfigFlutterConfig; +export 'src/extension.dart' show FlutterExtension; diff --git a/packages/flutter_hook_config/lib/src/config.dart b/packages/flutter_hook_config/lib/src/config.dart new file mode 100644 index 000000000000..c493abbdb063 --- /dev/null +++ b/packages/flutter_hook_config/lib/src/config.dart @@ -0,0 +1,147 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:hooks/hooks.dart'; + +/// The hook config field that holds protocol-extension namespaces. +const String _extensionsKey = 'extensions'; + +/// The key under which Flutter-specific configuration is stored inside the hook +/// config's [_extensionsKey] map. +const String _flutterExtensionKey = 'flutter'; + +const String _engineVersionKey = 'engine_version'; +const String _impellercKey = 'impellerc'; +const String _libtessellatorKey = 'libtessellator'; + +/// Flutter-specific configuration supplied to a build or link hook. +/// +/// Obtained via [HookConfigFlutterConfig.flutter]. Only available when the hook +/// is invoked by a Flutter SDK that supports this extension; check +/// [HookConfigFlutterConfig.buildForFlutter] before accessing it. +/// +/// `hooks_runner` keys the hook cache on the contents of this config, so +/// changes to any field here invalidate the cache and force the hook to be +/// re-run. In particular, [engineVersion] changes whenever the Flutter SDK is +/// upgraded, which is what causes hooks consuming engine host tools (such as +/// `impellerc`) to re-run with the new binaries even though [impellerc] and +/// [libtessellator] point at the same paths. +final class FlutterConfig { + FlutterConfig._(this._json); + + final Map _json; + + /// An opaque identifier for the Flutter engine the invoking SDK targets. + /// + /// This is the Flutter engine revision under a normal `flutter` invocation, + /// or a stable identifier derived from the local engine output directory + /// under `--local-engine`. Treat the value as opaque: it is only meaningful + /// for equality comparison and for ensuring that a different Flutter SDK + /// produces a different value (so that the hook cache invalidates). + String get engineVersion => _string(_engineVersionKey); + + /// The absolute path to the `impellerc` offline shader compiler that ships + /// with the engine artifacts of the invoking Flutter SDK. + /// + /// When the SDK is invoked with `--local-engine`, this points at the locally + /// built `impellerc`, matching the engine the app is being built against. + Uri get impellerc => _filePath(_impellercKey); + + /// The absolute path to the `libtessellator` dynamic library that ships with + /// the engine artifacts of the invoking Flutter SDK. + /// + /// When the SDK is invoked with `--local-engine`, this points at the locally + /// built `libtessellator`. + Uri get libtessellator => _filePath(_libtessellatorKey); + + Uri _filePath(String key) => Uri.file(_string(key)); + + String _string(String key) { + final Object? value = _json[key]; + if (value is! String) { + throw FormatException( + 'Expected a String at ' + "'config.$_extensionsKey.$_flutterExtensionKey.$key' in the hook " + 'input, got: $value', + ); + } + return value; + } +} + +/// Extension on [HookConfig] providing access to Flutter-specific +/// configuration. +extension HookConfigFlutterConfig on HookConfig { + /// Whether this hook is being invoked as part of a Flutter build. + /// + /// When `false`, the hook is being invoked by a plain `dart` build, or by a + /// Flutter SDK that predates the `flutter_hook_config` extension, and + /// [flutter] must not be accessed. Hooks that need Flutter-supplied + /// configuration should fall back to their own discovery logic in that case. + bool get buildForFlutter => _flutterExtensionJson != null; + + /// The Flutter-specific configuration for this hook invocation. + /// + /// Only valid when [buildForFlutter] is `true`; throws a [StateError] + /// otherwise. + FlutterConfig get flutter { + final Map? extensionJson = _flutterExtensionJson; + if (extensionJson == null) { + throw StateError( + 'No Flutter-specific hook configuration is available. The hook is not ' + 'being invoked by a Flutter SDK, or the Flutter SDK predates ' + 'flutter_hook_config support. Check `config.buildForFlutter` first.', + ); + } + return FlutterConfig._(extensionJson); + } + + Map? get _flutterExtensionJson { + final Object? extensions = json[_extensionsKey]; + if (extensions is! Map) { + return null; + } + final Object? flutterJson = extensions[_flutterExtensionKey]; + return flutterJson is Map ? flutterJson : null; + } +} + +/// Extension on [HookConfigBuilder] for writing Flutter-specific configuration +/// onto a hook input. +/// +/// This is intended for use by the Flutter SDK (`flutter_tools`) via +/// [FlutterExtension]; ordinary hook authors do not call this directly. +extension HookConfigBuilderFlutterConfig on HookConfigBuilder { + /// Records the Flutter-specific configuration on a build or link hook input. + /// + /// [engineVersion] is an opaque identifier that must change whenever any + /// engine artifact exposed here can change (typically the engine revision + /// for a stock SDK; a stable identifier for the local engine output + /// directory under `--local-engine`). Surfacing it as part of the config + /// ensures the hook cache invalidates when the Flutter SDK is upgraded. + /// + /// [impellerc] and [libtessellator] must be absolute file URIs. + void setupFlutter({ + required String engineVersion, + required Uri impellerc, + required Uri libtessellator, + }) { + assert(engineVersion.isNotEmpty, 'engineVersion must not be empty'); + assert( + impellerc.isAbsolute && impellerc.isScheme('file'), + 'impellerc must be an absolute file URI', + ); + assert( + libtessellator.isAbsolute && libtessellator.isScheme('file'), + 'libtessellator must be an absolute file URI', + ); + final extensions = + (json[_extensionsKey] ??= {}) as Map; + extensions[_flutterExtensionKey] = { + _engineVersionKey: engineVersion, + _impellercKey: impellerc.toFilePath(), + _libtessellatorKey: libtessellator.toFilePath(), + }; + } +} diff --git a/packages/flutter_hook_config/lib/src/extension.dart b/packages/flutter_hook_config/lib/src/extension.dart new file mode 100644 index 000000000000..a0011dc8ea95 --- /dev/null +++ b/packages/flutter_hook_config/lib/src/extension.dart @@ -0,0 +1,80 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:hooks/hooks.dart'; + +import 'config.dart'; + +/// A [ProtocolExtension] that supplies Flutter-specific configuration to build +/// and link hooks. +/// +/// This is constructed by the Flutter SDK (`flutter_tools`) and passed to the +/// hook runner alongside the other protocol extensions. Hook authors consume +/// the data it injects via [HookConfigFlutterConfig.flutter] rather than using +/// this class directly. +final class FlutterExtension implements ProtocolExtension { + /// Creates a [FlutterExtension]. + /// + /// [engineVersion] is an opaque identifier that must change whenever any of + /// the exposed engine artifacts can change (typically the Flutter engine + /// revision; a stable identifier for the local engine output directory under + /// `--local-engine`). It is what causes hook caches to invalidate when the + /// Flutter SDK is upgraded. + /// + /// [impellerc] and [libtessellator] must be absolute file URIs pointing at + /// the corresponding engine host tools. + FlutterExtension({ + required this.engineVersion, + required this.impellerc, + required this.libtessellator, + }); + + /// An opaque identifier for the Flutter engine the invoking SDK targets. + final String engineVersion; + + /// The absolute path to the `impellerc` offline shader compiler. + final Uri impellerc; + + /// The absolute path to the `libtessellator` dynamic library. + final Uri libtessellator; + + void _setup(HookConfigBuilder config) => config.setupFlutter( + engineVersion: engineVersion, + impellerc: impellerc, + libtessellator: libtessellator, + ); + + @override + void setupBuildInput(BuildInputBuilder input) => _setup(input.config); + + @override + void setupLinkInput(LinkInputBuilder input) => _setup(input.config); + + @override + Future validateBuildInput(BuildInput input) async => + const []; + + @override + Future validateLinkInput(LinkInput input) async => + const []; + + @override + Future validateBuildOutput( + BuildInput input, + BuildOutput output, + ) async => const []; + + @override + Future validateLinkOutput( + LinkInput input, + LinkOutput output, + ) async => const []; + + @override + Future validateApplicationAssets( + List assets, + ) async => const []; +} diff --git a/packages/flutter_hook_config/pubspec.yaml b/packages/flutter_hook_config/pubspec.yaml new file mode 100644 index 000000000000..27a3485eb8cd --- /dev/null +++ b/packages/flutter_hook_config/pubspec.yaml @@ -0,0 +1,21 @@ +name: flutter_hook_config +description: >- + A package:hooks protocol extension that exposes Flutter engine host-tool + paths (such as impellerc) to build and link hooks. +version: 0.1.0 +repository: https://github.com/flutter/packages/tree/main/packages/flutter_hook_config +issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A%20flutter_hook_config%22 + +environment: + sdk: ^3.9.0 + +dependencies: + hooks: ^1.0.0 + +dev_dependencies: + test: ^1.25.0 + +topics: + - hooks + - build + - native-assets diff --git a/packages/flutter_hook_config/test/flutter_hook_config_test.dart b/packages/flutter_hook_config/test/flutter_hook_config_test.dart new file mode 100644 index 000000000000..4798c1275296 --- /dev/null +++ b/packages/flutter_hook_config/test/flutter_hook_config_test.dart @@ -0,0 +1,99 @@ +// Copyright 2013 The Flutter Authors +// 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:flutter_hook_config/flutter_hook_config.dart'; +import 'package:hooks/hooks.dart'; +import 'package:test/test.dart'; + +void main() { + // Absolute, OS-correct URIs so the file-path encoding round-trips on every + // platform CI runs on. + final Uri engineArtifactsDir = Directory.systemTemp.uri.resolve( + 'flutter_hook_config_test/engine/', + ); + final Uri impellerc = engineArtifactsDir.resolve('impellerc'); + final Uri libtessellator = engineArtifactsDir.resolve('libtessellator'); + const engineVersion = 'a1b2c3d4e5'; + + BuildInput buildInput({List extensions = const []}) { + final builder = BuildInputBuilder() + ..setupShared( + packageRoot: Directory.systemTemp.uri.resolve('pkg/'), + packageName: 'example', + outputFile: Directory.systemTemp.uri.resolve('out/output.json'), + outputDirectoryShared: Directory.systemTemp.uri.resolve('out/shared/'), + ) + ..setupBuildInput() + ..config.setupBuild(linkingEnabled: false); + extensions.forEach(builder.addExtension); + return builder.build(); + } + + test('FlutterExtension injects impellerc and libtessellator', () { + final BuildInput input = buildInput( + extensions: [ + FlutterExtension( + engineVersion: engineVersion, + impellerc: impellerc, + libtessellator: libtessellator, + ), + ], + ); + + expect(input.config.buildForFlutter, isTrue); + expect(input.config.flutter.engineVersion, equals(engineVersion)); + expect(input.config.flutter.impellerc, equals(impellerc)); + expect(input.config.flutter.libtessellator, equals(libtessellator)); + }); + + test('buildForFlutter is false and flutter throws when the extension is ' + 'absent', () { + final BuildInput input = buildInput(); + + expect(input.config.buildForFlutter, isFalse); + expect(() => input.config.flutter, throwsStateError); + }); + + test('configuration round-trips through JSON', () { + final BuildInput input = buildInput( + extensions: [ + FlutterExtension( + engineVersion: engineVersion, + impellerc: impellerc, + libtessellator: libtessellator, + ), + ], + ); + + final roundTripped = BuildInput(Map.from(input.json)); + + expect(roundTripped.config.buildForFlutter, isTrue); + expect(roundTripped.config.flutter.engineVersion, equals(engineVersion)); + expect(roundTripped.config.flutter.impellerc, equals(impellerc)); + expect(roundTripped.config.flutter.libtessellator, equals(libtessellator)); + }); + + test('engineVersion participates in the hook config JSON', () { + BuildInput buildWithVersion(String version) => buildInput( + extensions: [ + FlutterExtension( + engineVersion: version, + impellerc: impellerc, + libtessellator: libtessellator, + ), + ], + ); + + final BuildInput a = buildWithVersion('engine-rev-A'); + final BuildInput b = buildWithVersion('engine-rev-B'); + + expect( + a.config.flutter.engineVersion, + isNot(equals(b.config.flutter.engineVersion)), + ); + expect(a.json, isNot(equals(b.json))); + }); +} diff --git a/script/configs/allowed_unpinned_deps.yaml b/script/configs/allowed_unpinned_deps.yaml index d5384884c993..ef0b7b003a85 100644 --- a/script/configs/allowed_unpinned_deps.yaml +++ b/script/configs/allowed_unpinned_deps.yaml @@ -38,6 +38,7 @@ - file_testing - gcloud - graphs +- hooks - html - http - intl