blob: a2e7ee2e2fc0b96731eaa7f91aab87032cc1db08 [file] [log] [blame]
Ed Tanous0ec8b832022-03-14 14:56:47 -07001#!/usr/bin/python3
2import os
Patrick Williamsfd06b302022-12-12 10:39:42 -06003import re
4import shutil
Ed Tanous0ec8b832022-03-14 14:56:47 -07005import xml.etree.ElementTree as ET
6from collections import defaultdict
Ed Tanous0ec8b832022-03-14 14:56:47 -07007
8SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
9REDFISH_SCHEMA_DIR = os.path.realpath(
10 os.path.join(SCRIPT_DIR, "..", "static", "redfish", "v1", "schema")
11)
12
Patrick Williamsfd06b302022-12-12 10:39:42 -060013OUTFOLDER = os.path.realpath(
14 os.path.join(
15 SCRIPT_DIR, "..", "redfish-core", "include", "generated", "enums"
16 )
Ed Tanous0ec8b832022-03-14 14:56:47 -070017)
18
19# Odata string types
20EDMX = "{http://docs.oasis-open.org/odata/ns/edmx}"
21EDM = "{http://docs.oasis-open.org/odata/ns/edm}"
22
23
24class Enum:
25 def __init__(self, name, values, namespace, from_file):
26 self.name = name
27 self.values = values
28 self.namespace = namespace
29 self.from_file = from_file
30
31
32def parse_schema(element, filename):
33 EntityTypes = []
34 namespace = element.attrib["Namespace"]
35 for schema_element in element:
36 name = schema_element.attrib.get("Name", None)
37 if name is None:
38 continue
39 if schema_element.tag == EDM + "EnumType":
40 enums = []
41 for member in schema_element.findall(EDM + "Member"):
42 enums.append(member.attrib["Name"])
43 EntityTypes.append(Enum(name, enums, namespace, filename))
44 return EntityTypes
45
46
47def parse_file(filename):
48 tree = ET.parse(filename)
49 root = tree.getroot()
50 results = []
51 data_services = root.findall(EDMX + "DataServices")
52 for ds in data_services:
53 for element in ds:
54 if element.tag == EDM + "Schema":
55 results.extend(parse_schema(element, filename))
56
57 return results
58
59
60def camel_to_snake(name):
61 # snake casing PCIeDevice and PCIeFunction results in mediocre results
62 # given that the standard didn't camel case those in a way that the
63 # algorithm expects, so change the casing explicitly to generate sane
64 # snake case results.
65 name = name.replace("PCIe", "Pcie")
66 name = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
67 return re.sub("([a-z0-9])([A-Z])", r"\1_\2", name).lower()
68
69
70def write_enum_list(redfish_defs_file, enum_list, snake_case_namespace):
71 redfish_defs_file.write(
72 "#pragma once\n"
73 "#include <nlohmann/json.hpp>\n\n"
74 "namespace {}\n"
75 "{{\n"
76 "// clang-format off\n\n".format(snake_case_namespace)
77 )
78
79 for element in enum_list:
80 redfish_defs_file.write("enum class {}{{\n".format(element.name))
81 values = element.values
82 if "Invalid" not in values:
83 values.insert(0, "Invalid")
84
85 for value in values:
86 redfish_defs_file.write(" {},\n".format(value))
87
88 redfish_defs_file.write("};\n\n")
89
90 for element in enum_list:
91 values = element.values
92 if "Invalid" not in values:
93 values.insert(0, "Invalid")
Ed Tanous8ece0e42024-01-02 13:16:50 -080094 # nlohmann::json apparently uses c style arrays in their enum
Ed Tanous0ec8b832022-03-14 14:56:47 -070095 # implementation, and clang-tidy isn't smart enough to figure out that
96 # the C arrays are in their code not bmcwebs, so we have to explicitly
97 # ignore the error.
98 redfish_defs_file.write(
Patrick Williamsfd06b302022-12-12 10:39:42 -060099 "NLOHMANN_JSON_SERIALIZE_ENUM({}, {{\n".format(element.name)
Ed Tanous0ec8b832022-03-14 14:56:47 -0700100 )
101 for value in values:
102 redfish_defs_file.write(
103 ' {{{}::{}, "{}"}},\n'.format(element.name, value, value)
104 )
105
106 redfish_defs_file.write("});\n\n")
107
108 print(element.name)
109
Patrick Williamsfd06b302022-12-12 10:39:42 -0600110 redfish_defs_file.write("}\n// clang-format on\n")
Ed Tanous0ec8b832022-03-14 14:56:47 -0700111
112
113def generate_enums(flat_list):
114 # clear out the old results if they exist
115 if os.path.exists(OUTFOLDER):
116 shutil.rmtree(OUTFOLDER)
117 os.makedirs(OUTFOLDER)
118
119 enum_by_namespace = defaultdict(list)
120
121 for element in flat_list:
122 if isinstance(element, Enum):
123 namespace_split = element.namespace.split(".")[0]
124 enum_by_namespace[namespace_split].append(element)
125
126 for namespace, enum_list in enum_by_namespace.items():
127 snake_case_namespace = camel_to_snake(namespace)
128 outfile = os.path.join(
129 OUTFOLDER, "{}.hpp".format(snake_case_namespace)
130 )
131
132 with open(outfile, "w") as redfish_defs:
133 write_enum_list(redfish_defs, enum_list, snake_case_namespace)
134
135
136def main():
137 print("Reading from {}".format(REDFISH_SCHEMA_DIR))
138 dir_list = os.listdir(REDFISH_SCHEMA_DIR)
139
140 filepaths = [
141 os.path.join(REDFISH_SCHEMA_DIR, filename) for filename in dir_list
142 ]
143
144 enum_list = []
145
146 for filepath in filepaths:
147 out = parse_file(filepath)
148 enum_list.extend(out)
149
150 print("Parsing done")
151
152 generate_enums(enum_list)
153
154
155if __name__ == "__main__":
156 main()