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 |