| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 |
| 11 import optparse | 11 import optparse |
| 12 import os | 12 import os |
| 13 import re | 13 import re |
| 14 import sys | 14 import sys |
| 15 | 15 |
| 16 | 16 |
| 17 LEADING_WHITESPACE = re.compile('^([ \t]*)') | 17 LEADING_WHITESPACE = re.compile('^([ \t]*)') |
| 18 TRAILING_WHITESPACE = re.compile('.*?([ \t]+)$') | 18 TRAILING_WHITESPACE = re.compile('.*?([ \t]+)$') |
| 19 # Matches all non-empty strings that contain no whitespaces. | 19 # Matches all non-empty strings that contain no whitespaces. |
| 20 NO_WHITESPACE = re.compile('[^\s]+$') | 20 NO_WHITESPACE = re.compile('[^\s]+$') |
| 21 | 21 |
| 22 # Convert a 'type' to its corresponding schema type. |
| 23 TYPE_TO_SCHEMA = { |
| 24 'int': 'integer', |
| 25 'list': 'array', |
| 26 'dict': 'object', |
| 27 'main': 'boolean', |
| 28 'string': 'string', |
| 29 'int-enum': 'integer', |
| 30 'string-enum': 'string', |
| 31 } |
| 22 | 32 |
| 23 class PolicyTemplateChecker(object): | 33 class PolicyTemplateChecker(object): |
| 24 | 34 |
| 25 def __init__(self): | 35 def __init__(self): |
| 26 self.error_count = 0 | 36 self.error_count = 0 |
| 27 self.warning_count = 0 | 37 self.warning_count = 0 |
| 28 self.num_policies = 0 | 38 self.num_policies = 0 |
| 29 self.num_groups = 0 | 39 self.num_groups = 0 |
| 30 self.num_policies_in_groups = 0 | 40 self.num_policies_in_groups = 0 |
| 31 self.options = None | 41 self.options = None |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 ''' | 115 ''' |
| 106 Checks a set of policy_ids to make sure it contains a continuous range | 116 Checks a set of policy_ids to make sure it contains a continuous range |
| 107 of entries (i.e. no holes). | 117 of entries (i.e. no holes). |
| 108 Holes would not be a technical problem, but we want to ensure that nobody | 118 Holes would not be a technical problem, but we want to ensure that nobody |
| 109 accidentally omits IDs. | 119 accidentally omits IDs. |
| 110 ''' | 120 ''' |
| 111 for i in range(len(policy_ids)): | 121 for i in range(len(policy_ids)): |
| 112 if (i + 1) not in policy_ids: | 122 if (i + 1) not in policy_ids: |
| 113 self._Error('No policy with id: %s' % (i + 1)) | 123 self._Error('No policy with id: %s' % (i + 1)) |
| 114 | 124 |
| 125 def _CheckPolicySchema(self, policy, policy_type): |
| 126 '''Checks that the 'schema' field matches the 'type' field.''' |
| 127 self._CheckContains(policy, 'schema', dict) |
| 128 if isinstance(policy.get('schema'), dict): |
| 129 self._CheckContains(policy['schema'], 'type', str) |
| 130 if policy['schema'].get('type') != TYPE_TO_SCHEMA[policy_type]: |
| 131 self._Error('Schema type must match the existing type for policy %s' % |
| 132 policy.get('name')) |
| 133 |
| 115 def _CheckPolicy(self, policy, is_in_group, policy_ids): | 134 def _CheckPolicy(self, policy, is_in_group, policy_ids): |
| 116 if not isinstance(policy, dict): | 135 if not isinstance(policy, dict): |
| 117 self._Error('Each policy must be a dictionary.', 'policy', None, policy) | 136 self._Error('Each policy must be a dictionary.', 'policy', None, policy) |
| 118 return | 137 return |
| 119 | 138 |
| 120 # There should not be any unknown keys in |policy|. | 139 # There should not be any unknown keys in |policy|. |
| 121 for key in policy: | 140 for key in policy: |
| 122 if key not in ('name', 'type', 'caption', 'desc', 'device_only', | 141 if key not in ('name', 'type', 'caption', 'desc', 'device_only', |
| 123 'supported_on', 'label', 'policies', 'items', | 142 'supported_on', 'label', 'policies', 'items', |
| 124 'example_value', 'features', 'deprecated', 'future', | 143 'example_value', 'features', 'deprecated', 'future', |
| 125 'id'): | 144 'id', 'schema'): |
| 126 self.warning_count += 1 | 145 self.warning_count += 1 |
| 127 print ('In policy %s: Warning: Unknown key: %s' % | 146 print ('In policy %s: Warning: Unknown key: %s' % |
| 128 (policy.get('name'), key)) | 147 (policy.get('name'), key)) |
| 129 | 148 |
| 130 # Each policy must have a name. | 149 # Each policy must have a name. |
| 131 self._CheckContains(policy, 'name', str, regexp_check=NO_WHITESPACE) | 150 self._CheckContains(policy, 'name', str, regexp_check=NO_WHITESPACE) |
| 132 | 151 |
| 133 # Each policy must have a type. | 152 # Each policy must have a type. |
| 134 policy_type = self._CheckContains(policy, 'type', str) | 153 policy_type = self._CheckContains(policy, 'type', str) |
| 135 if policy_type not in ('group', 'main', 'string', 'int', 'list', 'int-enum', | 154 if policy_type not in ('group', 'main', 'string', 'int', 'list', 'int-enum', |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 'policy', policy) | 193 'policy', policy) |
| 175 | 194 |
| 176 # Statistics. | 195 # Statistics. |
| 177 self.num_groups += 1 | 196 self.num_groups += 1 |
| 178 else: # policy_type != group | 197 else: # policy_type != group |
| 179 | 198 |
| 180 # Each policy must have a protobuf ID. | 199 # Each policy must have a protobuf ID. |
| 181 id = self._CheckContains(policy, 'id', int) | 200 id = self._CheckContains(policy, 'id', int) |
| 182 self._AddPolicyID(id, policy_ids, policy) | 201 self._AddPolicyID(id, policy_ids, policy) |
| 183 | 202 |
| 203 # 'schema' is the new 'type'. |
| 204 # TODO(joaodasilva): remove the 'type' checks once 'schema' is used |
| 205 # everywhere. |
| 206 self._CheckPolicySchema(policy, policy_type) |
| 207 |
| 184 # Each policy must have a supported_on list. | 208 # Each policy must have a supported_on list. |
| 185 supported_on = self._CheckContains(policy, 'supported_on', list) | 209 supported_on = self._CheckContains(policy, 'supported_on', list) |
| 186 if supported_on is not None: | 210 if supported_on is not None: |
| 187 for s in supported_on: | 211 for s in supported_on: |
| 188 if not isinstance(s, str): | 212 if not isinstance(s, str): |
| 189 self._Error('Entries in "supported_on" must be strings.', 'policy', | 213 self._Error('Entries in "supported_on" must be strings.', 'policy', |
| 190 policy, supported_on) | 214 policy, supported_on) |
| 191 | 215 |
| 192 # Each policy must have a 'features' dict. | 216 # Each policy must have a 'features' dict. |
| 193 self._CheckContains(policy, 'features', dict) | 217 self._CheckContains(policy, 'features', dict) |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 if filename is None: | 434 if filename is None: |
| 411 if len(args) != 2: | 435 if len(args) != 2: |
| 412 parser.print_help() | 436 parser.print_help() |
| 413 sys.exit(1) | 437 sys.exit(1) |
| 414 filename = args[1] | 438 filename = args[1] |
| 415 return self.Main(filename, options) | 439 return self.Main(filename, options) |
| 416 | 440 |
| 417 | 441 |
| 418 if __name__ == '__main__': | 442 if __name__ == '__main__': |
| 419 sys.exit(PolicyTemplateChecker().Run(sys.argv)) | 443 sys.exit(PolicyTemplateChecker().Run(sys.argv)) |
| OLD | NEW |