From 2c1eda66c4d7a0df8f0a05ad16be38942f54dcee Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Tue, 6 Jan 2015 14:50:40 -0500 Subject: First python extension package: setuptools --- var/spack/packages/py-setuptools/package.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 var/spack/packages/py-setuptools/package.py (limited to 'var') diff --git a/var/spack/packages/py-setuptools/package.py b/var/spack/packages/py-setuptools/package.py new file mode 100644 index 0000000000..e2c4e1a0be --- /dev/null +++ b/var/spack/packages/py-setuptools/package.py @@ -0,0 +1,19 @@ +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): + site_packages_dir = "%s/lib/python2.7/site-packages" % prefix + mkdirp(site_packages_dir) + + env['PYTHONPATH'] = site_packages_dir + + python = which('python') + python('setup.py', 'install', '--prefix=%s' % prefix) -- cgit v1.2.3-70-g09d2 From 99775434785779d223997a9e41972da470214e5d Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Wed, 7 Jan 2015 11:48:21 -0800 Subject: Added feature: package extensions - packages can be "extended" by others - allows extension to be symlinked into extendee's prefix. - used for python modules. - first module: py-setuptools --- lib/spack/llnl/util/filesystem.py | 82 +++++++++++++++++++++++++++++++++- lib/spack/spack/__init__.py | 2 +- lib/spack/spack/directory_layout.py | 55 ++++++++++++++++------- lib/spack/spack/hooks/extensions.py | 49 +++++++++++++++++++++ lib/spack/spack/package.py | 85 ++++++++++++++++++++++++++++++++++++ lib/spack/spack/relations.py | 4 +- var/spack/packages/python/package.py | 3 ++ 7 files changed, 261 insertions(+), 19 deletions(-) create mode 100644 lib/spack/spack/hooks/extensions.py (limited to 'var') diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index 0578415653..9fb76d3a35 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -24,7 +24,8 @@ ############################################################################## __all__ = ['set_install_permissions', 'install', 'expand_user', 'working_dir', 'touch', 'mkdirp', 'force_remove', 'join_path', 'ancestor', - 'can_access', 'filter_file', 'change_sed_delimiter', 'is_exe'] + 'can_access', 'filter_file', 'change_sed_delimiter', 'is_exe', + 'check_link_tree', 'merge_link_tree', 'unmerge_link_tree'] import os import sys @@ -222,3 +223,82 @@ def ancestor(dir, n=1): def can_access(file_name): """True if we have read/write access to the file.""" return os.access(file_name, os.R_OK|os.W_OK) + + +def traverse_link_tree(src_root, dest_root, follow_nonexisting=True, **kwargs): + # Yield directories before or after their contents. + 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', None) + if isinstance(ignore, basestring): + ignore = (ignore,) + + for dirpath, dirnames, filenames in os.walk(src_root): + rel_path = dirpath[len(src_root):] + rel_path = rel_path.lstrip(os.path.sep) + dest_dirpath = os.path.join(dest_root, rel_path) + + # Don't descend into ignored directories + if ignore and dest_dirpath in ignore: + return + + # Don't descend into dirs in dest that do not exist in src. + if not follow_nonexisting: + dirnames[:] = [ + d for d in dirnames + if os.path.exists(os.path.join(dest_dirpath, d))] + + # preorder yields directories before children + if order == 'pre': + yield (dirpath, dest_dirpath) + + for name in filenames: + src_file = os.path.join(dirpath, name) + dest_file = os.path.join(dest_dirpath, name) + + # Ignore particular paths inside the install root. + src_relpath = src_file[len(src_root):] + src_relpath = src_relpath.lstrip(os.path.sep) + if ignore and src_relpath in ignore: + continue + + yield (src_file, dest_file) + + # postorder yields directories after children + if order == 'post': + yield (dirpath, dest_dirpath) + + + +def check_link_tree(src_root, dest_root, **kwargs): + for src, dest in traverse_link_tree(src_root, dest_root, False, **kwargs): + if os.path.exists(dest) and not os.path.isdir(dest): + return dest + return None + + +def merge_link_tree(src_root, dest_root, **kwargs): + kwargs['order'] = 'pre' + for src, dest in traverse_link_tree(src_root, dest_root, **kwargs): + if os.path.isdir(src): + mkdirp(dest) + else: + assert(not os.path.exists(dest)) + os.symlink(src, dest) + + +def unmerge_link_tree(src_root, dest_root, **kwargs): + kwargs['order'] = 'post' + for src, dest in traverse_link_tree(src_root, dest_root, **kwargs): + if os.path.isdir(dest): + if not os.listdir(dest): + # TODO: what if empty directories were present pre-merge? + shutil.rmtree(dest, ignore_errors=True) + + 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/directory_layout.py b/lib/spack/spack/directory_layout.py index 4ab9a515cf..ff327ed504 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. @@ -156,6 +169,11 @@ class SpecHashDirectoryLayout(DirectoryLayout): self.extension_file_name = extension_file_name + @property + def hidden_file_paths(self): + return ('.spec', '.extensions') + + def relative_path_for_spec(self, spec): _check_concrete(spec) dir_name = spec.format('$_$@$+$#') @@ -249,28 +267,32 @@ class SpecHashDirectoryLayout(DirectoryLayout): def get_extensions(self, spec): - path = self.extension_file_path(spec) + _check_concrete(spec) + path = self.extension_file_path(spec) extensions = set() if os.path.exists(path): - with closing(open(path)) as spec_file: - for line in spec_file: + with closing(open(path)) as ext_file: + for line in ext_file: try: - extensions.add(Spec(line)) - except SpecError, e: + extensions.add(Spec(line.strip())) + except spack.error.SpackError, e: raise InvalidExtensionSpecError(str(e)) return extensions - def write_extensions(self, 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" % extensions) + spec_file.write("%s\n" % extension) def add_extension(self, spec, extension_spec): - exts = get_extensions(spec) + _check_concrete(spec) + _check_concrete(extension_spec) + + exts = self.get_extensions(spec) if extension_spec in exts: raise ExtensionAlreadyInstalledError(spec, extension_spec) else: @@ -279,16 +301,19 @@ class SpecHashDirectoryLayout(DirectoryLayout): raise ExtensionConflictError(spec, extension_spec, already_installed) exts.add(extension_spec) - self.write_extensions(exts) + self.write_extensions(spec, exts) def remove_extension(self, spec, extension_spec): - exts = get_extensions(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(exts) + self.write_extensions(spec, exts) class DirectoryLayoutError(SpackError): @@ -328,7 +353,7 @@ 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, spec)) + "%s is already installed in %s" % (extension_spec.short_spec, spec.short_spec)) class ExtensionConflictError(DirectoryLayoutError): @@ -336,12 +361,12 @@ class ExtensionConflictError(DirectoryLayoutError): def __init__(self, spec, extension_spec, conflict): super(ExtensionConflictError, self).__init__( "%s cannot be installed in %s because it conflicts with %s."% ( - extension_spec, spec, conflict)) + 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 beacuse it's not installed."% ( - extension_spec, spec, conflict)) + "%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/extensions.py b/lib/spack/spack/hooks/extensions.py new file mode 100644 index 0000000000..444472bffa --- /dev/null +++ b/lib/spack/spack/hooks/extensions.py @@ -0,0 +1,49 @@ +############################################################################## +# 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): + assert(pkg.spec.concrete) + for name, spec in pkg.extendees.items(): + ext = pkg.spec[name] + epkg = ext.package + if epkg.installed: + epkg.do_activate(pkg) + + +def pre_uninstall(pkg): + assert(pkg.spec.concrete) + + # Need to do this b/c uninstall does not automatically do it. + # TODO: store full graph info in stored .spec file. + pkg.spec.normalize() + + for name, spec in pkg.extendees.items(): + ext = pkg.spec[name] + epkg = ext.package + if epkg.installed: + epkg.do_deactivate(pkg) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 04f0d842da..b7dae552e4 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -329,6 +329,9 @@ class Package(object): """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. @@ -398,6 +401,9 @@ class Package(object): self._fetch_time = 0.0 self._total_time = 0.0 + for name, spec in self.extendees.items(): + spack.db.get(spec)._check_extendable() + @property def version(self): @@ -877,6 +883,79 @@ 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, extension): + self._check_extendable() + if not self.installed: + raise ValueError("Can only (de)activate extensions for installed packages.") + if not extension.installed: + raise ValueError("Extensions must first be installed.") + if not self.name in extension.extendees: + raise ValueError("%s does not extend %s!" % (extension.name, self.name)) + if not self.spec.satisfies(extension.extendees[self.name]): + raise ValueError("%s does not satisfy %s!" % (self.spec, extension.spec)) + + + def do_activate(self, extension): + self._sanity_check_extension(extension) + + self.activate(extension) + spack.install_layout.add_extension(self.spec, extension.spec) + tty.msg("Activated extension %s for %s." + % (extension.spec.short_spec, self.spec.short_spec)) + + + def activate(self, extension): + """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. + + """ + conflict = check_link_tree( + extension.prefix, self.prefix, + ignore=spack.install_layout.hidden_file_paths) + + if conflict: + raise ExtensionConflictError(conflict) + + merge_link_tree(extension.prefix, self.prefix, + ignore=spack.install_layout.hidden_file_paths) + + + def do_deactivate(self, extension): + self._sanity_check_extension(extension) + self.deactivate(extension) + + ext = extension.spec + if ext in spack.install_layout.get_extensions(self.spec): + spack.install_layout.remove_extension(self.spec, ext) + + tty.msg("Deactivated extension %s for %s." + % (extension.spec.short_spec, self.spec.short_spec)) + + + def deactivate(self, extension): + """Unlinks all files from extension out of extendee'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. + + """ + unmerge_link_tree(extension.prefix, self.prefix, + ignore=spack.install_layout.hidden_file_paths) + tty.msg("Deactivated %s as extension of %s." + % (extension.spec.short_spec, self.spec.short_spec)) + + def do_clean(self): if self.stage.expanded_archive_path: self.stage.chdir_to_source() @@ -1068,3 +1147,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/relations.py b/lib/spack/spack/relations.py index aaca9c199e..17bec1664f 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 @@ -135,7 +135,7 @@ def extends(*specs): for string in specs: for spec in spack.spec.parse(string): if pkg == spec.name: - raise CircularReferenceError('depends_on', pkg) + raise CircularReferenceError('extends', pkg) dependencies[spec.name] = spec extendees[spec.name] = spec diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index e6c3e28820..953be69cc2 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -1,10 +1,13 @@ from spack import * + 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") -- cgit v1.2.3-70-g09d2 From bcccf020204a556e382c0af2897ad9126bb24984 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 10 Jan 2015 19:37:01 -0800 Subject: Add setup_extension_environment() method. - lets packages do some setup before their extensions run install() --- lib/spack/spack/package.py | 30 +++++++++++++++++++++++++++++ var/spack/packages/py-setuptools/package.py | 6 ------ var/spack/packages/python/package.py | 23 +++++++++++++++++++++- 3 files changed, 52 insertions(+), 7 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index da251dc4e8..8504b96fcf 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -783,6 +783,12 @@ class Package(object): self.stage.chdir_to_source() build_env.setup_package(self) + # Allow extendees to further set up the environment. + for ext_name in self.extendees: + ext_spec = self.spec[ext_name] + ext_spec.package.setup_extension_environment( + self.module, ext_spec, self.spec) + if fake_install: self.do_fake_install() else: @@ -854,6 +860,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) diff --git a/var/spack/packages/py-setuptools/package.py b/var/spack/packages/py-setuptools/package.py index e2c4e1a0be..755288d55c 100644 --- a/var/spack/packages/py-setuptools/package.py +++ b/var/spack/packages/py-setuptools/package.py @@ -10,10 +10,4 @@ class PySetuptools(Package): extends('python') def install(self, spec, prefix): - site_packages_dir = "%s/lib/python2.7/site-packages" % prefix - mkdirp(site_packages_dir) - - env['PYTHONPATH'] = site_packages_dir - - python = which('python') python('setup.py', 'install', '--prefix=%s' % prefix) diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index 953be69cc2..9700179ab8 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -1,5 +1,5 @@ from spack import * - +import os class Python(Package): """The Python programming language.""" @@ -26,3 +26,24 @@ class Python(Package): "--enable-shared") make() make("install") + + + 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 = join_path(ext_spec.prefix.lib, 'python%d.%d' % self.version[:2]) + module.site_packages_dir = join_path(module.python_lib_dir, 'site-packages') + + # 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) -- cgit v1.2.3-70-g09d2 From 7992f415fe0e50c5e15964f348ed23c1fc1795b5 Mon Sep 17 00:00:00 2001 From: "Gregory L. Lee" Date: Thu, 15 Jan 2015 10:11:40 -0800 Subject: added py-nose --- var/spack/packages/py-nose/package.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 var/spack/packages/py-nose/package.py (limited to 'var') diff --git a/var/spack/packages/py-nose/package.py b/var/spack/packages/py-nose/package.py new file mode 100644 index 0000000000..7bd7106b8c --- /dev/null +++ b/var/spack/packages/py-nose/package.py @@ -0,0 +1,13 @@ +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) -- cgit v1.2.3-70-g09d2 From 9fa489b7f2dab452929729e300f189f8c50b817c Mon Sep 17 00:00:00 2001 From: "Gregory L. Lee" Date: Tue, 20 Jan 2015 09:39:21 -0800 Subject: added several modules --- var/spack/packages/py-cython/package.py | 13 +++++++++++++ var/spack/packages/py-dateutil/package.py | 13 +++++++++++++ var/spack/packages/py-epydoc/package.py | 13 +++++++++++++ var/spack/packages/py-ipython/package.py | 14 ++++++++++++++ var/spack/packages/py-matplotlib/package.py | 20 ++++++++++++++++++++ var/spack/packages/py-numpy/package.py | 14 ++++++++++++++ var/spack/packages/py-pexpect/package.py | 13 +++++++++++++ var/spack/packages/py-pygments/package.py | 14 ++++++++++++++ var/spack/packages/py-pyparsing/package.py | 13 +++++++++++++ var/spack/packages/py-pyside/package.py | 18 ++++++++++++++++++ var/spack/packages/py-pytz/package.py | 13 +++++++++++++ var/spack/packages/py-scipy/package.py | 15 +++++++++++++++ var/spack/packages/py-six/package.py | 13 +++++++++++++ var/spack/packages/py-virtualenv/package.py | 18 ++++++++++++++++++ 14 files changed, 204 insertions(+) create mode 100644 var/spack/packages/py-cython/package.py create mode 100644 var/spack/packages/py-dateutil/package.py create mode 100644 var/spack/packages/py-epydoc/package.py create mode 100644 var/spack/packages/py-ipython/package.py create mode 100644 var/spack/packages/py-matplotlib/package.py create mode 100644 var/spack/packages/py-numpy/package.py create mode 100644 var/spack/packages/py-pexpect/package.py create mode 100644 var/spack/packages/py-pygments/package.py create mode 100644 var/spack/packages/py-pyparsing/package.py create mode 100644 var/spack/packages/py-pyside/package.py create mode 100644 var/spack/packages/py-pytz/package.py create mode 100644 var/spack/packages/py-scipy/package.py create mode 100644 var/spack/packages/py-six/package.py create mode 100644 var/spack/packages/py-virtualenv/package.py (limited to 'var') 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..96e3ecab07 --- /dev/null +++ b/var/spack/packages/py-dateutil/package.py @@ -0,0 +1,13 @@ +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') + + 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-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-matplotlib/package.py b/var/spack/packages/py-matplotlib/package.py new file mode 100644 index 0000000000..836273c923 --- /dev/null +++ b/var/spack/packages/py-matplotlib/package.py @@ -0,0 +1,20 @@ +from spack import * + +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') + + 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-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-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-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-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-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-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) -- cgit v1.2.3-70-g09d2 From ff9cb94f4f92112739f53881bcb0a9a19811684d Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Tue, 20 Jan 2015 00:23:16 -0800 Subject: Add arguements to extends() and activate/deactivate. --- lib/spack/spack/package.py | 40 ++++++++++++++++++++++++++---------- lib/spack/spack/relations.py | 17 ++++++++------- var/spack/packages/python/package.py | 32 +++++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 20 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index ae34f8ae45..bd63c2e0c0 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -497,16 +497,26 @@ class Package(object): @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 - + if not self.extendees: + return None name = next(iter(self.extendees)) if not name in self.spec: - return self.extendees[name] + 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 @@ -949,6 +959,8 @@ class Package(object): 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() @@ -967,14 +979,14 @@ class Package(object): activate() directly. """ self._sanity_check_extension() - self.extendee_spec.package.activate(self) + 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): + 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 @@ -983,17 +995,20 @@ class Package(object): always executed. """ + ignore_files = set(spack.install_layout.hidden_file_paths) + ignore_files.update(kwargs.get('ignore', ())) + tree = LinkTree(extension.prefix) - conflict = tree.find_conflict( - self.prefix, ignore=spack.install_layout.hidden_file_paths) + conflict = tree.find_conflict(self.prefix, ignore=ignore_files) if conflict: raise ExtensionConflictError(conflict) - tree.merge(self.prefix, ignore=spack.install_layout.hidden_file_paths) + tree.merge(self.prefix, ignore=ignore_files) 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_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) @@ -1002,7 +1017,7 @@ class Package(object): % (self.spec.short_spec, self.extendee_spec.short_spec)) - def deactivate(self, extension): + 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 @@ -1011,8 +1026,11 @@ class Package(object): always executed. """ + ignore_files = set(spack.install_layout.hidden_file_paths) + ignore_files.update(kwargs.get('ignore', ())) + tree = LinkTree(extension.prefix) - tree.unmerge(self.prefix, ignore=spack.install_layout.hidden_file_paths) + tree.unmerge(self.prefix, ignore=ignore_files) def do_clean(self): diff --git a/lib/spack/spack/relations.py b/lib/spack/spack/relations.py index 60ff5bef34..a0c7723473 100644 --- a/lib/spack/spack/relations.py +++ b/lib/spack/spack/relations.py @@ -117,7 +117,7 @@ def depends_on(*specs): dependencies[spec.name] = spec -def extends(*specs): +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 @@ -126,6 +126,10 @@ def extends(*specs): 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() @@ -134,12 +138,11 @@ def extends(*specs): if extendees: raise RelationError("Packages can extend at most one other package.") - for string in specs: - for spec in spack.spec.parse(string): - if pkg == spec.name: - raise CircularReferenceError('extends', pkg) - dependencies[spec.name] = spec - extendees[spec.name] = spec + spec = Spec(spec) + if pkg == spec.name: + raise CircularReferenceError('extends', pkg) + dependencies[spec.name] = spec + extendees[spec.name] = (spec, kwargs) def provides(*specs, **kwargs): diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index 9700179ab8..86b903bc23 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -28,6 +28,16 @@ class Python(Package): make("install") + @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. @@ -39,11 +49,29 @@ class Python(Package): 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 = join_path(ext_spec.prefix.lib, 'python%d.%d' % self.version[:2]) - module.site_packages_dir = join_path(module.python_lib_dir, 'site-packages') + 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) + + + def add_ignore_files(self, args): + """Add some ignore files to activate/deactivate args.""" + ignore = set(args.get('ignore', ())) + ignore.add(os.path.join(self.site_packages_dir, 'site.py')) + ignore.add(os.path.join(self.site_packages_dir, 'site.pyc')) + args.update(ignore=ignore) + + + def activate(self, ext_pkg, **args): + self.add_ignore_files(args) + super(Python, self).activate(ext_pkg, **args) + + + def deactivate(self, ext_pkg, **args): + self.add_ignore_files(args) + super(Python, self).deactivate(ext_pkg, **args) -- cgit v1.2.3-70-g09d2 From de91c95e8e45b8ab066ba3dfc8f89c92da761b5a Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Tue, 20 Jan 2015 15:07:53 -0800 Subject: Ability to ignore files in activate/deactivate for extensions. --- lib/spack/llnl/util/link_tree.py | 11 ++++------- lib/spack/spack/package.py | 16 +++++++++------- var/spack/packages/py-nose/package.py | 4 +++- var/spack/packages/python/package.py | 17 ++++++++++------- 4 files changed, 26 insertions(+), 22 deletions(-) (limited to 'var') diff --git a/lib/spack/llnl/util/link_tree.py b/lib/spack/llnl/util/link_tree.py index 19c2d46938..2d7126be2c 100644 --- a/lib/spack/llnl/util/link_tree.py +++ b/lib/spack/llnl/util/link_tree.py @@ -72,8 +72,7 @@ class LinkTree(object): order=[pre|post] -- Whether to do pre- or post-order traveral. - ignore= -- Optional container of root-relative - paths to ignore. + ignore= -- Predicate indicating which files to ignore. follow_nonexisting -- Whether to descend into directories in src that do not exit in dest. @@ -85,9 +84,7 @@ class LinkTree(object): raise ValueError("Order must be 'pre' or 'post'.") # List of relative paths to ignore under the src root. - ignore = kwargs.get('ignore', None) - if isinstance(ignore, basestring): - ignore = (ignore,) + ignore = kwargs.get('ignore', lambda filename: False) # Whether to descend when dirs dont' exist in dest. follow_nonexisting = kwargs.get('follow_nonexisting', True) @@ -98,7 +95,7 @@ class LinkTree(object): dest_dirpath = os.path.join(dest_root, rel_path) # Don't descend into ignored directories - if ignore and dest_dirpath in ignore: + if ignore(dest_dirpath): return # Don't descend into dirs in dest that do not exist in src. @@ -118,7 +115,7 @@ class LinkTree(object): # Ignore particular paths inside the install root. src_relpath = src_file[len(self._root):] src_relpath = src_relpath.lstrip(os.path.sep) - if ignore and src_relpath in ignore: + if ignore(src_relpath): continue yield (src_file, dest_file) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index bd63c2e0c0..43b1fcd9c8 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -995,14 +995,15 @@ class Package(object): always executed. """ - ignore_files = set(spack.install_layout.hidden_file_paths) - ignore_files.update(kwargs.get('ignore', ())) + 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_files) + conflict = tree.find_conflict(self.prefix, ignore=ignore) if conflict: raise ExtensionConflictError(conflict) - tree.merge(self.prefix, ignore=ignore_files) + tree.merge(self.prefix, ignore=ignore) def do_deactivate(self): @@ -1026,11 +1027,12 @@ class Package(object): always executed. """ - ignore_files = set(spack.install_layout.hidden_file_paths) - ignore_files.update(kwargs.get('ignore', ())) + 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_files) + tree.unmerge(self.prefix, ignore=ignore) def do_clean(self): diff --git a/var/spack/packages/py-nose/package.py b/var/spack/packages/py-nose/package.py index 7bd7106b8c..6df84e831d 100644 --- a/var/spack/packages/py-nose/package.py +++ b/var/spack/packages/py-nose/package.py @@ -1,7 +1,9 @@ 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.""" + """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" diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index 86b903bc23..a22bd54c82 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -1,5 +1,6 @@ from spack import * import os +import re class Python(Package): """The Python programming language.""" @@ -59,19 +60,21 @@ class Python(Package): mkdirp(module.site_packages_dir) - def add_ignore_files(self, args): + def make_ignore(self, args): """Add some ignore files to activate/deactivate args.""" - ignore = set(args.get('ignore', ())) - ignore.add(os.path.join(self.site_packages_dir, 'site.py')) - ignore.add(os.path.join(self.site_packages_dir, 'site.pyc')) - args.update(ignore=ignore) + 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 + orig_ignore(filename)) + return ignore def activate(self, ext_pkg, **args): - self.add_ignore_files(args) + args.update(ignore=self.make_ignore(args)) super(Python, self).activate(ext_pkg, **args) def deactivate(self, ext_pkg, **args): - self.add_ignore_files(args) + args.update(ignore=self.make_ignore(args)) super(Python, self).deactivate(ext_pkg, **args) -- cgit v1.2.3-70-g09d2 From 2bc3f74df263eb92a99e5477f4ce04972eb76994 Mon Sep 17 00:00:00 2001 From: "Gregory L. Lee" Date: Thu, 22 Jan 2015 11:50:01 -0800 Subject: added more Python modules --- var/spack/packages/hdf5/package.py | 6 ++++-- var/spack/packages/py-basemap/package.py | 24 +++++++++++++++++++++++ var/spack/packages/py-biopython/package.py | 14 +++++++++++++ var/spack/packages/py-gnuplot/package.py | 13 ++++++++++++ var/spack/packages/py-h5py/package.py | 18 +++++++++++++++++ var/spack/packages/py-matplotlib/package.py | 17 ++++++++++++++++ var/spack/packages/py-mpi4py/package.py | 13 ++++++++++++ var/spack/packages/py-mx/package.py | 13 ++++++++++++ var/spack/packages/py-pil/package.py | 14 +++++++++++++ var/spack/packages/py-pmw/package.py | 13 ++++++++++++ var/spack/packages/py-pylint/package.py | 16 +++++++++++++++ var/spack/packages/py-rpy2/package.py | 14 +++++++++++++ var/spack/packages/py-scientificpython/package.py | 13 ++++++++++++ var/spack/packages/py-scikit-learn/package.py | 13 ++++++++++++ var/spack/packages/py-sympy/package.py | 13 ++++++++++++ 15 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 var/spack/packages/py-basemap/package.py create mode 100644 var/spack/packages/py-biopython/package.py create mode 100644 var/spack/packages/py-gnuplot/package.py create mode 100644 var/spack/packages/py-h5py/package.py create mode 100644 var/spack/packages/py-mpi4py/package.py create mode 100644 var/spack/packages/py-mx/package.py create mode 100644 var/spack/packages/py-pil/package.py create mode 100644 var/spack/packages/py-pmw/package.py create mode 100644 var/spack/packages/py-pylint/package.py create mode 100644 var/spack/packages/py-rpy2/package.py create mode 100644 var/spack/packages/py-scientificpython/package.py create mode 100644 var/spack/packages/py-scikit-learn/package.py create mode 100644 var/spack/packages/py-sympy/package.py (limited to 'var') 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/py-basemap/package.py b/var/spack/packages/py-basemap/package.py new file mode 100644 index 0000000000..8955bf8827 --- /dev/null +++ b/var/spack/packages/py-basemap/package.py @@ -0,0 +1,24 @@ +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-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-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-matplotlib/package.py b/var/spack/packages/py-matplotlib/package.py index 836273c923..270a1ebfe4 100644 --- a/var/spack/packages/py-matplotlib/package.py +++ b/var/spack/packages/py-matplotlib/package.py @@ -1,4 +1,5 @@ from spack import * +import os class PyMatplotlib(Package): """Python plotting package.""" @@ -18,3 +19,19 @@ class PyMatplotlib(Package): 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-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-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-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-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) -- cgit v1.2.3-70-g09d2 From 48f1ff87f836f214e72e1d02f47eac4678f0292a Mon Sep 17 00:00:00 2001 From: "Gregory L. Lee" Date: Fri, 23 Jan 2015 13:53:36 -0800 Subject: added more Python modules --- var/spack/packages/py-dateutil/package.py | 1 + var/spack/packages/py-libxml2/package.py | 13 +++++++++++++ var/spack/packages/py-matplotlib/package.py | 1 + var/spack/packages/py-pychecker/package.py | 13 +++++++++++++ var/spack/packages/py-pyqt4/package.py | 18 ++++++++++++++++++ var/spack/packages/py-sip/package.py | 15 +++++++++++++++ var/spack/packages/qt/package.py | 5 +++-- 7 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 var/spack/packages/py-libxml2/package.py create mode 100644 var/spack/packages/py-pychecker/package.py create mode 100644 var/spack/packages/py-pyqt4/package.py create mode 100644 var/spack/packages/py-sip/package.py (limited to 'var') diff --git a/var/spack/packages/py-dateutil/package.py b/var/spack/packages/py-dateutil/package.py index 96e3ecab07..11699e07ee 100644 --- a/var/spack/packages/py-dateutil/package.py +++ b/var/spack/packages/py-dateutil/package.py @@ -8,6 +8,7 @@ class PyDateutil(Package): 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-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-matplotlib/package.py b/var/spack/packages/py-matplotlib/package.py index 270a1ebfe4..5979ceeab0 100644 --- a/var/spack/packages/py-matplotlib/package.py +++ b/var/spack/packages/py-matplotlib/package.py @@ -16,6 +16,7 @@ class PyMatplotlib(Package): 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) 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-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-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/qt/package.py b/var/spack/packages/qt/package.py index 01f9de7f3c..6a55c89701 100644 --- a/var/spack/packages/qt/package.py +++ b/var/spack/packages/qt/package.py @@ -37,8 +37,9 @@ class Qt(Package): '-fast', '-optimized-qmake', '-no-pch', - '-no-phonon', - '-no-phonon-backend', +# phonon required for py-pyqt4 +# '-no-phonon', +# '-no-phonon-backend', '-no-openvg') make() make("install") -- cgit v1.2.3-70-g09d2 From 2d9190d264dd276853aca41998fffbab1baecdb0 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 2 Feb 2015 06:09:35 -0800 Subject: Add extensions command. --- lib/spack/llnl/util/link_tree.py | 5 ++- lib/spack/spack/cmd/extensions.py | 9 ++-- lib/spack/spack/directory_layout.py | 2 +- lib/spack/spack/package.py | 5 +++ lib/spack/spack/packages.py | 5 +++ lib/spack/spack/spec.py | 7 +++ var/spack/packages/py-basemap/package.py | 1 + var/spack/packages/python/package.py | 77 +++++++++++++++++++++++++++++--- 8 files changed, 99 insertions(+), 12 deletions(-) (limited to 'var') 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 @@ -552,6 +552,13 @@ class Spec(object): 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 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) -- cgit v1.2.3-70-g09d2 From 5cc369c2b831446f1afaaba41cbf0dbdba75b4ed Mon Sep 17 00:00:00 2001 From: "Gregory L. Lee" Date: Fri, 6 Feb 2015 16:35:35 -0800 Subject: add dependent packages to PYTHONPATH for build --- var/spack/packages/python/package.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'var') diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index 8a6d574d9b..23b528b089 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -66,6 +66,11 @@ class Python(Package): # Make the site packages directory if it does not exist already. mkdirp(module.site_packages_dir) + # Add dependent packages' site-packages directory to PYTHONPATH + for d in ext_spec.traverse(): + if d.package.extends(self.spec): + os.environ['PYTHONPATH'] += ':' + os.path.join(d.prefix, self.site_packages_dir) + # ======================================================================== # Handle specifics of activating and deactivating python modules. -- cgit v1.2.3-70-g09d2 From e51e01f4f066f9b0f412354cb8abab3642845d43 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 8 Feb 2015 19:39:36 -0800 Subject: Cleaned up python to remove redundant line. --- var/spack/packages/python/package.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'var') diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index 23b528b089..8bffbf393c 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -60,16 +60,16 @@ class Python(Package): 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) - # Add dependent packages' site-packages directory to PYTHONPATH + # Set PYTHONPATH to include site-packages dir for the + # extension and any other python extensions it depends on. + python_paths = [] for d in ext_spec.traverse(): if d.package.extends(self.spec): - os.environ['PYTHONPATH'] += ':' + os.path.join(d.prefix, self.site_packages_dir) + python_paths.append(os.path.join(d.prefix, self.site_packages_dir)) + os.environ['PYTHONPATH'] = ':'.join(python_paths) # ======================================================================== -- cgit v1.2.3-70-g09d2 From 20ec80295dbf2a36b633860c139d113f9c0e6388 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 8 Feb 2015 19:41:17 -0800 Subject: setup_extension_environment is now setup_dependent_environment. - other packages, like Qt, can now use this to set up relevant build variables and env vars for their dependencies. - not just extensions anymore. --- lib/spack/spack/package.py | 14 ++++++++------ var/spack/packages/python/package.py | 2 +- var/spack/packages/qt/package.py | 6 ++++++ 3 files changed, 15 insertions(+), 7 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index b905968540..6e319a1f87 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -829,10 +829,10 @@ class Package(object): 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) + # Allow dependencies to further set up the environment. + for dep_spec in self.spec.traverse(root=False): + dep_spec.package.setup_dependent_environment( + self.module, dep_spec, self.spec) if fake_install: self.do_fake_install() @@ -910,8 +910,8 @@ class Package(object): fromlist=[self.__class__.__name__]) - def setup_extension_environment(self, module, spec, ext_spec): - """Called before the install() method of extensions. + def setup_dependent_environment(self, module, spec, dependent_spec): + """Called before the install() method of dependents. Default implementation does nothing, but this can be overridden by an extendable package to set up the install @@ -930,6 +930,8 @@ class Package(object): put a 'python' Execuable object in the module scope for the extension package to simplify extension installs. + 3. A lot of Qt extensions need QTDIR set. This can be used to do that. + """ pass diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index 8bffbf393c..eed81d095c 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -46,7 +46,7 @@ class Python(Package): return os.path.join(self.python_lib_dir, 'site-packages') - def setup_extension_environment(self, module, spec, ext_spec): + def setup_dependent_environment(self, module, spec, ext_spec): """Called before python modules' install() methods. In most cases, extensions will only need to have one line:: diff --git a/var/spack/packages/qt/package.py b/var/spack/packages/qt/package.py index 6a55c89701..fcbcd2491a 100644 --- a/var/spack/packages/qt/package.py +++ b/var/spack/packages/qt/package.py @@ -1,3 +1,4 @@ +import os from spack import * class Qt(Package): @@ -20,6 +21,11 @@ class Qt(Package): depends_on("libmng") depends_on("jpeg") + def setup_dependent_environment(self, module, spec, dep_spec): + """Dependencies of Qt find it using the QTDIR environment variable.""" + os.environ['QTDIR'] = self.prefix + + def patch(self): # Fix qmake compilers in the default mkspec qmake_conf = 'mkspecs/common/g++-base.conf' -- cgit v1.2.3-70-g09d2 From 25af341954fa7c9a88943fe24cad88275ee00795 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 9 Feb 2015 02:54:49 -0800 Subject: Python package improvements. --- var/spack/packages/geos/package.py | 31 +++++++++++++++++++++++++++++ var/spack/packages/py-basemap/package.py | 9 ++------- var/spack/packages/py-biopython/package.py | 1 + var/spack/packages/py-gnuplot/package.py | 1 + var/spack/packages/py-libxml2/package.py | 1 + var/spack/packages/py-matplotlib/package.py | 3 +++ var/spack/packages/py-pyside/package.py | 31 +++++++++++++++++++++++++---- var/spack/packages/py-shiboken/package.py | 21 +++++++++++++++++++ var/spack/packages/python/package.py | 5 +++-- 9 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 var/spack/packages/geos/package.py create mode 100644 var/spack/packages/py-shiboken/package.py (limited to 'var') diff --git a/var/spack/packages/geos/package.py b/var/spack/packages/geos/package.py new file mode 100644 index 0000000000..4a2657e32f --- /dev/null +++ b/var/spack/packages/geos/package.py @@ -0,0 +1,31 @@ +from spack import * + +class Geos(Package): + """GEOS (Geometry Engine - Open Source) is a C++ port of the Java + Topology Suite (JTS). As such, it aims to contain the complete + functionality of JTS in C++. This includes all the OpenGIS + Simple Features for SQL spatial predicate functions and spatial + operators, as well as specific JTS enhanced topology functions.""" + + homepage = "http://trac.osgeo.org/geos/" + url = "http://download.osgeo.org/geos/geos-3.4.2.tar.bz2" + + version('3.4.2', 'fc5df2d926eb7e67f988a43a92683bae') + version('3.4.1', '4c930dec44c45c49cd71f3e0931ded7e') + version('3.4.0', 'e41318fc76b5dc764a69d43ac6b18488') + version('3.3.9', '4794c20f07721d5011c93efc6ccb8e4e') + version('3.3.8', '75be476d0831a2d14958fed76ca266de') + version('3.3.7', '95ab996d22672b067d92c7dee2170460') + version('3.3.6', '6fadfb941541875f4976f75fb0bbc800') + version('3.3.5', '2ba61afb7fe2c5ddf642d82d7b16e75b') + version('3.3.4', '1bb9f14d57ef06ffa41cb1d67acb55a1') + version('3.3.3', '8454e653d7ecca475153cc88fd1daa26') + + extends('python') + depends_on('swig') + + def install(self, spec, prefix): + configure("--prefix=%s" % prefix, + "--enable-python") + make() + make("install") diff --git a/var/spack/packages/py-basemap/package.py b/var/spack/packages/py-basemap/package.py index 7b6d8e7e65..45f1085ba1 100644 --- a/var/spack/packages/py-basemap/package.py +++ b/var/spack/packages/py-basemap/package.py @@ -8,18 +8,13 @@ class PyBasemap(Package): 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') + depends_on("geos") 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 + env['GEOS_DIR'] = spec['geos'].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 index 2ed04c389e..8ecaf48626 100644 --- a/var/spack/packages/py-biopython/package.py +++ b/var/spack/packages/py-biopython/package.py @@ -9,6 +9,7 @@ class PyBiopython(Package): extends('python') depends_on('py-mx') + depends_on('py-numpy') 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 index 0a2c073a49..ede4472c03 100644 --- a/var/spack/packages/py-gnuplot/package.py +++ b/var/spack/packages/py-gnuplot/package.py @@ -8,6 +8,7 @@ class PyGnuplot(Package): version('1.8', 'abd6f571e7aec68ae7db90a5217cd5b1') extends('python') + depends_on('py-numpy') 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 index 0dcefbd9cf..e645acb5dd 100644 --- a/var/spack/packages/py-libxml2/package.py +++ b/var/spack/packages/py-libxml2/package.py @@ -8,6 +8,7 @@ class PyLibxml2(Package): version('2.6.21', '229dd2b3d110a77defeeaa73af83f7f3') extends('python') + depends_on('libxml2') 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 index 5979ceeab0..8b8684c563 100644 --- a/var/spack/packages/py-matplotlib/package.py +++ b/var/spack/packages/py-matplotlib/package.py @@ -17,9 +17,12 @@ class PyMatplotlib(Package): depends_on('py-pytz') depends_on('py-nose') depends_on('py-numpy') + depends_on('qt') + 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 diff --git a/var/spack/packages/py-pyside/package.py b/var/spack/packages/py-pyside/package.py index b01e16d7e6..7528a0bf72 100644 --- a/var/spack/packages/py-pyside/package.py +++ b/var/spack/packages/py-pyside/package.py @@ -10,9 +10,32 @@ class PyPyside(Package): version('1.2.2', 'c45bc400c8a86d6b35f34c29e379e44d') extends('python') + depends_on('py-setuptools') + depends_on('qt@:4') + + + def patch(Self): + """Undo PySide RPATH handling and add Spack RPATH.""" + # Add Spack's standard CMake args to the sub-builds. + # They're called BY setup.py so we have to patch it. + filter_file( + r'OPTION_CMAKE,', + r'OPTION_CMAKE, ' + ( + '"-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=FALSE", ' + '"-DCMAKE_INSTALL_RPATH=%s",' % ':'.join(self.rpath)), + 'setup.py') + + # PySide tries to patch ELF files to remove RPATHs + # Disable this and go with the one we set. + filter_file( + r'rpath_cmd\(pyside_path, srcpath\)', + r'#rpath_cmd(pyside_path, srcpath)', + 'pyside_postinstall.py') + 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) + python('setup.py', 'install', + '--prefix=%s' % prefix, + '--jobs=%s' % make_jobs) + + diff --git a/var/spack/packages/py-shiboken/package.py b/var/spack/packages/py-shiboken/package.py new file mode 100644 index 0000000000..47abe64e65 --- /dev/null +++ b/var/spack/packages/py-shiboken/package.py @@ -0,0 +1,21 @@ +from spack import * + +class PyShiboken(Package): + """Shiboken generates bindings for C++ libraries using CPython source code.""" + homepage = "https://shiboken.readthedocs.org/" + url = "https://pypi.python.org/packages/source/S/Shiboken/Shiboken-1.2.2.tar.gz" + + version('1.2.2', '345cfebda221f525842e079a6141e555') + + # TODO: make build dependency + # depends_on("cmake") + + extends('python') + depends_on("py-setuptools") + depends_on("libxml2") + depends_on("qt@:4.8") + + def install(self, spec, prefix): + python('setup.py', 'install', + '--prefix=%s' % prefix, + '--jobs=%s' % make_jobs) diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index eed81d095c..4b3b31eb6b 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -1,9 +1,10 @@ -from spack import * -import spack import os import re from contextlib import closing +from spack import * +import spack + class Python(Package): """The Python programming language.""" -- cgit v1.2.3-70-g09d2 From 5c2608b032f04c063c437eca7d8360baaf6a2a16 Mon Sep 17 00:00:00 2001 From: "Gregory L. Lee" Date: Mon, 9 Feb 2015 15:55:18 -0800 Subject: typo: Self -> self --- var/spack/packages/py-pyside/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'var') diff --git a/var/spack/packages/py-pyside/package.py b/var/spack/packages/py-pyside/package.py index 7528a0bf72..1fd037d75f 100644 --- a/var/spack/packages/py-pyside/package.py +++ b/var/spack/packages/py-pyside/package.py @@ -14,7 +14,7 @@ class PyPyside(Package): depends_on('qt@:4') - def patch(Self): + def patch(self): """Undo PySide RPATH handling and add Spack RPATH.""" # Add Spack's standard CMake args to the sub-builds. # They're called BY setup.py so we have to patch it. -- cgit v1.2.3-70-g09d2 From c0c08799249fb56c281f62b3659e7cf7d7080188 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 01:58:35 -0800 Subject: Better extension activation/deactivation --- lib/spack/spack/cmd/extensions.py | 4 +- lib/spack/spack/directory_layout.py | 150 +++++++++++++++++++++++++---------- lib/spack/spack/package.py | 19 ++++- var/spack/packages/python/package.py | 16 ++-- 4 files changed, 133 insertions(+), 56 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py index ae73d8ac55..fc8e6842c3 100644 --- a/lib/spack/spack/cmd/extensions.py +++ b/lib/spack/spack/cmd/extensions.py @@ -89,10 +89,10 @@ def extensions(parser, args): spack.cmd.find.display_specs(installed, mode=args.mode) # List specs of activated extensions. - activated = spack.install_layout.get_extensions(spec) + activated = spack.install_layout.extension_map(spec) print if not activated: tty.msg("None activated.") return tty.msg("%d currently activated:" % len(activated)) - spack.cmd.find.display_specs(activated, mode=args.mode) + spack.cmd.find.display_specs(activated.values(), mode=args.mode) diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py index 37740720a2..562c0bd3ed 100644 --- a/lib/spack/spack/directory_layout.py +++ b/lib/spack/spack/directory_layout.py @@ -27,6 +27,7 @@ import os import exceptions import hashlib import shutil +import tempfile from contextlib import closing import llnl.util.tty as tty @@ -84,17 +85,38 @@ class DirectoryLayout(object): raise NotImplementedError() - def get_extensions(self, spec): - """Get a set of currently installed extension packages for a spec.""" + def extension_map(self, spec): + """Get a dict of currently installed extension packages for a spec. + + Dict maps { name : extension_spec } + Modifying dict does not affect internals of this layout. + """ + raise NotImplementedError() + + + def check_extension_conflict(self, spec, ext_spec): + """Ensure that ext_spec can be activated in spec. + + If not, raise ExtensionAlreadyInstalledError or + ExtensionConflictError. + """ + raise NotImplementedError() + + + def check_activated(self, spec, ext_spec): + """Ensure that ext_spec can be removed from spec. + + If not, raise NoSuchExtensionError. + """ raise NotImplementedError() - def add_extension(self, spec, extension_spec): + def add_extension(self, spec, ext_spec): """Add to the list of currently installed extensions.""" raise NotImplementedError() - def remove_extension(self, spec, extension_spec): + def remove_extension(self, spec, ext_spec): """Remove from the list of currently installed extensions.""" raise NotImplementedError() @@ -173,6 +195,8 @@ class SpecHashDirectoryLayout(DirectoryLayout): self.spec_file_name = spec_file_name self.extension_file_name = extension_file_name + # Cache of already written/read extension maps. + self._extension_maps = {} @property def hidden_file_paths(self): @@ -271,54 +295,94 @@ class SpecHashDirectoryLayout(DirectoryLayout): return join_path(self.path_for_spec(spec), self.extension_file_name) - def get_extensions(self, spec): + def _extension_map(self, spec): + """Get a dict spec> for all extensions currnetly + installed for this package.""" _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 + if not spec in self._extension_maps: + path = self.extension_file_path(spec) + if not os.path.exists(path): + self._extension_maps[spec] = {} + + else: + exts = {} + with closing(open(path)) as ext_file: + for line in ext_file: + try: + spec = Spec(line.strip()) + exts[spec.name] = spec + except spack.error.SpackError, e: + # TODO: do something better here -- should be + # resilient to corrupt files. + raise InvalidExtensionSpecError(str(e)) + self._extension_maps[spec] = exts + + return self._extension_maps[spec] + + + def extension_map(self, spec): + """Defensive copying version of _extension_map() for external API.""" + return self._extension_map(spec).copy() + + + def check_extension_conflict(self, spec, ext_spec): + exts = self._extension_map(spec) + if ext_spec.name in exts: + installed_spec = exts[ext_spec.name] + if ext_spec == installed_spec: + raise ExtensionAlreadyInstalledError(spec, ext_spec) + else: + raise ExtensionConflictError(spec, ext_spec, installed_spec) + + def check_activated(self, spec, ext_spec): + exts = self._extension_map(spec) + if (not ext_spec.name in exts) or (ext_spec != exts[ext_spec.name]): + raise NoSuchExtensionError(spec, ext_spec) - def write_extensions(self, spec, 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) + + # Create a temp file in the same directory as the actual file. + dirname, basename = os.path.split(path) + tmp = tempfile.NamedTemporaryFile( + prefix=basename, dir=dirname, delete=False) + + # Write temp file. + with closing(tmp): + for extension in sorted(extensions.values()): + tmp.write("%s\n" % extension) + + # Atomic update by moving tmpfile on top of old one. + os.rename(tmp.name, path) - def add_extension(self, spec, extension_spec): + def add_extension(self, spec, ext_spec): _check_concrete(spec) - _check_concrete(extension_spec) + _check_concrete(ext_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) + # Check whether it's already installed or if it's a conflict. + exts = self.extension_map(spec) + self.check_extension_conflict(spec, ext_spec) - exts.add(extension_spec) - self.write_extensions(spec, exts) + # do the actual adding. + exts[ext_spec.name] = ext_spec + self._write_extensions(spec, exts) - def remove_extension(self, spec, extension_spec): + def remove_extension(self, spec, ext_spec): _check_concrete(spec) - _check_concrete(extension_spec) + _check_concrete(ext_spec) - exts = self.get_extensions(spec) - if not extension_spec in exts: - raise NoSuchExtensionError(spec, extension_spec) + # Make sure it's installed before removing. + exts = self.extension_map(spec) + self.check_activated(spec, ext_spec) - exts.remove(extension_spec) - self.write_extensions(spec, exts) + # do the actual removing. + del exts[ext_spec.name] + self._write_extensions(spec, exts) class DirectoryLayoutError(SpackError): @@ -365,24 +429,24 @@ class InvalidExtensionSpecError(DirectoryLayoutError): class ExtensionAlreadyInstalledError(DirectoryLayoutError): """Raised when an extension is added to a package that already has it.""" - def __init__(self, spec, extension_spec): + def __init__(self, spec, ext_spec): super(ExtensionAlreadyInstalledError, self).__init__( - "%s is already installed in %s" % (extension_spec.short_spec, spec.short_spec)) + "%s is already installed in %s" % (ext_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): + def __init__(self, spec, ext_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)) + ext_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): + def __init__(self, spec, ext_spec): super(NoSuchExtensionError, self).__init__( "%s cannot be removed from %s because it's not installed."% ( - extension_spec.short_spec, spec.short_spec)) + ext_spec.short_spec, spec.short_spec)) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index b18d054990..a624c1ebf5 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -534,7 +534,8 @@ class Package(object): 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) + exts = spack.install_layout.extension_map(self.extendee_spec) + return (self.name in exts) and (exts[self.name] == self.spec) def preorder_traversal(self, visited=None, **kwargs): @@ -987,6 +988,8 @@ class Package(object): activate() directly. """ self._sanity_check_extension() + spack.install_layout.check_extension_conflict(self.extendee_spec, self.spec) + self.extendee_spec.package.activate(self, **self.extendee_args) spack.install_layout.add_extension(self.extendee_spec, self.spec) @@ -1014,12 +1017,22 @@ class Package(object): tree.merge(self.prefix, ignore=ignore) - def do_deactivate(self): + def do_deactivate(self, **kwargs): """Called on the extension to invoke extendee's deactivate() method.""" + force = kwargs.get('force', False) + self._sanity_check_extension() + + # Allow a force deactivate to happen. This can unlink + # spurious files if something was corrupted. + if not force: + spack.install_layout.check_activated(self.extendee_spec, self.spec) + self.extendee_spec.package.deactivate(self, **self.extendee_args) - if self.spec in spack.install_layout.get_extensions(self.extendee_spec): + # redundant activation check -- makes SURE the spec is not + # still activated even if something was wrong above. + if self.activated: spack.install_layout.remove_extension(self.extendee_spec, self.spec) tty.msg("Deactivated extension %s for %s." diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index 4b3b31eb6b..de7f412b52 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -98,9 +98,9 @@ class Python(Package): return ignore - def write_easy_install_pth(self, extensions): + def write_easy_install_pth(self, exts): paths = [] - for ext in extensions: + for ext in sorted(exts.values()): ext_site_packages = os.path.join(ext.prefix, self.site_packages_dir) easy_pth = "%s/easy-install.pth" % ext_site_packages @@ -139,15 +139,15 @@ class Python(Package): 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) + exts = spack.install_layout.extension_map(self.spec) + exts[ext_pkg.name] = ext_pkg.spec + self.write_easy_install_pth(exts) 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) + exts = spack.install_layout.extension_map(self.spec) + del exts[ext_pkg.name] + self.write_easy_install_pth(exts) -- cgit v1.2.3-70-g09d2 From 3c0048dd89e4d18ac95afd19b65d7ce54a48d862 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 01:59:36 -0800 Subject: py-sip installs properly into a prefix --- var/spack/packages/py-sip/package.py | 7 ++++++- var/spack/packages/python/package.py | 10 ++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'var') diff --git a/var/spack/packages/py-sip/package.py b/var/spack/packages/py-sip/package.py index 06aea35a74..6753bdd2a5 100644 --- a/var/spack/packages/py-sip/package.py +++ b/var/spack/packages/py-sip/package.py @@ -1,4 +1,5 @@ from spack import * +import os class PySip(Package): """SIP is a tool that makes it very easy to create Python bindings for C and C++ libraries.""" @@ -10,6 +11,10 @@ class PySip(Package): extends('python') def install(self, spec, prefix): - python('configure.py') + python('configure.py', + '--destdir=%s' % site_packages_dir, + '--bindir=%s' % spec.prefix.bin, + '--incdir=%s' % python_include_dir, + '--sipdir=%s' % os.path.join(spec.prefix.share, 'sip')) make() make('install') diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index de7f412b52..fb875a7eeb 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -42,6 +42,11 @@ class Python(Package): return os.path.join('lib', 'python%d.%d' % self.version[:2]) + @property + def python_include_dir(self): + return os.path.join('include', 'python%d.%d' % self.version[:2]) + + @property def site_packages_dir(self): return os.path.join(self.python_lib_dir, 'site-packages') @@ -58,8 +63,9 @@ class Python(Package): 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) + module.python_lib_dir = os.path.join(ext_spec.prefix, self.python_lib_dir) + module.python_include_dir = os.path.join(ext_spec.prefix, self.python_include_dir) + module.site_packages_dir = os.path.join(ext_spec.prefix, self.site_packages_dir) # Make the site packages directory if it does not exist already. mkdirp(module.site_packages_dir) -- cgit v1.2.3-70-g09d2 From 2f67cdaf10a3e64474f7ac242518fdfe93e9c87a Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 12:39:10 -0800 Subject: Better time output on build completion. --- lib/spack/spack/package.py | 16 ++++++++++++++-- var/spack/packages/py-pyqt/package.py | 21 +++++++++++++++++++++ var/spack/packages/py-pyqt4/package.py | 18 ------------------ 3 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 var/spack/packages/py-pyqt/package.py delete mode 100644 var/spack/packages/py-pyqt4/package.py (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index a624c1ebf5..c48816cb5b 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -848,8 +848,8 @@ class Package(object): build_time = self._total_time - self._fetch_time tty.msg("Successfully installed %s." % self.name, - "Fetch: %.2f sec. Build: %.2f sec. Total: %.2f sec." - % (self._fetch_time, build_time, self._total_time)) + "Fetch: %s. Build: %s. Total: %s." + % (_hms(self._fetch_time), _hms(build_time), _hms(self._total_time))) print_pkg(self.prefix) # Use os._exit here to avoid raising a SystemExit exception, @@ -1201,6 +1201,18 @@ def print_pkg(message): print message +def _hms(seconds): + """Convert time in seconds to hours, minutes, seconds.""" + m, s = divmod(seconds, 60) + h, m = divmod(m, 60) + + parts = [] + if h: parts.append("%dh" % h) + if m: parts.append("%dm" % m) + if s: parts.append("%.2fs" % s) + return ' '.join(parts) + + class FetchError(spack.error.SpackError): """Raised when something goes wrong during fetch.""" def __init__(self, message, long_msg=None): diff --git a/var/spack/packages/py-pyqt/package.py b/var/spack/packages/py-pyqt/package.py new file mode 100644 index 0000000000..cb40af351a --- /dev/null +++ b/var/spack/packages/py-pyqt/package.py @@ -0,0 +1,21 @@ +from spack import * + +class PyPyqt(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@4') # TODO: allow qt5 when conditional deps are supported. + depends_on('py-sip') + + def install(self, spec, prefix): + python('configure.py', + '--confirm-license', + '--destdir=%s' % site_packages_dir) + make() + make('install') diff --git a/var/spack/packages/py-pyqt4/package.py b/var/spack/packages/py-pyqt4/package.py deleted file mode 100644 index eeb1382560..0000000000 --- a/var/spack/packages/py-pyqt4/package.py +++ /dev/null @@ -1,18 +0,0 @@ -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') -- cgit v1.2.3-70-g09d2 From b11061f99d9e501f69d6d39bae56f0b69d17eaa1 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 12:40:02 -0800 Subject: Rename py-pyqt4 to py-pyqt. --- var/spack/packages/py-pyqt/package.py | 5 ++++- var/spack/packages/qt/package.py | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'var') diff --git a/var/spack/packages/py-pyqt/package.py b/var/spack/packages/py-pyqt/package.py index cb40af351a..8edca105bb 100644 --- a/var/spack/packages/py-pyqt/package.py +++ b/var/spack/packages/py-pyqt/package.py @@ -10,9 +10,12 @@ class PyPyqt(Package): version('4.11.3', '997c3e443165a89a559e0d96b061bf70') extends('python') - depends_on('qt@4') # TODO: allow qt5 when conditional deps are supported. depends_on('py-sip') + # TODO: allow qt5 when conditional deps are supported. + # TODO: Fix version matching so that @4 works like @:4 + depends_on('qt@:4') + def install(self, spec, prefix): python('configure.py', '--confirm-license', diff --git a/var/spack/packages/qt/package.py b/var/spack/packages/qt/package.py index fcbcd2491a..3b5096c4f0 100644 --- a/var/spack/packages/qt/package.py +++ b/var/spack/packages/qt/package.py @@ -43,9 +43,9 @@ class Qt(Package): '-fast', '-optimized-qmake', '-no-pch', -# phonon required for py-pyqt4 -# '-no-phonon', -# '-no-phonon-backend', + # phonon required for py-pyqt + # '-no-phonon', + # '-no-phonon-backend', '-no-openvg') make() make("install") -- cgit v1.2.3-70-g09d2 From ce011501f9b0184888ba2b6648fcf6d360f7c404 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 23:02:21 -0800 Subject: Add R package. --- var/spack/packages/R/package.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 var/spack/packages/R/package.py (limited to 'var') diff --git a/var/spack/packages/R/package.py b/var/spack/packages/R/package.py new file mode 100644 index 0000000000..2e6f65a742 --- /dev/null +++ b/var/spack/packages/R/package.py @@ -0,0 +1,33 @@ +from spack import * + +class R(Package): + """R is 'GNU S', a freely available language and environment for + statistical computing and graphics which provides a wide va + riety of statistical and graphical techniques: linear and + nonlinear modelling, statistical tests, time series analysis, + classification, clustering, etc. Please consult the R project + homepage for further information.""" + homepage = "http://www.example.com" + url = "http://cran.cnr.berkeley.edu/src/base/R-3/R-3.1.2.tar.gz" + + version('3.1.2', '3af29ec06704cbd08d4ba8d69250ae74') + + depends_on("readline") + depends_on("ncurses") + depends_on("icu") + depends_on("glib") + depends_on("zlib") + depends_on("libtiff") + depends_on("jpeg") + depends_on("cairo") + depends_on("pango") + depends_on("freetype") + depends_on("tcl") + depends_on("tk") + + def install(self, spec, prefix): + configure("--prefix=%s" % prefix, + "--enable-R-shlib", + "--enable-BLAS-shlib") + make() + make("install") -- cgit v1.2.3-70-g09d2 From 36579844d9f105b5c9182beed83a65bf0bb556a9 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 23:02:36 -0800 Subject: Add Tcl/Tk packages. --- var/spack/packages/tcl/package.py | 22 ++++++++++++++++++++++ var/spack/packages/tk/package.py | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 var/spack/packages/tcl/package.py create mode 100644 var/spack/packages/tk/package.py (limited to 'var') diff --git a/var/spack/packages/tcl/package.py b/var/spack/packages/tcl/package.py new file mode 100644 index 0000000000..529adf7788 --- /dev/null +++ b/var/spack/packages/tcl/package.py @@ -0,0 +1,22 @@ +from spack import * + +class Tcl(Package): + """Tcl (Tool Command Language) is a very powerful but easy to + learn dynamic programming language, suitable for a very wide + range of uses, including web and desktop applications, + networking, administration, testing and many more. Open source + and business-friendly, Tcl is a mature yet evolving language + that is truly cross platform, easily deployed and highly + extensible.""" + homepage = "http://www.tcl.tk" + + version('8.6.3', 'db382feca91754b7f93da16dc4cdad1f', + url="http://prdownloads.sourceforge.net/tcl/tcl8.6.3-src.tar.gz") + + depends_on('zlib') + + def install(self, spec, prefix): + with working_dir('unix'): + configure("--prefix=%s" % prefix) + make() + make("install") diff --git a/var/spack/packages/tk/package.py b/var/spack/packages/tk/package.py new file mode 100644 index 0000000000..96736f6f95 --- /dev/null +++ b/var/spack/packages/tk/package.py @@ -0,0 +1,22 @@ +from spack import * + +class Tk(Package): + """Tk is a graphical user interface toolkit that takes developing + desktop applications to a higher level than conventional + approaches. Tk is the standard GUI not only for Tcl, but for + many other dynamic languages, and can produce rich, native + applications that run unchanged across Windows, Mac OS X, Linux + and more.""" + homepage = "http://www.tcl.tk" + url = "http://prdownloads.sourceforge.net/tcl/tk8.6.3-src.tar.gz" + + version('src', '85ca4dbf4dcc19777fd456f6ee5d0221') + + depends_on("tcl") + + def install(self, spec, prefix): + with working_dir('unix'): + configure("--prefix=%s" % prefix, + "--with-tcl=%s" % spec['tcl'].prefix.lib) + make() + make("install") -- cgit v1.2.3-70-g09d2 From 65d60f92f5c479bdcf8b4cbfa244135a131d08f9 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 23:02:51 -0800 Subject: qhull package. --- var/spack/packages/qhull/package.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 var/spack/packages/qhull/package.py (limited to 'var') diff --git a/var/spack/packages/qhull/package.py b/var/spack/packages/qhull/package.py new file mode 100644 index 0000000000..9da4078a70 --- /dev/null +++ b/var/spack/packages/qhull/package.py @@ -0,0 +1,27 @@ +from spack import * + +class Qhull(Package): + """Qhull computes the convex hull, Delaunay triangulation, Voronoi + diagram, halfspace intersection about a point, furt hest-site + Delaunay triangulation, and furthest-site Voronoi diagram. The + source code runs in 2-d, 3-d, 4-d, and higher dimensions. Qhull + implements the Quickhull algorithm for computing the convex + hull. It handles roundoff errors from floating point + arithmetic. It computes volumes, surface areas, and + approximations to the convex hull. + + Qhull does not support triangulation of non-convex surfaces, + mesh generation of non-convex objects, medium-sized inputs in + 9-D and higher, alpha shapes, weighted Voronoi diagrams, + Voronoi volumes, or constrained Delaunay triangulations.""" + + homepage = "http://www.qhull.org" + + version('1.0', 'd0f978c0d8dfb2e919caefa56ea2953c', + url="http://www.qhull.org/download/qhull-2012.1-src.tgz") + + def install(self, spec, prefix): + with working_dir('spack-build', create=True): + cmake('..', *std_cmake_args) + make() + make("install") -- cgit v1.2.3-70-g09d2 From b86eb695523c235371169d0139486bcae15a7948 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 23:03:33 -0800 Subject: libgcrypt and libgpg-error packages. --- var/spack/packages/libgcrypt/package.py | 19 +++++++++++++++++++ var/spack/packages/libgpg-error/package.py | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 var/spack/packages/libgcrypt/package.py create mode 100644 var/spack/packages/libgpg-error/package.py (limited to 'var') diff --git a/var/spack/packages/libgcrypt/package.py b/var/spack/packages/libgcrypt/package.py new file mode 100644 index 0000000000..1d0a57f317 --- /dev/null +++ b/var/spack/packages/libgcrypt/package.py @@ -0,0 +1,19 @@ +from spack import * + +class Libgcrypt(Package): + """Libgcrypt is a general purpose cryptographic library based on + the code from GnuPG. It provides functions for all cryptographic + building blocks: symmetric ciphers, hash algorithms, MACs, public + key algorithms, large integer functions, random numbers and a lot + of supporting functions. """ + homepage = "http://www.gnu.org/software/libgcrypt/" + url = "ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.6.2.tar.bz2" + + version('1.6.2', 'b54395a93cb1e57619943c082da09d5f') + + depends_on("libgpg-error") + + def install(self, spec, prefix): + configure("--prefix=%s" % prefix) + make() + make("install") diff --git a/var/spack/packages/libgpg-error/package.py b/var/spack/packages/libgpg-error/package.py new file mode 100644 index 0000000000..6c1d1a10a7 --- /dev/null +++ b/var/spack/packages/libgpg-error/package.py @@ -0,0 +1,17 @@ +from spack import * + +class LibgpgError(Package): + """Libgpg-error is a small library that defines common error + values for all GnuPG components. Among these are GPG, GPGSM, + GPGME, GPG-Agent, libgcrypt, Libksba, DirMngr, Pinentry, + SmartCard Daemon and possibly more in the future. """ + + homepage = "https://www.gnupg.org/related_software/libgpg-error" + url = "ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.18.tar.bz2" + + version('1.18', '12312802d2065774b787cbfc22cc04e9') + + def install(self, spec, prefix): + configure("--prefix=%s" % prefix) + make() + make("install") -- cgit v1.2.3-70-g09d2 From 847ed8ad399973477a7889b6367911f10c56f6bf Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 23:04:04 -0800 Subject: Add libxslt, cleanup libxml2. --- var/spack/packages/libxml2/package.py | 3 +++ var/spack/packages/libxslt/package.py | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 var/spack/packages/libxslt/package.py (limited to 'var') diff --git a/var/spack/packages/libxml2/package.py b/var/spack/packages/libxml2/package.py index 5eaed36d94..72199d8def 100644 --- a/var/spack/packages/libxml2/package.py +++ b/var/spack/packages/libxml2/package.py @@ -9,6 +9,9 @@ class Libxml2(Package): version('2.9.2', '9e6a9aca9d155737868b3dc5fd82f788') + depends_on('zlib') + depends_on('xz') + def install(self, spec, prefix): configure("--prefix=%s" % prefix, "--without-python") diff --git a/var/spack/packages/libxslt/package.py b/var/spack/packages/libxslt/package.py new file mode 100644 index 0000000000..f97332d020 --- /dev/null +++ b/var/spack/packages/libxslt/package.py @@ -0,0 +1,24 @@ +from spack import * + +class Libxslt(Package): + """Libxslt is the XSLT C library developed for the GNOME + project. XSLT itself is a an XML language to define + transformation for XML. Libxslt is based on libxml2 the XML C + library developed for the GNOME project. It also implements + most of the EXSLT set of processor-portable extensions + functions and some of Saxon's evaluate and expressions + extensions.""" + homepage = "http://www.xmlsoft.org/XSLT/index.html" + url = "http://xmlsoft.org/sources/libxslt-1.1.28.tar.gz" + + version('1.1.28', '9667bf6f9310b957254fdcf6596600b7') + + depends_on("libxml2") + depends_on("xz") + depends_on("zlib") + depends_on("libgcrypt") + + def install(self, spec, prefix): + configure("--prefix=%s" % prefix) + make() + make("install") -- cgit v1.2.3-70-g09d2 From 8aa3afcfde9cebd34fdb534141c258c214ae4132 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sun, 15 Feb 2015 23:04:20 -0800 Subject: Python package cleanup. - Added a number of dependencies to python packages. - Python packages may still not build without some OS support. - Example: Numpy needs ATLAS, and will use a system ATLAS install. - Atlas requires turning off CPU throttling to build. - can't do this as a regular user -- how to build ATLAS with Spack - currnetly relying on a system ATLAS install. --- var/spack/packages/py-libxml2/package.py | 1 + var/spack/packages/py-matplotlib/package.py | 6 +++++- var/spack/packages/py-pyside/package.py | 1 - var/spack/packages/py-rpy2/package.py | 2 ++ var/spack/packages/py-scientificpython/package.py | 6 +++++- var/spack/packages/py-shiboken/package.py | 19 +++++++++++++++++++ 6 files changed, 32 insertions(+), 3 deletions(-) (limited to 'var') diff --git a/var/spack/packages/py-libxml2/package.py b/var/spack/packages/py-libxml2/package.py index e645acb5dd..59005428e4 100644 --- a/var/spack/packages/py-libxml2/package.py +++ b/var/spack/packages/py-libxml2/package.py @@ -9,6 +9,7 @@ class PyLibxml2(Package): extends('python') depends_on('libxml2') + depends_on('libxslt') 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 index 8b8684c563..f6b9c587fd 100644 --- a/var/spack/packages/py-matplotlib/package.py +++ b/var/spack/packages/py-matplotlib/package.py @@ -17,8 +17,12 @@ class PyMatplotlib(Package): depends_on('py-pytz') depends_on('py-nose') depends_on('py-numpy') - depends_on('qt') + depends_on('qt') + depends_on('bzip2') + depends_on('tcl') + depends_on('tk') + depends_on('qhull') def install(self, spec, prefix): python('setup.py', 'install', '--prefix=%s' % prefix) diff --git a/var/spack/packages/py-pyside/package.py b/var/spack/packages/py-pyside/package.py index 1fd037d75f..c165d9b3bf 100644 --- a/var/spack/packages/py-pyside/package.py +++ b/var/spack/packages/py-pyside/package.py @@ -13,7 +13,6 @@ class PyPyside(Package): depends_on('py-setuptools') depends_on('qt@:4') - def patch(self): """Undo PySide RPATH handling and add Spack RPATH.""" # Add Spack's standard CMake args to the sub-builds. diff --git a/var/spack/packages/py-rpy2/package.py b/var/spack/packages/py-rpy2/package.py index 3817059911..dd0c0672af 100644 --- a/var/spack/packages/py-rpy2/package.py +++ b/var/spack/packages/py-rpy2/package.py @@ -10,5 +10,7 @@ class PyRpy2(Package): extends('python') depends_on('py-setuptools') + depends_on('R') + 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 index 73600e6cb9..020d830703 100644 --- a/var/spack/packages/py-scientificpython/package.py +++ b/var/spack/packages/py-scientificpython/package.py @@ -1,7 +1,11 @@ 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.""" + """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" diff --git a/var/spack/packages/py-shiboken/package.py b/var/spack/packages/py-shiboken/package.py index 47abe64e65..e900947939 100644 --- a/var/spack/packages/py-shiboken/package.py +++ b/var/spack/packages/py-shiboken/package.py @@ -15,6 +15,25 @@ class PyShiboken(Package): depends_on("libxml2") depends_on("qt@:4.8") + def patch(self): + """Undo Shiboken RPATH handling and add Spack RPATH.""" + # Add Spack's standard CMake args to the sub-builds. + # They're called BY setup.py so we have to patch it. + filter_file( + r'OPTION_CMAKE,', + r'OPTION_CMAKE, ' + ( + '"-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=FALSE", ' + '"-DCMAKE_INSTALL_RPATH=%s",' % ':'.join(self.rpath)), + 'setup.py') + + # Shiboken tries to patch ELF files to remove RPATHs + # Disable this and go with the one we set. + filter_file( + r'^\s*rpath_cmd\(shiboken_path, srcpath\)', + r'#rpath_cmd(shiboken_path, srcpath)', + 'shiboken_postinstall.py') + + def install(self, spec, prefix): python('setup.py', 'install', '--prefix=%s' % prefix, -- cgit v1.2.3-70-g09d2 From 614c22fc1b1ac10c85ed9e27a1e59eeb88de0898 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 16 Feb 2015 12:41:22 -0800 Subject: Allow forced deactivation -- best effort unlinking spack deactivate -f will unlink even if Spack thinks the package isn't enabled. Made deactivate routines idempotent. --- lib/spack/llnl/util/link_tree.py | 4 ++++ lib/spack/spack/cmd/deactivate.py | 7 +++++-- lib/spack/spack/cmd/find.py | 3 +++ var/spack/packages/python/package.py | 5 +++-- 4 files changed, 15 insertions(+), 4 deletions(-) (limited to 'var') diff --git a/lib/spack/llnl/util/link_tree.py b/lib/spack/llnl/util/link_tree.py index 4e4e48316e..4d778eca1e 100644 --- a/lib/spack/llnl/util/link_tree.py +++ b/lib/spack/llnl/util/link_tree.py @@ -175,6 +175,10 @@ class LinkTree(object): kwargs['order'] = 'post' for src, dest in traverse_tree(self._root, dest_root, **kwargs): if os.path.isdir(src): + # Skip non-existing links. + if not os.path.exists(dest): + continue + if not os.path.isdir(dest): raise ValueError("File blocks directory: %s" % dest) diff --git a/lib/spack/spack/cmd/deactivate.py b/lib/spack/spack/cmd/deactivate.py index fd13f051df..f37dfd79ed 100644 --- a/lib/spack/spack/cmd/deactivate.py +++ b/lib/spack/spack/cmd/deactivate.py @@ -30,6 +30,9 @@ import spack.cmd description = "Deactivate a package extension." def setup_parser(subparser): + subparser.add_argument( + '-f', '--force', action='store_true', + help="Run deactivation even if spec is NOT currently activated.") subparser.add_argument( 'spec', nargs=argparse.REMAINDER, help="spec of package extension to deactivate.") @@ -44,7 +47,7 @@ def deactivate(parser, args): spack.db.get(specs[0]) spec = spack.cmd.disambiguate_spec(specs[0]) - if not spec.package.activated: + if not args.force and not spec.package.activated: tty.die("Package %s is not activated." % specs[0].short_spec) - spec.package.do_deactivate() + spec.package.do_deactivate(force=args.force) diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py index f6f503afe5..dee1dfece7 100644 --- a/lib/spack/spack/cmd/find.py +++ b/lib/spack/spack/cmd/find.py @@ -122,5 +122,8 @@ def find(parser, args): if not args.mode: args.mode = 'short' + + if sys.stdout.isatty(): + tty.msg("%d installed packages." % len(specs)) display_specs(specs, mode=args.mode) diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index fb875a7eeb..705d002e80 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -155,5 +155,6 @@ class Python(Package): super(Python, self).deactivate(ext_pkg, **args) exts = spack.install_layout.extension_map(self.spec) - del exts[ext_pkg.name] - self.write_easy_install_pth(exts) + if ext_pkg.name in exts: # Make deactivate idempotent. + del exts[ext_pkg.name] + self.write_easy_install_pth(exts) -- cgit v1.2.3-70-g09d2 From 13376efafc42c6eeb1bf0ad3b35f509924f1a6df Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 16 Feb 2015 21:53:34 -0800 Subject: Add package-specific rpath back to shiboken and pyside. --- var/spack/packages/py-pyside/package.py | 13 ++++++++++--- var/spack/packages/py-shiboken/package.py | 7 ++++++- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'var') diff --git a/var/spack/packages/py-pyside/package.py b/var/spack/packages/py-pyside/package.py index c165d9b3bf..6583431124 100644 --- a/var/spack/packages/py-pyside/package.py +++ b/var/spack/packages/py-pyside/package.py @@ -1,5 +1,4 @@ from spack import * -import spack.package import os class PyPyside(Package): @@ -9,25 +8,33 @@ class PyPyside(Package): version('1.2.2', 'c45bc400c8a86d6b35f34c29e379e44d') + # TODO: make build dependency + # depends_on("cmake") + extends('python') depends_on('py-setuptools') depends_on('qt@:4') def patch(self): """Undo PySide RPATH handling and add Spack RPATH.""" + # Figure out the special RPATH + pypkg = self.spec['python'].package + rpath = self.rpath + rpath.append(os.path.join(self.prefix, pypkg.site_packages_dir, 'PySide')) + # Add Spack's standard CMake args to the sub-builds. # They're called BY setup.py so we have to patch it. filter_file( r'OPTION_CMAKE,', r'OPTION_CMAKE, ' + ( '"-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=FALSE", ' - '"-DCMAKE_INSTALL_RPATH=%s",' % ':'.join(self.rpath)), + '"-DCMAKE_INSTALL_RPATH=%s",' % ':'.join(rpath)), 'setup.py') # PySide tries to patch ELF files to remove RPATHs # Disable this and go with the one we set. filter_file( - r'rpath_cmd\(pyside_path, srcpath\)', + r'^\s*rpath_cmd\(pyside_path, srcpath\)', r'#rpath_cmd(pyside_path, srcpath)', 'pyside_postinstall.py') diff --git a/var/spack/packages/py-shiboken/package.py b/var/spack/packages/py-shiboken/package.py index e900947939..e4bf4ce07e 100644 --- a/var/spack/packages/py-shiboken/package.py +++ b/var/spack/packages/py-shiboken/package.py @@ -1,4 +1,5 @@ from spack import * +import os class PyShiboken(Package): """Shiboken generates bindings for C++ libraries using CPython source code.""" @@ -19,11 +20,15 @@ class PyShiboken(Package): """Undo Shiboken RPATH handling and add Spack RPATH.""" # Add Spack's standard CMake args to the sub-builds. # They're called BY setup.py so we have to patch it. + pypkg = self.spec['python'].package + rpath = self.rpath + rpath.append(os.path.join(self.prefix, pypkg.site_packages_dir, 'Shiboken')) + filter_file( r'OPTION_CMAKE,', r'OPTION_CMAKE, ' + ( '"-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=FALSE", ' - '"-DCMAKE_INSTALL_RPATH=%s",' % ':'.join(self.rpath)), + '"-DCMAKE_INSTALL_RPATH=%s",' % ':'.join(rpath)), 'setup.py') # Shiboken tries to patch ELF files to remove RPATHs -- cgit v1.2.3-70-g09d2 From 06d6b0b205095f849ace216aa51393b907cf821b Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 16 Feb 2015 21:53:55 -0800 Subject: More py-setuptools dependencies added. --- var/spack/packages/py-ipython/package.py | 1 + var/spack/packages/py-mpi4py/package.py | 1 + var/spack/packages/py-nose/package.py | 1 + var/spack/packages/py-pylint/package.py | 4 ++-- var/spack/packages/py-virtualenv/package.py | 1 + 5 files changed, 6 insertions(+), 2 deletions(-) (limited to 'var') diff --git a/var/spack/packages/py-ipython/package.py b/var/spack/packages/py-ipython/package.py index 731e661dfd..907ea9edcd 100644 --- a/var/spack/packages/py-ipython/package.py +++ b/var/spack/packages/py-ipython/package.py @@ -9,6 +9,7 @@ class PyIpython(Package): extends('python') depends_on('py-pygments') + depends_on('py-setuptools') def install(self, spec, prefix): python('setup.py', 'install', '--prefix=%s' % prefix) diff --git a/var/spack/packages/py-mpi4py/package.py b/var/spack/packages/py-mpi4py/package.py index fdea340dc2..8001689a18 100644 --- a/var/spack/packages/py-mpi4py/package.py +++ b/var/spack/packages/py-mpi4py/package.py @@ -7,6 +7,7 @@ class PyMpi4py(Package): version('1.3.1', 'dbe9d22bdc8ed965c23a7ceb6f32fc3c') extends('python') + depends_on('py-setuptools') depends_on('mpi') def install(self, spec, prefix): diff --git a/var/spack/packages/py-nose/package.py b/var/spack/packages/py-nose/package.py index 6df84e831d..b902a35fbb 100644 --- a/var/spack/packages/py-nose/package.py +++ b/var/spack/packages/py-nose/package.py @@ -10,6 +10,7 @@ class PyNose(Package): version('1.3.4', '6ed7169887580ddc9a8e16048d38274d') 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 index ebde861f94..7a6ee7dbbc 100644 --- a/var/spack/packages/py-pylint/package.py +++ b/var/spack/packages/py-pylint/package.py @@ -8,9 +8,9 @@ class PyPylint(Package): version('1.4.1', 'df7c679bdcce5019389038847e4de622') -# extends('python') - extends('python', ignore=lambda f:re.match(r"site.py*", f)) + extends('python') depends_on('py-nose') + depends_on('py-setuptools') 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 index c1b359e164..9d94c2dcda 100644 --- a/var/spack/packages/py-virtualenv/package.py +++ b/var/spack/packages/py-virtualenv/package.py @@ -9,6 +9,7 @@ class PyVirtualenv(Package): version('1.11.6', 'f61cdd983d2c4e6aeabb70b1060d6f49') extends('python') + depends_on('py-setuptools') def clean(self): if os.path.exists('build'): -- cgit v1.2.3-70-g09d2 From 67db8ddca8ac7ab9adeb827a7dadd34a385b2b6b Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Tue, 17 Feb 2015 00:21:15 -0800 Subject: Factor ignore logic into a predicate builder. --- lib/spack/llnl/util/lang.py | 31 +++++++++++++++++++++++++++++++ var/spack/packages/python/package.py | 25 +++++++++++-------------- 2 files changed, 42 insertions(+), 14 deletions(-) (limited to 'var') diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py index db15da0506..332367f537 100644 --- a/lib/spack/llnl/util/lang.py +++ b/lib/spack/llnl/util/lang.py @@ -291,6 +291,37 @@ def check_kwargs(kwargs, fun): % (next(kwargs.iterkeys()), fun.__name__)) +def match_predicate(*args): + """Utility function for making string matching predicates. + + Each arg can be a: + - regex + - list or tuple of regexes + - predicate that takes a string. + + This returns a predicate that is true if: + - any arg regex matches + - any regex in a list or tuple of regexes matches. + - any predicate in args matches. + """ + def match(string): + for arg in args: + if isinstance(arg, basestring): + if re.search(arg, string): + return True + elif isinstance(arg, list) or isinstance(arg, tuple): + if any(re.search(i, string) for i in arg): + return True + elif callable(arg): + if arg(string): + return True + else: + raise ValueError("args to match_predicate must be regex, " + "list of regexes, or callable.") + return False + return match + + class RequiredAttributeError(ValueError): def __init__(self, message): super(RequiredAttributeError, self).__init__(message) diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py index 705d002e80..31a12ea653 100644 --- a/var/spack/packages/python/package.py +++ b/var/spack/packages/python/package.py @@ -1,6 +1,7 @@ import os import re from contextlib import closing +from llnl.util.lang import match_predicate from spack import * import spack @@ -85,23 +86,19 @@ class Python(Package): def python_ignore(self, ext_pkg, args): """Add some ignore files to activate/deactivate args.""" - orig_ignore = args.get('ignore', lambda f: False) + ignore_arg = 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$'] + # 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$') + # 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 + return match_predicate(ignore_arg, patterns) def write_easy_install_pth(self, exts): -- cgit v1.2.3-70-g09d2 From 57f331e2acf75c5bf4c464d0df888fd882295a68 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Tue, 17 Feb 2015 00:22:18 -0800 Subject: Ignore conflicting nose tests in py-nose and py-matplotlib. --- var/spack/packages/py-matplotlib/package.py | 3 ++- var/spack/packages/py-nose/package.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'var') diff --git a/var/spack/packages/py-matplotlib/package.py b/var/spack/packages/py-matplotlib/package.py index f6b9c587fd..04037f004e 100644 --- a/var/spack/packages/py-matplotlib/package.py +++ b/var/spack/packages/py-matplotlib/package.py @@ -8,7 +8,8 @@ class PyMatplotlib(Package): version('1.4.2', '7d22efb6cce475025733c50487bd8898') - extends('python') + extends('python', ignore=r'bin/nosetests.*$') + depends_on('py-pyside') depends_on('py-ipython') depends_on('py-pyparsing') diff --git a/var/spack/packages/py-nose/package.py b/var/spack/packages/py-nose/package.py index b902a35fbb..155019289d 100644 --- a/var/spack/packages/py-nose/package.py +++ b/var/spack/packages/py-nose/package.py @@ -9,7 +9,7 @@ class PyNose(Package): version('1.3.4', '6ed7169887580ddc9a8e16048d38274d') - extends('python') + extends('python', ignore=r'bin/nosetests.*$') depends_on('py-setuptools') def install(self, spec, prefix): -- cgit v1.2.3-70-g09d2