blob: 641e3dd672c0e79dfe704edfaec6ac5be57a0481 [file] [log] [blame]
# Copyright 2020 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/packages/package_metadata.gni")
import("//build/packages/prebuilt_package.gni")
declare_args() {
# Used to configure the set of package flavors desired.
#
# Usage:
#
# package_flavor_selections = [
# {
# name = "snazzy"
# flavor = "with_hooks"
# },
# {
# name = "some_other_package"
# flavor = "some_other_flavor"
# },
# ]
#
# The above specifies that the package "snazzy" should use the
# "with_hooks" flavor, and that "some_other_package" should use
# the "some_other_flavor" flavor instead of their default flavor
# all other packages using this template would use their default
# package flavors.
package_flavor_selections = []
}
# Choose which flavor from a set of signed, sealed pre-built package files
# which all are mutually-exclusive implementations of a given package.
#
# This template produces a single GN label and package to publish in
# build output TUF repo.
#
# THIS SHOULD BE USED WITH CARE
#
# This template records metadata about which flavor was chosen, which
# can be used to generate build output manifests of the chosen flavors
#
# src/prebuilt/snazzy/BUILD.gn:
#
# prebuilt_package_with_flavors("snazzy") {
# default = "release"
# flavors = [
# {
# name = "release"
# archive = "some/path/to/snazzy/release"
# },
# {
# name = "with_hooks"
# archive = "some/path/to/snazzy/with_hooks"
# }
# ]
# package_flavor_selections
# }
#
# and the following in GN build args:
#
# package_flavor_selections = [
# {
# name = "snzzy"
# flavor = "with_hooks"
# },
#]
#
# will produce the following GN label:
# `//src/prebuilt/snazzy:snazzy`
#
# a package with the name `snazzy` and will use the archive at
# `some/path/to/snazzy/with_hooks` as the implementation for that
# package.
#
# Which package flavors were chosen is emitted in the build output, at
# $out_dir/prebuilt_package_flavor_selections.json. This is
# performed by the //:prebuilt_package_flavors build_api() target.
#
# Parameters
#
# default (required; string)
# The name of the default flavor to use if not overridden
# in `flavor_selections`
#
# flavors (required)
# A list of "flavor" definition scopes, each of which has:
# name (required)
# The name of the flavor
# archive (required)
# The path to this flavor's prebuilt archive
# production_safe (optional, boolean, default: false)
# If not set to true, the flavor is marked with
# //build/validate:non_production_tag
# deps (optional)
# Extra dependencies specific to this flavor.
#
# package_name (optional)
# Name of the prebuilt package, defaults to template's target name
#
# selections (optional; scope)
# The package_flavor_selections, if and only if the caller of the template
# has logic that attempts to change the flavor based on other build args.
# This is not the preferred mechanism, but may be used in some cases.
#
# deps (optional)
# testonly (optional)
# visibility (optional)
# Usual GN meanings.
#
template("prebuilt_package_with_flavors") {
pkg_name = target_name
# Start with the default value
assert(defined(invoker.default), "A default flavor must be specified")
flavor_name_to_use = invoker.default
# If the invoker has modified and passed-in the package_flavor_selections
# list, use that instead of the one from GN args.
if (defined(invoker.selections)) {
flavor_selections = invoker.selections
} else {
flavor_selections = package_flavor_selections
}
# Since we can't index into a scope by a variable, flavor_selections is a list
# that's walked, looking for an entry that matches this invocation of the
# template. If multiple entries in the list match, the last one wins
# (which is the same result as if it was key=value pairs in a scope).
foreach(selection, flavor_selections) {
assert(defined(selection.name),
"package flavor selections need to have a `name`")
assert(
defined(selection.flavor),
"package flavor selection for ${selection.name} doesn't have a `flavor`")
if (selection.name == pkg_name) {
flavor_name_to_use = selection.flavor
}
}
# This is used to track all the flavor names for error printing
all_names = []
# Find the selected flavor in the list of possible flavors
foreach(flavor, invoker.flavors) {
assert(defined(flavor.name), "all package flavors must be named")
assert(defined(flavor.archive),
"${flavor.name} does not define an archive to use")
all_names += [ flavor.name ]
if (flavor_name_to_use == flavor.name) {
flavor_to_use = flavor
}
}
assert(
defined(flavor_to_use),
"The chosen flavor: '${flavor_name_to_use}', is not a valid flavor: ${all_names}")
# Default all prebuilts to not "production-safe" unless they explicitly are set to true
production_safe = false
if (defined(flavor_to_use.production_safe)) {
production_safe = flavor_to_use.production_safe
}
# Invoke the prebuilt_package template with the chosen flavor.
prebuilt_package(pkg_name) {
archive = flavor_to_use.archive
forward_variables_from(invoker,
[
"deps",
"testonly",
"visibility",
"package_name",
"repository",
])
# setup the non-production-safe status of the package
if (!production_safe) {
if (!defined(deps)) {
deps = []
}
# Mark as not safe for production use.
deps += [ "//build/validate:non_production_tag" ]
}
if (defined(flavor_to_use.deps)) {
if (!defined(deps)) {
deps = []
}
# Add flavor-specific dependencies.
deps += flavor_to_use.deps
}
# Set up the metadata to track which flavor is being used.
metadata = {
prebuilt_package_with_flavors = [
{
package = pkg_name
# This also passes any other fields set on the scope for the flavor,
# so that it can additionally be captured in the metadata manifest.
forward_variables_from(flavor_to_use, "*")
},
]
}
}
}