blob: fb39b980bb667c77ced727412cf7657ce2e84e5d [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(
Ed Tanous720c9892024-05-11 07:28:09 -070010 os.path.join(SCRIPT_DIR, "..", "redfish-core", "schema")
Ed Tanous0ec8b832022-03-14 14:56:47 -070011)
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):
Ed Tanous720c9892024-05-11 07:28:09 -070048 print(f"Parsing {filename}")
Ed Tanous0ec8b832022-03-14 14:56:47 -070049 tree = ET.parse(filename)
50 root = tree.getroot()
51 results = []
52 data_services = root.findall(EDMX + "DataServices")
53 for ds in data_services:
54 for element in ds:
55 if element.tag == EDM + "Schema":
56 results.extend(parse_schema(element, filename))
57
58 return results
59
60
61def camel_to_snake(name):
62 # snake casing PCIeDevice and PCIeFunction results in mediocre results
63 # given that the standard didn't camel case those in a way that the
64 # algorithm expects, so change the casing explicitly to generate sane
65 # snake case results.
66 name = name.replace("PCIe", "Pcie")
67 name = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
68 return re.sub("([a-z0-9])([A-Z])", r"\1_\2", name).lower()
69
70
71def write_enum_list(redfish_defs_file, enum_list, snake_case_namespace):
72 redfish_defs_file.write(
73 "#pragma once\n"
74 "#include <nlohmann/json.hpp>\n\n"
75 "namespace {}\n"
76 "{{\n"
77 "// clang-format off\n\n".format(snake_case_namespace)
78 )
79
80 for element in enum_list:
81 redfish_defs_file.write("enum class {}{{\n".format(element.name))
82 values = element.values
83 if "Invalid" not in values:
84 values.insert(0, "Invalid")
85
86 for value in values:
87 redfish_defs_file.write(" {},\n".format(value))
88
89 redfish_defs_file.write("};\n\n")
90
91 for element in enum_list:
92 values = element.values
93 if "Invalid" not in values:
94 values.insert(0, "Invalid")
Ed Tanous8ece0e42024-01-02 13:16:50 -080095 # nlohmann::json apparently uses c style arrays in their enum
Ed Tanous0ec8b832022-03-14 14:56:47 -070096 # implementation, and clang-tidy isn't smart enough to figure out that
97 # the C arrays are in their code not bmcwebs, so we have to explicitly
98 # ignore the error.
99 redfish_defs_file.write(
Patrick Williamsfd06b302022-12-12 10:39:42 -0600100 "NLOHMANN_JSON_SERIALIZE_ENUM({}, {{\n".format(element.name)
Ed Tanous0ec8b832022-03-14 14:56:47 -0700101 )
102 for value in values:
103 redfish_defs_file.write(
104 ' {{{}::{}, "{}"}},\n'.format(element.name, value, value)
105 )
106
107 redfish_defs_file.write("});\n\n")
108
109 print(element.name)
110
Patrick Williamsfd06b302022-12-12 10:39:42 -0600111 redfish_defs_file.write("}\n// clang-format on\n")
Ed Tanous0ec8b832022-03-14 14:56:47 -0700112
113
114def generate_enums(flat_list):
115 # clear out the old results if they exist
116 if os.path.exists(OUTFOLDER):
117 shutil.rmtree(OUTFOLDER)
118 os.makedirs(OUTFOLDER)
119
120 enum_by_namespace = defaultdict(list)
121
122 for element in flat_list:
123 if isinstance(element, Enum):
124 namespace_split = element.namespace.split(".")[0]
125 enum_by_namespace[namespace_split].append(element)
126
127 for namespace, enum_list in enum_by_namespace.items():
128 snake_case_namespace = camel_to_snake(namespace)
129 outfile = os.path.join(
130 OUTFOLDER, "{}.hpp".format(snake_case_namespace)
131 )
132
133 with open(outfile, "w") as redfish_defs:
134 write_enum_list(redfish_defs, enum_list, snake_case_namespace)
135
136
137def main():
138 print("Reading from {}".format(REDFISH_SCHEMA_DIR))
Ed Tanous0ec8b832022-03-14 14:56:47 -0700139
Ed Tanous720c9892024-05-11 07:28:09 -0700140 filepaths = []
141 for root, dirs, files in os.walk(REDFISH_SCHEMA_DIR):
142 for csdl_file in files:
143 if csdl_file.endswith(".xml"):
144 filepaths.append(os.path.join(root, csdl_file))
145 print(filepaths)
Ed Tanous0ec8b832022-03-14 14:56:47 -0700146 enum_list = []
147
148 for filepath in filepaths:
149 out = parse_file(filepath)
150 enum_list.extend(out)
151
152 print("Parsing done")
153
154 generate_enums(enum_list)
155
156
157if __name__ == "__main__":
158 main()