summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2015-02-02 06:09:35 -0800
committerTodd Gamblin <tgamblin@llnl.gov>2015-02-02 11:20:36 -0800
commit2d9190d264dd276853aca41998fffbab1baecdb0 (patch)
tree304c5b3eadc15363529e5a504025447daaddc405
parent6b90017efa1f3157fe4be7d0c7b199b6e51b9fa8 (diff)
downloadspack-2d9190d264dd276853aca41998fffbab1baecdb0.tar.gz
spack-2d9190d264dd276853aca41998fffbab1baecdb0.tar.bz2
spack-2d9190d264dd276853aca41998fffbab1baecdb0.tar.xz
spack-2d9190d264dd276853aca41998fffbab1baecdb0.zip
Add extensions command.
-rw-r--r--lib/spack/llnl/util/link_tree.py5
-rw-r--r--lib/spack/spack/cmd/extensions.py9
-rw-r--r--lib/spack/spack/directory_layout.py2
-rw-r--r--lib/spack/spack/package.py5
-rw-r--r--lib/spack/spack/packages.py5
-rw-r--r--lib/spack/spack/spec.py7
-rw-r--r--var/spack/packages/py-basemap/package.py1
-rw-r--r--var/spack/packages/python/package.py77
8 files changed, 99 insertions, 12 deletions
diff --git a/lib/spack/llnl/util/link_tree.py b/lib/spack/llnl/util/link_tree.py
index 887f6f4d26..4e4e48316e 100644
--- a/lib/spack/llnl/util/link_tree.py
+++ b/lib/spack/llnl/util/link_tree.py
@@ -27,7 +27,7 @@ __all__ = ['LinkTree']
import os
import shutil
-from llnl.util.filesystem import mkdirp
+from llnl.util.filesystem import *
empty_file_name = '.spack-empty'
@@ -93,6 +93,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
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 (
@@ -101,7 +102,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
# 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_child, dest_child, rel_path, **kwargs)
+ tuples = traverse_tree(source_root, dest_root, rel_child, **kwargs)
for t in tuples: yield t
# Treat as a file.
diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py
index 961d7e3f24..f28a388bf2 100644
--- a/lib/spack/spack/cmd/extensions.py
+++ b/lib/spack/spack/cmd/extensions.py
@@ -26,6 +26,7 @@ import sys
from external import argparse
import llnl.util.tty as tty
+from llnl.util.tty.colify import colify
import spack
import spack.cmd
@@ -66,10 +67,10 @@ def extensions(parser, args):
exts = spack.install_layout.get_extensions(spec)
if not exts:
- tty.msg("%s has no activated extensions." % spec.short_spec)
+ tty.msg("%s has no activated extensions." % spec.cshort_spec)
else:
- tty.msg("Showing %d activated extension%s for package:"
- % (len(exts), 's' if len(exts) > 1 else ''),
- spec.short_spec)
+ tty.msg("Extensions for package %s:" % spec.cshort_spec)
+ colify(pkg.name for pkg in spack.db.extensions_for(spec))
print
+ tty.msg("%d currently activated:" % len(exts))
spack.cmd.find.display_specs(exts, mode=args.mode)
diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py
index ff327ed504..efc40a17a4 100644
--- a/lib/spack/spack/directory_layout.py
+++ b/lib/spack/spack/directory_layout.py
@@ -269,8 +269,8 @@ class SpecHashDirectoryLayout(DirectoryLayout):
def get_extensions(self, spec):
_check_concrete(spec)
- path = self.extension_file_path(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:
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 0b6bc4ce6c..b905968540 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -522,6 +522,11 @@ class Package(object):
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:
diff --git a/lib/spack/spack/packages.py b/lib/spack/spack/packages.py
index bb5a94bcab..b3049e812f 100644
--- a/lib/spack/spack/packages.py
+++ b/lib/spack/spack/packages.py
@@ -112,6 +112,11 @@ 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)]
+
+
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/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/var/spack/packages/py-basemap/package.py b/var/spack/packages/py-basemap/package.py
index 8955bf8827..7b6d8e7e65 100644
--- a/var/spack/packages/py-basemap/package.py
+++ b/var/spack/packages/py-basemap/package.py
@@ -11,6 +11,7 @@ class PyBasemap(Package):
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')
diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py
index a22bd54c82..8a6d574d9b 100644
--- a/var/spack/packages/python/package.py
+++ b/var/spack/packages/python/package.py
@@ -1,6 +1,9 @@
from spack import *
+import spack
import os
import re
+from contextlib import closing
+
class Python(Package):
"""The Python programming language."""
@@ -29,6 +32,10 @@ class Python(Package):
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])
@@ -60,21 +67,81 @@ class Python(Package):
mkdirp(module.site_packages_dir)
- def make_ignore(self, args):
+ # ========================================================================
+ # 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):
- return (re.search(r'/site\.pyc?$', filename) or
- re.search(r'\.pth$', filename) or
+ # 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.make_ignore(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.make_ignore(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)