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 _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 |