Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Kelly (KT) Thompson 2016-03-10 09:09:16 -07:00
commit 280384fce3
10 changed files with 238 additions and 70 deletions

View File

@ -35,7 +35,7 @@
shebang_limit = 127 shebang_limit = 127
def shebang_too_long(path): def shebang_too_long(path):
"""Detects whether an file has a shebang line that is too long.""" """Detects whether a file has a shebang line that is too long."""
with open(path, 'r') as script: with open(path, 'r') as script:
bytes = script.read(2) bytes = script.read(2)
if bytes != '#!': if bytes != '#!':
@ -47,14 +47,21 @@ def shebang_too_long(path):
def filter_shebang(path): def filter_shebang(path):
"""Adds a second shebang line, using sbang, at the beginning of a file.""" """Adds a second shebang line, using sbang, at the beginning of a file."""
with open(path, 'r') as original_file:
original = original_file.read()
# This line will be prepended to file
new_sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.spack_root
# Skip files that are already using sbang.
if original.startswith(new_sbang_line):
return
backup = path + ".shebang.bak" backup = path + ".shebang.bak"
os.rename(path, backup) os.rename(path, backup)
with open(backup, 'r') as bak_file:
original = bak_file.read()
with open(path, 'w') as new_file: with open(path, 'w') as new_file:
new_file.write('#!/bin/bash %s/bin/sbang\n' % spack.spack_root) new_file.write(new_sbang_line)
new_file.write(original) new_file.write(original)
copy_mode(backup, path) copy_mode(backup, path)
@ -63,15 +70,29 @@ def filter_shebang(path):
tty.warn("Patched overly long shebang in %s" % path) tty.warn("Patched overly long shebang in %s" % path)
def filter_shebangs_in_directory(directory):
for file in os.listdir(directory):
path = os.path.join(directory, file)
# only handle files
if not os.path.isfile(path):
continue
# only handle links that resolve within THIS package's prefix.
if os.path.islink(path):
real_path = os.path.realpath(path)
if not real_path.startswith(directory + os.sep):
continue
# test the file for a long shebang, and filter
if shebang_too_long(path):
filter_shebang(path)
def post_install(pkg): def post_install(pkg):
"""This hook edits scripts so that they call /bin/bash """This hook edits scripts so that they call /bin/bash
$spack_prefix/bin/sbang instead of something longer than the $spack_prefix/bin/sbang instead of something longer than the
shebang limit.""" shebang limit."""
if not os.path.isdir(pkg.prefix.bin): if not os.path.isdir(pkg.prefix.bin):
return return
filter_shebangs_in_directory(pkg.prefix.bin)
for file in os.listdir(pkg.prefix.bin):
path = os.path.join(pkg.prefix.bin, file)
if shebang_too_long(path):
filter_shebang(path)

View File

