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
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:
bytes = script.read(2)
if bytes != '#!':
@ -47,14 +47,21 @@ def shebang_too_long(path):
def filter_shebang(path):
"""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"
os.rename(path, backup)
with open(backup, 'r') as bak_file:
original = bak_file.read()
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)
copy_mode(backup, path)
@ -63,15 +70,29 @@ def filter_shebang(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):
"""This hook edits scripts so that they call /bin/bash
$spack_prefix/bin/sbang instead of something longer than the
shebang limit."""
if not os.path.isdir(pkg.prefix.bin):
return
for file in os.listdir(pkg.prefix.bin):
path = os.path.join(pkg.prefix.bin, file)
if shebang_too_long(path):
filter_shebang(path)
filter_shebangs_in_directory(pkg.prefix.bin)

View File

@ -825,7 +825,7 @@ def _resource_stage(self, resource):
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):
"""Called by commands to install a package and its dependencies.
@ -834,8 +834,9 @@ def do_install(self,
Args:
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.
By default, stage is destroyed only if there are no exceptions.
keep_stage -- By default, stage is destroyed only if there are no
exceptions during build. Set to True to keep the stage
even with exceptions.
ignore_deps -- Do not install dependencies before installing this package.
fake -- Don't really build -- install fake stub files instead.
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.
"""
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.
Parameters:
url_or_fetch_strategy
@ -108,10 +109,9 @@ def __init__(self, url_or_fetch_strategy, name=None, mirror_path=None, keep=None
keep
By default, when used as a context manager, the Stage
is cleaned up when everything goes well, and it is
kept intact when an exception is raised. You can
override this behavior by setting keep to True
(always keep) or False (always delete).
is deleted on exit when no exceptions are raised.
Pass True to keep the stage intact even if no
exceptions are raised.
"""
# TODO: fetch/stage coupling needs to be reworked -- the logic
# TODO: here is convoluted and not modular enough.
@ -166,12 +166,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
Returns:
Boolean
"""
if self.keep is None:
# Default: delete when there are no exceptions.
if exc_type is None: self.destroy()
elif not self.keep:
# Overridden. Either always keep or always delete.
# Delete when there are no exceptions, unless asked to keep.
if exc_type is None and not self.keep:
self.destroy()
@ -195,8 +191,8 @@ def _need_to_create_path(self):
real_tmp = os.path.realpath(self.tmp_root)
if spack.use_tmp_stage:
# If we're using a tmp dir, it's a link, and it points at the right spot,
# then keep it.
# If we're using a tmp dir, it's a link, and it points at the
# right spot, then keep it.
if (real_path.startswith(real_tmp) and os.path.exists(real_path)):
return False
else:
@ -441,7 +437,7 @@ def __enter__(self):
def __exit__(self, exc_type, exc_val, exc_tb):
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)
#

View File

@ -65,7 +65,8 @@
'lock',
'database',
'namespace_trie',
'yaml']
'yaml',
'sbang']
def list_tests():
@ -87,20 +88,20 @@ def run(names, outputDir, verbose=False):
"Valid names are:")
colify(sorted(test_names), indent=4)
sys.exit(1)
tally = Tally()
for test in names:
module = 'spack.test.' + test
print module
tty.msg("Running test: %s" % test)
runOpts = ["--with-%s" % spack.test.tally_plugin.Tally.name]
if outputDir:
xmlOutputFname = "unittests-{0}.xml".format(test)
xmlOutputPath = join_path(outputDir, xmlOutputFname)
runOpts += ["--with-xunit",
runOpts += ["--with-xunit",
"--xunit-file={0}".format(xmlOutputPath)]
argv = [""] + runOpts + [module]
result = nose.run(argv=argv, addplugins=[tally])

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.assertFalse('foobar' in os.listdir(stage.source_path))
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('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('szip', default=False, description='Enable szip support')
@ -74,6 +73,13 @@ def install(self, spec, prefix):
self.validate(spec)
# Handle compilation after spec validation
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:
extra_args.append('--enable-debug=all')
else:
@ -84,9 +90,6 @@ def install(self, spec, prefix):
else:
extra_args.append('--enable-static-exec')
if '+unsupported' in spec:
extra_args.append("--enable-unsupported")
if '+cxx' in spec:
extra_args.append('--enable-cxx')

View File

@ -28,8 +28,9 @@ class Mpfr(Package):
"""The MPFR library is a C library for multiple-precision
floating-point computations with correct rounding."""
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.2', 'ee2c3ac63bf0c2359bf08fc3ee094c19')

View File

@ -15,6 +15,7 @@ class Petsc(Package):
version('3.5.3', 'd4fd2734661e89f18ac6014b5dd1ef2f')
version('3.5.2', 'ad170802b3b058b5deb9cd1f968e7e13')
version('3.5.1', 'a557e029711ebf425544e117ffa44d8f')
version('3.4.4', '7edbc68aa6d8d6a3295dd5f6c2f6979d')
variant('shared', default=True, description='Enables the build of shared libraries')
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('hypre', default=True, description='Activates support for Hypre')
# Build dependencies
depends_on('python @2.6:2.9') # requires Python for building
# Virtual dependencies
depends_on('blas')
depends_on('lapack')
depends_on('mpi', when='+mpi')
# Build dependencies
depends_on('python @2.6:2.7')
# Other dependencies
depends_on('boost', when='+boost')
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('hypre', when='+hypre+mpi')
depends_on('hypre', when='+hypre+mpi')
def mpi_dependent_options(self):
if '~mpi' in self.spec:
@ -50,7 +51,12 @@ def mpi_dependent_options(self):
'--with-mpi=0'
]
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:
errors = ['incompatible variants given'] + errors
raise RuntimeError('\n'.join(errors))
@ -70,7 +76,7 @@ def install(self, spec, prefix):
'--with-blas-lapack-dir=%s' % spec['lapack'].prefix
])
# Activates library support if needed
for library in ('metis', 'boost', 'hfd5', 'hypre', 'parmetis'):
for library in ('metis', 'boost', 'hdf5', 'hypre', 'parmetis'):
options.append(
'--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)
)
configure('--prefix=%s' % prefix, *options)
# PETSc has its own way of doing parallel make.
make('MAKE_NP=%s' % make_jobs, parallel=False)
make("install")

View File

@ -12,33 +12,44 @@ class Thrift(Package):
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("automake")
depends_on("bison")
depends_on("boost")
depends_on("flex")
depends_on("jdk")
depends_on("libtool")
depends_on("openssl")
depends_on("python")
depends_on('jdk')
depends_on('autoconf')
depends_on('automake')
depends_on('libtool')
depends_on('boost@1.53:')
depends_on('bison')
depends_on('flex')
depends_on('openssl')
# 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):
env["PY_PREFIX"] = prefix
env["JAVA_PREFIX"] = prefix
env['PY_PREFIX'] = prefix
env['JAVA_HOME'] = spec['jdk'].prefix
configure("--prefix=%s" % prefix,
"--with-boost=%s" % spec['boost'].prefix,
"--with-c=no",
"--with-go=no",
"--with-python=yes",
"--with-lua=no",
"--with-php=no",
"--with-qt4=no",
"--enable-tests=no")
# configure options
options = ['--prefix=%s' % prefix]
options.append('--with-boost=%s' % spec['boost'].prefix)
options.append('--enable-tests=no')
options.append('--with-c=%s' % ('yes' if '+c' in spec else 'no'))
options.append('--with-python=%s' % ('yes' if '+python' in spec else '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("install")