blob: c1fe3b2a0e7488aa09336f55f03db6940d64643a [file] [log] [blame]
# 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.
"""Rule for declaring a Fuchsia product configuration."""
load("//fuchsia/private:fuchsia_package.bzl", "get_driver_component_manifests")
load("//fuchsia/private:providers.bzl", "FuchsiaPackageInfo")
# buildifier: disable=module-docstring
load(
":providers.bzl",
"FuchsiaAssembledPackageInfo",
"FuchsiaOmahaOtaConfigInfo",
"FuchsiaProductConfigInfo",
)
load(":util.bzl", "extract_labels", "replace_labels_with_files")
# Define build types
BUILD_TYPES = struct(
ENG = "eng",
USER = "user",
USER_DEBUG = "userdebug",
)
# Define input device types option
INPUT_DEVICE_TYPE = struct(
BUTTON = "button",
KEYBOARD = "keyboard",
MOUSE = "mouse",
TOUCHSCREEN = "touchscreen",
)
def _create_pkg_detail(dep):
if FuchsiaPackageInfo in dep:
return {"manifest": dep[FuchsiaPackageInfo].package_manifest.path}
package = dep[FuchsiaAssembledPackageInfo].package
configs = dep[FuchsiaAssembledPackageInfo].configs
config_data = []
for config in configs:
config_data.append(
{
"destination": config.destination,
"source": config.source.path,
},
)
return {"manifest": package.package_manifest.path, "config_data": config_data}
def _collect_file_deps(dep):
if FuchsiaPackageInfo in dep:
return dep[FuchsiaPackageInfo].files
return dep[FuchsiaAssembledPackageInfo].files
def _fuchsia_product_configuration_impl(ctx):
product_config = json.decode(ctx.attr.product_config)
product_config_file = ctx.actions.declare_file(ctx.label.name + "_product_config.json")
if (ctx.attr.relative_paths):
# Relativize paths in the product config relative to the directory
# containing the product config
replace_labels_with_files(product_config, ctx.attr.product_config_labels, relative = product_config_file.dirname)
else:
# Use absolute paths
replace_labels_with_files(product_config, ctx.attr.product_config_labels)
platform = product_config.get("platform", {})
build_type = platform.get("build_type")
product = product_config.get("product", {})
packages = {}
output_files = []
base_pkg_details = []
for dep in ctx.attr.base_packages:
base_pkg_details.append(_create_pkg_detail(dep))
output_files += _collect_file_deps(dep)
packages["base"] = base_pkg_details
cache_pkg_details = []
for dep in ctx.attr.cache_packages:
cache_pkg_details.append(_create_pkg_detail(dep))
output_files += _collect_file_deps(dep)
packages["cache"] = cache_pkg_details
product["packages"] = packages
base_driver_details = []
for dep in ctx.attr.base_driver_packages:
base_driver_details.append(
{
"package": dep[FuchsiaPackageInfo].package_manifest.path,
"components": get_driver_component_manifests(dep),
},
)
output_files += _collect_file_deps(dep)
product["base_drivers"] = base_driver_details
product_config["product"] = product
if ctx.attr.ota_configuration:
swd_config = product_config["platform"].setdefault("software_delivery", {})
update_checker_config = swd_config.setdefault("update_checker", {})
omaha_config = update_checker_config.setdefault("omaha_client", {})
ota_config_info = ctx.attr.ota_configuration[FuchsiaOmahaOtaConfigInfo]
channels_file = ctx.actions.declare_file("channel_config.json")
ctx.actions.write(channels_file, ota_config_info.channels)
output_files.append(channels_file)
omaha_config["channels_path"] = channels_file.path
tuf_config_paths = []
for (hostname, repo_config) in ota_config_info.tuf_repositories.items():
repo_config_file = ctx.actions.declare_file(hostname + ".json")
ctx.actions.write(repo_config_file, repo_config)
tuf_config_paths.append(repo_config_file.path)
output_files.append(repo_config_file)
swd_config["tuf_config_paths"] = tuf_config_paths
content = json.encode_indent(product_config, indent = " ")
ctx.actions.write(product_config_file, content)
output_files.append(product_config_file)
return [
DefaultInfo(files = depset(direct = output_files + ctx.files.product_config_labels + ctx.files.deps)),
FuchsiaProductConfigInfo(
product_config = product_config_file,
build_type = build_type,
),
]
_fuchsia_product_configuration = rule(
doc = """Generates a product configuration file.""",
implementation = _fuchsia_product_configuration_impl,
toolchains = ["@fuchsia_sdk//fuchsia:toolchain"],
attrs = {
"product_config": attr.string(
doc = "Raw json config. Used as a base template for the config.",
default = "{}",
),
"product_config_labels": attr.label_keyed_string_dict(
doc = "Map of labels in the raw json config to LABEL(label) strings. Labels in the raw json config are replaced by file paths identified by their corresponding values in this dict.",
allow_files = True,
default = {},
),
"base_packages": attr.label_list(
doc = "Fuchsia packages to be included in base.",
providers = [
[FuchsiaAssembledPackageInfo],
[FuchsiaPackageInfo],
],
default = [],
),
"cache_packages": attr.label_list(
doc = "Fuchsia packages to be included in cache.",
providers = [
[FuchsiaAssembledPackageInfo],
[FuchsiaPackageInfo],
],
default = [],
),
"base_driver_packages": attr.label_list(
doc = "Base-driver packages to include in product.",
providers = [FuchsiaPackageInfo],
default = [],
),
"ota_configuration": attr.label(
doc = "OTA configuration to include in the product. Only for use with products that use Omaha.",
providers = [FuchsiaOmahaOtaConfigInfo],
),
"relative_paths": attr.bool(
doc = "Whether to generate an Assembly product configuration with relative path, so it can be relocated.",
default = False,
),
"deps": attr.label_list(
doc = "Additional dependencies that must be built before this target is built.",
default = [],
),
},
)
def fuchsia_product_configuration(
name,
product_config_json = None,
base_packages = None,
cache_packages = None,
base_driver_packages = None,
ota_configuration = None,
relative_paths = False,
**kwarg):
"""A new implementation of fuchsia_product_configuration that takes raw a json config.
Args:
name: Name of the rule.
TODO(https://fxbug.dev/42073826): Point to document instead of Rust definition
product_config_json: product assembly json config, as a starlark dictionary.
Format of this JSON config can be found in this Rust definitions:
//src/lib/assembly/config_schema/src/assembly_config.rs
Key values that take file paths should be declared as a string with
the label path wrapped via "LABEL(" prefix and ")" suffix. For
example:
```
{
"platform": {
"some_file": "LABEL(//path/to/file)",
},
},
```
All assembly json inputs are supported, except for product.packages
and product.base_drivers, which must be
specified through the following args.
base_packages: Fuchsia packages to be included in base.
cache_packages: Fuchsia packages to be included in cache.
base_driver_packages: Base driver packages to include in product.
ota_configuration: OTA configuration to use with the product.
**kwarg: Common bazel rule args passed through to the implementation rule.
"""
json_config = product_config_json
if not product_config_json:
json_config = {}
if type(json_config) != "dict":
fail("expecting a dictionary")
_fuchsia_product_configuration(
name = name,
product_config = json.encode_indent(json_config, indent = " "),
product_config_labels = extract_labels(json_config),
base_packages = base_packages,
cache_packages = cache_packages,
base_driver_packages = base_driver_packages,
ota_configuration = ota_configuration,
relative_paths = False,
**kwarg
)