#!/usr/bin/python2.4 # Copyright 2008, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Input gathering tool for SCons.""" import re import SCons.Script def GatherInputs(env, target, groups=['.*'], exclude_pattern=None): """Find all (non-generated) input files used for a target. Args: target: a target node to find source files for For example: File('bob.exe') groups: a list of patterns to use as categories For example: ['.*\\.c$', '.*\\.h$'] exclude_pattern: a pattern to exclude from the search For example: '.*third_party.*' Returns: A list of lists of files for each category. Each file will be placed in the first category which matches, even if categories overlap. For example: [['bob.c', 'jim.c'], ['bob.h', 'jim.h']] """ # Compile exclude pattern if any if exclude_pattern: exclude_pattern = re.compile(exclude_pattern) def _FindSources(ptrns, tgt, all): """Internal Recursive function to find all pattern matches.""" # Recursively process lists if SCons.Util.is_List(tgt): for t in tgt: _FindSources(ptrns, t, all) else: # Get key to use for tracking whether we've seen this node target_abspath = None if hasattr(tgt, 'abspath'): # Use target's absolute path as the key target_abspath = tgt.abspath target_key = target_abspath else: # Hope node's representation is unique enough (the default repr # contains a pointer to the target as a string). This works for # Alias() nodes. target_key = repr(tgt) # Skip if we have been here before if target_key in all: return # Note that we have been here all[target_key] = True # Skip ones that match an exclude pattern, if we have one. if (exclude_pattern and target_abspath and exclude_pattern.match(target_abspath)): return # Handle non-leaf nodes recursively lst = tgt.children(scan=1) if lst: _FindSources(ptrns, lst, all) return # Get real file (backed by repositories). rfile = tgt.rfile() rfile_is_file = rfile.isfile() # See who it matches for pattern, lst in ptrns.items(): # Add files to the list for the first pattern that matches (implicitly, # don't add directories). if rfile_is_file and pattern.match(rfile.path): lst.append(rfile.abspath) break # Prepare a group for each pattern. patterns = {} for g in groups: patterns[re.compile(g, re.IGNORECASE)] = [] # Do the search. _FindSources(patterns, target, {}) return patterns.values() def generate(env): # NOTE: SCons requires the use of this name, which fails gpylint. """SCons entry point for this tool.""" # Add a method to gather all inputs needed by a target. env.AddMethod(GatherInputs, 'GatherInputs')