diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/docs/.gitignore | 1 | ||||
-rw-r--r-- | lib/spack/docs/Makefile | 13 | ||||
-rw-r--r-- | lib/spack/docs/_themes/sphinx_rtd_theme/footer.html | 2 | ||||
-rw-r--r-- | lib/spack/docs/conf.py | 2 | ||||
-rw-r--r-- | lib/spack/docs/features.rst | 2 | ||||
-rw-r--r-- | lib/spack/docs/index.rst | 1 | ||||
-rw-r--r-- | lib/spack/external/argparse.py | 6 | ||||
-rw-r--r-- | lib/spack/llnl/util/filesystem.py | 27 | ||||
-rw-r--r-- | lib/spack/llnl/util/tty/colify.py | 27 | ||||
-rw-r--r-- | lib/spack/spack/__init__.py | 4 | ||||
-rw-r--r-- | lib/spack/spack/cmd/checksum.py | 8 | ||||
-rw-r--r-- | lib/spack/spack/cmd/edit.py | 49 | ||||
-rw-r--r-- | lib/spack/spack/cmd/info.py | 103 | ||||
-rw-r--r-- | lib/spack/spack/cmd/list.py | 33 | ||||
-rw-r--r-- | lib/spack/spack/cmd/location.py | 27 | ||||
-rw-r--r-- | lib/spack/spack/compiler.py | 6 | ||||
-rw-r--r-- | lib/spack/spack/compilers/gcc.py | 2 | ||||
-rw-r--r-- | lib/spack/spack/fetch_strategy.py | 5 | ||||
-rw-r--r-- | lib/spack/spack/package.py | 2 | ||||
-rw-r--r-- | lib/spack/spack/test/__init__.py | 1 | ||||
-rw-r--r-- | lib/spack/spack/test/url_substitution.py | 73 | ||||
-rw-r--r-- | lib/spack/spack/url.py | 20 |
22 files changed, 356 insertions, 58 deletions
diff --git a/lib/spack/docs/.gitignore b/lib/spack/docs/.gitignore index 4d5300fbb9..7701dd9f12 100644 --- a/lib/spack/docs/.gitignore +++ b/lib/spack/docs/.gitignore @@ -1,2 +1,3 @@ +package_list.rst spack*.rst _build diff --git a/lib/spack/docs/Makefile b/lib/spack/docs/Makefile index 4baba720ef..e3068ea10c 100644 --- a/lib/spack/docs/Makefile +++ b/lib/spack/docs/Makefile @@ -22,6 +22,12 @@ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . all: html # +# This autogenerates a package list. +# +package_list: + spack info -r > package_list.rst + +# # This creates a git repository and commits generated html docs. # It them pushes the new branch into THIS repository as gh-pages. # @@ -36,12 +42,14 @@ gh-pages: _build/html touch .nojekyll && \ git init && \ git add . && \ - git commit -m "Initial commit" && \ + git commit -m "Spack Documentation" && \ git push -f $$root master:gh-pages && \ rm -rf .git upload: rsync -avz --rsh=ssh --delete _build/html/ cab:/usr/global/web-pages/lc/www/adept/docs/spack + git push -f origin gh-pages + git push -f github gh-pages apidoc: sphinx-apidoc -T -o . $(PYTHONPATH)/spack @@ -69,9 +77,10 @@ help: @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: + -rm -f package_list.rst -rm -rf $(BUILDDIR)/* $(APIDOC_FILES) -html: apidoc +html: apidoc package_list $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/lib/spack/docs/_themes/sphinx_rtd_theme/footer.html b/lib/spack/docs/_themes/sphinx_rtd_theme/footer.html index 0eccd11178..5ec315e58f 100644 --- a/lib/spack/docs/_themes/sphinx_rtd_theme/footer.html +++ b/lib/spack/docs/_themes/sphinx_rtd_theme/footer.html @@ -13,7 +13,7 @@ <hr/> <p> - © Copyright 2013, + © Copyright 2013-2014, <a href="https://scalability.llnl.gov/">Lawrence Livermore National Laboratory</a>. <br/> Written by Todd Gamblin, <a href="mailto:tgamblin@llnl.gov">tgamblin@llnl.gov</a>, LLNL-CODE-647188 diff --git a/lib/spack/docs/conf.py b/lib/spack/docs/conf.py index 700cb00299..b4d49c594d 100644 --- a/lib/spack/docs/conf.py +++ b/lib/spack/docs/conf.py @@ -90,7 +90,7 @@ master_doc = 'index' # General information about the project. project = u'Spack' -copyright = u'2013, Lawrence Livermore National Laboratory' +copyright = u'2013-2014, Lawrence Livermore National Laboratory' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/lib/spack/docs/features.rst b/lib/spack/docs/features.rst index 22dc594d7f..b39dcd3390 100644 --- a/lib/spack/docs/features.rst +++ b/lib/spack/docs/features.rst @@ -93,7 +93,7 @@ creates a simple python file: homepage = "http://www.example.com/" url = "http://www.mr511.de/software/libelf-0.8.13.tar.gz" - versions = { '0.8.13' : '4136d7b4c04df68b686570afa26988ac' } + version('0.8.13', '4136d7b4c04df68b686570afa26988ac') def install(self, prefix): configure("--prefix=%s" % prefix) diff --git a/lib/spack/docs/index.rst b/lib/spack/docs/index.rst index ac0eac93f3..73eff43ab7 100644 --- a/lib/spack/docs/index.rst +++ b/lib/spack/docs/index.rst @@ -48,6 +48,7 @@ Table of Contents packaging_guide site_configuration developer_guide + package_list API Docs <spack> Indices and tables diff --git a/lib/spack/external/argparse.py b/lib/spack/external/argparse.py index c8dfdd3bed..42b64ee7be 100644 --- a/lib/spack/external/argparse.py +++ b/lib/spack/external/argparse.py @@ -108,6 +108,8 @@ import re as _re import sys as _sys import textwrap as _textwrap +from llnl.util.tty.colify import colified + from gettext import gettext as _ try: @@ -2285,8 +2287,8 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def _check_value(self, action, value): # converted value must be one of the choices (if specified) if action.choices is not None and value not in action.choices: - tup = value, ', '.join(map(repr, action.choices)) - msg = _('invalid choice: %r (choose from %s)') % tup + cols = colified(sorted(action.choices), indent=4, tty=True) + msg = _('invalid choice: %r choose from:\n%s') % (value, cols) raise ArgumentError(action, msg) # ======================= diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index 3782aefcce..a70111b915 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -38,7 +38,7 @@ import llnl.util.tty as tty from spack.util.compression import ALLOWED_ARCHIVE_TYPES -def filter_file(regex, repl, *filenames): +def filter_file(regex, repl, *filenames, **kwargs): """Like sed, but uses python regular expressions. Filters every line of file through regex and replaces the file @@ -49,16 +49,31 @@ def filter_file(regex, repl, *filenames): return a suitable replacement string. If it is a string, it can contain ``\1``, ``\2``, etc. to represent back-substitution as sed would allow. + + Keyword Options: + string[=False] If True, treat regex as a plain string. + backup[=True] Make a backup files suffixed with ~ + ignore_absent[=False] Ignore any files that don't exist. """ - # Keep callables intact - if not hasattr(repl, '__call__'): - # Allow strings to use \1, \2, etc. for replacement, like sed + string = kwargs.get('string', False) + backup = kwargs.get('backup', True) + ignore_absent = kwargs.get('ignore_absent', False) + + # Allow strings to use \1, \2, etc. for replacement, like sed + if not callable(repl): unescaped = repl.replace(r'\\', '\\') repl = lambda m: re.sub( r'\\([0-9])', lambda x: m.group(int(x.group(1))), unescaped) + if string: + regex = re.escape(regex) + for filename in filenames: backup = filename + "~" + + if ignore_absent and not os.path.exists(filename): + continue + shutil.copy(filename, backup) try: with closing(open(backup)) as infile: @@ -71,6 +86,10 @@ def filter_file(regex, repl, *filenames): shutil.move(backup, filename) raise + finally: + if not backup: + shutil.rmtree(backup, ignore_errors=True) + def change_sed_delimiter(old_delim, new_delim, *filenames): """Find all sed search/replace commands and change the delimiter. diff --git a/lib/spack/llnl/util/tty/colify.py b/lib/spack/llnl/util/tty/colify.py index 1b04f1012f..ff06241937 100644 --- a/lib/spack/llnl/util/tty/colify.py +++ b/lib/spack/llnl/util/tty/colify.py @@ -37,9 +37,11 @@ import sys import fcntl import termios import struct +from StringIO import StringIO from llnl.util.tty import terminal_size + class ColumnConfig: def __init__(self, cols): self.cols = cols @@ -102,16 +104,20 @@ def colify(elts, **options): output = options.get("output", sys.stdout) indent = options.get("indent", 0) padding = options.get("padding", 2) + tty = options.get('tty', None) # elts needs to be an array of strings so we can count the elements elts = [str(elt) for elt in elts] if not elts: - return + return (0, ()) + + if not tty: + if tty is False or not isatty(output): + for elt in elts: + output.write("%s\n" % elt) - if not isatty(output): - for elt in elts: - output.write("%s\n" % elt) - return + maxlen = max(len(str(s)) for s in elts) + return (1, (maxlen,)) console_cols = options.get("cols", None) if not console_cols: @@ -146,6 +152,17 @@ def colify(elts, **options): if row == rows_last_col: cols -= 1 + return (config.cols, tuple(config.widths)) + + +def colified(elts, **options): + """Invokes the colify() function but returns the result as a string + instead of writing it to an output string.""" + sio = StringIO() + options['output'] = sio + colify(elts, **options) + return sio.getvalue() + if __name__ == "__main__": import optparse diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index bf91a885ca..da7088640f 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -137,9 +137,9 @@ sys_type = None # 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', 'Version', 'when'] +__all__ = ['Package', 'Version', 'when', 'ver'] from spack.package import Package -from spack.version import Version +from spack.version import Version, ver from spack.multimethod import when import llnl.util.filesystem diff --git a/lib/spack/spack/cmd/checksum.py b/lib/spack/spack/cmd/checksum.py index 5a8109b70f..f9218b9df1 100644 --- a/lib/spack/spack/cmd/checksum.py +++ b/lib/spack/spack/cmd/checksum.py @@ -96,7 +96,7 @@ def checksum(parser, args): if not versions: tty.die("Could not fetch any available versions for %s." % pkg.name) - versions = list(reversed(versions)) + versions = list(reversed(sorted(versions))) urls = [pkg.url_for_version(v) for v in versions] @@ -117,7 +117,5 @@ def checksum(parser, args): if not version_hashes: tty.die("Could not fetch any available versions for %s." % pkg.name) - dict_string = [" '%s' : '%s'," % (v, h) for v, h in version_hashes] - dict_string = ['{'] + dict_string + ["}"] - - tty.msg("Checksummed new versions of %s:" % pkg.name, *dict_string) + version_lines = [" version('%s', '%s')" % (v, h) for v, h in version_hashes] + tty.msg("Checksummed new versions of %s:" % pkg.name, *version_lines) diff --git a/lib/spack/spack/cmd/edit.py b/lib/spack/spack/cmd/edit.py index 3647186a3c..842dcd7faf 100644 --- a/lib/spack/spack/cmd/edit.py +++ b/lib/spack/spack/cmd/edit.py @@ -27,9 +27,10 @@ import string from contextlib import closing import llnl.util.tty as tty -from llnl.util.filesystem import mkdirp +from llnl.util.filesystem import mkdirp, join_path import spack +import spack.cmd from spack.util.naming import mod_to_class description = "Open package files in $EDITOR" @@ -58,31 +59,43 @@ def setup_parser(subparser): '-f', '--force', dest='force', action='store_true', help="Open a new file in $EDITOR even if package doesn't exist.") subparser.add_argument( + '-c', '--command', dest='edit_command', action='store_true', + help="Edit the command with the supplied name instead of a package.") + subparser.add_argument( 'name', nargs='?', default=None, help="name of package to edit") def edit(parser, args): name = args.name - # By default open the directory where packages live. - if not name: - path = spack.packages_path + if args.edit_command: + if not name: + path = spack.cmd.command_path + else: + path = join_path(spack.cmd.command_path, name + ".py") + if not os.path.exists(path): + tty.die("No command named '%s'." % name) + else: - path = spack.db.filename_for_package_name(name) - - if os.path.exists(path): - if not os.path.isfile(path): - tty.die("Something's wrong. '%s' is not a file!" % path) - if not os.access(path, os.R_OK|os.W_OK): - tty.die("Insufficient permissions on '%s'!" % path) - elif not args.force: - tty.die("No package '%s'. Use spack create, or supply -f/--force " - "to edit a new file." % name) + # By default open the directory where packages or commands live. + if not name: + path = spack.packages_path else: - mkdirp(os.path.dirname(path)) - with closing(open(path, "w")) as pkg_file: - pkg_file.write( - package_template.substitute(name=name, class_name=mod_to_class(name))) + path = spack.db.filename_for_package_name(name) + + if os.path.exists(path): + if not os.path.isfile(path): + tty.die("Something's wrong. '%s' is not a file!" % path) + if not os.access(path, os.R_OK|os.W_OK): + tty.die("Insufficient permissions on '%s'!" % path) + elif not args.force: + tty.die("No package '%s'. Use spack create, or supply -f/--force " + "to edit a new file." % name) + else: + mkdirp(os.path.dirname(path)) + with closing(open(path, "w")) as pkg_file: + pkg_file.write( + package_template.substitute(name=name, class_name=mod_to_class(name))) # If everything checks out, go ahead and edit. spack.editor(path) diff --git a/lib/spack/spack/cmd/info.py b/lib/spack/spack/cmd/info.py index a1c35269be..29568b8c5d 100644 --- a/lib/spack/spack/cmd/info.py +++ b/lib/spack/spack/cmd/info.py @@ -24,23 +24,98 @@ ############################################################################## import re import textwrap -from llnl.util.tty.colify import colify +from StringIO import StringIO +from llnl.util.tty.colify import * import spack import spack.fetch_strategy as fs description = "Get detailed information on a particular package" def setup_parser(subparser): - subparser.add_argument('name', metavar="PACKAGE", help="name of packages to get info on") + subparser.add_argument('-r', '--rst', action='store_true', + help="List all packages in reStructured text, for docs.") + subparser.add_argument('name', metavar="PACKAGE", nargs='?', help="name of packages to get info on") -def info(parser, args): - pkg = spack.db.get(args.name) +def format_doc(pkg, **kwargs): + """Wrap doc string at 72 characters and format nicely""" + indent = kwargs.get('indent', 0) + + if not pkg.__doc__: + return "" + + doc = re.sub(r'\s+', ' ', pkg.__doc__) + lines = textwrap.wrap(doc, 72) + results = StringIO() + for line in lines: + results.write((" " * indent) + line + "\n") + return results.getvalue() + + +def github_url(pkg): + """Link to a package file on github.""" + return ("https://github.com/scalability-llnl/spack/blob/master/var/spack/packages/%s/package.py" % + pkg.name) + + +def rst_table(elts): + """Print out a RST-style table.""" + cols = StringIO() + ncol, widths = colify(elts, output=cols, tty=True) + header = " ".join("=" * (w-1) for w in widths) + return "%s\n%s%s" % (header, cols.getvalue(), header) + + +def info_rst(): + """Print out information on all packages in restructured text.""" + pkgs = sorted(spack.db.all_packages(), key=lambda s:s.name.lower()) + + print "Package List" + print "==================" + + print "This is a list of things you can install using Spack. It is" + print "automatically generated based on the packages in the latest Spack" + print "release." + print + + print "Spack currently has %d mainline packages:" % len(pkgs) + print + print rst_table("`%s`_" % p.name for p in pkgs) + print + print "-----" + + # Output some text for each package. + for pkg in pkgs: + print + print ".. _%s:" % pkg.name + print + print pkg.name + print "-" * len(pkg.name) + print "Links" + print " * `Homepage <%s>`__" % pkg.homepage + print " * `%s/package.py <%s>`__" % (pkg.name, github_url(pkg)) + print + if pkg.versions: + print "Versions:" + print " " + ", ".join(str(v) for v in reversed(sorted(pkg.versions))) + if pkg.dependencies: + print "Dependencies" + print " " + ", ".join("`%s`_" % d if d != "mpi" else d + for d in pkg.dependencies) + print + print "Description" + print format_doc(pkg, indent=2) + print + print "-----" + + +def info_text(pkg): + """Print out a plain text description of a package.""" print "Package: ", pkg.name print "Homepage: ", pkg.homepage print - print "Versions: " + print "Safe versions: " if not pkg.versions: print("None.") @@ -59,7 +134,7 @@ def info(parser, args): print " None" print - print "Virtual pkgs: " + print "Virtual packages: " if pkg.provided: for spec, when in pkg.provided.items(): print " %s provides %s" % (when, spec) @@ -69,9 +144,17 @@ def info(parser, args): print print "Description:" if pkg.__doc__: - doc = re.sub(r'\s+', ' ', pkg.__doc__) - lines = textwrap.wrap(doc, 72) - for line in lines: - print " " + line + print format_doc(pkg, indent=4) else: print " None" + + +def info(parser, args): + if args.rst: + info_rst() + + else: + if not args.name: + tty.die("You must supply a package name.") + pkg = spack.db.get(args.name) + info_text(pkg) diff --git a/lib/spack/spack/cmd/list.py b/lib/spack/spack/cmd/list.py index 2b996371ea..5c7051d6a9 100644 --- a/lib/spack/spack/cmd/list.py +++ b/lib/spack/spack/cmd/list.py @@ -22,15 +22,44 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## +import sys +import llnl.util.tty as tty +from external import argparse from llnl.util.tty.colify import colify + import spack +import fnmatch description ="List available spack packages" def setup_parser(subparser): - pass + subparser.add_argument( + 'filter', nargs=argparse.REMAINDER, + help='Optional glob patterns to filter results.') + subparser.add_argument( + '-i', '--insensitive', action='store_true', default=False, + help='Filtering will be case insensitive.') def list(parser, args): + # Start with all package names. + pkgs = spack.db.all_package_names() + + # filter if a filter arg was provided + if args.filter: + def match(p, f): + if args.insensitive: + p = p.lower() + f = f.lower() + return fnmatch.fnmatchcase(p, f) + pkgs = [p for p in pkgs if any(match(p, f) for f in args.filter)] + + # sort before displaying. + sorted_packages = sorted(pkgs, key=lambda s:s.lower()) + # Print all the package names in columns - colify(spack.db.all_package_names()) + indent=0 + if sys.stdout.isatty(): + tty.msg("%d packages." % len(sorted_packages)) + indent=2 + colify(sorted_packages, indent=indent) diff --git a/lib/spack/spack/cmd/location.py b/lib/spack/spack/cmd/location.py index e92737ab4e..3fc05d471d 100644 --- a/lib/spack/spack/cmd/location.py +++ b/lib/spack/spack/cmd/location.py @@ -49,6 +49,9 @@ def setup_parser(subparser): '-p', '--package-dir', action='store_true', help="Directory enclosing a spec's package.py file.") directories.add_argument( + '-P', '--packages', action='store_true', + help="Top-level packages directory for Spack.") + directories.add_argument( '-s', '--stage-dir', action='store_true', help="Stage directory for a spec.") directories.add_argument( '-b', '--build-dir', action='store_true', @@ -65,21 +68,39 @@ def location(parser, args): elif args.spack_root: print spack.prefix + elif args.packages: + print spack.db.root + else: - specs = spack.cmd.parse_specs(args.spec, concretize=True) + specs = spack.cmd.parse_specs(args.spec) if not specs: tty.die("You must supply a spec.") if len(specs) != 1: - tty.die("Too many specs. Need only one.") + tty.die("Too many specs. Supply only one.") spec = specs[0] if args.install_dir: - print spec.prefix + # install_dir command matches against installed specs. + matching_specs = spack.db.get_installed(spec) + if not matching_specs: + tty.die("Spec '%s' matches no installed packages." % spec) + + elif len(matching_specs) > 1: + args = ["%s matches multiple packages." % spec, + "Matching packages:"] + args += [" " + str(s) for s in matching_specs] + args += ["Use a more specific spec."] + tty.die(*args) + + print matching_specs[0].prefix elif args.package_dir: + # This one just needs the spec name. print join_path(spack.db.root, spec.name) else: + # These versions need concretized specs. + spec.concretize() pkg = spack.db.get(spec) if args.stage_dir: diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py index 90fbf08241..35e3b898ec 100644 --- a/lib/spack/spack/compiler.py +++ b/lib/spack/spack/compiler.py @@ -190,6 +190,12 @@ class Compiler(object): except ProcessError, e: tty.debug("Couldn't get version for compiler %s" % full_path, e) return None + except Exception, e: + # Catching "Exception" here is fine because it just + # means something went wrong running a candidate executable. + tty.debug("Error while executing candidate compiler %s" % full_path, + "%s: %s" %(e.__class__.__name__, e)) + return None successful = [key for key in parmap(check, checks) if key is not None] return dict(((v, p, s), path) for v, p, s, path in successful) diff --git a/lib/spack/spack/compilers/gcc.py b/lib/spack/spack/compilers/gcc.py index 097b24bb87..f0d27d590e 100644 --- a/lib/spack/spack/compilers/gcc.py +++ b/lib/spack/spack/compilers/gcc.py @@ -56,7 +56,7 @@ class Gcc(Compiler): return get_compiler_version( fc, '-dumpversion', # older gfortran versions don't have simple dumpversion output. - r'(?:GNU Fortran \(GCC\))?(\d+\.\d+\.\d+)') + r'(?:GNU Fortran \(GCC\))?(\d+\.\d+(?:\.\d+)?)') @classmethod diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py index 779cd76bae..98c78c2e08 100644 --- a/lib/spack/spack/fetch_strategy.py +++ b/lib/spack/spack/fetch_strategy.py @@ -144,6 +144,7 @@ class URLFetchStrategy(FetchStrategy): # Run curl but grab the mime type from the http headers headers = spack.curl('-#', # status bar '-O', # save file to disk + '-f', # fail on >400 errors '-D', '-', # print out HTML headers '-L', self.url, return_output=True, fail_on_error=False) @@ -153,6 +154,10 @@ class URLFetchStrategy(FetchStrategy): if self.archive_file: os.remove(self.archive_file) + if spack.curl.returncode == 22: + # This is a 404. Curl will print the error. + raise FailedDownloadError(url) + if spack.curl.returncode == 60: # This is a certificate error. Suggest spack -k raise FailedDownloadError( diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 160f84f9df..649e772a10 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -891,7 +891,7 @@ def find_versions_of_archive(archive_url, **kwargs): list_depth = kwargs.get('list_depth', 1) if not list_url: - list_url = os.path.dirname(archive_url) + list_url = url.find_list_url(archive_url) # This creates a regex from the URL with a capture group for the # version part of the URL. The capture group is converted to a diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py index aa986662bf..9eae3261c2 100644 --- a/lib/spack/spack/test/__init__.py +++ b/lib/spack/spack/test/__init__.py @@ -36,6 +36,7 @@ import spack.test.install """Names of tests to be included in Spack's test suite""" test_names = ['versions', 'url_parse', + 'url_substitution', 'packages', 'stage', 'spec_syntax', diff --git a/lib/spack/spack/test/url_substitution.py b/lib/spack/spack/test/url_substitution.py new file mode 100644 index 0000000000..db7ddd251d --- /dev/null +++ b/lib/spack/spack/test/url_substitution.py @@ -0,0 +1,73 @@ +############################################################################## +# Copyright (c) 2013, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://scalability-llnl.github.io/spack +# Please also see the LICENSE file for our notice and the LGPL. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License (as published by +# the Free Software Foundation) version 2.1 dated February 1999. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and +# conditions of the GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## +"""\ +This test does sanity checks on substituting new versions into URLs +""" +import unittest + +import spack +import spack.url as url +from spack.packages import PackageDB + + +class PackageSanityTest(unittest.TestCase): + def test_hypre_url_substitution(self): + base = "https://computation-rnd.llnl.gov/linear_solvers/download/hypre-2.9.0b.tar.gz" + + self.assertEqual(url.substitute_version(base, '2.9.0b'), base) + self.assertEqual( + url.substitute_version(base, '2.8.0b'), + "https://computation-rnd.llnl.gov/linear_solvers/download/hypre-2.8.0b.tar.gz") + self.assertEqual( + url.substitute_version(base, '2.7.0b'), + "https://computation-rnd.llnl.gov/linear_solvers/download/hypre-2.7.0b.tar.gz") + self.assertEqual( + url.substitute_version(base, '2.6.0b'), + "https://computation-rnd.llnl.gov/linear_solvers/download/hypre-2.6.0b.tar.gz") + self.assertEqual( + url.substitute_version(base, '1.14.0b'), + "https://computation-rnd.llnl.gov/linear_solvers/download/hypre-1.14.0b.tar.gz") + self.assertEqual( + url.substitute_version(base, '1.13.0b'), + "https://computation-rnd.llnl.gov/linear_solvers/download/hypre-1.13.0b.tar.gz") + self.assertEqual( + url.substitute_version(base, '2.0.0'), + "https://computation-rnd.llnl.gov/linear_solvers/download/hypre-2.0.0.tar.gz") + self.assertEqual( + url.substitute_version(base, '1.6.0'), + "https://computation-rnd.llnl.gov/linear_solvers/download/hypre-1.6.0.tar.gz") + + + def test_otf2_url_substitution(self): + base = "http://www.vi-hps.org/upload/packages/otf2/otf2-1.4.tar.gz" + + self.assertEqual(url.substitute_version(base, '1.4'), base) + + self.assertEqual( + url.substitute_version(base, '1.3.1'), + "http://www.vi-hps.org/upload/packages/otf2/otf2-1.3.1.tar.gz") + self.assertEqual( + url.substitute_version(base, '1.2.1'), + "http://www.vi-hps.org/upload/packages/otf2/otf2-1.2.1.tar.gz") diff --git a/lib/spack/spack/url.py b/lib/spack/spack/url.py index 902ce9817d..e2fbb19f5d 100644 --- a/lib/spack/spack/url.py +++ b/lib/spack/spack/url.py @@ -78,6 +78,26 @@ class UndetectableNameError(UrlParseError): "Couldn't parse package name in: " + path, path) +def find_list_url(url): + """Finds a good list URL for the supplied URL. This depends on + the site. By default, just assumes that a good list URL is the + dirname of an archive path. For github URLs, this returns the + URL of the project's releases page. + """ + + url_types = [ + # e.g. https://github.com/scalability-llnl/callpath/archive/v1.0.1.tar.gz + (r'^(https://github.com/[^/]+/[^/]+)/archive/', lambda m: m.group(1) + '/releases') + ] + + for pattern, fun in url_types: + match = re.search(pattern, url) + if match: + return fun(match) + else: + return os.path.dirname(url) + + def parse_version_string_with_indices(path): """Try to extract a version string from a filename or URL. This is taken largely from Homebrew's Version class.""" |