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 initialize_jinja_env, normalize_and_sort_includes, re nder_template | |
Yuki
2017/07/15 12:09:19
nit: 80 columns rule
https://google.github.io/styl
iclelland
2017/07/16 04:23:06
Done, thanks. Ran the whole file through autopep8
| |
20 from idl_reader import IdlReader | |
21 from utilities import create_component_info_provider, write_file, idl_filename_t o_component | |
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 return [ | |
30 {"condition": 'OriginTrials::%sEnabled' % uncapitalize(feature_name), | |
31 "name": feature_name, | |
32 "install_method": "install%s" % feature_name, | |
33 "v8_class": interface_info[1], | |
34 "v8_class_or_partial": interface_info[2]} | |
35 for feature_name in feature_names | |
36 for interface_info in interfaces] | |
37 | |
38 | |
39 def get_conditional_feature_names_from_interface(interface): | |
40 feature_names = set() | |
41 if 'OriginTrialEnabled' in interface.extended_attributes and interface.is_pa rtial: | |
42 feature_names.add(interface.extended_attributes['OriginTrialEnabled']) | |
43 for operation in interface.operations: | |
44 if 'OriginTrialEnabled' in operation.extended_attributes: | |
45 feature_names.add(operation.extended_attributes['OriginTrialEnabled' ]) | |
46 for attribute in interface.attributes: | |
47 if 'OriginTrialEnabled' in attribute.extended_attributes: | |
48 feature_names.add(attribute.extended_attributes['OriginTrialEnabled' ]) | |
49 return list(feature_names) | |
50 | |
51 | |
52 def read_idl_file(reader, idl_filename): | |
53 interfaces = reader.read_idl_file(idl_filename).interfaces | |
54 assert len(interfaces) == 1 | |
55 return interfaces.items()[0][1] | |
56 | |
57 | |
58 def interface_is_global(interface): | |
59 return 'Global' in interface.extended_attributes or 'PrimaryGlobal' in inter face.extended_attributes | |
60 | |
61 | |
62 # Reads a set of IDL files and compiles the mapping between interfaces and the | |
Yuki
2017/07/15 12:09:19
Good comment. Thanks.
Could you follow the pydoc
iclelland
2017/07/16 04:23:06
Done.
| |
63 # conditional features defined on them. | |
64 # | |
65 # Returns a tuple (features_for_type, types_for_feature, includes): | |
66 # features_for_type is a mapping of interface->feature | |
67 # types_for_feature is the reverse mapping: feature->interface | |
68 # includes is a set of header files which need to be included in the generated | |
69 # implementation code. | |
70 def conditional_features_info(info_provider, reader, idl_filenames, target_compo nent): | |
71 features_for_type = defaultdict(set) | |
72 types_for_feature = defaultdict(set) | |
73 includes = set() | |
74 | |
75 for idl_filename in idl_filenames: | |
76 interface = read_idl_file(reader, idl_filename) | |
77 feature_names = get_conditional_feature_names_from_interface(interface) | |
78 if feature_names: | |
79 is_global = interface_is_global(interface) | |
80 if interface.is_partial: | |
81 # For partial interfaces, we need to generate different | |
82 # includes if the parent interface is in a different | |
83 # component. | |
84 parent_interface_info = info_provider.interfaces_info[interface. name] | |
85 parent_interface = read_idl_file(reader, parent_interface_info.g et('full_path')) | |
86 is_global = is_global or interface_is_global(parent_interface) | |
87 parent_component = idl_filename_to_component(parent_interface_in fo.get('full_path')) | |
88 if interface.is_partial and target_component != parent_component: | |
89 includes.add('bindings/%s/v8/V8%s.h' % (parent_component, interf ace.name)) | |
90 includes.add('bindings/%s/v8/V8%sPartial.h' % (target_component, interface.name)) | |
91 else: | |
92 includes.add('bindings/%s/v8/V8%s.h' % (target_component, interf ace.name)) | |
93 # If this is a partial interface in the same component as | |
94 # its parent, then treat it as a non-partial interface. | |
95 interface.is_partial = False | |
96 interface_info = (interface.name, v8_class_name(interface), v8_class _name_or_partial(interface), is_global) | |
97 for feature_name in feature_names: | |
98 features_for_type[interface_info].add(feature_name) | |
99 types_for_feature[feature_name].add(interface_info) | |
100 | |
101 return features_for_type, types_for_feature, includes | |
102 | |
103 | |
104 def conditional_features_context(generator_name, feature_info): | |
105 context = {'code_generator': generator_name} | |
106 | |
107 # Unpack the feature info tuple. | |
108 features_for_type, types_for_feature, includes = feature_info | |
109 | |
110 # Add includes needed for cpp code and normalize. | |
111 includes.update([ | |
112 "core/context_features/ContextFeatureSettings.h", | |
113 "core/dom/ExecutionContext.h", | |
114 "core/frame/Frame.h", | |
115 "core/origin_trials/OriginTrials.h", | |
116 "platform/bindings/ConditionalFeatures.h", | |
117 "platform/bindings/ScriptState.h", | |
118 # TODO(iclelland): Remove the need to explicitly include this; it is | |
119 # here because the ContextFeatureSettings code needs it. | |
120 "bindings/core/v8/V8Window.h", | |
121 ]) | |
122 context['includes'] = normalize_and_sort_includes(includes) | |
123 | |
124 # For each interface, collect a list of bindings installation functions to | |
125 # call, organized by conditional feature. | |
126 context['installers_by_interface'] = [ | |
127 {"name": interface_info[0], | |
128 "is_global": interface_info[3], | |
129 "v8_class": interface_info[1], | |
130 "installers": get_install_functions([interface_info], feature_names)} | |
131 for interface_info, feature_names in features_for_type.items()] | |
132 context['installers_by_interface'].sort(key=lambda x: x['name']) | |
133 | |
134 # For each conditional feature, collect a list of bindings installation | |
135 # functions to call, organized by interface. | |
136 context['installers_by_feature'] = [ | |
137 {"name": feature_name, | |
138 "installers": get_install_functions(interfaces, [feature_name])} | |
139 for feature_name, interfaces in types_for_feature.items()] | |
140 context['installers_by_feature'].sort(key=lambda x: x['name']) | |
141 | |
142 return context | |
143 | |
144 | |
145 def parse_options(): | |
146 parser = optparse.OptionParser() | |
147 parser.add_option('--cache-directory', | |
148 help='cache directory, defaults to output directory') | |
149 parser.add_option('--output-directory') | |
150 parser.add_option('--info-dir') | |
151 parser.add_option('--target-component', | |
152 type='choice', | |
153 choices=['Core', 'Modules'], | |
154 help='target component to generate code') | |
155 parser.add_option('--idl-files-list') | |
156 | |
157 options, _ = parser.parse_args() | |
158 if options.output_directory is None: | |
159 parser.error('Must specify output directory using --output-directory.') | |
160 return options | |
161 | |
162 | |
163 def generate_conditional_features(info_provider, options, idl_filenames): | |
164 reader = IdlReader(info_provider.interfaces_info, options.cache_directory) | |
165 jinja_env = initialize_jinja_env(options.cache_directory) | |
166 | |
167 # Extract the bidirectional mapping of conditional features <-> interfaces | |
168 # from the global info provider and the supplied list of IDL files. | |
169 feature_info = conditional_features_info(info_provider, | |
170 reader, idl_filenames, | |
171 options.target_component.lower()) | |
172 | |
173 # Convert that mapping into the context required for the Jinja2 templates. | |
174 template_context = conditional_features_context(MODULE_PYNAME, feature_info) | |
175 | |
176 # Generate and write out the header file | |
177 header_text = render_template(jinja_env.get_template( | |
178 "ConditionalFeaturesFor%s.h.tmpl" % options.target_component.title()), t emplate_context) | |
179 header_path = posixpath.join(options.output_directory, | |
180 "ConditionalFeaturesFor%s.h" % options.target_c omponent.title()) | |
181 write_file(header_text, header_path) | |
182 | |
183 # Generate and write out the implementation file | |
184 cpp_text = render_template(jinja_env.get_template( | |
185 "ConditionalFeaturesFor%s.cpp.tmpl" % options.target_component.title()), template_context) | |
186 cpp_path = posixpath.join(options.output_directory, | |
187 "ConditionalFeaturesFor%s.cpp" % options.target_co mponent.title()) | |
188 write_file(cpp_text, cpp_path) | |
189 | |
190 | |
191 def main(): | |
192 options = parse_options() | |
193 | |
194 info_provider = create_component_info_provider( | |
195 os.path.normpath(options.info_dir), options.target_component.lower()) | |
196 idl_filenames = map(str.strip, open(options.idl_files_list)) | |
197 | |
198 generate_conditional_features(info_provider, options, idl_filenames) | |
199 return 0 | |
200 | |
201 | |
202 if __name__ == '__main__': | |
203 sys.exit(main()) | |
OLD | NEW |