summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2014-07-02 23:22:38 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2014-07-02 23:24:10 -0700
commit05516389441e6818ff3ee22bb4e51d50b3bb5cd4 (patch)
tree3592d0b2cc494dae052b42e4136857a0efd85527 /lib
parenta7fd8be51468e923209ede9d517579042ab187a8 (diff)
downloadspack-05516389441e6818ff3ee22bb4e51d50b3bb5cd4.tar.gz
spack-05516389441e6818ff3ee22bb4e51d50b3bb5cd4.tar.bz2
spack-05516389441e6818ff3ee22bb4e51d50b3bb5cd4.tar.xz
spack-05516389441e6818ff3ee22bb4e51d50b3bb5cd4.zip
Add TAU package and routines to filter files, fix sed calls.
- TAU doesn't install to directories with '@' in the name. - Need to fix up its scripts. - routines to filter files as sed would, but using python regular expressions. - TAU package uses this.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/llnl/util/filesystem.py74
-rw-r--r--lib/spack/spack/__init__.py3
2 files changed, 75 insertions, 2 deletions
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index 80341f3ddc..11c3dee604 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -23,19 +23,91 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
__all__ = ['install', 'expand_user', 'working_dir', 'touch', 'mkdirp',
- 'join_path', 'ancestor', 'can_access']
+ 'join_path', 'ancestor', 'can_access', 'filter_file', 'change_sed_delimiter']
import os
+import sys
import re
import shutil
import errno
import getpass
from contextlib import contextmanager, closing
+from tempfile import NamedTemporaryFile
import llnl.util.tty as tty
from spack.util.compression import ALLOWED_ARCHIVE_TYPES
+def filter_file(regex, repl, *filenames):
+ """Like sed, but uses python regular expressions.
+
+ Filters every line of file through regex and replaces the file
+ with a filtered version. Preserves mode of filtered files.
+
+ As with re.sub, ``repl`` can be either a string or a callable.
+ If it is a callable, it is passed the match object and should
+ return a suitable replacement string. If it is a string, it
+ can contain ``\1``, ``\2``, etc. to represent back-substitution
+ as sed would allow.
+ """
+ # Keep callables intact
+ if not hasattr(repl, '__call__'):
+ # Allow strings to use \1, \2, etc. for replacement, like sed
+ unescaped = repl.replace(r'\\', '\\')
+ repl = lambda m: re.sub(
+ r'\\([0-9])', lambda x: m.group(int(x.group(1))), unescaped)
+
+ for filename in filenames:
+ backup = filename + "~"
+ shutil.copy(filename, backup)
+ try:
+ with closing(open(backup)) as infile:
+ with closing(open(filename, 'w')) as outfile:
+ for line in infile:
+ foo = re.sub(regex, repl, line)
+ outfile.write(foo)
+ except:
+ # clean up the original file on failure.
+ shutil.move(backup, filename)
+ raise
+
+
+def change_sed_delimiter(old_delim, new_delim, *filenames):
+ """Find all sed search/replace commands and change the delimiter.
+ e.g., if the file contains seds that look like 's///', you can
+ call change_sed_delimeter('/', '@', file) to change the
+ delimiter to '@'.
+
+ NOTE that this routine will fail if the delimiter is ' or ".
+ Handling those is left for future work.
+ """
+ assert(len(old_delim) == 1)
+ assert(len(new_delim) == 1)
+
+ # TODO: handle these cases one day?
+ assert(old_delim != '"')
+ assert(old_delim != "'")
+ assert(new_delim != '"')
+ assert(new_delim != "'")
+
+ whole_lines = "^s@([^@]*)@(.*)@[gIp]$"
+ whole_lines = whole_lines.replace('@', old_delim)
+
+ single_quoted = r"'s@((?:\\'|[^@'])*)@((?:\\'|[^'])*)@[gIp]?'"
+ single_quoted = single_quoted.replace('@', old_delim)
+
+ double_quoted = r'"s@((?:\\"|[^@"])*)@((?:\\"|[^"])*)@[gIp]?"'
+ double_quoted = double_quoted.replace('@', old_delim)
+
+ repl = r's@\1@\2@g'
+ repl = repl.replace('@', new_delim)
+
+ for f in filenames:
+ filter_file(whole_lines, repl, f)
+ filter_file(single_quoted, "'%s'" % repl, f)
+ filter_file(double_quoted, '"%s"' % repl, f)
+
+
def install(src, dest):
"""Manually install a file to a particular location."""
tty.info("Installing %s to %s" % (src, dest))
diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py
index 904c6262c8..58796d8854 100644
--- a/lib/spack/spack/__init__.py
+++ b/lib/spack/spack/__init__.py
@@ -33,7 +33,8 @@
# TODO: it's not clear where all the stuff that needs to be included in packages
# should live. This file is overloaded for spack core vs. for packages.
__all__ = ['Package', 'when', 'provides', 'depends_on',
- 'patch', 'Version', 'working_dir', 'which', 'Executable']
+ 'patch', 'Version', 'working_dir', 'which', 'Executable',
+ 'filter_file', 'change_sed_delimiter']
import os
import tempfile