From 560f2c299a384183d314a0c4968169a0f35cc9c1 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Thu, 12 Mar 2015 10:32:29 -0700 Subject: Add install_tree, force_symlink helper functions. --- lib/spack/llnl/util/filesystem.py | 121 ++++++++++++++++++++++++++++++++--- lib/spack/llnl/util/link_tree.py | 82 ------------------------ lib/spack/spack/build_environment.py | 25 ++++---- 3 files changed, 125 insertions(+), 103 deletions(-) (limited to 'lib') diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index 576aeb16bd..1fdd25f608 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -22,9 +22,10 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## -__all__ = ['set_install_permissions', 'install', 'expand_user', 'working_dir', - 'touch', 'touchp', 'mkdirp', 'force_remove', 'join_path', 'ancestor', - 'can_access', 'filter_file', 'change_sed_delimiter', 'is_exe'] +__all__ = ['set_install_permissions', 'install', 'install_tree', 'traverse_tree', + 'expand_user', 'working_dir', 'touch', 'touchp', 'mkdirp', + 'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file', + 'change_sed_delimiter', 'is_exe', 'force_symlink'] import os import sys @@ -140,12 +141,7 @@ def set_install_permissions(path): os.chmod(path, 0644) -def install(src, dest): - """Manually install a file to a particular location.""" - tty.info("Installing %s to %s" % (src, dest)) - shutil.copy(src, dest) - set_install_permissions(dest) - +def copy_mode(src, dest): src_mode = os.stat(src).st_mode dest_mode = os.stat(dest).st_mode if src_mode | stat.S_IXUSR: dest_mode |= stat.S_IXUSR @@ -154,6 +150,24 @@ def install(src, dest): os.chmod(dest, dest_mode) +def install(src, dest): + """Manually install a file to a particular location.""" + tty.info("Installing %s to %s" % (src, dest)) + shutil.copy(src, dest) + set_install_permissions(dest) + copy_mode(src, dest) + + +def install_tree(src, dest, **kwargs): + """Manually install a file to a particular location.""" + tty.info("Installing %s to %s" % (src, dest)) + shutil.copytree(src, dest, **kwargs) + + for s, d in traverse_tree(src, dest, follow_nonexisting=False): + set_install_permissions(d) + copy_mode(s, d) + + def is_exe(path): """True if path is an executable file.""" return os.path.isfile(path) and os.access(path, os.X_OK) @@ -210,6 +224,14 @@ def touchp(path): touch(path) +def force_symlink(src, dest): + try: + os.symlink(src, dest) + except OSError, e: + os.remove(dest) + os.symlink(src, dest) + + def join_path(prefix, *args): path = str(prefix) for elt in args: @@ -228,3 +250,84 @@ def ancestor(dir, n=1): def can_access(file_name): """True if we have read/write access to the file.""" return os.access(file_name, os.R_OK|os.W_OK) + + +def traverse_tree(source_root, dest_root, rel_path='', **kwargs): + """Traverse two filesystem trees simultaneously. + + Walks the LinkTree directory in pre or post order. Yields each + file in the source directory with a matching path from the dest + directory, along with whether the file is a directory. + e.g., for this tree:: + + root/ + a/ + file1 + file2 + b/ + file3 + + When called on dest, this yields:: + + ('root', 'dest') + ('root/a', 'dest/a') + ('root/a/file1', 'dest/a/file1') + ('root/a/file2', 'dest/a/file2') + ('root/b', 'dest/b') + ('root/b/file3', 'dest/b/file3') + + Optional args: + + order=[pre|post] -- Whether to do pre- or post-order traveral. + + ignore= -- Predicate indicating which files to ignore. + + follow_nonexisting -- Whether to descend into directories in + src that do not exit in dest. Default True. + + follow_links -- Whether to descend into symlinks in src. + + """ + follow_nonexisting = kwargs.get('follow_nonexisting', True) + follow_links = kwargs.get('follow_link', False) + + # Yield in pre or post order? + order = kwargs.get('order', 'pre') + if order not in ('pre', 'post'): + raise ValueError("Order must be 'pre' or 'post'.") + + # List of relative paths to ignore under the src root. + ignore = kwargs.get('ignore', lambda filename: False) + + # Don't descend into ignored directories + if ignore(rel_path): + return + + source_path = os.path.join(source_root, rel_path) + dest_path = os.path.join(dest_root, rel_path) + + # preorder yields directories before children + if order == 'pre': + yield (source_path, dest_path) + + for f in os.listdir(source_path): + source_child = os.path.join(source_path, f) + dest_child = os.path.join(dest_path, f) + rel_child = os.path.join(rel_path, f) + + # Treat as a directory + if os.path.isdir(source_child) and ( + follow_links or not os.path.islink(source_child)): + + # When follow_nonexisting isn't set, don't descend into dirs + # in source that do not exist in dest + if follow_nonexisting or os.path.exists(dest_child): + tuples = traverse_tree(source_root, dest_root, rel_child, **kwargs) + for t in tuples: yield t + + # Treat as a file. + elif not ignore(os.path.join(rel_path, f)): + yield (source_child, dest_child) + + if order == 'post': + yield (source_path, dest_path) diff --git a/lib/spack/llnl/util/link_tree.py b/lib/spack/llnl/util/link_tree.py index 4d778eca1e..583f077b79 100644 --- a/lib/spack/llnl/util/link_tree.py +++ b/lib/spack/llnl/util/link_tree.py @@ -32,88 +32,6 @@ from llnl.util.filesystem import * empty_file_name = '.spack-empty' -def traverse_tree(source_root, dest_root, rel_path='', **kwargs): - """Traverse two filesystem trees simultaneously. - - Walks the LinkTree directory in pre or post order. Yields each - file in the source directory with a matching path from the dest - directory, along with whether the file is a directory. - e.g., for this tree:: - - root/ - a/ - file1 - file2 - b/ - file3 - - When called on dest, this yields:: - - ('root', 'dest') - ('root/a', 'dest/a') - ('root/a/file1', 'dest/a/file1') - ('root/a/file2', 'dest/a/file2') - ('root/b', 'dest/b') - ('root/b/file3', 'dest/b/file3') - - Optional args: - - order=[pre|post] -- Whether to do pre- or post-order traveral. - - ignore= -- Predicate indicating which files to ignore. - - follow_nonexisting -- Whether to descend into directories in - src that do not exit in dest. Default True. - - follow_links -- Whether to descend into symlinks in src. - - """ - follow_nonexisting = kwargs.get('follow_nonexisting', True) - follow_links = kwargs.get('follow_link', False) - - # Yield in pre or post order? - order = kwargs.get('order', 'pre') - if order not in ('pre', 'post'): - raise ValueError("Order must be 'pre' or 'post'.") - - # List of relative paths to ignore under the src root. - ignore = kwargs.get('ignore', lambda filename: False) - - # Don't descend into ignored directories - if ignore(rel_path): - return - - source_path = os.path.join(source_root, rel_path) - dest_path = os.path.join(dest_root, rel_path) - - # preorder yields directories before children - if order == 'pre': - yield (source_path, dest_path) - - for f in os.listdir(source_path): - source_child = os.path.join(source_path, f) - dest_child = os.path.join(dest_path, f) - rel_child = os.path.join(rel_path, f) - - # Treat as a directory - if os.path.isdir(source_child) and ( - follow_links or not os.path.islink(source_child)): - - # When follow_nonexisting isn't set, don't descend into dirs - # in source that do not exist in dest - if follow_nonexisting or os.path.exists(dest_child): - tuples = traverse_tree(source_root, dest_root, rel_child, **kwargs) - for t in tuples: yield t - - # Treat as a file. - elif not ignore(os.path.join(rel_path, f)): - yield (source_child, dest_child) - - if order == 'post': - yield (source_path, dest_path) - - - class LinkTree(object): """Class to create trees of symbolic links from a source directory. diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index 59b25d96e7..d11e2e270c 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -189,18 +189,19 @@ def set_module_variables_for_package(pkg): m.std_cmake_args.append('-DCMAKE_INSTALL_RPATH=%s' % ":".join(get_rpaths(pkg))) # Emulate some shell commands for convenience - m.pwd = os.getcwd - m.cd = os.chdir - m.mkdir = os.mkdir - m.makedirs = os.makedirs - m.remove = os.remove - m.removedirs = os.removedirs - m.symlink = os.symlink - - m.mkdirp = mkdirp - m.install = install - m.rmtree = shutil.rmtree - m.move = shutil.move + m.pwd = os.getcwd + m.cd = os.chdir + m.mkdir = os.mkdir + m.makedirs = os.makedirs + m.remove = os.remove + m.removedirs = os.removedirs + m.symlink = os.symlink + + m.mkdirp = mkdirp + m.install = install + m.install_tree = install_tree + m.rmtree = shutil.rmtree + m.move = shutil.move # Useful directories within the prefix are encapsulated in # a Prefix object. -- cgit v1.2.3-70-g09d2