blob: fcdacf5439149b0b65879c660a1da6e122fb6238 [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 = []
Matt Spinler5cb5deb2019-09-27 13:51:36 -050024 for entry in registry_json['PELs']:
Matt Spinler446d2b92020-03-05 16:49:14 -060025 if entry['Name'] in names:
Matt Spinler5cb5deb2019-09-27 13:51:36 -050026 sys.exit("Found multiple uses of error {}".format(entry['Name']))
27 else:
Matt Spinler446d2b92020-03-05 16:49:14 -060028 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 = []
Matt Spinler55a69782019-10-25 13:49:30 -050040 for entry in registry_json['PELs']:
Matt Spinler446d2b92020-03-05 16:49:14 -060041 if entry['SRC']['ReasonCode'] in reasonCodes:
Matt Spinler55a69782019-10-25 13:49:30 -050042 sys.exit("Found duplicate SRC reason code {}".format(
43 entry['SRC']['ReasonCode']))
44 else:
Matt Spinler446d2b92020-03-05 16:49:14 -060045 reasonCodes.append(entry['SRC']['ReasonCode'])
Matt Spinler55a69782019-10-25 13:49:30 -050046
47
Matt Spinler5cb5deb2019-09-27 13:51:36 -050048def check_component_id(registry_json):
49 r"""
50 Check that the upper byte of the ComponentID field matches the upper byte
51 of the ReasonCode field, but not on "11" type SRCs where they aren't
52 supposed to match.
53
54 registry_json: The message registry JSON
55 """
56
57 for entry in registry_json['PELs']:
58
59 # Don't check on "11" SRCs as those reason codes aren't supposed to
60 # match the component ID.
Matt Spinlerc2d9ec02020-06-25 09:41:39 -050061 if entry['SRC'].get('Type', '') == "11":
Matt Spinler5cb5deb2019-09-27 13:51:36 -050062 continue
63
64 if 'ComponentID' in entry:
65 id = int(entry['ComponentID'], 16)
66 reason_code = int(entry['SRC']['ReasonCode'], 16)
67
68 if (id & 0xFF00) != (reason_code & 0xFF00):
69 sys.exit("Found mismatching component ID {} vs reason "
70 "code {} for error {}".format(
71 entry['ComponentID'],
72 entry['SRC']['ReasonCode'],
73 entry['Name']))
74
75
76def check_message_args(registry_json):
77 r"""
78 Check that if the Message field uses the '%' style placeholders that there
79 are that many entries in the MessageArgSources field. Also checks that
80 the MessageArgSources field is present but only if there are placeholders.
81
82 registry_json: The message registry JSON
83 """
84
85 for entry in registry_json['PELs']:
86 num_placeholders = entry['Documentation']['Message'].count('%')
87 if num_placeholders == 0:
88 continue
89
90 if 'MessageArgSources' not in entry['Documentation']:
91 sys.exit("Missing MessageArgSources property for error {}".
92 format(entry['Name']))
93
94 if num_placeholders != \
95 len(entry['Documentation']['MessageArgSources']):
96 sys.exit("Different number of placeholders found in "
97 "Message vs MessageArgSources for error {}".
98 format(entry['Name']))
99
100
101def validate_schema(registry, schema):
102 r"""
103 Validates the passed in JSON against the passed in schema JSON
104
105 registry: Path of the file containing the registry JSON
106 schema: Path of the file containing the schema JSON
107 Use None to skip the pure schema validation
108 """
109
110 with open(registry) as registry_handle:
111 registry_json = json.load(registry_handle)
112
113 if schema:
114
115 import jsonschema
116
117 with open(schema) as schema_handle:
118 schema_json = json.load(schema_handle)
119
120 try:
121 jsonschema.validate(registry_json, schema_json)
122 except jsonschema.ValidationError as e:
123 print(e)
124 sys.exit("Schema validation failed")
125
126 check_duplicate_names(registry_json)
127
Matt Spinler55a69782019-10-25 13:49:30 -0500128 check_duplicate_reason_codes(registry_json)
129
Matt Spinler5cb5deb2019-09-27 13:51:36 -0500130 check_component_id(registry_json)
131
132 check_message_args(registry_json)
133
134
135if __name__ == '__main__':
136
137 parser = argparse.ArgumentParser(
138 description='PEL message registry processor')
139
140 parser.add_argument('-v', '--validate', action='store_true',
141 dest='validate',
142 help='Validate the JSON using the schema')
143
144 parser.add_argument('-s', '--schema-file', dest='schema_file',
145 help='The message registry JSON schema file')
146
147 parser.add_argument('-r', '--registry-file', dest='registry_file',
148 help='The message registry JSON file')
149 parser.add_argument('-k', '--skip-schema-validation', action='store_true',
150 dest='skip_schema',
151 help='Skip running schema validation. '
152 'Only do the extra checks.')
153
154 args = parser.parse_args()
155
156 if args.validate:
157 if not args.schema_file:
158 sys.exit("Schema file required")
159
160 if not args.registry_file:
161 sys.exit("Registry file required")
162
163 schema = args.schema_file
164 if args.skip_schema:
165 schema = None
166
167 validate_schema(args.registry_file, schema)