| OLD | NEW | 
|    1 #!/usr/bin/python |    1 #!/usr/bin/python | 
|    2 # |    2 # | 
|    3 # Copyright (C) 2013 Google Inc. All rights reserved. |    3 # Copyright (C) 2013 Google Inc. All rights reserved. | 
|    4 # |    4 # | 
|    5 # Redistribution and use in source and binary forms, with or without |    5 # Redistribution and use in source and binary forms, with or without | 
|    6 # modification, are permitted provided that the following conditions are |    6 # modification, are permitted provided that the following conditions are | 
|    7 # met: |    7 # met: | 
|    8 # |    8 # | 
|    9 #     * Redistributions of source code must retain the above copyright |    9 #     * Redistributions of source code must retain the above copyright | 
|   10 # notice, this list of conditions and the following disclaimer. |   10 # notice, this list of conditions and the following disclaimer. | 
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   46 import os |   46 import os | 
|   47 import posixpath |   47 import posixpath | 
|   48 import sys |   48 import sys | 
|   49  |   49  | 
|   50 from idl_reader import IdlReader |   50 from idl_reader import IdlReader | 
|   51 from utilities import get_file_contents, read_file_to_list, idl_filename_to_inte
     rface_name, idl_filename_to_component, write_pickle_file, get_interface_extended
     _attributes_from_idl, is_callback_interface_from_idl |   51 from utilities import get_file_contents, read_file_to_list, idl_filename_to_inte
     rface_name, idl_filename_to_component, write_pickle_file, get_interface_extended
     _attributes_from_idl, is_callback_interface_from_idl | 
|   52  |   52  | 
|   53 module_path = os.path.dirname(__file__) |   53 module_path = os.path.dirname(__file__) | 
|   54 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir)) |   54 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir)) | 
|   55  |   55  | 
|   56 # Global variables (filled in and exported) |  | 
|   57 interfaces_info = {} |  | 
|   58 partial_interface_files = defaultdict(lambda: { |  | 
|   59     'full_paths': [], |  | 
|   60     'include_paths': [], |  | 
|   61 }) |  | 
|   62  |  | 
|   63  |   56  | 
|   64 class IdlBadFilenameError(Exception): |   57 class IdlBadFilenameError(Exception): | 
|   65     """Raised if an IDL filename disagrees with the interface name in the file."
     "" |   58     """Raised if an IDL filename disagrees with the interface name in the file."
     "" | 
|   66     pass |   59     pass | 
|   67  |   60  | 
|   68  |   61  | 
|   69 def parse_options(): |   62 def parse_options(): | 
|   70     usage = 'Usage: %prog [options] [generated1.idl]...' |   63     usage = 'Usage: %prog [options] [generated1.idl]...' | 
|   71     parser = optparse.OptionParser(usage=usage) |   64     parser = optparse.OptionParser(usage=usage) | 
|   72     parser.add_option('--cache-directory', help='cache directory') |   65     parser.add_option('--cache-directory', help='cache directory') | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  104     """ |   97     """ | 
|  105     relative_dir = relative_dir_posix(idl_filename) |   98     relative_dir = relative_dir_posix(idl_filename) | 
|  106  |   99  | 
|  107     # IDL file basename is used even if only a partial interface file |  100     # IDL file basename is used even if only a partial interface file | 
|  108     idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename)) |  101     idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename)) | 
|  109     cpp_class_name = implemented_as or idl_file_basename |  102     cpp_class_name = implemented_as or idl_file_basename | 
|  110  |  103  | 
|  111     return posixpath.join(relative_dir, cpp_class_name + '.h') |  104     return posixpath.join(relative_dir, cpp_class_name + '.h') | 
|  112  |  105  | 
|  113  |  106  | 
|  114 def add_paths_to_partials_dict(partial_interface_name, full_path, this_include_p
     ath=None): |  | 
