diff options
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/generate_schema_enums.py | 163 | ||||
-rwxr-xr-x | scripts/update_schemas.py | 3 |
2 files changed, 166 insertions, 0 deletions
diff --git a/scripts/generate_schema_enums.py b/scripts/generate_schema_enums.py new file mode 100755 index 0000000000..13fbefe40f --- /dev/null +++ b/scripts/generate_schema_enums.py @@ -0,0 +1,163 @@ +#!/usr/bin/python3 +import os +import xml.etree.ElementTree as ET +from collections import defaultdict +import shutil +import re + + +SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) +REDFISH_SCHEMA_DIR = os.path.realpath( + os.path.join(SCRIPT_DIR, "..", "static", "redfish", "v1", "schema") +) + +OUTFOLDER = os.path.realpath(os.path.join( + SCRIPT_DIR, + "..", + "redfish-core", + "include", + "generated", + "enums" + ) +) + +# Odata string types +EDMX = "{http://docs.oasis-open.org/odata/ns/edmx}" +EDM = "{http://docs.oasis-open.org/odata/ns/edm}" + + +class Enum: + def __init__(self, name, values, namespace, from_file): + self.name = name + self.values = values + self.namespace = namespace + self.from_file = from_file + + +def parse_schema(element, filename): + EntityTypes = [] + namespace = element.attrib["Namespace"] + for schema_element in element: + name = schema_element.attrib.get("Name", None) + if name is None: + continue + if schema_element.tag == EDM + "EnumType": + enums = [] + for member in schema_element.findall(EDM + "Member"): + enums.append(member.attrib["Name"]) + EntityTypes.append(Enum(name, enums, namespace, filename)) + return EntityTypes + + +def parse_file(filename): + tree = ET.parse(filename) + root = tree.getroot() + results = [] + data_services = root.findall(EDMX + "DataServices") + for ds in data_services: + for element in ds: + if element.tag == EDM + "Schema": + results.extend(parse_schema(element, filename)) + + return results + + +def camel_to_snake(name): + # snake casing PCIeDevice and PCIeFunction results in mediocre results + # given that the standard didn't camel case those in a way that the + # algorithm expects, so change the casing explicitly to generate sane + # snake case results. + name = name.replace("PCIe", "Pcie") + name = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) + return re.sub("([a-z0-9])([A-Z])", r"\1_\2", name).lower() + + +def write_enum_list(redfish_defs_file, enum_list, snake_case_namespace): + redfish_defs_file.write( + "#pragma once\n" + "#include <nlohmann/json.hpp>\n\n" + "namespace {}\n" + "{{\n" + "// clang-format off\n\n".format(snake_case_namespace) + ) + + for element in enum_list: + redfish_defs_file.write("enum class {}{{\n".format(element.name)) + values = element.values + if "Invalid" not in values: + values.insert(0, "Invalid") + + for value in values: + redfish_defs_file.write(" {},\n".format(value)) + + redfish_defs_file.write("};\n\n") + + for element in enum_list: + values = element.values + if "Invalid" not in values: + values.insert(0, "Invalid") + # nlohmann::json aparently uses c style arrays in their enum + # implementation, and clang-tidy isn't smart enough to figure out that + # the C arrays are in their code not bmcwebs, so we have to explicitly + # ignore the error. + redfish_defs_file.write( + "NLOHMANN_JSON_SERIALIZE_ENUM({}, {{\n".format( + element.name + ) + ) + for value in values: + redfish_defs_file.write( + ' {{{}::{}, "{}"}},\n'.format(element.name, value, value) + ) + + redfish_defs_file.write("});\n\n") + + print(element.name) + + redfish_defs_file.write("}\n" "// clang-format on\n") + + +def generate_enums(flat_list): + # clear out the old results if they exist + if os.path.exists(OUTFOLDER): + shutil.rmtree(OUTFOLDER) + os.makedirs(OUTFOLDER) + + enum_by_namespace = defaultdict(list) + + for element in flat_list: + if isinstance(element, Enum): + namespace_split = element.namespace.split(".")[0] + enum_by_namespace[namespace_split].append(element) + + for namespace, enum_list in enum_by_namespace.items(): + snake_case_namespace = camel_to_snake(namespace) + outfile = os.path.join( + OUTFOLDER, "{}.hpp".format(snake_case_namespace) + ) + + with open(outfile, "w") as redfish_defs: + write_enum_list(redfish_defs, enum_list, snake_case_namespace) + + +def main(): + print("Reading from {}".format(REDFISH_SCHEMA_DIR)) + dir_list = os.listdir(REDFISH_SCHEMA_DIR) + + filepaths = [ + os.path.join(REDFISH_SCHEMA_DIR, filename) for filename in dir_list + ] + + enum_list = [] + + for filepath in filepaths: + out = parse_file(filepath) + enum_list.extend(out) + + print("Parsing done") + + generate_enums(enum_list) + + +if __name__ == "__main__": + main() diff --git a/scripts/update_schemas.py b/scripts/update_schemas.py index 459d0457bd..f6eca42c78 100755 --- a/scripts/update_schemas.py +++ b/scripts/update_schemas.py @@ -8,6 +8,7 @@ from io import BytesIO import requests from packaging.version import parse +import generate_schema_enums VERSION = "DSP8010_2022.2" @@ -390,3 +391,5 @@ with open(os.path.join(cpp_path, "schemas.hpp"), "w") as hpp_file: hpp_file.write(" };\n}\n") zip_ref.close() + +generate_schema_enums.main() |