summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2015-03-17 20:59:47 -0400
committerTodd Gamblin <tgamblin@llnl.gov>2015-05-10 12:24:03 -0700
commit0944ba120cad3de7b84b15e19b9c889f5bea6241 (patch)
treeaa93b47f69e95c93ae046afffdacf801d317e1d1 /lib
parent8e87b2176ad762a75acfdab158ddd788648ee997 (diff)
downloadspack-0944ba120cad3de7b84b15e19b9c889f5bea6241.tar.gz
spack-0944ba120cad3de7b84b15e19b9c889f5bea6241.tar.bz2
spack-0944ba120cad3de7b84b15e19b9c889f5bea6241.tar.xz
spack-0944ba120cad3de7b84b15e19b9c889f5bea6241.zip
relations are now "directives", and code is cleaned up.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/llnl/util/lang.py25
-rw-r--r--lib/spack/spack/__init__.py6
-rw-r--r--lib/spack/spack/directives.py (renamed from lib/spack/spack/relations.py)128
-rw-r--r--lib/spack/spack/multimethod.py2
-rw-r--r--lib/spack/spack/package.py3
5 files changed, 82 insertions, 82 deletions
diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py
index 332367f537..13453c20ed 100644
--- a/lib/spack/llnl/util/lang.py
+++ b/lib/spack/llnl/util/lang.py
@@ -126,9 +126,9 @@ def caller_locals():
del stack
-def get_calling_package_name():
+def get_calling_module_name():
"""Make sure that the caller is a class definition, and return the
- module's name.
+ enclosing module's name.
"""
stack = inspect.stack()
try:
@@ -322,6 +322,27 @@ def match_predicate(*args):
return match
+
+def DictWrapper(dictionary):
+ """Returns a class that wraps a dictionary and enables it to be used
+ like an object."""
+ class wrapper(object):
+ def __getattr__(self, name):
+ return dictionary[name]
+
+ def __setattr__(self, name, value):
+ dictionary[name] = value
+ return value
+
+ def setdefault(self, *args):
+ return dictionary.setdefault(*args)
+
+ def get(self, *args):
+ return dictionary.get(*args)
+
+ return wrapper()
+
+
class RequiredAttributeError(ValueError):
def __init__(self, message):
super(RequiredAttributeError, self).__init__(message)
diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py
index eb891e3d57..053c4036d8 100644
--- a/lib/spack/spack/__init__.py
+++ b/lib/spack/spack/__init__.py
@@ -146,9 +146,9 @@ import llnl.util.filesystem
from llnl.util.filesystem import *
__all__ += llnl.util.filesystem.__all__
-import spack.relations
-from spack.relations import *
-__all__ += spack.relations.__all__
+import spack.directives
+from spack.directives import *
+__all__ += spack.directives.__all__
import spack.util.executable
from spack.util.executable import *
diff --git a/lib/spack/spack/relations.py b/lib/spack/spack/directives.py
index a0c7723473..e1589c019f 100644
--- a/lib/spack/spack/relations.py
+++ b/lib/spack/spack/directives.py
@@ -22,51 +22,26 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
-"""
-This package contains relationships that can be defined among packages.
-Relations are functions that can be called inside a package definition,
-for example:
+"""This package contains directives that can be used within a package.
+
+Directives are functions that can be called inside a package
+definition to modify the package, for example:
- class OpenMPI(Package):
+ class OpenMpi(Package):
depends_on("hwloc")
provides("mpi")
...
-The available relations are:
-
-depends_on
- Above, the OpenMPI package declares that it "depends on" hwloc. This means
- that the hwloc package needs to be installed before OpenMPI can be
- installed. When a user runs 'spack install openmpi', spack will fetch
- hwloc and install it first.
-
-provides
- This is useful when more than one package can satisfy a dependence. Above,
- OpenMPI declares that it "provides" mpi. Other implementations of the MPI
- interface, like mvapich and mpich, also provide mpi, e.g.:
+``provides`` and ``depends_on`` are spack directives.
- class Mvapich(Package):
- provides("mpi")
- ...
+The available directives are:
- class Mpich(Package):
- provides("mpi")
- ...
+ * ``version``
+ * ``depends_on``
+ * ``provides``
+ * ``extends``
+ * ``patch``
- Instead of depending on openmpi, mvapich, or mpich, another package can
- declare that it depends on "mpi":
-
- class Mpileaks(Package):
- depends_on("mpi")
- ...
-
- Now the user can pick which MPI they would like to build with when they
- install mpileaks. For example, the user could install 3 instances of
- mpileaks, one for each MPI version, by issuing these three commands:
-
- spack install mpileaks ^openmpi
- spack install mpileaks ^mvapich
- spack install mpileaks ^mpich
"""
__all__ = [ 'depends_on', 'extends', 'provides', 'patch', 'version' ]
@@ -84,14 +59,27 @@ from spack.patch import Patch
from spack.spec import Spec, parse_anonymous_spec
+def directive(fun):
+ """Decorator that allows a function to be called while a class is
+ being constructed, and to modify the class.
-def version(ver, checksum=None, **kwargs):
+ Adds the class scope as an initial parameter when called, like
+ a class method would.
+ """
+ def directive_function(*args, **kwargs):
+ pkg = DictWrapper(caller_locals())
+ pkg.name = get_calling_module_name()
+ return fun(pkg, *args, **kwargs)
+ return directive_function
+
+
+@directive
+def version(pkg, ver, checksum=None, **kwargs):
"""Adds a version and metadata describing how to fetch it.
Metadata is just stored as a dict in the package's versions
dictionary. Package must turn it into a valid fetch strategy
later.
"""
- pkg = caller_locals()
versions = pkg.setdefault('versions', {})
# special case checksum for backward compatibility
@@ -103,21 +91,21 @@ def version(ver, checksum=None, **kwargs):
versions[Version(ver)] = kwargs
-def depends_on(*specs):
+@directive
+def depends_on(pkg, *specs):
"""Adds a dependencies local variable in the locals of
the calling class, based on args. """
- pkg = get_calling_package_name()
- clocals = caller_locals()
- dependencies = clocals.setdefault('dependencies', {})
+ dependencies = pkg.setdefault('dependencies', {})
for string in specs:
for spec in spack.spec.parse(string):
- if pkg == spec.name:
- raise CircularReferenceError('depends_on', pkg)
+ if pkg.name == spec.name:
+ raise CircularReferenceError('depends_on', pkg.name)
dependencies[spec.name] = spec
-def extends(spec, **kwargs):
+@directive
+def extends(pkg, spec, **kwargs):
"""Same as depends_on, but dependency is symlinked into parent prefix.
This is for Python and other language modules where the module
@@ -131,64 +119,54 @@ def extends(spec, **kwargs):
mechanism.
"""
- pkg = get_calling_package_name()
- clocals = caller_locals()
- dependencies = clocals.setdefault('dependencies', {})
- extendees = clocals.setdefault('extendees', {})
+ dependencies = pkg.setdefault('dependencies', {})
+ extendees = pkg.setdefault('extendees', {})
if extendees:
raise RelationError("Packages can extend at most one other package.")
spec = Spec(spec)
- if pkg == spec.name:
- raise CircularReferenceError('extends', pkg)
+ if pkg.name == spec.name:
+ raise CircularReferenceError('extends', pkg.name)
dependencies[spec.name] = spec
extendees[spec.name] = (spec, kwargs)
-def provides(*specs, **kwargs):
+@directive
+def provides(pkg, *specs, **kwargs):
"""Allows packages to provide a virtual dependency. If a package provides
'mpi', other packages can declare that they depend on "mpi", and spack
can use the providing package to satisfy the dependency.
"""
- pkg = get_calling_package_name()
- spec_string = kwargs.get('when', pkg)
- provider_spec = parse_anonymous_spec(spec_string, pkg)
+ spec_string = kwargs.get('when', pkg.name)
+ provider_spec = parse_anonymous_spec(spec_string, pkg.name)
- provided = caller_locals().setdefault("provided", {})
+ provided = pkg.setdefault("provided", {})
for string in specs:
for provided_spec in spack.spec.parse(string):
- if pkg == provided_spec.name:
- raise CircularReferenceError('depends_on', pkg)
+ if pkg.name == provided_spec.name:
+ raise CircularReferenceError('depends_on', pkg.name)
provided[provided_spec] = provider_spec
-def patch(url_or_filename, **kwargs):
+@directive
+def patch(pkg, url_or_filename, **kwargs):
"""Packages can declare patches to apply to source. You can
optionally provide a when spec to indicate that a particular
patch should only be applied when the package's spec meets
certain conditions (e.g. a particular version).
"""
- pkg = get_calling_package_name()
level = kwargs.get('level', 1)
- when_spec = parse_anonymous_spec(kwargs.get('when', pkg), pkg)
+ when = kwargs.get('when', pkg.name)
- patches = caller_locals().setdefault('patches', {})
+ patches = pkg.setdefault('patches', {})
+
+ when_spec = parse_anonymous_spec(when, pkg.name)
if when_spec not in patches:
- patches[when_spec] = [Patch(pkg, url_or_filename, level)]
+ patches[when_spec] = [Patch(pkg.name, url_or_filename, level)]
else:
# if this spec is identical to some other, then append this
# patch to the existing list.
- patches[when_spec].append(Patch(pkg, url_or_filename, level))
-
-
-def conflicts(*specs):
- """Packages can declare conflicts with other packages.
- This can be as specific as you like: use regular spec syntax.
-
- NOT YET IMPLEMENTED.
- """
- # TODO: implement conflicts
- pass
+ patches[when_spec].append(Patch(pkg.name, url_or_filename, level))
class RelationError(spack.error.SpackError):
diff --git a/lib/spack/spack/multimethod.py b/lib/spack/spack/multimethod.py
index 974401e1aa..892619c6ac 100644
--- a/lib/spack/spack/multimethod.py
+++ b/lib/spack/spack/multimethod.py
@@ -195,7 +195,7 @@ class when(object):
"""
class when(object):
def __init__(self, spec):
- pkg = get_calling_package_name()
+ pkg = get_calling_module_name()
self.spec = parse_anonymous_spec(spec, pkg)
def __call__(self, method):
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 7d9eca5077..7f2b53ceed 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -303,7 +303,8 @@ class Package(object):
"""
#
- # These variables are defaults for the various "relations".
+ # These variables are defaults for Spack's various package
+ # directives.
#
"""Map of information about Versions of this package.
Map goes: Version -> dict of attributes"""