|  115     paths_dict = partial_interface_files[partial_interface_name] |  | 
|  116     paths_dict['full_paths'].append(full_path) |  | 
|  117     if this_include_path: |  | 
|  118         paths_dict['include_paths'].append(this_include_path) |  | 
|  119  |  | 
|  120  |  | 
|  121 def get_implements_from_definitions(definitions, definition_name): |  107 def get_implements_from_definitions(definitions, definition_name): | 
|  122     left_interfaces = [] |  108     left_interfaces = [] | 
|  123     right_interfaces = [] |  109     right_interfaces = [] | 
|  124     for implement in definitions.implements: |  110     for implement in definitions.implements: | 
|  125         if definition_name == implement.left_interface: |  111         if definition_name == implement.left_interface: | 
|  126             right_interfaces.append(implement.right_interface) |  112             right_interfaces.append(implement.right_interface) | 
|  127         elif definition_name == implement.right_interface: |  113         elif definition_name == implement.right_interface: | 
|  128             left_interfaces.append(implement.left_interface) |  114             left_interfaces.append(implement.left_interface) | 
|  129         else: |  115         else: | 
|  130             raise IdlBadFilenameError( |  116             raise IdlBadFilenameError( | 
|  131                 'implements statement found in unrelated IDL file.\n' |  117                 'implements statement found in unrelated IDL file.\n' | 
|  132                 'Statement is:\n' |  118                 'Statement is:\n' | 
|  133                 '    %s implements %s;\n' |  119                 '    %s implements %s;\n' | 
|  134                 'but filename is unrelated "%s.idl"' % |  120                 'but filename is unrelated "%s.idl"' % | 
|  135                 (implement.left_interface, implement.right_interface, definition
     _name)) |  121                 (implement.left_interface, implement.right_interface, definition
     _name)) | 
|  136     return left_interfaces, right_interfaces |  122     return left_interfaces, right_interfaces | 
|  137  |  123  | 
|  138  |  124  | 
|  139 def get_put_forward_interfaces_from_definition(definition): |  125 def get_put_forward_interfaces_from_definition(definition): | 
|  140     return sorted(set(attribute.idl_type.base_type |  126     return sorted(set(attribute.idl_type.base_type | 
|  141                       for attribute in definition.attributes |  127                       for attribute in definition.attributes | 
|  142                       if 'PutForwards' in attribute.extended_attributes)) |  128                       if 'PutForwards' in attribute.extended_attributes)) | 
|  143  |  129  | 
|  144  |  130  | 
|  145 def compute_info_individual(idl_filename, reader): |  131 class InterfaceInfoCollector(object): | 
|  146     definitions = reader.read_idl_file(idl_filename) |  132     """A class that collects interface information from idl files.""" | 
|  147     if len(definitions.interfaces) > 0: |  133     def __init__(self, cache_directory=None): | 
|  148         definition = next(definitions.interfaces.itervalues()) |  134         self.reader = IdlReader(interfaces_info=None, outputdir=cache_directory) | 
|  149         interface_info = { |  135         self.interfaces_info = {} | 
|  150             'is_callback_interface': definition.is_callback, |  136         self.partial_interface_files = defaultdict(lambda: { | 
|  151             'is_dictionary': False, |  137             'full_paths': [], | 
|  152             # Interfaces that are referenced (used as types) and that we introsp
     ect |  138             'include_paths': [], | 
|  153             # during code generation (beyond interface-level data ([ImplementedA
     s], |  139         }) | 
|  154             # is_callback_interface, ancestors, and inherited extended attribute
     s): |  140  | 
