Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/python | |
| 2 # | |
| 3 # Copyright 2017 The Chromium Authors. All rights reserved. | |
| 4 # Use of this source code is governed by a BSD-style license that can be | |
| 5 # found in the LICENSE file. | |
| 6 | |
| 7 # This script reads the global interface data collected by | |
| 8 # compute_interfaces_info_overall.py, and writes out the code which adds | |
| 9 # bindings for origin-trial-enabled features at runtime. | |
| 10 | |
| 11 # pylint: disable=W0403 | |
| 12 | |
| 13 import optparse | |
| 14 import os | |
| 15 import posixpath | |
| 16 import sys | |
| 17 from collections import defaultdict | |
| 18 | |
| 19 from code_generator import CodeGeneratorBase | |
| 20 from idl_reader import IdlReader | |
| 21 from utilities import create_component_info_provider, write_file, read_pickle_fi le | |
| 22 from v8_utilities import v8_class_name, v8_class_name_or_partial, uncapitalize | |
| 23 | |
| 24 # Make sure extension is .py, not .pyc or .pyo, so doesn't depend on caching | |
| 25 MODULE_PYNAME = os.path.splitext(os.path.basename(__file__))[0] + '.py' | |
| 26 | |
| 27 | |
| 28 def get_install_functions(interfaces, feature_names): | |
| 29 install_functions = [] | |
| 30 for interface_info in interfaces: | |
| 31 for feature_name in feature_names: | |
| 32 install_function = { | |
| 33 "condition": 'OriginTrials::%sEnabled' % uncapitalize(feature_na me), | |
|
chasej
2017/07/11 20:12:31
I'm wondering if it would be better to have the co
iclelland
2017/07/12 17:23:20
I was definitely thinking about other kinds of con
| |
| 34 "name": feature_name, | |
| 35 "install_method": "install%s" % feature_name, | |
| 36 "class": interface_info[1], | |
| 37 "class_or_partial": interface_info[2] | |
| 38 } | |
| 39 install_functions.append(install_function) | |
| 40 return install_functions | |
| 41 | |
| 42 | |
| 43 def get_conditional_feature_names_from_interface(interface): | |
| 44 feature_names = set() | |
| 45 if 'OriginTrialEnabled' in interface.extended_attributes and interface.is_pa rtial: | |
| 46 feature_names.add(interface.extended_attributes['OriginTrialEnabled']) | |
| 47 for operation in interface.operations: | |
| 48 if 'OriginTrialEnabled' in operation.extended_attributes: | |
| 49 feature_names.add(operation.extended_attributes['OriginTrialEnabled' ]) | |
| 50 for attribute in interface.attributes: | |
| 51 if 'OriginTrialEnabled' in attribute.extended_attributes: | |
| 52 feature_names.add(attribute.extended_attributes['OriginTrialEnabled' ]) | |
| 53 return list(feature_names) | |
| 54 | |
| 55 | |
| 56 class ConditionalFeaturesCodeGenerator(CodeGeneratorBase): | |
| 57 def __init__(self, generator_name, info_provider, global_objects, cache_dir, output_dir): | |
| 58 super(ConditionalFeaturesCodeGenerator, self).__init__(generator_name, i nfo_provider, cache_dir, output_dir) | |
| 59 self.global_objects = global_objects | |
| 60 | |
| 61 def generate_code(self, reader, idl_filenames, header_template, cpp_template , target_component): | |
| 62 context = {} | |
| 63 context['header_includes'] = [] | |
| 64 | |
| 65 includes = set([ | |
| 66 "core/context_features/ContextFeatureSettings.h", | |
| 67 "core/dom/ExecutionContext.h", | |
| 68 "core/frame/Frame.h", | |
| 69 "core/origin_trials/OriginTrials.h", | |
| 70 "platform/bindings/ConditionalFeatures.h", | |
| 71 "platform/bindings/ScriptState.h", | |
| 72 ]) | |
| 73 # TODO(iclelland): Remove the need to explicitly include this; it is | |
| 74 # here because the ContextFeatureSettings code needs it. | |
| 75 includes.add("bindings/core/v8/V8Window.h") | |
| 76 | |
| 77 features_for_type = defaultdict(set) | |
| 78 types_for_feature = defaultdict(set) | |
| 79 | |
| 80 for idl_filename in idl_filenames: | |
| 81 interfaces_read = reader.read_idl_file(idl_filename).interfaces | |
| 82 assert len(interfaces_read) == 1 | |
| 83 name, interface_read = interfaces_read.items()[0] | |
| 84 feature_names = get_conditional_feature_names_from_interface(interfa ce_read) | |
| 85 if feature_names: | |
| 86 # HACK WARNING: This is here becase the ServiceWorker interface | |
| 87 # is actually a complete interface in modules/, but the Origin | |
| 88 # Trial declarations end up on | |
| 89 # ServiceWorkerGlobalScopeModulesConstructors.idl, which is a | |
| 90 # partial interface declaration. TODO: Fix this by correctly | |
| 91 # determining whether the interface where the install* methods | |
| 92 # are declared is partial or not. | |
| 93 if 'ServiceWorkerGlobalScope' in idl_filename: | |
| 94 interface_read.is_partial = False | |
| 95 # END OF HACK | |
| 96 if interface_read.is_partial: | |
| 97 includes.add('bindings/core/v8/V8%s.h' % name) | |
| 98 includes.add('bindings/%s/v8/V8%sPartial.h' % (target_compon ent, name)) | |
| 99 else: | |
| 100 includes.add('bindings/%s/v8/V8%s.h' % (target_component, na me)) | |
| 101 interface_info = (name, v8_class_name(interface_read), v8_class_ name_or_partial(interface_read)) | |
| 102 for feature_name in feature_names: | |
| 103 features_for_type[interface_info].add(feature_name) | |
| 104 types_for_feature[feature_name].add(interface_info) | |
| 105 | |
| 106 context['installers_by_interface'] = [ | |
| 107 {"name": interface_info[0], | |
| 108 "is_global": interface_info[0] in self.global_objects, | |
| 109 "class": interface_info[1], | |
| 110 "installers": get_install_functions([interface_info], feature_names )} | |
| 111 for interface_info, feature_names in features_for_type.items()] | |
| 112 context['installers_by_interface'].sort(key=lambda x: x['name']) | |
| 113 | |
| 114 context['installers_by_feature'] = [ | |
| 115 {"name": feature_name, | |
| 116 "installers": get_install_functions(interfaces, [feature_name])} | |
| 117 for feature_name, interfaces in types_for_feature.items()] | |
| 118 context['installers_by_feature'].sort(key=lambda x: x['name']) | |
| 119 | |
| 120 context['includes'] = sorted(includes) | |
| 121 return self.render_template( | |
| 122 [], | |
| 123 self.jinja_env.get_template(header_template), | |
| 124 self.jinja_env.get_template(cpp_template), | |
| 125 context, target_component) | |
| 126 | |
| 127 | |
| 128 def parse_options(): | |
| 129 parser = optparse.OptionParser() | |
| 130 parser.add_option('--cache-directory', | |
| 131 help='cache directory, defaults to output directory') | |
| 132 parser.add_option('--output-directory') | |
| 133 parser.add_option('--info-dir') | |
| 134 parser.add_option('--target-component', | |
| 135 type='choice', | |
| 136 choices=['Core', 'Modules'], | |
| 137 help='target component to generate code') | |
| 138 parser.add_option('--idl-files-list') | |
| 139 parser.add_option('--global-objects-file') | |
| 140 | |
| 141 options, _ = parser.parse_args() | |
| 142 if options.output_directory is None: | |
| 143 parser.error('Must specify output directory using --output-directory.') | |
| 144 return options | |
| 145 | |
| 146 | |
| 147 def main(): | |
| 148 options = parse_options() | |
| 149 info_provider = create_component_info_provider( | |
| 150 os.path.normpath(options.info_dir), options.target_component.lower()) | |
| 151 | |
| 152 idl_filenames = map(str.strip, open(options.idl_files_list)) | |
| 153 reader = IdlReader(info_provider.interfaces_info, options.cache_directory) | |
| 154 cg = ConditionalFeaturesCodeGenerator(MODULE_PYNAME, info_provider, | |
| 155 read_pickle_file(options.global_object s_file), | |
| 156 options.cache_directory, | |
| 157 options.output_directory) | |
| 158 | |
| 159 header_text, cpp_text = cg.generate_code( | |
| 160 reader, idl_filenames, | |
| 161 "ConditionalFeaturesFor%s.h.tmpl" % options.target_component, | |
| 162 "ConditionalFeaturesFor%s.cpp.tmpl" % options.target_component, | |
| 163 options.target_component.lower()) | |
| 164 header_path = posixpath.join(options.output_directory, | |
| 165 "ConditionalFeaturesFor%s.h" % options.target_c omponent) | |
| 166 cpp_path = posixpath.join(options.output_directory, | |
| 167 "ConditionalFeaturesFor%s.cpp" % options.target_co mponent) | |
| 168 write_file(header_text, header_path) | |
| 169 write_file(cpp_text, cpp_path) | |
| 170 return 0 | |
| 171 | |
| 172 | |
| 173 if __name__ == '__main__': | |
| 174 sys.exit(main()) | |
| OLD | NEW |