blob: 285b3b4cd4706fd8843d3d2d868403073702b890 [file] [log] [blame]
Matt Spinler446d2b92020-03-05 16:49:14 -06001#!/usr/bin/env python3
Matt Spinler5cb5deb2019-09-27 13:51:36 -05002
3import argparse
4import json
5import sys
6
7r"""
8Validates the PEL message registry JSON, which includes checking it against
9a JSON schema using the jsonschema module as well as doing some extra checks
10that can't be encoded in the schema.
11"""
12
13
14def check_duplicate_names(registry_json):
15 r"""
16 Check that there aren't any message registry entries with the same
17 'Name' field. There may be a use case for this in the future, but there
18 isn't right now.
19
20 registry_json: The message registry JSON
21 """
22
Matt Spinler446d2b92020-03-05 16:49:14 -060023 names = []
Patrick Williamse6555f52022-08-04 13:56:17 -050024 for entry in registry_json["PELs"]:
25 if entry["Name"] in names:
26 sys.exit("Found multiple uses of error {}".format(entry["Name"]))
Matt Spinler5cb5deb2019-09-27 13:51:36 -050027 else:
Patrick Williamse6555f52022-08-04 13:56:17 -050028 names.append(entry["Name"])
Matt Spinler5cb5deb2019-09-27 13:51:36 -050029
30
Matt Spinler55a69782019-10-25 13:49:30 -050031def check_duplicate_reason_codes(registry_json):
32 r"""
33 Check that there aren't any message registry entries with the same
34 'ReasonCode' field.
35
36 registry_json: The message registry JSON
37 """
38
Matt Spinler446d2b92020-03-05 16:49:14 -060039 reasonCodes = []
Patrick Williamse6555f52022-08-04 13:56:17 -050040 for entry in registry_json["PELs"]:
41 if entry["SRC"]["ReasonCode"] in reasonCodes:
42 sys.exit(
43 "Found duplicate SRC reason code {}".format(
44 entry["SRC"]["ReasonCode"]
45 )
46 )
Matt Spinler55a69782019-10-25 13:49:30 -050047 else:
Patrick Williamse6555f52022-08-04 13:56:17 -050048 reasonCodes.append(entry["SRC"]["ReasonCode"])
Matt Spinler55a69782019-10-25 13:49:30 -050049
50
Matt Spinler5cb5deb2019-09-27 13:51:36 -050051def check_component_id(registry_json):
52 r"""
53 Check that the upper byte of the ComponentID field matches the upper byte
54 of the ReasonCode field, but not on "11" type SRCs where they aren't
55 supposed to match.
56
57 registry_json: The message registry JSON
58 """
59
Patrick Williamse6555f52022-08-04 13:56:17 -050060 for entry in registry_json["PELs"]:
Matt Spinler5cb5deb2019-09-27 13:51:36 -050061 # Don't check on "11" SRCs as those reason codes aren't supposed to
62 # match the component ID.
Patrick Williamse6555f52022-08-04 13:56:17 -050063 if entry["SRC"].get("Type", "") == "11":
Matt Spinler5cb5deb2019-09-27 13:51:36 -050064 continue
65
Patrick Williamse6555f52022-08-04 13:56:17 -050066 if "ComponentID" in entry:
67 id = int(entry["ComponentID"], 16)
68 reason_code = int(entry["SRC"]["ReasonCode"], 16)
Matt Spinler5cb5deb2019-09-27 13:51:36 -050069
70 if (id & 0xFF00) != (reason_code & 0xFF00):
Patrick Williamse6555f52022-08-04 13:56:17 -050071 sys.exit(
72 "Found mismatching component ID {} vs reason "
73 "code {} for error {}".format(
74 entry["ComponentID"],
75 entry["SRC"]["ReasonCode"],
76 entry["Name"],
77 )
78 )
Matt Spinler5cb5deb2019-09-27 13:51:36 -050079
80
81def check_message_args(registry_json):
82 r"""
83 Check that if the Message field uses the '%' style placeholders that there
84 are that many entries in the MessageArgSources field. Also checks that
85 the MessageArgSources field is present but only if there are placeholders.
86
87 registry_json: The message registry JSON
88 """
89
Patrick Williamse6555f52022-08-04 13:56:17 -050090 for entry in registry_json["PELs"]:
91 num_placeholders = entry["Documentation"]["Message"].count("%")
Matt Spinler5cb5deb2019-09-27 13:51:36 -050092 if num_placeholders == 0:
93 continue
94
Patrick Williamse6555f52022-08-04 13:56:17 -050095 if "MessageArgSources" not in entry["Documentation"]:
96 sys.exit(
97 "Missing MessageArgSources property for error {}".format(
98 entry["Name"]
99 )
100 )
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500101
Patrick Williamse6555f52022-08-04 13:56:17 -0500102 if num_placeholders != len(
103 entry["Documentation"]["MessageArgSources"]
104 ):
105 sys.exit(
106 "Different number of placeholders found in "
107 "Message vs MessageArgSources for error {}".format(
108 entry["Name"]
109 )
110 )
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500111
112
113def validate_schema(registry, schema):
114 r"""
115 Validates the passed in JSON against the passed in schema JSON
116
117 registry: Path of the file containing the registry JSON
118 schema: Path of the file containing the schema JSON
119 Use None to skip the pure schema validation
120 """
121
122 with open(registry) as registry_handle:
123 registry_json = json.load(registry_handle)
124
125 if schema:
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500126 import jsonschema
127
128 with open(schema) as schema_handle:
129 schema_json = json.load(schema_handle)
130
131 try:
132 jsonschema.validate(registry_json, schema_json)
133 except jsonschema.ValidationError as e:
134 print(e)
135 sys.exit("Schema validation failed")
136
137 check_duplicate_names(registry_json)
138
Matt Spinler55a69782019-10-25 13:49:30 -0500139 check_duplicate_reason_codes(registry_json)
140
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500141 check_component_id(registry_json)
142
143 check_message_args(registry_json)
144
145
Patrick Williamse6555f52022-08-04 13:56:17 -0500146if __name__ == "__main__":
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500147 parser = argparse.ArgumentParser(
Matt Spinler1ed10672023-03-08 16:39:15 -0600148 description="PEL message registry validator"
Patrick Williamse6555f52022-08-04 13:56:17 -0500149 )
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500150
Patrick Williamse6555f52022-08-04 13:56:17 -0500151 parser.add_argument(
152 "-s",
153 "--schema-file",
154 dest="schema_file",
155 help="The message registry JSON schema file",
Matt Spinler1ed10672023-03-08 16:39:15 -0600156 required=True,
Patrick Williamse6555f52022-08-04 13:56:17 -0500157 )
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500158
Patrick Williamse6555f52022-08-04 13:56:17 -0500159 parser.add_argument(
160 "-r",
161 "--registry-file",
162 dest="registry_file",
163 help="The message registry JSON file",
Matt Spinler1ed10672023-03-08 16:39:15 -0600164 required=True,
Patrick Williamse6555f52022-08-04 13:56:17 -0500165 )
Matt Spinler1ed10672023-03-08 16:39:15 -0600166
Patrick Williamse6555f52022-08-04 13:56:17 -0500167 parser.add_argument(
168 "-k",
169 "--skip-schema-validation",
170 action="store_true",
171 dest="skip_schema",
Patrick Williamsd27675d2022-12-08 06:18:00 -0600172 help="Skip running schema validation. Only do the extra checks.",
Patrick Williamse6555f52022-08-04 13:56:17 -0500173 )
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500174
175 args = parser.parse_args()
176
Matt Spinler1ed10672023-03-08 16:39:15 -0600177 schema = args.schema_file
178 if args.skip_schema:
179 schema = None
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500180
Matt Spinler1ed10672023-03-08 16:39:15 -0600181 validate_schema(args.registry_file, schema)