|  155             # deep dependencies. |  141     def add_paths_to_partials_dict(self, partial_interface_name, full_path, | 
|  156             # These cause rebuilds of referrers, due to the dependency, so these |  142                                    this_include_path=None): | 
|  157             # should be minimized; currently only targets of [PutForwards]. |  143         paths_dict = self.partial_interface_files[partial_interface_name] | 
|  158             'referenced_interfaces': get_put_forward_interfaces_from_definition(
     definition), |  144         paths_dict['full_paths'].append(full_path) | 
 |  145         if this_include_path: | 
 |  146             paths_dict['include_paths'].append(this_include_path) | 
 |  147  | 
 |  148     def collect_info(self, idl_filename): | 
 |  149         """Reads an idl file and collects information which is required by the | 
 |  150         binding code generation.""" | 
 |  151         definitions = self.reader.read_idl_file(idl_filename) | 
 |  152         if len(definitions.interfaces) > 0: | 
 |  153             definition = next(definitions.interfaces.itervalues()) | 
 |  154             interface_info = { | 
 |  155                 'is_callback_interface': definition.is_callback, | 
 |  156                 'is_dictionary': False, | 
 |  157                 # Interfaces that are referenced (used as types) and that we | 
 |  158                 # introspect during code generation (beyond interface-level | 
 |  159                 # data ([ImplementedAs], is_callback_interface, ancestors, and | 
 |  160                 # inherited extended attributes): deep dependencies. | 
 |  161                 # These cause rebuilds of referrers, due to the dependency, | 
 |  162                 # so these should be minimized; currently only targets of | 
 |  163                 # [PutForwards]. | 
 |  164                 'referenced_interfaces': get_put_forward_interfaces_from_definit
     ion(definition), | 
 |  165             } | 
 |  166         elif len(definitions.dictionaries) > 0: | 
 |  167             definition = next(definitions.dictionaries.itervalues()) | 
 |  168             interface_info = { | 
 |  169                 'is_callback_interface': False, | 
 |  170                 'is_dictionary': True, | 
 |  171                 'referenced_interfaces': None, | 
 |  172             } | 
 |  173         else: | 
 |  174             raise Exception('IDL file must contain one interface or dictionary') | 
 |  175  | 
 |  176         extended_attributes = definition.extended_attributes | 
 |  177         implemented_as = extended_attributes.get('ImplementedAs') | 
 |  178         full_path = os.path.realpath(idl_filename) | 
 |  179         this_include_path = None if 'NoImplHeader' in extended_attributes else i
     nclude_path(idl_filename, implemented_as) | 
 |  180         if definition.is_partial: | 
 |  181             # We don't create interface_info for partial interfaces, but | 
 |  182             # adds paths to another dict. | 
 |  183             self.add_paths_to_partials_dict(definition.name, full_path, this_inc
     lude_path) | 
 |  184             return | 
 |  185  | 
 |  186         # 'implements' statements can be included in either the file for the | 
 |  187         # implement*ing* interface (lhs of 'implements') or implement*ed* interf
     ace | 
 |  188         # (rhs of 'implements'). Store both for now, then merge to implement*ing
     * | 
 |  189         # interface later. | 
 |  190         left_interfaces, right_interfaces = get_implements_from_definitions( | 
 |  191             definitions, definition.name) | 
 |  192  | 
 |  193         interface_info.update({ | 
 |  194             'extended_attributes': extended_attributes, | 
 |  195             'full_path': full_path, | 
 |  196             'implemented_as': implemented_as, | 
 |  197             'implemented_by_interfaces': left_interfaces, | 
 |  198             'implements_interfaces': right_interfaces, | 
 |  199             'include_path': this_include_path, | 
 |  200             # FIXME: temporary private field, while removing old treatement of | 
 |  201             # 'implements': http://crbug.com/360435 | 
 |  202             'is_legacy_treat_as_partial_interface': 'LegacyTreatAsPartialInterfa
     ce' in extended_attributes, | 
 |  203             'parent': definition.parent, | 
 |  204             'relative_dir': relative_dir_posix(idl_filename), | 
 |  205         }) | 
 |  206         self.interfaces_info[definition.name] = interface_info | 
 |  207  | 
 |  208     def get_info_as_dict(self): | 
 |  209         """Returns info packaged as a dict.""" | 
 |  210         return { | 
 |  211             'interfaces_info': self.interfaces_info, | 
 |  212             # Can't pickle defaultdict, convert to dict | 
 |  213             'partial_interface_files': dict(self.partial_interface_files), | 
|  159         } |  214         } | 
|  160     elif len(definitions.dictionaries) > 0: |  | 
|  161         definition = next(definitions.dictionaries.itervalues()) |  | 
|  162         interface_info = { |  | 
|  163             'is_callback_interface': False, |  | 
|  164             'is_dictionary': True, |  | 
|  165             'referenced_interfaces': None, |  | 
|  166         } |  | 
|  167     else: |  | 
|  168         raise Exception('IDL file must contain one interface or dictionary') |  | 
|  169  |  | 
|  170     extended_attributes = definition.extended_attributes |  | 
|  171     implemented_as = extended_attributes.get('ImplementedAs') |  | 
|  172     full_path = os.path.realpath(idl_filename) |  | 
|  173     this_include_path = None if 'NoImplHeader' in extended_attributes else inclu
     de_path(idl_filename, implemented_as) |  | 
