| # Copyright 2022 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/group_with_inputs.gni") |
| |
| # Create a product assembly config file from the lists of packages and config |
| # passed into the template. |
| # |
| # This template specifically converts lists of labels for fuchsia_package() and |
| # prebuilt_package() into the lists of output paths needed. This keeps the |
| # contract about where those two templates place the package manifest internal |
| # to fuchsia.git. |
| # |
| # As outputs, this creates: |
| # |
| # outputs = [ |
| # "${target_out_dir}/${target_name}/product_assembly_config.json" |
| # ] |
| # |
| # |
| # Arguments: |
| # |
| # Product-specified Package Sets: |
| # These are optional lists of targets that produce Fuchsia Packages. These |
| # are NOT walked for metadata, but must be the exact desired package-creating |
| # targets. |
| # |
| # base_packages [optional] |
| # [list, GN targets] A list of GN targets that are the specific targets for |
| # the product-provided packages to place into the base set. |
| # |
| # cache_packages [optional] |
| # [list, GN targets] A list of GN targets that are the specific targets for |
| # the product-provided packages to place into the cache set. |
| # |
| # platform [optional] |
| # [scope] This is the platform configuration scope |
| # |
| # product [optional] |
| # [scope] This is the product configuration scope |
| # |
| # GN Usual: |
| # testonly |
| # visibility |
| template("product_assembly_configuration") { |
| labels = { |
| # So it can be reused. |
| target_name = target_name |
| |
| assembly_config = "${target_name}.product_assembly_config.json" |
| |
| # This is a publicly visible, test-only target, that allows the assembly |
| # config to be used without needing the deps used create it. |
| assembly_config_for_validation = |
| "${target_name}.product_assembly_config.json.for_validation" |
| |
| base_package_set = "${target_name}.base_packages" |
| cache_package_set = "${target_name}.cache_packages" |
| |
| # Base packages specified by the invoker, used to create the list of |
| # manifests and as the deps for the package set targets. |
| base_package_labels = [] |
| if (defined(invoker.base_packages)) { |
| base_package_labels += invoker.base_packages |
| } |
| |
| # Cache packages specified by the invoker, used to create the list of |
| # manifests and as the deps for the package set targets. |
| cache_package_labels = [] |
| if (defined(invoker.cache_packages)) { |
| cache_package_labels += invoker.cache_packages |
| } |
| } |
| |
| files = { |
| outdir = "$target_out_dir/$target_name" |
| assembly_config_file = "$outdir/product_assembly_config.json" |
| |
| # Compute the paths for the package manifests (as files). This is |
| # closely coupled with how fuchsia_package() and prebuilt_package() both |
| # create a package manifest from their label. |
| |
| base_package_manifests = [] |
| foreach(package_target, labels.base_package_labels) { |
| _package_out_dir = get_label_info(package_target, "target_out_dir") |
| _package_name = get_label_info(package_target, "name") |
| base_package_manifests += |
| [ "${_package_out_dir}/${_package_name}/package_manifest.json" ] |
| } |
| |
| cache_package_manifests = [] |
| foreach(package_target, labels.cache_package_labels) { |
| _package_out_dir = get_label_info(package_target, "target_out_dir") |
| _package_name = get_label_info(package_target, "name") |
| cache_package_manifests += |
| [ "${_package_out_dir}/${_package_name}/package_manifest.json" ] |
| } |
| } |
| |
| _assembly_config = { |
| # Create the platform configuration section from the caller's argument |
| platform = { |
| if (defined(invoker.platform)) { |
| forward_variables_from(invoker.platform, "*") |
| } |
| assert(defined(build_type), "The platform build-type must be specified.") |
| } |
| |
| # Create the product configuration section from the caller's arguments. |
| product = { |
| if (defined(invoker.product)) { |
| forward_variables_from(invoker.product, "*") |
| } |
| |
| # Create the packages.base and package.cache sets if they weren't passed |
| # in from the invoker. |
| if (!defined(packages)) { |
| packages = { |
| } |
| } |
| if (!defined(packages.base)) { |
| packages.base = [] |
| } |
| if (!defined(packages.cache)) { |
| packages.cache = [] |
| } |
| |
| packages.base += rebase_path(files.base_package_manifests, root_build_dir) |
| packages.cache += |
| rebase_path(files.cache_package_manifests, root_build_dir) |
| } |
| } |
| |
| # Generate the Product Assembly configuration file itself. |
| # |
| # This does _not_ have deps on any of the passed in targets, which is why it |
| # restricts it's visibility to the target that does dep on them. |
| # |
| generated_file(labels.assembly_config) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| visibility = [ |
| ":${labels.assembly_config_for_validation}", |
| ":${labels.target_name}", |
| ] |
| outputs = [ files.assembly_config_file ] |
| output_conversion = "json" |
| contents = _assembly_config |
| } |
| |
| # These are used to detect if the deps don't correspond to a set of input |
| # files (the deps can be larger than the set of files, but not the other way |
| # around). Since we're computing the manifest paths from the labels, if the |
| # label to something other than a package is added, we'll compute a manifest |
| # path that doesn't exist. This catches it here, instead of inside a build |
| # action which can't explain why it can't find a file. |
| |
| # Create a target for the base packages, so they appear in the dep graph |
| # as distinct from the cache packages, and validate that they produce all of |
| # the manifests whose paths were computed from the labels. |
| group_with_inputs(labels.base_package_set) { |
| inputs = files.base_package_manifests |
| deps = labels.base_package_labels |
| } |
| |
| # Create a target for the cache packages, so they appear in the dep graph |
| # as distinct from the cache packages, and validate that they produce all of |
| # the manifests whose paths were computed from the labels. |
| group_with_inputs(labels.cache_package_set) { |
| inputs = files.cache_package_manifests |
| deps = labels.cache_package_labels |
| } |
| |
| group(labels.target_name) { |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "public_deps", |
| "testonly", |
| "visibility", |
| ]) |
| if (!defined(public_deps)) { |
| public_deps = [] |
| } |
| public_deps += [ ":${labels.assembly_config}" ] |
| |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += [ |
| ":${labels.base_package_set}", |
| ":${labels.cache_package_set}", |
| ] |
| } |
| |
| # A testonly group with no visibilty restrictions, that allows the use of the |
| # generated product assembly config file in validation actions that don't |
| # require the existence of the packages and binaries that it points to. |
| group(labels.assembly_config_for_validation) { |
| testonly = true |
| public_deps = [ ":${labels.assembly_config}" ] |
| } |
| } |