Skip to content
Snippets Groups Projects
Commit 2d9190d2 authored by Todd Gamblin's avatar Todd Gamblin
Browse files

Add extensions command.

parent 6b90017e
No related branches found
No related tags found
No related merge requests found
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
import os import os
import shutil import shutil
from llnl.util.filesystem import mkdirp from llnl.util.filesystem import *
empty_file_name = '.spack-empty' empty_file_name = '.spack-empty'
...@@ -93,6 +93,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs): ...@@ -93,6 +93,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
for f in os.listdir(source_path): for f in os.listdir(source_path):
source_child = os.path.join(source_path, f) source_child = os.path.join(source_path, f)
dest_child = os.path.join(dest_path, f) dest_child = os.path.join(dest_path, f)
rel_child = os.path.join(rel_path, f)
# Treat as a directory # Treat as a directory
if os.path.isdir(source_child) and ( if os.path.isdir(source_child) and (
...@@ -101,7 +102,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs): ...@@ -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 # When follow_nonexisting isn't set, don't descend into dirs
# in source that do not exist in dest # in source that do not exist in dest
if follow_nonexisting or os.path.exists(dest_child): 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 for t in tuples: yield t
# Treat as a file. # Treat as a file.
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
from external import argparse from external import argparse
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.tty.colify import colify
import spack import spack
import spack.cmd import spack.cmd
...@@ -66,10 +67,10 @@ def extensions(parser, args): ...@@ -66,10 +67,10 @@ def extensions(parser, args):
exts = spack.install_layout.get_extensions(spec) exts = spack.install_layout.get_extensions(spec)
if not exts: if not exts:
tty.msg("%s has no activated extensions." % spec.short_spec) tty.msg("%s has no activated extensions." % spec.cshort_spec)
else: else:
tty.msg("Showing %d activated extension%s for package:" tty.msg("Extensions for package %s:" % spec.cshort_spec)
% (len(exts), 's' if len(exts) > 1 else ''), colify(pkg.name for pkg in spack.db.extensions_for(spec))
spec.short_spec)
print print
tty.msg("%d currently activated:" % len(exts))
spack.cmd.find.display_specs(exts, mode=args.mode) spack.cmd.find.display_specs(exts, mode=args.mode)
...@@ -269,8 +269,8 @@ def extension_file_path(self, spec): ...@@ -269,8 +269,8 @@ def extension_file_path(self, spec):
def get_extensions(self, spec): def get_extensions(self, spec):
_check_concrete(spec) _check_concrete(spec)
path = self.extension_file_path(spec)
extensions = set() extensions = set()
path = self.extension_file_path(spec)
if os.path.exists(path): if os.path.exists(path):
with closing(open(path)) as ext_file: with closing(open(path)) as ext_file:
for line in ext_file: for line in ext_file:
......
...@@ -522,6 +522,11 @@ def is_extension(self): ...@@ -522,6 +522,11 @@ def is_extension(self):
return len(self.extendees) > 0 return len(self.extendees) > 0
def extends(self, spec):
return (spec.name in self.extendees and
spec.satisfies(self.extendees[spec.name][0]))
@property @property
def activated(self): def activated(self):
if not self.spec.concrete: if not self.spec.concrete:
......
...@@ -112,6 +112,11 @@ def providers_for(self, vpkg_spec): ...@@ -112,6 +112,11 @@ def providers_for(self, vpkg_spec):
return providers 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): def dirname_for_package_name(self, pkg_name):
"""Get the directory name for a particular package. This is the """Get the directory name for a particular package. This is the
directory that contains its package.py file.""" directory that contains its package.py file."""
......
...@@ -552,6 +552,13 @@ def short_spec(self): ...@@ -552,6 +552,13 @@ def short_spec(self):
return self.format('$_$@$%@$+$=$#') return self.format('$_$@$%@$+$=$#')
@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 @property
def prefix(self): def prefix(self):
return Prefix(spack.install_layout.path_for_spec(self)) return Prefix(spack.install_layout.path_for_spec(self))
......
...@@ -11,6 +11,7 @@ class PyBasemap(Package): ...@@ -11,6 +11,7 @@ class PyBasemap(Package):
geos_version = {'1.0.7' : '3.3.3'} geos_version = {'1.0.7' : '3.3.3'}
extends('python') extends('python')
depends_on('py-setuptools')
depends_on('py-numpy') depends_on('py-numpy')
depends_on('py-matplotlib') depends_on('py-matplotlib')
depends_on('py-pil') depends_on('py-pil')
......
from spack import * from spack import *
import spack
import os import os
import re import re
from contextlib import closing
class Python(Package): class Python(Package):
"""The Python programming language.""" """The Python programming language."""
...@@ -29,6 +32,10 @@ def install(self, spec, prefix): ...@@ -29,6 +32,10 @@ def install(self, spec, prefix):
make("install") make("install")
# ========================================================================
# Set up environment to make install easy for python extensions.
# ========================================================================
@property @property
def python_lib_dir(self): def python_lib_dir(self):
return os.path.join('lib', 'python%d.%d' % self.version[:2]) return os.path.join('lib', 'python%d.%d' % self.version[:2])
...@@ -60,21 +67,81 @@ def setup_extension_environment(self, module, spec, ext_spec): ...@@ -60,21 +67,81 @@ def setup_extension_environment(self, module, spec, ext_spec):
mkdirp(module.site_packages_dir) 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.""" """Add some ignore files to activate/deactivate args."""
orig_ignore = args.get('ignore', lambda f: False) orig_ignore = args.get('ignore', lambda f: False)
def ignore(filename): def ignore(filename):
return (re.search(r'/site\.pyc?$', filename) or # Always ignore easy-install.pth, as it needs to be merged.
re.search(r'\.pth$', filename) or 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)) orig_ignore(filename))
return ignore 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): 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) 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): 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) 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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment