blob: 3357c0d6645f5b5142cf10b06c540d1781da7439 [file] [log] [blame]
Matt Spinler5cb5deb2019-09-27 13:51:36 -05001#!/usr/bin/env python
2
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
23 names = {}
24 for entry in registry_json['PELs']:
25 if entry['Name'] in names.keys():
26 sys.exit("Found multiple uses of error {}".format(entry['Name']))
27 else:
28 names[entry['Name']] = {}
29
30
31def check_component_id(registry_json):
32 r"""
33 Check that the upper byte of the ComponentID field matches the upper byte
34 of the ReasonCode field, but not on "11" type SRCs where they aren't
35 supposed to match.
36
37 registry_json: The message registry JSON
38 """
39
40 for entry in registry_json['PELs']:
41
42 # Don't check on "11" SRCs as those reason codes aren't supposed to
43 # match the component ID.
44 if entry.get('Type', '') == "11":
45 continue
46
47 if 'ComponentID' in entry:
48 id = int(entry['ComponentID'], 16)
49 reason_code = int(entry['SRC']['ReasonCode'], 16)
50
51 if (id & 0xFF00) != (reason_code & 0xFF00):
52 sys.exit("Found mismatching component ID {} vs reason "
53 "code {} for error {}".format(
54 entry['ComponentID'],
55 entry['SRC']['ReasonCode'],
56 entry['Name']))
57
58
59def check_message_args(registry_json):
60 r"""
61 Check that if the Message field uses the '%' style placeholders that there
62 are that many entries in the MessageArgSources field. Also checks that
63 the MessageArgSources field is present but only if there are placeholders.
64
65 registry_json: The message registry JSON
66 """
67
68 for entry in registry_json['PELs']:
69 num_placeholders = entry['Documentation']['Message'].count('%')
70 if num_placeholders == 0:
71 continue
72
73 if 'MessageArgSources' not in entry['Documentation']:
74 sys.exit("Missing MessageArgSources property for error {}".
75 format(entry['Name']))
76
77 if num_placeholders != \
78 len(entry['Documentation']['MessageArgSources']):
79 sys.exit("Different number of placeholders found in "
80 "Message vs MessageArgSources for error {}".
81 format(entry['Name']))
82
83
84def validate_schema(registry, schema):
85 r"""
86 Validates the passed in JSON against the passed in schema JSON
87
88 registry: Path of the file containing the registry JSON
89 schema: Path of the file containing the schema JSON
90 Use None to skip the pure schema validation
91 """
92
93 with open(registry) as registry_handle:
94 registry_json = json.load(registry_handle)
95
96 if schema:
97
98 import jsonschema
99
100 with open(schema) as schema_handle:
101 schema_json = json.load(schema_handle)
102
103 try:
104 jsonschema.validate(registry_json, schema_json)
105 except jsonschema.ValidationError as e:
106 print(e)
107 sys.exit("Schema validation failed")
108
109 check_duplicate_names(registry_json)
110
111 check_component_id(registry_json)
112
113 check_message_args(registry_json)
114
115
116if __name__ == '__main__':
117
118 parser = argparse.ArgumentParser(
119 description='PEL message registry processor')
120
121 parser.add_argument('-v', '--validate', action='store_true',
122 dest='validate',
123 help='Validate the JSON using the schema')
124
125 parser.add_argument('-s', '--schema-file', dest='schema_file',
126 help='The message registry JSON schema file')
127
128 parser.add_argument('-r', '--registry-file', dest='registry_file',
129 help='The message registry JSON file')
130 parser.add_argument('-k', '--skip-schema-validation', action='store_true',
131 dest='skip_schema',
132 help='Skip running schema validation. '
133 'Only do the extra checks.')
134
135 args = parser.parse_args()
136
137 if args.validate:
138 if not args.schema_file:
139 sys.exit("Schema file required")
140
141 if not args.registry_file:
142 sys.exit("Registry file required")
143
144 schema = args.schema_file
145 if args.skip_schema:
146 schema = None
147
148 validate_schema(args.registry_file, schema)