blob: e7370b3b9b544cc5d80c2c03fb699c9f51cc9097 [file]
#!/usr/bin/env python3
# Copyright 2024 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""generate_early_boot_checks generates code to check early-boot feature state.
Feature_library requires all early-boot features to have default values
specified in a file, default_states.json. It enforces this by making the code to
check feature state private. This script uses default_states.json to generate
public code (one function for each feature) to actually check the feature state.
"""
import argparse
import dataclasses
import json
import sys
from typing import Dict
import jinja2 # pylint: disable=import-error
@dataclasses.dataclass
class Feature:
"""Wrapper class for parsed Feature state."""
name: str
default_val: bool
params: Dict[str, str]
def generate_code(defaults_json: str, template_folder: str, header_path: str):
loaded = json.loads(defaults_json)
features = []
for k, v in loaded.items():
params = v["params"] if "params" in v else {}
features.append(Feature(k, v["enabled_by_default"], params))
env = jinja2.Environment(
loader=jinja2.FileSystemLoader(template_folder),
autoescape=jinja2.select_autoescape(enabled_extensions=("cpp",)),
)
for feature in features:
if not feature.name.startswith("CrOSEarlyBoot"):
raise ValueError(f"{feature.name} must start with CrOSEarlyBoot")
cc_template = env.get_template("early_boot_state_checks_cc.jinja")
h_template = env.get_template("early_boot_state_checks_h.jinja")
header_guard = header_path.upper().replace("/", "_").replace(".", "_")
return (
str(cc_template.render(features=features)),
str(h_template.render(features=features, header_guard=header_guard)),
)
def main(args):
parser = argparse.ArgumentParser(
description="Generates C++ functions to query individual feature status"
" with the given default states.",
)
parser.add_argument(
"--default_states",
help="Path to JSON file containing default states.",
required=True,
)
parser.add_argument(
"--fileroot_output",
help="Path to write output, with no extensions (e.g. .h).",
required=True,
)
parser.add_argument(
"--template_folder",
help="Directory containing the jinja templates.",
required=True,
)
# TODO(b/318555424): Support options to generate Rust and C code.
opts = parser.parse_args(args=args)
with open(opts.default_states, encoding="utf-8") as f:
defaults_json = f.read()
header_path = opts.fileroot_output + ".h"
code, header = generate_code(
defaults_json, opts.template_folder, header_path
)
with open(opts.fileroot_output + ".cc", "w", encoding="utf-8") as f:
f.write(code)
with open(header_path, "w", encoding="utf-8") as f:
f.write(header)
if __name__ == "__main__":
main(sys.argv[1:])