Chromium Code Reviews| Index: chrome/tools/build/generate_policy_source.py |
| diff --git a/chrome/tools/build/generate_policy_source.py b/chrome/tools/build/generate_policy_source.py |
| index d88374d173342f98a96c3f951e641c090256ae58..9ac971e04b5acc8d0e84efba6b5cf48ffd34b7d2 100755 |
| --- a/chrome/tools/build/generate_policy_source.py |
| +++ b/chrome/tools/build/generate_policy_source.py |
| @@ -53,6 +53,7 @@ class PolicyDetails: |
| self.name = policy['name'] |
| self.is_deprecated = policy.get('deprecated', False) |
| self.is_device_only = policy.get('device_only', False) |
| + self.schema = policy.get('schema', {}) |
| if is_chromium_os: |
| expected_platform = 'chrome_os' |
| @@ -216,7 +217,11 @@ def _WritePolicyConstantHeader(policies, os, f): |
| '#include "base/basictypes.h"\n' |
| '#include "base/values.h"\n' |
| '\n' |
| - 'namespace policy {\n\n') |
| + 'namespace policy {\n' |
| + '\n' |
| + 'namespace internal {\n' |
| + 'struct SchemaData;\n' |
| + '}\n\n') |
| if os == 'win': |
| f.write('// The windows registry path where Chrome policy ' |
| @@ -243,7 +248,11 @@ def _WritePolicyConstantHeader(policies, os, f): |
| 'bool IsDeprecatedPolicy(const std::string& policy);\n' |
| '\n' |
| '// Returns the default policy definition list for Chrome.\n' |
| - 'const PolicyDefinitionList* GetChromePolicyDefinitionList();\n\n') |
| + 'const PolicyDefinitionList* GetChromePolicyDefinitionList();\n' |
| + '\n' |
| + '// Returns the schema data of the Chrome policy schema.\n' |
| + 'const internal::SchemaData* GetChromeSchemaData();\n' |
| + '\n') |
| f.write('// Key names for the policy settings.\n' |
| 'namespace key {\n\n') |
| for policy in policies: |
| @@ -263,14 +272,165 @@ def _GetValueType(policy_type): |
| return policy_type if policy_type != 'TYPE_EXTERNAL' else 'TYPE_DICTIONARY' |
| +# A mapping of the simple schema types to base::Value::Types. |
| +SIMPLE_SCHEMA_NAME_MAP = { |
| + 'boolean': 'TYPE_BOOLEAN', |
| + 'integer': 'TYPE_INTEGER', |
| + 'null' : 'TYPE_NULL', |
| + 'number' : 'TYPE_DOUBLE', |
| + 'string' : 'TYPE_STRING', |
| +} |
| + |
| + |
| +class SchemaNodesGenerator: |
| + """Builds the internal structs to represent a JSON schema.""" |
| + |
| + def __init__(self, shared_strings): |
| + """Creates a new generator. |
| + |
| + |shared_strings| is a map of strings to a C expression that evaluates to |
| + that string at runtime. This mapping can be used to reuse existing string |
| + constants.""" |
| + self.shared_strings = shared_strings |
| + self.schema_nodes = [] |
| + self.property_nodes = [] |
| + self.properties_nodes = [] |
| + self.simple_types = { |
| + 'boolean': -1, |
| + 'integer': -1, |
| + 'null': -1, |
| + 'number': -1, |
| + 'string': -1, |
| + } |
| + self.stringlist_type = -1 |
| + |
| + def GetString(self, s): |
| + if s in self.shared_strings: |
|
dconnelly
2013/10/21 10:25:08
In case you didn't know, there's a ternary express
Joao da Silva
2013/10/22 12:53:27
Good idea, done.
|
| + return self.shared_strings[s] |
| + else: |
| + return '"%s"' % s |
| + |
| + def AppendSchema(self, type, extra, comment=''): |
| + index = len(self.schema_nodes) |
| + self.schema_nodes.append((type, extra, comment)) |
| + return index |
| + |
| + def GetSimpleType(self, name): |
| + assert name in self.simple_types |
| + assert name in SIMPLE_SCHEMA_NAME_MAP |
|
dconnelly
2013/10/21 10:25:08
These asserts aren't necessary and aren't very idi
Joao da Silva
2013/10/22 12:53:27
Done.
|
| + if self.simple_types[name] == -1: |
| + self.simple_types[name] = self.AppendSchema( |
| + SIMPLE_SCHEMA_NAME_MAP[name], |
| + -1, |
| + 'simple type: ' + name) |
| + return self.simple_types[name] |
| + |
| + def GetStringList(self): |
| + if self.stringlist_type == -1: |
| + self.stringlist_type = self.AppendSchema( |
| + 'TYPE_LIST', |
| + self.GetSimpleType('string'), |
| + 'simple type: stringlist') |
| + return self.stringlist_type |
| + |
| + def Generate(self, schema, name): |
| + """Generates the structs for the given schema. |
| + |
| + |schema|: a valid JSON schema in a dictionary. |
| + |name|: the name of the current node, for the generated comments.""" |
| + # Simple types use shared nodes. |
| + if schema['type'] in self.simple_types: |
| + return self.GetSimpleType(schema['type']) |
| + |
| + if schema['type'] == 'array': |
| + # 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)) |
| + 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 |
| + # SchemaNodes array. |
| + index = self.AppendSchema('TYPE_DICTIONARY', -1) |
| + |
| + if 'additionalProperties' in schema: |
| + additionalProperties = self.Generate( |
| + schema['additionalProperties'], |
| + 'additionalProperties of ' + name) |
| + else: |
| + additionalProperties = -1 |
| + |
| + # Properties must be sorted by name, for the binary search lookup. |
| + sorted_properties = sorted(schema.get('properties', {}).items()) |
| + properties = [ (self.GetString(key), self.Generate(schema, key)) |
| + for key, schema in sorted_properties ] |
| + begin = len(self.property_nodes) |
| + self.property_nodes += properties |
| + end = len(self.property_nodes) |
| + |
| + extra = len(self.properties_nodes) |
| + self.properties_nodes.append((begin, end, additionalProperties, name)) |
| + |
| + # Set the right data at |index| now. |
| + self.schema_nodes[index] = ('TYPE_DICTIONARY', extra, name) |
| + return index |
| + else: |
| + assert False |
| + |
| + def Write(self, f): |
| + """Writes the generated structs to the given file. |
| + |
| + |f| an open file to write to.""" |
| + f.write('const internal::SchemaNode kSchemas[] = {\n' |
| + '// Type Extra\n') |
| + for type, extra, comment in self.schema_nodes: |
| + type += ',' |
| + f.write(' { base::Value::%-18s %3d }, // %s\n' % (type, extra, comment)) |
| + f.write('};\n\n') |
| + |
| + f.write('const internal::PropertyNode kPropertyNodes[] = {\n' |
| + '// Property #Schema\n') |
| + for key, schema in self.property_nodes: |
| + key += ',' |
| + f.write(' { %-50s %7d },\n' % (key, schema)) |
| + f.write('};\n\n') |
| + |
| + f.write('const internal::PropertiesNode kProperties[] = {\n' |
| + '// Begin End Additional Properties\n') |
| + for node in self.properties_nodes: |
| + f.write(' { %5d, %5d, %5d }, // %s\n' % node) |
| + f.write('};\n\n') |
| + |
| + f.write('const internal::SchemaData kChromeSchemaData = {\n' |
| + ' kSchemas,\n' |
| + ' kPropertyNodes,\n' |
| + ' kProperties,\n' |
| + '};\n\n') |
| + |
| + |
| def _WritePolicyConstantSource(policies, os, f): |
| f.write('#include "base/basictypes.h"\n' |
| '#include "base/logging.h"\n' |
| + '#include "components/policy/core/common/schema_internal.h"\n' |
| '#include "policy/policy_constants.h"\n' |
| '\n' |
| - 'namespace policy {\n\n') |
| + 'namespace policy {\n' |
| + '\n' |
| + 'namespace {\n' |
| + '\n') |
| - f.write('namespace {\n\n') |
| + # Generate the Chrome schema. |
| + chrome_schema = { |
| + 'type': 'object', |
| + 'properties': {}, |
| + } |
| + shared_strings = {} |
| + for policy in policies: |
| + shared_strings[policy.name] = "key::k%s" % policy.name |
| + if policy.is_supported: |
| + chrome_schema['properties'][policy.name] = policy.schema |
| f.write('const PolicyDefinitionList::Entry kEntries[] = {\n') |
| for policy in policies: |
| @@ -297,6 +457,10 @@ def _WritePolicyConstantSource(policies, os, f): |
| f.write(' key::k%s,\n' % policy.name) |
| f.write('};\n\n') |
| + schema_generator = SchemaNodesGenerator(shared_strings) |
| + schema_generator.Generate(chrome_schema, 'root node') |
| + schema_generator.Write(f) |
| + |
| f.write('} // namespace\n\n') |
| if os == 'win': |
| @@ -323,6 +487,10 @@ def _WritePolicyConstantSource(policies, os, f): |
| ' return &kChromePolicyList;\n' |
| '}\n\n') |
| + f.write('const internal::SchemaData* GetChromeSchemaData() {\n' |
| + ' return &kChromeSchemaData;\n' |
| + '}\n\n') |
| + |
| f.write('namespace key {\n\n') |
| for policy in policies: |
| # TODO(joaodasilva): Include only supported policies in |