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