@ -825,7 +825,7 @@ def _resource_stage(self, resource):
def do_install(self, def do_install(self,
keep_prefix=False, keep_stage=None, ignore_deps=False, keep_prefix=False, keep_stage=False, ignore_deps=False,
skip_patch=False, verbose=False, make_jobs=None, fake=False): skip_patch=False, verbose=False, make_jobs=None, fake=False):
"""Called by commands to install a package and its dependencies. """Called by commands to install a package and its dependencies.
@ -834,8 +834,9 @@ def do_install(self,
Args: Args:
keep_prefix -- Keep install prefix on failure. By default, destroys it. keep_prefix -- Keep install prefix on failure. By default, destroys it.
keep_stage -- Set to True or false to always keep or always delete stage. keep_stage -- By default, stage is destroyed only if there are no
By default, stage is destroyed only if there are no exceptions. exceptions during build. Set to True to keep the stage
even with exceptions.
ignore_deps -- Do not install dependencies before installing this package. ignore_deps -- Do not install dependencies before installing this package.
fake -- Don't really build -- install fake stub files instead. fake -- Don't really build -- install fake stub files instead.
skip_patch -- Skip patch stage of build if True. skip_patch -- Skip patch stage of build if True.

View File

@ -88,7 +88,8 @@ class Stage(object):
similar, and are intended to persist for only one run of spack. similar, and are intended to persist for only one run of spack.
""" """
def __init__(self, url_or_fetch_strategy, name=None, mirror_path=None, keep=None): def __init__(self, url_or_fetch_strategy,
name=None, mirror_path=None, keep=False):
"""Create a stage object. """Create a stage object.
Parameters: Parameters:
url_or_fetch_strategy url_or_fetch_strategy
@ -108,10 +109,9 @@ def __init__(self, url_or_fetch_strategy, name=None, mirror_path=None, keep=None
keep keep
By default, when used as a context manager, the Stage By default, when used as a context manager, the Stage
is cleaned up when everything goes well, and it is is deleted on exit when no exceptions are raised.
kept intact when an exception is raised. You can Pass True to keep the stage intact even if no
override this behavior by setting keep to True exceptions are raised.
(always keep) or False (always delete).
""" """
# TODO: fetch/stage coupling needs to be reworked -- the logic # TODO: fetch/stage coupling needs to be reworked -- the logic
# TODO: here is convoluted and not modular enough. # TODO: here is convoluted and not modular enough.
@ -166,12 +166,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
Returns: Returns:
Boolean Boolean
""" """
if self.keep is None: # Delete when there are no exceptions, unless asked to keep.
# Default: delete when there are no exceptions. if exc_type is None and not self.keep:
if exc_type is None: self.destroy()
elif not self.keep:
# Overridden. Either always keep or always delete.
self.destroy() self.destroy()
@ -195,8 +191,8 @@ def _need_to_create_path(self):
real_tmp = os.path.realpath(self.tmp_root) real_tmp = os.path.realpath(self.tmp_root)
if spack.use_tmp_stage: if spack.use_tmp_stage:
# If we're using a tmp dir, it's a link, and it points at the right spot, # If we're using a tmp dir, it's a link, and it points at the
# then keep it. # right spot, then keep it.
if (real_path.startswith(real_tmp) and os.path.exists(real_path)): if (real_path.startswith(real_tmp) and os.path.exists(real_path)):
return False return False
else: else:
@ -441,7 +437,7 @@ def __enter__(self):
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
for item in reversed(self): for item in reversed(self):
item.keep = getattr(self, 'keep', None) item.keep = getattr(self, 'keep', False)
item.__exit__(exc_type, exc_val, exc_tb) item.__exit__(exc_type, exc_val, exc_tb)
# #

View File

@ -65,7 +65,8 @@
'lock', 'lock',
'database', 'database',
'namespace_trie', 'namespace_trie',
'yaml'] 'yaml',
'sbang']
def list_tests(): def list_tests():

View File

