| 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..0be012abf272e7c6998a84d851e007416443d5ec 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)) | 
| +          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. The wrapper needs to be used for every call to | 
| +    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,29 @@ 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): | 
| +    return params[:index] + (self.GetByID(params[index]),) + params[index+1:] | 
| + | 
| +  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 suggests that it's a resolved | 
| +    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 +604,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' | 
|  |