summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/llnl/util/filesystem.py15
-rw-r--r--lib/spack/llnl/util/link_tree.py193
-rw-r--r--lib/spack/spack/__init__.py2
-rw-r--r--lib/spack/spack/cmd/__init__.py15
-rw-r--r--lib/spack/spack/cmd/activate.py50
-rw-r--r--lib/spack/spack/cmd/deactivate.py50
-rw-r--r--lib/spack/spack/cmd/extensions.py97
-rw-r--r--lib/spack/spack/cmd/find.py69
-rw-r--r--lib/spack/spack/cmd/location.py48
-rw-r--r--lib/spack/spack/cmd/uninstall.py1
-rw-r--r--lib/spack/spack/directory_layout.py122
-rw-r--r--lib/spack/spack/hooks/__init__.py7
-rw-r--r--lib/spack/spack/hooks/extensions.py40
-rw-r--r--lib/spack/spack/mirror.py13
-rw-r--r--lib/spack/spack/modules.py8
-rw-r--r--lib/spack/spack/package.py235
-rw-r--r--lib/spack/spack/packages.py13
-rw-r--r--lib/spack/spack/relations.py33
-rw-r--r--lib/spack/spack/spec.py7
-rw-r--r--lib/spack/spack/test/__init__.py3
-rw-r--r--lib/spack/spack/test/link_tree.py153
-rw-r--r--lib/spack/spack/test/mirror.py8
-rwxr-xr-xshare/spack/setup-env.sh4
-rw-r--r--var/spack/packages/bison/package.py17
-rw-r--r--var/spack/packages/cloog/package.py26
-rw-r--r--var/spack/packages/dri2proto/package.py14
-rw-r--r--var/spack/packages/flex/package.py15
-rw-r--r--var/spack/packages/gcc/package.py29
-rw-r--r--var/spack/packages/hdf5/package.py6
-rw-r--r--var/spack/packages/icu4c/package.py17
-rw-r--r--var/spack/packages/isl/package.py17
-rw-r--r--var/spack/packages/libdrm/package.py18
-rw-r--r--var/spack/packages/libxcb/package.py21
-rw-r--r--var/spack/packages/libxshmfence/package.py16
-rw-r--r--var/spack/packages/llvm/package.py6
-rw-r--r--var/spack/packages/mesa/package.py33
-rw-r--r--var/spack/packages/ppl/package.py28
-rw-r--r--var/spack/packages/py-basemap/package.py25
-rw-r--r--var/spack/packages/py-biopython/package.py14
-rw-r--r--var/spack/packages/py-cython/package.py13
-rw-r--r--var/spack/packages/py-dateutil/package.py14
-rw-r--r--var/spack/packages/py-epydoc/package.py13
-rw-r--r--var/spack/packages/py-gnuplot/package.py13
-rw-r--r--var/spack/packages/py-h5py/package.py18
-rw-r--r--var/spack/packages/py-ipython/package.py14
-rw-r--r--var/spack/packages/py-libxml2/package.py13
-rw-r--r--var/spack/packages/py-mako/package.py16
-rw-r--r--var/spack/packages/py-matplotlib/package.py38
-rw-r--r--var/spack/packages/py-mpi4py/package.py13
-rw-r--r--var/spack/packages/py-mx/package.py13
-rw-r--r--var/spack/packages/py-nose/package.py15
-rw-r--r--var/spack/packages/py-numpy/package.py14
-rw-r--r--var/spack/packages/py-pexpect/package.py13
-rw-r--r--var/spack/packages/py-pil/package.py14
-rw-r--r--var/spack/packages/py-pmw/package.py13
-rw-r--r--var/spack/packages/py-pychecker/package.py13
-rw-r--r--var/spack/packages/py-pygments/package.py14
-rw-r--r--var/spack/packages/py-pylint/package.py16
-rw-r--r--var/spack/packages/py-pyparsing/package.py13
-rw-r--r--var/spack/packages/py-pyqt4/package.py18
-rw-r--r--var/spack/packages/py-pyside/package.py18
-rw-r--r--var/spack/packages/py-pytz/package.py13
-rw-r--r--var/spack/packages/py-rpy2/package.py14
-rw-r--r--var/spack/packages/py-scientificpython/package.py13
-rw-r--r--var/spack/packages/py-scikit-learn/package.py13
-rw-r--r--var/spack/packages/py-scipy/package.py15
-rw-r--r--var/spack/packages/py-setuptools/package.py13
-rw-r--r--var/spack/packages/py-sip/package.py15
-rw-r--r--var/spack/packages/py-six/package.py13
-rw-r--r--var/spack/packages/py-sympy/package.py13
-rw-r--r--var/spack/packages/py-virtualenv/package.py18
-rw-r--r--var/spack/packages/python/package.py122
-rw-r--r--var/spack/packages/qt/package.py71
-rw-r--r--var/spack/packages/ruby/package.py16
-rw-r--r--var/spack/packages/util-linux/package.py20
-rw-r--r--var/spack/packages/xcb-proto/package.py15
76 files changed, 2074 insertions, 137 deletions
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index 9f08832598..576aeb16bd 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -23,8 +23,8 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
__all__ = ['set_install_permissions', 'install', 'expand_user', 'working_dir',
- 'touch', 'mkdirp', 'force_remove', 'join_path', 'ancestor',
- 'can_access', 'filter_file', 'change_sed_delimiter']
+ 'touch', 'touchp', 'mkdirp', 'force_remove', 'join_path', 'ancestor',
+ 'can_access', 'filter_file', 'change_sed_delimiter', 'is_exe']
import os
import sys
@@ -154,6 +154,11 @@ def install(src, dest):
os.chmod(dest, dest_mode)
+def is_exe(path):
+ """True if path is an executable file."""
+ return os.path.isfile(path) and os.access(path, os.X_OK)
+
+
def expand_user(path):
"""Find instances of '%u' in a path and replace with the current user's
username."""
@@ -199,6 +204,12 @@ def touch(path):
os.utime(path, None)
+def touchp(path):
+ """Like touch, but creates any parent directories needed for the file."""
+ mkdirp(os.path.dirname(path))
+ touch(path)
+
+
def join_path(prefix, *args):
path = str(prefix)
for elt in args:
diff --git a/lib/spack/llnl/util/link_tree.py b/lib/spack/llnl/util/link_tree.py
new file mode 100644
index 0000000000..4e4e48316e
--- /dev/null
+++ b/lib/spack/llnl/util/link_tree.py
@@ -0,0 +1,193 @@
+##############################################################################
+# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+"""LinkTree class for setting up trees of symbolic links."""
+__all__ = ['LinkTree']
+
+import os
+import shutil
+from llnl.util.filesystem import *
+
+empty_file_name = '.spack-empty'
+
+
+def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
+ """Traverse two filesystem trees simultaneously.
+
+ Walks the LinkTree directory in pre or post order. Yields each
+ file in the source directory with a matching path from the dest
+ directory, along with whether the file is a directory.
+ e.g., for this tree::
+
+ root/
+ a/
+ file1
+ file2
+ b/
+ file3
+
+ When called on dest, this yields::
+
+ ('root', 'dest')
+ ('root/a', 'dest/a')
+ ('root/a/file1', 'dest/a/file1')
+ ('root/a/file2', 'dest/a/file2')
+ ('root/b', 'dest/b')
+ ('root/b/file3', 'dest/b/file3')
+
+ Optional args:
+
+ order=[pre|post] -- Whether to do pre- or post-order traveral.
+
+ ignore=<predicate> -- Predicate indicating which files to ignore.
+
+ follow_nonexisting -- Whether to descend into directories in
+ src that do not exit in dest. Default True.
+
+ follow_links -- Whether to descend into symlinks in src.
+
+ """
+ follow_nonexisting = kwargs.get('follow_nonexisting', True)
+ follow_links = kwargs.get('follow_link', False)
+
+ # Yield in pre or post order?
+ order = kwargs.get('order', 'pre')
+ if order not in ('pre', 'post'):
+ raise ValueError("Order must be 'pre' or 'post'.")
+
+ # List of relative paths to ignore under the src root.
+ ignore = kwargs.get('ignore', lambda filename: False)
+
+ # Don't descend into ignored directories
+ if ignore(rel_path):
+ return
+
+ source_path = os.path.join(source_root, rel_path)
+ dest_path = os.path.join(dest_root, rel_path)
+
+ # preorder yields directories before children
+ if order == 'pre':
+ yield (source_path, dest_path)
+
+ for f in os.listdir(source_path):
+ source_child = os.path.join(source_path, f)
+ dest_child = os.path.join(dest_path, f)
+ rel_child = os.path.join(rel_path, f)
+
+ # Treat as a directory
+ if os.path.isdir(source_child) and (
+ follow_links or not os.path.islink(source_child)):
+
+ # When follow_nonexisting isn't set, don't descend into dirs
+ # in source that do not exist in dest
+ if follow_nonexisting or os.path.exists(dest_child):
+ tuples = traverse_tree(source_root, dest_root, rel_child, **kwargs)
+ for t in tuples: yield t
+
+ # Treat as a file.
+ elif not ignore(os.path.join(rel_path, f)):
+ yield (source_child, dest_child)
+
+ if order == 'post':
+ yield (source_path, dest_path)
+
+
+
+class LinkTree(object):
+ """Class to create trees of symbolic links from a source directory.
+
+ LinkTree objects are constructed with a source root. Their
+ methods allow you to create and delete trees of symbolic links
+ back to the source tree in specific destination directories.
+ Trees comprise symlinks only to files; directries are never
+ symlinked to, to prevent the source directory from ever being
+ modified.
+
+ """
+ def __init__(self, source_root):
+ if not os.path.exists(source_root):
+ raise IOError("No such file or directory: '%s'", source_root)
+
+ self._root = source_root
+
+
+ def find_conflict(self, dest_root, **kwargs):
+ """Returns the first file in dest that conflicts with src"""
+ kwargs['follow_nonexisting'] = False
+ for src, dest in traverse_tree(self._root, dest_root, **kwargs):
+ if os.path.isdir(src):
+ if os.path.exists(dest) and not os.path.isdir(dest):
+ return dest
+ elif os.path.exists(dest):
+ return dest
+ return None
+
+
+ def merge(self, dest_root, **kwargs):
+ """Link all files in src into dest, creating directories if necessary."""
+ kwargs['order'] = 'pre'
+ for src, dest in traverse_tree(self._root, dest_root, **kwargs):
+ if os.path.isdir(src):
+ if not os.path.exists(dest):
+ mkdirp(dest)
+ continue
+
+ if not os.path.isdir(dest):
+ raise ValueError("File blocks directory: %s" % dest)
+
+ # mark empty directories so they aren't removed on unmerge.
+ if not os.listdir(dest):
+ marker = os.path.join(dest, empty_file_name)
+ touch(marker)
+
+ else:
+ assert(not os.path.exists(dest))
+ os.symlink(src, dest)
+
+
+ def unmerge(self, dest_root, **kwargs):
+ """Unlink all files in dest that exist in src.
+
+ Unlinks directories in dest if they are empty.
+
+ """
+ kwargs['order'] = 'post'
+ for src, dest in traverse_tree(self._root, dest_root, **kwargs):
+ if os.path.isdir(src):
+ if not os.path.isdir(dest):
+ raise ValueError("File blocks directory: %s" % dest)
+
+ # remove directory if it is empty.
+ if not os.listdir(dest):
+ shutil.rmtree(dest, ignore_errors=True)
+
+ # remove empty dir marker if present.
+ marker = os.path.join(dest, empty_file_name)
+ if os.path.exists(marker):
+ os.remove(marker)
+
+ elif os.path.exists(dest):
+ if not os.path.islink(dest):
+ raise ValueError("%s is not a link tree!" % dest)
+ os.remove(dest)
diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py
index 6697e00e40..6763411f7d 100644
--- a/lib/spack/spack/__init__.py
+++ b/lib/spack/spack/__init__.py
@@ -138,7 +138,7 @@ sys_type = None
# should live. This file is overloaded for spack core vs. for packages.
#
__all__ = ['Package', 'Version', 'when', 'ver']
-from spack.package import Package
+from spack.package import Package, ExtensionConflictError
from spack.version import Version, ver
from spack.multimethod import when
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py
index 537db536dd..b96ac5af51 100644
--- a/lib/spack/spack/cmd/__init__.py
+++ b/lib/spack/spack/cmd/__init__.py
@@ -121,3 +121,18 @@ def elide_list(line_list, max_num=10):
return line_list[:max_num-1] + ['...'] + line_list[-1:]
else:
return line_list
+
+
+def disambiguate_spec(spec):
+ matching_specs = spack.db.get_installed(spec)
+ if not matching_specs:
+ tty.die("Spec '%s' matches no installed packages." % spec)
+
+ elif len(matching_specs) > 1:
+ args = ["%s matches multiple packages." % spec,
+ "Matching packages:"]
+ args += [" " + str(s) for s in matching_specs]
+ args += ["Use a more specific spec."]
+ tty.die(*args)
+
+ return matching_specs[0]
diff --git a/lib/spack/spack/cmd/activate.py b/lib/spack/spack/cmd/activate.py
new file mode 100644
index 0000000000..c1e23852d6
--- /dev/null
+++ b/lib/spack/spack/cmd/activate.py
@@ -0,0 +1,50 @@
+##############################################################################
+# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+from external import argparse
+import llnl.util.tty as tty
+import spack
+import spack.cmd
+
+description = "Activate a package extension."
+
+def setup_parser(subparser):
+ subparser.add_argument(
+ 'spec', nargs=argparse.REMAINDER, help="spec of package extension to activate.")
+
+
+def activate(parser, args):
+ specs = spack.cmd.parse_specs(args.spec, concretize=True)
+ if len(specs) != 1:
+ tty.die("activate requires one spec. %d given." % len(specs))
+
+ # TODO: remove this hack when DAG info is stored in dir layout.
+ # This ensures the ext spec is always normalized properly.
+ spack.db.get(specs[0])
+
+ spec = spack.cmd.disambiguate_spec(specs[0])
+ if spec.package.activated:
+ tty.die("Package %s is already activated." % specs[0].short_spec)
+
+ spec.package.do_activate()
diff --git a/lib/spack/spack/cmd/deactivate.py b/lib/spack/spack/cmd/deactivate.py
new file mode 100644
index 0000000000..fd13f051df
--- /dev/null
+++ b/lib/spack/spack/cmd/deactivate.py
@@ -0,0 +1,50 @@
+##############################################################################
+# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+from external import argparse
+import llnl.util.tty as tty
+import spack
+import spack.cmd
+
+description = "Deactivate a package extension."
+
+def setup_parser(subparser):
+ subparser.add_argument(
+ 'spec', nargs=argparse.REMAINDER, help="spec of package extension to deactivate.")
+
+
+def deactivate(parser, args):
+ specs = spack.cmd.parse_specs(args.spec, concretize=True)
+ if len(specs) != 1:
+ tty.die("deactivate requires one spec. %d given." % len(specs))
+
+ # TODO: remove this hack when DAG info is stored in dir layout.
+ # This ensures the ext spec is always normalized properly.
+ spack.db.get(specs[0])
+
+ spec = spack.cmd.disambiguate_spec(specs[0])
+ if not spec.package.activated:
+ tty.die("Package %s is not activated." % specs[0].short_spec)
+
+ spec.package.do_deactivate()
diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py
new file mode 100644
index 0000000000..f6ccd7b515
--- /dev/null
+++ b/lib/spack/spack/cmd/extensions.py
@@ -0,0 +1,97 @@
+##############################################################################
+# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+import sys
+from external import argparse
+
+import llnl.util.tty as tty
+from llnl.util.tty.colify import colify
+
+import spack
+import spack.cmd
+import spack.cmd.find
+
+description = "List extensions for package."
+
+def setup_parser(subparser):
+ format_group = subparser.add_mutually_exclusive_group()
+ format_group.add_argument(
+ '-l', '--long', action='store_const', dest='mode', const='long',
+ help='Show dependency hashes as well as versions.')
+ format_group.add_argument(
+ '-p', '--paths', action='store_const', dest='mode', const='paths',
+ help='Show paths to extension install directories')
+ format_group.add_argument(
+ '-d', '--deps', action='store_const', dest='mode', const='deps',
+ help='Show full dependency DAG of extensions')
+
+ subparser.add_argument(
+ 'spec', nargs=argparse.REMAINDER, help='Spec of package to list extensions for')
+
+
+def extensions(parser, args):
+ if not args.spec:
+ tty.die("extensions requires a package spec.")
+
+ # Checks
+ spec = spack.cmd.parse_specs(args.spec)
+ if len(spec) > 1:
+ tty.die("Can only list extensions for one package.")
+
+ if not spec[0].package.extendable:
+ tty.die("%s is not an extendable package." % spec[0].name)
+
+ spec = spack.cmd.disambiguate_spec(spec[0])
+
+ if not spec.package.extendable:
+ tty.die("%s does not have extensions." % spec.short_spec)
+
+ if not args.mode:
+ args.mode = 'short'
+
+ # List package names of extensions
+ extensions = spack.db.extensions_for(spec)
+ if not extensions:
+ tty.msg("%s has no extensions." % spec.cshort_spec)
+ return
+ tty.msg("%s extensions:" % spec.cshort_spec)
+ colify(ext.name for ext in extensions)
+
+ # List specs of installed extensions.
+ installed = [s.spec for s in spack.db.installed_extensions_for(spec)]
+ print
+ if not installed:
+ tty.msg("None activated.")
+ return
+ tty.msg("%d installed:" % len(installed))
+ spack.cmd.find.display_specs(installed, mode=args.mode)
+
+ # List specs of activated extensions.
+ activated = spack.install_layout.get_extensions(spec)
+ print
+ if not activated:
+ tty.msg("None activated.")
+ return
+ tty.msg("%d currently activated:" % len(exts))
+ spack.cmd.find.display_specs(installed, mode=args.mode)
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
index 1de3413d42..f6f503afe5 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -41,13 +41,13 @@ description ="Find installed spack packages"
def setup_parser(subparser):
format_group = subparser.add_mutually_exclusive_group()
format_group.add_argument(
- '-l', '--long', action='store_true', dest='long',
+ '-l', '--long', action='store_const', dest='mode', const='long',
help='Show dependency hashes as well as versions.')
format_group.add_argument(
- '-p', '--paths', action='store_true', dest='paths',
+ '-p', '--paths', action='store_const', dest='mode', const='paths',
help='Show paths to package install directories')
format_group.add_argument(
- '-d', '--deps', action='store_true', dest='full_deps',
+ '-d', '--deps', action='store_const', dest='mode', const='deps',
help='Show full dependency DAG of installed packages')
subparser.add_argument(
@@ -55,26 +55,8 @@ def setup_parser(subparser):
help='optional specs to filter results')
-def find(parser, args):
- # Filter out specs that don't exist.
- query_specs = spack.cmd.parse_specs(args.query_specs)
- query_specs, nonexisting = partition_list(
- query_specs, lambda s: spack.db.exists(s.name))
-
- if nonexisting:
- msg = "No such package%s: " % ('s' if len(nonexisting) > 1 else '')
- msg += ", ".join(s.name for s in nonexisting)
- tty.msg(msg)
-
- if not query_specs:
- return
-
- # Get all the specs the user asked for
- if not query_specs:
- specs = set(spack.db.installed_package_specs())
- else:
- results = [set(spack.db.get_installed(qs)) for qs in query_specs]
- specs = set.union(*results)
+def display_specs(specs, **kwargs):
+ mode = kwargs.get('mode', 'short')
# Make a dict with specs keyed by architecture and compiler.
index = index_by(specs, ('architecture', 'compiler'))
@@ -92,7 +74,7 @@ def find(parser, args):
specs.sort()
abbreviated = [s.format('$_$@$+', color=True) for s in specs]
- if args.paths:
+ if mode == 'paths':
# Print one spec per line along with prefix path
width = max(len(s) for s in abbreviated)
width += 2
@@ -101,11 +83,44 @@ def find(parser, args):
for abbrv, spec in zip(abbreviated, specs):
print format % (abbrv, spec.prefix)
- elif args.full_deps:
+ elif mode == 'deps':
for spec in specs:
print spec.tree(indent=4, format='$_$@$+', color=True),
- else:
+
+ elif mode in ('short', 'long'):
fmt = '$-_$@$+'
- if args.long:
+ if mode == 'long':
fmt += '$#'
colify(s.format(fmt, color=True) for s in specs)
+
+ else:
+ raise ValueError(
+ "Invalid mode for display_specs: %s. Must be one of (paths, deps, short)." % mode)
+
+
+
+def find(parser, args):
+ # Filter out specs that don't exist.
+ query_specs = spack.cmd.parse_specs(args.query_specs)
+ query_specs, nonexisting = partition_list(
+ query_specs, lambda s: spack.db.exists(s.name))
+
+ if nonexisting:
+ msg = "No such package%s: " % ('s' if len(nonexisting) > 1 else '')
+ msg += ", ".join(s.name for s in nonexisting)
+ tty.msg(msg)
+
+ if not query_specs:
+ return
+
+ # Get all the specs the user asked for
+ if not query_specs:
+ specs = set(spack.db.installed_package_specs())
+ else:
+ results = [set(spack.db.get_installed(qs)) for qs in query_specs]
+ specs = set.union(*results)
+
+ if not args.mode:
+ args.mode = 'short'
+ display_specs(specs, mode=args.mode)
+
diff --git a/lib/spack/spack/cmd/location.py b/lib/spack/spack/cmd/location.py
index e422eaf966..709e894b7f 100644
--- a/lib/spack/spack/cmd/location.py
+++ b/lib/spack/spack/cmd/location.py
@@ -78,38 +78,30 @@ def location(parser, args):
tty.die("You must supply a spec.")
if len(specs) != 1:
tty.die("Too many specs. Supply only one.")
- spec = specs[0]
if args.install_dir:
# install_dir command matches against installed specs.
- matching_specs = spack.db.get_installed(spec)
- if not matching_specs:
- tty.die("Spec '%s' matches no installed packages." % spec)
+ spec = spack.cmd.disambiguate_spec(specs[0])
+ print spec.prefix
- elif len(matching_specs) > 1:
- tty.error("%s matches multiple packages:" % spec)
- for s in matching_specs:
- sys.stderr.write(s.tree(color=True))
- sys.stderr.write("\n")
- sys.stderr.write("Use a more specific spec.\n")
- sys.exit(1)
+ else:
+ spec = specs[0]
- print matching_specs[0].prefix
+ if args.package_dir:
+ # This one just needs the spec name.
+ print join_path(spack.db.root, spec.name)
- elif args.package_dir:
- # This one just needs the spec name.
- print join_path(spack.db.root, spec.name)
+ else:
+ # These versions need concretized specs.
+ spec.concretize()
+ pkg = spack.db.get(spec)
+
+ if args.stage_dir:
+ print pkg.stage.path
+
+ else: # args.build_dir is the default.
+ if not pkg.stage.source_path:
+ tty.die("Build directory does not exist yet. Run this to create it:",
+ "spack stage " + " ".join(args.spec))
+ print pkg.stage.source_path
- else:
- # These versions need concretized specs.
- spec.concretize()
- pkg = spack.db.get(spec)
-
- if args.stage_dir:
- print pkg.stage.path
-
- else: # args.build_dir is the default.
- if not pkg.stage.source_path:
- tty.die("Build directory does not exist yet. Run this to create it:",
- "spack stage " + " ".join(args.spec))
- print pkg.stage.source_path
diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py
index e787c460ad..0962942f43 100644
--- a/lib/spack/spack/cmd/uninstall.py
+++ b/lib/spack/spack/cmd/uninstall.py
@@ -65,7 +65,6 @@ def uninstall(parser, args):
" b) use a more specific spec."]
tty.die(*args)
-
if len(matching_specs) == 0:
tty.die("%s does not match any installed packages." % spec)
diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py
index 42cac0c9d2..efc40a17a4 100644
--- a/lib/spack/spack/directory_layout.py
+++ b/lib/spack/spack/directory_layout.py
@@ -53,6 +53,19 @@ class DirectoryLayout(object):
self.root = root
+ @property
+ def hidden_file_paths(self):
+ """Return a list of hidden files used by the directory layout.
+
+ Paths are relative to the root of an install directory.
+
+ If the directory layout uses no hidden files to maintain
+ state, this should return an empty container, e.g. [] or (,).
+
+ """
+ raise NotImplementedError()
+
+
def all_specs(self):
"""To be implemented by subclasses to traverse all specs for which there is
a directory within the root.
@@ -71,6 +84,21 @@ class DirectoryLayout(object):
raise NotImplementedError()
+ def get_extensions(self, spec):
+ """Get a set of currently installed extension packages for a spec."""
+ raise NotImplementedError()
+
+
+ def add_extension(self, spec, extension_spec):
+ """Add to the list of currently installed extensions."""
+ raise NotImplementedError()
+
+
+ def remove_extension(self, spec, extension_spec):
+ """Remove from the list of currently installed extensions."""
+ raise NotImplementedError()
+
+
def path_for_spec(self, spec):
"""Return an absolute path from the root to a directory for the spec."""
_check_concrete(spec)
@@ -134,9 +162,16 @@ class SpecHashDirectoryLayout(DirectoryLayout):
"""Prefix size is number of characters in the SHA-1 prefix to use
to make each hash unique.
"""
- spec_file_name = kwargs.get('spec_file_name', '.spec')
+ spec_file_name = kwargs.get('spec_file_name', '.spec')
+ extension_file_name = kwargs.get('extension_file_name', '.extensions')
super(SpecHashDirectoryLayout, self).__init__(root)
self.spec_file_name = spec_file_name
+ self.extension_file_name = extension_file_name
+
+
+ @property
+ def hidden_file_paths(self):
+ return ('.spec', '.extensions')
def relative_path_for_spec(self, spec):
@@ -225,6 +260,62 @@ class SpecHashDirectoryLayout(DirectoryLayout):
yield spec
+ def extension_file_path(self, spec):
+ """Gets full path to an installed package's extension file"""
+ _check_concrete(spec)
+ return join_path(self.path_for_spec(spec), self.extension_file_name)
+
+
+ def get_extensions(self, spec):
+ _check_concrete(spec)
+
+ extensions = set()
+ path = self.extension_file_path(spec)
+ if os.path.exists(path):
+ with closing(open(path)) as ext_file:
+ for line in ext_file:
+ try:
+ extensions.add(Spec(line.strip()))
+ except spack.error.SpackError, e:
+ raise InvalidExtensionSpecError(str(e))
+ return extensions
+
+
+ def write_extensions(self, spec, extensions):
+ path = self.extension_file_path(spec)
+ with closing(open(path, 'w')) as spec_file:
+ for extension in sorted(extensions):
+ spec_file.write("%s\n" % extension)
+
+
+ def add_extension(self, spec, extension_spec):
+ _check_concrete(spec)
+ _check_concrete(extension_spec)
+
+ exts = self.get_extensions(spec)
+ if extension_spec in exts:
+ raise ExtensionAlreadyInstalledError(spec, extension_spec)
+ else:
+ for already_installed in exts:
+ if spec.name == extension_spec.name:
+ raise ExtensionConflictError(spec, extension_spec, already_installed)
+
+ exts.add(extension_spec)
+ self.write_extensions(spec, exts)
+
+
+ def remove_extension(self, spec, extension_spec):
+ _check_concrete(spec)
+ _check_concrete(extension_spec)
+
+ exts = self.get_extensions(spec)
+ if not extension_spec in exts:
+ raise NoSuchExtensionError(spec, extension_spec)
+
+ exts.remove(extension_spec)
+ self.write_extensions(spec, exts)
+
+
class DirectoryLayoutError(SpackError):
"""Superclass for directory layout errors."""
def __init__(self, message):
@@ -250,3 +341,32 @@ class InstallDirectoryAlreadyExistsError(DirectoryLayoutError):
def __init__(self, path):
super(InstallDirectoryAlreadyExistsError, self).__init__(
"Install path %s already exists!")
+
+
+class InvalidExtensionSpecError(DirectoryLayoutError):
+ """Raised when an extension file has a bad spec in it."""
+ def __init__(self, message):
+ super(InvalidExtensionSpecError, self).__init__(message)
+
+
+class ExtensionAlreadyInstalledError(DirectoryLayoutError):
+ """Raised when an extension is added to a package that already has it."""
+ def __init__(self, spec, extension_spec):
+ super(ExtensionAlreadyInstalledError, self).__init__(
+ "%s is already installed in %s" % (extension_spec.short_spec, spec.short_spec))
+
+
+class ExtensionConflictError(DirectoryLayoutError):
+ """Raised when an extension is added to a package that already has it."""
+ def __init__(self, spec, extension_spec, conflict):
+ super(ExtensionConflictError, self).__init__(
+ "%s cannot be installed in %s because it conflicts with %s."% (
+ extension_spec.short_spec, spec.short_spec, conflict.short_spec))
+
+
+class NoSuchExtensionError(DirectoryLayoutError):
+ """Raised when an extension isn't there on remove."""
+ def __init__(self, spec, extension_spec):
+ super(NoSuchExtensionError, self).__init__(
+ "%s cannot be removed from %s because it's not installed."% (
+ extension_spec.short_spec, spec.short_spec))
diff --git a/lib/spack/spack/hooks/__init__.py b/lib/spack/spack/hooks/__init__.py
index 98b7f2323f..1c44e8abaa 100644
--- a/lib/spack/spack/hooks/__init__.py
+++ b/lib/spack/spack/hooks/__init__.py
@@ -31,7 +31,9 @@
Currently the following hooks are supported:
+ * pre_install()
* post_install()
+ * pre_uninstall()
* post_uninstall()
This can be used to implement support for things like module
@@ -70,5 +72,8 @@ class HookRunner(object):
#
# Define some functions that can be called to fire off hooks.
#
-post_install = HookRunner('post_install')
+pre_install = HookRunner('pre_install')
+post_install = HookRunner('post_install')
+
+pre_uninstall = HookRunner('pre_uninstall')
post_uninstall = HookRunner('post_uninstall')
diff --git a/lib/spack/spack/hooks/extensions.py b/lib/spack/spack/hooks/extensions.py
new file mode 100644
index 0000000000..718b24b965
--- /dev/null
+++ b/lib/spack/spack/hooks/extensions.py
@@ -0,0 +1,40 @@
+##############################################################################
+# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+
+import spack
+
+
+def post_install(pkg):
+ if pkg.is_extension:
+ pkg.do_activate()
+
+
+def pre_uninstall(pkg):
+ # Need to do this b/c uninstall does not automatically do it.
+ # TODO: store full graph info in stored .spec file.
+ pkg.spec.normalize()
+
+ if pkg.is_extension:
+ pkg.do_deactivate()
diff --git a/lib/spack/spack/mirror.py b/lib/spack/spack/mirror.py
index 929c514b61..114c7b6a35 100644
--- a/lib/spack/spack/mirror.py
+++ b/lib/spack/spack/mirror.py
@@ -46,7 +46,7 @@ from spack.util.compression import extension
def mirror_archive_filename(spec):
- """Get the path that this spec will live at within a mirror."""
+ """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.")
@@ -61,6 +61,11 @@ def mirror_archive_filename(spec):
return "%s-%s.%s" % (spec.package.name, spec.version, ext)
+def mirror_archive_path(spec):
+ """Get the relative path to the spec's archive within a mirror."""
+ return join_path(spec.name, mirror_archive_filename(spec))
+
+
def get_matching_versions(specs, **kwargs):
"""Get a spec for EACH known version matching any spec in the list."""
matching = []
@@ -141,12 +146,10 @@ def create(path, specs, **kwargs):
stage = None
try:
# create a subdirectory for the current package@version
- subdir = join_path(mirror_root, pkg.name)
+ archive_path = join_path(path, mirror_archive_path(spec))
+ subdir = os.path.dirname(archive_path)
mkdirp(subdir)
- archive_file = mirror_archive_filename(spec)
- archive_path = join_path(subdir, archive_file)
-
if os.path.exists(archive_path):
tty.msg("Already added %s" % spec.format("$_$@"))
present.append(spec)
diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py
index 755e9ea900..7d2ca97a62 100644
--- a/lib/spack/spack/modules.py
+++ b/lib/spack/spack/modules.py
@@ -49,6 +49,7 @@ import os
import re
import textwrap
import shutil
+from glob import glob
from contextlib import closing
import llnl.util.tty as tty
@@ -123,6 +124,13 @@ class EnvModule(object):
if os.path.isdir(directory):
add_path(var, directory)
+ # Add python path unless it's an actual python installation
+ # TODO: is there a better way to do this?
+ if self.spec.name != 'python':
+ site_packages = glob(join_path(self.spec.prefix.lib, "python*/site-packages"))
+ if site_packages:
+ add_path('PYTHONPATH', site_packages[0])
+
# short description is just the package + version
# TODO: maybe packages can optionally provide it.
self.short_description = self.spec.format("$_ $@")
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 1a797e88b1..b905968540 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -45,6 +45,7 @@ import textwrap
from StringIO import StringIO
import llnl.util.tty as tty
+from llnl.util.link_tree import LinkTree
from llnl.util.filesystem import *
from llnl.util.lang import *
@@ -320,12 +321,21 @@ class Package(object):
"""Patches to apply to newly expanded source, if any."""
patches = {}
+ """Specs of package this one extends, or None.
+
+ Currently, ppackages can extend at most one other package.
+ """
+ extendees = {}
+
#
# These are default values for instance variables.
#
"""By default we build in parallel. Subclasses can override this."""
parallel = True
+ """Most packages are NOT extendable. Set to True if you want extensions."""
+ extendable = False
+
def __init__(self, spec):
# this determines how the package should be built.
@@ -395,6 +405,9 @@ class Package(object):
self._fetch_time = 0.0
self._total_time = 0.0
+ if self.is_extension:
+ spack.db.get(self.extendee_spec)._check_extendable()
+
@property
def version(self):
@@ -459,7 +472,7 @@ class Package(object):
raise ValueError("Can only get a stage for a concrete package.")
if self._stage is None:
- mp = spack.mirror.mirror_archive_filename(self.spec)
+ mp = spack.mirror.mirror_archive_path(self.spec)
self._stage = Stage(
self.fetcher, mirror_path=mp, name=self.spec.short_spec)
return self._stage
@@ -481,6 +494,49 @@ class Package(object):
self._fetcher = f
+ @property
+ def extendee_spec(self):
+ """Spec of the extendee of this package, or None if it is not an extension."""
+ if not self.extendees:
+ return None
+ name = next(iter(self.extendees))
+ if not name in self.spec:
+ spec, kwargs = self.extendees[name]
+ return spec
+
+ # Need to do this to get the concrete version of the spec
+ return self.spec[name]
+
+
+ @property
+ def extendee_args(self):
+ """Spec of the extendee of this package, or None if it is not an extension."""
+ if not self.extendees:
+ return None
+ name = next(iter(self.extendees))
+ return self.extendees[name][1]
+
+
+ @property
+ def is_extension(self):
+ return len(self.extendees) > 0
+
+
+ def extends(self, spec):
+ return (spec.name in self.extendees and
+ spec.satisfies(self.extendees[spec.name][0]))
+
+
+ @property
+ def activated(self):
+ if not self.spec.concrete:
+ raise ValueError("Only concrete package extensions can be activated.")
+ if not self.is_extension:
+ raise ValueError("is_extension called on package that is not an extension.")
+
+ return self.spec in spack.install_layout.get_extensions(self.extendee_spec)
+
+
def preorder_traversal(self, visited=None, **kwargs):
"""This does a preorder traversal of the package's dependence DAG."""
virtual = kwargs.get("virtual", False)
@@ -713,6 +769,14 @@ class Package(object):
tty.msg("Patched %s" % self.name)
+ def do_fake_install(self):
+ """Make a fake install directory contaiing a 'fake' file in bin."""
+ mkdirp(self.prefix.bin)
+ touch(join_path(self.prefix.bin, 'fake'))
+ mkdirp(self.prefix.lib)
+ mkdirp(self.prefix.man1)
+
+
def do_install(self, **kwargs):
"""This class should call this version of the install method.
Package implementations should override install().
@@ -733,7 +797,7 @@ class Package(object):
tty.msg("Installing %s" % self.name)
if not ignore_deps:
- self.do_install_dependencies()
+ self.do_install_dependencies(**kwargs)
start_time = time.time()
if not fake_install:
@@ -757,23 +821,27 @@ class Package(object):
# package naming scheme it likes.
spack.install_layout.make_path_for_spec(self.spec)
+ # Run the pre-install hook in the child process after
+ # the directory is created.
+ spack.hooks.pre_install(self)
+
# Set up process's build environment before running install.
+ self.stage.chdir_to_source()
build_env.setup_package(self)
+ # Allow extendees to further set up the environment.
+ if self.is_extension:
+ self.extendee_spec.package.setup_extension_environment(
+ self.module, self.extendee_spec, self.spec)
+
if fake_install:
- mkdirp(self.prefix.bin)
- touch(join_path(self.prefix.bin, 'fake'))
- mkdirp(self.prefix.lib)
- mkdirp(self.prefix.man1)
+ self.do_fake_install()
else:
# Subclasses implement install() to do the real work.
self.install(self.spec, self.prefix)
# Ensure that something was actually installed.
- if not os.listdir(self.prefix):
- raise InstallError(
- "Install failed for %s. Nothing was installed!"
- % self.name)
+ self._sanity_check_install()
# On successful install, remove the stage.
if not keep_stage:
@@ -814,15 +882,23 @@ class Package(object):
if returncode != 0:
sys.exit(1)
-
# Once everything else is done, run post install hooks
spack.hooks.post_install(self)
- def do_install_dependencies(self):
+
+ def _sanity_check_install(self):
+ installed = set(os.listdir(self.prefix))
+ installed.difference_update(spack.install_layout.hidden_file_paths)
+ if not installed:
+ raise InstallError(
+ "Install failed for %s. Nothing was installed!" % self.name)
+
+
+ def do_install_dependencies(self, **kwargs):
# Pass along paths of dependencies here
for dep in self.spec.dependencies.values():
- dep.package.do_install()
+ dep.package.do_install(**kwargs)
@property
@@ -834,6 +910,30 @@ class Package(object):
fromlist=[self.__class__.__name__])
+ def setup_extension_environment(self, module, spec, ext_spec):
+ """Called before the install() method of extensions.
+
+ Default implementation does nothing, but this can be
+ overridden by an extendable package to set up the install
+ environment for its extensions. This is useful if there are
+ some common steps to installing all extensions for a
+ certain package.
+
+ Some examples:
+
+ 1. Installing python modules generally requires PYTHONPATH to
+ point to the lib/pythonX.Y/site-packages directory in the
+ module's install prefix. This could set that variable.
+
+ 2. Extensions often need to invoke the 'python' interpreter
+ from the Python installation being extended. This routine can
+ put a 'python' Execuable object in the module scope for the
+ extension package to simplify extension installs.
+
+ """
+ pass
+
+
def install(self, spec, prefix):
"""Package implementations override this with their own build configuration."""
raise InstallError("Package %s provides no install method!" % self.name)
@@ -853,6 +953,10 @@ class Package(object):
"The following installed packages depend on it: %s" %
' '.join(formatted_deps))
+ # Pre-uninstall hook runs first.
+ spack.hooks.pre_uninstall(self)
+
+ # Uninstalling in Spack only requires removing the prefix.
self.remove_prefix()
tty.msg("Successfully uninstalled %s." % self.spec.short_spec)
@@ -860,6 +964,88 @@ class Package(object):
spack.hooks.post_uninstall(self)
+ def _check_extendable(self):
+ if not self.extendable:
+ raise ValueError("Package %s is not extendable!" % self.name)
+
+
+ def _sanity_check_extension(self):
+ if not self.is_extension:
+ raise ValueError("This package is not an extension.")
+ extendee_package = self.extendee_spec.package
+ extendee_package._check_extendable()
+
+ if not extendee_package.installed:
+ raise ValueError("Can only (de)activate extensions for installed packages.")
+ if not self.installed:
+ raise ValueError("Extensions must first be installed.")
+ if not self.extendee_spec.name in self.extendees:
+ raise ValueError("%s does not extend %s!" % (self.name, self.extendee.name))
+
+
+ def do_activate(self):
+ """Called on an etension to invoke the extendee's activate method.
+
+ Commands should call this routine, and should not call
+ activate() directly.
+ """
+ self._sanity_check_extension()
+ self.extendee_spec.package.activate(self, **self.extendee_args)
+
+ spack.install_layout.add_extension(self.extendee_spec, self.spec)
+ tty.msg("Activated extension %s for %s."
+ % (self.spec.short_spec, self.extendee_spec.short_spec))
+
+
+ def activate(self, extension, **kwargs):
+ """Symlinks all files from the extension into extendee's install dir.
+
+ Package authors can override this method to support other
+ extension mechanisms. Spack internals (commands, hooks, etc.)
+ should call do_activate() method so that proper checks are
+ always executed.
+
+ """
+ def ignore(filename):
+ return (filename in spack.install_layout.hidden_file_paths or
+ kwargs.get('ignore', lambda f: False)(filename))
+
+ tree = LinkTree(extension.prefix)
+ conflict = tree.find_conflict(self.prefix, ignore=ignore)
+ if conflict:
+ raise ExtensionConflictError(conflict)
+ tree.merge(self.prefix, ignore=ignore)
+
+
+ def do_deactivate(self):
+ """Called on the extension to invoke extendee's deactivate() method."""
+ self._sanity_check_extension()
+ self.extendee_spec.package.deactivate(self, **self.extendee_args)
+
+ if self.spec in spack.install_layout.get_extensions(self.extendee_spec):
+ spack.install_layout.remove_extension(self.extendee_spec, self.spec)
+
+ tty.msg("Deactivated extension %s for %s."
+ % (self.spec.short_spec, self.extendee_spec.short_spec))
+
+
+ def deactivate(self, extension, **kwargs):
+ """Unlinks all files from extension out of this package's install dir.
+
+ Package authors can override this method to support other
+ extension mechanisms. Spack internals (commands, hooks, etc.)
+ should call do_deactivate() method so that proper checks are
+ always executed.
+
+ """
+ def ignore(filename):
+ return (filename in spack.install_layout.hidden_file_paths or
+ kwargs.get('ignore', lambda f: False)(filename))
+
+ tree = LinkTree(extension.prefix)
+ tree.unmerge(self.prefix, ignore=ignore)
+
+
def do_clean(self):
if self.stage.expanded_archive_path:
self.stage.chdir_to_source()
@@ -925,6 +1111,23 @@ class Package(object):
e.url, e.message)
+ @property
+ def rpath(self):
+ """Get the rpath this package links with, as a list of paths."""
+ rpaths = [self.prefix.lib, self.prefix.lib64]
+ rpaths.extend(d.prefix.lib for d in self.spec.traverse(root=False)
+ if os.path.isdir(d.prefix.lib))
+ rpaths.extend(d.prefix.lib64 for d in self.spec.traverse(root=False)
+ if os.path.isdir(d.prefix.lib64))
+ return rpaths
+
+
+ @property
+ def rpath_args(self):
+ """Get the rpath args as a string, with -Wl,-rpath= for each element."""
+ return " ".join("-Wl,-rpath=%s" % p for p in self.rpath)
+
+
def find_versions_of_archive(*archive_urls, **kwargs):
list_url = kwargs.get('list_url', None)
list_depth = kwargs.get('list_depth', 1)
@@ -1034,3 +1237,9 @@ class NoURLError(PackageError):
def __init__(self, cls):
super(NoURLError, self).__init__(
"Package %s has no version with a URL." % cls.__name__)
+
+
+class ExtensionConflictError(PackageError):
+ def __init__(self, path):
+ super(ExtensionConflictError, self).__init__(
+ "Extension blocked by file: %s" % path)
diff --git a/lib/spack/spack/packages.py b/lib/spack/spack/packages.py
index db43d3909a..7ef8135c1a 100644
--- a/lib/spack/spack/packages.py
+++ b/lib/spack/spack/packages.py
@@ -77,6 +77,8 @@ class PackageDB(object):
copy = spec.copy()
self.instances[copy] = package_class(copy)
except Exception, e:
+ if spack.debug:
+ sys.excepthook(*sys.exc_info())
raise FailedConstructorError(spec.name, e)
return self.instances[spec]
@@ -110,6 +112,17 @@ class PackageDB(object):
return providers
+ @_autospec
+ def extensions_for(self, extendee_spec):
+ return [p for p in self.all_packages() if p.extends(extendee_spec)]
+
+
+ @_autospec
+ def installed_extensions_for(self, extendee_spec):
+ return [s.package for s in self.installed_package_specs()
+ if s.package.extends(extendee_spec)]
+
+
def dirname_for_package_name(self, pkg_name):
"""Get the directory name for a particular package. This is the
directory that contains its package.py file."""
diff --git a/lib/spack/spack/relations.py b/lib/spack/spack/relations.py
index b1f4348945..a0c7723473 100644
--- a/lib/spack/spack/relations.py
+++ b/lib/spack/spack/relations.py
@@ -68,7 +68,7 @@ provides
spack install mpileaks ^mvapich
spack install mpileaks ^mpich
"""
-__all__ = [ 'depends_on', 'provides', 'patch', 'version' ]
+__all__ = [ 'depends_on', 'extends', 'provides', 'patch', 'version' ]
import re
import inspect
@@ -107,8 +107,9 @@ def depends_on(*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 = caller_locals().setdefault('dependencies', {})
for string in specs:
for spec in spack.spec.parse(string):
if pkg == spec.name:
@@ -116,6 +117,34 @@ def depends_on(*specs):
dependencies[spec.name] = spec
+def extends(spec, **kwargs):
+ """Same as depends_on, but dependency is symlinked into parent prefix.
+
+ This is for Python and other language modules where the module
+ needs to be installed into the prefix of the Python installation.
+ Spack handles this by installing modules into their own prefix,
+ but allowing ONE module version to be symlinked into a parent
+ Python install at a time.
+
+ keyword arguments can be passed to extends() so that extension
+ packages can pass parameters to the extendee's extension
+ mechanism.
+
+ """
+ pkg = get_calling_package_name()
+ clocals = caller_locals()
+ dependencies = clocals.setdefault('dependencies', {})
+ extendees = clocals.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)
+ dependencies[spec.name] = spec
+ extendees[spec.name] = (spec, kwargs)
+
+
def provides(*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
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 2f4fe9ca24..dffdccaddb 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -553,6 +553,13 @@ class Spec(object):
@property
+ def cshort_spec(self):
+ """Returns a version of the spec with the dependencies hashed
+ instead of completely enumerated."""
+ return self.format('$_$@$%@$+$=$#', color=True)
+
+
+ @property
def prefix(self):
return Prefix(spack.install_layout.path_for_spec(self))
diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py
index 0eda667abc..c53e6774fc 100644
--- a/lib/spack/spack/test/__init__.py
+++ b/lib/spack/spack/test/__init__.py
@@ -51,7 +51,8 @@ test_names = ['versions',
'hg_fetch',
'mirror',
'url_extrapolate',
- 'cc']
+ 'cc',
+ 'link_tree']
def list_tests():
diff --git a/lib/spack/spack/test/link_tree.py b/lib/spack/spack/test/link_tree.py
new file mode 100644
index 0000000000..bc7c2c6b5e
--- /dev/null
+++ b/lib/spack/spack/test/link_tree.py
@@ -0,0 +1,153 @@
+##############################################################################
+# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+import os
+import unittest
+import shutil
+import tempfile
+from contextlib import closing
+
+from llnl.util.filesystem import *
+from llnl.util.link_tree import LinkTree
+
+from spack.stage import Stage
+
+
+class LinkTreeTest(unittest.TestCase):
+ """Tests Spack's LinkTree class."""
+
+ def setUp(self):
+ self.stage = Stage('link-tree-test')
+
+ with working_dir(self.stage.path):
+ touchp('source/1')
+ touchp('source/a/b/2')
+ touchp('source/a/b/3')
+ touchp('source/c/4')
+ touchp('source/c/d/5')
+ touchp('source/c/d/6')
+ touchp('source/c/d/e/7')
+
+ source_path = os.path.join(self.stage.path, 'source')
+ self.link_tree = LinkTree(source_path)
+
+
+ def tearDown(self):
+ if self.stage:
+ self.stage.destroy()
+
+
+ def check_file_link(self, filename):
+ self.assertTrue(os.path.isfile(filename))
+ self.assertTrue(os.path.islink(filename))
+
+
+ def check_dir(self, filename):
+ self.assertTrue(os.path.isdir(filename))
+
+
+ def test_merge_to_new_directory(self):
+ with working_dir(self.stage.path):
+ self.link_tree.merge('dest')
+
+ self.check_file_link('dest/1')
+ self.check_file_link('dest/a/b/2')
+ self.check_file_link('dest/a/b/3')
+ self.check_file_link('dest/c/4')
+ self.check_file_link('dest/c/d/5')
+ self.check_file_link('dest/c/d/6')
+ self.check_file_link('dest/c/d/e/7')
+
+ self.link_tree.unmerge('dest')
+
+ self.assertFalse(os.path.exists('dest'))
+
+
+ def test_merge_to_existing_directory(self):
+ with working_dir(self.stage.path):
+
+ touchp('dest/x')
+ touchp('dest/a/b/y')
+
+ self.link_tree.merge('dest')
+
+ self.check_file_link('dest/1')
+ self.check_file_link('dest/a/b/2')
+ self.check_file_link('dest/a/b/3')
+ self.check_file_link('dest/c/4')
+ self.check_file_link('dest/c/d/5')
+ self.check_file_link('dest/c/d/6')
+ self.check_file_link('dest/c/d/e/7')
+
+ self.assertTrue(os.path.isfile('dest/x'))
+ self.assertTrue(os.path.isfile('dest/a/b/y'))
+
+ self.link_tree.unmerge('dest')
+
+ self.assertTrue(os.path.isfile('dest/x'))
+ self.assertTrue(os.path.isfile('dest/a/b/y'))
+
+ self.assertFalse(os.path.isfile('dest/1'))
+ self.assertFalse(os.path.isfile('dest/a/b/2'))
+ self.assertFalse(os.path.isfile('dest/a/b/3'))
+ self.assertFalse(os.path.isfile('dest/c/4'))
+ self.assertFalse(os.path.isfile('dest/c/d/5'))
+ self.assertFalse(os.path.isfile('dest/c/d/6'))
+ self.assertFalse(os.path.isfile('dest/c/d/e/7'))
+
+
+ def test_merge_with_empty_directories(self):
+ with working_dir(self.stage.path):
+ mkdirp('dest/f/g')
+ mkdirp('dest/a/b/h')
+
+ self.link_tree.merge('dest')
+ self.link_tree.unmerge('dest')
+
+ self.assertFalse(os.path.exists('dest/1'))
+ self.assertFalse(os.path.exists('dest/a/b/2'))
+ self.assertFalse(os.path.exists('dest/a/b/3'))
+ self.assertFalse(os.path.exists('dest/c/4'))
+ self.assertFalse(os.path.exists('dest/c/d/5'))
+ self.assertFalse(os.path.exists('dest/c/d/6'))
+ self.assertFalse(os.path.exists('dest/c/d/e/7'))
+
+ self.assertTrue(os.path.isdir('dest/a/b/h'))
+ self.assertTrue(os.path.isdir('dest/f/g'))
+
+
+ def test_ignore(self):
+ with working_dir(self.stage.path):
+ touchp('source/.spec')
+ touchp('dest/.spec')
+
+ self.link_tree.merge('dest', ignore=lambda x: x == '.spec')
+ self.link_tree.unmerge('dest', ignore=lambda x: x == '.spec')
+
+ self.assertFalse(os.path.exists('dest/1'))
+ self.assertFalse(os.path.exists('dest/a'))
+ self.assertFalse(os.path.exists('dest/c'))
+
+ self.assertTrue(os.path.isfile('source/.spec'))
+ self.assertTrue(os.path.isfile('dest/.spec'))
diff --git a/lib/spack/spack/test/mirror.py b/lib/spack/spack/test/mirror.py
index 51334198ec..89ab14359e 100644
--- a/lib/spack/spack/test/mirror.py
+++ b/lib/spack/spack/test/mirror.py
@@ -44,7 +44,7 @@ class MirrorTest(MockPackagesTest):
self.repos = {}
- def set_up_package(self, name, mock_repo_class, url_attr):
+ def set_up_package(self, name, MockRepoClass, url_attr):
"""Use this to set up a mock package to be mirrored.
Each package needs us to:
1. Set up a mock repo/archive to fetch from.
@@ -56,7 +56,7 @@ class MirrorTest(MockPackagesTest):
# Get the package and fix its fetch args to point to a mock repo
pkg = spack.db.get(spec)
- repo = mock_repo_class()
+ repo = MockRepoClass()
self.repos[name] = repo
# change the fetch args of the first (only) version.
@@ -71,7 +71,7 @@ class MirrorTest(MockPackagesTest):
for name, repo in self.repos.items():
if repo.stage:
- repo.stage.destroy()
+ pass #repo.stage.destroy()
self.repos.clear()
@@ -129,7 +129,7 @@ class MirrorTest(MockPackagesTest):
self.assertTrue(all(l in exclude for l in dcmp.left_only))
finally:
- stage.destroy()
+ pass #stage.destroy()
def test_git_mirror(self):
diff --git a/share/spack/setup-env.sh b/share/spack/setup-env.sh
index 91b1dc4630..b2bcbaf6c7 100755
--- a/share/spack/setup-env.sh
+++ b/share/spack/setup-env.sh
@@ -165,8 +165,8 @@ fi
#
# Set up modules and dotkit search paths in the user environment
#
-_sp_share_dir="$(dirname $_sp_source_file)"
-_sp_prefix="$(dirname $(dirname $_sp_share_dir))"
+_sp_share_dir=$(cd "$(dirname $_sp_source_file)" && pwd)
+_sp_prefix=$(cd "$(dirname $(dirname $_sp_share_dir))" && pwd)
# TODO: fix SYS_TYPE to something non-LLNL-specific
_spack_pathadd DK_NODE "$_sp_share_dir/dotkit/$SYS_TYPE"
diff --git a/var/spack/packages/bison/package.py b/var/spack/packages/bison/package.py
new file mode 100644
index 0000000000..7c526fb958
--- /dev/null
+++ b/var/spack/packages/bison/package.py
@@ -0,0 +1,17 @@
+from spack import *
+
+class Bison(Package):
+ """Bison is a general-purpose parser generator that converts
+ an annotated context-free grammar into a deterministic LR or
+ generalized LR (GLR) parser employing LALR(1) parser tables."""
+
+ homepage = "http://www.gnu.org/software/bison/"
+ url = "http://ftp.gnu.org/gnu/bison/bison-3.0.tar.gz"
+
+ version('3.0.4', 'a586e11cd4aff49c3ff6d3b6a4c9ccf8')
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/cloog/package.py b/var/spack/packages/cloog/package.py
new file mode 100644
index 0000000000..814a33c76c
--- /dev/null
+++ b/var/spack/packages/cloog/package.py
@@ -0,0 +1,26 @@
+from spack import *
+
+class Cloog(Package):
+ """CLooG is a free software and library to generate code for
+ scanning Z-polyhedra. That is, it finds a code (e.g. in C,
+ FORTRAN...) that reaches each integral point of one or more
+ parameterized polyhedra."""
+
+ homepage = "http://www.cloog.org"
+ url = "http://www.bastoul.net/cloog/pages/download/count.php3?url=./cloog-0.18.1.tar.gz"
+ list_url = "http://www.bastoul.net/cloog/pages/download"
+
+ version('0.18.1', 'e34fca0540d840e5d0f6427e98c92252')
+ version('0.18.0', 'be78a47bd82523250eb3e91646db5b3d')
+ version('0.17.0', '0aa3302c81f65ca62c114e5264f8a802')
+
+ depends_on("gmp")
+ depends_on("isl")
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix,
+ "--with-osl=no",
+ "--with-isl=%s" % spec['isl'].prefix,
+ "--with-gmp=%s" % spec['gmp'].prefix)
+ make()
+ make("install")
diff --git a/var/spack/packages/dri2proto/package.py b/var/spack/packages/dri2proto/package.py
new file mode 100644
index 0000000000..11dfa568e2
--- /dev/null
+++ b/var/spack/packages/dri2proto/package.py
@@ -0,0 +1,14 @@
+from spack import *
+
+class Dri2proto(Package):
+ """DRI2 Protocol Headers."""
+ homepage = "http://http://cgit.freedesktop.org/xorg/proto/dri2proto/"
+ url = "http://xorg.freedesktop.org/releases/individual/proto/dri2proto-2.8.tar.gz"
+
+ version('2.8', '19ea18f63d8ae8053c9fa84b60365b77')
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/flex/package.py b/var/spack/packages/flex/package.py
new file mode 100644
index 0000000000..b065904912
--- /dev/null
+++ b/var/spack/packages/flex/package.py
@@ -0,0 +1,15 @@
+from spack import *
+
+class Flex(Package):
+ """Flex is a tool for generating scanners."""
+
+ homepage = "http://flex.sourceforge.net/"
+ url = "http://download.sourceforge.net/flex/flex-2.5.39.tar.gz"
+
+ version('2.5.39', 'e133e9ead8ec0a58d81166b461244fde')
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/gcc/package.py b/var/spack/packages/gcc/package.py
index da0debd5dc..3da6c25d47 100644
--- a/var/spack/packages/gcc/package.py
+++ b/var/spack/packages/gcc/package.py
@@ -32,29 +32,46 @@ class Gcc(Package):
Objective-C, Fortran, and Java."""
homepage = "https://gcc.gnu.org"
+ url = "http://open-source-box.org/gcc/gcc-4.9.2/gcc-4.9.2.tar.bz2"
list_url = 'http://open-source-box.org/gcc/'
list_depth = 2
- version('4.9.2', '4df8ee253b7f3863ad0b86359cd39c43',
- url="http://open-source-box.org/gcc/gcc-4.9.2/gcc-4.9.2.tar.bz2")
- version('4.9.1', 'fddf71348546af523353bd43d34919c1',
- url="http://open-source-box.org/gcc/gcc-4.9.1/gcc-4.9.1.tar.bz2")
+ version('4.9.2', '4df8ee253b7f3863ad0b86359cd39c43')
+ version('4.9.1', 'fddf71348546af523353bd43d34919c1')
+ version('4.8.4', '5a84a30839b2aca22a2d723de2a626ec')
+ version('4.7.4', '4c696da46297de6ae77a82797d2abe28')
+ version('4.6.4', 'b407a3d1480c11667f293bfb1f17d1a4')
+ version('4.5.4', '27e459c2566b8209ab064570e1b378f7')
- depends_on("mpc")
depends_on("mpfr")
depends_on("gmp")
+ depends_on("mpc") # when @4.5:
depends_on("libelf")
+ # Save these until we can do optional deps.
+ #depends_on("isl")
+ #depends_on("ppl")
+ #depends_on("cloog")
def install(self, spec, prefix):
# libjava/configure needs a minor fix to install into spack paths.
filter_file(r"'@.*@'", "'@[[:alnum:]]*@'", 'libjava/configure', string=True)
+ enabled_languages = set(('c', 'c++', 'fortran', 'java', 'objc'))
+ if spec.satisfies("@4.7.1:"):
+ enabled_languages.add('go')
+
# Rest of install is straightforward.
configure("--prefix=%s" % prefix,
"--libdir=%s/lib64" % prefix,
"--disable-multilib",
- "--enable-languages=c,c++,fortran,java,objc,go",
+ "--enable-languages=" + ','.join(enabled_languages),
+ "--with-mpc=%s" % spec['mpc'].prefix,
+ "--with-mpfr=%s" % spec['mpfr'].prefix,
+ "--with-gmp=%s" % spec['gmp'].prefix,
+ "--with-libelf=%s" % spec['libelf'].prefix,
+ "--with-stage1-ldflags=%s" % self.rpath_args,
+ "--with-boot-ldflags=%s" % self.rpath_args,
"--enable-lto",
"--with-quad")
make()
diff --git a/var/spack/packages/hdf5/package.py b/var/spack/packages/hdf5/package.py
index 615c2a7fe4..992dd8ec70 100644
--- a/var/spack/packages/hdf5/package.py
+++ b/var/spack/packages/hdf5/package.py
@@ -18,12 +18,14 @@ class Hdf5(Package):
# TODO: currently hard-coded to use OpenMPI
def install(self, spec, prefix):
+
configure(
"--prefix=%s" % prefix,
"--with-zlib=%s" % spec['zlib'].prefix,
"--enable-parallel",
- "CC=%s" % spec['openmpi'].prefix.bin + "/mpicc",
- "CXX=%s" % spec['openmpi'].prefix.bin + "/mpic++")
+ "--enable-shared",
+ "CC=%s" % spec['mpich'].prefix.bin + "/mpicc",
+ "CXX=%s" % spec['mpich'].prefix.bin + "/mpic++")
make()
make("install")
diff --git a/var/spack/packages/icu4c/package.py b/var/spack/packages/icu4c/package.py
new file mode 100644
index 0000000000..55b44463b2
--- /dev/null
+++ b/var/spack/packages/icu4c/package.py
@@ -0,0 +1,17 @@
+from spack import *
+
+class Icu4c(Package):
+ """ICU is a mature, widely used set of C/C++ and Java libraries
+ providing Unicode and Globalization support for software applications."""
+
+ homepage = "http://site.icu-project.org/"
+ url = "http://downloads.sourceforge.net/project/icu/ICU4C/54.1/icu4c-54_1-src.tgz"
+
+ version('54_1', 'e844caed8f2ca24c088505b0d6271bc0')
+
+ def install(self, spec, prefix):
+ cd("source")
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/isl/package.py b/var/spack/packages/isl/package.py
new file mode 100644
index 0000000000..836ef3ea40
--- /dev/null
+++ b/var/spack/packages/isl/package.py
@@ -0,0 +1,17 @@
+from spack import *
+
+class Isl(Package):
+ """isl is a thread-safe C library for manipulating sets and
+ relations of integer points bounded by affine constraints."""
+ homepage = "http://isl.gforge.inria.fr"
+ url = "http://isl.gforge.inria.fr/isl-0.14.tar.bz2"
+
+ version('0.14', 'acd347243fca5609e3df37dba47fd0bb')
+
+ depends_on("gmp")
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix,
+ "--with-gmp-prefix=%s" % spec['gmp'].prefix)
+ make()
+ make("install")
diff --git a/var/spack/packages/libdrm/package.py b/var/spack/packages/libdrm/package.py
new file mode 100644
index 0000000000..00736b7811
--- /dev/null
+++ b/var/spack/packages/libdrm/package.py
@@ -0,0 +1,18 @@
+from spack import *
+
+class Libdrm(Package):
+ """A userspace library for accessing the DRM, direct
+ rendering manager, on Linux, BSD and other operating
+ systems that support the ioctl interface."""
+
+ homepage = "http://dri.freedesktop.org/libdrm/" # no real website...
+ url = "http://dri.freedesktop.org/libdrm/libdrm-2.4.59.tar.gz"
+
+ version('2.4.59', '105ac7af1afcd742d402ca7b4eb168b6')
+ version('2.4.33', '86e4e3debe7087d5404461e0032231c8')
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/libxcb/package.py b/var/spack/packages/libxcb/package.py
new file mode 100644
index 0000000000..521cd0d475
--- /dev/null
+++ b/var/spack/packages/libxcb/package.py
@@ -0,0 +1,21 @@
+from spack import *
+
+class Libxcb(Package):
+ """The X protocol C-language Binding (XCB) is a replacement
+ for Xlib featuring a small footprint, latency hiding, direct
+ access to the protocol, improved threading support, and
+ extensibility."""
+
+ homepage = "http://xcb.freedesktop.org/"
+ url = "http://xcb.freedesktop.org/dist/libxcb-1.11.tar.gz"
+
+ version('1.11', '1698dd837d7e6e94d029dbe8b3a82deb')
+
+ depends_on("python")
+ depends_on("xcb-proto")
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/libxshmfence/package.py b/var/spack/packages/libxshmfence/package.py
new file mode 100644
index 0000000000..3aa2448b46
--- /dev/null
+++ b/var/spack/packages/libxshmfence/package.py
@@ -0,0 +1,16 @@
+from spack import *
+
+class Libxshmfence(Package):
+ """This is a tiny library that exposes a event API on top of Linux
+ futexes."""
+
+ homepage = "http://keithp.com/blogs/dri3_extension/" # not really...
+ url = "http://xorg.freedesktop.org/archive/individual/lib/libxshmfence-1.2.tar.gz"
+
+ version('1.2', 'f0b30c0fc568b22ec524859ee28556f1')
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/llvm/package.py b/var/spack/packages/llvm/package.py
index c7a10df55a..69354a5c90 100644
--- a/var/spack/packages/llvm/package.py
+++ b/var/spack/packages/llvm/package.py
@@ -35,6 +35,12 @@ class Llvm(Package):
url = "http://llvm.org/releases/3.4.2/llvm-3.4.2.src.tar.gz"
version('3.4.2', 'a20669f75967440de949ac3b1bad439c')
+ version('3.0', 'a8e5f5f1c1adebae7b4a654c376a6005',
+ url='http://llvm.org/releases/3.0/llvm-3.0.tar.gz')
+ version('2.9', '793138412d2af2c7c7f54615f8943771',
+ url='http://llvm.org/releases/2.9/llvm-2.9.tgz')
+ version('2.8', '220d361b4d17051ff4bb21c64abe05ba',
+ url='http://llvm.org/releases/2.8/llvm-2.8.tgz')
def install(self, spec, prefix):
env['CXXFLAGS'] = self.compiler.cxx11_flag
diff --git a/var/spack/packages/mesa/package.py b/var/spack/packages/mesa/package.py
new file mode 100644
index 0000000000..2dba878a77
--- /dev/null
+++ b/var/spack/packages/mesa/package.py
@@ -0,0 +1,33 @@
+from spack import *
+
+class Mesa(Package):
+ """Mesa is an open-source implementation of the OpenGL
+ specification - a system for rendering interactive 3D graphics."""
+
+ homepage = "http://www.mesa3d.org"
+ url = "ftp://ftp.freedesktop.org/pub/mesa/older-versions/8.x/8.0.5/MesaLib-8.0.5.tar.gz"
+ # url = "ftp://ftp.freedesktop.org/pub/mesa/10.4.4/MesaLib-10.4.4.tar.gz"
+
+ # version('10.4.4', '8d863a3c209bf5116b2babfccccc68ce')
+ version('8.0.5', 'cda5d101f43b8784fa60bdeaca4056f2')
+
+ # mesa 7.x, 8.x, 9.x
+ depends_on("libdrm@2.4.33")
+ depends_on("llvm@3.0")
+
+ # patch("llvm-fixes.patch") # using newer llvm
+
+ # mesa 10.x
+ # depends_on("py-mako")
+ # depends_on("flex")
+ # depends_on("bison")
+ # depends_on("dri2proto")
+ # depends_on("libxcb")
+ # depends_on("libxshmfence")
+
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/ppl/package.py b/var/spack/packages/ppl/package.py
new file mode 100644
index 0000000000..018d5c523d
--- /dev/null
+++ b/var/spack/packages/ppl/package.py
@@ -0,0 +1,28 @@
+from spack import *
+
+class Ppl(Package):
+ """The Parma Polyhedra Library (PPL) provides numerical
+ abstractions especially targeted at applications in the field of
+ analysis and verification of complex systems. These abstractions
+ include convex polyhedra, some special classes of polyhedra shapes
+ that offer interesting complexity/precision tradeoffs, and grids
+ which represent regularly spaced points that satisfy a set of
+ linear congruence relations. The library also supports finite
+ powersets and products of polyhedra and grids, a mixed integer
+ linear programming problem solver using an exact-arithmetic
+ version of the simplex algorithm, a parametric integer programming
+ solver, and primitives for termination analysis via the automatic
+ synthesis of linear ranking functions."""
+
+ homepage = "http://bugseng.com/products/ppl/"
+ url = "http://bugseng.com/products/ppl/download/ftp/releases/1.1/ppl-1.1.tar.gz"
+
+ version('1.1', '4f2422c0ef3f409707af32108deb30a7')
+
+ depends_on("gmp")
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix,
+ "--with-gmp=%s" % spec['gmp'].prefix)
+ make()
+ make("install")
diff --git a/var/spack/packages/py-basemap/package.py b/var/spack/packages/py-basemap/package.py
new file mode 100644
index 0000000000..7b6d8e7e65
--- /dev/null
+++ b/var/spack/packages/py-basemap/package.py
@@ -0,0 +1,25 @@
+from spack import *
+import os
+
+class PyBasemap(Package):
+ """The matplotlib basemap toolkit is a library for plotting 2D data on maps in Python."""
+ homepage = "http://matplotlib.org/basemap/"
+ url = "https://downloads.sourceforge.net/project/matplotlib/matplotlib-toolkits/basemap-1.0.7/basemap-1.0.7.tar.gz"
+
+ version('1.0.7', '48c0557ced9e2c6e440b28b3caff2de8')
+
+ geos_version = {'1.0.7' : '3.3.3'}
+
+ extends('python')
+ depends_on('py-setuptools')
+ depends_on('py-numpy')
+ depends_on('py-matplotlib')
+ depends_on('py-pil')
+
+ def install(self, spec, prefix):
+ with working_dir('geos-%s' % self.geos_version[str(self.version)]):
+ configure("--prefix=" + prefix)
+ make()
+ make("install")
+ os.environ['GEOS_DIR'] = prefix
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-biopython/package.py b/var/spack/packages/py-biopython/package.py
new file mode 100644
index 0000000000..2ed04c389e
--- /dev/null
+++ b/var/spack/packages/py-biopython/package.py
@@ -0,0 +1,14 @@
+from spack import *
+
+class PyBiopython(Package):
+ """It is a distributed collaborative effort to develop Python libraries and applications which address the needs of current and future work in bioinformatics."""
+ homepage = "http://biopython.org/wiki/Main_Page"
+ url = "http://biopython.org/DIST/biopython-1.65.tar.gz"
+
+ version('1.65', '143e7861ade85c0a8b5e2bbdd1da1f67')
+
+ extends('python')
+ depends_on('py-mx')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-cython/package.py b/var/spack/packages/py-cython/package.py
new file mode 100644
index 0000000000..af67a15526
--- /dev/null
+++ b/var/spack/packages/py-cython/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyCython(Package):
+ """The Cython compiler for writing C extensions for the Python language."""
+ homepage = "https://pypi.python.org/pypi/cython"
+ url = "https://pypi.python.org/packages/source/C/Cython/Cython-0.21.2.tar.gz"
+
+ version('0.21.2', 'd21adb870c75680dc857cd05d41046a4')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-dateutil/package.py b/var/spack/packages/py-dateutil/package.py
new file mode 100644
index 0000000000..11699e07ee
--- /dev/null
+++ b/var/spack/packages/py-dateutil/package.py
@@ -0,0 +1,14 @@
+from spack import *
+
+class PyDateutil(Package):
+ """Extensions to the standard Python datetime module."""
+ homepage = "https://pypi.python.org/pypi/dateutil"
+ url = "https://pypi.python.org/packages/source/p/python-dateutil/python-dateutil-2.4.0.tar.gz"
+
+ version('2.4.0', '75714163bb96bedd07685cdb2071b8bc')
+
+ extends('python')
+ depends_on('py-setuptools')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-epydoc/package.py b/var/spack/packages/py-epydoc/package.py
new file mode 100644
index 0000000000..af05510504
--- /dev/null
+++ b/var/spack/packages/py-epydoc/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyEpydoc(Package):
+ """Epydoc is a tool for generating API documentation documentation for Python modules, based on their docstrings."""
+ homepage = "https://pypi.python.org/pypi/epydoc"
+ url = "https://pypi.python.org/packages/source/e/epydoc/epydoc-3.0.1.tar.gz"
+
+ version('3.0.1', '36407974bd5da2af00bf90ca27feeb44')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-gnuplot/package.py b/var/spack/packages/py-gnuplot/package.py
new file mode 100644
index 0000000000..0a2c073a49
--- /dev/null
+++ b/var/spack/packages/py-gnuplot/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyGnuplot(Package):
+ """Gnuplot.py is a Python package that allows you to create graphs from within Python using the gnuplot plotting program."""
+ homepage = "http://gnuplot-py.sourceforge.net/"
+ url = "http://downloads.sourceforge.net/project/gnuplot-py/Gnuplot-py/1.8/gnuplot-py-1.8.tar.gz"
+
+ version('1.8', 'abd6f571e7aec68ae7db90a5217cd5b1')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-h5py/package.py b/var/spack/packages/py-h5py/package.py
new file mode 100644
index 0000000000..f72b3ac06e
--- /dev/null
+++ b/var/spack/packages/py-h5py/package.py
@@ -0,0 +1,18 @@
+from spack import *
+import re
+
+class PyH5py(Package):
+ """The h5py package provides both a high- and low-level interface to the HDF5 library from Python."""
+ homepage = "https://pypi.python.org/pypi/h5py"
+ url = "https://pypi.python.org/packages/source/h/h5py/h5py-2.4.0.tar.gz"
+
+ version('2.4.0', '80c9a94ae31f84885cc2ebe1323d6758')
+
+ extends('python', ignore=lambda f: re.match(r'cy*', f))
+ depends_on('hdf5')
+ depends_on('py-numpy')
+ depends_on('py-cython')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'configure', '--hdf5=%s' % spec['hdf5'].prefix)
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-ipython/package.py b/var/spack/packages/py-ipython/package.py
new file mode 100644
index 0000000000..731e661dfd
--- /dev/null
+++ b/var/spack/packages/py-ipython/package.py
@@ -0,0 +1,14 @@
+from spack import *
+
+class PyIpython(Package):
+ """IPython provides a rich toolkit to help you make the most out of using Python interactively."""
+ homepage = "https://pypi.python.org/pypi/ipython"
+ url = "https://pypi.python.org/packages/source/i/ipython/ipython-2.3.1.tar.gz"
+
+ version('2.3.1', '2b7085525dac11190bfb45bb8ec8dcbf')
+
+ extends('python')
+ depends_on('py-pygments')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-libxml2/package.py b/var/spack/packages/py-libxml2/package.py
new file mode 100644
index 0000000000..0dcefbd9cf
--- /dev/null
+++ b/var/spack/packages/py-libxml2/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyLibxml2(Package):
+ """A Python wrapper around libxml2."""
+ homepage = "https://xmlsoft.org/python.html"
+ url = "ftp://xmlsoft.org/libxml2/python/libxml2-python-2.6.21.tar.gz"
+
+ version('2.6.21', '229dd2b3d110a77defeeaa73af83f7f3')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-mako/package.py b/var/spack/packages/py-mako/package.py
new file mode 100644
index 0000000000..3e91ffd8e5
--- /dev/null
+++ b/var/spack/packages/py-mako/package.py
@@ -0,0 +1,16 @@
+from spack import *
+
+class PyMako(Package):
+ """A super-fast templating language that borrows the best
+ ideas from the existing templating languages."""
+
+ homepage = "https://pypi.python.org/pypi/mako"
+ url = "https://pypi.python.org/packages/source/M/Mako/Mako-1.0.1.tar.gz"
+
+ version('1.0.1', '9f0aafd177b039ef67b90ea350497a54')
+
+ depends_on('py-setuptools')
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-matplotlib/package.py b/var/spack/packages/py-matplotlib/package.py
new file mode 100644
index 0000000000..5979ceeab0
--- /dev/null
+++ b/var/spack/packages/py-matplotlib/package.py
@@ -0,0 +1,38 @@
+from spack import *
+import os
+
+class PyMatplotlib(Package):
+ """Python plotting package."""
+ homepage = "https://pypi.python.org/pypi/matplotlib"
+ url = "https://pypi.python.org/packages/source/m/matplotlib/matplotlib-1.4.2.tar.gz"
+
+ version('1.4.2', '7d22efb6cce475025733c50487bd8898')
+
+ extends('python')
+ depends_on('py-pyside')
+ depends_on('py-ipython')
+ depends_on('py-pyparsing')
+ depends_on('py-six')
+ depends_on('py-dateutil')
+ depends_on('py-pytz')
+ depends_on('py-nose')
+ depends_on('py-numpy')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
+ if str(self.version) == '1.4.2':
+ # hack to fix configuration file
+ config_file = None
+ for p,d,f in os.walk(prefix.lib):
+ for file in f:
+ if file.find('matplotlibrc') != -1:
+ config_file = join_path(p, 'matplotlibrc')
+ print config_file
+ if config_file == None:
+ raise InstallError('could not find config file')
+ filter_file(r'backend : pyside',
+ 'backend : Qt4Agg',
+ config_file)
+ filter_file(r'#backend.qt4 : PyQt4',
+ 'backend.qt4 : PySide',
+ config_file)
diff --git a/var/spack/packages/py-mpi4py/package.py b/var/spack/packages/py-mpi4py/package.py
new file mode 100644
index 0000000000..fdea340dc2
--- /dev/null
+++ b/var/spack/packages/py-mpi4py/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyMpi4py(Package):
+ """This package provides Python bindings for the Message Passing Interface (MPI) standard. It is implemented on top of the MPI-1/MPI-2 specification and exposes an API which grounds on the standard MPI-2 C++ bindings."""
+ homepage = "https://pypi.python.org/pypi/mpi4py"
+ url = "https://pypi.python.org/packages/source/m/mpi4py/mpi4py-1.3.1.tar.gz"
+
+ version('1.3.1', 'dbe9d22bdc8ed965c23a7ceb6f32fc3c')
+ extends('python')
+ depends_on('mpi')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-mx/package.py b/var/spack/packages/py-mx/package.py
new file mode 100644
index 0000000000..717ee0562b
--- /dev/null
+++ b/var/spack/packages/py-mx/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyMx(Package):
+ """The eGenix.com mx Base Distribution for Python is a collection of professional quality software tools which enhance Python's usability in many important areas such as fast text searching, date/time processing and high speed data types."""
+ homepage = "http://www.egenix.com/products/python/mxBase/"
+ url = "https://downloads.egenix.com/python/egenix-mx-base-3.2.8.tar.gz"
+
+ version('3.2.8', '9d9d3a25f9dc051a15e97f452413423b')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-nose/package.py b/var/spack/packages/py-nose/package.py
new file mode 100644
index 0000000000..6df84e831d
--- /dev/null
+++ b/var/spack/packages/py-nose/package.py
@@ -0,0 +1,15 @@
+from spack import *
+
+class PyNose(Package):
+ """nose extends the test loading and running features of unittest,
+ making it easier to write, find and run tests."""
+
+ homepage = "https://pypi.python.org/pypi/nose"
+ url = "https://pypi.python.org/packages/source/n/nose/nose-1.3.4.tar.gz"
+
+ version('1.3.4', '6ed7169887580ddc9a8e16048d38274d')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-numpy/package.py b/var/spack/packages/py-numpy/package.py
new file mode 100644
index 0000000000..e6cb6a464f
--- /dev/null
+++ b/var/spack/packages/py-numpy/package.py
@@ -0,0 +1,14 @@
+from spack import *
+
+class PyNumpy(Package):
+ """array processing for numbers, strings, records, and objects."""
+ homepage = "https://pypi.python.org/pypi/numpy"
+ url = "https://pypi.python.org/packages/source/n/numpy/numpy-1.9.1.tar.gz"
+
+ version('1.9.1', '78842b73560ec378142665e712ae4ad9')
+
+ extends('python')
+ depends_on('py-nose')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-pexpect/package.py b/var/spack/packages/py-pexpect/package.py
new file mode 100644
index 0000000000..ff5fac84e0
--- /dev/null
+++ b/var/spack/packages/py-pexpect/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyPexpect(Package):
+ """Pexpect allows easy control of interactive console applications."""
+ homepage = "https://pypi.python.org/pypi/pexpect"
+ url = "https://pypi.python.org/packages/source/p/pexpect/pexpect-3.3.tar.gz"
+
+ version('3.3', '0de72541d3f1374b795472fed841dce8')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-pil/package.py b/var/spack/packages/py-pil/package.py
new file mode 100644
index 0000000000..743b761981
--- /dev/null
+++ b/var/spack/packages/py-pil/package.py
@@ -0,0 +1,14 @@
+from spack import *
+
+class PyPil(Package):
+ """The Python Imaging Library (PIL) adds image processing capabilities to your Python interpreter. This library supports many file formats, and provides powerful image processing and graphics capabilities."""
+
+ homepage = "http://www.pythonware.com/products/pil/"
+ url = "http://effbot.org/media/downloads/Imaging-1.1.7.tar.gz"
+
+ version('1.1.7', 'fc14a54e1ce02a0225be8854bfba478e')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-pmw/package.py b/var/spack/packages/py-pmw/package.py
new file mode 100644
index 0000000000..56131811e9
--- /dev/null
+++ b/var/spack/packages/py-pmw/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyPmw(Package):
+ """Pmw is a toolkit for building high-level compound widgets, or megawidgets, constructed using other widgets as component parts."""
+ homepage = "https://pypi.python.org/pypi/Pmw"
+ url = "https://pypi.python.org/packages/source/P/Pmw/Pmw-2.0.0.tar.gz"
+
+ version('2.0.0', 'c7c3f26c4f5abaa99807edefee578fc0')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-pychecker/package.py b/var/spack/packages/py-pychecker/package.py
new file mode 100644
index 0000000000..bda5a746aa
--- /dev/null
+++ b/var/spack/packages/py-pychecker/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyPychecker(Package):
+ """"""
+ homepage = "http://pychecker.sourceforge.net/"
+ url = "http://sourceforge.net/projects/pychecker/files/pychecker/0.8.19/pychecker-0.8.19.tar.gz"
+
+ version('0.8.19', 'c37182863dfb09209d6ba4f38fce9d2b')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-pygments/package.py b/var/spack/packages/py-pygments/package.py
new file mode 100644
index 0000000000..990eebde65
--- /dev/null
+++ b/var/spack/packages/py-pygments/package.py
@@ -0,0 +1,14 @@
+from spack import *
+
+class PyPygments(Package):
+ """Pygments is a syntax highlighting package written in Python."""
+ homepage = "https://pypi.python.org/pypi/pygments"
+ url = "https://pypi.python.org/packages/source/P/Pygments/Pygments-2.0.1.tar.gz"
+
+ version('2.0.1', 'e0daf4c14a4fe5b630da765904de4d6c')
+
+ extends('python')
+ depends_on('py-setuptools')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-pylint/package.py b/var/spack/packages/py-pylint/package.py
new file mode 100644
index 0000000000..ebde861f94
--- /dev/null
+++ b/var/spack/packages/py-pylint/package.py
@@ -0,0 +1,16 @@
+from spack import *
+import re
+
+class PyPylint(Package):
+ """array processing for numbers, strings, records, and objects."""
+ homepage = "https://pypi.python.org/pypi/pylint"
+ url = "https://pypi.python.org/packages/source/p/pylint/pylint-1.4.1.tar.gz"
+
+ version('1.4.1', 'df7c679bdcce5019389038847e4de622')
+
+# extends('python')
+ extends('python', ignore=lambda f:re.match(r"site.py*", f))
+ depends_on('py-nose')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-pyparsing/package.py b/var/spack/packages/py-pyparsing/package.py
new file mode 100644
index 0000000000..a6e50ad139
--- /dev/null
+++ b/var/spack/packages/py-pyparsing/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyPyparsing(Package):
+ """A Python Parsing Module."""
+ homepage = "https://pypi.python.org/pypi/pyparsing"
+ url = "https://pypi.python.org/packages/source/p/pyparsing/pyparsing-2.0.3.tar.gz"
+
+ version('2.0.3', '0fe479be09fc2cf005f753d3acc35939')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-pyqt4/package.py b/var/spack/packages/py-pyqt4/package.py
new file mode 100644
index 0000000000..eeb1382560
--- /dev/null
+++ b/var/spack/packages/py-pyqt4/package.py
@@ -0,0 +1,18 @@
+from spack import *
+
+class PyPyqt4(Package):
+ """PyQt is a set of Python v2 and v3 bindings for Digia's Qt application framework and runs on all platforms supported by Qt including Windows, MacOS/X and Linux."""
+ homepage = "http://www.riverbankcomputing.com/software/pyqt/intro"
+ url = "http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.3/PyQt-x11-gpl-4.11.3.tar.gz"
+
+ version('4.11.3', '997c3e443165a89a559e0d96b061bf70')
+
+ extends('python')
+ depends_on('qt')
+ depends_on('py-sip')
+
+ def install(self, spec, prefix):
+ version_array = str(spec['python'].version).split('.')
+ python('configure.py', '--confirm-license', '--destdir=%s/python%s.%s/site-packages' %(self.prefix.lib, version_array[0], version_array[1]))
+ make()
+ make('install')
diff --git a/var/spack/packages/py-pyside/package.py b/var/spack/packages/py-pyside/package.py
new file mode 100644
index 0000000000..b01e16d7e6
--- /dev/null
+++ b/var/spack/packages/py-pyside/package.py
@@ -0,0 +1,18 @@
+from spack import *
+import spack.package
+import os
+
+class PyPyside(Package):
+ """array processing for numbers, strings, records, and objects."""
+ homepage = "https://pypi.python.org/pypi/pyside"
+ url = "https://pypi.python.org/packages/source/P/PySide/PySide-1.2.2.tar.gz"
+
+ version('1.2.2', 'c45bc400c8a86d6b35f34c29e379e44d')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ qmake_path = '/usr/lib64/qt4/bin/qmake'
+ if not os.path.exists(qmake_path):
+ raise spack.package.InstallError("Failed to find qmake in %s" % qmake_path)
+ python('setup.py', 'install', '--prefix=%s' % prefix, '--qmake=%s' % qmake_path)
diff --git a/var/spack/packages/py-pytz/package.py b/var/spack/packages/py-pytz/package.py
new file mode 100644
index 0000000000..80bcfe82ca
--- /dev/null
+++ b/var/spack/packages/py-pytz/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyPytz(Package):
+ """World timezone definitions, modern and historical."""
+ homepage = "https://pypi.python.org/pypi/pytz"
+ url = "https://pypi.python.org/packages/source/p/pytz/pytz-2014.10.tar.gz"
+
+ version('2014.10', 'eb1cb941a20c5b751352c52486aa1dd7')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-rpy2/package.py b/var/spack/packages/py-rpy2/package.py
new file mode 100644
index 0000000000..3817059911
--- /dev/null
+++ b/var/spack/packages/py-rpy2/package.py
@@ -0,0 +1,14 @@
+from spack import *
+
+class PyRpy2(Package):
+ """rpy2 is a redesign and rewrite of rpy. It is providing a low-level interface to R from Python, a proposed high-level interface, including wrappers to graphical libraries, as well as R-like structures and functions."""
+ homepage = "https://pypi.python.org/pypi/rpy2"
+ url = "https://pypi.python.org/packages/source/r/rpy2/rpy2-2.5.4.tar.gz"
+
+ version('2.5.4', '115a20ac30883f096da2bdfcab55196d')
+
+ extends('python')
+ depends_on('py-setuptools')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-scientificpython/package.py b/var/spack/packages/py-scientificpython/package.py
new file mode 100644
index 0000000000..73600e6cb9
--- /dev/null
+++ b/var/spack/packages/py-scientificpython/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyScientificpython(Package):
+ """ScientificPython is a collection of Python modules for scientific computing. It contains support for geometry, mathematical functions, statistics, physical units, IO, visualization, and parallelization."""
+ homepage = "https://sourcesup.renater.fr/projects/scientific-py/"
+ url = "https://sourcesup.renater.fr/frs/download.php/4411/ScientificPython-2.8.1.tar.gz"
+
+ version('2.8.1', '73ee0df19c7b58cdf2954261f0763c77')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-scikit-learn/package.py b/var/spack/packages/py-scikit-learn/package.py
new file mode 100644
index 0000000000..c59c05a619
--- /dev/null
+++ b/var/spack/packages/py-scikit-learn/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PyScikitLearn(Package):
+ """"""
+ homepage = "https://pypi.python.org/pypi/scikit-learn"
+ url = "https://pypi.python.org/packages/source/s/scikit-learn/scikit-learn-0.15.2.tar.gz"
+
+ version('0.15.2', 'd9822ad0238e17b382a3c756ea94fe0d')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-scipy/package.py b/var/spack/packages/py-scipy/package.py
new file mode 100644
index 0000000000..b5325b919f
--- /dev/null
+++ b/var/spack/packages/py-scipy/package.py
@@ -0,0 +1,15 @@
+from spack import *
+
+class PyScipy(Package):
+ """Scientific Library for Python."""
+ homepage = "https://pypi.python.org/pypi/scipy"
+ url = "https://pypi.python.org/packages/source/s/scipy/scipy-0.15.0.tar.gz"
+
+ version('0.15.0', '639112f077f0aeb6d80718dc5019dc7a')
+
+ extends('python')
+ depends_on('py-nose')
+ depends_on('py-numpy')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-setuptools/package.py b/var/spack/packages/py-setuptools/package.py
new file mode 100644
index 0000000000..755288d55c
--- /dev/null
+++ b/var/spack/packages/py-setuptools/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PySetuptools(Package):
+ """Easily download, build, install, upgrade, and uninstall Python packages."""
+ homepage = "https://pypi.python.org/pypi/setuptools"
+ url = "https://pypi.python.org/packages/source/s/setuptools/setuptools-11.3.tar.gz"
+
+ version('11.3.1', '01f69212e019a2420c1693fb43593930')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-sip/package.py b/var/spack/packages/py-sip/package.py
new file mode 100644
index 0000000000..06aea35a74
--- /dev/null
+++ b/var/spack/packages/py-sip/package.py
@@ -0,0 +1,15 @@
+from spack import *
+
+class PySip(Package):
+ """SIP is a tool that makes it very easy to create Python bindings for C and C++ libraries."""
+ homepage = "http://www.riverbankcomputing.com/software/sip/intro"
+ url = "http://sourceforge.net/projects/pyqt/files/sip/sip-4.16.5/sip-4.16.5.tar.gz"
+
+ version('4.16.5', '6d01ea966a53e4c7ae5c5e48c40e49e5')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('configure.py')
+ make()
+ make('install')
diff --git a/var/spack/packages/py-six/package.py b/var/spack/packages/py-six/package.py
new file mode 100644
index 0000000000..04d29adced
--- /dev/null
+++ b/var/spack/packages/py-six/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PySix(Package):
+ """Python 2 and 3 compatibility utilities."""
+ homepage = "https://pypi.python.org/pypi/six"
+ url = "https://pypi.python.org/packages/source/s/six/six-1.9.0.tar.gz"
+
+ version('1.9.0', '476881ef4012262dfc8adc645ee786c4')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-sympy/package.py b/var/spack/packages/py-sympy/package.py
new file mode 100644
index 0000000000..c17e35b95f
--- /dev/null
+++ b/var/spack/packages/py-sympy/package.py
@@ -0,0 +1,13 @@
+from spack import *
+
+class PySympy(Package):
+ """SymPy is a Python library for symbolic mathematics."""
+ homepage = "https://pypi.python.org/pypi/sympy"
+ url = "https://pypi.python.org/packages/source/s/sympy/sympy-0.7.6.tar.gz"
+
+ version('0.7.6', '3d04753974306d8a13830008e17babca')
+
+ extends('python')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-virtualenv/package.py b/var/spack/packages/py-virtualenv/package.py
new file mode 100644
index 0000000000..c1b359e164
--- /dev/null
+++ b/var/spack/packages/py-virtualenv/package.py
@@ -0,0 +1,18 @@
+from spack import *
+import shutil
+
+class PyVirtualenv(Package):
+ """virtualenv is a tool to create isolated Python environments."""
+ homepage = "http://virtualenv.readthedocs.org/projects/virtualenv/"
+ url = "https://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.11.6.tar.gz"
+
+ version('1.11.6', 'f61cdd983d2c4e6aeabb70b1060d6f49')
+
+ extends('python')
+
+ def clean(self):
+ if os.path.exists('build'):
+ shutil.rmtree('build')
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py
index e6c3e28820..8a6d574d9b 100644
--- a/var/spack/packages/python/package.py
+++ b/var/spack/packages/python/package.py
@@ -1,10 +1,17 @@
from spack import *
+import spack
+import os
+import re
+from contextlib import closing
+
class Python(Package):
"""The Python programming language."""
homepage = "http://www.python.org"
url = "http://www.python.org/ftp/python/2.7.8/Python-2.7.8.tar.xz"
+ extendable = True
+
version('2.7.8', 'd235bdfa75b8396942e360a70487ee00')
depends_on("openssl")
@@ -23,3 +30,118 @@ class Python(Package):
"--enable-shared")
make()
make("install")
+
+
+ # ========================================================================
+ # Set up environment to make install easy for python extensions.
+ # ========================================================================
+
+ @property
+ def python_lib_dir(self):
+ return os.path.join('lib', 'python%d.%d' % self.version[:2])
+
+
+ @property
+ def site_packages_dir(self):
+ return os.path.join(self.python_lib_dir, 'site-packages')
+
+
+ def setup_extension_environment(self, module, spec, ext_spec):
+ """Called before python modules' install() methods.
+
+ In most cases, extensions will only need to have one line::
+
+ python('setup.py', 'install', '--prefix=%s' % prefix)
+ """
+ # Python extension builds can have a global python executable function
+ module.python = Executable(join_path(spec.prefix.bin, 'python'))
+
+ # Add variables for lib/pythonX.Y and lib/pythonX.Y/site-packages dirs.
+ module.python_lib_dir = os.path.join(ext_spec.prefix, self.python_lib_dir)
+ module.site_packages_dir = os.path.join(ext_spec.prefix, self.site_packages_dir)
+
+ # Add site packages directory to the PYTHONPATH
+ os.environ['PYTHONPATH'] = module.site_packages_dir
+
+ # Make the site packages directory if it does not exist already.
+ mkdirp(module.site_packages_dir)
+
+
+ # ========================================================================
+ # Handle specifics of activating and deactivating python modules.
+ # ========================================================================
+
+ def python_ignore(self, ext_pkg, args):
+ """Add some ignore files to activate/deactivate args."""
+ orig_ignore = args.get('ignore', lambda f: False)
+
+ def ignore(filename):
+ # Always ignore easy-install.pth, as it needs to be merged.
+ patterns = [r'easy-install\.pth$']
+
+ # Ignore pieces of setuptools installed by other packages.
+ if ext_pkg.name != 'py-setuptools':
+ patterns.append(r'/site\.pyc?$')
+ patterns.append(r'setuptools\.pth')
+ patterns.append(r'bin/easy_install[^/]*$')
+ patterns.append(r'setuptools.*egg$')
+
+ return (any(re.search(p, filename) for p in patterns) or
+ orig_ignore(filename))
+
+ return ignore
+
+
+ def write_easy_install_pth(self, extensions):
+ paths = []
+ for ext in extensions:
+ ext_site_packages = os.path.join(ext.prefix, self.site_packages_dir)
+ easy_pth = "%s/easy-install.pth" % ext_site_packages
+
+ if not os.path.isfile(easy_pth):
+ continue
+
+ with closing(open(easy_pth)) as f:
+ for line in f:
+ line = line.rstrip()
+
+ # Skip lines matching these criteria
+ if not line: continue
+ if re.search(r'^(import|#)', line): continue
+ if (ext.name != 'py-setuptools' and
+ re.search(r'setuptools.*egg$', line)): continue
+
+ paths.append(line)
+
+ site_packages = os.path.join(self.prefix, self.site_packages_dir)
+ main_pth = "%s/easy-install.pth" % site_packages
+
+ if not paths:
+ if os.path.isfile(main_pth):
+ os.remove(main_pth)
+
+ else:
+ with closing(open(main_pth, 'w')) as f:
+ f.write("import sys; sys.__plen = len(sys.path)\n")
+ for path in paths:
+ f.write("%s\n" % path)
+ f.write("import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; "
+ "p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)\n")
+
+
+ def activate(self, ext_pkg, **args):
+ args.update(ignore=self.python_ignore(ext_pkg, args))
+ super(Python, self).activate(ext_pkg, **args)
+
+ extensions = set(spack.install_layout.get_extensions(self.spec))
+ extensions.add(ext_pkg.spec)
+ self.write_easy_install_pth(extensions)
+
+
+ def deactivate(self, ext_pkg, **args):
+ args.update(ignore=self.python_ignore(ext_pkg, args))
+ super(Python, self).deactivate(ext_pkg, **args)
+
+ extensions = set(spack.install_layout.get_extensions(self.spec))
+ extensions.remove(ext_pkg.spec)
+ self.write_easy_install_pth(extensions)
diff --git a/var/spack/packages/qt/package.py b/var/spack/packages/qt/package.py
index 4f82a9d9d6..c8b19d07f5 100644
--- a/var/spack/packages/qt/package.py
+++ b/var/spack/packages/qt/package.py
@@ -1,4 +1,5 @@
from spack import *
+import os
class Qt(Package):
"""Qt is a comprehensive cross-platform C++ application framework."""
@@ -29,7 +30,16 @@ class Qt(Package):
depends_on("libmng")
depends_on("jpeg")
- depends_on("gperf") # Needed to build Qt with webkit.
+ # Webkit
+ # depends_on("gperf")
+ # depends_on("flex")
+ # depends_on("bison")
+ # depends_on("ruby")
+ # depends_on("icu4c")
+
+ # OpenGL hardware acceleration
+ depends_on("mesa")
+ depends_on("libxcb")
def patch(self):
if self.spec.satisfies('@4'):
@@ -45,46 +55,25 @@ class Qt(Package):
filter_file(r'^QMAKE_CXX *=.*$', 'QMAKE_CXX = c++', qmake_conf)
- @property
- def common_config_args(self):
- return [
- '-prefix', self.prefix,
- '-v',
- '-opensource',
- "-release",
- '-shared',
- '-confirm-license',
- '-openssl-linked',
- '-dbus-linked',
- '-optimized-qmake',
- '-no-openvg',
- '-no-pch',
- # For now, disable all the database drivers
- "-no-sql-db2", "-no-sql-ibase", "-no-sql-mysql", "-no-sql-oci", "-no-sql-odbc",
- "-no-sql-psql", "-no-sql-sqlite", "-no-sql-sqlite2", "-no-sql-tds",
- # NIS is deprecated in more recent glibc
- "-no-nis"]
-
-
- @when('@4')
- def configure(self):
- configure('-no-phonon',
- '-no-phonon-backend',
- '-fast',
- *self.common_config_args)
-
-
- @when('@5')
- def configure(self):
- configure('-no-eglfs',
- '-no-directfb',
- '-qt-xcb',
- # If someone wants to get a webkit build working, be my guest!
- '-skip', 'qtwebkit',
- *self.common_config_args)
-
-
def install(self, spec, prefix):
- self.configure()
+ # Apparently this is the only way to
+ # "truly" get rid of webkit compiles now...
+ os.rename("qtwebkit","no-qtwebkit")
+ os.rename("qtwebkit-examples","no-qtwebkit-examples")
+ configure('-v',
+ '-confirm-license',
+ '-opensource',
+ '-prefix', prefix,
+ '-openssl-linked',
+ '-dbus-linked',
+ #'-fast',
+ '-opengl',
+ '-qt-xcb',
+ '-optimized-qmake',
+ '-no-pch',
+# phonon required for py-pyqt4
+# '-no-phonon',
+# '-no-phonon-backend',
+ '-no-openvg')
make()
make("install")
diff --git a/var/spack/packages/ruby/package.py b/var/spack/packages/ruby/package.py
new file mode 100644
index 0000000000..718fd0a3be
--- /dev/null
+++ b/var/spack/packages/ruby/package.py
@@ -0,0 +1,16 @@
+from spack import *
+
+class Ruby(Package):
+ """A dynamic, open source programming language with a focus on
+ simplicity and productivity."""
+
+ homepage = "https://www.ruby-lang.org/"
+ url = "http://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.0.tar.gz"
+
+ version('2.2.0', 'cd03b28fd0b555970f5c4fd481700852')
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")
diff --git a/var/spack/packages/util-linux/package.py b/var/spack/packages/util-linux/package.py
new file mode 100644
index 0000000000..cb7ceabf57
--- /dev/null
+++ b/var/spack/packages/util-linux/package.py
@@ -0,0 +1,20 @@
+from spack import *
+import os
+
+class UtilLinux(Package):
+ """Util-linux is a suite of essential utilities for any Linux system."""
+
+ homepage = "http://freecode.com/projects/util-linux"
+ url = "https://www.kernel.org/pub/linux/utils/util-linux/v2.25/util-linux-2.25.tar.gz"
+
+ version('2.25', 'f6d7fc6952ec69c4dc62c8d7c59c1d57')
+
+ depends_on("python@2.7:")
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix,
+ "PKG_CONFIG_PATH=%s/pkgconfig" % spec['python'].prefix.lib,
+ "--disable-use-tty-group")
+
+ make()
+ make("install")
diff --git a/var/spack/packages/xcb-proto/package.py b/var/spack/packages/xcb-proto/package.py
new file mode 100644
index 0000000000..17a94bd892
--- /dev/null
+++ b/var/spack/packages/xcb-proto/package.py
@@ -0,0 +1,15 @@
+from spack import *
+
+class XcbProto(Package):
+ """Protocol for libxcb"""
+
+ homepage = "http://xcb.freedesktop.org/"
+ url = "http://xcb.freedesktop.org/dist/xcb-proto-1.11.tar.gz"
+
+ version('1.11', 'c8c6cb72c84f58270f4db1f39607f66a')
+
+ def install(self, spec, prefix):
+ configure("--prefix=%s" % prefix)
+
+ make()
+ make("install")