@ -0,0 +1,93 @@
##############################################################################
# Copyright (c) 2013-2015, 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://github.com/llnl/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
##############################################################################
"""\
Test that Spack's shebang filtering works correctly.
"""
import os
import unittest
import tempfile
import shutil
from llnl.util.filesystem import *
from spack.hooks.sbang import filter_shebangs_in_directory
import spack
short_line = "#!/this/is/short/bin/bash\n"
long_line = "#!/this/" + ('x' * 200) + "/is/long\n"
sbang_line = '#!/bin/bash %s/bin/sbang\n' % spack.spack_root
last_line = "last!\n"
class SbangTest(unittest.TestCase):
def setUp(self):
self.tempdir = tempfile.mkdtemp()
# make sure we can ignore non-files
directory = os.path.join(self.tempdir, 'dir')
mkdirp(directory)
# Script with short shebang
self.short_shebang = os.path.join(self.tempdir, 'short')
with open(self.short_shebang, 'w') as f:
f.write(short_line)
f.write(last_line)
# Script with long shebang
self.long_shebang = os.path.join(self.tempdir, 'long')
with open(self.long_shebang, 'w') as f:
f.write(long_line)
f.write(last_line)
# Script already using sbang.
self.has_shebang = os.path.join(self.tempdir, 'shebang')
with open(self.has_shebang, 'w') as f:
f.write(sbang_line)
f.write(long_line)
f.write(last_line)
def tearDown(self):
shutil.rmtree(self.tempdir, ignore_errors=True)
def test_shebang_handling(self):
filter_shebangs_in_directory(self.tempdir)
# Make sure this is untouched
with open(self.short_shebang, 'r') as f:
self.assertEqual(f.readline(), short_line)
self.assertEqual(f.readline(), last_line)
# Make sure this got patched.
with open(self.long_shebang, 'r') as f:
self.assertEqual(f.readline(), sbang_line)
self.assertEqual(f.readline(), long_line)
self.assertEqual(f.readline(), last_line)
# Make sure this is untouched
with open(self.has_shebang, 'r') as f:
self.assertEqual(f.readline(), sbang_line)
self.assertEqual(f.readline(), long_line)
self.assertEqual(f.readline(), last_line)

View File

@ -277,3 +277,38 @@ def test_restage(self):
self.check_chdir_to_source(stage, stage_name) self.check_chdir_to_source(stage, stage_name)
self.assertFalse('foobar' in os.listdir(stage.source_path)) self.assertFalse('foobar' in os.listdir(stage.source_path))
self.check_destroy(stage, stage_name) self.check_destroy(stage, stage_name)
def test_no_keep_without_exceptions(self):
with Stage(archive_url, name=stage_name, keep=False) as stage:
pass
self.check_destroy(stage, stage_name)
def test_keep_without_exceptions(self):
with Stage(archive_url, name=stage_name, keep=True) as stage:
pass
path = self.get_stage_path(stage, stage_name)
self.assertTrue(os.path.isdir(path))
def test_no_keep_with_exceptions(self):
try:
with Stage(archive_url, name=stage_name, keep=False) as stage:
raise Exception()
path = self.get_stage_path(stage, stage_name)
self.assertTrue(os.path.isdir(path))
except:
pass # ignore here.
def test_keep_exceptions(self):
try:
with Stage(archive_url, name=stage_name, keep=True) as stage:
raise Exception()
path = self.get_stage_path(stage, stage_name)
self.assertTrue(os.path.isdir(path))
except:
pass # ignore here.

View File

@ -46,7 +46,6 @@ class Hdf5(Package):
variant('cxx', default=True, description='Enable C++ support') variant('cxx', default=True, description='Enable C++ support')
variant('fortran', default=True, description='Enable Fortran support') variant('fortran', default=True, description='Enable Fortran support')
variant('unsupported', default=True, description='Enables unsupported configuration options')
variant('mpi', default=False, description='Enable MPI support') variant('mpi', default=False, description='Enable MPI support')
variant('szip', default=False, description='Enable szip support') variant('szip', default=False, description='Enable szip support')
@ -74,6 +73,13 @@ def install(self, spec, prefix):
self.validate(spec) self.validate(spec)
# Handle compilation after spec validation # Handle compilation after spec validation
extra_args = [] extra_args = []
# Always enable this option. This does not actually enable any
# features: it only *allows* the user to specify certain
# combinations of other arguments. Enabling it just skips a
# sanity check in configure, so this doesn't merit a variant.
extra_args.append("--enable-unsupported")
if '+debug' in spec: if '+debug' in spec:
extra_args.append('--enable-debug=all') extra_args.append('--enable-debug=all')
else: else:
@ -84,9 +90,6 @@ def install(self, spec, prefix):
else: else:
extra_args.append('--enable-static-exec') extra_args.append('--enable-static-exec')
if '+unsupported' in spec:
extra_args.append("--enable-unsupported")
if '+cxx' in spec: if '+cxx' in spec:
extra_args.append('--enable-cxx') extra_args.append('--enable-cxx')

