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 _AddPolicyID(self, id, policy_ids, policy): |
85 ''' | |
86 Adds |id| to |policy_ids|. Generates an error message if the | |
87 |id| exists already; |policy| is needed for this message. | |
88 ''' | |
89 if id in policy_ids: | |
90 self._Error('Duplicate id', 'policy', policy.get('name'), | |
91 id) | |
92 else: | |
93 policy_ids.add(id) | |
94 | |
95 def _CheckPolicyIDs(self, policy_ids): | |
96 ''' | |
97 Checks a set of policy_ids to make sure it contains a continuous range | |
98 of entries (i.e. no holes). | |
99 Holes would not be a technical problem, but we want to ensure that nobody | |
100 accidentally omits IDs. | |
101 ''' | |
102 for i in range(len(policy_ids)): | |
103 if (i + 1) not in policy_ids: | |
104 self._Error('No policy with id: %s' % (i + 1)) | |
105 | |
106 def _CheckPolicy(self, policy, is_in_group, policy_ids): | |
85 if not isinstance(policy, dict): | 107 if not isinstance(policy, dict): |
86 self._Error('Each policy must be a dictionary.', 'policy', None, policy) | 108 self._Error('Each policy must be a dictionary.', 'policy', None, policy) |
87 return | 109 return |
88 | 110 |
89 # There should not be any unknown keys in |policy|. | 111 # There should not be any unknown keys in |policy|. |
90 for key in policy: | 112 for key in policy: |
91 if key not in ('name', 'type', 'caption', 'desc', 'supported_on', | 113 if key not in ('name', 'type', 'caption', 'desc', 'supported_on', |
92 'label', 'policies', 'items', 'example_value', 'features', | 114 'label', 'policies', 'items', 'example_value', 'features', |
93 'deprecated', 'future'): | 115 'deprecated', 'future', 'id'): |
94 self.warning_count += 1 | 116 self.warning_count += 1 |
95 print ('In policy %s: Warning: Unknown key: %s' % | 117 print ('In policy %s: Warning: Unknown key: %s' % |
96 (policy.get('name'), key)) | 118 (policy.get('name'), key)) |
97 | 119 |
98 # Each policy must have a name. | 120 # Each policy must have a name. |
99 self._CheckContains(policy, 'name', str) | 121 self._CheckContains(policy, 'name', str) |
100 | 122 |
101 # Each policy must have a type. | 123 # Each policy must have a type. |
102 policy_type = self._CheckContains(policy, 'type', str) | 124 policy_type = self._CheckContains(policy, 'type', str) |
103 if policy_type not in ('group', 'main', 'string', 'int', 'list', 'int-enum', | 125 if policy_type not in ('group', 'main', 'string', 'int', 'list', 'int-enum', |
(...skipping 13 matching lines...) Expand all Loading... | |
117 | 139 |
118 # If 'deprecated' is present, it must be a bool. | 140 # If 'deprecated' is present, it must be a bool. |
119 self._CheckContains(policy, 'deprecated', bool, True) | 141 self._CheckContains(policy, 'deprecated', bool, True) |
120 | 142 |
121 # If 'future' is present, it must be a bool. | 143 # If 'future' is present, it must be a bool. |
122 self._CheckContains(policy, 'future', bool, True) | 144 self._CheckContains(policy, 'future', bool, True) |
123 | 145 |
124 if policy_type == 'group': | 146 if policy_type == 'group': |
125 | 147 |
126 # Groups must not be nested. | 148 # Groups must not be nested. |
127 if not may_contain_groups: | 149 if is_in_group: |
danno
2011/02/11 11:00:42
Check that there are no ids in the group?
Jakob Kummerow
2011/02/14 16:14:26
Done.
| |
128 self._Error('Policy groups must not be nested.', 'policy', policy) | 150 self._Error('Policy groups must not be nested.', 'policy', policy) |
129 | 151 |
130 # Each policy group must have a list of policies. | 152 # Each policy group must have a list of policies. |
131 policies = self._CheckContains(policy, 'policies', list) | 153 policies = self._CheckContains(policy, 'policies', list) |
154 | |
155 # Check sub-policies. | |
132 if policies is not None: | 156 if policies is not None: |
133 for nested_policy in policies: | 157 for nested_policy in policies: |
134 self._CheckPolicy(nested_policy, False) | 158 self._CheckPolicy(nested_policy, True, policy_ids) |
135 | 159 |
136 # Statistics. | 160 # Statistics. |
137 self.num_groups += 1 | 161 self.num_groups += 1 |
138 else: # policy_type != group | 162 else: # policy_type != group |
139 | 163 |
164 # Each policy must have a protobuf ID. | |
165 id = self._CheckContains(policy, 'id', int) | |
166 self._AddPolicyID(id, policy_ids, policy) | |
167 | |
140 # Each policy must have a supported_on list. | 168 # Each policy must have a supported_on list. |
141 supported_on = self._CheckContains(policy, 'supported_on', list) | 169 supported_on = self._CheckContains(policy, 'supported_on', list) |
142 if supported_on is not None: | 170 if supported_on is not None: |
143 for s in supported_on: | 171 for s in supported_on: |
144 if not isinstance(s, str): | 172 if not isinstance(s, str): |
145 self._Error('Entries in "supported_on" must be strings.', 'policy', | 173 self._Error('Entries in "supported_on" must be strings.', 'policy', |
146 policy, supported_on) | 174 policy, supported_on) |
147 | 175 |
148 # Each policy must have a 'features' dict. | 176 # Each policy must have a 'features' dict. |
149 self._CheckContains(policy, 'features', dict) | 177 self._CheckContains(policy, 'features', dict) |
150 | 178 |
151 # Each policy must have an 'example_value' of appropriate type. | 179 # Each policy must have an 'example_value' of appropriate type. |
152 if policy_type == 'main': | 180 if policy_type == 'main': |
153 value_type = bool | 181 value_type = bool |
154 elif policy_type in ('string', 'string-enum'): | 182 elif policy_type in ('string', 'string-enum'): |
155 value_type = str | 183 value_type = str |
156 elif policy_type in ('int', 'int-enum'): | 184 elif policy_type in ('int', 'int-enum'): |
157 value_type = int | 185 value_type = int |
158 elif policy_type == 'list': | 186 elif policy_type == 'list': |
159 value_type = list | 187 value_type = list |
160 else: | 188 else: |
161 raise NotImplementedError('Unimplemented policy type: %s' % policy_type) | 189 raise NotImplementedError('Unimplemented policy type: %s' % policy_type) |
162 self._CheckContains(policy, 'example_value', value_type) | 190 self._CheckContains(policy, 'example_value', value_type) |
163 | 191 |
164 # Statistics. | 192 # Statistics. |
165 self.num_policies += 1 | 193 self.num_policies += 1 |
166 if not may_contain_groups: | 194 if is_in_group: |
167 self.num_policies_in_groups += 1 | 195 self.num_policies_in_groups += 1 |
168 | 196 |
169 if policy_type in ('int-enum', 'string-enum'): | 197 if policy_type in ('int-enum', 'string-enum'): |
170 | 198 |
171 # Enums must contain a list of items. | 199 # Enums must contain a list of items. |
172 items = self._CheckContains(policy, 'items', list) | 200 items = self._CheckContains(policy, 'items', list) |
173 if items is not None: | 201 if items is not None: |
174 if len(items) < 1: | 202 if len(items) < 1: |
175 self._Error('"items" must not be empty.', 'policy', policy, items) | 203 self._Error('"items" must not be empty.', 'policy', policy, items) |
176 for item in items: | 204 for item in items: |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
329 self.options = options | 357 self.options = options |
330 | 358 |
331 # First part: check JSON structure. | 359 # First part: check JSON structure. |
332 | 360 |
333 # Check policy definitions. | 361 # Check policy definitions. |
334 policy_definitions = self._CheckContains(data, 'policy_definitions', list, | 362 policy_definitions = self._CheckContains(data, 'policy_definitions', list, |
335 parent_element=None, | 363 parent_element=None, |
336 container_name='The root element', | 364 container_name='The root element', |
337 offending=None) | 365 offending=None) |
338 if policy_definitions is not None: | 366 if policy_definitions is not None: |
367 policy_ids = set() | |
339 for policy in policy_definitions: | 368 for policy in policy_definitions: |
340 self._CheckPolicy(policy, True) | 369 self._CheckPolicy(policy, False, policy_ids) |
370 self._CheckPolicyIDs(policy_ids) | |
341 | 371 |
342 # Check (non-policy-specific) message definitions. | 372 # Check (non-policy-specific) message definitions. |
343 messages = self._CheckContains(data, 'messages', dict, | 373 messages = self._CheckContains(data, 'messages', dict, |
344 parent_element=None, | 374 parent_element=None, |
345 container_name='The root element', | 375 container_name='The root element', |
346 offending=None) | 376 offending=None) |
347 if messages is not None: | 377 if messages is not None: |
348 for message in messages: | 378 for message in messages: |
349 self._CheckMessage(message, messages[message]) | 379 self._CheckMessage(message, messages[message]) |
350 | 380 |
351 # Check placeholders. | 381 # Check placeholders. |
352 placeholders = self._CheckContains(data, 'placeholders', list, | 382 placeholders = self._CheckContains(data, 'placeholders', list, |
353 parent_element=None, | 383 parent_element=None, |
354 container_name='The root element', | 384 container_name='The root element', |
355 offending=None) | 385 offending=None) |
356 if placeholders is not None: | 386 if placeholders is not None: |
357 for placeholder in placeholders: | 387 for placeholder in placeholders: |
358 self._CheckPlaceholder(placeholder) | 388 self._CheckPlaceholder(placeholder) |
359 | 389 |
360 # Second part: check formatting. | 390 # Second part: check formatting. |
361 self._CheckFormat(filename) | 391 self._CheckFormat(filename) |
362 | 392 |
363 # Third part: summary and exit. | 393 # Third part: summary and exit. |
364 print ('Finished. %d errors, %d warnings.' % | 394 print ('Finished checking %s. %d errors, %d warnings.' % |
365 (self.error_count, self.warning_count)) | 395 (filename, self.error_count, self.warning_count)) |
366 if self.options.stats: | 396 if self.options.stats: |
367 if self.num_groups > 0: | 397 if self.num_groups > 0: |
368 print ('%d policies, %d of those in %d groups (containing on ' | 398 print ('%d policies, %d of those in %d groups (containing on ' |
369 'average %.1f policies).' % | 399 'average %.1f policies).' % |
370 (self.num_policies, self.num_policies_in_groups, self.num_groups, | 400 (self.num_policies, self.num_policies_in_groups, self.num_groups, |
371 (1.0 * self.num_policies_in_groups / self.num_groups))) | 401 (1.0 * self.num_policies_in_groups / self.num_groups))) |
372 else: | 402 else: |
373 print self.num_policies, 'policies, 0 policy groups.' | 403 print self.num_policies, 'policies, 0 policy groups.' |
374 if self.error_count > 0: | 404 if self.error_count > 0: |
375 return 1 | 405 return 1 |
(...skipping 14 matching lines...) Expand all Loading... | |
390 if len(args) != 2: | 420 if len(args) != 2: |
391 parser.print_help() | 421 parser.print_help() |
392 sys.exit(1) | 422 sys.exit(1) |
393 filename = args[1] | 423 filename = args[1] |
394 return self.Main(filename, options) | 424 return self.Main(filename, options) |
395 | 425 |
396 | 426 |
397 if __name__ == '__main__': | 427 if __name__ == '__main__': |
398 checker = PolicyTemplateChecker() | 428 checker = PolicyTemplateChecker() |
399 sys.exit(checker.Run(sys.argv)) | 429 sys.exit(checker.Run(sys.argv)) |
OLD | NEW |