Chromium Code Reviews| 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 '''python %prog [options] platform chromium_os_flag template | 6 '''python %prog [options] platform chromium_os_flag template |
| 7 | 7 |
| 8 platform specifies which platform source is being generated for | 8 platform specifies which platform source is being generated for |
| 9 and can be one of (win, mac, linux) | 9 and can be one of (win, mac, linux) |
| 10 chromium_os_flag should be 1 if this is a Chromium OS build | 10 chromium_os_flag should be 1 if this is a Chromium OS build |
| 11 template is the path to a .json policy template file.''' | 11 template is the path to a .json policy template file.''' |
| 12 | 12 |
| 13 from __future__ import with_statement | 13 from __future__ import with_statement |
| 14 import json | 14 import json |
| 15 from optparse import OptionParser | 15 from optparse import OptionParser |
| 16 import re | 16 import re |
| 17 import sys | 17 import sys |
| 18 import textwrap | 18 import textwrap |
| 19 import types | |
| 19 | 20 |
| 20 | 21 |
| 21 CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome' | 22 CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome' |
| 22 CHROMIUM_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Chromium' | 23 CHROMIUM_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Chromium' |
| 23 | 24 |
| 24 | 25 |
| 25 class PolicyDetails: | 26 class PolicyDetails: |
| 26 """Parses a policy template and caches all its details.""" | 27 """Parses a policy template and caches all its details.""" |
| 27 | 28 |
| 28 # Maps policy types to a tuple with 3 other types: | 29 # Maps policy types to a tuple with 3 other types: |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 self.string_enums = [] | 276 self.string_enums = [] |
| 276 self.simple_types = { | 277 self.simple_types = { |
| 277 'boolean': None, | 278 'boolean': None, |
| 278 'integer': None, | 279 'integer': None, |
| 279 'null': None, | 280 'null': None, |
| 280 'number': None, | 281 'number': None, |
| 281 'string': None, | 282 'string': None, |
| 282 } | 283 } |
| 283 self.stringlist_type = None | 284 self.stringlist_type = None |
| 284 self.ranges = {} | 285 self.ranges = {} |
| 286 self.id_map = {} | |
| 285 | 287 |
| 286 def GetString(self, s): | 288 def GetString(self, s): |
| 287 if s in self.shared_strings: | 289 if s in self.shared_strings: |
| 288 return self.shared_strings[s] | 290 return self.shared_strings[s] |
| 289 # Generate JSON escaped string, which is slightly different from desired | 291 # Generate JSON escaped string, which is slightly different from desired |
| 290 # C/C++ escaped string. Known differences includes unicode escaping format. | 292 # C/C++ escaped string. Known differences includes unicode escaping format. |
| 291 return json.dumps(s) | 293 return json.dumps(s) |
| 292 | 294 |
| 293 def AppendSchema(self, type, extra, comment=''): | 295 def AppendSchema(self, type, extra, comment=''): |
| 294 index = len(self.schema_nodes) | 296 index = len(self.schema_nodes) |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 str(min_value) if min_value_set else 'INT_MIN') | 393 str(min_value) if min_value_set else 'INT_MIN') |
| 392 return self.AppendSchema('TYPE_INTEGER', | 394 return self.AppendSchema('TYPE_INTEGER', |
| 393 index, | 395 index, |
| 394 'integer with ranged restriction: %s' % name) | 396 'integer with ranged restriction: %s' % name) |
| 395 | 397 |
| 396 def Generate(self, schema, name): | 398 def Generate(self, schema, name): |
| 397 """Generates the structs for the given schema. | 399 """Generates the structs for the given schema. |
| 398 | 400 |
| 399 |schema|: a valid JSON schema in a dictionary. | 401 |schema|: a valid JSON schema in a dictionary. |
| 400 |name|: the name of the current node, for the generated comments.""" | 402 |name|: the name of the current node, for the generated comments.""" |
| 403 if schema.has_key('$ref'): | |
| 404 if schema.has_key('id'): | |
| 405 raise RuntimeError("Schemas with a $ref can't have an id") | |
| 406 return schema['$ref'] | |
| 401 if schema['type'] in self.simple_types: | 407 if schema['type'] in self.simple_types: |
| 402 if not self.SchemaHaveRestriction(schema): | 408 if not self.SchemaHaveRestriction(schema): |
| 403 # Simple types use shared nodes. | 409 # Simple types use shared nodes. |
| 404 return self.GetSimpleType(schema['type']) | 410 return self.CheckID(schema, self.GetSimpleType(schema['type'])) |
|
Joao da Silva
2014/04/08 15:02:10
I think adding CheckID() in the right places is ha
binjin
2014/04/09 11:00:36
Done.
| |
| 405 elif 'enum' in schema: | 411 elif 'enum' in schema: |
| 406 return self.GetEnumType(schema, name) | 412 return self.CheckID(schema, self.GetEnumType(schema, name)) |
| 407 elif 'pattern' in schema: | 413 elif 'pattern' in schema: |
| 408 return self.GetPatternType(schema, name) | 414 return self.CheckID(schema, self.GetPatternType(schema, name)) |
| 409 else: | 415 else: |
| 410 return self.GetRangedType(schema, name) | 416 return self.CheckID(schema, self.GetRangedType(schema, name)) |
| 411 | 417 |
| 412 if schema['type'] == 'array': | 418 if schema['type'] == 'array': |
| 413 # Special case for lists of strings, which is a common policy type. | 419 # Special case for lists of strings, which is a common policy type. |
| 414 if schema['items']['type'] == 'string': | 420 if schema['items']['type'] == 'string': |
| 415 return self.GetStringList() | 421 return self.CheckID(schema, self.GetStringList()) |
| 416 return self.AppendSchema( | 422 return self.CheckID(schema, self.AppendSchema( |
| 417 'TYPE_LIST', | 423 'TYPE_LIST', |
| 418 self.Generate(schema['items'], 'items of ' + name)) | 424 self.Generate(schema['items'], 'items of ' + name))) |
| 419 elif schema['type'] == 'object': | 425 elif schema['type'] == 'object': |
| 420 # Reserve an index first, so that dictionaries come before their | 426 # Reserve an index first, so that dictionaries come before their |
| 421 # properties. This makes sure that the root node is the first in the | 427 # properties. This makes sure that the root node is the first in the |
| 422 # SchemaNodes array. | 428 # SchemaNodes array. |
| 423 index = self.AppendSchema('TYPE_DICTIONARY', -1) | 429 index = self.AppendSchema('TYPE_DICTIONARY', -1) |
| 424 | 430 |
| 425 if 'additionalProperties' in schema: | 431 if 'additionalProperties' in schema: |
| 426 additionalProperties = self.Generate( | 432 additionalProperties = self.Generate( |
| 427 schema['additionalProperties'], | 433 schema['additionalProperties'], |
| 428 'additionalProperties of ' + name) | 434 'additionalProperties of ' + name) |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 451 if index == 0: | 457 if index == 0: |
| 452 self.root_properties_begin = begin | 458 self.root_properties_begin = begin |
| 453 self.root_properties_end = end | 459 self.root_properties_end = end |
| 454 | 460 |
| 455 extra = len(self.properties_nodes) | 461 extra = len(self.properties_nodes) |
| 456 self.properties_nodes.append((begin, end, pattern_end, | 462 self.properties_nodes.append((begin, end, pattern_end, |
| 457 additionalProperties, name)) | 463 additionalProperties, name)) |
| 458 | 464 |
| 459 # Set the right data at |index| now. | 465 # Set the right data at |index| now. |
| 460 self.schema_nodes[index] = ('TYPE_DICTIONARY', extra, name) | 466 self.schema_nodes[index] = ('TYPE_DICTIONARY', extra, name) |
| 461 return index | 467 return self.CheckID(schema, index) |
| 462 else: | 468 else: |
| 463 assert False | 469 assert False |
| 464 | 470 |
| 465 def Write(self, f): | 471 def Write(self, f): |
| 466 """Writes the generated structs to the given file. | 472 """Writes the generated structs to the given file. |
| 467 | 473 |
| 468 |f| an open file to write to.""" | 474 |f| an open file to write to.""" |
| 469 f.write('const internal::SchemaNode kSchemas[] = {\n' | 475 f.write('const internal::SchemaNode kSchemas[] = {\n' |
| 470 '// Type Extra\n') | 476 '// Type Extra\n') |
| 471 for type, extra, comment in self.schema_nodes: | 477 for type, extra, comment in self.schema_nodes: |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 509 | 515 |
| 510 f.write('const internal::SchemaData kChromeSchemaData = {\n' | 516 f.write('const internal::SchemaData kChromeSchemaData = {\n' |
| 511 ' kSchemas,\n') | 517 ' kSchemas,\n') |
| 512 f.write(' kPropertyNodes,\n' if self.property_nodes else ' NULL,\n') | 518 f.write(' kPropertyNodes,\n' if self.property_nodes else ' NULL,\n') |
| 513 f.write(' kProperties,\n' if self.properties_nodes else ' NULL,\n') | 519 f.write(' kProperties,\n' if self.properties_nodes else ' NULL,\n') |
| 514 f.write(' kRestrictionNodes,\n' if self.restriction_nodes else ' NULL,\n') | 520 f.write(' kRestrictionNodes,\n' if self.restriction_nodes else ' NULL,\n') |
| 515 f.write(' kIntegerEnumerations,\n' if self.int_enums else ' NULL,\n') | 521 f.write(' kIntegerEnumerations,\n' if self.int_enums else ' NULL,\n') |
| 516 f.write(' kStringEnumerations,\n' if self.string_enums else ' NULL,\n') | 522 f.write(' kStringEnumerations,\n' if self.string_enums else ' NULL,\n') |
| 517 f.write('};\n\n') | 523 f.write('};\n\n') |
| 518 | 524 |
| 525 def CheckID(self, schema, index): | |
| 526 """Check and add 'id' attribute to id_map | |
| 527 | |
| 528 |schema|: target JSON schema that might come with 'id' attribute | |
| 529 |index|: index for parsed |schema|, like the one returned by Generate() | |
| 530 """ | |
| 531 if not schema.has_key('id'): | |
| 532 return index | |
| 533 id_str = schema['id'] | |
| 534 if self.id_map.has_key(id_str): | |
| 535 raise RuntimeError('Duplicated id: ' + id_str) | |
| 536 self.id_map[id_str] = index | |
| 537 return index | |
| 538 | |
| 539 def ResolveReference(self): | |
|
Joao da Silva
2014/04/08 15:02:10
ResolveReferences
binjin
2014/04/09 11:00:36
Done.
| |
| 540 """ Resolve reference mapping, required to be called after Generate() | |
|
Joao da Silva
2014/04/08 15:02:10
Remove the space after """
binjin
2014/04/09 11:00:36
Done.
| |
| 541 | |
| 542 After calling Generate(), the type of indices used in schema structures | |
| 543 might be either int or string. An int type suggest that it's a resolved | |
| 544 index, but for string type it's unresolved. Resolving a reference is as | |
| 545 simple as looking up for corresponding index in self.id_map, and replace the | |
|
Joao da Silva
2014/04/08 15:02:10
corresponding ID
binjin
2014/04/09 11:00:36
Done.
| |
| 546 old index with it. | |
|
Joao da Silva
2014/04/08 15:02:10
old index with the mapped index.
binjin
2014/04/09 11:00:36
Done.
| |
| 547 """ | |
| 548 for i in xrange(len(self.schema_nodes)): | |
| 549 (type, extra, comment) = self.schema_nodes[i] | |
| 550 if isinstance(extra, types.StringTypes): | |
| 551 self.schema_nodes[i] = (type, self.GetByID(extra), comment) | |
| 552 for i in xrange(len(self.property_nodes)): | |
| 553 (key, schema) = self.property_nodes[i] | |
| 554 if isinstance(schema, types.StringTypes): | |
| 555 self.property_nodes[i] = (key, self.GetByID(schema)) | |
| 556 for i in xrange(len(self.properties_nodes)): | |
| 557 (begin, end, pattern_end, additional, name) = self.properties_nodes[i] | |
| 558 if isinstance(additional, types.StringTypes): | |
| 559 self.properties_nodes[i] = (begin, end, pattern_end, | |
| 560 self.GetByID(additional), name) | |
|
Joao da Silva
2014/04/08 15:02:10
This is a bit more complicated than it needs to be
binjin
2014/04/09 11:00:36
Done.
| |
| 561 | |
| 562 def GetByID(self, id_str): | |
| 563 if not self.id_map.has_key(id_str): | |
| 564 raise RuntimeError('Invalid $ref: ' + id_str) | |
| 565 return self.id_map[id_str] | |
| 566 | |
| 519 | 567 |
| 520 def _WritePolicyConstantSource(policies, os, f): | 568 def _WritePolicyConstantSource(policies, os, f): |
| 521 f.write('#include "policy/policy_constants.h"\n' | 569 f.write('#include "policy/policy_constants.h"\n' |
| 522 '\n' | 570 '\n' |
| 523 '#include <algorithm>\n' | 571 '#include <algorithm>\n' |
| 524 '#include <climits>\n' | 572 '#include <climits>\n' |
| 525 '\n' | 573 '\n' |
| 526 '#include "base/logging.h"\n' | 574 '#include "base/logging.h"\n' |
| 527 '#include "components/policy/core/common/schema_internal.h"\n' | 575 '#include "components/policy/core/common/schema_internal.h"\n' |
| 528 '\n' | 576 '\n' |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 552 if policy.is_supported: | 600 if policy.is_supported: |
| 553 f.write(' { %-14s %-16s %3s, %24s },\n' % ( | 601 f.write(' { %-14s %-16s %3s, %24s },\n' % ( |
| 554 'true,' if policy.is_deprecated else 'false,', | 602 'true,' if policy.is_deprecated else 'false,', |
| 555 'true,' if policy.is_device_only else 'false,', | 603 'true,' if policy.is_device_only else 'false,', |
| 556 policy.id, | 604 policy.id, |
| 557 policy.max_size)) | 605 policy.max_size)) |
| 558 f.write('};\n\n') | 606 f.write('};\n\n') |
| 559 | 607 |
| 560 schema_generator = SchemaNodesGenerator(shared_strings) | 608 schema_generator = SchemaNodesGenerator(shared_strings) |
| 561 schema_generator.Generate(chrome_schema, 'root node') | 609 schema_generator.Generate(chrome_schema, 'root node') |
| 610 schema_generator.ResolveReference() | |
| 562 schema_generator.Write(f) | 611 schema_generator.Write(f) |
| 563 | 612 |
| 564 f.write('bool CompareKeys(const internal::PropertyNode& node,\n' | 613 f.write('bool CompareKeys(const internal::PropertyNode& node,\n' |
| 565 ' const std::string& key) {\n' | 614 ' const std::string& key) {\n' |
| 566 ' return node.key < key;\n' | 615 ' return node.key < key;\n' |
| 567 '}\n\n') | 616 '}\n\n') |
| 568 | 617 |
| 569 f.write('} // namespace\n\n') | 618 f.write('} // namespace\n\n') |
| 570 | 619 |
| 571 if os == 'win': | 620 if os == 'win': |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 870 def _WriteCloudPolicyDecoder(policies, os, f): | 919 def _WriteCloudPolicyDecoder(policies, os, f): |
| 871 f.write(CPP_HEAD) | 920 f.write(CPP_HEAD) |
| 872 for policy in policies: | 921 for policy in policies: |
| 873 if policy.is_supported and not policy.is_device_only: | 922 if policy.is_supported and not policy.is_device_only: |
| 874 _WritePolicyCode(f, policy) | 923 _WritePolicyCode(f, policy) |
| 875 f.write(CPP_FOOT) | 924 f.write(CPP_FOOT) |
| 876 | 925 |
| 877 | 926 |
| 878 if __name__ == '__main__': | 927 if __name__ == '__main__': |
| 879 sys.exit(main()) | 928 sys.exit(main()) |
| OLD | NEW |