View File

@ -28,8 +28,9 @@ class Mpfr(Package):
"""The MPFR library is a C library for multiple-precision """The MPFR library is a C library for multiple-precision
floating-point computations with correct rounding.""" floating-point computations with correct rounding."""
homepage = "http://www.mpfr.org" homepage = "http://www.mpfr.org"
url = "http://www.mpfr.org/mpfr-current/mpfr-3.1.3.tar.bz2" url = "https://gforge.inria.fr/frs/download.php/latestfile/159/mpfr-3.1.2.tar.bz2"
version('3.1.4', 'b8a2f6b0e68bef46e53da2ac439e1cf4')
version('3.1.3', '5fdfa3cfa5c86514ee4a241a1affa138') version('3.1.3', '5fdfa3cfa5c86514ee4a241a1affa138')
version('3.1.2', 'ee2c3ac63bf0c2359bf08fc3ee094c19') version('3.1.2', 'ee2c3ac63bf0c2359bf08fc3ee094c19')

View File

@ -15,6 +15,7 @@ class Petsc(Package):
version('3.5.3', 'd4fd2734661e89f18ac6014b5dd1ef2f') version('3.5.3', 'd4fd2734661e89f18ac6014b5dd1ef2f')
version('3.5.2', 'ad170802b3b058b5deb9cd1f968e7e13') version('3.5.2', 'ad170802b3b058b5deb9cd1f968e7e13')
version('3.5.1', 'a557e029711ebf425544e117ffa44d8f') version('3.5.1', 'a557e029711ebf425544e117ffa44d8f')
version('3.4.4', '7edbc68aa6d8d6a3295dd5f6c2f6979d')
variant('shared', default=True, description='Enables the build of shared libraries') variant('shared', default=True, description='Enables the build of shared libraries')
variant('mpi', default=True, description='Activates MPI support') variant('mpi', default=True, description='Activates MPI support')
@ -25,21 +26,21 @@ class Petsc(Package):
variant('boost', default=True, description='Activates support for Boost') variant('boost', default=True, description='Activates support for Boost')
variant('hypre', default=True, description='Activates support for Hypre') variant('hypre', default=True, description='Activates support for Hypre')
# Build dependencies
depends_on('python @2.6:2.9') # requires Python for building
# Virtual dependencies # Virtual dependencies
depends_on('blas') depends_on('blas')
depends_on('lapack') depends_on('lapack')
depends_on('mpi', when='+mpi') depends_on('mpi', when='+mpi')
# Build dependencies
depends_on('python @2.6:2.7')
# Other dependencies # Other dependencies
depends_on('boost', when='+boost') depends_on('boost', when='+boost')
depends_on('metis', when='+metis') depends_on('metis', when='+metis')
depends_on('hdf5~cxx~unsupported+mpi', when='+hdf5+mpi') depends_on('hdf5+mpi', when='+hdf5+mpi')
depends_on('parmetis', when='+metis+mpi') depends_on('parmetis', when='+metis+mpi')
depends_on('hypre', when='+hypre+mpi') depends_on('hypre', when='+hypre+mpi')
def mpi_dependent_options(self): def mpi_dependent_options(self):
if '~mpi' in self.spec: if '~mpi' in self.spec:
@ -50,7 +51,12 @@ def mpi_dependent_options(self):
'--with-mpi=0' '--with-mpi=0'
] ]
error_message_fmt = '\t{library} support requires "+mpi" to be activated' error_message_fmt = '\t{library} support requires "+mpi" to be activated'
errors = [error_message_fmt.format(library=x) for x in ('hdf5', 'hypre') if ('+'+x) in self.spec]
# If mpi is disabled (~mpi), it's an error to have any of these enabled.
# This generates a list of any such errors.
errors = [error_message_fmt.format(library=x)
for x in ('hdf5', 'hypre', 'parmetis')
if ('+'+x) in self.spec]
if errors: if errors:
errors = ['incompatible variants given'] + errors errors = ['incompatible variants given'] + errors
raise RuntimeError('\n'.join(errors)) raise RuntimeError('\n'.join(errors))
@ -70,7 +76,7 @@ def install(self, spec, prefix):
'--with-blas-lapack-dir=%s' % spec['lapack'].prefix '--with-blas-lapack-dir=%s' % spec['lapack'].prefix
]) ])
# Activates library support if needed # Activates library support if needed
for library in ('metis', 'boost', 'hfd5', 'hypre', 'parmetis'): for library in ('metis', 'boost', 'hdf5', 'hypre', 'parmetis'):
options.append( options.append(
'--with-{library}={value}'.format(library=library, value=('1' if library in spec else '0')) '--with-{library}={value}'.format(library=library, value=('1' if library in spec else '0'))
) )
@ -79,8 +85,8 @@ def install(self, spec, prefix):
'--with-{library}-dir={path}'.format(library=library, path=spec[library].prefix) '--with-{library}-dir={path}'.format(library=library, path=spec[library].prefix)
) )
configure('--prefix=%s' % prefix, *options) configure('--prefix=%s' % prefix, *options)
# PETSc has its own way of doing parallel make. # PETSc has its own way of doing parallel make.
make('MAKE_NP=%s' % make_jobs, parallel=False) make('MAKE_NP=%s' % make_jobs, parallel=False)
make("install") make("install")

