From 05516389441e6818ff3ee22bb4e51d50b3bb5cd4 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Wed, 2 Jul 2014 23:22:38 -0700 Subject: 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. --- bin/spack | 1 + lib/spack/llnl/util/filesystem.py | 74 ++++++++++++++++++++++++++++++++++++++- lib/spack/spack/__init__.py | 3 +- var/spack/packages/tau/package.py | 20 +++++++++++ 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 var/spack/packages/tau/package.py diff --git a/bin/spack b/bin/spack index a0ce203d63..c63178b191 100755 --- a/bin/spack +++ b/bin/spack @@ -44,6 +44,7 @@ try: working_dir = os.getcwd() except OSError: os.chdir(SPACK_PREFIX) + working_dir = SPACK_PREFIX # clean up the scope and start using spack package instead. del SPACK_FILE, SPACK_PREFIX, SPACK_LIB_PATH 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 diff --git a/var/spack/packages/tau/package.py b/var/spack/packages/tau/package.py new file mode 100644 index 0000000000..373c51c8b8 --- /dev/null +++ b/var/spack/packages/tau/package.py @@ -0,0 +1,20 @@ +from spack import * + +class Tau(Package): + """A portable profiling and tracing toolkit for performance + analysis of parallel programs written in Fortran, C, C++, UPC, + Java, Python.""" + homepage = "http://www.cs.uoregon.edu/research/tau" + url = "http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/tau-2.23.1.tar.gz" + + versions = { '2.23.1' : '6593b47ae1e7a838e632652f0426fe72', } + + def install(self, spec, prefix): + # TAU isn't happy with directories that have '@' in the path. Sigh. + change_sed_delimiter('@', ';', 'configure') + change_sed_delimiter('@', ';', 'utils/FixMakefile') + change_sed_delimiter('@', ';', 'utils/FixMakefile.sed.default') + + # After that, it's relatively standard. + configure("-prefix=%s" % prefix) + make("install") -- cgit v1.2.3-60-g2f50