platform_build/core/release_config.scl
LaMont Jones 979c1bdfc4 release_config: cleanup how default values are used
Set the flag value to the default value, rather than waiting until the
end to check if it was set anywhere.

This matters when the flag is declared `appends=True`.

Bug: none
Test: manual
Ignore-AOSP-First: Will CP, testing on internal first.
Change-Id: I8384cf8e0e0caedb5fb5a343f8be23f37bf4dc87
Merged-In: I8384cf8e0e0caedb5fb5a343f8be23f37bf4dc87
2024-03-28 22:42:36 +00:00

243 lines
7.6 KiB
Text

# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Export build flags (with values) to make.
"""
load("//build/bazel/utils:schema_validation.scl", "validate")
# Partitions that get build system flag summaries
_flag_partitions = [
"product",
"system",
"system_ext",
"vendor",
]
ALL = ["all"]
PRODUCT = ["product"]
SYSTEM = ["system"]
SYSTEM_EXT = ["system_ext"]
VENDOR = ["vendor"]
_valid_types = ["NoneType", "bool", "list", "string", "int"]
_all_flags_schema = {
"type": "list",
"of": {
"type": "dict",
"required_keys": {
"name": {"type": "string"},
"partitions": {
"type": "list",
"of": {
"type": "string",
"choices": _flag_partitions + ["all"],
},
"unique": True,
},
"default": {
"or": [
{"type": t}
for t in _valid_types
],
},
"origin": {"type": "string"},
"declared_in": {"type": "string"},
},
"optional_keys": {
"appends": {
"type": "bool",
},
},
},
}
_all_values_schema = {
"type": "list",
"of": {
"type": "dict",
"required_keys": {
"name": {"type": "string"},
"value": {
"or": [
{"type": t}
for t in _valid_types
],
},
"set_in": {"type": "string"},
},
},
}
def flag(name, partitions, default, *, origin = "Unknown", appends = False):
"""Declare a flag.
Args:
name: name of the flag
partitions: the partitions where this should be recorded.
default: the default value of the flag.
origin: The origin of this flag.
appends: Whether new values should be append (not replace) the old.
Returns:
A dictionary containing the flag declaration.
"""
if not partitions:
fail("At least 1 partition is required")
if not name.startswith("RELEASE_"):
fail("Release flag names must start with RELEASE_")
if " " in name or "\t" in name or "\n" in name:
fail("Flag names must not contain whitespace: \"" + name + "\"")
for partition in partitions:
if partition == "all":
if len(partitions) > 1:
fail("\"all\" can't be combined with other partitions: " + str(partitions))
elif partition not in _flag_partitions:
fail("Invalid partition: " + partition + ", allowed partitions: " +
str(_flag_partitions))
if type(default) not in _valid_types:
fail("Invalid type of default for flag \"" + name + "\" (" + type(default) + ")")
return {
"name": name,
"partitions": partitions,
"default": default,
"appends": appends,
"origin": origin,
}
def value(name, value):
"""Define the flag value for a particular configuration.
Args:
name: The name of the flag.
value: The value for the flag.
Returns:
A dictionary containing the name and value to be used.
"""
return {
"name": name,
"value": value,
}
def _format_value(val):
"""Format the starlark type correctly for make.
Args:
val: The value to format
Returns:
The value, formatted correctly for make.
"""
if type(val) == "NoneType":
return ""
elif type(val) == "bool":
return "true" if val else ""
else:
return val
def equal_flag_declaration(flag, other):
"""Return true if the flag declarations are equal.
Args:
flag: This flag declaration.
other: Another flag declaration.
Returns:
Whether the declarations are the same.
"""
for key in "name", "partitions", "default", "appends":
if flag[key] != other[key]:
return False
# For now, allow Unknown to match any other origin.
if flag["origin"] == "Unknown" or other["origin"] == "Unknown":
return True
return flag["origin"] == other["origin"]
def release_config(all_flags, all_values):
"""Return the make variables that should be set for this release config.
Args:
all_flags: A list of flag objects (from flag() calls).
all_values: A list of value objects (from value() calls).
Returns:
A dictionary of {name: value} variables for make.
"""
validate(all_flags, _all_flags_schema)
validate(all_values, _all_values_schema)
# Final values.
values = {}
# Validate flags
flag_names = []
flags_dict = {}
for flag in all_flags:
name = flag["name"]
if name in flag_names:
if equal_flag_declaration(flag, flags_dict[name]):
continue
else:
fail(flag["declared_in"] + ": Duplicate declaration of flag " + name +
" (declared first in " + flags_dict[name]["declared_in"] + ")")
flag_names.append(name)
flags_dict[name] = flag
# Set the flag value to the default value.
values[name] = {"name": name, "value": _format_value(flag["default"]), "set_in": flag["declared_in"]}
# Record which flags go on which partition
partitions = {}
for flag in all_flags:
for partition in flag["partitions"]:
if partition == "all":
if len(flag["partitions"]) > 1:
fail("\"all\" can't be combined with other partitions: " + str(flag["partitions"]))
for partition in _flag_partitions:
partitions.setdefault(partition, []).append(flag["name"])
else:
partitions.setdefault(partition, []).append(flag["name"])
# Generate final values.
# Only declared flags may have a value.
for value in all_values:
name = value["name"]
if name not in flag_names:
fail(value["set_in"] + ": Value set for undeclared build flag: " + name)
if flags_dict[name]["appends"]:
if name in values:
values[name]["value"] += " " + value["value"]
values[name]["set_in"] += " " + value["set_in"]
else:
values[name] = value
else:
values[name] = value
# Collect values
result = {
"_ALL_RELEASE_FLAGS": sorted(flag_names),
}
for partition, names in partitions.items():
result["_ALL_RELEASE_FLAGS.PARTITIONS." + partition] = names
for flag in all_flags:
val = _format_value(values[flag["name"]]["value"])
result[flag["name"]] = val
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".PARTITIONS"] = flag["partitions"]
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".DEFAULT"] = _format_value(flag["default"])
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".VALUE"] = val
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".DECLARED_IN"] = flag["declared_in"]
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".SET_IN"] = values[flag["name"]]["set_in"]
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".ORIGIN"] = flag["origin"]
return result