#!/usr/bin/python # Copyright (c) 2011 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 template platform specifies which platform source is being generated for and can be one of (win, mac, linux). template is the path to a .json policy template file.''' from __future__ import with_statement from optparse import OptionParser import sys; CHROME_SUBKEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome'; CHROMIUM_SUBKEY = 'SOFTWARE\\\\Policies\\\\Chromium'; 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("--pth", "--policy-type-header", dest="type_path", help="generate header file for policy type enumeration", metavar="FILE"); parser.add_option("--ppb", "--policy-protobuf", dest="proto_path", help="generate cloud policy protobuf file", metavar="FILE"); parser.add_option("--ppd", "--protobuf-decoder", dest="decoder_path", help="generate C++ code decoding the policy protobuf", metavar="FILE"); (opts, args) = parser.parse_args(); if len(args) < 2 or len(args) > 2: print "exactly one platform and input file must be specified." parser.print_help() sys.exit(2) template_file_contents = _LoadJSONFile(args[1]); if opts.header_path is not None: _WritePolicyConstantHeader(template_file_contents, args, opts); if opts.source_path is not None: _WritePolicyConstantSource(template_file_contents, args, opts); if opts.type_path is not None: _WritePolicyTypeEnumerationHeader(template_file_contents, args, opts); if opts.proto_path is not None: _WriteProtobuf(template_file_contents, args, opts.proto_path) if opts.decoder_path is not None: _WriteProtobufParser(template_file_contents, args, opts.decoder_path) #------------------ shared helpers ---------------------------------# def _OutputGeneratedWarningForC(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') def _GetPolicyNameList(template_file_contents): policy_names = []; for policy in template_file_contents['policy_definitions']: if policy['type'] == 'group': for sub_policy in policy['policies']: policy_names.append(sub_policy['name']) else: policy_names.append(policy['name']) policy_names.sort() return policy_names def _LoadJSONFile(json_file): with open(json_file, "r") as f: text = f.read() return eval(text) #------------------ policy constants header ------------------------# def _WritePolicyConstantHeader(template_file_contents, args, opts): platform = args[0]; with open(opts.header_path, "w") as f: _OutputGeneratedWarningForC(f, args[1]) f.write('#ifndef CHROME_COMMON_POLICY_CONSTANTS_H_\n' '#define CHROME_COMMON_POLICY_CONSTANTS_H_\n' '#pragma once\n' '\n' 'namespace policy {\n\n') if platform == "win": f.write('// The windows registry path where policy configuration ' 'resides.\nextern const wchar_t kRegistrySubKey[];\n\n') f.write('// Key names for the policy settings.\n' 'namespace key {\n\n') for policy_name in _GetPolicyNameList(template_file_contents): 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 ------------------------# def _WritePolicyConstantSource(template_file_contents, args, opts): platform = args[0]; with open(opts.source_path, "w") as f: _OutputGeneratedWarningForC(f, args[1]) f.write('#include "policy/policy_constants.h"\n' '\n' 'namespace policy {\n' '\n') if platform == "win": f.write('#if defined(GOOGLE_CHROME_BUILD)\n' 'const wchar_t kRegistrySubKey[] = ' 'L"' + CHROME_SUBKEY + '";\n' '#else\n' 'const wchar_t kRegistrySubKey[] = ' 'L"' + CHROMIUM_SUBKEY + '";\n' '#endif\n\n') f.write('namespace key {\n\n') for policy_name in _GetPolicyNameList(template_file_contents): f.write('const char k%s[] = "%s";\n' % (policy_name, policy_name)) f.write('\n} // namespace key\n\n' '} // namespace policy\n') #------------------ policy type enumeration header -----------------# def _WritePolicyTypeEnumerationHeader(template_file_contents, args, opts): with open(opts.type_path, "w") as f: _OutputGeneratedWarningForC(f, args[1]) f.write('#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_TYPE_H_\n' '#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_TYPE_H_\n' '#pragma once\n' '\n' 'namespace policy {\n' '\n' 'enum ConfigurationPolicyType {\n') for policy_name in _GetPolicyNameList(template_file_contents): f.write(' kPolicy' + policy_name + ",\n"); f.write('};\n\n' '} // namespace policy\n\n' '#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_TYPE_H_\n') #------------------ policy protobuf --------------------------------# 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; } optional PolicyMode mode = 1 [default = MANDATORY]; } ''' PROTOBUF_TYPE = { 'main': 'bool', 'string': 'string', 'string-enum': 'string', 'int': 'int64', 'int-enum': 'int64', 'list': 'StringList', } # Field IDs [1..RESERVED_IDS] will not be used in the wrapping protobuf. RESERVED_IDS = 2 def _WritePolicyProto(file, policy, fields): if policy.get('device_only', False): return file.write('message %sProto {\n' % policy['name']) file.write(' optional PolicyOptions policy_options = 1;\n') file.write(' optional %s %s = 2;\n' % (PROTOBUF_TYPE[policy['type']], policy['name'])) file.write('}\n\n') fields += [' optional %sProto %s = %s;\n' % (policy['name'], policy['name'], policy['id'] + RESERVED_IDS)] def _WriteProtobuf(template_file_contents, args, outfilepath): with open(outfilepath, 'w') as f: _OutputGeneratedWarningForC(f, args[1]) f.write(PROTO_HEAD) fields = [] f.write('// PBs for individual settings.\n\n') for policy in template_file_contents['policy_definitions']: if policy['type'] == 'group': for sub_policy in policy['policies']: _WritePolicyProto(f, sub_policy, fields) else: _WritePolicyProto(f, policy, fields) f.write('// --------------------------------------------------\n' '// Big wrapper PB containing the above groups.\n\n' 'message CloudPolicySettings {\n') f.write(''.join(fields)) f.write('}\n\n') #------------------ protobuf decoder -------------------------------# CPP_HEAD = ''' #include <limits> #include <map> #include <string> #include "base/logging.h" #include "base/values.h" #include "chrome/browser/policy/configuration_policy_provider.h" #include "chrome/browser/policy/policy_map.h" #include "chrome/browser/policy/proto/cloud_policy.pb.h" #include "policy/configuration_policy_type.h" using google::protobuf::RepeatedPtrField; namespace policy { namespace em = enterprise_management; 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 Value::CreateIntegerValue(static_cast<int>(value)); } ListValue* DecodeStringList(const em::StringList& string_list) { ListValue* list_value = new ListValue; RepeatedPtrField<std::string>::const_iterator entry; for (entry = string_list.entries().begin(); entry != string_list.entries().end(); ++entry) { list_value->Append(Value::CreateStringValue(*entry)); } return list_value; } void DecodePolicy(const em::CloudPolicySettings& policy, PolicyMap* mandatory, PolicyMap* recommended) { DCHECK(mandatory); DCHECK(recommended); ''' CPP_FOOT = '''} } // namespace policy ''' def _CreateValue(type): if type == 'main': return "Value::CreateBooleanValue" elif type in ('int', 'int-enum'): return "DecodeIntegerValue" elif type in ('string', 'string-enum'): return "Value::CreateStringValue" elif type == 'list': return "DecodeStringList" else: raise NotImplementedError() def _WritePolicyCode(file, policy): if policy.get('device_only', False): return membername = policy['name'].lower() proto_type = "%sProto" % policy['name'] proto_name = "%s_proto" % membername file.write(' if (policy.has_%s()) {\n' % membername) file.write(' const em::%s& %s = policy.%s();\n' % (proto_type, proto_name, membername)) file.write(' if (%s.has_%s()) {\n' % (proto_name, membername)) file.write(' Value* value = %s(%s.%s());\n' % (_CreateValue(policy['type']), proto_name, membername)) file.write(' PolicyMap* destination = mandatory;\n' ' if (%s.has_policy_options()) {\n' ' switch(%s.policy_options().mode()) {\n' % (proto_name, proto_name)) file.write(' case em::PolicyOptions::RECOMMENDED:\n' ' destination = recommended;\n' ' break;\n' ' case em::PolicyOptions::MANDATORY:\n' ' break;\n' ' }\n' ' }\n' ' destination->Set(kPolicy%s, value);\n' % policy['name']) file.write(' }\n' ' }\n') def _WriteProtobufParser(template_file_contents, args, outfilepath): with open(outfilepath, 'w') as f: _OutputGeneratedWarningForC(f, args[1]) f.write(CPP_HEAD) for policy in template_file_contents['policy_definitions']: if policy['type'] == 'group': for sub_policy in policy['policies']: _WritePolicyCode(f, sub_policy) else: _WritePolicyCode(f, policy) f.write(CPP_FOOT) #------------------ main() -----------------------------------------# if __name__ == '__main__': main();