| Index: site_scons/site_tools/replicate.py
|
| ===================================================================
|
| --- site_scons/site_tools/replicate.py (revision 0)
|
| +++ site_scons/site_tools/replicate.py (revision 0)
|
| @@ -0,0 +1,123 @@
|
| +#!/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.
|
| +
|
| +"""Replicate tool for SCons."""
|
| +
|
| +
|
| +import re
|
| +
|
| +
|
| +def Replicate(env, target, source, **kw):
|
| + """Replicates (copies) source files/directories to the target directory.
|
| +
|
| + Much like env.Install(), with the following differences:
|
| + * If the source is a directory, recurses through it and calls
|
| + env.Install() on each source file, rather than copying the entire
|
| + directory at once. This provides more opportunity for hard linking, and
|
| + also makes the destination files/directories all writable.
|
| + * Can take sources which contain env.Glob()-style wildcards.
|
| + * Can take multiple target directories; will copy to all of them.
|
| + * Handles duplicate requests.
|
| +
|
| + Args:
|
| + env: Environment in which to operate.
|
| + target: Destination(s) for copy. Must evaluate to a directory via
|
| + env.Dir(), or a list of directories. If more than one directory is
|
| + passed, the entire source list will be copied to all target
|
| + directories.
|
| + source: Source file(s) to copy. May be a string, Node, or a list of
|
| + mixed strings or Nodes. Strings will be passed through env.Glob() to
|
| + evaluate wildcards. If a source evaluates to a directory, the entire
|
| + directory will be recursively copied.
|
| +
|
| + From env:
|
| + REPLICATE_RENAME: A list of pairs of regex search and replacement strings.
|
| + Each full destination path has substitution performed on each pair
|
| + (search_regex, replacement) in order.
|
| +
|
| + env.Replicate('destdir', ['footxt.txt'], REPLICATE_REPLACE = [
|
| + ('\\.txt', '.bar'), ('est', 'ist')])
|
| + will copy to 'distdir/footxt.bar'
|
| +
|
| + In the example above, note the use of \\ to escape the '.' character,
|
| + so that it doesn't act like the regexp '.' and match any character.
|
| +
|
| + Returns:
|
| + A list of the destination nodes from the calls to env.Install().
|
| + """
|
| + replace_list = kw.get('REPLICATE_REPLACE', env.get('REPLICATE_REPLACE', []))
|
| +
|
| + dest_nodes = []
|
| + for target_entry in env.Flatten(target):
|
| + for source_entry in env.Flatten(source):
|
| + if type(source_entry) == str:
|
| + # Search for matches for each source entry
|
| + source_nodes = env.Glob(source_entry)
|
| + else:
|
| + # Source entry is already a file or directory node; no need to glob it
|
| + source_nodes = [source_entry]
|
| + for s in source_nodes:
|
| + target_name = env.Dir(target_entry).abspath + '/' + s.name
|
| + # We need to use the following incantation rather than s.isdir() in
|
| + # order to handle chained replicates (A -> B -> C). The isdir()
|
| + # function is not properly defined in all of the Node type classes in
|
| + # SCons. This change is particularly crucial if hardlinks are present,
|
| + # in which case using isdir() can cause files to be unintentionally
|
| + # deleted.
|
| + # TODO(bradnelson): Look into fixing the innards of SCons so this isn't
|
| + # needed.
|
| + if str(s.__class__) == 'SCons.Node.FS.Dir':
|
| + # Recursively copy all files in subdir. Since glob('*') doesn't
|
| + # match dot files, also glob('.*').
|
| + dest_nodes += env.Replicate(
|
| + target_name, [s.abspath + '/*', s.abspath + '/.*'],
|
| + REPLICATE_REPLACE=replace_list)
|
| + else:
|
| + # Apply replacement strings, if any
|
| + for r in replace_list:
|
| + target_name = re.sub(r[0], r[1], target_name)
|
| + target = env.File(target_name)
|
| + if (target.has_builder()
|
| + and target.get_builder().name == 'InstallBuilder'
|
| + and target.sources == [s]):
|
| + # Already installed that file, so pass through the destination node
|
| + dest_nodes += [target]
|
| + else:
|
| + dest_nodes += env.InstallAs(target_name, s)
|
| +
|
| + # Return list of destination nodes
|
| + return dest_nodes
|
| +
|
| +
|
| +def generate(env):
|
| + # NOTE: SCons requires the use of this name, which fails gpylint.
|
| + """SCons entry point for this tool."""
|
| +
|
| + env.AddMethod(Replicate)
|
|
|