Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / scripts / compute_interfaces_info_individual.py
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2013 Google Inc. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met:
8 #
9 #     * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 #     * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
14 # distribution.
15 #     * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 """Compute global interface information for individual IDL files.
32
33 Auxiliary module for compute_interfaces_info_overall, which consolidates
34 this individual information, computing info that spans multiple files
35 (dependencies and ancestry).
36
37 This distinction is so that individual interface info can be computed
38 separately for each component (avoiding duplicated reading of individual
39 files), then consolidated using *only* the info visible to a given component.
40
41 Design doc: http://www.chromium.org/developers/design-documents/idl-build
42 """
43
44 from collections import defaultdict
45 import optparse
46 import os
47 import posixpath
48 import sys
49
50 from utilities import get_file_contents, read_file_to_list, idl_filename_to_interface_name, idl_filename_to_component, write_pickle_file, get_interface_extended_attributes_from_idl, is_callback_interface_from_idl, is_dictionary_from_idl, get_partial_interface_name_from_idl, get_implements_from_idl, get_parent_interface, get_put_forward_interfaces_from_idl
51
52 module_path = os.path.dirname(__file__)
53 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir))
54
55 # Global variables (filled in and exported)
56 interfaces_info = {}
57 partial_interface_files = defaultdict(lambda: {
58     'full_paths': [],
59     'include_paths': [],
60 })
61
62
63 def parse_options():
64     usage = 'Usage: %prog [options] [generated1.idl]...'
65     parser = optparse.OptionParser(usage=usage)
66     parser.add_option('--idl-files-list', help='file listing IDL files')
67     parser.add_option('--interfaces-info-file', help='output pickle file')
68     parser.add_option('--write-file-only-if-changed', type='int', help='if true, do not write an output file if it would be identical to the existing one, which avoids unnecessary rebuilds in ninja')
69
70     options, args = parser.parse_args()
71     if options.interfaces_info_file is None:
72         parser.error('Must specify an output file using --interfaces-info-file.')
73     if options.idl_files_list is None:
74         parser.error('Must specify a file listing IDL files using --idl-files-list.')
75     if options.write_file_only_if_changed is None:
76         parser.error('Must specify whether file is only written if changed using --write-file-only-if-changed.')
77     options.write_file_only_if_changed = bool(options.write_file_only_if_changed)
78     return options, args
79
80
81 ################################################################################
82 # Computations
83 ################################################################################
84
85 def relative_dir_posix(idl_filename):
86     """Returns relative path to the directory of idl_file in POSIX format."""
87     relative_path_local = os.path.relpath(idl_filename, source_path)
88     relative_dir_local = os.path.dirname(relative_path_local)
89     return relative_dir_local.replace(os.path.sep, posixpath.sep)
90
91
92 def include_path(idl_filename, implemented_as=None):
93     """Returns relative path to header file in POSIX format; used in includes.
94
95     POSIX format is used for consistency of output, so reference tests are
96     platform-independent.
97     """
98     relative_dir = relative_dir_posix(idl_filename)
99
100     # IDL file basename is used even if only a partial interface file
101     idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename))
102     cpp_class_name = implemented_as or idl_file_basename
103
104     return posixpath.join(relative_dir, cpp_class_name + '.h')
105
106
107 def add_paths_to_partials_dict(partial_interface_name, full_path, this_include_path=None):
108     paths_dict = partial_interface_files[partial_interface_name]
109     paths_dict['full_paths'].append(full_path)
110     if this_include_path:
111         paths_dict['include_paths'].append(this_include_path)
112
113
114 def compute_info_individual(idl_filename):
115     full_path = os.path.realpath(idl_filename)
116     idl_file_contents = get_file_contents(full_path)
117
118     extended_attributes = get_interface_extended_attributes_from_idl(idl_file_contents)
119     implemented_as = extended_attributes.get('ImplementedAs')
120     relative_dir = relative_dir_posix(idl_filename)
121     this_include_path = None if 'NoImplHeader' in extended_attributes else include_path(idl_filename, implemented_as)
122
123     # Handle partial interfaces
124     partial_interface_name = get_partial_interface_name_from_idl(idl_file_contents)
125     if partial_interface_name:
126         add_paths_to_partials_dict(partial_interface_name, full_path, this_include_path)
127         return
128
129     # If not a partial interface, the basename is the interface name
130     interface_name = idl_filename_to_interface_name(idl_filename)
131
132     # 'implements' statements can be included in either the file for the
133     # implement*ing* interface (lhs of 'implements') or implement*ed* interface
134     # (rhs of 'implements'). Store both for now, then merge to implement*ing*
135     # interface later.
136     left_interfaces, right_interfaces = get_implements_from_idl(idl_file_contents, interface_name)
137
138     interfaces_info[interface_name] = {
139         'extended_attributes': extended_attributes,
140         'full_path': full_path,
141         'implemented_as': implemented_as,
142         'implemented_by_interfaces': left_interfaces,  # private, merged to next
143         'implements_interfaces': right_interfaces,
144         'include_path': this_include_path,
145         'is_callback_interface': is_callback_interface_from_idl(idl_file_contents),
146         'is_dictionary': is_dictionary_from_idl(idl_file_contents),
147         # FIXME: temporary private field, while removing old treatement of
148         # 'implements': http://crbug.com/360435
149         'is_legacy_treat_as_partial_interface': 'LegacyTreatAsPartialInterface' in extended_attributes,
150         'parent': get_parent_interface(idl_file_contents),
151         # Interfaces that are referenced (used as types) and that we introspect
152         # during code generation (beyond interface-level data ([ImplementedAs],
153         # is_callback_interface, ancestors, and inherited extended attributes):
154         # deep dependencies.
155         # These cause rebuilds of referrers, due to the dependency, so these
156         # should be minimized; currently only targets of [PutForwards].
157         'referenced_interfaces': get_put_forward_interfaces_from_idl(idl_file_contents),
158         'relative_dir': relative_dir,
159     }
160
161
162 def info_individual():
163     """Returns info packaged as a dict."""
164     return {
165         'interfaces_info': interfaces_info,
166         # Can't pickle defaultdict, convert to dict
167         'partial_interface_files': dict(partial_interface_files),
168     }
169
170
171 ################################################################################
172
173 def main():
174     options, args = parse_options()
175
176     # Static IDL files are passed in a file (generated at GYP time), due to OS
177     # command line length limits
178     idl_files = read_file_to_list(options.idl_files_list)
179     # Generated IDL files are passed at the command line, since these are in the
180     # build directory, which is determined at build time, not GYP time, so these
181     # cannot be included in the file listing static files
182     idl_files.extend(args)
183
184     # Compute information for individual files
185     # Information is stored in global variables interfaces_info and
186     # partial_interface_files.
187     for idl_filename in idl_files:
188         compute_info_individual(idl_filename)
189
190     write_pickle_file(options.interfaces_info_file,
191                       info_individual(),
192                       options.write_file_only_if_changed)
193
194
195 if __name__ == '__main__':
196     sys.exit(main())