| #!/usr/bin/env python |
| # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| '''python %prog [options] platform chromium_os_flag template |
| |
| platform specifies which platform source is being generated for |
| and can be one of (win, mac, linux) |
| 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 |
| import json |
| from optparse import OptionParser |
| import re |
| import sys |
| import textwrap |
| |
| |
| CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome' |
| CHROMIUM_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Chromium' |
| |
| |
| class PolicyDetails: |
| """Parses a policy template and caches all its details.""" |
| |
| # Maps policy types to a tuple with 3 other types: |
| # - the equivalent base::Value::Type or 'TYPE_EXTERNAL' if the policy |
| # references external data |
| # - the equivalent Protobuf field type |
| # - the name of one of the protobufs for shared policy types |
| # TODO(joaodasilva): refactor the 'dict' type into a more generic 'json' type |
| # that can also be used to represent lists of other JSON objects. |
| TYPE_MAP = { |
| 'dict': ('TYPE_DICTIONARY', 'string', 'String'), |
| 'external': ('TYPE_EXTERNAL', 'string', 'String'), |
| 'int': ('TYPE_INTEGER', 'int64', 'Integer'), |
| 'int-enum': ('TYPE_INTEGER', 'int64', 'Integer'), |
| 'list': ('TYPE_LIST', 'StringList', 'StringList'), |
| 'main': ('TYPE_BOOLEAN', 'bool', 'Boolean'), |
| 'string': ('TYPE_STRING', 'string', 'String'), |
| 'string-enum': ('TYPE_STRING', 'string', 'String'), |
| } |
| |
| class EnumItem: |
| def __init__(self, item): |
| self.caption = PolicyDetails._RemovePlaceholders(item['caption']) |
| self.value = item['value'] |
| |
| def __init__(self, policy, os, is_chromium_os): |
| self.id = policy['id'] |
| 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', {}) |
| |
| expected_platform = 'chrome_os' if is_chromium_os else os.lower() |
| self.platforms = [] |
| for platform, version in [ p.split(':') for p in policy['supported_on'] ]: |
| if not version.endswith('-'): |
| continue |
| |
| if platform.startswith('chrome.'): |
| platform_sub = platform[7:] |
| if platform_sub == '*': |
| self.platforms.extend(['win', 'mac', 'linux']) |
| else: |
| self.platforms.append(platform_sub) |
| else: |
| self.platforms.append(platform) |
| |
| self.platforms.sort() |
| self.is_supported = expected_platform in self.platforms |
| |
| if not PolicyDetails.TYPE_MAP.has_key(policy['type']): |
| raise NotImplementedError('Unknown policy type for %s: %s' % |
| (policy['name'], policy['type'])) |
| self.policy_type, self.protobuf_type, self.policy_protobuf_type = \ |
| PolicyDetails.TYPE_MAP[policy['type']] |
| self.schema = policy['schema'] |
| |
| self.desc = '\n'.join( |
| map(str.strip, |
| PolicyDetails._RemovePlaceholders(policy['desc']).splitlines())) |
| self.caption = PolicyDetails._RemovePlaceholders(policy['caption']) |
| self.max_size = policy.get('max_size', 0) |
| |
| items = policy.get('items') |
| if items is None: |
| self.items = None |
| else: |
| self.items = [ PolicyDetails.EnumItem(entry) for entry in items ] |
| |
| PH_PATTERN = re.compile('<ph[^>]*>([^<]*|[^<]*<ex>([^<]*)</ex>[^<]*)</ph>') |
| |
| # Simplistic grit placeholder stripper. |
| @staticmethod |
| def _RemovePlaceholders(text): |
| result = '' |
| pos = 0 |
| for m in PolicyDetails.PH_PATTERN.finditer(text): |
| result += text[pos:m.start(0)] |
| result += m.group(2) or m.group(1) |
| pos = m.end(0) |
| result += text[pos:] |
| return result |
| |
| |
| def main(): |
| parser = OptionParser(usage=__doc__) |
| parser.add_option('--pch', '--policy-constants-header', dest='header_path', |
| help='generate header file of policy constants', |
| metavar='FILE') |
| parser.add_option('--pcc', '--policy-constants-source', dest='source_path', |
| help='generate source file of policy constants', |
| metavar='FILE') |
| parser.add_option('--cpp', '--cloud-policy-protobuf', |
| dest='cloud_policy_proto_path', |
| help='generate cloud policy protobuf file', |
| metavar='FILE') |
| parser.add_option('--csp', '--chrome-settings-protobuf', |
| dest='chrome_settings_proto_path', |
| help='generate chrome settings protobuf file', |
| metavar='FILE') |
| parser.add_option('--cpd', '--cloud-policy-decoder', |
| dest='cloud_policy_decoder_path', |
| help='generate C++ code decoding the cloud policy protobuf', |
| metavar='FILE') |
| |
| (opts, args) = parser.parse_args() |
| |
| if len(args) != 3: |
| print 'exactly platform, chromium_os flag and input file must be specified.' |
| parser.print_help() |
| return 2 |
| |
| os = args[0] |
| is_chromium_os = args[1] == '1' |
| template_file_name = args[2] |
| |
| template_file_contents = _LoadJSONFile(template_file_name) |
| policy_details = [ PolicyDetails(policy, os, is_chromium_os) |
| for policy in _Flatten(template_file_contents) ] |
| sorted_policy_details = sorted(policy_details, key=lambda policy: policy.name) |
| |
| def GenerateFile(path, writer, sorted=False): |
| if path: |
| with open(path, 'w') as f: |
| _OutputGeneratedWarningHeader(f, template_file_name) |
| writer(sorted and sorted_policy_details or policy_details, os, f) |
| |
| GenerateFile(opts.header_path, _WritePolicyConstantHeader, sorted=True) |
| GenerateFile(opts.source_path, _WritePolicyConstantSource, sorted=True) |
| GenerateFile(opts.cloud_policy_proto_path, _WriteCloudPolicyProtobuf) |
| GenerateFile(opts.chrome_settings_proto_path, _WriteChromeSettingsProtobuf) |
| GenerateFile(opts.cloud_policy_decoder_path, _WriteCloudPolicyDecoder) |
| |
| return 0 |
| |
| |
| #------------------ shared helpers ---------------------------------# |
| |
| def _OutputGeneratedWarningHeader(f, template_file_path): |
| f.write('//\n' |
| '// DO NOT MODIFY THIS FILE DIRECTLY!\n' |
| '// IT IS GENERATED BY generate_policy_source.py\n' |
| '// FROM ' + template_file_path + '\n' |
| '//\n\n') |
| |
| |
| COMMENT_WRAPPER = textwrap.TextWrapper() |
| COMMENT_WRAPPER.width = 80 |
| COMMENT_WRAPPER.initial_indent = '// ' |
| COMMENT_WRAPPER.subsequent_indent = '// ' |
| COMMENT_WRAPPER.replace_whitespace = False |
| |
| |
| # Writes a comment, each line prefixed by // and wrapped to 80 spaces. |
| def _OutputComment(f, comment): |
| for line in comment.splitlines(): |
| if len(line) == 0: |
| f.write('//') |
| else: |
| f.write(COMMENT_WRAPPER.fill(line)) |
| f.write('\n') |
| |
| |
| # Returns an iterator over all the policies in |template_file_contents|. |
| def _Flatten(template_file_contents): |
| for policy in template_file_contents['policy_definitions']: |
| if policy['type'] == 'group': |
| for sub_policy in policy['policies']: |
| yield sub_policy |
| else: |
| yield policy |
| |
| |
| def _LoadJSONFile(json_file): |
| with open(json_file, 'r') as f: |
| text = f.read() |
| return eval(text) |
| |
| |
| #------------------ policy constants header ------------------------# |
| |
| def _WritePolicyConstantHeader(policies, os, f): |
| f.write('#ifndef CHROME_COMMON_POLICY_CONSTANTS_H_\n' |
| '#define CHROME_COMMON_POLICY_CONSTANTS_H_\n' |
| '\n' |
| '#include <string>\n' |
| '\n' |
| '#include "base/basictypes.h"\n' |
| '#include "base/values.h"\n' |
| '#include "components/policy/core/common/policy_details.h"\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 ' |
| 'configuration resides.\n' |
| 'extern const wchar_t kRegistryChromePolicyKey[];\n') |
| |
| f.write('// Returns the PolicyDetails for |policy| if |policy| is a known\n' |
| '// Chrome policy, otherwise returns NULL.\n' |
| 'const PolicyDetails* GetChromePolicyDetails(' |
| 'const std::string& policy);\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: |
| # TODO(joaodasilva): Include only supported policies in |
| # configuration_policy_handler.cc and configuration_policy_handler_list.cc |
| # so that these names can be conditional on 'policy.is_supported'. |
| # http://crbug.com/223616 |
| f.write('extern const char k' + policy.name + '[];\n') |
| f.write('\n} // namespace key\n\n' |
| '} // namespace policy\n\n' |
| '#endif // CHROME_COMMON_POLICY_CONSTANTS_H_\n') |
| |
| |
| #------------------ policy constants source ------------------------# |
| |
| # 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': None, |
| 'integer': None, |
| 'null': None, |
| 'number': None, |
| 'string': None, |
| } |
| self.stringlist_type = None |
| |
| def GetString(self, s): |
| return self.shared_strings[s] if s in self.shared_strings else '"%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): |
| if self.simple_types[name] == None: |
| 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 == None: |
| 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. |
| # Note that |properties| must be evaluated immediately, so that all the |
| # 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(schema, key)) |
| for key, schema in sorted_properties ] |
| begin = len(self.property_nodes) |
| self.property_nodes += properties |
| end = len(self.property_nodes) |
| if index == 0: |
| self.root_properties_begin = begin |
| self.root_properties_end = end |
| |
| 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 "policy/policy_constants.h"\n' |
| '\n' |
| '#include <algorithm>\n' |
| '\n' |
| '#include "base/logging.h"\n' |
| '#include "components/policy/core/common/schema_internal.h"\n' |
| '\n' |
| 'namespace policy {\n' |
| '\n' |
| '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 |
| |
| # Note: this list must be kept in sync with the known property list of the |
| # Chrome schema, so that binary seaching in the PropertyNode array gets the |
| # right index on this array as well. See the implementation of |
| # GetChromePolicyDetails() below. |
| f.write('const PolicyDetails kChromePolicyDetails[] = {\n' |
| '// is_deprecated is_device_policy id max_external_data_size\n') |
| for policy in policies: |
| if policy.is_supported: |
| f.write(' { %-14s %-16s %3s, %24s },\n' % ( |
| 'true,' if policy.is_deprecated else 'false,', |
| 'true,' if policy.is_device_only else 'false,', |
| policy.id, |
| policy.max_size)) |
| f.write('};\n\n') |
| |
| schema_generator = SchemaNodesGenerator(shared_strings) |
| schema_generator.Generate(chrome_schema, 'root node') |
| schema_generator.Write(f) |
| |
| f.write('bool CompareKeys(const internal::PropertyNode& node,\n' |
| ' const std::string& key) {\n' |
| ' return node.key < key;\n' |
| '}\n\n') |
| |
| f.write('} // namespace\n\n') |
| |
| if os == 'win': |
| f.write('#if defined(GOOGLE_CHROME_BUILD)\n' |
| 'const wchar_t kRegistryChromePolicyKey[] = ' |
| 'L"' + CHROME_POLICY_KEY + '";\n' |
| '#else\n' |
| 'const wchar_t kRegistryChromePolicyKey[] = ' |
| 'L"' + CHROMIUM_POLICY_KEY + '";\n' |
| '#endif\n\n') |
| |
| f.write('const internal::SchemaData* GetChromeSchemaData() {\n' |
| ' return &kChromeSchemaData;\n' |
| '}\n\n') |
| |
| f.write('const PolicyDetails* GetChromePolicyDetails(' |
| 'const std::string& policy) {\n' |
| ' // First index in kPropertyNodes of the Chrome policies.\n' |
| ' static const int begin_index = %s;\n' |
| ' // One-past-the-end of the Chrome policies in kPropertyNodes.\n' |
| ' static const int end_index = %s;\n' % |
| (schema_generator.root_properties_begin, |
| schema_generator.root_properties_end)) |
| f.write(' const internal::PropertyNode* begin =\n' |
| ' kPropertyNodes + begin_index;\n' |
| ' const internal::PropertyNode* end = kPropertyNodes + end_index;\n' |
| ' const internal::PropertyNode* it =\n' |
| ' std::lower_bound(begin, end, policy, CompareKeys);\n' |
| ' if (it == end || it->key != policy)\n' |
| ' return NULL;\n' |
| ' // This relies on kPropertyNodes from begin_index to end_index\n' |
| ' // having exactly the same policies (and in the same order) as\n' |
| ' // kChromePolicyDetails, so that binary searching on the first\n' |
| ' // gets the same results as a binary search on the second would.\n' |
| ' // However, kPropertyNodes has the policy names and\n' |
| ' // kChromePolicyDetails doesn\'t, so we obtain the index into\n' |
| ' // the second array by searching the first to avoid duplicating\n' |
| ' // the policy name pointers.\n' |
| ' // Offsetting |it| from |begin| here obtains the index we\'re\n' |
| ' // looking for.\n' |
| ' size_t index = it - begin;\n' |
| ' CHECK_LT(index, arraysize(kChromePolicyDetails));\n' |
| ' return kChromePolicyDetails + index;\n' |
| '}\n\n') |
| |
| f.write('namespace key {\n\n') |
| for policy in policies: |
| # TODO(joaodasilva): Include only supported policies in |
| # configuration_policy_handler.cc and configuration_policy_handler_list.cc |
| # so that these names can be conditional on 'policy.is_supported'. |
| # http://crbug.com/223616 |
| f.write('const char k{name}[] = "{name}";\n'.format(name=policy.name)) |
| f.write('\n} // namespace key\n\n' |
| '} // namespace policy\n') |
| |
| |
| #------------------ policy protobufs --------------------------------# |
| |
| CHROME_SETTINGS_PROTO_HEAD = ''' |
| syntax = "proto2"; |
| |
| option optimize_for = LITE_RUNTIME; |
| |
| package enterprise_management; |
| |
| // For StringList and PolicyOptions. |
| import "cloud_policy.proto"; |
| |
| ''' |
| |
| |
| CLOUD_POLICY_PROTO_HEAD = ''' |
| syntax = "proto2"; |
| |
| option optimize_for = LITE_RUNTIME; |
| |
| package enterprise_management; |
| |
| message StringList { |
| repeated string entries = 1; |
| } |
| |
| message PolicyOptions { |
| enum PolicyMode { |
| // The given settings are applied regardless of user choice. |
| MANDATORY = 0; |
| // The user may choose to override the given settings. |
| RECOMMENDED = 1; |
| // No policy value is present and the policy should be ignored. |
| UNSET = 2; |
| } |
| optional PolicyMode mode = 1 [default = MANDATORY]; |
| } |
| |
| message BooleanPolicyProto { |
| optional PolicyOptions policy_options = 1; |
| optional bool value = 2; |
| } |
| |
| message IntegerPolicyProto { |
| optional PolicyOptions policy_options = 1; |
| optional int64 value = 2; |
| } |
| |
| message StringPolicyProto { |
| optional PolicyOptions policy_options = 1; |
| optional string value = 2; |
| } |
| |
| message StringListPolicyProto { |
| optional PolicyOptions policy_options = 1; |
| optional StringList value = 2; |
| } |
| |
| ''' |
| |
| |
| # Field IDs [1..RESERVED_IDS] will not be used in the wrapping protobuf. |
| RESERVED_IDS = 2 |
| |
| |
| def _WritePolicyProto(f, policy, fields): |
| _OutputComment(f, policy.caption + '\n\n' + policy.desc) |
| if policy.items is not None: |
| _OutputComment(f, '\nValid values:') |
| for item in policy.items: |
| _OutputComment(f, ' %s: %s' % (str(item.value), item.caption)) |
| if policy.policy_type == 'TYPE_DICTIONARY': |
| _OutputComment(f, '\nValue schema:\n%s' % |
| json.dumps(policy.schema, sort_keys=True, indent=4, |
| separators=(',', ': '))) |
| _OutputComment(f, '\nSupported on: %s' % ', '.join(policy.platforms)) |
| f.write('message %sProto {\n' % policy.name) |
| f.write(' optional PolicyOptions policy_options = 1;\n') |
| f.write(' optional %s %s = 2;\n' % (policy.protobuf_type, policy.name)) |
| f.write('}\n\n') |
| fields += [ ' optional %sProto %s = %s;\n' % |
| (policy.name, policy.name, policy.id + RESERVED_IDS) ] |
| |
| |
| def _WriteChromeSettingsProtobuf(policies, os, f): |
| f.write(CHROME_SETTINGS_PROTO_HEAD) |
| |
| fields = [] |
| f.write('// PBs for individual settings.\n\n') |
| for policy in policies: |
| # Note: this protobuf also gets the unsupported policies, since it's an |
| # exaustive list of all the supported user policies on any platform. |
| if not policy.is_device_only: |
| _WritePolicyProto(f, policy, fields) |
| |
| f.write('// --------------------------------------------------\n' |
| '// Big wrapper PB containing the above groups.\n\n' |
| 'message ChromeSettingsProto {\n') |
| f.write(''.join(fields)) |
| f.write('}\n\n') |
| |
| |
| def _WriteCloudPolicyProtobuf(policies, os, f): |
| f.write(CLOUD_POLICY_PROTO_HEAD) |
| f.write('message CloudPolicySettings {\n') |
| for policy in policies: |
| if policy.is_supported and not policy.is_device_only: |
| f.write(' optional %sPolicyProto %s = %s;\n' % |
| (policy.policy_protobuf_type, policy.name, |
| policy.id + RESERVED_IDS)) |
| f.write('}\n\n') |
| |
| |
| #------------------ protobuf decoder -------------------------------# |
| |
| CPP_HEAD = ''' |
| #include <limits> |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/callback.h" |
| #include "base/json/json_reader.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/values.h" |
| #include "components/policy/core/common/cloud/cloud_external_data_manager.h" |
| #include "components/policy/core/common/external_data_fetcher.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "policy/policy_constants.h" |
| #include "policy/proto/cloud_policy.pb.h" |
| |
| using google::protobuf::RepeatedPtrField; |
| |
| namespace policy { |
| |
| namespace em = enterprise_management; |
| |
| base::Value* DecodeIntegerValue(google::protobuf::int64 value) { |
| if (value < std::numeric_limits<int>::min() || |
| value > std::numeric_limits<int>::max()) { |
| LOG(WARNING) << "Integer value " << value |
| << " out of numeric limits, ignoring."; |
| return NULL; |
| } |
| |
| return base::Value::CreateIntegerValue(static_cast<int>(value)); |
| } |
| |
| base::ListValue* DecodeStringList(const em::StringList& string_list) { |
| base::ListValue* list_value = new base::ListValue; |
| RepeatedPtrField<std::string>::const_iterator entry; |
| for (entry = string_list.entries().begin(); |
| entry != string_list.entries().end(); ++entry) { |
| list_value->Append(base::Value::CreateStringValue(*entry)); |
| } |
| return list_value; |
| } |
| |
| base::Value* DecodeJson(const std::string& json) { |
| scoped_ptr<base::Value> root( |
| base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS)); |
| |
| if (!root) |
| LOG(WARNING) << "Invalid JSON string, ignoring: " << json; |
| |
| // Accept any Value type that parsed as JSON, and leave it to the handler to |
| // convert and check the concrete type. |
| return root.release(); |
| } |
| |
| void DecodePolicy(const em::CloudPolicySettings& policy, |
| base::WeakPtr<CloudExternalDataManager> external_data_manager, |
| PolicyMap* map) { |
| ''' |
| |
| |
| CPP_FOOT = '''} |
| |
| } // namespace policy |
| ''' |
| |
| |
| def _CreateValue(type, arg): |
| if type == 'TYPE_BOOLEAN': |
| return 'base::Value::CreateBooleanValue(%s)' % arg |
| elif type == 'TYPE_INTEGER': |
| return 'DecodeIntegerValue(%s)' % arg |
| elif type == 'TYPE_STRING': |
| return 'base::Value::CreateStringValue(%s)' % arg |
| elif type == 'TYPE_LIST': |
| return 'DecodeStringList(%s)' % arg |
| elif type == 'TYPE_DICTIONARY' or type == 'TYPE_EXTERNAL': |
| return 'DecodeJson(%s)' % arg |
| else: |
| raise NotImplementedError('Unknown type %s' % type) |
| |
| |
| def _CreateExternalDataFetcher(type, name): |
| if type == 'TYPE_EXTERNAL': |
| return 'new ExternalDataFetcher(external_data_manager, key::k%s)' % name |
| return 'NULL' |
| |
| |
| def _WritePolicyCode(f, policy): |
| membername = policy.name.lower() |
| proto_type = '%sPolicyProto' % policy.policy_protobuf_type |
| f.write(' if (policy.has_%s()) {\n' % membername) |
| f.write(' const em::%s& policy_proto = policy.%s();\n' % |
| (proto_type, membername)) |
| f.write(' if (policy_proto.has_value()) {\n') |
| f.write(' PolicyLevel level = POLICY_LEVEL_MANDATORY;\n' |
| ' bool do_set = true;\n' |
| ' if (policy_proto.has_policy_options()) {\n' |
| ' do_set = false;\n' |
| ' switch(policy_proto.policy_options().mode()) {\n' |
| ' case em::PolicyOptions::MANDATORY:\n' |
| ' do_set = true;\n' |
| ' level = POLICY_LEVEL_MANDATORY;\n' |
| ' break;\n' |
| ' case em::PolicyOptions::RECOMMENDED:\n' |
| ' do_set = true;\n' |
| ' level = POLICY_LEVEL_RECOMMENDED;\n' |
| ' break;\n' |
| ' case em::PolicyOptions::UNSET:\n' |
| ' break;\n' |
| ' }\n' |
| ' }\n' |
| ' if (do_set) {\n') |
| f.write(' base::Value* value = %s;\n' % |
| (_CreateValue(policy.policy_type, 'policy_proto.value()'))) |
| # TODO(bartfab): |value| == NULL indicates that the policy value could not be |
| # parsed successfully. Surface such errors in the UI. |
| f.write(' if (value) {\n') |
| f.write(' ExternalDataFetcher* external_data_fetcher = %s;\n' % |
| _CreateExternalDataFetcher(policy.policy_type, policy.name)) |
| f.write(' map->Set(key::k%s, level, POLICY_SCOPE_USER,\n' % |
| policy.name) |
| f.write(' value, external_data_fetcher);\n' |
| ' }\n' |
| ' }\n' |
| ' }\n' |
| ' }\n') |
| |
| |
| def _WriteCloudPolicyDecoder(policies, os, f): |
| f.write(CPP_HEAD) |
| for policy in policies: |
| if policy.is_supported and not policy.is_device_only: |
| _WritePolicyCode(f, policy) |
| f.write(CPP_FOOT) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |