summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap9
-rw-r--r--lib/spack/spack/build_environment.py4
-rw-r--r--lib/spack/spack/cmd/create.py2
-rw-r--r--lib/spack/spack/compilers/__init__.py32
-rw-r--r--lib/spack/spack/directives.py2
-rw-r--r--lib/spack/spack/fetch_strategy.py127
-rw-r--r--lib/spack/spack/mirror.py84
-rw-r--r--lib/spack/spack/modules.py13
-rw-r--r--lib/spack/spack/package.py128
-rw-r--r--lib/spack/spack/repository.py7
-rw-r--r--lib/spack/spack/stage.py86
-rw-r--r--lib/spack/spack/test/__init__.py1
-rw-r--r--lib/spack/spack/test/install.py7
-rw-r--r--lib/spack/spack/test/mirror.py1
-rw-r--r--lib/spack/spack/test/pattern.py104
-rw-r--r--lib/spack/spack/util/pattern.py116
-rw-r--r--var/spack/repos/builtin/packages/SuiteSparse/package.py27
-rw-r--r--var/spack/repos/builtin/packages/arpack-ng/package.py57
-rw-r--r--var/spack/repos/builtin/packages/cmake/package.py20
-rw-r--r--var/spack/repos/builtin/packages/cryptopp/package.py31
-rw-r--r--var/spack/repos/builtin/packages/dakota/package.py55
-rw-r--r--var/spack/repos/builtin/packages/eigen/package.py5
-rw-r--r--var/spack/repos/builtin/packages/espresso/package.py65
-rw-r--r--var/spack/repos/builtin/packages/exodusii/exodus-cmake.patch12
-rw-r--r--var/spack/repos/builtin/packages/exodusii/package.py49
-rw-r--r--var/spack/repos/builtin/packages/gcc/package.py9
-rw-r--r--var/spack/repos/builtin/packages/hdf5/package.py9
-rw-r--r--var/spack/repos/builtin/packages/libedit/package.py2
-rw-r--r--var/spack/repos/builtin/packages/libgpg-error/package.py1
-rw-r--r--var/spack/repos/builtin/packages/llvm/package.py19
-rw-r--r--var/spack/repos/builtin/packages/mpich/package.py9
-rw-r--r--var/spack/repos/builtin/packages/ndiff/package.py21
-rw-r--r--var/spack/repos/builtin/packages/netcdf/package.py10
-rw-r--r--var/spack/repos/builtin/packages/netlib-scalapack/package.py4
-rw-r--r--var/spack/repos/builtin/packages/openblas/package.py2
-rw-r--r--var/spack/repos/builtin/packages/opencv/package.py50
-rw-r--r--var/spack/repos/builtin/packages/paraview/package.py1
-rw-r--r--var/spack/repos/builtin/packages/py-mpi4py/package.py2
-rw-r--r--var/spack/repos/builtin/packages/py-phonopy/package.py18
-rw-r--r--var/spack/repos/builtin/packages/py-pyyaml/package.py13
-rw-r--r--var/spack/repos/builtin/packages/qhull/package.py14
-rw-r--r--var/spack/repos/builtin/packages/qt/package.py3
-rw-r--r--var/spack/repos/builtin/packages/tetgen/package.py28
-rw-r--r--var/spack/repos/builtin/packages/triangle/package.py20
-rw-r--r--var/spack/repos/builtin/packages/trilinos/package.py38
-rw-r--r--var/spack/repos/builtin/packages/xz/package.py8
46 files changed, 1031 insertions, 294 deletions
diff --git a/.mailmap b/.mailmap
index 1b99da32b5..39ec183241 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1,13 +1,20 @@
Todd Gamblin <tgamblin@llnl.gov> George Todd Gamblin <gamblin2@llnl.gov>
+Todd Gamblin <tgamblin@llnl.gov> Todd Gamblin <gamblin2@llnl.gov>
Adam Moody <moody20@llnl.gov> Adam T. Moody <moody20@llnl.gov>
Alfredo Gimenez <gimenez1@llnl.gov> Alfredo Gimenez <alfredo.gimenez@gmail.com>
David Boehme <boehme3@llnl.gov> David Boehme <boehme3@sierra324.llnl.gov>
David Boehme <boehme3@llnl.gov> David Boehme <boehme3@sierra648.llnl.gov>
Kevin Brandstatter <kjbrandstatter@gmail.com> Kevin Brandstatter <kbrandst@hawk.iit.edu>
Luc Jaulmes <luc.jaulmes@bsc.es> Luc Jaulmes <jaulmes1@llnl.gov>
-Saravan Pantham <saravan.pantham@gmail.com> Saravan Pantham <pantham1@surface86.llnl.gov
+Saravan Pantham <saravan.pantham@gmail.com> Saravan Pantham <pantham1@surface86.llnl.gov>
Tom Scogland <tscogland@llnl.gov> Tom Scogland <scogland1@llnl.gov>
Tom Scogland <tscogland@llnl.gov> Tom Scogland <tom.scogland@gmail.com>
Joachim Protze <protze@rz.rwth-aachen.de> jprotze <protze@rz.rwth-aachen.de>
Gregory L. Lee <lee218@llnl.gov> Gregory L. Lee <lee218@surface86.llnl.gov>
+Gregory L. Lee <lee218@llnl.gov> Gregory L. Lee <lee218@cab687.llnl.gov>
+Gregory L. Lee <lee218@llnl.gov> Gregory L. Lee <lee218@cab690.llnl.gov>
+Gregory L. Lee <lee218@llnl.gov> Gregory L. Lee <lee218@catalyst159.llnl.gov>
Gregory L. Lee <lee218@llnl.gov> Gregory Lee <lee218@llnl.gov>
+Massimiliano Culpo <massimiliano.culpo@epfl.ch> Massimiliano Culpo <massimiliano.culpo@googlemail.com>
+Massimiliano Culpo <massimiliano.culpo@epfl.ch> alalazo <massimiliano.culpo@googlemail.com>
+Mark Miller <miller86@llnl.gov> miller86 <miller86@llnl.gov>
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index b2db83acb7..1b87778080 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -237,9 +237,9 @@ def set_module_variables_for_package(pkg, m):
def get_rpaths(pkg):
"""Get a list of all the rpaths for a package."""
rpaths = [pkg.prefix.lib, pkg.prefix.lib64]
- rpaths.extend(d.prefix.lib for d in pkg.spec.traverse(root=False)
+ rpaths.extend(d.prefix.lib for d in pkg.spec.dependencies.values()
if os.path.isdir(d.prefix.lib))
- rpaths.extend(d.prefix.lib64 for d in pkg.spec.traverse(root=False)
+ rpaths.extend(d.prefix.lib64 for d in pkg.spec.dependencies.values()
if os.path.isdir(d.prefix.lib64))
return rpaths
diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py
index edcea0718c..6809209046 100644
--- a/lib/spack/spack/cmd/create.py
+++ b/lib/spack/spack/cmd/create.py
@@ -222,7 +222,7 @@ def fetch_tarballs(url, name, args):
archives_to_fetch = 1
if not versions:
# If the fetch failed for some reason, revert to what the user provided
- versions = { version : url }
+ versions = { "version" : url }
elif len(versions) > 1:
tty.msg("Found %s versions of %s:" % (len(versions), name),
*spack.cmd.elide_list(
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index 6159ef576c..3a04bc2ebc 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -74,28 +74,36 @@ def _to_dict(compiler):
def get_compiler_config(arch=None, scope=None):
"""Return the compiler configuration for the specified architecture.
"""
- # If any configuration file has compilers, just stick with the
- # ones already configured.
- config = spack.config.get_config('compilers', scope=scope)
-
+ # Check whether we're on a front-end (native) architecture.
my_arch = spack.architecture.sys_type()
if arch is None:
arch = my_arch
- if arch in config:
- return config[arch]
-
- # Only for the current arch in *highest* scope: automatically try to
- # find compilers if none are configured yet.
- if arch == my_arch and scope == 'user':
+ def init_compiler_config():
+ """Compiler search used when Spack has no compilers."""
config[arch] = {}
compilers = find_compilers(*get_path('PATH'))
for compiler in compilers:
config[arch].update(_to_dict(compiler))
spack.config.update_config('compilers', config, scope=scope)
- return config[arch]
- return {}
+ config = spack.config.get_config('compilers', scope=scope)
+
+ # Update the configuration if there are currently no compilers
+ # configured. Avoid updating automatically if there ARE site
+ # compilers configured but no user ones.
+ if arch == my_arch and arch not in config:
+ if scope is None:
+ # We know no compilers were configured in any scope.
+ init_compiler_config()
+ elif scope == 'user':
+ # Check the site config and update the user config if
+ # nothing is configured at the site level.
+ site_config = spack.config.get_config('compilers', scope='site')
+ if not site_config:
+ init_compiler_config()
+
+ return config[arch] if arch in config else {}
def add_compilers_to_config(compilers, arch=None, scope=None):
diff --git a/lib/spack/spack/directives.py b/lib/spack/spack/directives.py
index 0b98211cb9..5745adce63 100644
--- a/lib/spack/spack/directives.py
+++ b/lib/spack/spack/directives.py
@@ -296,8 +296,8 @@ def resource(pkg, **kwargs):
raise RuntimeError(message)
when_spec = parse_anonymous_spec(when, pkg.name)
resources = pkg.resources.setdefault(when_spec, [])
- fetcher = from_kwargs(**kwargs)
name = kwargs.get('name')
+ fetcher = from_kwargs(**kwargs)
resources.append(Resource(name, fetcher, destination, placement))
diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py
index 337dd1e198..83a2dbb59c 100644
--- a/lib/spack/spack/fetch_strategy.py
+++ b/lib/spack/spack/fetch_strategy.py
@@ -44,6 +44,7 @@ import os
import sys
import re
import shutil
+import copy
from functools import wraps
import llnl.util.tty as tty
from llnl.util.filesystem import *
@@ -55,53 +56,59 @@ from spack.util.string import *
from spack.version import Version, ver
from spack.util.compression import decompressor_for, extension
+import spack.util.pattern as pattern
+
"""List of all fetch strategies, created by FetchStrategy metaclass."""
all_strategies = []
+
def _needs_stage(fun):
"""Many methods on fetch strategies require a stage to be set
using set_stage(). This decorator adds a check for self.stage."""
+
@wraps(fun)
def wrapper(self, *args, **kwargs):
if not self.stage:
raise NoStageError(fun)
return fun(self, *args, **kwargs)
+
return wrapper
class FetchStrategy(object):
"""Superclass of all fetch strategies."""
- enabled = False # Non-abstract subclasses should be enabled.
+ enabled = False # Non-abstract subclasses should be enabled.
required_attributes = None # Attributes required in version() args.
class __metaclass__(type):
"""This metaclass registers all fetch strategies in a list."""
+
def __init__(cls, name, bases, dict):
type.__init__(cls, name, bases, dict)
if cls.enabled: all_strategies.append(cls)
-
def __init__(self):
# The stage is initialized late, so that fetch strategies can be constructed
# at package construction time. This is where things will be fetched.
self.stage = None
-
def set_stage(self, stage):
"""This is called by Stage before any of the fetching
methods are called on the stage."""
self.stage = stage
-
# Subclasses need to implement these methods
def fetch(self): pass # Return True on success, False on fail.
+
def check(self): pass # Do checksum.
+
def expand(self): pass # Expand archive.
+
def reset(self): pass # Revert to freshly downloaded state.
def archive(self, destination): pass # Used to create tarball for mirror.
- def __str__(self): # Should be human readable URL.
+ def __str__(self): # Should be human readable URL.
return "FetchStrategy.__str___"
# This method is used to match fetch strategies to version()
@@ -111,6 +118,15 @@ class FetchStrategy(object):
return any(k in args for k in cls.required_attributes)
+@pattern.composite(interface=FetchStrategy)
+class FetchStrategyComposite(object):
+ """
+ Composite for a FetchStrategy object. Implements the GoF composite pattern.
+ """
+ matches = FetchStrategy.matches
+ set_stage = FetchStrategy.set_stage
+
+
class URLFetchStrategy(FetchStrategy):
"""FetchStrategy that pulls source code from a URL for an archive,
checks the archive against a checksum,and decompresses the archive.
@@ -142,15 +158,15 @@ class URLFetchStrategy(FetchStrategy):
tty.msg("Trying to fetch from %s" % self.url)
- curl_args = ['-O', # save file to disk
- '-f', # fail on >400 errors
- '-D', '-', # print out HTML headers
- '-L', self.url,]
+ curl_args = ['-O', # save file to disk
+ '-f', # fail on >400 errors
+ '-D', '-', # print out HTML headers
+ '-L', self.url, ]
if sys.stdout.isatty():
curl_args.append('-#') # status bar when using a tty
else:
- curl_args.append('-sS') # just errors when not.
+ curl_args.append('-sS') # just errors when not.
# Run curl but grab the mime type from the http headers
headers = spack.curl(
@@ -164,24 +180,23 @@ class URLFetchStrategy(FetchStrategy):
if spack.curl.returncode == 22:
# This is a 404. Curl will print the error.
raise FailedDownloadError(
- self.url, "URL %s was not found!" % self.url)
+ self.url, "URL %s was not found!" % self.url)
elif spack.curl.returncode == 60:
# This is a certificate error. Suggest spack -k
raise FailedDownloadError(
- self.url,
- "Curl was unable to fetch due to invalid certificate. "
- "This is either an attack, or your cluster's SSL configuration "
- "is bad. If you believe your SSL configuration is bad, you "
- "can try running spack -k, which will not check SSL certificates."
- "Use this at your own risk.")
+ self.url,
+ "Curl was unable to fetch due to invalid certificate. "
+ "This is either an attack, or your cluster's SSL configuration "
+ "is bad. If you believe your SSL configuration is bad, you "
+ "can try running spack -k, which will not check SSL certificates."
+ "Use this at your own risk.")
else:
# This is some other curl error. Curl will print the
# error, but print a spack message too
raise FailedDownloadError(
- self.url, "Curl failed with error %d" % spack.curl.returncode)
-
+ self.url, "Curl failed with error %d" % spack.curl.returncode)
# Check if we somehow got an HTML file rather than the archive we
# asked for. We only look at the last content type, to handle
@@ -196,7 +211,6 @@ class URLFetchStrategy(FetchStrategy):
if not self.archive_file:
raise FailedDownloadError(self.url)
-
@property
def archive_file(self):
"""Path to the source archive within this stage directory."""
@@ -209,7 +223,7 @@ class URLFetchStrategy(FetchStrategy):
self.stage.chdir()
if not self.archive_file:
raise NoArchiveFileError("URLFetchStrategy couldn't find archive file",
- "Failed on expand() for URL %s" % self.url)
+ "Failed on expand() for URL %s" % self.url)
decompress = decompressor_for(self.archive_file)
@@ -241,7 +255,6 @@ class URLFetchStrategy(FetchStrategy):
# Set the wd back to the stage when done.
self.stage.chdir()
-
def archive(self, destination):
"""Just moves this archive to the destination."""
if not self.archive_file:
@@ -252,7 +265,6 @@ class URLFetchStrategy(FetchStrategy):
shutil.move(self.archive_file, destination)
-
@_needs_stage
def check(self):
"""Check the downloaded archive against a checksum digest.
@@ -263,9 +275,8 @@ class URLFetchStrategy(FetchStrategy):
checker = crypto.Checker(self.digest)
if not checker.check(self.archive_file):
raise ChecksumError(
- "%s checksum failed for %s." % (checker.hash_name, self.archive_file),
- "Expected %s but got %s." % (self.digest, checker.sum))
-
+ "%s checksum failed for %s." % (checker.hash_name, self.archive_file),
+ "Expected %s but got %s." % (self.digest, checker.sum))
@_needs_stage
def reset(self):
@@ -277,12 +288,10 @@ class URLFetchStrategy(FetchStrategy):
shutil.rmtree(self.stage.source_path, ignore_errors=True)
self.expand()
-
def __repr__(self):
url = self.url if self.url else "no url"
return "URLFetchStrategy<%s>" % url
-
def __str__(self):
if self.url:
return self.url
@@ -298,33 +307,30 @@ class VCSFetchStrategy(FetchStrategy):
# Set a URL based on the type of fetch strategy.
self.url = kwargs.get(name, None)
if not self.url: raise ValueError(
- "%s requires %s argument." % (self.__class__, name))
+ "%s requires %s argument." % (self.__class__, name))
# Ensure that there's only one of the rev_types
if sum(k in kwargs for k in rev_types) > 1:
raise FetchStrategyError(
- "Supply only one of %s to fetch with %s." % (
- comma_or(rev_types), name))
+ "Supply only one of %s to fetch with %s." % (
+ comma_or(rev_types), name))
# Set attributes for each rev type.
for rt in rev_types:
setattr(self, rt, kwargs.get(rt, None))
-
@_needs_stage
def check(self):
tty.msg("No checksum needed when fetching with %s." % self.name)
-
@_needs_stage
def expand(self):
tty.debug("Source fetched with %s is already expanded." % self.name)
-
@_needs_stage
def archive(self, destination, **kwargs):
- assert(extension(destination) == 'tar.gz')
- assert(self.stage.source_path.startswith(self.stage.path))
+ assert (extension(destination) == 'tar.gz')
+ assert (self.stage.source_path.startswith(self.stage.path))
tar = which('tar', required=True)
@@ -338,16 +344,13 @@ class VCSFetchStrategy(FetchStrategy):
self.stage.chdir()
tar('-czf', destination, os.path.basename(self.stage.source_path))
-
def __str__(self):
return "VCS: %s" % self.url
-
def __repr__(self):
return "%s<%s>" % (self.__class__, self.url)
-
class GitFetchStrategy(VCSFetchStrategy):
"""Fetch strategy that gets source code from a git repository.
Use like this in a package:
@@ -368,24 +371,25 @@ class GitFetchStrategy(VCSFetchStrategy):
required_attributes = ('git',)
def __init__(self, **kwargs):
+ # Discards the keywords in kwargs that may conflict with the next call to __init__
+ forwarded_args = copy.copy(kwargs)
+ forwarded_args.pop('name', None)
+
super(GitFetchStrategy, self).__init__(
- 'git', 'tag', 'branch', 'commit', **kwargs)
+ 'git', 'tag', 'branch', 'commit', **forwarded_args)
self._git = None
-
@property
def git_version(self):
vstring = self.git('--version', output=str).lstrip('git version ')
return Version(vstring)
-
@property
def git(self):
if not self._git:
self._git = which('git', required=True)
return self._git
-
@_needs_stage
def fetch(self):
self.stage.chdir()
@@ -418,7 +422,7 @@ class GitFetchStrategy(VCSFetchStrategy):
if self.branch:
args.extend(['--branch', self.branch])
elif self.tag and self.git_version >= ver('1.8.5.2'):
- args.extend(['--branch', self.tag])
+ args.extend(['--branch', self.tag])
# Try to be efficient if we're using a new enough git.
# This checks out only one branch's history
@@ -429,7 +433,7 @@ class GitFetchStrategy(VCSFetchStrategy):
# Yet more efficiency, only download a 1-commit deep tree
if self.git_version >= ver('1.7.1'):
try:
- self.git(*(args + ['--depth','1', self.url]))
+ self.git(*(args + ['--depth', '1', self.url]))
cloned = True
except spack.error.SpackError:
# This will fail with the dumb HTTP transport
@@ -452,18 +456,15 @@ class GitFetchStrategy(VCSFetchStrategy):
self.git('pull', '--tags', ignore_errors=1)
self.git('checkout', self.tag)
-
def archive(self, destination):
super(GitFetchStrategy, self).archive(destination, exclude='.git')
-
@_needs_stage
def reset(self):
self.stage.chdir_to_source()
self.git('checkout', '.')
self.git('clean', '-f')
-
def __str__(self):
return "[git] %s" % self.url
@@ -483,20 +484,22 @@ class SvnFetchStrategy(VCSFetchStrategy):
required_attributes = ['svn']
def __init__(self, **kwargs):
+ # Discards the keywords in kwargs that may conflict with the next call to __init__
+ forwarded_args = copy.copy(kwargs)
+ forwarded_args.pop('name', None)
+
super(SvnFetchStrategy, self).__init__(
- 'svn', 'revision', **kwargs)
+ 'svn', 'revision', **forwarded_args)
self._svn = None
if self.revision is not None:
self.revision = str(self.revision)
-
@property
def svn(self):
if not self._svn:
self._svn = which('svn', required=True)
return self._svn
-
@_needs_stage
def fetch(self):
self.stage.chdir()
@@ -515,7 +518,6 @@ class SvnFetchStrategy(VCSFetchStrategy):
self.svn(*args)
self.stage.chdir_to_source()
-
def _remove_untracked_files(self):
"""Removes untracked files in an svn repository."""
status = self.svn('status', '--no-ignore', output=str)
@@ -529,23 +531,19 @@ class SvnFetchStrategy(VCSFetchStrategy):
elif os.path.isdir(path):
shutil.rmtree(path, ignore_errors=True)
-
def archive(self, destination):
super(SvnFetchStrategy, self).archive(destination, exclude='.svn')
-
@_needs_stage
def reset(self):
self.stage.chdir_to_source()
self._remove_untracked_files()
self.svn('revert', '.', '-R')
-
def __str__(self):
return "[svn] %s" % self.url
-
class HgFetchStrategy(VCSFetchStrategy):
"""Fetch strategy that gets source code from a Mercurial repository.
Use like this in a package:
@@ -567,11 +565,14 @@ class HgFetchStrategy(VCSFetchStrategy):
required_attributes = ['hg']
def __init__(self, **kwargs):
+ # Discards the keywords in kwargs that may conflict with the next call to __init__
+ forwarded_args = copy.copy(kwargs)
+ forwarded_args.pop('name', None)
+
super(HgFetchStrategy, self).__init__(
- 'hg', 'revision', **kwargs)
+ 'hg', 'revision', **forwarded_args)
self._hg = None
-
@property
def hg(self):
if not self._hg:
@@ -597,11 +598,9 @@ class HgFetchStrategy(VCSFetchStrategy):
self.hg(*args)
-
def archive(self, destination):
super(HgFetchStrategy, self).archive(destination, exclude='.hg')
-
@_needs_stage
def reset(self):
self.stage.chdir()
@@ -619,7 +618,6 @@ class HgFetchStrategy(VCSFetchStrategy):
shutil.move(scrubbed, source_path)
self.stage.chdir_to_source()
-
def __str__(self):
return "[hg] %s" % self.url
@@ -693,9 +691,10 @@ class FetchError(spack.error.SpackError):
class FailedDownloadError(FetchError):
"""Raised wen a download fails."""
+
def __init__(self, url, msg=""):
super(FailedDownloadError, self).__init__(
- "Failed to fetch file from URL: %s" % url, msg)
+ "Failed to fetch file from URL: %s" % url, msg)
self.url = url
@@ -718,12 +717,14 @@ class InvalidArgsError(FetchError):
class ChecksumError(FetchError):
"""Raised when archive fails to checksum."""
+
def __init__(self, message, long_msg=None):
super(ChecksumError, self).__init__(message, long_msg)
class NoStageError(FetchError):
"""Raised when fetch operations are called before set_stage()."""
+
def __init__(self, method):
super(NoStageError, self).__init__(
- "Must call FetchStrategy.set_stage() before calling %s" % method.__name__)
+ "Must call FetchStrategy.set_stage() before calling %s" % method.__name__)
diff --git a/lib/spack/spack/mirror.py b/lib/spack/spack/mirror.py
index 341cc4cb88..fa29e20803 100644
--- a/lib/spack/spack/mirror.py
+++ b/lib/spack/spack/mirror.py
@@ -45,12 +45,11 @@ from spack.version import *
from spack.util.compression import extension, allowed_archive
-def mirror_archive_filename(spec):
+def mirror_archive_filename(spec, fetcher):
"""Get the name of the spec's archive in the mirror."""
if not spec.version.concrete:
raise ValueError("mirror.path requires spec with concrete version.")
- fetcher = spec.package.fetcher
if isinstance(fetcher, fs.URLFetchStrategy):
# If we fetch this version with a URLFetchStrategy, use URL's archive type
ext = url.downloaded_file_extension(fetcher.url)
@@ -61,9 +60,9 @@ def mirror_archive_filename(spec):
return "%s-%s.%s" % (spec.package.name, spec.version, ext)
-def mirror_archive_path(spec):
+def mirror_archive_path(spec, fetcher):
"""Get the relative path to the spec's archive within a mirror."""
- return join_path(spec.name, mirror_archive_filename(spec))
+ return join_path(spec.name, mirror_archive_filename(spec, fetcher))
def get_matching_versions(specs, **kwargs):
@@ -167,72 +166,47 @@ def create(path, specs, **kwargs):
everything_already_exists = True
for spec in version_specs:
pkg = spec.package
-
- stage = None
+ tty.msg("Adding package {pkg} to mirror".format(pkg=spec.format("$_$@")))
try:
- # create a subdirectory for the current package@version
- archive_path = os.path.abspath(join_path(mirror_root, mirror_archive_path(spec)))
- subdir = os.path.dirname(archive_path)
- try:
+ for ii, stage in enumerate(pkg.stage):
+ fetcher = stage.fetcher
+ if ii == 0:
+ # create a subdirectory for the current package@version
+ archive_path = os.path.abspath(join_path(mirror_root, mirror_archive_path(spec, fetcher)))
+ name = spec.format("$_$@")
+ else:
+ resource = stage.resource
+ archive_path = join_path(subdir, suggest_archive_basename(resource))
+ name = "{resource} ({pkg}).".format(resource=resource.name, pkg=spec.format("$_$@"))
+ subdir = os.path.dirname(archive_path)
mkdirp(subdir)
- except OSError as e:
- raise MirrorError(
- "Cannot create directory '%s':" % subdir, str(e))
- if os.path.exists(archive_path):
- tty.msg("Already added %s" % spec.format("$_$@"))
- else:
- everything_already_exists = False
- # Set up a stage and a fetcher for the download
- unique_fetch_name = spec.format("$_$@")
- fetcher = fs.for_package_version(pkg, pkg.version)
- stage = Stage(fetcher, name=unique_fetch_name)
- fetcher.set_stage(stage)
-
- # Do the fetch and checksum if necessary
- fetcher.fetch()
- if not kwargs.get('no_checksum', False):
- fetcher.check()
- tty.msg("Checksum passed for %s@%s" % (pkg.name, pkg.version))
-
- # Fetchers have to know how to archive their files. Use
- # that to move/copy/create an archive in the mirror.
- fetcher.archive(archive_path)
- tty.msg("Added %s." % spec.format("$_$@"))
-
- # Fetch resources if they are associated with the spec
- resources = pkg._get_resources()
- for resource in resources:
- resource_archive_path = join_path(subdir, suggest_archive_basename(resource))
- if os.path.exists(resource_archive_path):
- tty.msg("Already added resource %s (%s@%s)." % (resource.name, pkg.name, pkg.version))
- continue
- everything_already_exists = False
- resource_stage_folder = pkg._resource_stage(resource)
- resource_stage = Stage(resource.fetcher, name=resource_stage_folder)
- resource.fetcher.set_stage(resource_stage)
- resource.fetcher.fetch()
- if not kwargs.get('no_checksum', False):
- resource.fetcher.check()
- tty.msg("Checksum passed for the resource %s (%s@%s)" % (resource.name, pkg.name, pkg.version))
- resource.fetcher.archive(resource_archive_path)
- tty.msg("Added resource %s (%s@%s)." % (resource.name, pkg.name, pkg.version))
+ if os.path.exists(archive_path):
+ tty.msg("{name} : already added".format(name=name))
+ else:
+ everything_already_exists = False
+ fetcher.fetch()
+ if not kwargs.get('no_checksum', False):
+ fetcher.check()
+ tty.msg("{name} : checksum passed".format(name=name))
+
+ # Fetchers have to know how to archive their files. Use
+ # that to move/copy/create an archive in the mirror.
+ fetcher.archive(archive_path)
+ tty.msg("{name} : added".format(name=name))
if everything_already_exists:
present.append(spec)
else:
mirrored.append(spec)
-
except Exception, e:
if spack.debug:
sys.excepthook(*sys.exc_info())
else:
tty.warn("Error while fetching %s." % spec.format('$_$@'), e.message)
error.append(spec)
-
finally:
- if stage:
- stage.destroy()
+ pkg.stage.destroy()
return (present, mirrored, error)
diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py
index 7036626e29..c834763564 100644
--- a/lib/spack/spack/modules.py
+++ b/lib/spack/spack/modules.py
@@ -194,12 +194,14 @@ class Dotkit(EnvModule):
@property
def file_name(self):
return join_path(Dotkit.path, self.spec.architecture,
- self.spec.format('$_$@$%@$+$#.dk'))
+ '%s.dk' % self.use_name)
@property
def use_name(self):
- return self.spec.format('$_$@$%@$+$#')
-
+ return "%s-%s-%s-%s-%s" % (self.spec.name, self.spec.version,
+ self.spec.compiler.name,
+ self.spec.compiler.version,
+ self.spec.dag_hash())
def _write(self, dk_file):
# Category
@@ -235,7 +237,10 @@ class TclModule(EnvModule):
@property
def use_name(self):
- return self.spec.format('$_$@$%@$+$#')
+ return "%s-%s-%s-%s-%s" % (self.spec.name, self.spec.version,
+ self.spec.compiler.name,
+ self.spec.compiler.version,
+ self.spec.dag_hash())
def _write(self, m_file):
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 8cb947c276..8019b29cba 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -63,7 +63,7 @@ import spack.url
import spack.util.web
import spack.fetch_strategy as fs
from spack.version import *
-from spack.stage import Stage
+from spack.stage import Stage, ResourceStage, StageComposite
from spack.util.compression import allowed_archive, extension
from spack.util.executable import ProcessError
@@ -433,23 +433,46 @@ class Package(object):
return spack.url.substitute_version(self.nearest_url(version),
self.url_version(version))
+ def _make_resource_stage(self, root_stage, fetcher, resource):
+ resource_stage_folder = self._resource_stage(resource)
+ resource_mirror = join_path(self.name, os.path.basename(fetcher.url))
+ stage = ResourceStage(resource.fetcher, root=root_stage, resource=resource,
+ name=resource_stage_folder, mirror_path=resource_mirror)
+ return stage
+
+ def _make_root_stage(self, fetcher):
+ # Construct a mirror path (TODO: get this out of package.py)
+ mp = spack.mirror.mirror_archive_path(self.spec, fetcher)
+ # Construct a path where the stage should build..
+ s = self.spec
+ stage_name = "%s-%s-%s" % (s.name, s.version, s.dag_hash())
+ # Build the composite stage
+ stage = Stage(fetcher, mirror_path=mp, name=stage_name)
+ return stage
+
+ def _make_stage(self):
+ # Construct a composite stage on top of the composite FetchStrategy
+ composite_fetcher = self.fetcher
+ composite_stage = StageComposite()
+ resources = self._get_resources()
+ for ii, fetcher in enumerate(composite_fetcher):
+ if ii == 0:
+ # Construct root stage first
+ stage = self._make_root_stage(fetcher)
+ else:
+ # Construct resource stage
+ resource = resources[ii - 1] # ii == 0 is root!
+ stage = self._make_resource_stage(composite_stage[0], fetcher, resource)
+ # Append the item to the composite
+ composite_stage.append(stage)
+ return composite_stage
@property
def stage(self):
if not self.spec.concrete:
raise ValueError("Can only get a stage for a concrete package.")
-
if self._stage is None:
- # Construct a mirror path (TODO: get this out of package.py)
- mp = spack.mirror.mirror_archive_path(self.spec)
-
- # Construct a path where the stage should build..
- s = self.spec
- stage_name = "%s-%s-%s" % (s.name, s.version, s.dag_hash())
-
- # Build the stage
- self._stage = Stage(self.fetcher, mirror_path=mp, name=stage_name)
-
+ self._stage = self._make_stage()
return self._stage
@@ -459,17 +482,25 @@ class Package(object):
self._stage = stage
+ def _make_fetcher(self):
+ # Construct a composite fetcher that always contains at least one element (the root package). In case there
+ # are resources associated with the package, append their fetcher to the composite.
+ root_fetcher = fs.for_package_version(self, self.version)
+ fetcher = fs.FetchStrategyComposite() # Composite fetcher
+ fetcher.append(root_fetcher) # Root fetcher is always present
+ resources = self._get_resources()
+ for resource in resources:
+ fetcher.append(resource.fetcher)
+ return fetcher
+
@property
def fetcher(self):
if not self.spec.versions.concrete:
- raise ValueError(
- "Can only get a fetcher for a package with concrete versions.")
-
+ raise ValueError("Can only get a fetcher for a package with concrete versions.")
if not self._fetcher:
- self._fetcher = fs.for_package_version(self, self.version)
+ self._fetcher = self._make_fetcher()
return self._fetcher
-
@fetcher.setter
def fetcher(self, f):
self._fetcher = f
@@ -632,7 +663,7 @@ class Package(object):
def do_fetch(self, mirror_only=False):
- """Creates a stage directory and downloads the taball for this package.
+ """Creates a stage directory and downloads the tarball for this package.
Working directory will be set to the stage directory.
"""
if not self.spec.concrete:
@@ -658,20 +689,6 @@ class Package(object):
self.stage.fetch(mirror_only)
- ##########
- # Fetch resources
- resources = self._get_resources()
- for resource in resources:
- resource_stage_folder = self._resource_stage(resource)
- # FIXME : works only for URLFetchStrategy
- resource_mirror = join_path(self.name, os.path.basename(resource.fetcher.url))
- resource_stage = Stage(resource.fetcher, name=resource_stage_folder, mirror_path=resource_mirror)
- resource.fetcher.set_stage(resource_stage)
- # Delegate to stage object to trigger mirror logic
- resource_stage.fetch()
- resource_stage.check()
- ##########
-
self._fetch_time = time.time() - start_time
if spack.do_checksum and self.version in self.versions:
@@ -684,52 +701,10 @@ class Package(object):
if not self.spec.concrete:
raise ValueError("Can only stage concrete packages.")
- def _expand_archive(stage, name=self.name):
- archive_dir = stage.source_path
- if not archive_dir:
- stage.expand_archive()
- tty.msg("Created stage in %s." % stage.path)
- else:
- tty.msg("Already staged %s in %s." % (name, stage.path))
-
self.do_fetch(mirror_only)
- _expand_archive(self.stage)
-
- ##########
- # Stage resources in appropriate path
- resources = self._get_resources()
- # TODO: this is to allow nested resources, a better solution would be
- # good
- for resource in sorted(resources, key=lambda res: len(res.destination)):
- stage = resource.fetcher.stage
- _expand_archive(stage, resource.name)
- # Turn placement into a dict with relative paths
- placement = os.path.basename(stage.source_path) if resource.placement is None else resource.placement
- if not isinstance(placement, dict):
- placement = {'': placement}
- # Make the paths in the dictionary absolute and link
- for key, value in placement.iteritems():
- target_path = join_path(self.stage.source_path, resource.destination)
- link_path = join_path(target_path, value)
- source_path = join_path(stage.source_path, key)
-
- try:
- os.makedirs(target_path)
- except OSError as err:
- if err.errno == errno.EEXIST and os.path.isdir(target_path):
- pass
- else: raise
-
- # NOTE: a reasonable fix for the TODO above might be to have
- # these expand in place, but expand_archive does not offer
- # this
-
- if not os.path.exists(link_path):
- shutil.move(source_path, link_path)
- ##########
+ self.stage.expand_archive()
self.stage.chdir_to_source()
-
def do_patch(self):
"""Calls do_stage(), then applied patches to the expanded tarball if they
haven't been applied already."""
@@ -828,6 +803,9 @@ class Package(object):
for when_spec, resource_list in self.resources.items():
if when_spec in self.spec:
resources.extend(resource_list)
+ # Sorts the resources by the length of the string representing their destination. Since any nested resource
+ # must contain another resource's name in its path, it seems that should work
+ resources = sorted(resources, key=lambda res: len(res.destination))
return resources
def _resource_stage(self, resource):
diff --git a/lib/spack/spack/repository.py b/lib/spack/spack/repository.py
index b5df1168b6..f58cd52125 100644
--- a/lib/spack/spack/repository.py
+++ b/lib/spack/spack/repository.py
@@ -300,8 +300,11 @@ class RepoPath(object):
for repo in self.repos:
if spec.name in repo:
return repo
- else:
- raise UnknownPackageError(spec.name)
+
+ # If the package isn't in any repo, return the one with
+ # highest precedence. This is for commands like `spack edit`
+ # that can operate on packages that don't exist yet.
+ return self.first_repo()
@_autospec
diff --git a/lib/spack/spack/stage.py b/lib/spack/spack/stage.py
index 79c9030e20..f217450d42 100644
--- a/lib/spack/spack/stage.py
+++ b/lib/spack/spack/stage.py
@@ -23,7 +23,7 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
import os
-import re
+import errno
import shutil
import tempfile
from urlparse import urljoin
@@ -31,17 +31,18 @@ from urlparse import urljoin
import llnl.util.tty as tty
from llnl.util.filesystem import *
+import spack.util.pattern as pattern
+
import spack
import spack.config
import spack.fetch_strategy as fs
import spack.error
-
STAGE_PREFIX = 'spack-stage-'
class Stage(object):
- """A Stage object manaages a directory where some source code is
+ """A Stage object manages a directory where some source code is
downloaded and built before being installed. It handles
fetching the source code, either as an archive to be expanded
or by checking it out of a repository. A stage's lifecycle
@@ -93,7 +94,7 @@ class Stage(object):
raise ValueError("Can't construct Stage without url or fetch strategy")
self.fetcher.set_stage(self)
self.default_fetcher = self.fetcher # self.fetcher can change with mirrors.
- self.skip_checksum_for_mirror = True # used for mirrored archives of repositories.
+ self.skip_checksum_for_mirror = True # used for mirrored archives of repositories.
self.name = kwargs.get('name')
self.mirror_path = kwargs.get('mirror_path')
@@ -102,7 +103,6 @@ class Stage(object):
self.path = None
self._setup()
-
def _cleanup_dead_links(self):
"""Remove any dead links in the stage directory."""
for file in os.listdir(spack.stage_path):
@@ -112,7 +112,6 @@ class Stage(object):
if not os.path.exists(path):
os.unlink(path)
-
def _need_to_create_path(self):
"""Makes sure nothing weird has happened since the last time we
looked at path. Returns True if path already exists and is ok.
@@ -130,7 +129,7 @@ class Stage(object):
# Path looks ok, but need to check the target of the link.
if os.path.islink(self.path):
real_path = os.path.realpath(self.path)
- real_tmp = os.path.realpath(self.tmp_root)
+ real_tmp = os.path.realpath(self.tmp_root)
if spack.use_tmp_stage:
# If we're using a tmp dir, it's a link, and it points at the right spot,
@@ -149,7 +148,6 @@ class Stage(object):
return False
-
def _setup(self):
"""Creates the stage directory.
If spack.use_tmp_stage is False, the stage directory is created
@@ -198,7 +196,6 @@ class Stage(object):
# Make sure we can actually do something with the stage we made.
ensure_access(self.path)
-
@property
def archive_file(self):
"""Path to the source archive within this stage directory."""
@@ -215,7 +212,6 @@ class Stage(object):
else:
return None
-
@property
def source_path(self):
"""Returns the path to the expanded/checked out source code
@@ -230,7 +226,6 @@ class Stage(object):
return p
return None
-
def chdir(self):
"""Changes directory to the stage path. Or dies if it is not set up."""
if os.path.isdir(self.path):
@@ -238,7 +233,6 @@ class Stage(object):
else:
tty.die("Setup failed: no such directory: " + self.path)
-
def fetch(self, mirror_only=False):
"""Downloads an archive or checks out code from a repository."""
self.chdir()
@@ -291,7 +285,6 @@ class Stage(object):
self.fetcher = self.default_fetcher
raise fs.FetchError(errMessage, None)
-
def check(self):
"""Check the downloaded archive against a checksum digest.
No-op if this stage checks code out of a repository."""
@@ -305,14 +298,17 @@ class Stage(object):
else:
self.fetcher.check()
-
def expand_archive(self):
"""Changes to the stage directory and attempt to expand the downloaded
archive. Fail if the stage is not set up or if the archive is not yet
downloaded.
"""
- self.fetcher.expand()
-
+ archive_dir = self.source_path
+ if not archive_dir:
+ self.fetcher.expand()
+ tty.msg("Created stage in %s." % self.path)
+ else:
+ tty.msg("Already staged %s in %s." % (self.name, self.path))
def chdir_to_source(self):
"""Changes directory to the expanded archive directory.
@@ -326,14 +322,12 @@ class Stage(object):
if not os.listdir(path):
tty.die("Archive was empty for %s" % self.name)
-
def restage(self):
"""Removes the expanded archive path if it exists, then re-expands
the archive.
"""
self.fetcher.reset()
-
def destroy(self):
"""Remove this stage directory."""
remove_linked_tree(self.path)
@@ -345,8 +339,63 @@ class Stage(object):
os.chdir(os.path.dirname(self.path))
+class ResourceStage(Stage):
+ def __init__(self, url_or_fetch_strategy, root, resource, **kwargs):
+ super(ResourceStage, self).__init__(url_or_fetch_strategy, **kwargs)
+ self.root_stage = root
+ self.resource = resource
+
+ def expand_archive(self):
+ super(ResourceStage, self).expand_archive()
+ root_stage = self.root_stage
+ resource = self.resource
+ placement = os.path.basename(self.source_path) if resource.placement is None else resource.placement
+ if not isinstance(placement, dict):
+ placement = {'': placement}
+ # Make the paths in the dictionary absolute and link
+ for key, value in placement.iteritems():
+ target_path = join_path(root_stage.source_path, resource.destination)
+ destination_path = join_path(target_path, value)
+ source_path = join_path(self.source_path, key)
+
+ try:
+ os.makedirs(target_path)
+ except OSError as err:
+ if err.errno == errno.EEXIST and os.path.isdir(target_path):
+ pass
+ else:
+ raise
+
+ if not os.path.exists(destination_path):
+ # Create a symlink
+ tty.info('Moving resource stage\n\tsource : {stage}\n\tdestination : {destination}'.format(
+ stage=source_path, destination=destination_path
+ ))
+ shutil.move(source_path, destination_path)
+
+
+@pattern.composite(method_list=['fetch', 'check', 'expand_archive', 'restage', 'destroy'])
+class StageComposite:
+ """
+ Composite for Stage type objects. The first item in this composite is considered to be the root package, and
+ operations that return a value are forwarded to it.
+ """
+
+ @property
+ def source_path(self):
+ return self[0].source_path
+
+ @property
+ def path(self):
+ return self[0].path
+
+ def chdir_to_source(self):
+ return self[0].chdir_to_source()
+
+
class DIYStage(object):
"""Simple class that allows any directory to be a spack stage."""
+
def __init__(self, path):
self.archive_file = None
self.path = path
@@ -384,7 +433,6 @@ def _get_mirrors():
return [val for name, val in config.iteritems()]
-
def ensure_access(file=spack.stage_path):
"""Ensure we can access a directory and die with an error if we can't."""
if not can_access(file):
diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py
index a569cbbf35..4b9a361d4b 100644
--- a/lib/spack/spack/test/__init__.py
+++ b/lib/spack/spack/test/__init__.py
@@ -48,6 +48,7 @@ test_names = ['versions',
'package_sanity',
'config',
'directory_layout',
+ 'pattern',
'python_version',
'git_fetch',
'svn_fetch',
diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py
index c09bd24c8e..8863d13c42 100644
--- a/lib/spack/spack/test/install.py
+++ b/lib/spack/spack/test/install.py
@@ -31,7 +31,7 @@ from llnl.util.filesystem import *
import spack
from spack.stage import Stage
-from spack.fetch_strategy import URLFetchStrategy
+from spack.fetch_strategy import URLFetchStrategy, FetchStrategyComposite
from spack.directory_layout import YamlDirectoryLayout
from spack.util.executable import which
from spack.test.mock_packages_test import *
@@ -79,7 +79,10 @@ class InstallTest(MockPackagesTest):
pkg = spack.repo.get(spec)
# Fake the URL for the package so it downloads from a file.
- pkg.fetcher = URLFetchStrategy(self.repo.url)
+
+ fetcher = FetchStrategyComposite()
+ fetcher.append(URLFetchStrategy(self.repo.url))
+ pkg.fetcher = fetcher
try:
pkg.do_install()
diff --git a/lib/spack/spack/test/mirror.py b/lib/spack/spack/test/mirror.py
index 046ec56604..f83cc8090c 100644
--- a/lib/spack/spack/test/mirror.py
+++ b/lib/spack/spack/test/mirror.py
@@ -102,6 +102,7 @@ class MirrorTest(MockPackagesTest):
spec = Spec(name).concretized()
pkg = spec.package
+ pkg._stage = None
saved_checksum_setting = spack.do_checksum
try:
# Stage the archive from the mirror and cd to it.
diff --git a/lib/spack/spack/test/pattern.py b/lib/spack/spack/test/pattern.py
new file mode 100644
index 0000000000..6c783c6a5f
--- /dev/null
+++ b/lib/spack/spack/test/pattern.py
@@ -0,0 +1,104 @@
+##############################################################################
+# 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://github.com/llnl/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
+##############################################################################
+
+import unittest
+
+import spack.util.pattern as pattern
+
+
+class CompositeTest(unittest.TestCase):
+
+ def setUp(self):
+ class Base:
+ counter = 0
+
+ def add(self):
+ raise NotImplemented('add not implemented')
+
+ def subtract(self):
+ raise NotImplemented('subtract not implemented')
+
+ class One(Base):
+ def add(self):
+ Base.counter += 1
+
+ def subtract(self):
+ Base.counter -= 1
+
+ class Two(Base):
+ def add(self):
+ Base.counter += 2
+
+ def subtract(self):
+ Base.counter -= 2
+
+ self.Base = Base
+ self.One = One
+ self.Two = Two
+
+ def test_composite_from_method_list(self):
+
+ @pattern.composite(method_list=['add', 'subtract'])
+ class CompositeFromMethodList:
+ pass
+
+ composite = CompositeFromMethodList()
+ composite.append(self.One())
+ composite.append(self.Two())
+ composite.add()
+ self.assertEqual(self.Base.counter, 3)
+ composite.pop()
+ composite.subtract()
+ self.assertEqual(self.Base.counter, 2)
+
+ def test_composite_from_interface(self):
+
+ @pattern.composite(interface=self.Base)
+ class CompositeFromInterface:
+ pass
+
+ composite = CompositeFromInterface()
+ composite.append(self.One())
+ composite.append(self.Two())
+ composite.add()
+ self.assertEqual(self.Base.counter, 3)
+ composite.pop()
+ composite.subtract()
+ self.assertEqual(self.Base.counter, 2)
+
+ def test_error_conditions(self):
+
+ def wrong_container():
+ @pattern.composite(interface=self.Base, container=2)
+ class CompositeFromInterface:
+ pass
+
+ def no_methods():
+ @pattern.composite()
+ class CompositeFromInterface:
+ pass
+
+ self.assertRaises(TypeError, wrong_container)
+ self.assertRaises(TypeError, no_methods)
diff --git a/lib/spack/spack/util/pattern.py b/lib/spack/spack/util/pattern.py
new file mode 100644
index 0000000000..17a126498b
--- /dev/null
+++ b/lib/spack/spack/util/pattern.py
@@ -0,0 +1,116 @@
+##############################################################################
+# 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://github.com/llnl/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
+##############################################################################
+import inspect
+import collections
+import functools
+
+
+def composite(interface=None, method_list=None, container=list):
+ """
+ Returns a class decorator that patches a class adding all the methods it needs to be a composite for a given
+ interface.
+
+ :param interface: class exposing the interface to which the composite object must conform. Only non-private and
+ non-special methods will be taken into account
+
+ :param method_list: names of methods that should be part of the composite
+
+ :param container: container for the composite object (default = list). Must fulfill the MutableSequence contract.
+ The composite class will expose the container API to manage object composition
+
+ :return: class decorator
+ """
+ # Check if container fulfills the MutableSequence contract and raise an exception if it doesn't
+ # The patched class returned by the decorator will inherit from the container class to expose the
+ # interface needed to manage objects composition
+ if not issubclass(container, collections.MutableSequence):
+ raise TypeError("Container must fulfill the MutableSequence contract")
+
+ # Check if at least one of the 'interface' or the 'method_list' arguments are defined
+ if interface is None and method_list is None:
+ raise TypeError("Either 'interface' or 'method_list' must be defined on a call to composite")
+
+ def cls_decorator(cls):
+ # Retrieve the base class of the composite. Inspect its methods and decide which ones will be overridden
+ def no_special_no_private(x):
+ return inspect.ismethod(x) and not x.__name__.startswith('_')
+
+ # Patch the behavior of each of the methods in the previous list. This is done associating an instance of the
+ # descriptor below to any method that needs to be patched.
+ class IterateOver(object):
+ """
+ Decorator used to patch methods in a composite. It iterates over all the items in the instance containing the
+ associated attribute and calls for each of them an attribute with the same name
+ """
+ def __init__(self, name, func=None):
+ self.name = name
+ self.func = func
+
+ def __get__(self, instance, owner):
+ def getter(*args, **kwargs):
+ for item in instance:
+ getattr(item, self.name)(*args, **kwargs)
+ # If we are using this descriptor to wrap a method from an interface, then we must conditionally
+ # use the `functools.wraps` decorator to set the appropriate fields.
+ if self.func is not None:
+ getter = functools.wraps(self.func)(getter)
+ return getter
+
+ dictionary_for_type_call = {}
+ # Construct a dictionary with the methods explicitly passed as name
+ if method_list is not None:
+ # python@2.7: method_list_dict = {name: IterateOver(name) for name in method_list}
+ method_list_dict = {}
+ for name in method_list:
+ method_list_dict[name] = IterateOver(name)
+ dictionary_for_type_call.update(method_list_dict)
+ # Construct a dictionary with the methods inspected from the interface
+ if interface is not None:
+ ##########
+ # python@2.7: interface_methods = {name: method for name, method in inspect.getmembers(interface, predicate=no_special_no_private)}
+ interface_methods = {}
+ for name, method in inspect.getmembers(interface, predicate=no_special_no_private):
+ interface_methods[name] = method
+ ##########
+ # python@2.7: interface_methods_dict = {name: IterateOver(name, method) for name, method in interface_methods.iteritems()}
+ interface_methods_dict = {}
+ for name, method in interface_methods.iteritems():
+ interface_methods_dict[name] = IterateOver(name, method)
+ ##########
+ dictionary_for_type_call.update(interface_methods_dict)
+ # Get the methods that are defined in the scope of the composite class and override any previous definition
+ ##########
+ # python@2.7: cls_method = {name: method for name, method in inspect.getmembers(cls, predicate=inspect.ismethod)}
+ cls_method = {}
+ for name, method in inspect.getmembers(cls, predicate=inspect.ismethod):
+ cls_method[name] = method
+ ##########
+ dictionary_for_type_call.update(cls_method)
+ # Generate the new class on the fly and return it
+ # FIXME : inherit from interface if we start to use ABC classes?
+ wrapper_class = type(cls.__name__, (cls, container), dictionary_for_type_call)
+ return wrapper_class
+
+ return cls_decorator
diff --git a/var/spack/repos/builtin/packages/SuiteSparse/package.py b/var/spack/repos/builtin/packages/SuiteSparse/package.py
new file mode 100644
index 0000000000..6e130d118f
--- /dev/null
+++ b/var/spack/repos/builtin/packages/SuiteSparse/package.py
@@ -0,0 +1,27 @@
+from spack import *
+
+
+class Suitesparse(Package):
+ """
+ SuiteSparse is a suite of sparse matrix algorithms
+ """
+ homepage = 'http://faculty.cse.tamu.edu/davis/suitesparse.html'
+ url = 'http://faculty.cse.tamu.edu/davis/SuiteSparse/SuiteSparse-4.5.1.tar.gz'
+
+ version('4.5.1', 'f0ea9aad8d2d1ffec66a5b6bfeff5319')
+
+ depends_on('blas')
+ depends_on('lapack')
+
+ depends_on('metis@5.1.0', when='@4.5.1')
+
+ def install(self, spec, prefix):
+ # The build system of SuiteSparse is quite old-fashioned
+ # It's basically a plain Makefile which include an header (SuiteSparse_config/SuiteSparse_config.mk)
+ # with a lot of convoluted logic in it.
+ # Any kind of customization will need to go through filtering of that file
+
+ # FIXME : this actually uses the current workaround
+ # FIXME : (blas / lapack always provide libblas and liblapack as aliases)
+ make('install', 'INSTALL=%s' % prefix, 'BLAS=-lblas', 'LAPACK=-llapack')
+
diff --git a/var/spack/repos/builtin/packages/arpack-ng/package.py b/var/spack/repos/builtin/packages/arpack-ng/package.py
new file mode 100644
index 0000000000..0b49d14202
--- /dev/null
+++ b/var/spack/repos/builtin/packages/arpack-ng/package.py
@@ -0,0 +1,57 @@
+from spack import *
+
+
+class ArpackNg(Package):
+ """
+ ARPACK-NG is a collection of Fortran77 subroutines designed to solve large scale eigenvalue problems.
+
+ Important Features:
+
+ * Reverse Communication Interface.
+ * Single and Double Precision Real Arithmetic Versions for Symmetric,
+ Non-symmetric, Standard or Generalized Problems.
+ * Single and Double Precision Complex Arithmetic Versions for Standard or
+ Generalized Problems.
+ * Routines for Banded Matrices - Standard or Generalized Problems.
+ * Routines for The Singular Value Decomposition.
+ * Example driver routines that may be used as templates to implement numerous
+ Shift-Invert strategies for all problem types, data types and precision.
+
+ This project is a joint project between Debian, Octave and Scilab in order to
+ provide a common and maintained version of arpack.
+
+ Indeed, no single release has been published by Rice university for the last
+ few years and since many software (Octave, Scilab, R, Matlab...) forked it and
+ implemented their own modifications, arpack-ng aims to tackle this by providing
+ a common repository and maintained versions.
+
+ arpack-ng is replacing arpack almost everywhere.
+ """
+ homepage = 'https://github.com/opencollab/arpack-ng'
+ url = 'https://github.com/opencollab/arpack-ng/archive/3.3.0.tar.gz'
+
+ version('3.3.0', 'ed3648a23f0a868a43ef44c97a21bad5')
+
+ variant('shared', default=True, description='Enables the build of shared libraries')
+ variant('mpi', default=False, description='Activates MPI support')
+
+ depends_on('blas')
+ depends_on('lapack')
+ depends_on('mpi', when='+mpi')
+
+ def install(self, spec, prefix):
+ # Apparently autotools are not bootstrapped
+ bootstrap = Executable('./bootstrap')
+
+ options = ['--prefix=%s' % prefix]
+
+ if '+mpi' in spec:
+ options.append('--enable-mpi')
+
+ if '~shared' in spec:
+ options.append('--enable-shared=no')
+
+ bootstrap()
+ configure(*options)
+ make()
+ make('install')
diff --git a/var/spack/repos/builtin/packages/cmake/package.py b/var/spack/repos/builtin/packages/cmake/package.py
index f67ae21ebd..e20c1e4aeb 100644
--- a/var/spack/repos/builtin/packages/cmake/package.py
+++ b/var/spack/repos/builtin/packages/cmake/package.py
@@ -28,20 +28,22 @@ class Cmake(Package):
"""A cross-platform, open-source build system. CMake is a family of
tools designed to build, test and package software."""
homepage = 'https://www.cmake.org'
+ url = 'https://cmake.org/files/v3.4/cmake-3.4.3.tar.gz'
- version('2.8.10.2', '097278785da7182ec0aea8769d06860c',
- url = 'http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz')
-
- version('3.0.2', 'db4c687a31444a929d2fdc36c4dfb95f',
- url = 'http://www.cmake.org/files/v3.0/cmake-3.0.2.tar.gz')
-
- version('3.4.0', 'cd3034e0a44256a0917e254167217fc8',
- url = 'http://cmake.org/files/v3.4/cmake-3.4.0.tar.gz')
+ version('3.4.3', '4cb3ff35b2472aae70f542116d616e63')
+ version('3.4.0', 'cd3034e0a44256a0917e254167217fc8')
+ version('3.3.1', '52638576f4e1e621fed6c3410d3a1b12')
+ version('3.0.2', 'db4c687a31444a929d2fdc36c4dfb95f')
+ version('2.8.10.2', '097278785da7182ec0aea8769d06860c')
variant('ncurses', default=True, description='Enables the build of the ncurses gui')
-
depends_on('ncurses', when='+ncurses')
+ def url_for_version(self, version):
+ """Handle CMake's version-based custom URLs."""
+ return 'https://cmake.org/files/v%s/cmake-%s.tar.gz' % (version.up_to(2), version)
+
+
def install(self, spec, prefix):
configure('--prefix=' + prefix,
'--parallel=' + str(make_jobs),
diff --git a/var/spack/repos/builtin/packages/cryptopp/package.py b/var/spack/repos/builtin/packages/cryptopp/package.py
new file mode 100644
index 0000000000..1693c4b160
--- /dev/null
+++ b/var/spack/repos/builtin/packages/cryptopp/package.py
@@ -0,0 +1,31 @@
+import glob
+from spack import *
+
+class Cryptopp(Package):
+ """Crypto++ is an open-source C++ library of cryptographic schemes. The
+ library supports a number of different cryptography algorithms, including
+ authenticated encryption schemes (GCM, CCM), hash functions (SHA-1, SHA2),
+ public-key encryption (RSA, DSA), and a few obsolete/historical encryption
+ algorithms (MD5, Panama)."""
+
+ homepage = "http://www.cryptopp.com/"
+ url = "http://www.cryptopp.com/cryptopp563.zip"
+
+ version('5.6.3', '3c5b70e2ec98b7a24988734446242d07')
+ version('5.6.2', '7ed022585698df48e65ce9218f6c6a67')
+
+ def install(self, spec, prefix):
+ make()
+
+ mkdirp(prefix.include)
+ for hfile in glob.glob('*.h*'):
+ install(hfile, prefix.include)
+
+ mkdirp(prefix.lib)
+ install('libcryptopp.a', prefix.lib)
+
+ def url_for_version(self, version):
+ version_tuple = tuple(v for v in iter(version))
+ version_string = reduce(lambda vs, nv: vs + str(nv), version_tuple, "")
+
+ return "%scryptopp%s.zip" % (Cryptopp.homepage, version_string)
diff --git a/var/spack/repos/builtin/packages/dakota/package.py b/var/spack/repos/builtin/packages/dakota/package.py
new file mode 100644
index 0000000000..5ec82ef83d
--- /dev/null
+++ b/var/spack/repos/builtin/packages/dakota/package.py
@@ -0,0 +1,55 @@
+from spack import *
+
+
+class Dakota(Package):
+ """
+ The Dakota toolkit provides a flexible, extensible interface between analysis codes and iterative systems
+ analysis methods. Dakota contains algorithms for:
+
+ - optimization with gradient and non gradient-based methods;
+ - uncertainty quantification with sampling, reliability, stochastic expansion, and epistemic methods;
+ - parameter estimation with nonlinear least squares methods;
+ - sensitivity/variance analysis with design of experiments and parameter study methods.
+
+ These capabilities may be used on their own or as components within advanced strategies such as hybrid optimization,
+ surrogate-based optimization, mixed integer nonlinear programming, or optimization under uncertainty.
+ """
+
+ homepage = 'https://dakota.sandia.gov/'
+ url = 'https://dakota.sandia.gov/sites/default/files/distributions/public/dakota-6.3-public.src.tar.gz'
+ _url_str = 'https://dakota.sandia.gov/sites/default/files/distributions/public/dakota-{version}-public.src.tar.gz'
+
+ version('6.3', '05a58d209fae604af234c894c3f73f6d')
+
+ variant('debug', default=False, description='Builds a debug version of the libraries')
+ variant('shared', default=True, description='Enables the build of shared libraries')
+ variant('mpi', default=True, description='Activates MPI support')
+
+ depends_on('blas')
+ depends_on('lapack')
+ depends_on('mpi', when='+mpi')
+
+ depends_on('python')
+ depends_on('boost')
+
+ def url_for_version(self, version):
+ return Dakota._url_str.format(version=version)
+
+ def install(self, spec, prefix):
+ options = []
+ options.extend(std_cmake_args)
+
+ options.extend(['-DCMAKE_BUILD_TYPE:STRING=%s' % ('Debug' if '+debug' in spec else 'Release'),
+ '-DBUILD_SHARED_LIBS:BOOL=%s' % ('ON' if '+shared' in spec else 'OFF')])
+
+ if '+mpi' in spec:
+ options.extend(['-DDAKOTA_HAVE_MPI:BOOL=ON',
+ '-DMPI_CXX_COMPILER:STRING=%s' % join_path(spec['mpi'].prefix.bin, 'mpicxx')])
+
+ build_directory = join_path(self.stage.path, 'spack-build')
+ source_directory = self.stage.source_path
+
+ with working_dir(build_directory, create=True):
+ cmake(source_directory, *options)
+ make()
+ make("install")
diff --git a/var/spack/repos/builtin/packages/eigen/package.py b/var/spack/repos/builtin/packages/eigen/package.py
index 44ee6819f5..e40046b452 100644
--- a/var/spack/repos/builtin/packages/eigen/package.py
+++ b/var/spack/repos/builtin/packages/eigen/package.py
@@ -41,13 +41,14 @@ class Eigen(Package):
variant('metis', default=True, description='Enables metis backend')
variant('scotch', default=True, description='Enables scotch backend')
variant('fftw', default=True, description='Enables FFTW backend')
+ variant('suitesparse', default=True, description='Enables SuiteSparse support')
- # TODO : dependency on SuiteSparse, googlehash, superlu, adolc missing
+ # TODO : dependency on googlehash, superlu, adolc missing
depends_on('metis', when='+metis')
depends_on('scotch', when='+scotch')
depends_on('fftw', when='+fftw')
-
+ depends_on('SuiteSparse', when='+suitesparse')
depends_on('mpfr@2.3.0:') # Eigen 3.2.7 requires at least 2.3.0
depends_on('gmp')
diff --git a/var/spack/repos/builtin/packages/espresso/package.py b/var/spack/repos/builtin/packages/espresso/package.py
new file mode 100644
index 0000000000..a2bf58f585
--- /dev/null
+++ b/var/spack/repos/builtin/packages/espresso/package.py
@@ -0,0 +1,65 @@
+from spack import *
+
+import os
+
+class Espresso(Package):
+ """
+ QE is an integrated suite of Open-Source computer codes for electronic-structure calculations and materials
+ modeling at the nanoscale. It is based on density-functional theory, plane waves, and pseudopotentials.
+ """
+ homepage = 'http://quantum-espresso.org'
+ url = 'http://www.qe-forge.org/gf/download/frsrelease/204/912/espresso-5.3.0.tar.gz'
+
+ version('5.3.0', '6848fcfaeb118587d6be36bd10b7f2c3')
+
+ variant('mpi', default=True, description='Build Quantum-ESPRESSO with mpi support')
+ variant('openmp', default=False, description='Enables openMP support')
+ variant('scalapack', default=True, description='Enables scalapack support')
+ variant('elpa', default=True, description='Use elpa as an eigenvalue solver')
+
+ depends_on('blas')
+ depends_on('lapack')
+
+ depends_on('mpi', when='+mpi')
+ depends_on('fftw~mpi', when='~mpi')
+ depends_on('fftw+mpi', when='+mpi')
+ depends_on('scalapack', when='+scalapack+mpi') # TODO : + mpi needed to avoid false dependencies installation
+
+ def check_variants(self, spec):
+ error = 'you cannot ask for \'+{variant}\' when \'+mpi\' is not active'
+ if '+scalapack' in spec and '~mpi' in spec:
+ raise RuntimeError(error.format(variant='scalapack'))
+ if '+elpa' in spec and ('~mpi' in spec or '~scalapack' in spec):
+ raise RuntimeError(error.format(variant='elpa'))
+
+ def install(self, spec, prefix):
+ self.check_variants(spec)
+
+ options = ['-prefix=%s' % prefix]
+
+ if '+mpi' in spec:
+ options.append('--enable-parallel')
+
+ if '+openmp' in spec:
+ options.append('--enable-openmp')
+
+ if '+scalapack' in spec:
+ options.append('--with-scalapack=yes')
+
+ if '+elpa' in spec:
+ options.append('--with-elpa=yes')
+
+ # Add a list of directories to search
+ search_list = []
+ for name, dependency_spec in spec.dependencies.iteritems():
+ search_list.extend([dependency_spec.prefix.lib,
+ dependency_spec.prefix.lib64])
+
+ search_list = " ".join(search_list)
+ options.append('LIBDIRS=%s' % search_list)
+ options.append('F90=%s' % os.environ['FC'])
+
+ configure(*options)
+ make('all')
+ make('install')
+
diff --git a/var/spack/repos/builtin/packages/exodusii/exodus-cmake.patch b/var/spack/repos/builtin/packages/exodusii/exodus-cmake.patch
new file mode 100644
index 0000000000..25355269ca
--- /dev/null
+++ b/var/spack/repos/builtin/packages/exodusii/exodus-cmake.patch
@@ -0,0 +1,12 @@
+diff --git a/cmake-exodus b/cmake-exodus
+index 787fd9d..ed073a2 100755
+--- a/cmake-exodus
++++ b/cmake-exodus
+@@ -1,4 +1,6 @@
+-EXTRA_ARGS=$@
++#!/bin/bash
++
++EXTRA_ARGS=-DSEACASProj_ENABLE_CXX11=OFF
+
+ ### Change this to point to the compilers you want to use
+ CC=gcc
diff --git a/var/spack/repos/builtin/packages/exodusii/package.py b/var/spack/repos/builtin/packages/exodusii/package.py
new file mode 100644
index 0000000000..af258b7e6e
--- /dev/null
+++ b/var/spack/repos/builtin/packages/exodusii/package.py
@@ -0,0 +1,49 @@
+from spack import *
+
+# TODO: Add support for a C++11 enabled installation that filters out the
+# TODO: "C++11-Disabled" flag (but only if the spec compiler supports C++11).
+
+# TODO: Add support for parallel installation that uses MPI.
+
+# TODO: Create installation options for NetCDF that support larger page size
+# TODO: suggested by Exodus (see the repository "README" file).
+
+class Exodusii(Package):
+ """Exodus II is a C++/Fortran library developed to store and retrieve data for
+ finite element analyses. It's used for preprocessing (problem definition),
+ postprocessing (results visualization), and data transfer between codes.
+ An Exodus II data file is a random access, machine independent, binary
+ file that is written and read via C, C++, or Fortran API routines."""
+
+ homepage = "https://github.com/gsjaardema/seacas"
+ url = "https://github.com/gsjaardema/seacas/archive/master.zip"
+
+ version('2016-02-08', git='https://github.com/gsjaardema/seacas.git', commit='dcf3529')
+
+ # TODO: Make this a build dependency once build dependencies are supported
+ # (see: https://github.com/LLNL/spack/pull/378).
+ depends_on('cmake@2.8.7:')
+ depends_on('hdf5~shared~mpi')
+ depends_on('netcdf~mpi')
+
+ patch('exodus-cmake.patch')
+
+ def patch(self):
+ ff = FileFilter('cmake-exodus')
+
+ ff.filter('CMAKE_INSTALL_PREFIX:PATH=${ACCESS}',
+ 'CMAKE_INSTALL_PREFIX:PATH=%s' % self.spec.prefix, string=True)
+ ff.filter('NetCDF_DIR:PATH=${TPL}',
+ 'NetCDF_DIR:PATH=%s' % self.spec['netcdf'].prefix, string=True)
+ ff.filter('HDF5_ROOT:PATH=${TPL}',
+ 'HDF5_ROOT:PATH=%s' % self.spec['hdf5'].prefix, string=True)
+
+ def install(self, spec, prefix):
+ mkdirp('build')
+ cd('build')
+
+ cmake_exodus = Executable('../cmake-exodus')
+ cmake_exodus()
+
+ make()
+ make('install')
diff --git a/var/spack/repos/builtin/packages/gcc/package.py b/var/spack/repos/builtin/packages/gcc/package.py
index 3e5895cfb8..f8958ee290 100644
--- a/var/spack/repos/builtin/packages/gcc/package.py
+++ b/var/spack/repos/builtin/packages/gcc/package.py
@@ -36,8 +36,6 @@ class Gcc(Package):
list_url = 'http://open-source-box.org/gcc/'
list_depth = 2
- DEPENDS_ON_ISL_PREDICATE = '@5.0:'
-
version('5.3.0', 'c9616fd448f980259c31de613e575719')
version('5.2.0', 'a51bcfeb3da7dd4c623e27207ed43467')
version('4.9.3', '6f831b4d251872736e8e9cc09746f327')
@@ -53,12 +51,11 @@ class Gcc(Package):
depends_on("mpfr")
depends_on("gmp")
- depends_on("mpc") # when @4.5:
+ depends_on("mpc", when='@4.5:')
+ depends_on("isl", when='@5.0:')
depends_on("binutils~libiberty", when='~gold')
depends_on("binutils~libiberty+gold", when='+gold')
- # Save these until we can do optional deps.
- depends_on("isl", when=DEPENDS_ON_ISL_PREDICATE)
#depends_on("ppl")
#depends_on("cloog")
@@ -91,7 +88,7 @@ class Gcc(Package):
"--with-as=%s/bin/as" % spec['binutils'].prefix]
options.extend(binutils_options)
# Isl
- if spec.satisfies(Gcc.DEPENDS_ON_ISL_PREDICATE):
+ if 'isl' in spec:
isl_options = ["--with-isl=%s" % spec['isl'].prefix]
options.extend(isl_options)
diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py
index 5321a191f0..ed4e7c35c9 100644
--- a/var/spack/repos/builtin/packages/hdf5/package.py
+++ b/var/spack/repos/builtin/packages/hdf5/package.py
@@ -42,10 +42,11 @@ class Hdf5(Package):
version('1.8.13', 'c03426e9e77d7766944654280b467289')
variant('debug', default=False, description='Builds a debug version of the library')
+ variant('shared', default=True, description='Builds a shared version of the library')
variant('cxx', default=True, description='Enable C++ support')
variant('fortran', default=True, description='Enable Fortran support')
- variant('unsupported', default=False, description='Enables unsupported configuration options')
+ variant('unsupported', default=True, description='Enables unsupported configuration options')
variant('mpi', default=False, description='Enable MPI support')
variant('szip', default=False, description='Enable szip support')
@@ -78,6 +79,11 @@ class Hdf5(Package):
else:
extra_args.append('--enable-production')
+ if '+shared' in spec:
+ extra_args.append('--enable-shared')
+ else:
+ extra_args.append('--enable-static-exec')
+
if '+unsupported' in spec:
extra_args.append("--enable-unsupported")
@@ -119,7 +125,6 @@ class Hdf5(Package):
configure(
"--prefix=%s" % prefix,
"--with-zlib=%s" % spec['zlib'].prefix,
- "--enable-shared", # TODO : this should be enabled by default, remove it?
*extra_args)
make()
make("install")
diff --git a/var/spack/repos/builtin/packages/libedit/package.py b/var/spack/repos/builtin/packages/libedit/package.py
index bcd5212b9e..faed8bad37 100644
--- a/var/spack/repos/builtin/packages/libedit/package.py
+++ b/var/spack/repos/builtin/packages/libedit/package.py
@@ -7,6 +7,8 @@ class Libedit(Package):
version('3.1', '43cdb5df3061d78b5e9d59109871b4f6', url="http://thrysoee.dk/editline/libedit-20150325-3.1.tar.gz")
+ depends_on('ncurses')
+
def install(self, spec, prefix):
configure('--prefix=%s' % prefix)
diff --git a/var/spack/repos/builtin/packages/libgpg-error/package.py b/var/spack/repos/builtin/packages/libgpg-error/package.py
index 6c1d1a10a7..dd5fc2408a 100644
--- a/var/spack/repos/builtin/packages/libgpg-error/package.py
+++ b/var/spack/repos/builtin/packages/libgpg-error/package.py
@@ -9,6 +9,7 @@ class LibgpgError(Package):
homepage = "https://www.gnupg.org/related_software/libgpg-error"
url = "ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.18.tar.bz2"
+ version('1.21', 'ab0b5aba6d0a185b41d07bda804fd8b2')
version('1.18', '12312802d2065774b787cbfc22cc04e9')
def install(self, spec, prefix):
diff --git a/var/spack/repos/builtin/packages/llvm/package.py b/var/spack/repos/builtin/packages/llvm/package.py
index a2b2c6eccc..1805d3ded8 100644
--- a/var/spack/repos/builtin/packages/llvm/package.py
+++ b/var/spack/repos/builtin/packages/llvm/package.py
@@ -171,6 +171,25 @@ class Llvm(Package):
when='@%(version)s' % release,
placement=resources[name].get('placement', None))
+ # SVN - current develop
+ version('develop', svn='http://llvm.org/svn/llvm-project/llvm/trunk')
+ resource(name='clang', svn='http://llvm.org/svn/llvm-project/cfe/trunk',
+ destination='tools', when='@develop', placement='clang')
+ resource(name='compiler-rt', svn='http://llvm.org/svn/llvm-project/compiler-rt/trunk',
+ destination='projects', when='@develop', placement='compiler-rt')
+ resource(name='openmp', svn='http://llvm.org/svn/llvm-project/openmp/trunk',
+ destination='projects', when='@develop', placement='openmp')
+ resource(name='libcxx', svn='http://llvm.org/svn/llvm-project/libcxx/trunk',
+ destination='projects', when='@develop', placement='libcxx')
+ resource(name='libcxxabi', svn='http://llvm.org/svn/llvm-project/libcxxabi/trunk',
+ destination='projects', when='@develop', placement='libcxxabi')
+ resource(name='polly', svn='http://llvm.org/svn/llvm-project/polly/trunk',
+ destination='tools', when='@develop', placement='polly')
+ resource(name='lldb', svn='http://llvm.org/svn/llvm-project/lldb/trunk',
+ destination='tools', when='@develop', placement='lldb')
+
+
+
def install(self, spec, prefix):
env['CXXFLAGS'] = self.compiler.cxx11_flag
cmake_args = [ arg for arg in std_cmake_args if 'BUILD_TYPE' not in arg ]
diff --git a/var/spack/repos/builtin/packages/mpich/package.py b/var/spack/repos/builtin/packages/mpich/package.py
index c856cfe277..c517defa83 100644
--- a/var/spack/repos/builtin/packages/mpich/package.py
+++ b/var/spack/repos/builtin/packages/mpich/package.py
@@ -48,10 +48,11 @@ class Mpich(Package):
def setup_dependent_environment(self, module, spec, dep_spec):
"""For dependencies, make mpicc's use spack wrapper."""
- os.environ['MPICH_CC'] = 'cc'
- os.environ['MPICH_CXX'] = 'c++'
- os.environ['MPICH_F77'] = 'f77'
- os.environ['MPICH_F90'] = 'f90'
+ os.environ['MPICH_CC'] = os.environ['CC']
+ os.environ['MPICH_CXX'] = os.environ['CXX']
+ os.environ['MPICH_F77'] = os.environ['F77']
+ os.environ['MPICH_F90'] = os.environ['FC']
+ os.environ['MPICH_FC'] = os.environ['FC']
def install(self, spec, prefix):
diff --git a/var/spack/repos/builtin/packages/ndiff/package.py b/var/spack/repos/builtin/packages/ndiff/package.py
new file mode 100644
index 0000000000..10e445c81e
--- /dev/null
+++ b/var/spack/repos/builtin/packages/ndiff/package.py
@@ -0,0 +1,21 @@
+from spack import *
+
+class Ndiff(Package):
+ """The ndiff tool is a binary utility that compares putatively similar files
+ while ignoring small numeric differernces. This utility is most often used
+ to compare files containing a lot of floating-point numeric data that
+ may be slightly different due to numeric error."""
+
+ homepage = "http://ftp.math.utah.edu/pub/ndiff/"
+ url = "http://ftp.math.utah.edu/pub/ndiff/ndiff-2.00.tar.gz"
+
+ version('2.00', '885548b4dc26e72c5455bebb5ba6c16d')
+ version('1.00', 'f41ffe5d12f36cd36b6311acf46eccdc')
+
+ def install(self, spec, prefix):
+ configure('--prefix=%s' % prefix)
+
+ mkdirp(prefix.bin)
+ mkdirp('%s/lib' % prefix.share)
+
+ make('install-exe', 'install-shrlib')
diff --git a/var/spack/repos/builtin/packages/netcdf/package.py b/var/spack/repos/builtin/packages/netcdf/package.py
index 3cd0b2ee7a..41a0d2b6f9 100644
--- a/var/spack/repos/builtin/packages/netcdf/package.py
+++ b/var/spack/repos/builtin/packages/netcdf/package.py
@@ -1,5 +1,6 @@
from spack import *
+
class Netcdf(Package):
"""NetCDF is a set of software libraries and self-describing, machine-independent
data formats that support the creation, access, and sharing of array-oriented
@@ -8,16 +9,18 @@ class Netcdf(Package):
homepage = "http://www.unidata.ucar.edu/software/netcdf/"
url = "ftp://ftp.unidata.ucar.edu/pub/netcdf/netcdf-4.3.3.tar.gz"
- version('4.4.0', 'f01cb26a0126dd9a6224e76472d25f6c')
+ version('4.4.0', 'cffda0cbd97fdb3a06e9274f7aef438e')
version('4.3.3', '5fbd0e108a54bd82cb5702a73f56d2ae')
+ variant('mpi', default=True, description='Enables MPI parallelism')
variant('fortran', default=False, description="Download and install NetCDF-Fortran")
variant('hdf4', default=False, description="Enable HDF4 support")
# Dependencies:
depends_on("curl") # required for DAP support
depends_on("hdf", when='+hdf4')
- depends_on("hdf5") # required for NetCDF-4 support
+ depends_on("hdf5+mpi~cxx", when='+mpi') # required for NetCDF-4 support
+ depends_on("hdf5~mpi", when='~mpi') # required for NetCDF-4 support
depends_on("zlib") # required for NetCDF-4 support
def install(self, spec, prefix):
@@ -41,6 +44,9 @@ class Netcdf(Package):
"--enable-dap"
]
+ if '+mpi' in spec:
+ config_args.append('--enable-parallel4')
+
CPPFLAGS.append("-I%s/include" % spec['hdf5'].prefix)
LDFLAGS.append( "-L%s/lib" % spec['hdf5'].prefix)
diff --git a/var/spack/repos/builtin/packages/netlib-scalapack/package.py b/var/spack/repos/builtin/packages/netlib-scalapack/package.py
index 5be91c4a40..22d538560e 100644
--- a/var/spack/repos/builtin/packages/netlib-scalapack/package.py
+++ b/var/spack/repos/builtin/packages/netlib-scalapack/package.py
@@ -22,8 +22,8 @@ class NetlibScalapack(Package):
def install(self, spec, prefix):
options = [
- "-DBUILD_SHARED_LIBS:BOOL=%s" % 'ON' if '+shared' in spec else 'OFF',
- "-DBUILD_STATIC_LIBS:BOOL=%s" % 'OFF' if '+shared' in spec else 'ON',
+ "-DBUILD_SHARED_LIBS:BOOL=%s" % ('ON' if '+shared' in spec else 'OFF'),
+ "-DBUILD_STATIC_LIBS:BOOL=%s" % ('OFF' if '+shared' in spec else 'ON'),
"-DUSE_OPTIMIZED_LAPACK_BLAS:BOOL=ON", # forces scalapack to use find_package(LAPACK)
]
diff --git a/var/spack/repos/builtin/packages/openblas/package.py b/var/spack/repos/builtin/packages/openblas/package.py
index 9c8fa1c694..3c909360a4 100644
--- a/var/spack/repos/builtin/packages/openblas/package.py
+++ b/var/spack/repos/builtin/packages/openblas/package.py
@@ -19,7 +19,9 @@ class Openblas(Package):
with working_dir(prefix.lib):
symlink('libopenblas.a', 'blas.a')
symlink('libopenblas.a', 'libblas.a')
+ symlink('libopenblas.so', 'libblas.so')
# Lapack virtual package should provide liblapack.a
with working_dir(prefix.lib):
symlink('libopenblas.a', 'liblapack.a')
+ symlink('libopenblas.so', 'liblapack.so')
diff --git a/var/spack/repos/builtin/packages/opencv/package.py b/var/spack/repos/builtin/packages/opencv/package.py
new file mode 100644
index 0000000000..99b555323f
--- /dev/null
+++ b/var/spack/repos/builtin/packages/opencv/package.py
@@ -0,0 +1,50 @@
+from spack import *
+
+
+class Opencv(Package):
+ """
+ OpenCV is released under a BSD license and hence it's free for both academic and commercial use. It has C++, C,
+ Python and Java interfaces and supports Windows, Linux, Mac OS, iOS and Android. OpenCV was designed for
+ computational efficiency and with a strong focus on real-time applications. Written in optimized C/C++, the library
+ can take advantage of multi-core processing. Enabled with OpenCL, it can take advantage of the hardware
+ acceleration of the underlying heterogeneous compute platform. Adopted all around the world, OpenCV has more than
+ 47 thousand people of user community and estimated number of downloads exceeding 9 million. Usage ranges from
+ interactive art, to mines inspection, stitching maps on the web or through advanced robotics.
+ """
+ homepage = 'http://opencv.org/'
+ url = 'https://github.com/Itseez/opencv/archive/3.1.0.tar.gz'
+
+ version('3.1.0', '70e1dd07f0aa06606f1bc0e3fa15abd3')
+
+ variant('shared', default=True, description='Enables the build of shared libraries')
+ variant('debug', default=False, description='Builds a debug version of the libraries')
+
+ variant('eigen', default=True, description='Activates support for eigen')
+ variant('ipp', default=True, description='Activates support for IPP')
+
+ depends_on('zlib')
+ depends_on('libpng')
+ depends_on('libjpeg-turbo')
+ depends_on('libtiff')
+
+ depends_on('python')
+ depends_on('py-numpy')
+
+ depends_on('eigen', when='+eigen')
+
+ # FIXME : GUI extensions missing
+ # FIXME : CUDA extensions still missing
+
+ def install(self, spec, prefix):
+ cmake_options = []
+ cmake_options.extend(std_cmake_args)
+
+ cmake_options.extend(['-DCMAKE_BUILD_TYPE:STRING=%s' % ('Debug' if '+debug' in spec else 'Release'),
+ '-DBUILD_SHARED_LIBS:BOOL=%s' % ('ON' if '+shared' in spec else 'OFF'),
+ '-DENABLE_PRECOMPILED_HEADERS:BOOL=OFF',
+ '-DWITH_IPP:BOOL=%s' % ('ON' if '+ipp' in spec else 'OFF')])
+
+ with working_dir('spack_build', create=True):
+ cmake('..', *cmake_options)
+ make('VERBOSE=1')
+ make("install")
diff --git a/var/spack/repos/builtin/packages/paraview/package.py b/var/spack/repos/builtin/packages/paraview/package.py
index aaab352e66..e43bdd4493 100644
--- a/var/spack/repos/builtin/packages/paraview/package.py
+++ b/var/spack/repos/builtin/packages/paraview/package.py
@@ -14,6 +14,7 @@ class Paraview(Package):
variant('osmesa', default=False, description='Enable OSMesa support')
variant('qt', default=False, description='Enable Qt support')
+ variant('opengl2', default=False, description='Enable OPengl2 backend')
depends_on('python', when='+python')
depends_on('py-numpy', when='+python')
diff --git a/var/spack/repos/builtin/packages/py-mpi4py/package.py b/var/spack/repos/builtin/packages/py-mpi4py/package.py
index 8001689a18..f599205644 100644
--- a/var/spack/repos/builtin/packages/py-mpi4py/package.py
+++ b/var/spack/repos/builtin/packages/py-mpi4py/package.py
@@ -5,7 +5,9 @@ class PyMpi4py(Package):
homepage = "https://pypi.python.org/pypi/mpi4py"
url = "https://pypi.python.org/packages/source/m/mpi4py/mpi4py-1.3.1.tar.gz"
+ version('2.0.0', '4f7d8126d7367c239fd67615680990e3')
version('1.3.1', 'dbe9d22bdc8ed965c23a7ceb6f32fc3c')
+
extends('python')
depends_on('py-setuptools')
depends_on('mpi')
diff --git a/var/spack/repos/builtin/packages/py-phonopy/package.py b/var/spack/repos/builtin/packages/py-phonopy/package.py
new file mode 100644
index 0000000000..6d10fea74f
--- /dev/null
+++ b/var/spack/repos/builtin/packages/py-phonopy/package.py
@@ -0,0 +1,18 @@
+from spack import *
+
+class PyPhonopy(Package):
+ """Phonopy is an open source package for phonon
+ calculations at harmonic and quasi-harmonic levels."""
+ homepage = "http://atztogo.github.io/phonopy/index.html"
+ url = "http://sourceforge.net/projects/phonopy/files/phonopy/phonopy-1.10/phonopy-1.10.0.tar.gz"
+
+ version('1.10.0', '973ed1bcea46e21b9bf747aab9061ff6')
+
+ extends('python')
+ depends_on('py-numpy')
+ depends_on('py-scipy')
+ depends_on('py-matplotlib')
+ depends_on('py-pyyaml')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--home=%s' % prefix)
diff --git a/var/spack/repos/builtin/packages/py-pyyaml/package.py b/var/spack/repos/builtin/packages/py-pyyaml/package.py
new file mode 100644
index 0000000000..cae42f6e59
--- /dev/null
+++ b/var/spack/repos/builtin/packages/py-pyyaml/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyPyyaml(Package):
+ """PyYAML is a YAML parser and emitter for Python."""
+ homepage = "http://pyyaml.org/wiki/PyYAML"
+ url = "http://pyyaml.org/download/pyyaml/PyYAML-3.11.tar.gz"
+
+ version('3.11', 'f50e08ef0fe55178479d3a618efe21db')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/repos/builtin/packages/qhull/package.py b/var/spack/repos/builtin/packages/qhull/package.py
index f6712ced38..8f7c2f31b1 100644
--- a/var/spack/repos/builtin/packages/qhull/package.py
+++ b/var/spack/repos/builtin/packages/qhull/package.py
@@ -8,20 +8,20 @@ class Qhull(Package):
implements the Quickhull algorithm for computing the convex
hull. It handles roundoff errors from floating point
arithmetic. It computes volumes, surface areas, and
- approximations to the convex hull.
-
- Qhull does not support triangulation of non-convex surfaces,
- mesh generation of non-convex objects, medium-sized inputs in
- 9-D and higher, alpha shapes, weighted Voronoi diagrams,
- Voronoi volumes, or constrained Delaunay triangulations."""
+ approximations to the convex hull."""
homepage = "http://www.qhull.org"
+ version('7.2.0', 'e6270733a826a6a7c32b796e005ec3dc',
+ url="http://www.qhull.org/download/qhull-2015-src-7.2.0.tgz")
+
version('1.0', 'd0f978c0d8dfb2e919caefa56ea2953c',
url="http://www.qhull.org/download/qhull-2012.1-src.tgz")
# https://github.com/qhull/qhull/pull/5
- patch('qhull-iterator.patch')
+ patch('qhull-iterator.patch', when='@1.0')
+
+ depends_on('cmake')
def install(self, spec, prefix):
with working_dir('spack-build', create=True):
diff --git a/var/spack/repos/builtin/packages/qt/package.py b/var/spack/repos/builtin/packages/qt/package.py
index e8d843519d..91afa420c1 100644
--- a/var/spack/repos/builtin/packages/qt/package.py
+++ b/var/spack/repos/builtin/packages/qt/package.py
@@ -23,6 +23,7 @@ class Qt(Package):
version('3.3.8b', '9f05b4125cfe477cc52c9742c3c09009',
url="http://download.qt.io/archive/qt/3/qt-x11-free-3.3.8b.tar.gz")
+ variant('mesa', default=False, description='depend on mesa')
# Add patch for compile issues with qt3 found with use in the OpenSpeedShop project
variant('krellpatch', default=False, description="build with openspeedshop based patch.")
patch('qt3krell.patch', when='@3.3.8b+krellpatch')
@@ -48,7 +49,7 @@ class Qt(Package):
# depends_on("icu4c")
# OpenGL hardware acceleration
- depends_on("mesa", when='@4:')
+ depends_on("mesa", when='@4:+mesa')
depends_on("libxcb")
diff --git a/var/spack/repos/builtin/packages/tetgen/package.py b/var/spack/repos/builtin/packages/tetgen/package.py
new file mode 100644
index 0000000000..30c2b76655
--- /dev/null
+++ b/var/spack/repos/builtin/packages/tetgen/package.py
@@ -0,0 +1,28 @@
+from spack import *
+
+class Tetgen(Package):
+ """TetGen is a program and library that can be used to generate tetrahedral
+ meshes for given 3D polyhedral domains. TetGen generates exact constrained
+ Delaunay tetrahedralizations, boundary conforming Delaunay meshes, and
+ Voronoi paritions."""
+
+ homepage = "http://www.tetgen.org"
+ url = "http://www.tetgen.org/files/tetgen1.4.3.tar.gz"
+
+ version('1.4.3', 'd6a4bcdde2ac804f7ec66c29dcb63c18')
+
+ # TODO: Make this a build dependency once build dependencies are supported
+ # (see: https://github.com/LLNL/spack/pull/378).
+ depends_on('cmake@2.8.7:', when='@1.5.0:')
+
+ def install(self, spec, prefix):
+ make('tetgen', 'tetlib')
+
+ mkdirp(prefix.bin)
+ install('tetgen', prefix.bin)
+
+ mkdirp(prefix.include)
+ install('tetgen.h', prefix.include)
+
+ mkdirp(prefix.lib)
+ install('libtet.a', prefix.lib)
diff --git a/var/spack/repos/builtin/packages/triangle/package.py b/var/spack/repos/builtin/packages/triangle/package.py
new file mode 100644
index 0000000000..f65d93776d
--- /dev/null
+++ b/var/spack/repos/builtin/packages/triangle/package.py
@@ -0,0 +1,20 @@
+from spack import *
+
+class Triangle(Package):
+ """Triangle is a two-dimensional mesh generator and Delaunay
+ triangulator. Triangle generates exact Delaunay triangulations,
+ constrained Delaunay triangulations, conforming Delaunay
+ triangulations, Voronoi diagrams, and high-quality triangular
+ meshes."""
+
+ homepage = "http://www.cs.cmu.edu/~quake/triangle.html"
+ url = "http://www.netlib.org/voronoi/triangle.zip"
+
+ version('1.6', '10aff8d7950f5e0e2fb6dd2e340be2c9')
+
+ def install(self, spec, prefix):
+ make()
+ mkdirp(prefix.bin)
+
+ install('triangle', prefix.bin)
+ install('showme', prefix.bin)
diff --git a/var/spack/repos/builtin/packages/trilinos/package.py b/var/spack/repos/builtin/packages/trilinos/package.py
index 7c43f796a4..edc40476e3 100644
--- a/var/spack/repos/builtin/packages/trilinos/package.py
+++ b/var/spack/repos/builtin/packages/trilinos/package.py
@@ -10,40 +10,44 @@ class Trilinos(Package):
homepage = "https://trilinos.org/"
url = "http://trilinos.csbsju.edu/download/files/trilinos-12.2.1-Source.tar.gz"
+ version('12.4.2', '7c830f7f0f68b8ad324690603baf404e')
version('12.2.1', '6161926ea247863c690e927687f83be9')
version('12.0.1', 'bd99741d047471e127b8296b2ec08017')
version('11.14.3', '2f4f83f8333e4233c57d0f01c4b57426')
version('11.14.2', 'a43590cf896c677890d75bfe75bc6254')
version('11.14.1', '40febc57f76668be8b6a77b7607bb67f')
- variant('mpi', default=True, description='Add a dependency on MPI and enables MPI dependent packages')
+ variant('shared', default=True, description='Enables the build of shared libraries')
+ variant('debug', default=False, description='Builds a debug version of the libraries')
# Everything should be compiled with -fpic
depends_on('blas')
depends_on('lapack')
depends_on('boost')
- depends_on('netcdf')
depends_on('matio')
depends_on('glm')
depends_on('swig')
- depends_on('mpi', when='+mpi')
- def install(self, spec, prefix):
+ # MPI related dependencies
+ depends_on('mpi')
+ depends_on('netcdf+mpi')
+
+ depends_on('python') # Needs py-numpy activated
- options = [
- '-DTrilinos_ENABLE_ALL_PACKAGES:BOOL=ON',
- '-DTrilinos_ENABLE_TESTS:BOOL=OFF',
- '-DTrilinos_ENABLE_EXAMPLES:BOOL=OFF',
- '-DBUILD_SHARED_LIBS:BOOL=ON',
- '-DBLAS_LIBRARY_DIRS:PATH=%s' % spec['blas'].prefix,
- '-DLAPACK_LIBRARY_DIRS:PATH=%s' % spec['lapack'].prefix
- ]
- if '+mpi' in spec:
- mpi_options = ['-DTPL_ENABLE_MPI:BOOL=ON']
- options.extend(mpi_options)
-
- # -DCMAKE_INSTALL_PREFIX and all the likes...
+ def install(self, spec, prefix):
+ options = []
options.extend(std_cmake_args)
+
+ options.extend(['-DTrilinos_ENABLE_ALL_PACKAGES:BOOL=ON',
+ '-DTrilinos_ENABLE_TESTS:BOOL=OFF',
+ '-DTrilinos_ENABLE_EXAMPLES:BOOL=OFF',
+ '-DCMAKE_BUILD_TYPE:STRING=%s' % ('Debug' if '+debug' in spec else 'Release'),
+ '-DBUILD_SHARED_LIBS:BOOL=%s' % ('ON' if '+shared' in spec else 'OFF'),
+ '-DTPL_ENABLE_MPI:STRING=ON',
+ '-DBLAS_LIBRARY_DIRS:PATH=%s' % spec['blas'].prefix,
+ '-DLAPACK_LIBRARY_DIRS:PATH=%s' % spec['lapack'].prefix
+ ])
+
with working_dir('spack-build', create=True):
cmake('..', *options)
make()
diff --git a/var/spack/repos/builtin/packages/xz/package.py b/var/spack/repos/builtin/packages/xz/package.py
index ba6c9733a7..fdcac95345 100644
--- a/var/spack/repos/builtin/packages/xz/package.py
+++ b/var/spack/repos/builtin/packages/xz/package.py
@@ -8,11 +8,9 @@ class Xz(Package):
homepage = "http://tukaani.org/xz/"
url = "http://tukaani.org/xz/xz-5.2.0.tar.bz2"
- version('5.2.0', '867cc8611760240ebf3440bd6e170bb9',
- url = 'http://tukaani.org/xz/xz-5.2.0.tar.bz2')
- version('5.2.2', 'f90c9a0c8b259aee2234c4e0d7fd70af',
- url = 'http://tukaani.org/xz/xz-5.2.2.tar.bz2')
-
+ version('5.2.0', '867cc8611760240ebf3440bd6e170bb9')
+ version('5.2.2', 'f90c9a0c8b259aee2234c4e0d7fd70af')
+
def install(self, spec, prefix):
configure("--prefix=%s" % prefix)
make()