summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/spack/__init__.py10
-rw-r--r--lib/spack/spack/package.py121
-rw-r--r--var/spack/repos/builtin/packages/swiftsim/package.py18
-rw-r--r--var/spack/repos/builtin/packages/szip/package.py32
4 files changed, 109 insertions, 72 deletions
diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py
index 0e811e5ee7..85a0a4e2f7 100644
--- a/lib/spack/spack/__init__.py
+++ b/lib/spack/spack/__init__.py
@@ -176,10 +176,14 @@ 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', 'CMakePackage', \
- 'Version', 'when', 'ver']
+__all__ = ['Package',
+ 'CMakePackage',
+ 'AutotoolsPackage',
+ 'Version',
+ 'when',
+ 'ver']
from spack.package import Package, ExtensionConflictError
-from spack.package import CMakePackage
+from spack.package import CMakePackage, AutotoolsPackage
from spack.version import Version, ver
from spack.multimethod import when
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 4194f30827..dd5637b9bc 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -38,8 +38,8 @@ import re
import string
import textwrap
import time
-import inspect
import functools
+import inspect
from StringIO import StringIO
from urlparse import urlparse
@@ -74,7 +74,7 @@ class InstallPhase(object):
"""Manages a single phase of the installation
This descriptor stores at creation time the name of the method it should search
- for execution. The method is retrieved at get time, so that it can be overridden
+ for execution. The method is retrieved at __get__ time, so that it can be overridden
by subclasses of whatever class declared the phases.
It also provides hooks to execute prerequisite and sanity checks.
@@ -116,31 +116,63 @@ class PackageMeta(type):
"""
phase_fmt = '_InstallPhase_{0}'
- def __init__(cls, name, bases, attr_dict):
- super(PackageMeta, cls).__init__(name, bases, attr_dict)
- # Parse if phases is in attr dict, then set
+ _InstallPhase_sanity_checks = {}
+ _InstallPhase_preconditions = {}
+
+ def __new__(meta, name, bases, attr_dict):
+ # Check if phases is in attr dict, then set
# install phases wrappers
if 'phases' in attr_dict:
- cls.phases = [PackageMeta.phase_fmt.format(name) for name in attr_dict['phases']]
- for phase_name, callback_name in zip(cls.phases, attr_dict['phases']):
- setattr(cls, phase_name, InstallPhase(callback_name))
+ phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']]
+ for phase_name, callback_name in zip(phases, attr_dict['phases']):
+ attr_dict[phase_name] = InstallPhase(callback_name)
+ attr_dict['phases'] = phases
- def _transform_checks(check_name):
+ def _append_checks(check_name):
+ # Name of the attribute I am going to check it exists
attr_name = PackageMeta.phase_fmt.format(check_name)
- checks = getattr(cls, attr_name, None)
+ checks = getattr(meta, attr_name)
if checks:
for phase_name, funcs in checks.items():
- phase = getattr(cls, PackageMeta.phase_fmt.format(phase_name))
+ phase = attr_dict.get(PackageMeta.phase_fmt.format(phase_name))
getattr(phase, check_name).extend(funcs)
- # TODO : this should delete the attribute, as it is just a placeholder
- # TODO : to know what to do at class definition time. Clearing it is fine
- # TODO : too, but it just leaves an empty dictionary in place
- setattr(cls, attr_name, {})
+ # Clear the attribute for the next class
+ setattr(meta, attr_name, {})
+
+ @classmethod
+ def _register_checks(cls, check_type, *args):
+ def _register_sanity_checks(func):
+ attr_name = PackageMeta.phase_fmt.format(check_type)
+ sanity_checks = getattr(meta, attr_name)
+ for item in args:
+ checks = sanity_checks.setdefault(item, [])
+ checks.append(func)
+ setattr(meta, attr_name, sanity_checks)
+ return func
+ return _register_sanity_checks
+
+ @classmethod
+ def precondition(cls, *args):
+ return cls._register_checks('preconditions', *args)
+
+ @classmethod
+ def sanity_check(cls, *args):
+ return cls._register_checks('sanity_checks', *args)
+
+ if all([not hasattr(x, '_register_checks') for x in bases]):
+ attr_dict['_register_checks'] = _register_checks
+
+ if all([not hasattr(x, 'sanity_check') for x in bases]):
+ attr_dict['sanity_check'] = sanity_check
+
+ if all([not hasattr(x, 'precondition') for x in bases]):
+ attr_dict['precondition'] = precondition
# Preconditions
- _transform_checks('preconditions')
+ _append_checks('preconditions')
# Sanity checks
- _transform_checks('sanity_checks')
+ _append_checks('sanity_checks')
+ return super(PackageMeta, meta).__new__(meta, name, bases, attr_dict)
class PackageBase(object):
@@ -993,7 +1025,7 @@ class PackageBase(object):
# Ensure package is not already installed
# FIXME : skip condition : if any is True skip the installation
- if 'install' in self.phases and spack.install_layout.check_installed(self.spec):
+ if spack.install_layout.check_installed(self.spec):
tty.msg("%s is already installed in %s" % (self.name, self.prefix))
rec = spack.installed_db.get_record(self.spec)
if (not rec.explicit) and explicit:
@@ -1499,29 +1531,39 @@ class PackageBase(object):
"""
return " ".join("-Wl,-rpath,%s" % p for p in self.rpath)
- @classmethod
- def _register_checks(cls, check_type, *args):
- def _register_sanity_checks(func):
- attr_name = PackageMeta.phase_fmt.format(check_type)
- sanity_checks = getattr(cls, attr_name, {})
- for item in args:
- checks = sanity_checks.setdefault(item, [])
- checks.append(func)
- setattr(cls, attr_name, sanity_checks)
- return func
- return _register_sanity_checks
- @classmethod
- def precondition(cls, *args):
- return cls._register_checks('preconditions', *args)
+class Package(PackageBase):
+ phases = ['install', 'log']
+ # This will be used as a registration decorator in user
+ # packages, if need be
+ PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
+
- @classmethod
- def sanity_check(cls, *args):
- return cls._register_checks('sanity_checks', *args)
+class AutotoolsPackage(PackageBase):
+ phases = ['autoreconf', 'configure', 'build', 'install', 'log']
+ def autoreconf(self, spec, prefix):
+ """Not needed usually, configure should be already there"""
+ pass
+
+ @PackageBase.sanity_check('autoreconf')
+ def is_configure_or_die(self):
+ if not os.path.exists('configure'):
+ raise RuntimeError('configure script not found in {0}'.format(os.getcwd()))
+
+ def configure_args(self):
+ return list()
+
+ def configure(self, spec, prefix):
+ options = ['--prefix={0}'.format(prefix)] + self.configure_args()
+ inspect.getmodule(self).configure(*options)
+
+ def build(self, spec, prefix):
+ inspect.getmodule(self).make()
+
+ def install(self, spec, prefix):
+ inspect.getmodule(self).make('install')
-class Package(PackageBase):
- phases = ['install', 'log']
# This will be used as a registration decorator in user
# packages, if need be
PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
@@ -1637,7 +1679,7 @@ def _hms(seconds):
class CMakePackage(PackageBase):
- phases = ['setup', 'configure', 'build', 'install', 'provenance']
+ phases = ['configure', 'build', 'install', 'provenance']
def make_make(self):
import multiprocessing
@@ -1657,7 +1699,7 @@ class CMakePackage(PackageBase):
def configure_env(self):
"""Returns package-specific environment under which the configure command should be run."""
- # FIXME : Why not EnvironmentModules
+ # FIXME : Why not EnvironmentModules and the hooks that PackageBase already provides ?
return dict()
def spack_transitive_include_path(self):
@@ -1720,7 +1762,6 @@ env = dict(os.environ)
fout.write('\nproc = subprocess.Popen(cmd, env=env)\nproc.wait()\n')
set_executable(setup_fname)
-
def configure(self, spec, prefix):
cmake = which('cmake')
with working_dir(self.build_directory, create=True):
diff --git a/var/spack/repos/builtin/packages/swiftsim/package.py b/var/spack/repos/builtin/packages/swiftsim/package.py
index 42e8fb466a..7c3204f96b 100644
--- a/var/spack/repos/builtin/packages/swiftsim/package.py
+++ b/var/spack/repos/builtin/packages/swiftsim/package.py
@@ -28,7 +28,7 @@ from spack import *
import llnl.util.tty as tty
-class Swiftsim(Package):
+class Swiftsim(AutotoolsPackage):
"""
SPH With Inter-dependent Fine-grained Tasking (SWIFT) provides
astrophysicists with a state of the art framework to perform
@@ -59,19 +59,15 @@ class Swiftsim(Package):
tty.warn('This is needed to clone SWIFT repository')
spack_env.set('GIT_SSL_NO_VERIFY', 1)
- def install(self, spec, prefix):
- # Generate configure from configure.ac
- # and Makefile.am
+ def autoreconf(self, spec, prefix):
libtoolize()
aclocal()
autoconf()
autogen = Executable('./autogen.sh')
autogen()
- # Configure and install
- options = ['--prefix=%s' % prefix,
- '--enable-mpi' if '+mpi' in spec else '--disable-mpi',
- '--enable-optimization']
- configure(*options)
- make()
- make("install")
+ def config_args(self):
+ return ['--prefix=%s' % prefix,
+ '--enable-mpi' if '+mpi' in spec else '--disable-mpi',
+ '--with-metis={0}'.format(self.spec['metis'].prefix),
+ '--enable-optimization']
diff --git a/var/spack/repos/builtin/packages/szip/package.py b/var/spack/repos/builtin/packages/szip/package.py
index ec6d8239a9..91934f7d03 100644
--- a/var/spack/repos/builtin/packages/szip/package.py
+++ b/var/spack/repos/builtin/packages/szip/package.py
@@ -24,26 +24,22 @@
##############################################################################
from spack import *
-class Szip(Package):
- """Szip is an implementation of the extended-Rice lossless compression algorithm.
- It provides lossless compression of scientific data, and is provided with HDF
- software products."""
- homepage = "https://www.hdfgroup.org/doc_resource/SZIP/"
- url = "http://www.hdfgroup.org/ftp/lib-external/szip/2.1/src/szip-2.1.tar.gz"
+class Szip(AutotoolsPackage):
+ """Szip is an implementation of the extended-Rice lossless
+ compression algorithm.
- version('2.1', '902f831bcefb69c6b635374424acbead')
+ It provides lossless compression of scientific data, and is
+ provided with HDF software products.
+ """
- @Package.sanity_check('install')
- def always_raise(self):
- raise RuntimeError('Precondition not respected')
+ homepage = "https://www.hdfgroup.org/doc_resource/SZIP/"
+ url = "http://www.hdfgroup.org/ftp/lib-external/szip/2.1/src/szip-2.1.tar.gz"
- def install(self, spec, prefix):
- configure('--prefix=%s' % prefix,
- '--enable-production',
- '--enable-shared',
- '--enable-static',
- '--enable-encoding')
+ version('2.1', '902f831bcefb69c6b635374424acbead')
- make()
- make("install")
+ def configure_args(self):
+ return ['--enable-production',
+ '--enable-shared',
+ '--enable-static',
+ '--enable-encoding']