OLD | NEW |
---|---|
1 #!/usr/bin/python2 | 1 #!/usr/bin/python2 |
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 ''' | 6 ''' |
7 Checks a policy_templates.json file for conformity to its syntax specification. | 7 Checks a policy_templates.json file for conformity to its syntax specification. |
8 ''' | 8 ''' |
9 | 9 |
10 import json | 10 import json |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 (container_name.title(), value_type.__name__, key), | 74 (container_name.title(), value_type.__name__, key), |
75 container_name, identifier, offending) | 75 container_name, identifier, offending) |
76 return None | 76 return None |
77 value = container[key] | 77 value = container[key] |
78 if not isinstance(value, value_type): | 78 if not isinstance(value, value_type): |
79 self._Error('Value of "%s" must be a %s.' % | 79 self._Error('Value of "%s" must be a %s.' % |
80 (key, value_type.__name__), | 80 (key, value_type.__name__), |
81 container_name, identifier, value) | 81 container_name, identifier, value) |
82 return value | 82 return value |
83 | 83 |
84 def _CheckPolicy(self, policy, may_contain_groups): | 84 def _AddProtobufID(self, protobuf_id, policy, is_in_group): |
85 ''' | |
86 Adds |protobuf_id| to either self.protobuf_ids or self.group_protobuf_ids, | |
87 depending on |is_in_group|. Generates an error message if the protobuf_id | |
88 exists already; |policy| is needed for this message. | |
89 ''' | |
90 if is_in_group: | |
91 if protobuf_id in self.group_protobuf_ids: | |
gfeher
2011/02/02 08:42:45
How about making |self.group_protobuf_ids| / |is_i
Jakob Kummerow
2011/02/03 14:36:52
Done. Good idea.
| |
92 self._Error('Duplicate protobuf_id', 'policy', policy.get('name'), | |
93 protobuf_id) | |
94 else: | |
95 self.group_protobuf_ids.add(protobuf_id) | |
96 else: | |
97 if protobuf_id in self.protobuf_ids: | |
98 self._Error('Duplicate protobuf_id', 'policy', policy.get('name'), | |
99 protobuf_id) | |
100 else: | |
101 self.protobuf_ids.add(protobuf_id) | |
102 | |
103 def _CheckProtobufIDs(self, protobuf_ids, group=None): | |
104 ''' | |
105 Checks a set of protobuf_ids to make sure it contains a continuous range | |
106 of entries (i.e. no holes). | |
gfeher
2011/02/02 08:42:45
Isn't it possible that we will have holes later as
Jakob Kummerow
2011/02/03 14:36:52
As discussed offline, we don't want to allow holes
| |
107 ''' | |
108 for i in range(len(protobuf_ids)): | |
109 if (i + 1) not in protobuf_ids: | |
110 if group is not None: | |
111 self._Error('Missing protobuf_id: %s' % (i + 1), 'policy group', | |
112 group.get('name')) | |
113 else: | |
114 self._Error('No policy with protobuf_id: %s' % (i + 1)) | |
115 | |
116 def _CheckPolicy(self, policy, is_in_group): | |
85 if not isinstance(policy, dict): | 117 if not isinstance(policy, dict): |
86 self._Error('Each policy must be a dictionary.', 'policy', None, policy) | 118 self._Error('Each policy must be a dictionary.', 'policy', None, policy) |
87 return | 119 return |
88 | 120 |
89 # There should not be any unknown keys in |policy|. | 121 # There should not be any unknown keys in |policy|. |
90 for key in policy: | 122 for key in policy: |
91 if key not in ('name', 'type', 'caption', 'desc', 'supported_on', | 123 if key not in ('name', 'type', 'caption', 'desc', 'supported_on', |
92 'label', 'policies', 'items', 'example_value', 'features', | 124 'label', 'policies', 'items', 'example_value', 'features', |
93 'deprecated'): | 125 'deprecated', 'protobuf_id'): |
94 self.warning_count += 1 | 126 self.warning_count += 1 |
95 print ('In policy %s: Warning: Unknown key: %s' % | 127 print ('In policy %s: Warning: Unknown key: %s' % |
96 (policy.get('name'), key)) | 128 (policy.get('name'), key)) |
97 | 129 |
98 # Each policy must have a name. | 130 # Each policy must have a name. |
99 self._CheckContains(policy, 'name', str) | 131 self._CheckContains(policy, 'name', str) |
100 | 132 |
101 # Each policy must have a type. | 133 # Each policy must have a type. |
102 policy_type = self._CheckContains(policy, 'type', str) | 134 policy_type = self._CheckContains(policy, 'type', str) |
103 if policy_type not in ('group', 'main', 'string', 'int', 'list', 'int-enum', | 135 if policy_type not in ('group', 'main', 'string', 'int', 'list', 'int-enum', |
104 'string-enum'): | 136 'string-enum'): |
105 self._Error('Policy type must be either of: group, main, string, int, ' | 137 self._Error('Policy type must be either of: group, main, string, int, ' |
106 'list, int-enum, string-enum', 'policy', policy, policy_type) | 138 'list, int-enum, string-enum', 'policy', policy, policy_type) |
107 return # Can't continue for unsupported type. | 139 return # Can't continue for unsupported type. |
108 | 140 |
109 # Each policy must have a caption message. | 141 # Each policy must have a caption message. |
110 self._CheckContains(policy, 'caption', str) | 142 self._CheckContains(policy, 'caption', str) |
111 | 143 |
112 # Each policy must have a description message. | 144 # Each policy must have a description message. |
113 self._CheckContains(policy, 'desc', str) | 145 self._CheckContains(policy, 'desc', str) |
114 | 146 |
115 # If 'label' is present, it must be a string. | 147 # If 'label' is present, it must be a string. |
116 self._CheckContains(policy, 'label', str, True) | 148 self._CheckContains(policy, 'label', str, True) |
117 | 149 |
150 # Each policy must have a protobuf ID. | |
151 protobuf_id = self._CheckContains(policy, 'protobuf_id', int) | |
152 self._AddProtobufID(protobuf_id, policy, is_in_group) | |
153 | |
118 # If 'deprecated' is present, it must be a bool. | 154 # If 'deprecated' is present, it must be a bool. |
119 self._CheckContains(policy, 'deprecated', bool, True) | 155 self._CheckContains(policy, 'deprecated', bool, True) |
120 | 156 |
121 if policy_type == 'group': | 157 if policy_type == 'group': |
122 | 158 |
123 # Groups must not be nested. | 159 # Groups must not be nested. |
124 if not may_contain_groups: | 160 if is_in_group: |
125 self._Error('Policy groups must not be nested.', 'policy', policy) | 161 self._Error('Policy groups must not be nested.', 'policy', policy) |
126 | 162 |
127 # Each policy group must have a list of policies. | 163 # Each policy group must have a list of policies. |
128 policies = self._CheckContains(policy, 'policies', list) | 164 policies = self._CheckContains(policy, 'policies', list) |
165 | |
166 # Check sub-policies. | |
167 self.group_protobuf_ids = set() | |
129 if policies is not None: | 168 if policies is not None: |
130 for nested_policy in policies: | 169 for nested_policy in policies: |
131 self._CheckPolicy(nested_policy, False) | 170 self._CheckPolicy(nested_policy, True) |
171 self._CheckProtobufIDs(self.group_protobuf_ids, policy) | |
132 | 172 |
133 # Statistics. | 173 # Statistics. |
134 self.num_groups += 1 | 174 self.num_groups += 1 |
135 else: # policy_type != group | 175 else: # policy_type != group |
136 | 176 |
137 # Each policy must have a supported_on list. | 177 # Each policy must have a supported_on list. |
138 supported_on = self._CheckContains(policy, 'supported_on', list) | 178 supported_on = self._CheckContains(policy, 'supported_on', list) |
139 if supported_on is not None: | 179 if supported_on is not None: |
140 for s in supported_on: | 180 for s in supported_on: |
141 if not isinstance(s, str): | 181 if not isinstance(s, str): |
142 self._Error('Entries in "supported_on" must be strings.', 'policy', | 182 self._Error('Entries in "supported_on" must be strings.', 'policy', |
143 policy, supported_on) | 183 policy, supported_on) |
144 | 184 |
145 # Each policy must have a 'features' dict. | 185 # Each policy must have a 'features' dict. |
146 self._CheckContains(policy, 'features', dict) | 186 self._CheckContains(policy, 'features', dict) |
147 | 187 |
148 # Each policy must have an 'example_value' of appropriate type. | 188 # Each policy must have an 'example_value' of appropriate type. |
149 if policy_type == 'main': | 189 if policy_type == 'main': |
150 value_type = bool | 190 value_type = bool |
151 elif policy_type in ('string', 'string-enum'): | 191 elif policy_type in ('string', 'string-enum'): |
152 value_type = str | 192 value_type = str |
153 elif policy_type in ('int', 'int-enum'): | 193 elif policy_type in ('int', 'int-enum'): |
154 value_type = int | 194 value_type = int |
155 elif policy_type == 'list': | 195 elif policy_type == 'list': |
156 value_type = list | 196 value_type = list |
157 else: | 197 else: |
158 raise NotImplementedError('Unimplemented policy type: %s' % policy_type) | 198 raise NotImplementedError('Unimplemented policy type: %s' % policy_type) |
159 self._CheckContains(policy, 'example_value', value_type) | 199 self._CheckContains(policy, 'example_value', value_type) |
160 | 200 |
161 # Statistics. | 201 # Statistics. |
162 self.num_policies += 1 | 202 self.num_policies += 1 |
163 if not may_contain_groups: | 203 if is_in_group: |
164 self.num_policies_in_groups += 1 | 204 self.num_policies_in_groups += 1 |
165 | 205 |
166 if policy_type in ('int-enum', 'string-enum'): | 206 if policy_type in ('int-enum', 'string-enum'): |
167 | 207 |
168 # Enums must contain a list of items. | 208 # Enums must contain a list of items. |
169 items = self._CheckContains(policy, 'items', list) | 209 items = self._CheckContains(policy, 'items', list) |
170 if items is not None: | 210 if items is not None: |
171 if len(items) < 1: | 211 if len(items) < 1: |
172 self._Error('"items" must not be empty.', 'policy', policy, items) | 212 self._Error('"items" must not be empty.', 'policy', policy, items) |
173 for item in items: | 213 for item in items: |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
326 self.options = options | 366 self.options = options |
327 | 367 |
328 # First part: check JSON structure. | 368 # First part: check JSON structure. |
329 | 369 |
330 # Check policy definitions. | 370 # Check policy definitions. |
331 policy_definitions = self._CheckContains(data, 'policy_definitions', list, | 371 policy_definitions = self._CheckContains(data, 'policy_definitions', list, |
332 parent_element=None, | 372 parent_element=None, |
333 container_name='The root element', | 373 container_name='The root element', |
334 offending=None) | 374 offending=None) |
335 if policy_definitions is not None: | 375 if policy_definitions is not None: |
376 self.protobuf_ids = set() | |
336 for policy in policy_definitions: | 377 for policy in policy_definitions: |
337 self._CheckPolicy(policy, True) | 378 self._CheckPolicy(policy, False) |
379 self._CheckProtobufIDs(self.protobuf_ids) | |
338 | 380 |
339 # Check (non-policy-specific) message definitions. | 381 # Check (non-policy-specific) message definitions. |
340 messages = self._CheckContains(data, 'messages', dict, | 382 messages = self._CheckContains(data, 'messages', dict, |
341 parent_element=None, | 383 parent_element=None, |
342 container_name='The root element', | 384 container_name='The root element', |
343 offending=None) | 385 offending=None) |
344 if messages is not None: | 386 if messages is not None: |
345 for message in messages: | 387 for message in messages: |
346 self._CheckMessage(message, messages[message]) | 388 self._CheckMessage(message, messages[message]) |
347 | 389 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 if len(args) != 2: | 429 if len(args) != 2: |
388 parser.print_help() | 430 parser.print_help() |
389 sys.exit(1) | 431 sys.exit(1) |
390 filename = args[1] | 432 filename = args[1] |
391 return self.Main(filename, options) | 433 return self.Main(filename, options) |
392 | 434 |
393 | 435 |
394 if __name__ == '__main__': | 436 if __name__ == '__main__': |
395 checker = PolicyTemplateChecker() | 437 checker = PolicyTemplateChecker() |
396 sys.exit(checker.Run(sys.argv)) | 438 sys.exit(checker.Run(sys.argv)) |
OLD | NEW |