summaryrefslogtreecommitdiffstats
path: root/o3d/site_scons/site_tools/replicate.py
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/site_scons/site_tools/replicate.py')
-rw-r--r--o3d/site_scons/site_tools/replicate.py125
1 files changed, 125 insertions, 0 deletions
diff --git a/o3d/site_scons/site_tools/replicate.py b/o3d/site_scons/site_tools/replicate.py
new file mode 100644
index 0000000..a434c72
--- /dev/null
+++ b/o3d/site_scons/site_tools/replicate.py
@@ -0,0 +1,125 @@
+#!/usr/bin/python2.4
+# Copyright 2009, 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 each target
+ directory.
+ 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_REPLACE: 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: 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 hasattr(target.get_builder(), 'name')
+ and target.get_builder().name == 'InstallBuilder'
+ and target.sources == [s]):
+ # Already installed that file, so pass through the destination node
+ # TODO: Is there a better way to determine if this is a duplicate
+ # call to install?
+ 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)