Chromium Code Reviews| Index: components/policy/tools/generate_policy_source.py |
| diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py |
| index 9ccf881d17137a2ecd5b98f6e3ea77f21a44cda8..6f9b1f643a4ae764e8f1f656a371afb7123d7a22 100755 |
| --- a/components/policy/tools/generate_policy_source.py |
| +++ b/components/policy/tools/generate_policy_source.py |
| @@ -11,11 +11,13 @@ chromium_os_flag should be 1 if this is a Chromium OS build |
| template is the path to a .json policy template file.''' |
| from __future__ import with_statement |
| +from functools import partial |
| import json |
| from optparse import OptionParser |
| import re |
| import sys |
| import textwrap |
| +import types |
| CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome' |
| @@ -282,6 +284,7 @@ class SchemaNodesGenerator: |
| } |
| self.stringlist_type = None |
| self.ranges = {} |
| + self.id_map = {} |
| def GetString(self, s): |
| if s in self.shared_strings: |
| @@ -398,6 +401,12 @@ class SchemaNodesGenerator: |
| |schema|: a valid JSON schema in a dictionary. |
| |name|: the name of the current node, for the generated comments.""" |
| + if schema.has_key('$ref'): |
| + if schema.has_key('id'): |
| + raise RuntimeError("Schemas with a $ref can't have an id") |
| + if not isinstance(schema['$ref'], types.StringTypes): |
| + raise RuntimeError("$ref attribute must be a string") |
| + return schema['$ref'] |
| if schema['type'] in self.simple_types: |
| if not self.SchemaHaveRestriction(schema): |
| # Simple types use shared nodes. |
| @@ -413,9 +422,8 @@ class SchemaNodesGenerator: |
| # Special case for lists of strings, which is a common policy type. |
| if schema['items']['type'] == 'string': |
| return self.GetStringList() |
| - return self.AppendSchema( |
| - 'TYPE_LIST', |
| - self.Generate(schema['items'], 'items of ' + name)) |
| + return self.AppendSchema('TYPE_LIST', |
| + self.GenerateAndCollectID(schema['items'], 'items of ' + name)) |
| elif schema['type'] == 'object': |
| # Reserve an index first, so that dictionaries come before their |
| # properties. This makes sure that the root node is the first in the |
| @@ -423,7 +431,7 @@ class SchemaNodesGenerator: |
| index = self.AppendSchema('TYPE_DICTIONARY', -1) |
| if 'additionalProperties' in schema: |
| - additionalProperties = self.Generate( |
| + additionalProperties = self.GenerateAndCollectID( |
| schema['additionalProperties'], |
| 'additionalProperties of ' + name) |
| else: |
| @@ -434,13 +442,14 @@ class SchemaNodesGenerator: |
| # recursive calls to Generate() append the necessary child nodes; if |
| # |properties| were a generator then this wouldn't work. |
| sorted_properties = sorted(schema.get('properties', {}).items()) |
| - properties = [ (self.GetString(key), self.Generate(subschema, key)) |
| - for key, subschema in sorted_properties ] |
| + properties = [ (self.GetString(key), |
| + self.GenerateAndCollectID(subschema, key)) |
|
Joao da Silva
2014/04/09 12:34:55
I think it's more readable if the tuple is all in
binjin
2014/04/09 14:09:59
Done.
|
| + for key, subschema in sorted_properties ] |
| pattern_properties = [] |
| for pattern, subschema in schema.get('patternProperties', {}).items(): |
| pattern_properties.append((self.GetString(pattern), |
| - self.Generate(subschema, pattern))); |
| + self.GenerateAndCollectID(subschema, pattern))); |
| begin = len(self.property_nodes) |
| self.property_nodes += properties |
| @@ -462,6 +471,20 @@ class SchemaNodesGenerator: |
| else: |
| assert False |
| + def GenerateAndCollectID(self, schema, name): |
| + """A wrapper of Generate(), will take the return value, check and add 'id' |
| + attribute to self.id_map. This wrapper need to be used for every call to |
|
Joao da Silva
2014/04/09 12:34:55
This wrapper needs
binjin
2014/04/09 14:09:59
Done.
|
| + Generate(). |
| + """ |
| + index = self.Generate(schema, name) |
| + if not schema.has_key('id'): |
| + return index |
| + id_str = schema['id'] |
| + if self.id_map.has_key(id_str): |
| + raise RuntimeError('Duplicated id: ' + id_str) |
| + self.id_map[id_str] = index |
| + return index |
| + |
| def Write(self, f): |
| """Writes the generated structs to the given file. |
| @@ -516,6 +539,31 @@ class SchemaNodesGenerator: |
| f.write(' kStringEnumerations,\n' if self.string_enums else ' NULL,\n') |
| f.write('};\n\n') |
| + def GetByID(self, id_str): |
| + if not isinstance(id_str, types.StringTypes): |
| + return id_str |
| + if not self.id_map.has_key(id_str): |
| + raise RuntimeError('Invalid $ref: ' + id_str) |
| + return self.id_map[id_str] |
| + |
| + def ResolveID(self, index, params): |
| + lst = list(params) |
| + lst[index] = self.GetByID(lst[index]) |
| + return tuple(lst) |
|
Joao da Silva
2014/04/09 12:34:55
Suggestion:
def ResolveID(self, index, params):
binjin
2014/04/09 14:09:59
Done.
|
| + |
| + def ResolveReferences(self): |
| + """Resolve reference mapping, required to be called after Generate() |
| + |
| + After calling Generate(), the type of indices used in schema structures |
| + might be either int or string. An int type suggest that it's a resolved |
|
Joao da Silva
2014/04/09 12:34:55
suggests
binjin
2014/04/09 14:09:59
Done.
|
| + index, but for string type it's unresolved. Resolving a reference is as |
| + simple as looking up for corresponding ID in self.id_map, and replace the |
| + old index with the mapped index. |
| + """ |
| + self.schema_nodes = map(partial(self.ResolveID, 1), self.schema_nodes) |
| + self.property_nodes = map(partial(self.ResolveID, 1), self.property_nodes) |
| + self.properties_nodes = map(partial(self.ResolveID, 3), |
| + self.properties_nodes) |
| def _WritePolicyConstantSource(policies, os, f): |
| f.write('#include "policy/policy_constants.h"\n' |
| @@ -558,7 +606,8 @@ def _WritePolicyConstantSource(policies, os, f): |
| f.write('};\n\n') |
| schema_generator = SchemaNodesGenerator(shared_strings) |
| - schema_generator.Generate(chrome_schema, 'root node') |
| + schema_generator.GenerateAndCollectID(chrome_schema, 'root node') |
| + schema_generator.ResolveReferences() |
| schema_generator.Write(f) |
| f.write('bool CompareKeys(const internal::PropertyNode& node,\n' |