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