Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: components/policy/tools/generate_policy_source.py

Issue 228423002: Add $ref support to policy schema (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@policy-schema-regex
Patch Set: Use GetKnownProperty() in new tests Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698