blob: 44dcde6551f890c6bf89c9743bf10ecc52903b1a [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(
Ed Tanous40e9b922024-09-10 13:50:16 -070073 "// SPDX-License-Identifier: Apache-2.0\n"
74 "// SPDX-FileCopyrightText: Copyright OpenBMC Authors\n"
Ed Tanous0ec8b832022-03-14 14:56:47 -070075 "#pragma once\n"
76 "#include <nlohmann/json.hpp>\n\n"
77 "namespace {}\n"
78 "{{\n"
79 "// clang-format off\n\n".format(snake_case_namespace)
80 )
81
82 for element in enum_list:
83 redfish_defs_file.write("enum class {}{{\n".format(element.name))
84 values = element.values
85 if "Invalid" not in values:
86 values.insert(0, "Invalid")
87
88 for value in values:
89 redfish_defs_file.write(" {},\n".format(value))
90
91 redfish_defs_file.write("};\n\n")
92
93 for element in enum_list:
94 values = element.values
95 if "Invalid" not in values:
96 values.insert(0, "Invalid")
Ed Tanous8ece0e42024-01-02 13:16:50 -080097 # nlohmann::json apparently uses c style arrays in their enum
Ed Tanous0ec8b832022-03-14 14:56:47 -070098 # implementation, and clang-tidy isn't smart enough to figure out that
99 # the C arrays are in their code not bmcwebs, so we have to explicitly
100 # ignore the error.
101 redfish_defs_file.write(
Patrick Williamsfd06b302022-12-12 10:39:42 -0600102 "NLOHMANN_JSON_SERIALIZE_ENUM({}, {{\n".format(element.name)
Ed Tanous0ec8b832022-03-14 14:56:47 -0700103 )
104 for value in values:
105 redfish_defs_file.write(
106 ' {{{}::{}, "{}"}},\n'.format(element.name, value, value)
107 )
108
109 redfish_defs_file.write("});\n\n")
110
111 print(element.name)
112
Patrick Williamsfd06b302022-12-12 10:39:42 -0600113 redfish_defs_file.write("}\n// clang-format on\n")
Ed Tanous0ec8b832022-03-14 14:56:47 -0700114
115
116def generate_enums(flat_list):
117 # clear out the old results if they exist
118 if os.path.exists(OUTFOLDER):
119 shutil.rmtree(OUTFOLDER)
120 os.makedirs(OUTFOLDER)
121
122 enum_by_namespace = defaultdict(list)
123
124 for element in flat_list:
125 if isinstance(element, Enum):
126 namespace_split = element.namespace.split(".")[0]
127 enum_by_namespace[namespace_split].append(element)
128
129 for namespace, enum_list in enum_by_namespace.items():
130 snake_case_namespace = camel_to_snake(namespace)
131 outfile = os.path.join(
132 OUTFOLDER, "{}.hpp".format(snake_case_namespace)
133 )
134
135 with open(outfile, "w") as redfish_defs:
136 write_enum_list(redfish_defs, enum_list, snake_case_namespace)
137
138
139def main():
140 print("Reading from {}".format(REDFISH_SCHEMA_DIR))
Ed Tanous0ec8b832022-03-14 14:56:47 -0700141
Ed Tanous720c9892024-05-11 07:28:09 -0700142 filepaths = []
143 for root, dirs, files in os.walk(REDFISH_SCHEMA_DIR):
144 for csdl_file in files:
Ed Tanousa529a6a2024-05-29 16:51:37 -0700145 filepath = os.path.join(root, csdl_file)
146 if os.path.islink(filepath):
147 continue
Ed Tanous720c9892024-05-11 07:28:09 -0700148 if csdl_file.endswith(".xml"):
Ed Tanousa529a6a2024-05-29 16:51:37 -0700149 filepaths.append(filepath)
Ed Tanous720c9892024-05-11 07:28:09 -0700150 print(filepaths)
Ed Tanous0ec8b832022-03-14 14:56:47 -0700151 enum_list = []
Ed Tanousa529a6a2024-05-29 16:51:37 -0700152 filepaths.sort()
Ed Tanous0ec8b832022-03-14 14:56:47 -0700153 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()