|  174     if definition.is_partial: |  | 
|  175         # We don't create interface_info for partial interfaces, but |  | 
|  176         # adds paths to another dict. |  | 
|  177         add_paths_to_partials_dict(definition.name, full_path, this_include_path
     ) |  | 
|  178         return |  | 
|  179  |  | 
|  180     # 'implements' statements can be included in either the file for the |  | 
|  181     # implement*ing* interface (lhs of 'implements') or implement*ed* interface |  | 
|  182     # (rhs of 'implements'). Store both for now, then merge to implement*ing* |  | 
|  183     # interface later. |  | 
|  184     left_interfaces, right_interfaces = get_implements_from_definitions(definiti
     ons, definition.name) |  | 
|  185  |  | 
|  186     interface_info.update({ |  | 
|  187         'extended_attributes': extended_attributes, |  | 
|  188         'full_path': full_path, |  | 
|  189         'implemented_as': implemented_as, |  | 
|  190         'implemented_by_interfaces': left_interfaces, |  | 
|  191         'implements_interfaces': right_interfaces, |  | 
|  192         'include_path': this_include_path, |  | 
|  193         # FIXME: temporary private field, while removing old treatement of |  | 
|  194         # 'implements': http://crbug.com/360435 |  | 
|  195         'is_legacy_treat_as_partial_interface': 'LegacyTreatAsPartialInterface' 
     in extended_attributes, |  | 
|  196         'parent': definition.parent, |  | 
|  197         'relative_dir': relative_dir_posix(idl_filename), |  | 
|  198     }) |  | 
|  199     interfaces_info[definition.name] = interface_info |  | 
|  200  |  | 
|  201  |  | 
|  202 def info_individual(): |  | 
|  203     """Returns info packaged as a dict.""" |  | 
|  204     return { |  | 
|  205         'interfaces_info': interfaces_info, |  | 
|  206         # Can't pickle defaultdict, convert to dict |  | 
|  207         'partial_interface_files': dict(partial_interface_files), |  | 
|  208     } |  | 
|  209  |  215  | 
|  210  |  216  | 
|  211 ################################################################################ |  217 ################################################################################ | 
|  212  |  218  | 
|  213 def main(): |  219 def main(): | 
|  214     options, args = parse_options() |  220     options, args = parse_options() | 
|  215  |  221  | 
|  216     # Static IDL files are passed in a file (generated at GYP time), due to OS |  222     # Static IDL files are passed in a file (generated at GYP time), due to OS | 
|  217     # command line length limits |  223     # command line length limits | 
|  218     idl_files = read_file_to_list(options.idl_files_list) |  224     idl_files = read_file_to_list(options.idl_files_list) | 
|  219     # Generated IDL files are passed at the command line, since these are in the |  225     # Generated IDL files are passed at the command line, since these are in the | 
|  220     # build directory, which is determined at build time, not GYP time, so these |  226     # build directory, which is determined at build time, not GYP time, so these | 
|  221     # cannot be included in the file listing static files |  227     # cannot be included in the file listing static files | 
|  222     idl_files.extend(args) |  228     idl_files.extend(args) | 
|  223  |  229  | 
|  224     # Compute information for individual files |  230     # Compute information for individual files | 
|  225     # Information is stored in global variables interfaces_info and |  231     # Information is stored in global variables interfaces_info and | 
|  226     # partial_interface_files. |  232     # partial_interface_files. | 
|  227     reader = IdlReader(interfaces_info=None, outputdir=options.cache_directory) |  233     info_collector = InterfaceInfoCollector(options.cache_directory) | 
|  228     for idl_filename in idl_files: |  234     for idl_filename in idl_files: | 
|  229         compute_info_individual(idl_filename, reader) |  235         info_collector.collect_info(idl_filename) | 
|  230  |  236  | 
|  231     write_pickle_file(options.interfaces_info_file, |  237     write_pickle_file(options.interfaces_info_file, | 
|  232                       info_individual(), |  238                       info_collector.get_info_as_dict(), | 
|  233                       options.write_file_only_if_changed) |  239                       options.write_file_only_if_changed) | 
|  234  |  240  | 
|  235  |  241  | 
|  236 if __name__ == '__main__': |  242 if __name__ == '__main__': | 
|  237     sys.exit(main()) |  243     sys.exit(main()) | 
| OLD | NEW |