View File

@ -12,33 +12,44 @@ class Thrift(Package):
version('0.9.2', '89f63cc4d0100912f4a1f8a9dee63678') version('0.9.2', '89f63cc4d0100912f4a1f8a9dee63678')
extends("python") # Currently only support for c-family and python
variant('c', default=True, description="Build support for C-family languages")
variant('python', default=True, description="Build support for python")
depends_on("autoconf") depends_on('jdk')
depends_on("automake") depends_on('autoconf')
depends_on("bison") depends_on('automake')
depends_on("boost") depends_on('libtool')
depends_on("flex") depends_on('boost@1.53:')
depends_on("jdk") depends_on('bison')
depends_on("libtool") depends_on('flex')
depends_on("openssl") depends_on('openssl')
depends_on("python")
# Variant dependencies
extends('python', when='+python')
depends_on('zlib', when='+c')
depends_on('libevent', when='+c')
# Compilation fails for most languages, fortunately cpp installs fine
# All other languages (yes, including C) are omitted until someone needs them
def install(self, spec, prefix): def install(self, spec, prefix):
env["PY_PREFIX"] = prefix env['PY_PREFIX'] = prefix
env["JAVA_PREFIX"] = prefix env['JAVA_HOME'] = spec['jdk'].prefix
configure("--prefix=%s" % prefix, # configure options
"--with-boost=%s" % spec['boost'].prefix, options = ['--prefix=%s' % prefix]
"--with-c=no",
"--with-go=no", options.append('--with-boost=%s' % spec['boost'].prefix)
"--with-python=yes", options.append('--enable-tests=no')
"--with-lua=no",
"--with-php=no", options.append('--with-c=%s' % ('yes' if '+c' in spec else 'no'))
"--with-qt4=no", options.append('--with-python=%s' % ('yes' if '+python' in spec else 'no'))
"--enable-tests=no") options.append('--with-java=%s' % ('yes' if '+java' in spec else 'no'))
options.append('--with-go=%s' % ('yes' if '+go' in spec else 'no'))
options.append('--with-lua=%s' % ('yes' if '+lua' in spec else 'no'))
options.append('--with-php=%s' % ('yes' if '+php' in spec else 'no'))
options.append('--with-qt4=%s' % ('yes' if '+qt4' in spec else 'no'))
configure(*options)
make() make()
make("install") make("install")