Merge branch 'develop'
This commit is contained in:
commit
de030c9932
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@
|
||||
.idea
|
||||
/etc/spackconfig
|
||||
/share/spack/dotkit
|
||||
/share/spack/modules
|
||||
|
18
README.md
18
README.md
@ -35,4 +35,20 @@ for Spack is also available.
|
||||
Authors
|
||||
----------------
|
||||
Spack was written by Todd Gamblin, tgamblin@llnl.gov.
|
||||
LLNL-CODE-647188
|
||||
|
||||
Significant contributions were also made by the following awesome
|
||||
people:
|
||||
|
||||
* David Beckingsale
|
||||
* David Boehme
|
||||
* Luc Jaulmes
|
||||
* Matt Legendre
|
||||
* Greg Lee
|
||||
* Adam Moody
|
||||
|
||||
Release
|
||||
----------------
|
||||
Spack is released under an LGPL license. For more details see the
|
||||
LICENSE file.
|
||||
|
||||
``LLNL-CODE-647188``
|
||||
|
13
bin/spack
13
bin/spack
@ -24,11 +24,10 @@
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import sys
|
||||
if not sys.version_info[:2] >= (2,7):
|
||||
sys.exit("Spack requires Python 2.7. Version was %s." % sys.version_info)
|
||||
if not sys.version_info[:2] >= (2,6):
|
||||
sys.exit("Spack requires Python 2.6. Version was %s." % sys.version_info)
|
||||
|
||||
import os
|
||||
import argparse
|
||||
|
||||
# Find spack's location and its prefix.
|
||||
SPACK_FILE = os.path.realpath(os.path.expanduser(__file__))
|
||||
@ -51,6 +50,7 @@ del SPACK_FILE, SPACK_PREFIX, SPACK_LIB_PATH
|
||||
import llnl.util.tty as tty
|
||||
import spack
|
||||
from spack.error import SpackError
|
||||
from external import argparse
|
||||
|
||||
# Command parsing
|
||||
parser = argparse.ArgumentParser(
|
||||
@ -75,6 +75,13 @@ for cmd in spack.cmd.commands:
|
||||
module = spack.cmd.get_module(cmd)
|
||||
subparser = subparsers.add_parser(cmd, help=module.description)
|
||||
module.setup_parser(subparser)
|
||||
|
||||
# Just print help and exit if run with no arguments at all
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
# actually parse the args.
|
||||
args = parser.parse_args()
|
||||
|
||||
# Set up environment based on args.
|
||||
|
6
lib/spack/env/cc
vendored
6
lib/spack/env/cc
vendored
@ -1,12 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
if not sys.version_info[:2] >= (2,7):
|
||||
sys.exit("Spack requires Python 2.7. Version was %s." % sys.version_info)
|
||||
if not sys.version_info[:2] >= (2,6):
|
||||
sys.exit("Spack requires Python 2.6. Version was %s." % sys.version_info)
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import argparse
|
||||
from contextlib import closing
|
||||
|
||||
# Import spack parameters through the build environment.
|
||||
@ -18,6 +17,7 @@ if not spack_lib:
|
||||
# Grab a minimal set of spack packages
|
||||
sys.path.append(spack_lib)
|
||||
from spack.compilation import *
|
||||
from external import argparse
|
||||
import llnl.util.tty as tty
|
||||
|
||||
spack_prefix = get_env_var("SPACK_PREFIX")
|
||||
|
33
lib/spack/external/__init__.py
vendored
Normal file
33
lib/spack/external/__init__.py
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
"""
|
||||
This module contains external, potentially separately licensed,
|
||||
packages that are included in spack.
|
||||
|
||||
So far:
|
||||
argparse: We include our own version to be Python 2.6 compatible.
|
||||
pyqver2: External script to query required python version of python source code.
|
||||
Used for ensuring 2.6 compatibility.
|
||||
"""
|
2382
lib/spack/external/argparse.py
vendored
Normal file
2382
lib/spack/external/argparse.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
30
lib/spack/external/functools.py
vendored
Normal file
30
lib/spack/external/functools.py
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
#
|
||||
# Backport of Python 2.7's total_ordering.
|
||||
#
|
||||
|
||||
def total_ordering(cls):
|
||||
"""Class decorator that fills in missing ordering methods"""
|
||||
convert = {
|
||||
'__lt__': [('__gt__', lambda self, other: not (self < other or self == other)),
|
||||
('__le__', lambda self, other: self < other or self == other),
|
||||
('__ge__', lambda self, other: not self < other)],
|
||||
'__le__': [('__ge__', lambda self, other: not self <= other or self == other),
|
||||
('__lt__', lambda self, other: self <= other and not self == other),
|
||||
('__gt__', lambda self, other: not self <= other)],
|
||||
'__gt__': [('__lt__', lambda self, other: not (self > other or self == other)),
|
||||
('__ge__', lambda self, other: self > other or self == other),
|
||||
('__le__', lambda self, other: not self > other)],
|
||||
'__ge__': [('__le__', lambda self, other: (not self >= other) or self == other),
|
||||
('__gt__', lambda self, other: self >= other and not self == other),
|
||||
('__lt__', lambda self, other: not self >= other)]
|
||||
}
|
||||
roots = set(dir(cls)) & set(convert)
|
||||
if not roots:
|
||||
raise ValueError('must define at least one ordering operation: < > <= >=')
|
||||
root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__
|
||||
for opname, opfunc in convert[root]:
|
||||
if opname not in roots:
|
||||
opfunc.__name__ = opname
|
||||
opfunc.__doc__ = getattr(int, opname).__doc__
|
||||
setattr(cls, opname, opfunc)
|
||||
return cls
|
262
lib/spack/external/ordereddict.py
vendored
Normal file
262
lib/spack/external/ordereddict.py
vendored
Normal file
@ -0,0 +1,262 @@
|
||||
#
|
||||
# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
|
||||
# Passes Python2.7's test suite and incorporates all the latest updates.
|
||||
#
|
||||
# From http://code.activestate.com/recipes/576693-ordered-dictionary-for-py24/
|
||||
# This file is in the public domain, and has no particular license.
|
||||
#
|
||||
try:
|
||||
from thread import get_ident as _get_ident
|
||||
except ImportError:
|
||||
from dummy_thread import get_ident as _get_ident
|
||||
|
||||
try:
|
||||
from _abcoll import KeysView, ValuesView, ItemsView
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class OrderedDict(dict):
|
||||
'Dictionary that remembers insertion order'
|
||||
# An inherited dict maps keys to values.
|
||||
# The inherited dict provides __getitem__, __len__, __contains__, and get.
|
||||
# The remaining methods are order-aware.
|
||||
# Big-O running times for all methods are the same as for regular dictionaries.
|
||||
|
||||
# The internal self.__map dictionary maps keys to links in a doubly linked list.
|
||||
# The circular doubly linked list starts and ends with a sentinel element.
|
||||
# The sentinel element never gets deleted (this simplifies the algorithm).
|
||||
# Each link is stored as a list of length three: [PREV, NEXT, KEY].
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
'''Initialize an ordered dictionary. Signature is the same as for
|
||||
regular dictionaries, but keyword arguments are not recommended
|
||||
because their insertion order is arbitrary.
|
||||
|
||||
'''
|
||||
if len(args) > 1:
|
||||
raise TypeError('expected at most 1 arguments, got %d' % len(args))
|
||||
try:
|
||||
self.__root
|
||||
except AttributeError:
|
||||
self.__root = root = [] # sentinel node
|
||||
root[:] = [root, root, None]
|
||||
self.__map = {}
|
||||
self.__update(*args, **kwds)
|
||||
|
||||
def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
|
||||
'od.__setitem__(i, y) <==> od[i]=y'
|
||||
# Setting a new item creates a new link which goes at the end of the linked
|
||||
# list, and the inherited dictionary is updated with the new key/value pair.
|
||||
if key not in self:
|
||||
root = self.__root
|
||||
last = root[0]
|
||||
last[1] = root[0] = self.__map[key] = [last, root, key]
|
||||
dict_setitem(self, key, value)
|
||||
|
||||
def __delitem__(self, key, dict_delitem=dict.__delitem__):
|
||||
'od.__delitem__(y) <==> del od[y]'
|
||||
# Deleting an existing item uses self.__map to find the link which is
|
||||
# then removed by updating the links in the predecessor and successor nodes.
|
||||
dict_delitem(self, key)
|
||||
link_prev, link_next, key = self.__map.pop(key)
|
||||
link_prev[1] = link_next
|
||||
link_next[0] = link_prev
|
||||
|
||||
def __iter__(self):
|
||||
'od.__iter__() <==> iter(od)'
|
||||
root = self.__root
|
||||
curr = root[1]
|
||||
while curr is not root:
|
||||
yield curr[2]
|
||||
curr = curr[1]
|
||||
|
||||
def __reversed__(self):
|
||||
'od.__reversed__() <==> reversed(od)'
|
||||
root = self.__root
|
||||
curr = root[0]
|
||||
while curr is not root:
|
||||
yield curr[2]
|
||||
curr = curr[0]
|
||||
|
||||
def clear(self):
|
||||
'od.clear() -> None. Remove all items from od.'
|
||||
try:
|
||||
for node in self.__map.itervalues():
|
||||
del node[:]
|
||||
root = self.__root
|
||||
root[:] = [root, root, None]
|
||||
self.__map.clear()
|
||||
except AttributeError:
|
||||
pass
|
||||
dict.clear(self)
|
||||
|
||||
def popitem(self, last=True):
|
||||
'''od.popitem() -> (k, v), return and remove a (key, value) pair.
|
||||
Pairs are returned in LIFO order if last is true or FIFO order if false.
|
||||
|
||||
'''
|
||||
if not self:
|
||||
raise KeyError('dictionary is empty')
|
||||
root = self.__root
|
||||
if last:
|
||||
link = root[0]
|
||||
link_prev = link[0]
|
||||
link_prev[1] = root
|
||||
root[0] = link_prev
|
||||
else:
|
||||
link = root[1]
|
||||
link_next = link[1]
|
||||
root[1] = link_next
|
||||
link_next[0] = root
|
||||
key = link[2]
|
||||
del self.__map[key]
|
||||
value = dict.pop(self, key)
|
||||
return key, value
|
||||
|
||||
# -- the following methods do not depend on the internal structure --
|
||||
|
||||
def keys(self):
|
||||
'od.keys() -> list of keys in od'
|
||||
return list(self)
|
||||
|
||||
def values(self):
|
||||
'od.values() -> list of values in od'
|
||||
return [self[key] for key in self]
|
||||
|
||||
def items(self):
|
||||
'od.items() -> list of (key, value) pairs in od'
|
||||
return [(key, self[key]) for key in self]
|
||||
|
||||
def iterkeys(self):
|
||||
'od.iterkeys() -> an iterator over the keys in od'
|
||||
return iter(self)
|
||||
|
||||
def itervalues(self):
|
||||
'od.itervalues -> an iterator over the values in od'
|
||||
for k in self:
|
||||
yield self[k]
|
||||
|
||||
def iteritems(self):
|
||||
'od.iteritems -> an iterator over the (key, value) items in od'
|
||||
for k in self:
|
||||
yield (k, self[k])
|
||||
|
||||
def update(*args, **kwds):
|
||||
'''od.update(E, **F) -> None. Update od from dict/iterable E and F.
|
||||
|
||||
If E is a dict instance, does: for k in E: od[k] = E[k]
|
||||
If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
|
||||
Or if E is an iterable of items, does: for k, v in E: od[k] = v
|
||||
In either case, this is followed by: for k, v in F.items(): od[k] = v
|
||||
|
||||
'''
|
||||
if len(args) > 2:
|
||||
raise TypeError('update() takes at most 2 positional '
|
||||
'arguments (%d given)' % (len(args),))
|
||||
elif not args:
|
||||
raise TypeError('update() takes at least 1 argument (0 given)')
|
||||
self = args[0]
|
||||
# Make progressively weaker assumptions about "other"
|
||||
other = ()
|
||||
if len(args) == 2:
|
||||
other = args[1]
|
||||
if isinstance(other, dict):
|
||||
for key in other:
|
||||
self[key] = other[key]
|
||||
elif hasattr(other, 'keys'):
|
||||
for key in other.keys():
|
||||
self[key] = other[key]
|
||||
else:
|
||||
for key, value in other:
|
||||
self[key] = value
|
||||
for key, value in kwds.items():
|
||||
self[key] = value
|
||||
|
||||
__update = update # let subclasses override update without breaking __init__
|
||||
|
||||
__marker = object()
|
||||
|
||||
def pop(self, key, default=__marker):
|
||||
'''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
|
||||
If key is not found, d is returned if given, otherwise KeyError is raised.
|
||||
|
||||
'''
|
||||
if key in self:
|
||||
result = self[key]
|
||||
del self[key]
|
||||
return result
|
||||
if default is self.__marker:
|
||||
raise KeyError(key)
|
||||
return default
|
||||
|
||||
def setdefault(self, key, default=None):
|
||||
'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
|
||||
if key in self:
|
||||
return self[key]
|
||||
self[key] = default
|
||||
return default
|
||||
|
||||
def __repr__(self, _repr_running={}):
|
||||
'od.__repr__() <==> repr(od)'
|
||||
call_key = id(self), _get_ident()
|
||||
if call_key in _repr_running:
|
||||
return '...'
|
||||
_repr_running[call_key] = 1
|
||||
try:
|
||||
if not self:
|
||||
return '%s()' % (self.__class__.__name__,)
|
||||
return '%s(%r)' % (self.__class__.__name__, self.items())
|
||||
finally:
|
||||
del _repr_running[call_key]
|
||||
|
||||
def __reduce__(self):
|
||||
'Return state information for pickling'
|
||||
items = [[k, self[k]] for k in self]
|
||||
inst_dict = vars(self).copy()
|
||||
for k in vars(OrderedDict()):
|
||||
inst_dict.pop(k, None)
|
||||
if inst_dict:
|
||||
return (self.__class__, (items,), inst_dict)
|
||||
return self.__class__, (items,)
|
||||
|
||||
def copy(self):
|
||||
'od.copy() -> a shallow copy of od'
|
||||
return self.__class__(self)
|
||||
|
||||
@classmethod
|
||||
def fromkeys(cls, iterable, value=None):
|
||||
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
|
||||
and values equal to v (which defaults to None).
|
||||
|
||||
'''
|
||||
d = cls()
|
||||
for key in iterable:
|
||||
d[key] = value
|
||||
return d
|
||||
|
||||
def __eq__(self, other):
|
||||
'''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
|
||||
while comparison to a regular mapping is order-insensitive.
|
||||
|
||||
'''
|
||||
if isinstance(other, OrderedDict):
|
||||
return len(self)==len(other) and self.items() == other.items()
|
||||
return dict.__eq__(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
# -- the following methods are only used in Python 2.7 --
|
||||
|
||||
def viewkeys(self):
|
||||
"od.viewkeys() -> a set-like object providing a view on od's keys"
|
||||
return KeysView(self)
|
||||
|
||||
def viewvalues(self):
|
||||
"od.viewvalues() -> an object providing a view on od's values"
|
||||
return ValuesView(self)
|
||||
|
||||
def viewitems(self):
|
||||
"od.viewitems() -> a set-like object providing a view on od's items"
|
||||
return ItemsView(self)
|
393
lib/spack/external/pyqver2.py
vendored
Executable file
393
lib/spack/external/pyqver2.py
vendored
Executable file
@ -0,0 +1,393 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# pyqver2.py
|
||||
# by Greg Hewgill
|
||||
# https://github.com/ghewgill/pyqver
|
||||
#
|
||||
# This software is provided 'as-is', without any express or implied
|
||||
# warranty. In no event will the author be held liable for any damages
|
||||
# arising from the use of this software.
|
||||
#
|
||||
# Permission is granted to anyone to use this software for any purpose,
|
||||
# including commercial applications, and to alter it and redistribute it
|
||||
# freely, subject to the following restrictions:
|
||||
#
|
||||
# 1. The origin of this software must not be misrepresented; you must not
|
||||
# claim that you wrote the original software. If you use this software
|
||||
# in a product, an acknowledgment in the product documentation would be
|
||||
# appreciated but is not required.
|
||||
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||
# misrepresented as being the original software.
|
||||
# 3. This notice may not be removed or altered from any source distribution.
|
||||
#
|
||||
# Copyright (c) 2009-2013 Greg Hewgill http://hewgill.com
|
||||
#
|
||||
|
||||
import compiler
|
||||
import platform
|
||||
import sys
|
||||
|
||||
StandardModules = {
|
||||
"__future__": (2, 1),
|
||||
"abc": (2, 6),
|
||||
"argparse": (2, 7),
|
||||
"ast": (2, 6),
|
||||
"atexit": (2, 0),
|
||||
"bz2": (2, 3),
|
||||
"cgitb": (2, 2),
|
||||
"collections": (2, 4),
|
||||
"contextlib": (2, 5),
|
||||
"cookielib": (2, 4),
|
||||
"cProfile": (2, 5),
|
||||
"csv": (2, 3),
|
||||
"ctypes": (2, 5),
|
||||
"datetime": (2, 3),
|
||||
"decimal": (2, 4),
|
||||
"difflib": (2, 1),
|
||||
"DocXMLRPCServer": (2, 3),
|
||||
"dummy_thread": (2, 3),
|
||||
"dummy_threading": (2, 3),
|
||||
"email": (2, 2),
|
||||
"fractions": (2, 6),
|
||||
"functools": (2, 5),
|
||||
"future_builtins": (2, 6),
|
||||
"hashlib": (2, 5),
|
||||
"heapq": (2, 3),
|
||||
"hmac": (2, 2),
|
||||
"hotshot": (2, 2),
|
||||
"HTMLParser": (2, 2),
|
||||
"importlib": (2, 7),
|
||||
"inspect": (2, 1),
|
||||
"io": (2, 6),
|
||||
"itertools": (2, 3),
|
||||
"json": (2, 6),
|
||||
"logging": (2, 3),
|
||||
"modulefinder": (2, 3),
|
||||
"msilib": (2, 5),
|
||||
"multiprocessing": (2, 6),
|
||||
"netrc": (1, 5, 2),
|
||||
"numbers": (2, 6),
|
||||
"optparse": (2, 3),
|
||||
"ossaudiodev": (2, 3),
|
||||
"pickletools": (2, 3),
|
||||
"pkgutil": (2, 3),
|
||||
"platform": (2, 3),
|
||||
"pydoc": (2, 1),
|
||||
"runpy": (2, 5),
|
||||
"sets": (2, 3),
|
||||
"shlex": (1, 5, 2),
|
||||
"SimpleXMLRPCServer": (2, 2),
|
||||
"spwd": (2, 5),
|
||||
"sqlite3": (2, 5),
|
||||
"ssl": (2, 6),
|
||||
"stringprep": (2, 3),
|
||||
"subprocess": (2, 4),
|
||||
"sysconfig": (2, 7),
|
||||
"tarfile": (2, 3),
|
||||
"textwrap": (2, 3),
|
||||
"timeit": (2, 3),
|
||||
"unittest": (2, 1),
|
||||
"uuid": (2, 5),
|
||||
"warnings": (2, 1),
|
||||
"weakref": (2, 1),
|
||||
"winsound": (1, 5, 2),
|
||||
"wsgiref": (2, 5),
|
||||
"xml.dom": (2, 0),
|
||||
"xml.dom.minidom": (2, 0),
|
||||
"xml.dom.pulldom": (2, 0),
|
||||
"xml.etree.ElementTree": (2, 5),
|
||||
"xml.parsers.expat":(2, 0),
|
||||
"xml.sax": (2, 0),
|
||||
"xml.sax.handler": (2, 0),
|
||||
"xml.sax.saxutils": (2, 0),
|
||||
"xml.sax.xmlreader":(2, 0),
|
||||
"xmlrpclib": (2, 2),
|
||||
"zipfile": (1, 6),
|
||||
"zipimport": (2, 3),
|
||||
"_ast": (2, 5),
|
||||
"_winreg": (2, 0),
|
||||
}
|
||||
|
||||
Functions = {
|
||||
"all": (2, 5),
|
||||
"any": (2, 5),
|
||||
"collections.Counter": (2, 7),
|
||||
"collections.defaultdict": (2, 5),
|
||||
"collections.OrderedDict": (2, 7),
|
||||
"functools.total_ordering": (2, 7),
|
||||
"enumerate": (2, 3),
|
||||
"frozenset": (2, 4),
|
||||
"itertools.compress": (2, 7),
|
||||
"math.erf": (2, 7),
|
||||
"math.erfc": (2, 7),
|
||||
"math.expm1": (2, 7),
|
||||
"math.gamma": (2, 7),
|
||||
"math.lgamma": (2, 7),
|
||||
"memoryview": (2, 7),
|
||||
"next": (2, 6),
|
||||
"os.getresgid": (2, 7),
|
||||
"os.getresuid": (2, 7),
|
||||
"os.initgroups": (2, 7),
|
||||
"os.setresgid": (2, 7),
|
||||
"os.setresuid": (2, 7),
|
||||
"reversed": (2, 4),
|
||||
"set": (2, 4),
|
||||
"subprocess.check_call": (2, 5),
|
||||
"subprocess.check_output": (2, 7),
|
||||
"sum": (2, 3),
|
||||
"symtable.is_declared_global": (2, 7),
|
||||
"weakref.WeakSet": (2, 7),
|
||||
}
|
||||
|
||||
Identifiers = {
|
||||
"False": (2, 2),
|
||||
"True": (2, 2),
|
||||
}
|
||||
|
||||
def uniq(a):
|
||||
if len(a) == 0:
|
||||
return []
|
||||
else:
|
||||
return [a[0]] + uniq([x for x in a if x != a[0]])
|
||||
|
||||
class NodeChecker(object):
|
||||
def __init__(self):
|
||||
self.vers = dict()
|
||||
self.vers[(2,0)] = []
|
||||
def add(self, node, ver, msg):
|
||||
if ver not in self.vers:
|
||||
self.vers[ver] = []
|
||||
self.vers[ver].append((node.lineno, msg))
|
||||
def default(self, node):
|
||||
for child in node.getChildNodes():
|
||||
self.visit(child)
|
||||
def visitCallFunc(self, node):
|
||||
def rollup(n):
|
||||
if isinstance(n, compiler.ast.Name):
|
||||
return n.name
|
||||
elif isinstance(n, compiler.ast.Getattr):
|
||||
r = rollup(n.expr)
|
||||
if r:
|
||||
return r + "." + n.attrname
|
||||
name = rollup(node.node)
|
||||
if name:
|
||||
v = Functions.get(name)
|
||||
if v is not None:
|
||||
self.add(node, v, name)
|
||||
self.default(node)
|
||||
def visitClass(self, node):
|
||||
if node.bases:
|
||||
self.add(node, (2,2), "new-style class")
|
||||
if node.decorators:
|
||||
self.add(node, (2,6), "class decorator")
|
||||
self.default(node)
|
||||
def visitDictComp(self, node):
|
||||
self.add(node, (2,7), "dictionary comprehension")
|
||||
self.default(node)
|
||||
def visitFloorDiv(self, node):
|
||||
self.add(node, (2,2), "// operator")
|
||||
self.default(node)
|
||||
def visitFrom(self, node):
|
||||
v = StandardModules.get(node.modname)
|
||||
if v is not None:
|
||||
self.add(node, v, node.modname)
|
||||
for n in node.names:
|
||||
name = node.modname + "." + n[0]
|
||||
v = Functions.get(name)
|
||||
if v is not None:
|
||||
self.add(node, v, name)
|
||||
def visitFunction(self, node):
|
||||
if node.decorators:
|
||||
self.add(node, (2,4), "function decorator")
|
||||
self.default(node)
|
||||
def visitGenExpr(self, node):
|
||||
self.add(node, (2,4), "generator expression")
|
||||
self.default(node)
|
||||
def visitGetattr(self, node):
|
||||
if (isinstance(node.expr, compiler.ast.Const)
|
||||
and isinstance(node.expr.value, str)
|
||||
and node.attrname == "format"):
|
||||
self.add(node, (2,6), "string literal .format()")
|
||||
self.default(node)
|
||||
def visitIfExp(self, node):
|
||||
self.add(node, (2,5), "inline if expression")
|
||||
self.default(node)
|
||||
def visitImport(self, node):
|
||||
for n in node.names:
|
||||
v = StandardModules.get(n[0])
|
||||
if v is not None:
|
||||
self.add(node, v, n[0])
|
||||
self.default(node)
|
||||
def visitName(self, node):
|
||||
v = Identifiers.get(node.name)
|
||||
if v is not None:
|
||||
self.add(node, v, node.name)
|
||||
self.default(node)
|
||||
def visitSet(self, node):
|
||||
self.add(node, (2,7), "set literal")
|
||||
self.default(node)
|
||||
def visitSetComp(self, node):
|
||||
self.add(node, (2,7), "set comprehension")
|
||||
self.default(node)
|
||||
def visitTryFinally(self, node):
|
||||
# try/finally with a suite generates a Stmt node as the body,
|
||||
# but try/except/finally generates a TryExcept as the body
|
||||
if isinstance(node.body, compiler.ast.TryExcept):
|
||||
self.add(node, (2,5), "try/except/finally")
|
||||
self.default(node)
|
||||
def visitWith(self, node):
|
||||
if isinstance(node.body, compiler.ast.With):
|
||||
self.add(node, (2,7), "with statement with multiple contexts")
|
||||
else:
|
||||
self.add(node, (2,5), "with statement")
|
||||
self.default(node)
|
||||
def visitYield(self, node):
|
||||
self.add(node, (2,2), "yield expression")
|
||||
self.default(node)
|
||||
|
||||
def get_versions(source):
|
||||
"""Return information about the Python versions required for specific features.
|
||||
|
||||
The return value is a dictionary with keys as a version number as a tuple
|
||||
(for example Python 2.6 is (2,6)) and the value are a list of features that
|
||||
require the indicated Python version.
|
||||
"""
|
||||
tree = compiler.parse(source)
|
||||
checker = compiler.walk(tree, NodeChecker())
|
||||
return checker.vers
|
||||
|
||||
def v27(source):
|
||||
if sys.version_info >= (2, 7):
|
||||
return qver(source)
|
||||
else:
|
||||
print >>sys.stderr, "Not all features tested, run --test with Python 2.7"
|
||||
return (2, 7)
|
||||
|
||||
def qver(source):
|
||||
"""Return the minimum Python version required to run a particular bit of code.
|
||||
|
||||
>>> qver('print "hello world"')
|
||||
(2, 0)
|
||||
>>> qver('class test(object): pass')
|
||||
(2, 2)
|
||||
>>> qver('yield 1')
|
||||
(2, 2)
|
||||
>>> qver('a // b')
|
||||
(2, 2)
|
||||
>>> qver('True')
|
||||
(2, 2)
|
||||
>>> qver('enumerate(a)')
|
||||
(2, 3)
|
||||
>>> qver('total = sum')
|
||||
(2, 0)
|
||||
>>> qver('sum(a)')
|
||||
(2, 3)
|
||||
>>> qver('(x*x for x in range(5))')
|
||||
(2, 4)
|
||||
>>> qver('class C:\\n @classmethod\\n def m(): pass')
|
||||
(2, 4)
|
||||
>>> qver('y if x else z')
|
||||
(2, 5)
|
||||
>>> qver('import hashlib')
|
||||
(2, 5)
|
||||
>>> qver('from hashlib import md5')
|
||||
(2, 5)
|
||||
>>> qver('import xml.etree.ElementTree')
|
||||
(2, 5)
|
||||
>>> qver('try:\\n try: pass;\\n except: pass;\\nfinally: pass')
|
||||
(2, 0)
|
||||
>>> qver('try: pass;\\nexcept: pass;\\nfinally: pass')
|
||||
(2, 5)
|
||||
>>> qver('from __future__ import with_statement\\nwith x: pass')
|
||||
(2, 5)
|
||||
>>> qver('collections.defaultdict(list)')
|
||||
(2, 5)
|
||||
>>> qver('from collections import defaultdict')
|
||||
(2, 5)
|
||||
>>> qver('"{0}".format(0)')
|
||||
(2, 6)
|
||||
>>> qver('memoryview(x)')
|
||||
(2, 7)
|
||||
>>> v27('{1, 2, 3}')
|
||||
(2, 7)
|
||||
>>> v27('{x for x in s}')
|
||||
(2, 7)
|
||||
>>> v27('{x: y for x in s}')
|
||||
(2, 7)
|
||||
>>> qver('from __future__ import with_statement\\nwith x:\\n with y: pass')
|
||||
(2, 5)
|
||||
>>> v27('from __future__ import with_statement\\nwith x, y: pass')
|
||||
(2, 7)
|
||||
>>> qver('@decorator\\ndef f(): pass')
|
||||
(2, 4)
|
||||
>>> qver('@decorator\\nclass test:\\n pass')
|
||||
(2, 6)
|
||||
|
||||
#>>> qver('0o0')
|
||||
#(2, 6)
|
||||
#>>> qver('@foo\\nclass C: pass')
|
||||
#(2, 6)
|
||||
"""
|
||||
return max(get_versions(source).keys())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Verbose = False
|
||||
MinVersion = (2, 3)
|
||||
Lint = False
|
||||
|
||||
files = []
|
||||
i = 1
|
||||
while i < len(sys.argv):
|
||||
a = sys.argv[i]
|
||||
if a == "--test":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
sys.exit(0)
|
||||
if a == "-v" or a == "--verbose":
|
||||
Verbose = True
|
||||
elif a == "-l" or a == "--lint":
|
||||
Lint = True
|
||||
elif a == "-m" or a == "--min-version":
|
||||
i += 1
|
||||
MinVersion = tuple(map(int, sys.argv[i].split(".")))
|
||||
else:
|
||||
files.append(a)
|
||||
i += 1
|
||||
|
||||
if not files:
|
||||
print >>sys.stderr, """Usage: %s [options] source ...
|
||||
|
||||
Report minimum Python version required to run given source files.
|
||||
|
||||
-m x.y or --min-version x.y (default 2.3)
|
||||
report version triggers at or above version x.y in verbose mode
|
||||
-v or --verbose
|
||||
print more detailed report of version triggers for each version
|
||||
""" % sys.argv[0]
|
||||
sys.exit(1)
|
||||
|
||||
for fn in files:
|
||||
try:
|
||||
f = open(fn)
|
||||
source = f.read()
|
||||
f.close()
|
||||
ver = get_versions(source)
|
||||
if Verbose:
|
||||
print fn
|
||||
for v in sorted([k for k in ver.keys() if k >= MinVersion], reverse=True):
|
||||
reasons = [x for x in uniq(ver[v]) if x]
|
||||
if reasons:
|
||||
# each reason is (lineno, message)
|
||||
print "\t%s\t%s" % (".".join(map(str, v)), ", ".join([x[1] for x in reasons]))
|
||||
elif Lint:
|
||||
for v in sorted([k for k in ver.keys() if k >= MinVersion], reverse=True):
|
||||
reasons = [x for x in uniq(ver[v]) if x]
|
||||
for r in reasons:
|
||||
# each reason is (lineno, message)
|
||||
print "%s:%s: %s %s" % (fn, r[0], ".".join(map(str, v)), r[1])
|
||||
else:
|
||||
print "%s\t%s" % (".".join(map(str, max(ver.keys()))), fn)
|
||||
except SyntaxError, x:
|
||||
print "%s: syntax error compiling with Python %s: %s" % (fn, platform.python_version(), x)
|
@ -124,8 +124,19 @@ def expand_user(path):
|
||||
return path.replace('%u', username)
|
||||
|
||||
|
||||
def mkdirp(*paths):
|
||||
for path in paths:
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
elif not os.path.isdir(path):
|
||||
raise OSError(errno.EEXIST, "File alredy exists", path)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def working_dir(dirname):
|
||||
def working_dir(dirname, **kwargs):
|
||||
if kwargs.get('create', False):
|
||||
mkdirp(dirname)
|
||||
|
||||
orig_dir = os.getcwd()
|
||||
os.chdir(dirname)
|
||||
yield
|
||||
@ -137,14 +148,6 @@ def touch(path):
|
||||
os.utime(path, None)
|
||||
|
||||
|
||||
def mkdirp(*paths):
|
||||
for path in paths:
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
elif not os.path.isdir(path):
|
||||
raise OSError(errno.EEXIST, "File alredy exists", path)
|
||||
|
||||
|
||||
def join_path(prefix, *args):
|
||||
path = str(prefix)
|
||||
for elt in args:
|
||||
|
@ -119,9 +119,8 @@ def caller_locals():
|
||||
|
||||
|
||||
def get_calling_package_name():
|
||||
"""Make sure that the caller is a class definition, and return
|
||||
the module's name. This is useful for getting the name of
|
||||
spack packages from inside a relation function.
|
||||
"""Make sure that the caller is a class definition, and return the
|
||||
module's name.
|
||||
"""
|
||||
stack = inspect.stack()
|
||||
try:
|
||||
@ -144,8 +143,9 @@ def get_calling_package_name():
|
||||
def attr_required(obj, attr_name):
|
||||
"""Ensure that a class has a required attribute."""
|
||||
if not hasattr(obj, attr_name):
|
||||
tty.die("No required attribute '%s' in class '%s'"
|
||||
% (attr_name, obj.__class__.__name__))
|
||||
raise RequiredAttributeError(
|
||||
"No required attribute '%s' in class '%s'"
|
||||
% (attr_name, obj.__class__.__name__))
|
||||
|
||||
|
||||
def attr_setdefault(obj, name, value):
|
||||
@ -259,3 +259,8 @@ def in_function(function_name):
|
||||
return False
|
||||
finally:
|
||||
del stack
|
||||
|
||||
|
||||
class RequiredAttributeError(ValueError):
|
||||
def __init__(self, message):
|
||||
super(RequiredAttributeError, self).__init__(message)
|
||||
|
@ -22,20 +22,6 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
|
||||
#
|
||||
# When packages call 'from spack import *', this is what is brought in.
|
||||
#
|
||||
# Spack internal code calls 'import spack' and accesses other
|
||||
# variables (spack.db, paths, etc.) directly.
|
||||
#
|
||||
# TODO: maybe this should be separated out and should go in build_environment.py?
|
||||
# TODO: it's not clear where all the stuff that needs to be included in packages
|
||||
# should live. This file is overloaded for spack core vs. for packages.
|
||||
__all__ = ['Package', 'when', 'provides', 'depends_on',
|
||||
'patch', 'Version', 'working_dir', 'which', 'Executable',
|
||||
'filter_file', 'change_sed_delimiter']
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
from llnl.util.filesystem import *
|
||||
@ -58,7 +44,6 @@
|
||||
stage_path = join_path(var_path, "stage")
|
||||
install_path = join_path(prefix, "opt")
|
||||
share_path = join_path(prefix, "share", "spack")
|
||||
dotkit_path = join_path(share_path, "dotkit")
|
||||
|
||||
#
|
||||
# Set up the packages database.
|
||||
@ -81,7 +66,7 @@
|
||||
# stage directories.
|
||||
#
|
||||
from spack.directory_layout import SpecHashDirectoryLayout
|
||||
install_layout = SpecHashDirectoryLayout(install_path, prefix_size=6)
|
||||
install_layout = SpecHashDirectoryLayout(install_path)
|
||||
|
||||
#
|
||||
# This controls how things are concretized in spack.
|
||||
@ -141,11 +126,30 @@
|
||||
#
|
||||
sys_type = None
|
||||
|
||||
|
||||
#
|
||||
# Extra imports that should be generally usable from package.py files.
|
||||
# When packages call 'from spack import *', this extra stuff is brought in.
|
||||
#
|
||||
from llnl.util.filesystem import working_dir
|
||||
# Spack internal code should call 'import spack' and accesses other
|
||||
# variables (spack.db, paths, etc.) directly.
|
||||
#
|
||||
# TODO: maybe this should be separated out and should go in build_environment.py?
|
||||
# TODO: it's not clear where all the stuff that needs to be included in packages
|
||||
# should live. This file is overloaded for spack core vs. for packages.
|
||||
#
|
||||
__all__ = ['Package', 'Version', 'when']
|
||||
from spack.package import Package
|
||||
from spack.relations import depends_on, provides, patch
|
||||
from spack.multimethod import when
|
||||
from spack.version import Version
|
||||
from spack.multimethod import when
|
||||
|
||||
import llnl.util.filesystem
|
||||
from llnl.util.filesystem import *
|
||||
__all__ += llnl.util.filesystem.__all__
|
||||
|
||||
import spack.relations
|
||||
from spack.relations import *
|
||||
__all__ += spack.relations.__all__
|
||||
|
||||
import spack.util.executable
|
||||
from spack.util.executable import *
|
||||
__all__ += spack.util.executable.__all__
|
||||
|
@ -84,7 +84,7 @@ def __call__(self, *args, **kwargs):
|
||||
|
||||
def set_compiler_environment_variables(pkg):
|
||||
assert(pkg.spec.concrete)
|
||||
compiler = compilers.compiler_for_spec(pkg.spec.compiler)
|
||||
compiler = pkg.compiler
|
||||
|
||||
# Set compiler variables used by CMake and autotools
|
||||
os.environ['CC'] = 'cc'
|
||||
@ -122,7 +122,7 @@ def set_build_environment_variables(pkg):
|
||||
|
||||
# Prefixes of all of the package's dependencies go in
|
||||
# SPACK_DEPENDENCIES
|
||||
dep_prefixes = [d.package.prefix for d in pkg.spec.dependencies.values()]
|
||||
dep_prefixes = [d.prefix for d in pkg.spec.traverse(root=False)]
|
||||
path_set(SPACK_DEPENDENCIES, dep_prefixes)
|
||||
|
||||
# Install prefix
|
||||
@ -143,6 +143,18 @@ def set_build_environment_variables(pkg):
|
||||
os.environ[SPACK_SPEC] = str(pkg.spec)
|
||||
os.environ[SPACK_DEBUG_LOG_DIR] = spack.spack_working_dir
|
||||
|
||||
# Add dependencies to CMAKE_PREFIX_PATH
|
||||
path_set("CMAKE_PREFIX_PATH", dep_prefixes)
|
||||
|
||||
# Add any pkgconfig directories to PKG_CONFIG_PATH
|
||||
pkg_config_dirs = []
|
||||
for p in dep_prefixes:
|
||||
for libdir in ('lib', 'lib64'):
|
||||
pcdir = join_path(p, libdir, 'pkgconfig')
|
||||
if os.path.isdir(pcdir):
|
||||
pkg_config_dirs.append(pcdir)
|
||||
path_set("PKG_CONFIG_PATH", pkg_config_dirs)
|
||||
|
||||
|
||||
def set_module_variables_for_package(pkg):
|
||||
"""Populate the module scope of install() with some useful functions.
|
||||
@ -153,6 +165,9 @@ def set_module_variables_for_package(pkg):
|
||||
m.make = MakeExecutable('make', pkg.parallel)
|
||||
m.gmake = MakeExecutable('gmake', pkg.parallel)
|
||||
|
||||
# easy shortcut to os.environ
|
||||
m.env = os.environ
|
||||
|
||||
# number of jobs spack prefers to build with.
|
||||
m.make_jobs = multiprocessing.cpu_count()
|
||||
|
||||
@ -168,7 +183,7 @@ def set_module_variables_for_package(pkg):
|
||||
|
||||
# standard CMake arguments
|
||||
m.std_cmake_args = ['-DCMAKE_INSTALL_PREFIX=%s' % pkg.prefix,
|
||||
'-DCMAKE_BUILD_TYPE=None']
|
||||
'-DCMAKE_BUILD_TYPE=RelWithDebInfo']
|
||||
if platform.mac_ver()[0]:
|
||||
m.std_cmake_args.append('-DCMAKE_FIND_FRAMEWORK=LAST')
|
||||
|
||||
|
@ -23,12 +23,13 @@
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import os
|
||||
from subprocess import check_call, check_output
|
||||
from subprocess import check_call
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import join_path
|
||||
from llnl.util.filesystem import join_path, mkdirp
|
||||
|
||||
import spack
|
||||
from spack.util.executable import which
|
||||
|
||||
description = "Create a new installation of spack in another prefix"
|
||||
|
||||
@ -38,8 +39,10 @@ def setup_parser(subparser):
|
||||
|
||||
def get_origin_url():
|
||||
git_dir = join_path(spack.prefix, '.git')
|
||||
origin_url = check_output(
|
||||
['git', '--git-dir=%s' % git_dir, 'config', '--get', 'remote.origin.url'])
|
||||
git = which('git', required=True)
|
||||
origin_url = git(
|
||||
'--git-dir=%s' % git_dir, 'config', '--get', 'remote.origin.url',
|
||||
return_output=True)
|
||||
return origin_url.strip()
|
||||
|
||||
|
||||
@ -49,6 +52,11 @@ def bootstrap(parser, args):
|
||||
|
||||
tty.msg("Fetching spack from origin: %s" % origin_url)
|
||||
|
||||
if os.path.isfile(prefix):
|
||||
tty.die("There is already a file at %s" % prefix)
|
||||
|
||||
mkdirp(prefix)
|
||||
|
||||
if os.path.exists(join_path(prefix, '.git')):
|
||||
tty.die("There already seems to be a git repository in %s" % prefix)
|
||||
|
||||
@ -62,10 +70,11 @@ def bootstrap(parser, args):
|
||||
"%s/lib/spack/..." % prefix)
|
||||
|
||||
os.chdir(prefix)
|
||||
check_call(['git', 'init', '--shared', '-q'])
|
||||
check_call(['git', 'remote', 'add', 'origin', origin_url])
|
||||
check_call(['git', 'fetch', 'origin', 'master:refs/remotes/origin/master', '-n', '-q'])
|
||||
check_call(['git', 'reset', '--hard', 'origin/master', '-q'])
|
||||
git = which('git', required=True)
|
||||
git('init', '--shared', '-q')
|
||||
git('remote', 'add', 'origin', origin_url)
|
||||
git('fetch', 'origin', 'master:refs/remotes/origin/master', '-n', '-q')
|
||||
git('reset', '--hard', 'origin/master', '-q')
|
||||
|
||||
tty.msg("Successfully created a new spack in %s" % prefix,
|
||||
"Run %s/bin/spack to use this installation." % prefix)
|
||||
|
38
lib/spack/spack/cmd/cd.py
Normal file
38
lib/spack/spack/cmd/cd.py
Normal file
@ -0,0 +1,38 @@
|
||||
##############################################################################
|
||||
# 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.cmd.location
|
||||
import spack.modules
|
||||
|
||||
description="cd to spack directories in the shell."
|
||||
|
||||
def setup_parser(subparser):
|
||||
"""This is for decoration -- spack cd is used through spack's
|
||||
shell support. This allows spack cd to print a descriptive
|
||||
help message when called with -h."""
|
||||
spack.cmd.location.setup_parser(subparser)
|
||||
|
||||
|
||||
def cd(parser, args):
|
||||
spack.modules.print_help()
|
@ -24,7 +24,7 @@
|
||||
##############################################################################
|
||||
import os
|
||||
import re
|
||||
import argparse
|
||||
from external import argparse
|
||||
import hashlib
|
||||
from pprint import pprint
|
||||
from subprocess import CalledProcessError
|
||||
|
@ -22,7 +22,7 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.tty.colify import colify
|
||||
|
@ -23,7 +23,7 @@
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import sys
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
|
@ -70,7 +70,7 @@ class ${class_name}(Package):
|
||||
homepage = "http://www.example.com"
|
||||
url = "${url}"
|
||||
|
||||
versions = ${versions}
|
||||
${versions}
|
||||
|
||||
def install(self, spec, prefix):
|
||||
# FIXME: Modify the configure line to suit your build system here.
|
||||
@ -87,6 +87,9 @@ def setup_parser(subparser):
|
||||
subparser.add_argument(
|
||||
'--keep-stage', action='store_true', dest='keep_stage',
|
||||
help="Don't clean up staging area when command completes.")
|
||||
subparser.add_argument(
|
||||
'-n', '--name', dest='alternate_name', default=None,
|
||||
help="Override the autodetected name for the created package.")
|
||||
subparser.add_argument(
|
||||
'-f', '--force', action='store_true', dest='force',
|
||||
help="Overwrite any existing package file with the same name.")
|
||||
@ -114,25 +117,11 @@ def __call__(self, stage):
|
||||
self.configure = '%s\n # %s' % (autotools, cmake)
|
||||
|
||||
|
||||
def make_version_dict(ver_hash_tuples):
|
||||
max_len = max(len(str(v)) for v,hfg in ver_hash_tuples)
|
||||
width = max_len + 2
|
||||
format = "%-" + str(width) + "s : '%s',"
|
||||
sep = '\n '
|
||||
return '{ ' + sep.join(format % ("'%s'" % v, h)
|
||||
for v, h in ver_hash_tuples) + ' }'
|
||||
|
||||
|
||||
def get_name():
|
||||
"""Prompt user to input a package name."""
|
||||
name = ""
|
||||
while not name:
|
||||
new_name = raw_input("Name: ")
|
||||
if spack.db.valid_name(name):
|
||||
name = new_name
|
||||
else:
|
||||
print "Package name can only contain A-Z, a-z, 0-9, '_' and '-'"
|
||||
return name
|
||||
def make_version_calls(ver_hash_tuples):
|
||||
"""Adds a version() call to the package for each version found."""
|
||||
max_len = max(len(str(v)) for v, h in ver_hash_tuples)
|
||||
format = " version(%%-%ds, '%%s')" % (max_len + 2)
|
||||
return '\n'.join(format % ("'%s'" % v, h) for v, h in ver_hash_tuples)
|
||||
|
||||
|
||||
def create(parser, args):
|
||||
@ -140,13 +129,22 @@ def create(parser, args):
|
||||
|
||||
# Try to deduce name and version of the new package from the URL
|
||||
name, version = spack.url.parse_name_and_version(url)
|
||||
if not name:
|
||||
tty.msg("Couldn't guess a name for this package.")
|
||||
name = get_name()
|
||||
|
||||
# Use a user-supplied name if one is present
|
||||
name = kwargs.get(args, 'alternate_name', False)
|
||||
if args.name:
|
||||
name = args.name
|
||||
|
||||
if not version:
|
||||
tty.die("Couldn't guess a version string from %s." % url)
|
||||
|
||||
if not name:
|
||||
tty.die("Couldn't guess a name for this package. Try running:", "",
|
||||
"spack create --name <name> <url>")
|
||||
|
||||
if not spack.db.valid_name(name):
|
||||
tty.die("Package name can only contain A-Z, a-z, 0-9, '_' and '-'")
|
||||
|
||||
tty.msg("This looks like a URL for %s version %s." % (name, version))
|
||||
tty.msg("Creating template for package %s" % name)
|
||||
|
||||
@ -195,7 +193,7 @@ def create(parser, args):
|
||||
configure=guesser.configure,
|
||||
class_name=mod_to_class(name),
|
||||
url=url,
|
||||
versions=make_version_dict(ver_hash_tuples)))
|
||||
versions=make_version_calls(ver_hash_tuples)))
|
||||
|
||||
# If everything checks out, go ahead and edit.
|
||||
spack.editor(pkg_path)
|
||||
|
@ -22,14 +22,14 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
|
||||
description = "Show dependent packages."
|
||||
description = "Show installed packages that depend on another."
|
||||
|
||||
def setup_parser(subparser):
|
||||
subparser.add_argument(
|
||||
@ -42,5 +42,5 @@ def dependents(parser, args):
|
||||
tty.die("spack dependents takes only one spec.")
|
||||
|
||||
fmt = '$_$@$%@$+$=$#'
|
||||
deps = [d.format(fmt) for d in specs[0].package.installed_dependents]
|
||||
tty.msg("Dependents of %s" % specs[0].format(fmt), *deps)
|
||||
deps = [d.format(fmt, color=True) for d in specs[0].package.installed_dependents]
|
||||
tty.msg("Dependents of %s" % specs[0].format(fmt, color=True), *deps)
|
||||
|
@ -1,99 +0,0 @@
|
||||
##############################################################################
|
||||
# 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 sys
|
||||
import os
|
||||
import shutil
|
||||
import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.lang import partition_list
|
||||
from llnl.util.filesystem import mkdirp
|
||||
|
||||
import spack.cmd
|
||||
import spack.hooks.dotkit
|
||||
from spack.spec import Spec
|
||||
|
||||
|
||||
description ="Find dotkits for packages if they exist."
|
||||
|
||||
def setup_parser(subparser):
|
||||
subparser.add_argument(
|
||||
'--refresh', action='store_true', help='Regenerate all dotkits')
|
||||
|
||||
subparser.add_argument(
|
||||
'spec', nargs=argparse.REMAINDER, help='spec to find a dotkit for.')
|
||||
|
||||
|
||||
def dotkit_find(parser, args):
|
||||
if not args.spec:
|
||||
parser.parse_args(['dotkit', '-h'])
|
||||
|
||||
spec = spack.cmd.parse_specs(args.spec)
|
||||
if len(spec) > 1:
|
||||
tty.die("You can only pass one spec.")
|
||||
spec = spec[0]
|
||||
|
||||
if not spack.db.exists(spec.name):
|
||||
tty.die("No such package: %s" % spec.name)
|
||||
|
||||
specs = [s for s in spack.db.installed_package_specs() if s.satisfies(spec)]
|
||||
|
||||
if len(specs) == 0:
|
||||
tty.die("No installed packages match spec %s" % spec)
|
||||
|
||||
if len(specs) > 1:
|
||||
tty.error("Multiple matches for spec %s. Choose one:" % spec)
|
||||
for s in specs:
|
||||
sys.stderr.write(s.tree(color=True))
|
||||
sys.exit(1)
|
||||
|
||||
match = specs[0]
|
||||
if not os.path.isfile(spack.hooks.dotkit.dotkit_file(match.package)):
|
||||
tty.die("No dotkit is installed for package %s." % spec)
|
||||
|
||||
print match.format('$_$@$+$%@$=$#')
|
||||
|
||||
|
||||
def dotkit_refresh(parser, args):
|
||||
query_specs = spack.cmd.parse_specs(args.spec)
|
||||
|
||||
specs = spack.db.installed_package_specs()
|
||||
if query_specs:
|
||||
specs = [s for s in specs
|
||||
if any(s.satisfies(q) for q in query_specs)]
|
||||
else:
|
||||
shutil.rmtree(spack.dotkit_path, ignore_errors=False)
|
||||
mkdirp(spack.dotkit_path)
|
||||
|
||||
for spec in specs:
|
||||
spack.hooks.dotkit.post_install(spec.package)
|
||||
|
||||
|
||||
|
||||
def dotkit(parser, args):
|
||||
if args.refresh:
|
||||
dotkit_refresh(parser, args)
|
||||
else:
|
||||
dotkit_find(parser, args)
|
@ -44,7 +44,7 @@ class ${class_name}(Package):
|
||||
homepage = "http://www.example.com"
|
||||
url = "http://www.example.com/${name}-1.0.tar.gz"
|
||||
|
||||
versions = { '1.0' : '0123456789abcdef0123456789abcdef' }
|
||||
version('1.0', '0123456789abcdef0123456789abcdef')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure("--prefix=%s" % prefix)
|
||||
|
@ -22,7 +22,7 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
|
@ -24,7 +24,7 @@
|
||||
##############################################################################
|
||||
import sys
|
||||
import collections
|
||||
import argparse
|
||||
from external import argparse
|
||||
from StringIO import StringIO
|
||||
|
||||
import llnl.util.tty as tty
|
||||
@ -89,7 +89,7 @@ def find(parser, args):
|
||||
format = " %-{}s%s".format(width)
|
||||
|
||||
for abbrv, spec in zip(abbreviated, specs):
|
||||
print format % (abbrv, spec.package.prefix)
|
||||
print format % (abbrv, spec.prefix)
|
||||
|
||||
elif args.full_specs:
|
||||
for spec in specs:
|
||||
|
@ -37,15 +37,17 @@ def info(parser, args):
|
||||
package = spack.db.get(args.name)
|
||||
print "Package: ", package.name
|
||||
print "Homepage: ", package.homepage
|
||||
print "Download: ", package.url
|
||||
|
||||
print
|
||||
print "Safe versions: "
|
||||
|
||||
if package.versions:
|
||||
colify(reversed(sorted(package.versions)), indent=4)
|
||||
if not package.versions:
|
||||
print("None.")
|
||||
else:
|
||||
print "None. Use spack versions %s to get a list of downloadable versions." % package.name
|
||||
maxlen = max(len(str(v)) for v in package.versions)
|
||||
fmt = "%%-%ss" % maxlen
|
||||
for v in reversed(sorted(package.versions)):
|
||||
print " " + (fmt % v) + " " + package.url_for_version(v)
|
||||
|
||||
print
|
||||
print "Dependencies:"
|
||||
|
@ -23,7 +23,7 @@
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import sys
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
|
38
lib/spack/spack/cmd/load.py
Normal file
38
lib/spack/spack/cmd/load.py
Normal file
@ -0,0 +1,38 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
|
||||
# Produced at the Lawrence Livermore National Laboratory.
|
||||
#
|
||||
# This file is part of Spack.
|
||||
# Written by David Beckingsale, david@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
|
||||
##############################################################################
|
||||
from external import argparse
|
||||
import spack.modules
|
||||
|
||||
description ="Add package to environment using modules."
|
||||
|
||||
def setup_parser(subparser):
|
||||
"""Parser is only constructed so that this prints a nice help
|
||||
message with -h. """
|
||||
subparser.add_argument(
|
||||
'spec', nargs=argparse.REMAINDER, help='Spec of package to load with modules.')
|
||||
|
||||
|
||||
def load(parser, args):
|
||||
spack.modules.print_help()
|
93
lib/spack/spack/cmd/location.py
Normal file
93
lib/spack/spack/cmd/location.py
Normal file
@ -0,0 +1,93 @@
|
||||
##############################################################################
|
||||
# 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 os
|
||||
from external import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import join_path
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
|
||||
description="Print out locations of various diectories used by Spack"
|
||||
|
||||
def setup_parser(subparser):
|
||||
global directories
|
||||
directories = subparser.add_mutually_exclusive_group()
|
||||
|
||||
directories.add_argument(
|
||||
'-m', '--module-dir', action='store_true', help="Spack python module directory.")
|
||||
directories.add_argument(
|
||||
'-r', '--spack-root', action='store_true', help="Spack installation root.")
|
||||
|
||||
directories.add_argument(
|
||||
'-i', '--install-dir', action='store_true',
|
||||
help="Install prefix for spec (spec need not be installed).")
|
||||
directories.add_argument(
|
||||
'-p', '--package-dir', action='store_true',
|
||||
help="Directory enclosing a spec's package.py file.")
|
||||
directories.add_argument(
|
||||
'-s', '--stage-dir', action='store_true', help="Stage directory for a spec.")
|
||||
directories.add_argument(
|
||||
'-b', '--build-dir', action='store_true',
|
||||
help="Expanded archive directory for a spec (requires it to be staged first).")
|
||||
|
||||
subparser.add_argument(
|
||||
'spec', nargs=argparse.REMAINDER, help="spec of package to fetch directory for.")
|
||||
|
||||
|
||||
def location(parser, args):
|
||||
if args.module_dir:
|
||||
print spack.module_path
|
||||
|
||||
elif args.spack_root:
|
||||
print spack.prefix
|
||||
|
||||
else:
|
||||
specs = spack.cmd.parse_specs(args.spec, concretize=True)
|
||||
if not specs:
|
||||
tty.die("You must supply a spec.")
|
||||
if len(specs) != 1:
|
||||
tty.die("Too many specs. Need only one.")
|
||||
spec = specs[0]
|
||||
|
||||
if args.install_dir:
|
||||
print spec.prefix
|
||||
|
||||
elif args.package_dir:
|
||||
print join_path(spack.db.root, spec.name)
|
||||
|
||||
else:
|
||||
pkg = spack.db.get(spec)
|
||||
|
||||
if args.stage_dir:
|
||||
print pkg.stage.path
|
||||
|
||||
else: # args.build_dir is the default.
|
||||
if not os.listdir(pkg.stage.path):
|
||||
tty.die("Build directory does not exist yet. Run this to create it:",
|
||||
"spack stage " + " ".join(args.spec))
|
||||
print pkg.stage.expanded_archive_path
|
||||
|
@ -24,10 +24,10 @@
|
||||
##############################################################################
|
||||
import os
|
||||
import shutil
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
from contextlib import closing
|
||||
|
||||
from external import argparse
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.tty.colify import colify
|
||||
from llnl.util.filesystem import mkdirp, join_path
|
||||
@ -41,7 +41,7 @@
|
||||
from spack.util.compression import extension
|
||||
|
||||
|
||||
description = "Manage spack mirrors."
|
||||
description = "Manage mirrors."
|
||||
|
||||
def setup_parser(subparser):
|
||||
subparser.add_argument(
|
||||
|
107
lib/spack/spack/cmd/module.py
Normal file
107
lib/spack/spack/cmd/module.py
Normal file
@ -0,0 +1,107 @@
|
||||
##############################################################################
|
||||
# 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 sys
|
||||
import os
|
||||
import shutil
|
||||
from external import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.lang import partition_list
|
||||
from llnl.util.filesystem import mkdirp
|
||||
|
||||
import spack.cmd
|
||||
from spack.modules import module_types
|
||||
from spack.util.string import *
|
||||
|
||||
from spack.spec import Spec
|
||||
|
||||
description ="Manipulate modules and dotkits."
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='module_command')
|
||||
|
||||
refresh_parser = sp.add_parser('refresh', help='Regenerate all module files.')
|
||||
|
||||
find_parser = sp.add_parser('find', help='Find module files for packages.')
|
||||
find_parser.add_argument(
|
||||
'module_type', help="Type of module to find file for. [" + '|'.join(module_types) + "]")
|
||||
find_parser.add_argument('spec', nargs='+', help='spec to find a module file for.')
|
||||
|
||||
|
||||
def module_find(mtype, spec_array):
|
||||
"""Look at all installed packages and see if the spec provided
|
||||
matches any. If it does, check whether there is a module file
|
||||
of type <mtype> there, and print out the name that the user
|
||||
should type to use that package's module.
|
||||
"""
|
||||
if mtype not in module_types:
|
||||
tty.die("Invalid module type: '%s'. Options are %s." % (mtype, comma_or(module_types)))
|
||||
|
||||
specs = spack.cmd.parse_specs(spec_array)
|
||||
if len(specs) > 1:
|
||||
tty.die("You can only pass one spec.")
|
||||
spec = specs[0]
|
||||
|
||||
specs = [s for s in spack.db.installed_package_specs() if s.satisfies(spec)]
|
||||
if len(specs) == 0:
|
||||
tty.die("No installed packages match spec %s" % spec)
|
||||
|
||||
if len(specs) > 1:
|
||||
tty.error("Multiple matches for spec %s. Choose one:" % spec)
|
||||
for s in specs:
|
||||
sys.stderr.write(s.tree(color=True))
|
||||
sys.exit(1)
|
||||
|
||||
mt = module_types[mtype]
|
||||
mod = mt(specs[0])
|
||||
if not os.path.isfile(mod.file_name):
|
||||
tty.die("No %s module is installed for %s." % (mtype, spec))
|
||||
|
||||
print mod.use_name
|
||||
|
||||
|
||||
def module_refresh():
|
||||
"""Regenerate all module files for installed packages known to
|
||||
spack (some packages may no longer exist)."""
|
||||
specs = [s for s in spack.db.installed_known_package_specs()]
|
||||
|
||||
for name, cls in module_types.items():
|
||||
tty.msg("Regenerating %s module files." % name)
|
||||
if os.path.isdir(cls.path):
|
||||
shutil.rmtree(cls.path, ignore_errors=False)
|
||||
mkdirp(cls.path)
|
||||
for spec in specs:
|
||||
tty.debug(" Writing file for %s." % spec)
|
||||
cls(spec).write()
|
||||
|
||||
|
||||
|
||||
def module(parser, args):
|
||||
if args.module_command == 'refresh':
|
||||
module_refresh()
|
||||
|
||||
elif args.module_command == 'find':
|
||||
module_find(args.module_type, args.spec)
|
@ -22,7 +22,7 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
import spack.cmd
|
||||
import spack
|
||||
|
124
lib/spack/spack/cmd/pkg.py
Normal file
124
lib/spack/spack/cmd/pkg.py
Normal file
@ -0,0 +1,124 @@
|
||||
##############################################################################
|
||||
# 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 os
|
||||
|
||||
from external import argparse
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.tty.colify import colify
|
||||
|
||||
import spack
|
||||
from spack.util.executable import *
|
||||
|
||||
description = "Query packages associated with particular git revisions in spack."
|
||||
|
||||
def setup_parser(subparser):
|
||||
sp = subparser.add_subparsers(
|
||||
metavar='SUBCOMMAND', dest='pkg_command')
|
||||
|
||||
list_parser = sp.add_parser('list', help=pkg_list.__doc__)
|
||||
list_parser.add_argument('rev', default='HEAD', nargs='?',
|
||||
help="Revision to list packages for.")
|
||||
|
||||
diff_parser = sp.add_parser('diff', help=pkg_diff.__doc__)
|
||||
diff_parser.add_argument('rev1', nargs='?', default='HEAD^',
|
||||
help="Revision to compare against.")
|
||||
diff_parser.add_argument('rev2', nargs='?', default='HEAD',
|
||||
help="Revision to compare to rev1 (default is HEAD).")
|
||||
|
||||
add_parser = sp.add_parser('added', help=pkg_added.__doc__)
|
||||
add_parser.add_argument('rev1', nargs='?', default='HEAD^',
|
||||
help="Revision to compare against.")
|
||||
add_parser.add_argument('rev2', nargs='?', default='HEAD',
|
||||
help="Revision to compare to rev1 (default is HEAD).")
|
||||
|
||||
rm_parser = sp.add_parser('removed', help=pkg_removed.__doc__)
|
||||
rm_parser.add_argument('rev1', nargs='?', default='HEAD^',
|
||||
help="Revision to compare against.")
|
||||
rm_parser.add_argument('rev2', nargs='?', default='HEAD',
|
||||
help="Revision to compare to rev1 (default is HEAD).")
|
||||
|
||||
|
||||
def get_git():
|
||||
# cd to spack prefix to do git operations
|
||||
os.chdir(spack.prefix)
|
||||
|
||||
# If this is a non-git version of spack, give up.
|
||||
if not os.path.isdir('.git'):
|
||||
tty.die("No git repo in %s. Can't use 'spack pkg'" % spack.prefix)
|
||||
|
||||
return which("git", required=True)
|
||||
|
||||
|
||||
def list_packages(rev):
|
||||
git = get_git()
|
||||
relpath = spack.packages_path[len(spack.prefix + os.path.sep):] + os.path.sep
|
||||
output = git('ls-tree', '--full-tree', '--name-only', rev, relpath,
|
||||
return_output=True)
|
||||
return sorted(line[len(relpath):] for line in output.split('\n') if line)
|
||||
|
||||
|
||||
def pkg_list(args):
|
||||
"""List packages associated with a particular spack git revision."""
|
||||
colify(list_packages(args.rev))
|
||||
|
||||
|
||||
def diff_packages(rev1, rev2):
|
||||
p1 = set(list_packages(rev1))
|
||||
p2 = set(list_packages(rev2))
|
||||
return p1.difference(p2), p2.difference(p1)
|
||||
|
||||
|
||||
def pkg_diff(args):
|
||||
"""Compare packages available in two different git revisions."""
|
||||
u1, u2 = diff_packages(args.rev1, args.rev2)
|
||||
|
||||
if u1:
|
||||
print "%s:" % args.rev1
|
||||
colify(sorted(u1), indent=4)
|
||||
if u1: print
|
||||
|
||||
if u2:
|
||||
print "%s:" % args.rev2
|
||||
colify(sorted(u2), indent=4)
|
||||
|
||||
|
||||
def pkg_removed(args):
|
||||
"""Show packages removed since a commit."""
|
||||
u1, u2 = diff_packages(args.rev1, args.rev2)
|
||||
if u1: colify(sorted(u1))
|
||||
|
||||
|
||||
def pkg_added(args):
|
||||
"""Show packages added since a commit."""
|
||||
u1, u2 = diff_packages(args.rev1, args.rev2)
|
||||
if u2: colify(sorted(u2))
|
||||
|
||||
|
||||
def pkg(parser, args):
|
||||
action = { 'diff' : pkg_diff,
|
||||
'list' : pkg_list,
|
||||
'removed' : pkg_removed,
|
||||
'added' : pkg_added }
|
||||
action[args.pkg_command](args)
|
@ -23,7 +23,7 @@
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import os
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
from llnl.util.tty.colify import colify
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
import os
|
||||
import sys
|
||||
import code
|
||||
import argparse
|
||||
from external import argparse
|
||||
import platform
|
||||
from contextlib import closing
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
from external import argparse
|
||||
import spack.cmd
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
@ -22,8 +22,10 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
import os
|
||||
from external import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
import spack
|
||||
import spack.cmd
|
||||
|
||||
@ -33,18 +35,21 @@ def setup_parser(subparser):
|
||||
subparser.add_argument(
|
||||
'-n', '--no-checksum', action='store_true', dest='no_checksum',
|
||||
help="Do not check downloaded packages against checksum")
|
||||
|
||||
dir_parser = subparser.add_mutually_exclusive_group()
|
||||
subparser.add_argument(
|
||||
'packages', nargs=argparse.REMAINDER, help="specs of packages to stage")
|
||||
'specs', nargs=argparse.REMAINDER, help="specs of packages to stage")
|
||||
|
||||
|
||||
def stage(parser, args):
|
||||
if not args.packages:
|
||||
if not args.specs:
|
||||
tty.die("stage requires at least one package argument")
|
||||
|
||||
if args.no_checksum:
|
||||
spack.do_checksum = False
|
||||
|
||||
specs = spack.cmd.parse_specs(args.packages, concretize=True)
|
||||
specs = spack.cmd.parse_specs(args.specs, concretize=True)
|
||||
for spec in specs:
|
||||
package = spack.db.get(spec)
|
||||
package.do_stage()
|
||||
|
||||
|
@ -22,12 +22,13 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
from external import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
import spack.packages
|
||||
|
||||
description="Remove an installed package"
|
||||
|
||||
@ -68,7 +69,15 @@ def uninstall(parser, args):
|
||||
if len(matching_specs) == 0:
|
||||
tty.die("%s does not match any installed packages." % spec)
|
||||
|
||||
pkgs.extend(spack.db.get(s) for s in matching_specs)
|
||||
for s in matching_specs:
|
||||
try:
|
||||
# should work if package is known to spack
|
||||
pkgs.append(spack.db.get(s))
|
||||
|
||||
except spack.packages.UnknownPackageError, e:
|
||||
# The package.py file has gone away -- but still want to uninstall.
|
||||
spack.Package(s).do_uninstall(force=True)
|
||||
|
||||
|
||||
# Sort packages to be uninstalled by the number of installed dependents
|
||||
# This ensures we do things in the right order
|
||||
|
38
lib/spack/spack/cmd/unload.py
Normal file
38
lib/spack/spack/cmd/unload.py
Normal file
@ -0,0 +1,38 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
|
||||
# Produced at the Lawrence Livermore National Laboratory.
|
||||
#
|
||||
# This file is part of Spack.
|
||||
# Written by David Beckingsale, david@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
|
||||
##############################################################################
|
||||
from external import argparse
|
||||
import spack.modules
|
||||
|
||||
description ="Remove package from environment using module."
|
||||
|
||||
def setup_parser(subparser):
|
||||
"""Parser is only constructed so that this prints a nice help
|
||||
message with -h. """
|
||||
subparser.add_argument(
|
||||
'spec', nargs=argparse.REMAINDER, help='Spec of package to unload with modules.')
|
||||
|
||||
|
||||
def unload(parser, args):
|
||||
spack.modules.print_help()
|
@ -22,15 +22,17 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
import spack.cmd.use
|
||||
from external import argparse
|
||||
import spack.modules
|
||||
|
||||
description ="Remove package from environment using dotkit."
|
||||
|
||||
def setup_parser(subparser):
|
||||
"""Parser is only constructed so that this prints a nice help
|
||||
message with -h. """
|
||||
subparser.add_argument(
|
||||
'spec', nargs=argparse.REMAINDER, help='Spec of package to remove.')
|
||||
'spec', nargs=argparse.REMAINDER, help='Spec of package to unuse with dotkit.')
|
||||
|
||||
|
||||
def unuse(parser, args):
|
||||
spack.cmd.use.print_help()
|
||||
spack.modules.print_help()
|
||||
|
@ -22,29 +22,17 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
import llnl.util.tty as tty
|
||||
import spack
|
||||
from external import argparse
|
||||
import spack.modules
|
||||
|
||||
description ="Add package to environment using dotkit."
|
||||
|
||||
def setup_parser(subparser):
|
||||
"""Parser is only constructed so that this prints a nice help
|
||||
message with -h. """
|
||||
subparser.add_argument(
|
||||
'spec', nargs=argparse.REMAINDER, help='Spec of package to add.')
|
||||
|
||||
|
||||
def print_help():
|
||||
tty.msg("Spack dotkit support is not initialized.",
|
||||
"",
|
||||
"To use dotkit with Spack, you must first run the command",
|
||||
"below, which you can copy and paste:",
|
||||
"",
|
||||
"For bash:",
|
||||
" . %s/setup-env.bash" % spack.share_path,
|
||||
"",
|
||||
"ksh/csh/tcsh shells are currently unsupported",
|
||||
"")
|
||||
'spec', nargs=argparse.REMAINDER, help='Spec of package to use with dotkit.')
|
||||
|
||||
|
||||
def use(parser, args):
|
||||
print_help()
|
||||
spack.modules.print_help()
|
||||
|
@ -94,6 +94,9 @@ class Compiler(object):
|
||||
# Names of generic arguments used by this compiler
|
||||
arg_rpath = '-Wl,-rpath,%s'
|
||||
|
||||
# argument used to get C++11 options
|
||||
cxx11_flag = "-std=c++11"
|
||||
|
||||
|
||||
def __init__(self, cspec, cc, cxx, f77, fc):
|
||||
def check(exe):
|
||||
@ -189,7 +192,7 @@ def check(key):
|
||||
return None
|
||||
|
||||
successful = [key for key in parmap(check, checks) if key is not None]
|
||||
return { (v, p, s) : path for v, p, s, path in successful }
|
||||
return dict(((v, p, s), path) for v, p, s, path in successful)
|
||||
|
||||
@classmethod
|
||||
def find(cls, *path):
|
||||
|
@ -176,7 +176,7 @@ def compilers_for_spec(compiler_spec):
|
||||
config = _get_config()
|
||||
|
||||
def get_compiler(cspec):
|
||||
items = { k:v for k,v in config.items('compiler "%s"' % cspec) }
|
||||
items = dict((k,v) for k,v in config.items('compiler "%s"' % cspec))
|
||||
|
||||
if not all(n in items for n in _required_instance_vars):
|
||||
raise InvalidCompilerConfigurationError(cspec)
|
||||
|
@ -22,7 +22,9 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import llnl.util.tty as tty
|
||||
from spack.compiler import *
|
||||
from spack.version import ver
|
||||
|
||||
class Gcc(Compiler):
|
||||
# Subclasses use possible names of C compiler
|
||||
@ -40,6 +42,15 @@ class Gcc(Compiler):
|
||||
# MacPorts builds gcc versions with prefixes and -mp-X.Y suffixes.
|
||||
suffixes = [r'-mp-\d\.\d']
|
||||
|
||||
@property
|
||||
def cxx11_flag(self):
|
||||
if self.version < ver('4.3'):
|
||||
tty.die("Only gcc 4.3 and above support c++11.")
|
||||
elif self.version < ver('4.7'):
|
||||
return "-std=gnu++0x"
|
||||
else:
|
||||
return "-std=gnu++11"
|
||||
|
||||
@classmethod
|
||||
def fc_version(cls, fc):
|
||||
return get_compiler_version(
|
||||
|
@ -37,6 +37,15 @@ class Intel(Compiler):
|
||||
# Subclasses use possible names of Fortran 90 compiler
|
||||
fc_names = ['ifort']
|
||||
|
||||
@property
|
||||
def cxx11_flag(self):
|
||||
if self.version < ver('11.1'):
|
||||
tty.die("Only intel 11.1 and above support c++11.")
|
||||
elif self.version < ver('13'):
|
||||
return "-std=c++0x"
|
||||
else:
|
||||
return "-std=c++11"
|
||||
|
||||
|
||||
@classmethod
|
||||
def default_version(cls, comp):
|
||||
|
@ -72,7 +72,7 @@ def concretize_version(self, spec):
|
||||
if valid_versions:
|
||||
spec.versions = ver([valid_versions[-1]])
|
||||
else:
|
||||
spec.versions = ver([pkg.default_version])
|
||||
raise NoValidVerionError(spec)
|
||||
|
||||
|
||||
def concretize_architecture(self, spec):
|
||||
@ -118,7 +118,7 @@ def concretize_compiler(self, spec):
|
||||
return
|
||||
|
||||
try:
|
||||
nearest = next(p for p in spec.preorder_traversal(direction='parents')
|
||||
nearest = next(p for p in spec.traverse(direction='parents')
|
||||
if p.compiler is not None).compiler
|
||||
|
||||
if not nearest in all_compilers:
|
||||
@ -158,3 +158,11 @@ def __init__(self, compiler_spec):
|
||||
super(UnavailableCompilerVersionError, self).__init__(
|
||||
"No available compiler version matches '%s'" % compiler_spec,
|
||||
"Run 'spack compilers' to see available compiler Options.")
|
||||
|
||||
|
||||
class NoValidVerionError(spack.error.SpackError):
|
||||
"""Raised when there is no available version for a package that
|
||||
satisfies a spec."""
|
||||
def __init__(self, spec):
|
||||
super(NoValidVerionError, self).__init__(
|
||||
"No available version of %s matches '%s'" % (spec.name, spec.versions))
|
||||
|
@ -84,10 +84,9 @@
|
||||
import re
|
||||
import inspect
|
||||
import ConfigParser as cp
|
||||
from collections import OrderedDict
|
||||
|
||||
from external.ordereddict import OrderedDict
|
||||
from llnl.util.lang import memoized
|
||||
|
||||
import spack.error
|
||||
|
||||
__all__ = [
|
||||
@ -222,7 +221,6 @@ class SpackConfigParser(cp.RawConfigParser):
|
||||
"""
|
||||
# Slightly modify Python option expressions to allow leading whitespace
|
||||
OPTCRE = re.compile(r'\s*' + cp.RawConfigParser.OPTCRE.pattern)
|
||||
OPTCRE_NV = re.compile(r'\s*' + cp.RawConfigParser.OPTCRE_NV.pattern)
|
||||
|
||||
def __init__(self, file_or_files):
|
||||
cp.RawConfigParser.__init__(self, dict_type=OrderedDict)
|
||||
@ -341,14 +339,13 @@ def write(self, path_or_fp=None):
|
||||
|
||||
|
||||
def _read(self, fp, fpname):
|
||||
"""This is a copy of Python 2.7's _read() method, with support for
|
||||
continuation lines removed.
|
||||
"""
|
||||
cursect = None # None, or a dictionary
|
||||
"""This is a copy of Python 2.6's _read() method, with support for
|
||||
continuation lines removed."""
|
||||
cursect = None # None, or a dictionary
|
||||
optname = None
|
||||
lineno = 0
|
||||
comment = 0
|
||||
e = None # None, or an exception
|
||||
lineno = 0
|
||||
e = None # None, or an exception
|
||||
while True:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
@ -359,7 +356,6 @@ def _read(self, fp, fpname):
|
||||
(line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR")):
|
||||
self._sections["comment-%d" % comment] = line
|
||||
comment += 1
|
||||
continue
|
||||
# a section header or option header?
|
||||
else:
|
||||
# is it a section header?
|
||||
@ -381,27 +377,21 @@ def _read(self, fp, fpname):
|
||||
raise cp.MissingSectionHeaderError(fpname, lineno, line)
|
||||
# an option line?
|
||||
else:
|
||||
mo = self._optcre.match(line)
|
||||
mo = self.OPTCRE.match(line)
|
||||
if mo:
|
||||
optname, vi, optval = mo.group('option', 'vi', 'value')
|
||||
if vi in ('=', ':') and ';' in optval:
|
||||
# ';' is a comment delimiter only if it follows
|
||||
# a spacing character
|
||||
pos = optval.find(';')
|
||||
if pos != -1 and optval[pos-1].isspace():
|
||||
optval = optval[:pos]
|
||||
optval = optval.strip()
|
||||
# allow empty values
|
||||
if optval == '""':
|
||||
optval = ''
|
||||
optname = self.optionxform(optname.rstrip())
|
||||
# This check is fine because the OPTCRE cannot
|
||||
# match if it would set optval to None
|
||||
if optval is not None:
|
||||
if vi in ('=', ':') and ';' in optval:
|
||||
# ';' is a comment delimiter only if it follows
|
||||
# a spacing character
|
||||
pos = optval.find(';')
|
||||
if pos != -1 and optval[pos-1].isspace():
|
||||
optval = optval[:pos]
|
||||
optval = optval.strip()
|
||||
# allow empty values
|
||||
if optval == '""':
|
||||
optval = ''
|
||||
cursect[optname] = [optval]
|
||||
else:
|
||||
# valueless option handling
|
||||
cursect[optname] = optval
|
||||
cursect[optname] = optval
|
||||
else:
|
||||
# a non-fatal parsing error occurred. set up the
|
||||
# exception but keep going. the exception will be
|
||||
@ -414,23 +404,13 @@ def _read(self, fp, fpname):
|
||||
if e:
|
||||
raise e
|
||||
|
||||
# join the multi-line values collected while reading
|
||||
all_sections = [self._defaults]
|
||||
all_sections.extend(self._sections.values())
|
||||
for options in all_sections:
|
||||
# skip comments
|
||||
if isinstance(options, basestring):
|
||||
continue
|
||||
|
||||
for name, val in options.items():
|
||||
if isinstance(val, list):
|
||||
options[name] = '\n'.join(val)
|
||||
|
||||
|
||||
def _write(self, fp):
|
||||
"""Write an .ini-format representation of the configuration state.
|
||||
|
||||
This is taken from the default Python 2.7 source. It writes 4
|
||||
This is taken from the default Python 2.6 source. It writes 4
|
||||
spaces at the beginning of lines instead of no leading space.
|
||||
"""
|
||||
if self._defaults:
|
||||
@ -449,11 +429,9 @@ def _write(self, fp):
|
||||
# Allow leading whitespace
|
||||
fp.write("[%s]\n" % section)
|
||||
for (key, value) in self._sections[section].items():
|
||||
if key == "__name__":
|
||||
continue
|
||||
if (value is not None) or (self._optcre == self.OPTCRE):
|
||||
key = " = ".join((key, str(value).replace('\n', '\n\t')))
|
||||
fp.write(" %s\n" % (key))
|
||||
if key != "__name__":
|
||||
fp.write(" %s = %s\n" %
|
||||
(key, str(value).replace('\n', '\n\t')))
|
||||
|
||||
|
||||
class SpackConfigurationError(spack.error.SpackError):
|
||||
|
@ -29,7 +29,10 @@
|
||||
import shutil
|
||||
from contextlib import closing
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import join_path, mkdirp
|
||||
|
||||
import spack
|
||||
from spack.spec import Spec
|
||||
from spack.error import SpackError
|
||||
|
||||
@ -131,12 +134,9 @@ def __init__(self, root, **kwargs):
|
||||
"""Prefix size is number of characters in the SHA-1 prefix to use
|
||||
to make each hash unique.
|
||||
"""
|
||||
prefix_size = kwargs.get('prefix_size', 8)
|
||||
spec_file = kwargs.get('spec_file', '.spec')
|
||||
|
||||
spec_file_name = kwargs.get('spec_file_name', '.spec')
|
||||
super(SpecHashDirectoryLayout, self).__init__(root)
|
||||
self.prefix_size = prefix_size
|
||||
self.spec_file = spec_file
|
||||
self.spec_file_name = spec_file_name
|
||||
|
||||
|
||||
def relative_path_for_spec(self, spec):
|
||||
@ -154,15 +154,36 @@ def write_spec(self, spec, path):
|
||||
def read_spec(self, path):
|
||||
"""Read the contents of a file and parse them as a spec"""
|
||||
with closing(open(path)) as spec_file:
|
||||
string = spec_file.read().replace('\n', '')
|
||||
return Spec(string)
|
||||
# Specs from files are assumed normal and concrete
|
||||
spec = Spec(spec_file.read().replace('\n', ''))
|
||||
|
||||
# If we do not have a package on hand for this spec, we know
|
||||
# it is concrete, and we *assume* that it is normal. This
|
||||
# prevents us from trying to fetch a non-existing package, and
|
||||
# allows best effort for commands like spack find.
|
||||
if not spack.db.exists(spec.name):
|
||||
spec._normal = True
|
||||
spec._concrete = True
|
||||
else:
|
||||
spec.normalize()
|
||||
if not spec.concrete:
|
||||
tty.warn("Spec read from installed package is not concrete:",
|
||||
path, spec)
|
||||
|
||||
return spec
|
||||
|
||||
|
||||
def spec_file_path(self, spec):
|
||||
"""Gets full path to spec file"""
|
||||
_check_concrete(spec)
|
||||
return join_path(self.path_for_spec(spec), self.spec_file_name)
|
||||
|
||||
|
||||
def make_path_for_spec(self, spec):
|
||||
_check_concrete(spec)
|
||||
|
||||
path = self.path_for_spec(spec)
|
||||
spec_file_path = join_path(path, self.spec_file)
|
||||
spec_file_path = self.spec_file_path(spec)
|
||||
|
||||
if os.path.isdir(path):
|
||||
if not os.path.isfile(spec_file_path):
|
||||
@ -176,8 +197,7 @@ def make_path_for_spec(self, spec):
|
||||
spec_hash = self.hash_spec(spec)
|
||||
installed_hash = self.hash_spec(installed_spec)
|
||||
if installed_spec == spec_hash:
|
||||
raise SpecHashCollisionError(
|
||||
installed_hash, spec_hash, self.prefix_size)
|
||||
raise SpecHashCollisionError(installed_hash, spec_hash)
|
||||
else:
|
||||
raise InconsistentInstallDirectoryError(
|
||||
'Spec file in %s does not match SHA-1 hash!'
|
||||
@ -194,7 +214,7 @@ def all_specs(self):
|
||||
for path in traverse_dirs_at_depth(self.root, 3):
|
||||
arch, compiler, last_dir = path
|
||||
spec_file_path = join_path(
|
||||
self.root, arch, compiler, last_dir, self.spec_file)
|
||||
self.root, arch, compiler, last_dir, self.spec_file_name)
|
||||
if os.path.exists(spec_file_path):
|
||||
spec = self.read_spec(spec_file_path)
|
||||
yield spec
|
||||
@ -208,10 +228,10 @@ def __init__(self, message):
|
||||
|
||||
class SpecHashCollisionError(DirectoryLayoutError):
|
||||
"""Raised when there is a hash collision in an SpecHashDirectoryLayout."""
|
||||
def __init__(self, installed_spec, new_spec, prefix_size):
|
||||
def __init__(self, installed_spec, new_spec):
|
||||
super(SpecHashDirectoryLayout, self).__init__(
|
||||
'Specs %s and %s have the same %d character SHA-1 prefix!'
|
||||
% prefix_size, installed_spec, new_spec)
|
||||
'Specs %s and %s have the same SHA-1 prefix!'
|
||||
% installed_spec, new_spec)
|
||||
|
||||
|
||||
class InconsistentInstallDirectoryError(DirectoryLayoutError):
|
||||
|
@ -28,7 +28,8 @@ class SpackError(Exception):
|
||||
Subclasses can be found in the modules they have to do with.
|
||||
"""
|
||||
def __init__(self, message, long_message=None):
|
||||
super(SpackError, self).__init__(message)
|
||||
super(SpackError, self).__init__()
|
||||
self.message = message
|
||||
self.long_message = long_message
|
||||
|
||||
|
||||
|
@ -22,62 +22,14 @@
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import os
|
||||
import re
|
||||
import textwrap
|
||||
import shutil
|
||||
from contextlib import closing
|
||||
|
||||
from llnl.util.filesystem import join_path, mkdirp
|
||||
|
||||
import spack
|
||||
|
||||
|
||||
def dotkit_file(pkg):
|
||||
dk_file_name = pkg.spec.format('$_$@$%@$+$=$#') + ".dk"
|
||||
return join_path(spack.dotkit_path, dk_file_name)
|
||||
import spack.modules
|
||||
|
||||
|
||||
def post_install(pkg):
|
||||
if not os.path.exists(spack.dotkit_path):
|
||||
mkdirp(spack.dotkit_path)
|
||||
|
||||
alterations = []
|
||||
for var, path in [
|
||||
('PATH', pkg.prefix.bin),
|
||||
('MANPATH', pkg.prefix.man),
|
||||
('MANPATH', pkg.prefix.share_man),
|
||||
('LD_LIBRARY_PATH', pkg.prefix.lib),
|
||||
('LD_LIBRARY_PATH', pkg.prefix.lib64)]:
|
||||
|
||||
if os.path.isdir(path):
|
||||
alterations.append("dk_alter %s %s\n" % (var, path))
|
||||
|
||||
if not alterations:
|
||||
return
|
||||
|
||||
alterations.append("dk_alter CMAKE_PREFIX_PATH %s\n" % pkg.prefix)
|
||||
|
||||
dk_file = dotkit_file(pkg)
|
||||
with closing(open(dk_file, 'w')) as dk:
|
||||
# Put everything in the spack category.
|
||||
dk.write('#c spack\n')
|
||||
|
||||
dk.write('#d %s\n' % pkg.spec.format("$_ $@"))
|
||||
|
||||
# Recycle the description
|
||||
if pkg.__doc__:
|
||||
doc = re.sub(r'\s+', ' ', pkg.__doc__)
|
||||
for line in textwrap.wrap(doc, 72):
|
||||
dk.write("#h %s\n" % line)
|
||||
|
||||
# Write alterations
|
||||
for alter in alterations:
|
||||
dk.write(alter)
|
||||
dk = spack.modules.Dotkit(pkg.spec)
|
||||
dk.write()
|
||||
|
||||
|
||||
def post_uninstall(pkg):
|
||||
dk_file = dotkit_file(pkg)
|
||||
if os.path.exists(dk_file):
|
||||
shutil.rmtree(dk_file, ignore_errors=True)
|
||||
|
||||
dk = spack.modules.Dotkit(pkg.spec)
|
||||
dk.remove()
|
||||
|
35
lib/spack/spack/hooks/tclmodule.py
Normal file
35
lib/spack/spack/hooks/tclmodule.py
Normal file
@ -0,0 +1,35 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
|
||||
# Produced at the Lawrence Livermore National Laboratory.
|
||||
#
|
||||
# This file is part of Spack.
|
||||
# Written by David Beckingsale, david@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.modules
|
||||
|
||||
|
||||
def post_install(pkg):
|
||||
dk = spack.modules.TclModule(pkg.spec)
|
||||
dk.write()
|
||||
|
||||
|
||||
def post_uninstall(pkg):
|
||||
dk = spack.modules.TclModule(pkg.spec)
|
||||
dk.remove()
|
247
lib/spack/spack/modules.py
Normal file
247
lib/spack/spack/modules.py
Normal file
@ -0,0 +1,247 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
"""This module contains code for creating environment modules, which
|
||||
can include dotkits, tcl modules, lmod, and others.
|
||||
|
||||
The various types of modules are installed by post-install hooks and
|
||||
removed after an uninstall by post-uninstall hooks. This class
|
||||
consolidates the logic for creating an abstract description of the
|
||||
information that module systems need. Currently that includes a
|
||||
number directories to be appended to paths in the user's environment:
|
||||
|
||||
* /bin directories to be appended to PATH
|
||||
* /lib* directories for LD_LIBRARY_PATH
|
||||
* /man* and /share/man* directories for LD_LIBRARY_PATH
|
||||
* the package prefix for CMAKE_PREFIX_PATH
|
||||
|
||||
This module also includes logic for coming up with unique names for
|
||||
the module files so that they can be found by the various
|
||||
shell-support files in $SPACK/share/spack/setup-env.*.
|
||||
|
||||
Each hook in hooks/ implements the logic for writing its specific type
|
||||
of module file.
|
||||
"""
|
||||
__all__ = ['EnvModule', 'Dotkit', 'TclModule']
|
||||
|
||||
import os
|
||||
import re
|
||||
import textwrap
|
||||
import shutil
|
||||
from contextlib import closing
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import join_path, mkdirp
|
||||
|
||||
import spack
|
||||
|
||||
"""Registry of all types of modules. Entries created by EnvModule's
|
||||
metaclass."""
|
||||
module_types = {}
|
||||
|
||||
|
||||
def print_help():
|
||||
"""For use by commands to tell user how to activate shell support."""
|
||||
|
||||
tty.msg("This command requires spack's shell integration.",
|
||||
"",
|
||||
"To initialize spack's shell commands, you must run one of",
|
||||
"the commands below. Choose the right command for your shell.",
|
||||
"",
|
||||
"For bash and zsh:",
|
||||
" . %s/setup-env.sh" % spack.share_path,
|
||||
"",
|
||||
"For csh and tcsh:",
|
||||
" setenv SPACK_ROOT %s" % spack.prefix,
|
||||
" source %s/setup-env.csh" % spack.share_path,
|
||||
"")
|
||||
|
||||
|
||||
class EnvModule(object):
|
||||
name = 'env_module'
|
||||
|
||||
class __metaclass__(type):
|
||||
def __init__(cls, name, bases, dict):
|
||||
type.__init__(cls, name, bases, dict)
|
||||
if cls.name != 'env_module':
|
||||
module_types[cls.name] = cls
|
||||
|
||||
|
||||
def __init__(self, spec=None):
|
||||
# category in the modules system
|
||||
# TODO: come up with smarter category names.
|
||||
self.category = "spack"
|
||||
|
||||
# Descriptions for the module system's UI
|
||||
self.short_description = ""
|
||||
self.long_description = ""
|
||||
|
||||
# dict pathname -> list of directories to be prepended to in
|
||||
# the module file.
|
||||
self._paths = None
|
||||
self.spec = spec
|
||||
|
||||
|
||||
@property
|
||||
def paths(self):
|
||||
if self._paths is None:
|
||||
self._paths = {}
|
||||
|
||||
def add_path(path_name, directory):
|
||||
path = self._paths.setdefault(path_name, [])
|
||||
path.append(directory)
|
||||
|
||||
# Add paths if they exist.
|
||||
for var, directory in [
|
||||
('PATH', self.spec.prefix.bin),
|
||||
('MANPATH', self.spec.prefix.man),
|
||||
('MANPATH', self.spec.prefix.share_man),
|
||||
('LD_LIBRARY_PATH', self.spec.prefix.lib),
|
||||
('LD_LIBRARY_PATH', self.spec.prefix.lib64)]:
|
||||
|
||||
if os.path.isdir(directory):
|
||||
add_path(var, directory)
|
||||
|
||||
# short description is just the package + version
|
||||
# TODO: maybe packages can optionally provide it.
|
||||
self.short_description = self.spec.format("$_ $@")
|
||||
|
||||
# long description is the docstring with reduced whitespace.
|
||||
if self.spec.package.__doc__:
|
||||
self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__)
|
||||
|
||||
return self._paths
|
||||
|
||||
|
||||
def write(self):
|
||||
"""Write out a module file for this object."""
|
||||
module_dir = os.path.dirname(self.file_name)
|
||||
if not os.path.exists(module_dir):
|
||||
mkdirp(module_dir)
|
||||
|
||||
# If there are no paths, no need for a dotkit.
|
||||
if not self.paths:
|
||||
return
|
||||
|
||||
with closing(open(self.file_name, 'w')) as f:
|
||||
self._write(f)
|
||||
|
||||
|
||||
def _write(self, stream):
|
||||
"""To be implemented by subclasses."""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
"""Subclasses should implement this to return the name of the file
|
||||
where this module lives."""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
@property
|
||||
def use_name(self):
|
||||
"""Subclasses should implement this to return the name the
|
||||
module command uses to refer to the package."""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def remove(self):
|
||||
mod_file = self.file_name
|
||||
if os.path.exists(mod_file):
|
||||
shutil.rmtree(mod_file, ignore_errors=True)
|
||||
|
||||
|
||||
class Dotkit(EnvModule):
|
||||
name = 'dotkit'
|
||||
path = join_path(spack.share_path, "dotkit")
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
return join_path(Dotkit.path, self.spec.architecture,
|
||||
self.spec.format('$_$@$%@$+$#.dk'))
|
||||
|
||||
@property
|
||||
def use_name(self):
|
||||
return self.spec.format('$_$@$%@$+$#')
|
||||
|
||||
|
||||
def _write(self, dk_file):
|
||||
# Category
|
||||
if self.category:
|
||||
dk_file.write('#c %s\n' % self.category)
|
||||
|
||||
# Short description
|
||||
if self.short_description:
|
||||
dk_file.write('#d %s\n' % self.short_description)
|
||||
|
||||
# Long description
|
||||
if self.long_description:
|
||||
for line in textwrap.wrap(self.long_description, 72):
|
||||
dk_file.write("#h %s\n" % line)
|
||||
|
||||
# Path alterations
|
||||
for var, dirs in self.paths.items():
|
||||
for directory in dirs:
|
||||
dk_file.write("dk_alter %s %s\n" % (var, directory))
|
||||
|
||||
# Let CMake find this package.
|
||||
dk_file.write("dk_alter CMAKE_PREFIX_PATH %s\n" % self.spec.prefix)
|
||||
|
||||
|
||||
class TclModule(EnvModule):
|
||||
name = 'tcl'
|
||||
path = join_path(spack.share_path, "modules")
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
return join_path(TclModule.path, self.spec.architecture, self.use_name)
|
||||
|
||||
|
||||
@property
|
||||
def use_name(self):
|
||||
return self.spec.format('$_$@$%@$+$#')
|
||||
|
||||
|
||||
def _write(self, m_file):
|
||||
# TODO: cateogry?
|
||||
m_file.write('#%Module1.0\n')
|
||||
|
||||
# Short description
|
||||
if self.short_description:
|
||||
m_file.write('module-whatis \"%s\"\n\n' % self.short_description)
|
||||
|
||||
# Long description
|
||||
if self.long_description:
|
||||
m_file.write('proc ModulesHelp { } {\n')
|
||||
doc = re.sub(r'"', '\"', self.long_description)
|
||||
m_file.write("puts stderr \"%s\"\n" % doc)
|
||||
m_file.write('}\n\n')
|
||||
|
||||
# Path alterations
|
||||
for var, dirs in self.paths.items():
|
||||
for directory in dirs:
|
||||
m_file.write("prepend-path %s \"%s\"\n" % (var, directory))
|
||||
|
||||
m_file.write("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % self.spec.prefix)
|
@ -48,6 +48,7 @@
|
||||
import spack
|
||||
import spack.spec
|
||||
import spack.error
|
||||
import spack.compilers
|
||||
import spack.hooks
|
||||
import spack.build_environment as build_env
|
||||
import spack.url as url
|
||||
@ -57,7 +58,7 @@
|
||||
from spack.util.compression import allowed_archive, extension
|
||||
|
||||
"""Allowed URL schemes for spack packages."""
|
||||
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file"]
|
||||
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"]
|
||||
|
||||
|
||||
class Package(object):
|
||||
@ -296,9 +297,12 @@ class SomePackage(Package):
|
||||
"""
|
||||
|
||||
#
|
||||
# These variables are defaults for the various relations defined on
|
||||
# packages. Subclasses will have their own versions of these.
|
||||
# These variables are defaults for the various "relations".
|
||||
#
|
||||
"""Map of information about Versions of this package.
|
||||
Map goes: Version -> VersionDescriptor"""
|
||||
versions = {}
|
||||
|
||||
"""Specs of dependency packages, keyed by name."""
|
||||
dependencies = {}
|
||||
|
||||
@ -317,17 +321,8 @@ class SomePackage(Package):
|
||||
"""By default we build in parallel. Subclasses can override this."""
|
||||
parallel = True
|
||||
|
||||
"""Dirty hack for forcing packages with uninterpretable URLs
|
||||
TODO: get rid of this.
|
||||
"""
|
||||
force_url = False
|
||||
|
||||
|
||||
def __init__(self, spec):
|
||||
# These attributes are required for all packages.
|
||||
attr_required(self.__class__, 'homepage')
|
||||
attr_required(self.__class__, 'url')
|
||||
|
||||
# this determines how the package should be built.
|
||||
self.spec = spec
|
||||
|
||||
@ -337,28 +332,36 @@ def __init__(self, spec):
|
||||
if '.' in self.name:
|
||||
self.name = self.name[self.name.rindex('.') + 1:]
|
||||
|
||||
# Make sure URL is an allowed type
|
||||
validate_package_url(self.url)
|
||||
|
||||
# patch up the URL with a new version if the spec version is concrete
|
||||
if self.spec.versions.concrete:
|
||||
self.url = self.url_for_version(self.spec.version)
|
||||
|
||||
# This is set by scraping a web page.
|
||||
self._available_versions = None
|
||||
|
||||
# versions should be a dict from version to checksum, for safe versions
|
||||
# of this package. If it's not present, make it an empty dict.
|
||||
if not hasattr(self, 'versions'):
|
||||
self.versions = {}
|
||||
# Sanity check some required variables that could be
|
||||
# overridden by package authors.
|
||||
def sanity_check_dict(attr_name):
|
||||
if not hasattr(self, attr_name):
|
||||
raise PackageError("Package %s must define %s" % attr_name)
|
||||
|
||||
if not isinstance(self.versions, dict):
|
||||
raise ValueError("versions attribute of package %s must be a dict!"
|
||||
% self.name)
|
||||
attr = getattr(self, attr_name)
|
||||
if not isinstance(attr, dict):
|
||||
raise PackageError("Package %s has non-dict %s attribute!"
|
||||
% (self.name, attr_name))
|
||||
sanity_check_dict('versions')
|
||||
sanity_check_dict('dependencies')
|
||||
sanity_check_dict('conflicted')
|
||||
sanity_check_dict('patches')
|
||||
|
||||
# Check versions in the versions dict.
|
||||
for v in self.versions:
|
||||
assert(isinstance(v, Version))
|
||||
|
||||
# Check version descriptors
|
||||
for v in sorted(self.versions):
|
||||
vdesc = self.versions[v]
|
||||
assert(isinstance(vdesc, spack.relations.VersionDescriptor))
|
||||
|
||||
# Version-ize the keys in versions dict
|
||||
try:
|
||||
self.versions = { Version(v):h for v,h in self.versions.items() }
|
||||
self.versions = dict((Version(v), h) for v,h in self.versions.items())
|
||||
except ValueError:
|
||||
raise ValueError("Keys of versions dict in package %s must be versions!"
|
||||
% self.name)
|
||||
@ -366,6 +369,10 @@ def __init__(self, spec):
|
||||
# stage used to build this package.
|
||||
self._stage = None
|
||||
|
||||
# patch up self.url based on the actual version
|
||||
if self.spec.concrete:
|
||||
self.url = self.url_for_version(self.version)
|
||||
|
||||
# Set a default list URL (place to find available versions)
|
||||
if not hasattr(self, 'list_url'):
|
||||
self.list_url = None
|
||||
@ -374,18 +381,6 @@ def __init__(self, spec):
|
||||
self.list_depth = 1
|
||||
|
||||
|
||||
@property
|
||||
def default_version(self):
|
||||
"""Get the version in the default URL for this package,
|
||||
or fails."""
|
||||
try:
|
||||
return url.parse_version(self.__class__.url)
|
||||
except UndetectableVersionError:
|
||||
raise PackageError(
|
||||
"Couldn't extract a default version from %s." % self.url,
|
||||
" You must specify it explicitly in the package file.")
|
||||
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
if not self.spec.concrete:
|
||||
@ -399,9 +394,13 @@ def stage(self):
|
||||
raise ValueError("Can only get a stage for a concrete package.")
|
||||
|
||||
if self._stage is None:
|
||||
if not self.url:
|
||||
raise PackageVersionError(self.version)
|
||||
|
||||
# TODO: move this logic into a mirror module.
|
||||
mirror_path = "%s/%s" % (self.name, "%s-%s.%s" % (
|
||||
self.name, self.version, extension(self.url)))
|
||||
|
||||
self._stage = Stage(
|
||||
self.url, mirror_path=mirror_path, name=self.spec.short_spec)
|
||||
return self._stage
|
||||
@ -496,7 +495,7 @@ def installed_dependents(self):
|
||||
on this one."""
|
||||
dependents = []
|
||||
for spec in spack.db.installed_package_specs():
|
||||
if self.spec != spec and self.spec in spec:
|
||||
if self.name != spec.name and self.spec in spec:
|
||||
dependents.append(spec)
|
||||
return dependents
|
||||
|
||||
@ -507,6 +506,14 @@ def prefix(self):
|
||||
return self.spec.prefix
|
||||
|
||||
|
||||
@property
|
||||
def compiler(self):
|
||||
"""Get the spack.compiler.Compiler object used to build this package."""
|
||||
if not self.spec.concrete:
|
||||
raise ValueError("Can only get a compiler for a concrete package.")
|
||||
return spack.compilers.compiler_for_spec(self.spec.compiler)
|
||||
|
||||
|
||||
def url_version(self, version):
|
||||
"""Given a version, this returns a string that should be substituted into the
|
||||
package's URL to download that version.
|
||||
@ -514,16 +521,48 @@ def url_version(self, version):
|
||||
override this, e.g. for boost versions where you need to ensure that there
|
||||
are _'s in the download URL.
|
||||
"""
|
||||
if self.force_url:
|
||||
return self.default_version
|
||||
return str(version)
|
||||
|
||||
|
||||
def url_for_version(self, version):
|
||||
"""Gives a URL that you can download a new version of this package from."""
|
||||
if self.force_url:
|
||||
return self.url
|
||||
return url.substitute_version(self.__class__.url, self.url_version(version))
|
||||
"""Returns a URL that you can download a new version of this package from."""
|
||||
if not isinstance(version, Version):
|
||||
version = Version(version)
|
||||
|
||||
def nearest_url(version):
|
||||
"""Finds the URL for the next lowest version with a URL.
|
||||
If there is no lower version with a URL, uses the
|
||||
package url property. If that isn't there, uses a
|
||||
*higher* URL, and if that isn't there raises an error.
|
||||
"""
|
||||
url = getattr(self, 'url', None)
|
||||
for v in sorted(self.versions):
|
||||
if v > version and url:
|
||||
break
|
||||
if self.versions[v].url:
|
||||
url = self.versions[v].url
|
||||
return url
|
||||
|
||||
if version in self.versions:
|
||||
vdesc = self.versions[version]
|
||||
if not vdesc.url:
|
||||
base_url = nearest_url(version)
|
||||
vdesc.url = url.substitute_version(
|
||||
base_url, self.url_version(version))
|
||||
return vdesc.url
|
||||
else:
|
||||
return nearest_url(version)
|
||||
|
||||
|
||||
@property
|
||||
def default_url(self):
|
||||
if self.concrete:
|
||||
return self.url_for_version(self.version)
|
||||
else:
|
||||
url = getattr(self, 'url', None)
|
||||
if url:
|
||||
return url
|
||||
|
||||
|
||||
|
||||
def remove_prefix(self):
|
||||
@ -548,7 +587,7 @@ def do_fetch(self):
|
||||
self.stage.fetch()
|
||||
|
||||
if spack.do_checksum and self.version in self.versions:
|
||||
digest = self.versions[self.version]
|
||||
digest = self.versions[self.version].checksum
|
||||
self.stage.check(digest)
|
||||
tty.msg("Checksum passed for %s@%s" % (self.name, self.version))
|
||||
|
||||
@ -743,7 +782,7 @@ def do_uninstall(self, **kwargs):
|
||||
' '.join(formatted_deps))
|
||||
|
||||
self.remove_prefix()
|
||||
tty.msg("Successfully uninstalled %s." % self.spec)
|
||||
tty.msg("Successfully uninstalled %s." % self.spec.short_spec)
|
||||
|
||||
# Once everything else is done, run post install hooks
|
||||
spack.hooks.post_uninstall(self)
|
||||
@ -779,6 +818,9 @@ def do_clean_dist(self):
|
||||
|
||||
|
||||
def fetch_available_versions(self):
|
||||
if not hasattr(self, 'url'):
|
||||
raise VersionFetchError(self.__class__)
|
||||
|
||||
# If not, then try to fetch using list_url
|
||||
if not self._available_versions:
|
||||
try:
|
||||
@ -865,7 +907,6 @@ def print_pkg(message):
|
||||
print message
|
||||
|
||||
|
||||
|
||||
class FetchError(spack.error.SpackError):
|
||||
"""Raised when something goes wrong during fetch."""
|
||||
def __init__(self, message, long_msg=None):
|
||||
@ -889,3 +930,19 @@ class InvalidPackageDependencyError(PackageError):
|
||||
its dependencies."""
|
||||
def __init__(self, message):
|
||||
super(InvalidPackageDependencyError, self).__init__(message)
|
||||
|
||||
|
||||
class PackageVersionError(PackageError):
|
||||
"""Raised when a version URL cannot automatically be determined."""
|
||||
def __init__(self, version):
|
||||
super(PackageVersionError, self).__init__(
|
||||
"Cannot determine a URL automatically for version %s." % version,
|
||||
"Please provide a url for this version in the package.py file.")
|
||||
|
||||
|
||||
class VersionFetchError(PackageError):
|
||||
"""Raised when a version URL cannot automatically be determined."""
|
||||
def __init__(self, cls):
|
||||
super(VersionFetchError, self).__init__(
|
||||
"Cannot fetch version for package %s " % cls.__name__ +
|
||||
"because it does not define a default url.")
|
||||
|
@ -69,9 +69,12 @@ def get(self, spec):
|
||||
|
||||
if not spec in self.instances:
|
||||
package_class = self.get_class_for_package_name(spec.name)
|
||||
self.instances[spec.name] = package_class(spec)
|
||||
try:
|
||||
self.instances[spec.copy()] = package_class(spec)
|
||||
except Exception, e:
|
||||
raise FailedConstructorError(spec.name, e)
|
||||
|
||||
return self.instances[spec.name]
|
||||
return self.instances[spec]
|
||||
|
||||
|
||||
@_autospec
|
||||
@ -115,7 +118,23 @@ def installed_package_specs(self):
|
||||
"""Read installed package names straight from the install directory
|
||||
layout.
|
||||
"""
|
||||
return spack.install_layout.all_specs()
|
||||
# Get specs from the directory layout but ensure that they're
|
||||
# all normalized properly.
|
||||
installed = []
|
||||
for spec in spack.install_layout.all_specs():
|
||||
spec.normalize()
|
||||
installed.append(spec)
|
||||
return installed
|
||||
|
||||
|
||||
def installed_known_package_specs(self):
|
||||
"""Read installed package names straight from the install
|
||||
directory layout, but return only specs for which the
|
||||
package is known to this version of spack.
|
||||
"""
|
||||
for spec in spack.install_layout.all_specs():
|
||||
if self.exists(spec.name):
|
||||
yield spec
|
||||
|
||||
|
||||
@memoized
|
||||
@ -179,24 +198,6 @@ def get_class_for_package_name(self, pkg_name):
|
||||
return cls
|
||||
|
||||
|
||||
def compute_dependents(self):
|
||||
"""Reads in all package files and sets dependence information on
|
||||
Package objects in memory.
|
||||
"""
|
||||
if not hasattr(compute_dependents, index):
|
||||
compute_dependents.index = {}
|
||||
|
||||
for pkg in all_packages():
|
||||
if pkg._dependents is None:
|
||||
pkg._dependents = []
|
||||
|
||||
for name, dep in pkg.dependencies.iteritems():
|
||||
dpkg = self.get(name)
|
||||
if dpkg._dependents is None:
|
||||
dpkg._dependents = []
|
||||
dpkg._dependents.append(pkg.name)
|
||||
|
||||
|
||||
def graph_dependencies(self, out=sys.stdout):
|
||||
"""Print out a graph of all the dependencies between package.
|
||||
Graph is in dot format."""
|
||||
@ -211,10 +212,17 @@ def quote(string):
|
||||
return '"%s"' % string
|
||||
|
||||
deps = []
|
||||
for pkg in all_packages():
|
||||
for pkg in self.all_packages():
|
||||
out.write(' %-30s [label="%s"]\n' % (quote(pkg.name), pkg.name))
|
||||
|
||||
# Add edges for each depends_on in the package.
|
||||
for dep_name, dep in pkg.dependencies.iteritems():
|
||||
deps.append((pkg.name, dep_name))
|
||||
|
||||
# If the package provides something, add an edge for that.
|
||||
for provider in set(p.name for p in pkg.provided):
|
||||
deps.append((provider, pkg.name))
|
||||
|
||||
out.write('\n')
|
||||
|
||||
for pair in deps:
|
||||
@ -227,3 +235,12 @@ class UnknownPackageError(spack.error.SpackError):
|
||||
def __init__(self, name):
|
||||
super(UnknownPackageError, self).__init__("Package %s not found." % name)
|
||||
self.name = name
|
||||
|
||||
|
||||
class FailedConstructorError(spack.error.SpackError):
|
||||
"""Raised when a package's class constructor fails."""
|
||||
def __init__(self, name, reason):
|
||||
super(FailedConstructorError, self).__init__(
|
||||
"Class constructor failed for package '%s'." % name,
|
||||
str(reason))
|
||||
self.name = name
|
||||
|
@ -68,23 +68,48 @@ class Mpileaks(Package):
|
||||
spack install mpileaks ^mvapich
|
||||
spack install mpileaks ^mpich
|
||||
"""
|
||||
__all__ = [ 'depends_on', 'provides', 'patch', 'version' ]
|
||||
|
||||
import re
|
||||
import inspect
|
||||
import importlib
|
||||
|
||||
from llnl.util.lang import *
|
||||
|
||||
import spack
|
||||
import spack.spec
|
||||
import spack.error
|
||||
import spack.url
|
||||
|
||||
from spack.version import Version
|
||||
from spack.patch import Patch
|
||||
from spack.spec import Spec, parse_anonymous_spec
|
||||
|
||||
|
||||
"""Adds a dependencies local variable in the locals of
|
||||
the calling class, based on args. """
|
||||
class VersionDescriptor(object):
|
||||
"""A VersionDescriptor contains information to describe a
|
||||
particular version of a package. That currently includes a URL
|
||||
for the version along with a checksum."""
|
||||
def __init__(self, checksum, url):
|
||||
self.checksum = checksum
|
||||
self.url = url
|
||||
|
||||
|
||||
def version(ver, checksum, **kwargs):
|
||||
"""Adds a version and associated metadata to the package."""
|
||||
pkg = caller_locals()
|
||||
|
||||
versions = pkg.setdefault('versions', {})
|
||||
patches = pkg.setdefault('patches', {})
|
||||
|
||||
ver = Version(ver)
|
||||
url = kwargs.get('url', None)
|
||||
|
||||
versions[ver] = VersionDescriptor(checksum, url)
|
||||
|
||||
|
||||
def depends_on(*specs):
|
||||
"""Adds a dependencies local variable in the locals of
|
||||
the calling class, based on args. """
|
||||
pkg = get_calling_package_name()
|
||||
|
||||
dependencies = caller_locals().setdefault('dependencies', {})
|
||||
|
@ -94,6 +94,7 @@
|
||||
import itertools
|
||||
import hashlib
|
||||
from StringIO import StringIO
|
||||
from operator import attrgetter
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.lang import *
|
||||
@ -309,9 +310,8 @@ def concrete(self):
|
||||
|
||||
|
||||
def __str__(self):
|
||||
sorted_dep_names = sorted(self.keys())
|
||||
return ''.join(
|
||||
["^" + str(self[name]) for name in sorted_dep_names])
|
||||
["^" + str(self[name]) for name in sorted(self.keys())])
|
||||
|
||||
|
||||
@key_ordering
|
||||
@ -345,6 +345,13 @@ def __init__(self, spec_like, *dep_like, **kwargs):
|
||||
self.compiler = other.compiler
|
||||
self.dependencies = other.dependencies
|
||||
|
||||
# Specs are by default not assumed to be normal, but in some
|
||||
# cases we've read them from a file want to assume normal.
|
||||
# This allows us to manipulate specs that Spack doesn't have
|
||||
# package.py files for.
|
||||
self._normal = kwargs.get('normal', False)
|
||||
self._concrete = kwargs.get('concrete', False)
|
||||
|
||||
# This allows users to construct a spec DAG with literals.
|
||||
# Note that given two specs a and b, Spec(a) copies a, but
|
||||
# Spec(a, b) will copy a but just add b as a dep.
|
||||
@ -432,17 +439,30 @@ def concrete(self):
|
||||
If any of the name, version, architecture, compiler, or depdenencies
|
||||
are ambiguous,then it is not concrete.
|
||||
"""
|
||||
return bool(not self.virtual
|
||||
and self.versions.concrete
|
||||
and self.architecture
|
||||
and self.compiler and self.compiler.concrete
|
||||
and self.dependencies.concrete)
|
||||
if self._concrete:
|
||||
return True
|
||||
|
||||
self._concrete = bool(not self.virtual
|
||||
and self.versions.concrete
|
||||
and self.architecture
|
||||
and self.compiler and self.compiler.concrete
|
||||
and self.dependencies.concrete)
|
||||
return self._concrete
|
||||
|
||||
|
||||
def preorder_traversal(self, visited=None, d=0, **kwargs):
|
||||
"""Generic preorder traversal of the DAG represented by this spec.
|
||||
def traverse(self, visited=None, d=0, **kwargs):
|
||||
"""Generic traversal of the DAG represented by this spec.
|
||||
This will yield each node in the spec. Options:
|
||||
|
||||
order [=pre|post]
|
||||
Order to traverse spec nodes. Defaults to preorder traversal.
|
||||
Options are:
|
||||
|
||||
'pre': Pre-order traversal; each node is yielded before its
|
||||
children in the dependency DAG.
|
||||
'post': Post-order traversal; each node is yielded after its
|
||||
children in the dependency DAG.
|
||||
|
||||
cover [=nodes|edges|paths]
|
||||
Determines how extensively to cover the dag. Possible vlaues:
|
||||
|
||||
@ -460,7 +480,7 @@ def preorder_traversal(self, visited=None, d=0, **kwargs):
|
||||
spec, but also their depth from the root in a (depth, node)
|
||||
tuple.
|
||||
|
||||
keyfun [=id]
|
||||
key [=id]
|
||||
Allow a custom key function to track the identity of nodes
|
||||
in the traversal.
|
||||
|
||||
@ -472,44 +492,57 @@ def preorder_traversal(self, visited=None, d=0, **kwargs):
|
||||
'parents', traverses upwards in the DAG towards the root.
|
||||
|
||||
"""
|
||||
# get initial values for kwargs
|
||||
depth = kwargs.get('depth', False)
|
||||
key_fun = kwargs.get('key', id)
|
||||
if isinstance(key_fun, basestring):
|
||||
key_fun = attrgetter(key_fun)
|
||||
yield_root = kwargs.get('root', True)
|
||||
cover = kwargs.get('cover', 'nodes')
|
||||
direction = kwargs.get('direction', 'children')
|
||||
order = kwargs.get('order', 'pre')
|
||||
|
||||
cover_values = ('nodes', 'edges', 'paths')
|
||||
if cover not in cover_values:
|
||||
raise ValueError("Invalid value for cover: %s. Choices are %s"
|
||||
% (cover, ",".join(cover_values)))
|
||||
|
||||
direction_values = ('children', 'parents')
|
||||
if direction not in direction_values:
|
||||
raise ValueError("Invalid value for direction: %s. Choices are %s"
|
||||
% (direction, ",".join(direction_values)))
|
||||
# Make sure kwargs have legal values; raise ValueError if not.
|
||||
def validate(name, val, allowed_values):
|
||||
if val not in allowed_values:
|
||||
raise ValueError("Invalid value for %s: %s. Choices are %s"
|
||||
% (name, val, ",".join(allowed_values)))
|
||||
validate('cover', cover, ('nodes', 'edges', 'paths'))
|
||||
validate('direction', direction, ('children', 'parents'))
|
||||
validate('order', order, ('pre', 'post'))
|
||||
|
||||
if visited is None:
|
||||
visited = set()
|
||||
|
||||
result = (d, self) if depth else self
|
||||
key = key_fun(self)
|
||||
|
||||
if key in visited:
|
||||
if cover == 'nodes': return
|
||||
if yield_root or d > 0: yield result
|
||||
if cover == 'edges': return
|
||||
else:
|
||||
if yield_root or d > 0: yield result
|
||||
# Node traversal does not yield visited nodes.
|
||||
if key in visited and cover == 'nodes':
|
||||
return
|
||||
|
||||
successors = self.dependencies
|
||||
if direction == 'parents':
|
||||
successors = self.dependents
|
||||
# Determine whether and what to yield for this node.
|
||||
yield_me = yield_root or d > 0
|
||||
result = (d, self) if depth else self
|
||||
|
||||
visited.add(key)
|
||||
for name in sorted(successors):
|
||||
child = successors[name]
|
||||
for elt in child.preorder_traversal(visited, d+1, **kwargs):
|
||||
yield elt
|
||||
# Preorder traversal yields before successors
|
||||
if yield_me and order == 'pre':
|
||||
yield result
|
||||
|
||||
# Edge traversal yields but skips children of visited nodes
|
||||
if not (key in visited and cover == 'edges'):
|
||||
# This code determines direction and yields the children/parents
|
||||
successors = self.dependencies
|
||||
if direction == 'parents':
|
||||
successors = self.dependents
|
||||
|
||||
visited.add(key)
|
||||
for name in sorted(successors):
|
||||
child = successors[name]
|
||||
for elt in child.traverse(visited, d+1, **kwargs):
|
||||
yield elt
|
||||
|
||||
# Postorder traversal yields after successors
|
||||
if yield_me and order == 'post':
|
||||
yield result
|
||||
|
||||
|
||||
@property
|
||||
@ -525,13 +558,14 @@ def prefix(self):
|
||||
|
||||
|
||||
def dep_hash(self, length=None):
|
||||
"""Return a hash representing the dependencies of this spec
|
||||
This will always normalize first so that the hash is consistent.
|
||||
"""
|
||||
self.normalize()
|
||||
"""Return a hash representing all dependencies of this spec
|
||||
(direct and indirect).
|
||||
|
||||
If you want this hash to be consistent, you should
|
||||
concretize the spec first so that it is not ambiguous.
|
||||
"""
|
||||
sha = hashlib.sha1()
|
||||
sha.update(str(self.dependencies))
|
||||
sha.update(self.dep_string())
|
||||
full_hash = sha.hexdigest()
|
||||
|
||||
return full_hash[:length]
|
||||
@ -594,7 +628,7 @@ def _expand_virtual_packages(self):
|
||||
a problem.
|
||||
"""
|
||||
while True:
|
||||
virtuals =[v for v in self.preorder_traversal() if v.virtual]
|
||||
virtuals =[v for v in self.traverse() if v.virtual]
|
||||
if not virtuals:
|
||||
return
|
||||
|
||||
@ -605,8 +639,8 @@ def _expand_virtual_packages(self):
|
||||
spec._replace_with(concrete)
|
||||
|
||||
# If there are duplicate providers or duplicate provider deps, this
|
||||
# consolidates them and merges constraints.
|
||||
self.normalize()
|
||||
# consolidates them and merge constraints.
|
||||
self.normalize(force=True)
|
||||
|
||||
|
||||
def concretize(self):
|
||||
@ -621,9 +655,13 @@ def concretize(self):
|
||||
with requirements of its pacakges. See flatten() and normalize() for
|
||||
more details on this.
|
||||
"""
|
||||
if self._concrete:
|
||||
return
|
||||
|
||||
self.normalize()
|
||||
self._expand_virtual_packages()
|
||||
self._concretize_helper()
|
||||
self._concrete = True
|
||||
|
||||
|
||||
def concretized(self):
|
||||
@ -635,47 +673,51 @@ def concretized(self):
|
||||
return clone
|
||||
|
||||
|
||||
def flat_dependencies(self):
|
||||
"""Return a DependencyMap containing all of this spec's dependencies
|
||||
with their constraints merged. If there are any conflicts, throw
|
||||
an exception.
|
||||
def flat_dependencies(self, **kwargs):
|
||||
"""Return a DependencyMap containing all of this spec's
|
||||
dependencies with their constraints merged.
|
||||
|
||||
This will work even on specs that are not normalized; i.e. specs
|
||||
that have two instances of the same dependency in the DAG.
|
||||
This is used as the first step of normalization.
|
||||
If copy is True, returns merged copies of its dependencies
|
||||
without modifying the spec it's called on.
|
||||
|
||||
If copy is False, clears this spec's dependencies and
|
||||
returns them.
|
||||
"""
|
||||
# This ensures that the package descriptions themselves are consistent
|
||||
if not self.virtual:
|
||||
self.package.validate_dependencies()
|
||||
copy = kwargs.get('copy', True)
|
||||
|
||||
# Once that is guaranteed, we know any constraint violations are due
|
||||
# to the spec -- so they're the user's fault, not Spack's.
|
||||
flat_deps = DependencyMap()
|
||||
try:
|
||||
for spec in self.preorder_traversal():
|
||||
for spec in self.traverse(root=False):
|
||||
if spec.name not in flat_deps:
|
||||
new_spec = spec.copy(dependencies=False)
|
||||
flat_deps[spec.name] = new_spec
|
||||
|
||||
if copy:
|
||||
flat_deps[spec.name] = spec.copy(deps=False)
|
||||
else:
|
||||
flat_deps[spec.name] = spec
|
||||
else:
|
||||
flat_deps[spec.name].constrain(spec)
|
||||
|
||||
except UnsatisfiableSpecError, e:
|
||||
# This REALLY shouldn't happen unless something is wrong in spack.
|
||||
# It means we got a spec DAG with two instances of the same package
|
||||
# that had inconsistent constraints. There's no way for a user to
|
||||
# produce a spec like this (the parser adds all deps to the root),
|
||||
# so this means OUR code is not sane!
|
||||
raise InconsistentSpecError("Invalid Spec DAG: %s" % e.message)
|
||||
if not copy:
|
||||
for dep in flat_deps.values():
|
||||
dep.dependencies.clear()
|
||||
dep.dependents.clear()
|
||||
self.dependencies.clear()
|
||||
|
||||
return flat_deps
|
||||
return flat_deps
|
||||
|
||||
except UnsatisfiableSpecError, e:
|
||||
# Here, the DAG contains two instances of the same package
|
||||
# with inconsistent constraints. Users cannot produce
|
||||
# inconsistent specs like this on the command line: the
|
||||
# parser doesn't allow it. Spack must be broken!
|
||||
raise InconsistentSpecError("Invalid Spec DAG: %s" % e.message)
|
||||
|
||||
|
||||
def flatten(self):
|
||||
"""Pull all dependencies up to the root (this spec).
|
||||
Merge constraints for dependencies with the same name, and if they
|
||||
conflict, throw an exception. """
|
||||
self.dependencies = self.flat_dependencies()
|
||||
for dep in self.flat_dependencies(copy=False):
|
||||
self._add_dependency(dep)
|
||||
|
||||
|
||||
def _normalize_helper(self, visited, spec_deps, provider_index):
|
||||
@ -754,7 +796,7 @@ def _normalize_helper(self, visited, spec_deps, provider_index):
|
||||
dependency._normalize_helper(visited, spec_deps, provider_index)
|
||||
|
||||
|
||||
def normalize(self):
|
||||
def normalize(self, **kwargs):
|
||||
"""When specs are parsed, any dependencies specified are hanging off
|
||||
the root, and ONLY the ones that were explicitly provided are there.
|
||||
Normalization turns a partial flat spec into a DAG, where:
|
||||
@ -772,14 +814,18 @@ def normalize(self):
|
||||
TODO: normalize should probably implement some form of cycle detection,
|
||||
to ensure that the spec is actually a DAG.
|
||||
"""
|
||||
if self._normal and not kwargs.get('force', False):
|
||||
return
|
||||
|
||||
# Ensure first that all packages & compilers in the DAG exist.
|
||||
self.validate_names()
|
||||
|
||||
# Then ensure that the packages referenced are sane, that the
|
||||
# provided spec is sane, and that all dependency specs are in the
|
||||
# root node of the spec. flat_dependencies will do this for us.
|
||||
spec_deps = self.flat_dependencies()
|
||||
self.dependencies.clear()
|
||||
# Ensure that the package & dep descriptions are consistent & sane
|
||||
if not self.virtual:
|
||||
self.package.validate_dependencies()
|
||||
|
||||
# Get all the dependencies into one DependencyMap
|
||||
spec_deps = self.flat_dependencies(copy=False)
|
||||
|
||||
# Figure out which of the user-provided deps provide virtual deps.
|
||||
# Remove virtual deps that are already provided by something in the spec
|
||||
@ -792,7 +838,7 @@ def normalize(self):
|
||||
|
||||
# If there are deps specified but not visited, they're not
|
||||
# actually deps of this package. Raise an error.
|
||||
extra = set(spec_deps.viewkeys()).difference(visited)
|
||||
extra = set(spec_deps.keys()).difference(visited)
|
||||
|
||||
# Also subtract out all the packags that provide a needed vpkg
|
||||
vdeps = [v for v in self.package.virtual_dependencies()]
|
||||
@ -805,6 +851,9 @@ def normalize(self):
|
||||
raise InvalidDependencyException(
|
||||
self.name + " does not depend on " + comma_or(extra))
|
||||
|
||||
# Mark the spec as normal once done.
|
||||
self._normal = True
|
||||
|
||||
|
||||
def normalized(self):
|
||||
"""Return a normalized copy of this spec without modifying this spec."""
|
||||
@ -818,7 +867,7 @@ def validate_names(self):
|
||||
If they're not, it will raise either UnknownPackageError or
|
||||
UnsupportedCompilerError.
|
||||
"""
|
||||
for spec in self.preorder_traversal():
|
||||
for spec in self.traverse():
|
||||
# Don't get a package for a virtual name.
|
||||
if not spec.virtual:
|
||||
spack.db.get(spec.name)
|
||||
@ -886,17 +935,17 @@ def _constrain_dependencies(self, other):
|
||||
def common_dependencies(self, other):
|
||||
"""Return names of dependencies that self an other have in common."""
|
||||
common = set(
|
||||
s.name for s in self.preorder_traversal(root=False))
|
||||
s.name for s in self.traverse(root=False))
|
||||
common.intersection_update(
|
||||
s.name for s in other.preorder_traversal(root=False))
|
||||
s.name for s in other.traverse(root=False))
|
||||
return common
|
||||
|
||||
|
||||
def dep_difference(self, other):
|
||||
"""Returns dependencies in self that are not in other."""
|
||||
mine = set(s.name for s in self.preorder_traversal(root=False))
|
||||
mine = set(s.name for s in self.traverse(root=False))
|
||||
mine.difference_update(
|
||||
s.name for s in other.preorder_traversal(root=False))
|
||||
s.name for s in other.traverse(root=False))
|
||||
return mine
|
||||
|
||||
|
||||
@ -955,8 +1004,8 @@ def satisfies_dependencies(self, other):
|
||||
return False
|
||||
|
||||
# For virtual dependencies, we need to dig a little deeper.
|
||||
self_index = ProviderIndex(self.preorder_traversal(), restrict=True)
|
||||
other_index = ProviderIndex(other.preorder_traversal(), restrict=True)
|
||||
self_index = ProviderIndex(self.traverse(), restrict=True)
|
||||
other_index = ProviderIndex(other.traverse(), restrict=True)
|
||||
|
||||
# This handles cases where there are already providers for both vpkgs
|
||||
if not self_index.satisfies(other_index):
|
||||
@ -978,7 +1027,7 @@ def satisfies_dependencies(self, other):
|
||||
|
||||
def virtual_dependencies(self):
|
||||
"""Return list of any virtual deps in this spec."""
|
||||
return [spec for spec in self.preorder_traversal() if spec.virtual]
|
||||
return [spec for spec in self.traverse() if spec.virtual]
|
||||
|
||||
|
||||
def _dup(self, other, **kwargs):
|
||||
@ -993,21 +1042,31 @@ def _dup(self, other, **kwargs):
|
||||
Whether deps should be copied too. Set to false to copy a
|
||||
spec but not its dependencies.
|
||||
"""
|
||||
# TODO: this needs to handle DAGs.
|
||||
# Local node attributes get copied first.
|
||||
self.name = other.name
|
||||
self.versions = other.versions.copy()
|
||||
self.variants = other.variants.copy()
|
||||
self.architecture = other.architecture
|
||||
self.compiler = None
|
||||
if other.compiler:
|
||||
self.compiler = other.compiler.copy()
|
||||
|
||||
self.compiler = other.compiler.copy() if other.compiler else None
|
||||
self.dependents = DependencyMap()
|
||||
copy_deps = kwargs.get('dependencies', True)
|
||||
if copy_deps:
|
||||
self.dependencies = other.dependencies.copy()
|
||||
else:
|
||||
self.dependencies = DependencyMap()
|
||||
self.dependencies = DependencyMap()
|
||||
|
||||
# If we copy dependencies, preserve DAG structure in the new spec
|
||||
if kwargs.get('deps', True):
|
||||
# This copies the deps from other using _dup(deps=False)
|
||||
new_nodes = other.flat_dependencies()
|
||||
new_nodes[self.name] = self
|
||||
|
||||
# Hook everything up properly here by traversing.
|
||||
for spec in other.traverse(cover='nodes'):
|
||||
parent = new_nodes[spec.name]
|
||||
for child in spec.dependencies:
|
||||
if child not in parent.dependencies:
|
||||
parent._add_dependency(new_nodes[child])
|
||||
|
||||
# Since we preserved structure, we can copy _normal safely.
|
||||
self._normal = other._normal
|
||||
self._concrete = other._concrete
|
||||
|
||||
|
||||
def copy(self, **kwargs):
|
||||
@ -1029,7 +1088,7 @@ def version(self):
|
||||
|
||||
def __getitem__(self, name):
|
||||
"""TODO: reconcile __getitem__, _add_dependency, __contains__"""
|
||||
for spec in self.preorder_traversal():
|
||||
for spec in self.traverse():
|
||||
if spec.name == name:
|
||||
return spec
|
||||
|
||||
@ -1040,15 +1099,82 @@ def __contains__(self, spec):
|
||||
"""True if this spec has any dependency that satisfies the supplied
|
||||
spec."""
|
||||
spec = self._autospec(spec)
|
||||
for s in self.preorder_traversal():
|
||||
for s in self.traverse():
|
||||
if s.satisfies(spec):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _cmp_key(self):
|
||||
def sorted_deps(self):
|
||||
"""Return a list of all dependencies sorted by name."""
|
||||
deps = self.flat_dependencies()
|
||||
return tuple(deps[name] for name in sorted(deps))
|
||||
|
||||
|
||||
def _eq_dag(self, other, vs, vo):
|
||||
"""Recursive helper for eq_dag and ne_dag. Does the actual DAG
|
||||
traversal."""
|
||||
vs.add(id(self))
|
||||
vo.add(id(other))
|
||||
|
||||
if self.ne_node(other):
|
||||
return False
|
||||
|
||||
if len(self.dependencies) != len(other.dependencies):
|
||||
return False
|
||||
|
||||
ssorted = [self.dependencies[name] for name in sorted(self.dependencies)]
|
||||
osorted = [other.dependencies[name] for name in sorted(other.dependencies)]
|
||||
|
||||
for s, o in zip(ssorted, osorted):
|
||||
visited_s = id(s) in vs
|
||||
visited_o = id(o) in vo
|
||||
|
||||
# Check for duplicate or non-equal dependencies
|
||||
if visited_s != visited_o: return False
|
||||
|
||||
# Skip visited nodes
|
||||
if visited_s or visited_o: continue
|
||||
|
||||
# Recursive check for equality
|
||||
if not s._eq_dag(o, vs, vo):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def eq_dag(self, other):
|
||||
"""True if the full dependency DAGs of specs are equal"""
|
||||
return self._eq_dag(other, set(), set())
|
||||
|
||||
|
||||
def ne_dag(self, other):
|
||||
"""True if the full dependency DAGs of specs are not equal"""
|
||||
return not self.eq_dag(other)
|
||||
|
||||
|
||||
def _cmp_node(self):
|
||||
"""Comparison key for just *this node* and not its deps."""
|
||||
return (self.name, self.versions, self.variants,
|
||||
self.architecture, self.compiler, self.dependencies)
|
||||
self.architecture, self.compiler)
|
||||
|
||||
|
||||
def eq_node(self, other):
|
||||
"""Equality with another spec, not including dependencies."""
|
||||
return self._cmp_node() == other._cmp_node()
|
||||
|
||||
|
||||
def ne_node(self, other):
|
||||
"""Inequality with another spec, not including dependencies."""
|
||||
return self._cmp_node() != other._cmp_node()
|
||||
|
||||
|
||||
def _cmp_key(self):
|
||||
"""Comparison key for this node and all dependencies *without*
|
||||
considering structure. This is the default, as
|
||||
normalization will restore structure.
|
||||
"""
|
||||
return self._cmp_node() + (self.sorted_deps(),)
|
||||
|
||||
|
||||
def colorized(self):
|
||||
@ -1151,12 +1277,12 @@ def write(s, c):
|
||||
return result
|
||||
|
||||
|
||||
def dep_string(self):
|
||||
return ''.join("^" + dep.format() for dep in self.sorted_deps())
|
||||
|
||||
|
||||
def __str__(self):
|
||||
by_name = lambda d: d.name
|
||||
deps = self.preorder_traversal(key=by_name, root=False)
|
||||
sorted_deps = sorted(deps, key=by_name)
|
||||
dep_string = ''.join("^" + dep.format() for dep in sorted_deps)
|
||||
return self.format() + dep_string
|
||||
return self.format() + self.dep_string()
|
||||
|
||||
|
||||
def tree(self, **kwargs):
|
||||
@ -1172,7 +1298,7 @@ def tree(self, **kwargs):
|
||||
out = ""
|
||||
cur_id = 0
|
||||
ids = {}
|
||||
for d, node in self.preorder_traversal(cover=cover, depth=True):
|
||||
for d, node in self.traverse(order='pre', cover=cover, depth=True):
|
||||
out += " " * indent
|
||||
if depth:
|
||||
out += "%-4d" % d
|
||||
@ -1261,6 +1387,9 @@ def spec(self):
|
||||
spec.dependents = DependencyMap()
|
||||
spec.dependencies = DependencyMap()
|
||||
|
||||
spec._normal = False
|
||||
spec._concrete = False
|
||||
|
||||
# record this so that we know whether version is
|
||||
# unspecified or not.
|
||||
added_version = False
|
||||
|
@ -120,8 +120,7 @@ def _need_to_create_path(self):
|
||||
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 (os.path.commonprefix((real_path, real_tmp)) == real_tmp
|
||||
and os.path.exists(real_path)):
|
||||
if (real_path.startswith(real_tmp) and os.path.exists(real_path)):
|
||||
return False
|
||||
else:
|
||||
# otherwise, just unlink it and start over.
|
||||
|
@ -45,7 +45,9 @@
|
||||
'multimethod',
|
||||
'install',
|
||||
'package_sanity',
|
||||
'config']
|
||||
'config',
|
||||
'directory_layout',
|
||||
'python_version']
|
||||
|
||||
|
||||
def list_tests():
|
||||
@ -70,7 +72,7 @@ def run(names, verbose=False):
|
||||
|
||||
runner = unittest.TextTestRunner(verbosity=verbosity)
|
||||
|
||||
testsRun = errors = failures = skipped = 0
|
||||
testsRun = errors = failures = 0
|
||||
for test in names:
|
||||
module = 'spack.test.' + test
|
||||
print module
|
||||
@ -81,12 +83,10 @@ def run(names, verbose=False):
|
||||
testsRun += result.testsRun
|
||||
errors += len(result.errors)
|
||||
failures += len(result.failures)
|
||||
skipped += len(result.skipped)
|
||||
|
||||
succeeded = not errors and not failures
|
||||
tty.msg("Tests Complete.",
|
||||
"%5d tests run" % testsRun,
|
||||
"%5d skipped" % skipped,
|
||||
"%5d failures" % failures,
|
||||
"%5d errors" % errors)
|
||||
|
||||
|
@ -134,29 +134,29 @@ def test_concretize_with_provides_when(self):
|
||||
def test_virtual_is_fully_expanded_for_callpath(self):
|
||||
# force dependence on fake "zmpi" by asking for MPI 10.0
|
||||
spec = Spec('callpath ^mpi@10.0')
|
||||
self.assertIn('mpi', spec.dependencies)
|
||||
self.assertNotIn('fake', spec)
|
||||
self.assertTrue('mpi' in spec.dependencies)
|
||||
self.assertFalse('fake' in spec)
|
||||
|
||||
spec.concretize()
|
||||
|
||||
self.assertIn('zmpi', spec.dependencies)
|
||||
self.assertNotIn('mpi', spec)
|
||||
self.assertIn('fake', spec.dependencies['zmpi'])
|
||||
self.assertTrue('zmpi' in spec.dependencies)
|
||||
self.assertFalse('mpi' in spec)
|
||||
self.assertTrue('fake' in spec.dependencies['zmpi'])
|
||||
|
||||
|
||||
def test_virtual_is_fully_expanded_for_mpileaks(self):
|
||||
spec = Spec('mpileaks ^mpi@10.0')
|
||||
self.assertIn('mpi', spec.dependencies)
|
||||
self.assertNotIn('fake', spec)
|
||||
self.assertTrue('mpi' in spec.dependencies)
|
||||
self.assertFalse('fake' in spec)
|
||||
|
||||
spec.concretize()
|
||||
|
||||
self.assertIn('zmpi', spec.dependencies)
|
||||
self.assertIn('callpath', spec.dependencies)
|
||||
self.assertIn('zmpi', spec.dependencies['callpath'].dependencies)
|
||||
self.assertIn('fake', spec.dependencies['callpath'].dependencies['zmpi'].dependencies)
|
||||
self.assertTrue('zmpi' in spec.dependencies)
|
||||
self.assertTrue('callpath' in spec.dependencies)
|
||||
self.assertTrue('zmpi' in spec.dependencies['callpath'].dependencies)
|
||||
self.assertTrue('fake' in spec.dependencies['callpath'].dependencies['zmpi'].dependencies)
|
||||
|
||||
self.assertNotIn('mpi', spec)
|
||||
self.assertFalse('mpi' in spec)
|
||||
|
||||
|
||||
def test_my_dep_depends_on_provider_of_my_virtual_dep(self):
|
||||
|
155
lib/spack/spack/test/directory_layout.py
Normal file
155
lib/spack/spack/test/directory_layout.py
Normal file
@ -0,0 +1,155 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
"""\
|
||||
This test verifies that the Spack directory layout works properly.
|
||||
"""
|
||||
import unittest
|
||||
import tempfile
|
||||
import shutil
|
||||
import os
|
||||
from contextlib import closing
|
||||
|
||||
from llnl.util.filesystem import *
|
||||
|
||||
import spack
|
||||
from spack.spec import Spec
|
||||
from spack.packages import PackageDB
|
||||
from spack.directory_layout import SpecHashDirectoryLayout
|
||||
|
||||
class DirectoryLayoutTest(unittest.TestCase):
|
||||
"""Tests that a directory layout works correctly and produces a
|
||||
consistent install path."""
|
||||
|
||||
def setUp(self):
|
||||
self.tmpdir = tempfile.mkdtemp()
|
||||
self.layout = SpecHashDirectoryLayout(self.tmpdir)
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmpdir, ignore_errors=True)
|
||||
self.layout = None
|
||||
|
||||
|
||||
def test_read_and_write_spec(self):
|
||||
"""This goes through each package in spack and creates a directory for
|
||||
it. It then ensures that the spec for the directory's
|
||||
installed package can be read back in consistently, and
|
||||
finally that the directory can be removed by the directory
|
||||
layout.
|
||||
"""
|
||||
for pkg in spack.db.all_packages():
|
||||
spec = pkg.spec
|
||||
|
||||
# If a spec fails to concretize, just skip it. If it is a
|
||||
# real error, it will be caught by concretization tests.
|
||||
try:
|
||||
spec.concretize()
|
||||
except:
|
||||
continue
|
||||
|
||||
self.layout.make_path_for_spec(spec)
|
||||
|
||||
install_dir = self.layout.path_for_spec(spec)
|
||||
spec_path = self.layout.spec_file_path(spec)
|
||||
|
||||
# Ensure directory has been created in right place.
|
||||
self.assertTrue(os.path.isdir(install_dir))
|
||||
self.assertTrue(install_dir.startswith(self.tmpdir))
|
||||
|
||||
# Ensure spec file exists when directory is created
|
||||
self.assertTrue(os.path.isfile(spec_path))
|
||||
self.assertTrue(spec_path.startswith(install_dir))
|
||||
|
||||
# Make sure spec file can be read back in to get the original spec
|
||||
spec_from_file = self.layout.read_spec(spec_path)
|
||||
self.assertEqual(spec, spec_from_file)
|
||||
self.assertTrue(spec.eq_dag, spec_from_file)
|
||||
self.assertTrue(spec_from_file.concrete)
|
||||
|
||||
# Ensure that specs that come out "normal" are really normal.
|
||||
with closing(open(spec_path)) as spec_file:
|
||||
read_separately = Spec(spec_file.read())
|
||||
|
||||
read_separately.normalize()
|
||||
self.assertEqual(read_separately, spec_from_file)
|
||||
|
||||
read_separately.concretize()
|
||||
self.assertEqual(read_separately, spec_from_file)
|
||||
|
||||
# Make sure the dep hash of the read-in spec is the same
|
||||
self.assertEqual(spec.dep_hash(), spec_from_file.dep_hash())
|
||||
|
||||
# Ensure directories are properly removed
|
||||
self.layout.remove_path_for_spec(spec)
|
||||
self.assertFalse(os.path.isdir(install_dir))
|
||||
self.assertFalse(os.path.exists(install_dir))
|
||||
|
||||
|
||||
def test_handle_unknown_package(self):
|
||||
"""This test ensures that spack can at least do *some*
|
||||
operations with packages that are installed but that it
|
||||
does not know about. This is actually not such an uncommon
|
||||
scenario with spack; it can happen when you switch from a
|
||||
git branch where you're working on a new package.
|
||||
|
||||
This test ensures that the directory layout stores enough
|
||||
information about installed packages' specs to uninstall
|
||||
or query them again if the package goes away.
|
||||
"""
|
||||
mock_db = PackageDB(spack.mock_packages_path)
|
||||
|
||||
not_in_mock = set(spack.db.all_package_names()).difference(
|
||||
set(mock_db.all_package_names()))
|
||||
|
||||
# Create all the packages that are not in mock.
|
||||
installed_specs = {}
|
||||
for pkg_name in not_in_mock:
|
||||
spec = spack.db.get(pkg_name).spec
|
||||
|
||||
# If a spec fails to concretize, just skip it. If it is a
|
||||
# real error, it will be caught by concretization tests.
|
||||
try:
|
||||
spec.concretize()
|
||||
except:
|
||||
continue
|
||||
|
||||
self.layout.make_path_for_spec(spec)
|
||||
installed_specs[spec] = self.layout.path_for_spec(spec)
|
||||
|
||||
tmp = spack.db
|
||||
spack.db = mock_db
|
||||
|
||||
# Now check that even without the package files, we know
|
||||
# enough to read a spec from the spec file.
|
||||
for spec, path in installed_specs.items():
|
||||
spec_from_file = self.layout.read_spec(join_path(path, '.spec'))
|
||||
|
||||
# To satisfy these conditions, directory layouts need to
|
||||
# read in concrete specs from their install dirs somehow.
|
||||
self.assertEqual(path, self.layout.path_for_spec(spec_from_file))
|
||||
self.assertEqual(spec, spec_from_file)
|
||||
self.assertEqual(spec.dep_hash(), spec_from_file.dep_hash())
|
||||
|
||||
spack.db = tmp
|
@ -25,15 +25,18 @@
|
||||
import os
|
||||
import unittest
|
||||
import shutil
|
||||
import tempfile
|
||||
from contextlib import closing
|
||||
|
||||
from llnl.util.filesystem import *
|
||||
|
||||
import spack
|
||||
from spack.stage import Stage
|
||||
from spack.directory_layout import SpecHashDirectoryLayout
|
||||
from spack.util.executable import which
|
||||
from spack.test.mock_packages_test import *
|
||||
|
||||
|
||||
dir_name = 'trivial-1.0'
|
||||
archive_name = 'trivial-1.0.tar.gz'
|
||||
install_test_package = 'trivial_install_test_package'
|
||||
@ -66,9 +69,16 @@ def setUp(self):
|
||||
tar = which('tar')
|
||||
tar('-czf', archive_name, dir_name)
|
||||
|
||||
# We use a fake pacakge, so skip the checksum.
|
||||
# We use a fake package, so skip the checksum.
|
||||
spack.do_checksum = False
|
||||
|
||||
# Use a fake install directory to avoid conflicts bt/w
|
||||
# installed pkgs and mock packages.
|
||||
self.tmpdir = tempfile.mkdtemp()
|
||||
self.orig_layout = spack.install_layout
|
||||
spack.install_layout = SpecHashDirectoryLayout(self.tmpdir)
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
super(InstallTest, self).tearDown()
|
||||
|
||||
@ -78,6 +88,10 @@ def tearDown(self):
|
||||
# Turn checksumming back on
|
||||
spack.do_checksum = True
|
||||
|
||||
# restore spack's layout.
|
||||
spack.install_layout = self.orig_layout
|
||||
shutil.rmtree(self.tmpdir, ignore_errors=True)
|
||||
|
||||
|
||||
def test_install_and_uninstall(self):
|
||||
# Get a basic concrete spec for the trivial install package.
|
||||
|
@ -39,7 +39,6 @@ def set_pkg_dep(pkg, spec):
|
||||
|
||||
|
||||
class MockPackagesTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUp(self):
|
||||
# Use the mock packages database for these tests. This allows
|
||||
# us to set up contrived packages that don't interfere with
|
||||
@ -52,7 +51,7 @@ def setUp(self):
|
||||
'site' : spack.mock_site_config,
|
||||
'user' : spack.mock_user_config }
|
||||
|
||||
@classmethod
|
||||
|
||||
def tearDown(self):
|
||||
"""Restore the real packages path after any test."""
|
||||
spack.db = self.real_db
|
||||
|
@ -29,19 +29,35 @@
|
||||
|
||||
import spack
|
||||
import spack.url as url
|
||||
from spack.packages import PackageDB
|
||||
|
||||
|
||||
class PackageSanityTest(unittest.TestCase):
|
||||
|
||||
def test_get_all_packages(self):
|
||||
"""Get all packages once and make sure that works."""
|
||||
def check_db(self):
|
||||
"""Get all packages in a DB to make sure they work."""
|
||||
for name in spack.db.all_package_names():
|
||||
spack.db.get(name)
|
||||
|
||||
|
||||
def test_get_all_packages(self):
|
||||
"""Get all packages once and make sure that works."""
|
||||
self.check_db()
|
||||
|
||||
|
||||
def test_get_all_mock_packages(self):
|
||||
"""Get the mock packages once each too."""
|
||||
tmp = spack.db
|
||||
spack.db = PackageDB(spack.mock_packages_path)
|
||||
self.check_db()
|
||||
spack.db = tmp
|
||||
|
||||
|
||||
def test_url_versions(self):
|
||||
"""Ensure that url_for_version does the right thing for at least the
|
||||
default version of each package.
|
||||
"""
|
||||
"""Check URLs for regular packages, if they are explicitly defined."""
|
||||
for pkg in spack.db.all_packages():
|
||||
v = url.parse_version(pkg.url)
|
||||
self.assertEqual(pkg.url, pkg.url_for_version(v))
|
||||
for v, vdesc in pkg.versions.items():
|
||||
if vdesc.url:
|
||||
# If there is a url for the version check it.
|
||||
v_url = pkg.url_for_version(v)
|
||||
self.assertEqual(vdesc.url, v_url)
|
||||
|
97
lib/spack/spack/test/python_version.py
Normal file
97
lib/spack/spack/test/python_version.py
Normal file
@ -0,0 +1,97 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
"""
|
||||
This test ensures that all Spack files are Python version 2.6 or less.
|
||||
|
||||
Spack was originally 2.7, but enough systems in 2014 are still using
|
||||
2.6 on their frontend nodes that we need 2.6 to get adopted.
|
||||
"""
|
||||
import unittest
|
||||
import os
|
||||
import re
|
||||
from contextlib import closing
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
from external import pyqver2
|
||||
import spack
|
||||
|
||||
spack_max_version = (2,6)
|
||||
|
||||
class PythonVersionTest(unittest.TestCase):
|
||||
|
||||
def spack_python_files(self):
|
||||
# first file is the spack script.
|
||||
yield spack.spack_file
|
||||
yield os.path.join(spack.build_env_path, 'cc')
|
||||
|
||||
# Next files are all the source files and package files.
|
||||
search_paths = [spack.lib_path, spack.var_path]
|
||||
|
||||
# Iterate through the whole spack source tree.
|
||||
for path in search_paths:
|
||||
for root, dirnames, filenames in os.walk(path):
|
||||
for filename in filenames:
|
||||
if re.match(r'^[^.#].*\.py$', filename):
|
||||
yield os.path.join(root, filename)
|
||||
|
||||
|
||||
def test_python_versions(self):
|
||||
# dict version -> filename -> reasons
|
||||
all_issues = {}
|
||||
|
||||
for fn in self.spack_python_files():
|
||||
with closing(open(fn)) as pyfile:
|
||||
versions = pyqver2.get_versions(pyfile.read())
|
||||
for ver, reasons in versions.items():
|
||||
if ver > spack_max_version:
|
||||
if not ver in all_issues:
|
||||
all_issues[ver] = {}
|
||||
all_issues[ver][fn] = reasons
|
||||
|
||||
if all_issues:
|
||||
tty.error("Spack must run on Python version %d.%d"
|
||||
% spack_max_version)
|
||||
|
||||
for v in sorted(all_issues.keys(), reverse=True):
|
||||
msgs = []
|
||||
for fn in sorted(all_issues[v].keys()):
|
||||
short_fn = fn
|
||||
if fn.startswith(spack.prefix):
|
||||
short_fn = fn[len(spack.prefix):]
|
||||
|
||||
reasons = [r for r in set(all_issues[v][fn]) if r]
|
||||
for r in reasons:
|
||||
msgs.append(("%s:%s" % ('spack' + short_fn, r[0]), r[1]))
|
||||
|
||||
tty.error("These files require version %d.%d:" % v)
|
||||
maxlen = max(len(f) for f, prob in msgs)
|
||||
fmt = "%%-%ds%%s" % (maxlen+3)
|
||||
print fmt % ('File', 'Reason')
|
||||
print fmt % ('-' * (maxlen), '-' * 20)
|
||||
for msg in msgs:
|
||||
print fmt % msg
|
||||
|
||||
self.assertTrue(len(all_issues) == 0)
|
@ -48,7 +48,7 @@ def test_conflicting_package_constraints(self):
|
||||
spec.package.validate_dependencies)
|
||||
|
||||
|
||||
def test_unique_node_traversal(self):
|
||||
def test_preorder_node_traversal(self):
|
||||
dag = Spec('mpileaks ^zmpi')
|
||||
dag.normalize()
|
||||
|
||||
@ -56,14 +56,14 @@ def test_unique_node_traversal(self):
|
||||
'zmpi', 'fake']
|
||||
pairs = zip([0,1,2,3,4,2,3], names)
|
||||
|
||||
traversal = dag.preorder_traversal()
|
||||
self.assertListEqual([x.name for x in traversal], names)
|
||||
traversal = dag.traverse()
|
||||
self.assertEqual([x.name for x in traversal], names)
|
||||
|
||||
traversal = dag.preorder_traversal(depth=True)
|
||||
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
traversal = dag.traverse(depth=True)
|
||||
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
|
||||
|
||||
def test_unique_edge_traversal(self):
|
||||
def test_preorder_edge_traversal(self):
|
||||
dag = Spec('mpileaks ^zmpi')
|
||||
dag.normalize()
|
||||
|
||||
@ -71,14 +71,14 @@ def test_unique_edge_traversal(self):
|
||||
'libelf', 'zmpi', 'fake', 'zmpi']
|
||||
pairs = zip([0,1,2,3,4,3,2,3,1], names)
|
||||
|
||||
traversal = dag.preorder_traversal(cover='edges')
|
||||
self.assertListEqual([x.name for x in traversal], names)
|
||||
traversal = dag.traverse(cover='edges')
|
||||
self.assertEqual([x.name for x in traversal], names)
|
||||
|
||||
traversal = dag.preorder_traversal(cover='edges', depth=True)
|
||||
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
traversal = dag.traverse(cover='edges', depth=True)
|
||||
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
|
||||
|
||||
def test_unique_path_traversal(self):
|
||||
def test_preorder_path_traversal(self):
|
||||
dag = Spec('mpileaks ^zmpi')
|
||||
dag.normalize()
|
||||
|
||||
@ -86,11 +86,56 @@ def test_unique_path_traversal(self):
|
||||
'libelf', 'zmpi', 'fake', 'zmpi', 'fake']
|
||||
pairs = zip([0,1,2,3,4,3,2,3,1,2], names)
|
||||
|
||||
traversal = dag.preorder_traversal(cover='paths')
|
||||
self.assertListEqual([x.name for x in traversal], names)
|
||||
traversal = dag.traverse(cover='paths')
|
||||
self.assertEqual([x.name for x in traversal], names)
|
||||
|
||||
traversal = dag.preorder_traversal(cover='paths', depth=True)
|
||||
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
traversal = dag.traverse(cover='paths', depth=True)
|
||||
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
|
||||
|
||||
def test_postorder_node_traversal(self):
|
||||
dag = Spec('mpileaks ^zmpi')
|
||||
dag.normalize()
|
||||
|
||||
names = ['libelf', 'libdwarf', 'dyninst', 'fake', 'zmpi',
|
||||
'callpath', 'mpileaks']
|
||||
pairs = zip([4,3,2,3,2,1,0], names)
|
||||
|
||||
traversal = dag.traverse(order='post')
|
||||
self.assertEqual([x.name for x in traversal], names)
|
||||
|
||||
traversal = dag.traverse(depth=True, order='post')
|
||||
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
|
||||
|
||||
def test_postorder_edge_traversal(self):
|
||||
dag = Spec('mpileaks ^zmpi')
|
||||
dag.normalize()
|
||||
|
||||
names = ['libelf', 'libdwarf', 'libelf', 'dyninst', 'fake', 'zmpi',
|
||||
'callpath', 'zmpi', 'mpileaks']
|
||||
pairs = zip([4,3,3,2,3,2,1,1,0], names)
|
||||
|
||||
traversal = dag.traverse(cover='edges', order='post')
|
||||
self.assertEqual([x.name for x in traversal], names)
|
||||
|
||||
traversal = dag.traverse(cover='edges', depth=True, order='post')
|
||||
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
|
||||
|
||||
def test_postorder_path_traversal(self):
|
||||
dag = Spec('mpileaks ^zmpi')
|
||||
dag.normalize()
|
||||
|
||||
names = ['libelf', 'libdwarf', 'libelf', 'dyninst', 'fake', 'zmpi',
|
||||
'callpath', 'fake', 'zmpi', 'mpileaks']
|
||||
pairs = zip([4,3,3,2,3,2,1,2,1,0], names)
|
||||
|
||||
traversal = dag.traverse(cover='paths', order='post')
|
||||
self.assertEqual([x.name for x in traversal], names)
|
||||
|
||||
traversal = dag.traverse(cover='paths', depth=True, order='post')
|
||||
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
|
||||
|
||||
|
||||
def test_conflicting_spec_constraints(self):
|
||||
@ -142,7 +187,7 @@ def test_normalize_with_virtual_spec(self):
|
||||
|
||||
# make sure nothing with the same name occurs twice
|
||||
counts = {}
|
||||
for spec in dag.preorder_traversal(keyfun=id):
|
||||
for spec in dag.traverse(key=id):
|
||||
if not spec.name in counts:
|
||||
counts[spec.name] = 0
|
||||
counts[spec.name] += 1
|
||||
@ -152,15 +197,15 @@ def test_normalize_with_virtual_spec(self):
|
||||
|
||||
|
||||
def check_links(self, spec_to_check):
|
||||
for spec in spec_to_check.preorder_traversal():
|
||||
for spec in spec_to_check.traverse():
|
||||
for dependent in spec.dependents.values():
|
||||
self.assertIn(
|
||||
spec.name, dependent.dependencies,
|
||||
self.assertTrue(
|
||||
spec.name in dependent.dependencies,
|
||||
"%s not in dependencies of %s" % (spec.name, dependent.name))
|
||||
|
||||
for dependency in spec.dependencies.values():
|
||||
self.assertIn(
|
||||
spec.name, dependency.dependents,
|
||||
self.assertTrue(
|
||||
spec.name in dependency.dependents,
|
||||
"%s not in dependents of %s" % (spec.name, dependency.name))
|
||||
|
||||
|
||||
@ -221,30 +266,53 @@ def test_invalid_dep(self):
|
||||
|
||||
|
||||
def test_equal(self):
|
||||
spec = Spec('mpileaks ^callpath ^libelf ^libdwarf')
|
||||
self.assertNotEqual(spec, Spec(
|
||||
'mpileaks', Spec('callpath',
|
||||
Spec('libdwarf',
|
||||
Spec('libelf')))))
|
||||
self.assertNotEqual(spec, Spec(
|
||||
'mpileaks', Spec('callpath',
|
||||
Spec('libelf',
|
||||
Spec('libdwarf')))))
|
||||
# Different spec structures to test for equality
|
||||
flat = Spec('mpileaks ^callpath ^libelf ^libdwarf')
|
||||
|
||||
self.assertEqual(spec, Spec(
|
||||
'mpileaks', Spec('callpath'), Spec('libdwarf'), Spec('libelf')))
|
||||
flat_init = Spec(
|
||||
'mpileaks', Spec('callpath'), Spec('libdwarf'), Spec('libelf'))
|
||||
|
||||
self.assertEqual(spec, Spec(
|
||||
'mpileaks', Spec('libelf'), Spec('libdwarf'), Spec('callpath')))
|
||||
flip_flat = Spec(
|
||||
'mpileaks', Spec('libelf'), Spec('libdwarf'), Spec('callpath'))
|
||||
|
||||
dag = Spec('mpileaks', Spec('callpath',
|
||||
Spec('libdwarf',
|
||||
Spec('libelf'))))
|
||||
|
||||
flip_dag = Spec('mpileaks', Spec('callpath',
|
||||
Spec('libelf',
|
||||
Spec('libdwarf'))))
|
||||
|
||||
# All these are equal to each other with regular ==
|
||||
specs = (flat, flat_init, flip_flat, dag, flip_dag)
|
||||
for lhs, rhs in zip(specs, specs):
|
||||
self.assertEqual(lhs, rhs)
|
||||
self.assertEqual(str(lhs), str(rhs))
|
||||
|
||||
# Same DAGs constructed different ways are equal
|
||||
self.assertTrue(flat.eq_dag(flat_init))
|
||||
|
||||
# order at same level does not matter -- (dep on same parent)
|
||||
self.assertTrue(flat.eq_dag(flip_flat))
|
||||
|
||||
# DAGs should be unequal if nesting is different
|
||||
self.assertFalse(flat.eq_dag(dag))
|
||||
self.assertFalse(flat.eq_dag(flip_dag))
|
||||
self.assertFalse(flip_flat.eq_dag(dag))
|
||||
self.assertFalse(flip_flat.eq_dag(flip_dag))
|
||||
self.assertFalse(dag.eq_dag(flip_dag))
|
||||
|
||||
|
||||
def test_normalize_mpileaks(self):
|
||||
# Spec parsed in from a string
|
||||
spec = Spec('mpileaks ^mpich ^callpath ^dyninst ^libelf@1.8.11 ^libdwarf')
|
||||
|
||||
# What that spec should look like after parsing
|
||||
expected_flat = Spec(
|
||||
'mpileaks', Spec('mpich'), Spec('callpath'), Spec('dyninst'),
|
||||
Spec('libelf@1.8.11'), Spec('libdwarf'))
|
||||
|
||||
# What it should look like after normalization
|
||||
mpich = Spec('mpich')
|
||||
libelf = Spec('libelf@1.8.11')
|
||||
expected_normalized = Spec(
|
||||
@ -257,7 +325,10 @@ def test_normalize_mpileaks(self):
|
||||
mpich),
|
||||
mpich)
|
||||
|
||||
expected_non_unique_nodes = Spec(
|
||||
# Similar to normalized spec, but now with copies of the same
|
||||
# libelf node. Normalization should result in a single unique
|
||||
# node for each package, so this is the wrong DAG.
|
||||
non_unique_nodes = Spec(
|
||||
'mpileaks',
|
||||
Spec('callpath',
|
||||
Spec('dyninst',
|
||||
@ -267,21 +338,33 @@ def test_normalize_mpileaks(self):
|
||||
mpich),
|
||||
Spec('mpich'))
|
||||
|
||||
self.assertEqual(expected_normalized, expected_non_unique_nodes)
|
||||
|
||||
self.assertEqual(str(expected_normalized), str(expected_non_unique_nodes))
|
||||
self.assertEqual(str(spec), str(expected_non_unique_nodes))
|
||||
self.assertEqual(str(expected_normalized), str(spec))
|
||||
# All specs here should be equal under regular equality
|
||||
specs = (spec, expected_flat, expected_normalized, non_unique_nodes)
|
||||
for lhs, rhs in zip(specs, specs):
|
||||
self.assertEqual(lhs, rhs)
|
||||
self.assertEqual(str(lhs), str(rhs))
|
||||
|
||||
# Test that equal and equal_dag are doing the right thing
|
||||
self.assertEqual(spec, expected_flat)
|
||||
self.assertNotEqual(spec, expected_normalized)
|
||||
self.assertNotEqual(spec, expected_non_unique_nodes)
|
||||
self.assertTrue(spec.eq_dag(expected_flat))
|
||||
|
||||
self.assertEqual(spec, expected_normalized)
|
||||
self.assertFalse(spec.eq_dag(expected_normalized))
|
||||
|
||||
self.assertEqual(spec, non_unique_nodes)
|
||||
self.assertFalse(spec.eq_dag(non_unique_nodes))
|
||||
|
||||
spec.normalize()
|
||||
|
||||
self.assertNotEqual(spec, expected_flat)
|
||||
# After normalizing, spec_dag_equal should match the normalized spec.
|
||||
self.assertEqual(spec, expected_flat)
|
||||
self.assertFalse(spec.eq_dag(expected_flat))
|
||||
|
||||
self.assertEqual(spec, expected_normalized)
|
||||
self.assertEqual(spec, expected_non_unique_nodes)
|
||||
self.assertTrue(spec.eq_dag(expected_normalized))
|
||||
|
||||
self.assertEqual(spec, non_unique_nodes)
|
||||
self.assertFalse(spec.eq_dag(non_unique_nodes))
|
||||
|
||||
|
||||
def test_normalize_with_virtual_package(self):
|
||||
@ -302,10 +385,63 @@ def test_normalize_with_virtual_package(self):
|
||||
|
||||
def test_contains(self):
|
||||
spec = Spec('mpileaks ^mpi ^libelf@1.8.11 ^libdwarf')
|
||||
self.assertIn(Spec('mpi'), spec)
|
||||
self.assertIn(Spec('libelf'), spec)
|
||||
self.assertIn(Spec('libelf@1.8.11'), spec)
|
||||
self.assertNotIn(Spec('libelf@1.8.12'), spec)
|
||||
self.assertIn(Spec('libdwarf'), spec)
|
||||
self.assertNotIn(Spec('libgoblin'), spec)
|
||||
self.assertIn(Spec('mpileaks'), spec)
|
||||
self.assertTrue(Spec('mpi') in spec)
|
||||
self.assertTrue(Spec('libelf') in spec)
|
||||
self.assertTrue(Spec('libelf@1.8.11') in spec)
|
||||
self.assertFalse(Spec('libelf@1.8.12') in spec)
|
||||
self.assertTrue(Spec('libdwarf') in spec)
|
||||
self.assertFalse(Spec('libgoblin') in spec)
|
||||
self.assertTrue(Spec('mpileaks') in spec)
|
||||
|
||||
|
||||
def test_copy_simple(self):
|
||||
orig = Spec('mpileaks')
|
||||
copy = orig.copy()
|
||||
|
||||
self.check_links(copy)
|
||||
|
||||
self.assertEqual(orig, copy)
|
||||
self.assertTrue(orig.eq_dag(copy))
|
||||
self.assertEqual(orig._normal, copy._normal)
|
||||
self.assertEqual(orig._concrete, copy._concrete)
|
||||
|
||||
# ensure no shared nodes bt/w orig and copy.
|
||||
orig_ids = set(id(s) for s in orig.traverse())
|
||||
copy_ids = set(id(s) for s in copy.traverse())
|
||||
self.assertFalse(orig_ids.intersection(copy_ids))
|
||||
|
||||
|
||||
def test_copy_normalized(self):
|
||||
orig = Spec('mpileaks')
|
||||
orig.normalize()
|
||||
copy = orig.copy()
|
||||
|
||||
self.check_links(copy)
|
||||
|
||||
self.assertEqual(orig, copy)
|
||||
self.assertTrue(orig.eq_dag(copy))
|
||||
self.assertEqual(orig._normal, copy._normal)
|
||||
self.assertEqual(orig._concrete, copy._concrete)
|
||||
|
||||
# ensure no shared nodes bt/w orig and copy.
|
||||
orig_ids = set(id(s) for s in orig.traverse())
|
||||
copy_ids = set(id(s) for s in copy.traverse())
|
||||
self.assertFalse(orig_ids.intersection(copy_ids))
|
||||
|
||||
|
||||
def test_copy_concretized(self):
|
||||
orig = Spec('mpileaks')
|
||||
orig.concretize()
|
||||
copy = orig.copy()
|
||||
|
||||
self.check_links(copy)
|
||||
|
||||
self.assertEqual(orig, copy)
|
||||
self.assertTrue(orig.eq_dag(copy))
|
||||
self.assertEqual(orig._normal, copy._normal)
|
||||
self.assertEqual(orig._concrete, copy._concrete)
|
||||
|
||||
# ensure no shared nodes bt/w orig and copy.
|
||||
orig_ids = set(id(s) for s in orig.traverse())
|
||||
copy_ids = set(id(s) for s in copy.traverse())
|
||||
self.assertFalse(orig_ids.intersection(copy_ids))
|
||||
|
@ -51,28 +51,20 @@
|
||||
stage_name = 'spack-test-stage'
|
||||
|
||||
|
||||
class with_tmp(object):
|
||||
"""Decorator that executes a function with or without spack set to use
|
||||
a temp dir. Spack allows builds to happen directly in the
|
||||
stage directory or in a tmp dir and symlinked into the stage
|
||||
directory, so this lets us use the same test in both cases.
|
||||
@contextmanager
|
||||
def use_tmp(use_tmp):
|
||||
"""Allow some test code to be executed with spack.use_tmp_stage
|
||||
set to a certain value. Context manager makes sure it's reset
|
||||
on failure.
|
||||
"""
|
||||
def __init__(self, use_tmp):
|
||||
self.use_tmp = use_tmp
|
||||
|
||||
def __call__(self, fun):
|
||||
use_tmp = self.use_tmp
|
||||
def new_test_function(self):
|
||||
old_tmp = spack.use_tmp_stage
|
||||
spack.use_tmp_stage = use_tmp
|
||||
fun(self)
|
||||
spack.use_tmp_stage = old_tmp
|
||||
return new_test_function
|
||||
old_tmp = spack.use_tmp_stage
|
||||
spack.use_tmp_stage = use_tmp
|
||||
yield
|
||||
spack.use_tmp_stage = old_tmp
|
||||
|
||||
|
||||
class StageTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
def setUp(self):
|
||||
"""This sets up a mock archive to fetch, and a mock temp space for use
|
||||
by the Stage class. It doesn't actually create the Stage -- that
|
||||
is done by individual tests.
|
||||
@ -92,52 +84,58 @@ def setUpClass(cls):
|
||||
tar('czf', archive_name, archive_dir)
|
||||
|
||||
# Make spack use the test environment for tmp stuff.
|
||||
cls.old_tmp_dirs = spack.tmp_dirs
|
||||
self.old_tmp_dirs = spack.tmp_dirs
|
||||
spack.tmp_dirs = [test_tmp_path]
|
||||
|
||||
# record this since this test changes to directories that will
|
||||
# be removed.
|
||||
self.working_dir = os.getcwd()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
|
||||
def tearDown(self):
|
||||
"""Blows away the test environment directory."""
|
||||
shutil.rmtree(test_files_dir)
|
||||
|
||||
# chdir back to original working dir
|
||||
os.chdir(self.working_dir)
|
||||
|
||||
# restore spack's original tmp environment
|
||||
spack.tmp_dirs = cls.old_tmp_dirs
|
||||
spack.tmp_dirs = self.old_tmp_dirs
|
||||
|
||||
|
||||
def get_stage_path(self, stage, stage_name):
|
||||
"""Figure out based on a stage and an intended name where it should
|
||||
be living. This depends on whether it's named or not.
|
||||
"""Figure out where a stage should be living. This depends on
|
||||
whether it's named.
|
||||
"""
|
||||
if stage_name:
|
||||
if stage_name is not None:
|
||||
# If it is a named stage, we know where the stage should be
|
||||
stage_path = join_path(spack.stage_path, stage_name)
|
||||
return join_path(spack.stage_path, stage_name)
|
||||
else:
|
||||
# If it's unnamed, ensure that we ran mkdtemp in the right spot.
|
||||
stage_path = stage.path
|
||||
self.assertIsNotNone(stage_path)
|
||||
self.assertEqual(
|
||||
os.path.commonprefix((stage_path, spack.stage_path)),
|
||||
spack.stage_path)
|
||||
return stage_path
|
||||
self.assertTrue(stage.path is not None)
|
||||
self.assertTrue(stage.path.startswith(spack.stage_path))
|
||||
return stage.path
|
||||
|
||||
|
||||
def check_setup(self, stage, stage_name):
|
||||
"""Figure out whether a stage was set up correctly."""
|
||||
stage_path = self.get_stage_path(stage, stage_name)
|
||||
|
||||
# Ensure stage was created in the spack stage directory
|
||||
self.assertTrue(os.path.isdir(stage_path))
|
||||
|
||||
if spack.use_tmp_stage:
|
||||
# Make sure everything was created and linked correctly for
|
||||
# a tmp stage.
|
||||
# Check that the stage dir is really a symlink.
|
||||
self.assertTrue(os.path.islink(stage_path))
|
||||
|
||||
# Make sure it points to a valid directory
|
||||
target = os.path.realpath(stage_path)
|
||||
self.assertTrue(os.path.isdir(target))
|
||||
self.assertFalse(os.path.islink(target))
|
||||
self.assertEqual(
|
||||
os.path.commonprefix((target, test_tmp_path)),
|
||||
test_tmp_path)
|
||||
|
||||
# Make sure the directory is in the place we asked it to
|
||||
# be (see setUp and tearDown)
|
||||
self.assertTrue(target.startswith(test_tmp_path))
|
||||
|
||||
else:
|
||||
# Make sure the stage path is NOT a link for a non-tmp stage
|
||||
@ -146,15 +144,15 @@ def check_setup(self, stage, stage_name):
|
||||
|
||||
def check_fetch(self, stage, stage_name):
|
||||
stage_path = self.get_stage_path(stage, stage_name)
|
||||
self.assertIn(archive_name, os.listdir(stage_path))
|
||||
self.assertTrue(archive_name in os.listdir(stage_path))
|
||||
self.assertEqual(join_path(stage_path, archive_name),
|
||||
stage.archive_file)
|
||||
|
||||
|
||||
def check_expand_archive(self, stage, stage_name):
|
||||
stage_path = self.get_stage_path(stage, stage_name)
|
||||
self.assertIn(archive_name, os.listdir(stage_path))
|
||||
self.assertIn(archive_dir, os.listdir(stage_path))
|
||||
self.assertTrue(archive_name in os.listdir(stage_path))
|
||||
self.assertTrue(archive_dir in os.listdir(stage_path))
|
||||
|
||||
self.assertEqual(
|
||||
join_path(stage_path, archive_dir),
|
||||
@ -192,32 +190,40 @@ def check_destroy(self, stage, stage_name):
|
||||
self.assertFalse(os.path.exists(target))
|
||||
|
||||
|
||||
def checkSetupAndDestroy(self, stage_name=None):
|
||||
stage = Stage(archive_url, name=stage_name)
|
||||
self.check_setup(stage, stage_name)
|
||||
|
||||
stage.destroy()
|
||||
self.check_destroy(stage, stage_name)
|
||||
|
||||
|
||||
@with_tmp(True)
|
||||
def test_setup_and_destroy_name_with_tmp(self):
|
||||
self.checkSetupAndDestroy(stage_name)
|
||||
with use_tmp(True):
|
||||
stage = Stage(archive_url, name=stage_name)
|
||||
self.check_setup(stage, stage_name)
|
||||
|
||||
stage.destroy()
|
||||
self.check_destroy(stage, stage_name)
|
||||
|
||||
|
||||
@with_tmp(False)
|
||||
def test_setup_and_destroy_name_without_tmp(self):
|
||||
self.checkSetupAndDestroy(stage_name)
|
||||
with use_tmp(False):
|
||||
stage = Stage(archive_url, name=stage_name)
|
||||
self.check_setup(stage, stage_name)
|
||||
|
||||
stage.destroy()
|
||||
self.check_destroy(stage, stage_name)
|
||||
|
||||
|
||||
@with_tmp(True)
|
||||
def test_setup_and_destroy_no_name_with_tmp(self):
|
||||
self.checkSetupAndDestroy(None)
|
||||
with use_tmp(True):
|
||||
stage = Stage(archive_url)
|
||||
self.check_setup(stage, None)
|
||||
|
||||
stage.destroy()
|
||||
self.check_destroy(stage, None)
|
||||
|
||||
|
||||
@with_tmp(False)
|
||||
def test_setup_and_destroy_no_name_without_tmp(self):
|
||||
self.checkSetupAndDestroy(None)
|
||||
with use_tmp(False):
|
||||
stage = Stage(archive_url)
|
||||
self.check_setup(stage, None)
|
||||
|
||||
stage.destroy()
|
||||
self.check_destroy(stage, None)
|
||||
|
||||
|
||||
def test_chdir(self):
|
||||
@ -286,7 +292,7 @@ def test_restage(self):
|
||||
with closing(open('foobar', 'w')) as file:
|
||||
file.write("this file is to be destroyed.")
|
||||
|
||||
self.assertIn('foobar', os.listdir(stage.expanded_archive_path))
|
||||
self.assertTrue('foobar' in os.listdir(stage.expanded_archive_path))
|
||||
|
||||
# Make sure the file is not there after restage.
|
||||
stage.restage()
|
||||
@ -295,7 +301,7 @@ def test_restage(self):
|
||||
|
||||
stage.chdir_to_archive()
|
||||
self.check_chdir_to_archive(stage, stage_name)
|
||||
self.assertNotIn('foobar', os.listdir(stage.expanded_archive_path))
|
||||
self.assertFalse('foobar' in os.listdir(stage.expanded_archive_path))
|
||||
|
||||
stage.destroy()
|
||||
self.check_destroy(stage, stage_name)
|
||||
|
@ -82,12 +82,16 @@ def parse_version_string_with_indices(path):
|
||||
"""Try to extract a version string from a filename or URL. This is taken
|
||||
largely from Homebrew's Version class."""
|
||||
|
||||
if os.path.isdir(path):
|
||||
stem = os.path.basename(path)
|
||||
elif re.search(r'((?:sourceforge.net|sf.net)/.*)/download$', path):
|
||||
stem = comp.stem(os.path.dirname(path))
|
||||
else:
|
||||
stem = comp.stem(path)
|
||||
# Strip off sourceforge download stuffix.
|
||||
if re.search(r'((?:sourceforge.net|sf.net)/.*)/download$', path):
|
||||
path = os.path.dirname(path)
|
||||
|
||||
# Strip archive extension
|
||||
path = comp.strip_extension(path)
|
||||
|
||||
# Take basename to avoid including parent dirs in version name
|
||||
# Remember the offset of the stem in the full path.
|
||||
stem = os.path.basename(path)
|
||||
|
||||
version_types = [
|
||||
# GitHub tarballs, e.g. v1.2.3
|
||||
@ -137,10 +141,10 @@ def parse_version_string_with_indices(path):
|
||||
(r'_((\d+\.)+\d+[a-z]?)[.]orig$', stem),
|
||||
|
||||
# e.g. http://www.openssl.org/source/openssl-0.9.8s.tar.gz
|
||||
(r'-([^-]+)', stem),
|
||||
(r'-([^-]+(-alpha|-beta)?)', stem),
|
||||
|
||||
# e.g. astyle_1.23_macosx.tar.gz
|
||||
(r'_([^_]+)', stem),
|
||||
(r'_([^_]+(_alpha|_beta)?)', stem),
|
||||
|
||||
# e.g. http://mirrors.jenkins-ci.org/war/1.486/jenkins.war
|
||||
(r'\/(\d\.\d+)\/', path),
|
||||
@ -152,7 +156,9 @@ def parse_version_string_with_indices(path):
|
||||
regex, match_string = vtype[:2]
|
||||
match = re.search(regex, match_string)
|
||||
if match and match.group(1) is not None:
|
||||
return match.group(1), match.start(1), match.end(1)
|
||||
version = match.group(1)
|
||||
start = path.index(version)
|
||||
return version, start, start+len(version)
|
||||
|
||||
raise UndetectableVersionError(path)
|
||||
|
||||
|
@ -48,7 +48,7 @@ def decompressor_for(path):
|
||||
return tar
|
||||
|
||||
|
||||
def stem(path):
|
||||
def strip_extension(path):
|
||||
"""Get the part of a path that does not include its compressed
|
||||
type extension."""
|
||||
for type in ALLOWED_ARCHIVE_TYPES:
|
||||
|
@ -35,7 +35,7 @@
|
||||
hashlib.sha512 ]
|
||||
|
||||
"""Index for looking up hasher for a digest."""
|
||||
_size_to_hash = { h().digest_size : h for h in _acceptable_hashes }
|
||||
_size_to_hash = dict((h().digest_size, h) for h in _acceptable_hashes)
|
||||
|
||||
|
||||
def checksum(hashlib_algo, filename, **kwargs):
|
||||
|
@ -121,7 +121,7 @@ def which(name, **kwargs):
|
||||
|
||||
for dir in path:
|
||||
exe = os.path.join(dir, name)
|
||||
if os.access(exe, os.X_OK):
|
||||
if os.path.isfile(exe) and os.access(exe, os.X_OK):
|
||||
return Executable(exe)
|
||||
|
||||
if required:
|
||||
|
@ -33,7 +33,9 @@ def comma_list(sequence, article=''):
|
||||
return sequence[0]
|
||||
else:
|
||||
out = ', '.join(str(s) for s in sequence[:-1])
|
||||
out += ', '
|
||||
if len(sequence) != 2:
|
||||
out += ',' # oxford comma
|
||||
out += ' '
|
||||
if article:
|
||||
out += article + ' '
|
||||
out += str(sequence[-1])
|
||||
|
@ -47,7 +47,8 @@
|
||||
import sys
|
||||
import re
|
||||
from bisect import bisect_left
|
||||
from functools import total_ordering, wraps
|
||||
from functools import wraps
|
||||
from external.functools import total_ordering
|
||||
|
||||
import llnl.util.compare.none_high as none_high
|
||||
import llnl.util.compare.none_low as none_low
|
||||
@ -181,7 +182,7 @@ def a_or_n(seg):
|
||||
|
||||
# Add possible alpha or beta indicator at the end of each segemnt
|
||||
# We treat these specially b/c they're so common.
|
||||
wc += '[ab]?)?' * (len(segments) - 1)
|
||||
wc += '(?:[a-z]|alpha|beta)?)?' * (len(segments) - 1)
|
||||
return wc
|
||||
|
||||
|
||||
|
23
share/spack/csh/pathadd.csh
Normal file
23
share/spack/csh/pathadd.csh
Normal file
@ -0,0 +1,23 @@
|
||||
########################################################################
|
||||
# Prepends directories to path, if they exist.
|
||||
# pathadd /path/to/dir # add to PATH
|
||||
# or pathadd OTHERPATH /path/to/dir # add to OTHERPATH
|
||||
########################################################################
|
||||
# If no variable name is supplied, just append to PATH
|
||||
# otherwise append to that variable.
|
||||
set _pa_varname = PATH;
|
||||
set _pa_new_path = $_pa_args[1];
|
||||
[ $#_pa_args -gt 1 ] && set _pa_varname = $_pa_args[1] && set _pa_new_path = $_pa_args[2];
|
||||
|
||||
# Check whether the variable is set yet.
|
||||
set _pa_old_value = ""
|
||||
eval set _pa_set = '$?'$_pa_varname
|
||||
[ $_pa_set -eq 1 ] && eval set _pa_old_value='$'$_pa_varname;
|
||||
|
||||
# Do the actual prepending here, if it is a dir and not already in the path
|
||||
if ( -d $_pa_new_path && \:$_pa_old_value\: !~ *\:$_pa_new_path\:* ) then
|
||||
[ -n "$_pa_old_value" ] && setenv $_pa_varname $_pa_new_path\:$_pa_old_value
|
||||
[ -z "$_pa_old_value" ] && setenv $_pa_varname $_pa_new_path
|
||||
endif
|
||||
|
||||
unset _pa_args _pa_new_path _pa_old_value _pa_set _pa_varname
|
101
share/spack/csh/spack.csh
Normal file
101
share/spack/csh/spack.csh
Normal file
@ -0,0 +1,101 @@
|
||||
########################################################################
|
||||
# This is a wrapper around the spack command that forwards calls to
|
||||
# 'spack use' and 'spack unuse' to shell functions. This in turn
|
||||
# allows them to be used to invoke dotkit functions.
|
||||
#
|
||||
# 'spack use' is smarter than just 'use' because it converts its
|
||||
# arguments into a unique spack spec that is then passed to dotkit
|
||||
# commands. This allows the user to use packages without knowing all
|
||||
# their installation details.
|
||||
#
|
||||
# e.g., rather than requring a full spec for libelf, the user can type:
|
||||
#
|
||||
# spack use libelf
|
||||
#
|
||||
# This will first find the available libelf dotkits and use a
|
||||
# matching one. If there are two versions of libelf, the user would
|
||||
# need to be more specific, e.g.:
|
||||
#
|
||||
# spack use libelf@0.8.13
|
||||
#
|
||||
# This is very similar to how regular spack commands work and it
|
||||
# avoids the need to come up with a user-friendly naming scheme for
|
||||
# spack dotfiles.
|
||||
########################################################################
|
||||
# accumulate initial flags for main spack command
|
||||
set _sp_flags = ""
|
||||
while ( $#_sp_args > 0 )
|
||||
if ( "$_sp_args[1]" !~ "-*" ) break
|
||||
set _sp_flags = "$_sp_flags $_sp_args[1]"
|
||||
shift _sp_args
|
||||
end
|
||||
|
||||
# h and V flags don't require further output parsing.
|
||||
if ( "$_sp_flags" =~ *h* || "$_sp_flags" =~ *V* ) then
|
||||
\spack $_sp_flags $_sp_args
|
||||
goto _sp_end
|
||||
endif
|
||||
|
||||
# Set up args -- we want a subcommand and a spec.
|
||||
set _sp_subcommand=""
|
||||
set _sp_spec=""
|
||||
[ $#_sp_args -gt 0 ] && set _sp_subcommand = ($_sp_args[1])
|
||||
[ $#_sp_args -gt 1 ] && set _sp_spec = ($_sp_args[2-])
|
||||
|
||||
# Figure out what type of module we're running here.
|
||||
set _sp_modtype = ""
|
||||
switch ($_sp_subcommand)
|
||||
case cd:
|
||||
shift _sp_args
|
||||
cd `spack location $_sp_args`
|
||||
breaksw
|
||||
case use:
|
||||
case unuse:
|
||||
case load:
|
||||
case unload:
|
||||
set _sp_module_args=""""
|
||||
if ( "$_sp_spec" =~ "-*" ) then
|
||||
set _sp_module_args = $_sp_spec[1]
|
||||
shift _sp_spec
|
||||
set _sp_spec = ($_sp_spec)
|
||||
endif
|
||||
|
||||
# Here the user has run use or unuse with a spec. Find a matching
|
||||
# spec using 'spack module find', then use the appropriate module
|
||||
# tool's commands to add/remove the result from the environment.
|
||||
switch ($_sp_subcommand)
|
||||
case "use":
|
||||
set _sp_full_spec = ( "`\spack $_sp_flags module find dotkit $_sp_spec`" )
|
||||
if ( $? == 0 ) then
|
||||
use $_sp_module_args $_sp_full_spec
|
||||
endif
|
||||
breaksw
|
||||
case "unuse":
|
||||
set _sp_full_spec = ( "`\spack $_sp_flags module find dotkit $_sp_spec`" )
|
||||
if ( $? == 0 ) then
|
||||
unuse $_sp_module_args $_sp_full_spec
|
||||
endif
|
||||
breaksw
|
||||
case "load":
|
||||
set _sp_full_spec = ( "`\spack $_sp_flags module find tcl $_sp_spec`" )
|
||||
if ( $? == 0 ) then
|
||||
module load $_sp_module_args $_sp_full_spec
|
||||
endif
|
||||
breaksw
|
||||
case "unload":
|
||||
set _sp_full_spec = ( "`\spack $_sp_flags module find tcl $_sp_spec`" )
|
||||
if ( $? == 0 ) then
|
||||
module unload $_sp_module_args $_sp_full_spec
|
||||
endif
|
||||
breaksw
|
||||
endsw
|
||||
breaksw
|
||||
|
||||
default:
|
||||
\spack $_sp_args
|
||||
breaksw
|
||||
endsw
|
||||
|
||||
_sp_end:
|
||||
unset _sp_args _sp_full_spec _sp_modtype _sp_module_args
|
||||
unset _sp_sh_cmd _sp_spec _sp_subcommand _sp_flags
|
@ -1,132 +0,0 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
|
||||
#
|
||||
#
|
||||
# This file is part of Spack and sets up the spack environment for
|
||||
# bash shells. This includes dotkit support as well as putting spack
|
||||
# in your path. Source it like this:
|
||||
#
|
||||
# . /path/to/spack/share/spack/setup-env.bash
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
########################################################################
|
||||
# This is a wrapper around the spack command that forwards calls to
|
||||
# 'spack use' and 'spack unuse' to shell functions. This in turn
|
||||
# allows them to be used to invoke dotkit functions.
|
||||
#
|
||||
# 'spack use' is smarter than just 'use' because it converts its
|
||||
# arguments into a unique spack spec that is then passed to dotkit
|
||||
# commands. This allows the user to use packages without knowing all
|
||||
# their installation details.
|
||||
#
|
||||
# e.g., rather than requring a full spec for libelf, the user can type:
|
||||
#
|
||||
# spack use libelf
|
||||
#
|
||||
# This will first find the available libelf dotkits and use a
|
||||
# matching one. If there are two versions of libelf, the user would
|
||||
# need to be more specific, e.g.:
|
||||
#
|
||||
# spack use libelf@0.8.13
|
||||
#
|
||||
# This is very similar to how regular spack commands work and it
|
||||
# avoids the need to come up with a user-friendly naming scheme for
|
||||
# spack dotfiles.
|
||||
########################################################################
|
||||
function spack {
|
||||
_spack_subcommand=$1; shift
|
||||
_spack_spec="$@"
|
||||
|
||||
# Filter out use and unuse. For any other commands, just run the
|
||||
# command.
|
||||
case $_spack_subcommand in
|
||||
"use") ;;
|
||||
"unuse") ;;
|
||||
*)
|
||||
command spack $_spack_subcommand "$@"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
# If no args or -h, just run that command as well.
|
||||
if [ -z "$1" -o "$1" = "-h" ]; then
|
||||
command spack $_spack_subcommand -h
|
||||
return
|
||||
fi
|
||||
|
||||
# Shift any other args for use off before parsing spec.
|
||||
_spack_use_args=""
|
||||
if [[ "$1" =~ ^- ]]; then
|
||||
_spack_use_args="$1"; shift
|
||||
_spack_spec="$@"
|
||||
fi
|
||||
|
||||
# Here the user has run use or unuse with a spec. Find a matching
|
||||
# spec with a dotkit using spack dotkit, then use or unuse the
|
||||
# result. If spack dotkit comes back with an error, do nothing.
|
||||
if _spack_full_spec=$(command spack dotkit $_spack_spec); then
|
||||
$_spack_subcommand $_spack_use_args $_spack_full_spec
|
||||
fi
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Prepends directories to path, if they exist.
|
||||
# pathadd /path/to/dir # add to PATH
|
||||
# or pathadd OTHERPATH /path/to/dir # add to OTHERPATH
|
||||
########################################################################
|
||||
function _spack_pathadd {
|
||||
# If no variable name is supplied, just append to PATH
|
||||
# otherwise append to that variable.
|
||||
varname=PATH
|
||||
path="$1"
|
||||
if [ -n "$2" ]; then
|
||||
varname="$1"
|
||||
path="$2"
|
||||
fi
|
||||
|
||||
# Do the actual prepending here.
|
||||
eval "oldvalue=\"\$$varname\""
|
||||
if [ -d "$path" ] && [[ ":$oldvalue:" != *":$path:"* ]]; then
|
||||
if [ -n "$oldvalue" ]; then
|
||||
eval "export $varname=\"$path:$oldvalue\""
|
||||
else
|
||||
export $varname="$path"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Set up dotkit and path in the user environment
|
||||
#
|
||||
_spack_share_dir="$(dirname ${BASH_SOURCE[0]})"
|
||||
_spack_prefix="$(dirname $(dirname $_spack_share_dir))"
|
||||
|
||||
_spack_pathadd DK_NODE "$_spack_share_dir/dotkit"
|
||||
_spack_pathadd PATH "$_spack_prefix/bin"
|
||||
|
47
share/spack/setup-env.csh
Executable file
47
share/spack/setup-env.csh
Executable file
@ -0,0 +1,47 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
|
||||
#
|
||||
# This file is part of Spack and sets up the spack environment for
|
||||
# csh and tcsh. This includes dotkit support, module support, and
|
||||
# it also puts spack in your path. Source it like this:
|
||||
#
|
||||
# setenv SPACK_ROOT /path/to/spack
|
||||
# source $SPACK_ROOT/share/spack/setup-env.csh
|
||||
#
|
||||
if ($?SPACK_ROOT) then
|
||||
set _spack_source_file = $SPACK_ROOT/share/spack/setup-env.csh
|
||||
set _spack_share_dir = $SPACK_ROOT/share/spack
|
||||
|
||||
# Command aliases point at separate source files
|
||||
alias spack 'set _sp_args = (\!*); source $_spack_share_dir/csh/spack.csh'
|
||||
alias _spack_pathadd 'set _pa_args = (\!*) && source $_spack_share_dir/csh/pathadd.csh'
|
||||
|
||||
# Set up modules and dotkit search paths in the user environment
|
||||
# TODO: fix SYS_TYPE to something non-LLNL-specific
|
||||
_spack_pathadd DK_NODE "$_spack_share_dir/dotkit/$SYS_TYPE"
|
||||
_spack_pathadd MODULEPATH "$_spack_share_dir/modules/$SYS_TYPE"
|
||||
_spack_pathadd PATH "$SPACK_ROOT/bin"
|
||||
endif
|
169
share/spack/setup-env.sh
Executable file
169
share/spack/setup-env.sh
Executable file
@ -0,0 +1,169 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
|
||||
#
|
||||
# This file is part of Spack and sets up the spack environment for
|
||||
# bash and zsh. This includes dotkit support, module support, and
|
||||
# it also puts spack in your path. Source it like this:
|
||||
#
|
||||
# . /path/to/spack/share/spack/setup-env.sh
|
||||
#
|
||||
|
||||
########################################################################
|
||||
# This is a wrapper around the spack command that forwards calls to
|
||||
# 'spack use' and 'spack unuse' to shell functions. This in turn
|
||||
# allows them to be used to invoke dotkit functions.
|
||||
#
|
||||
# 'spack use' is smarter than just 'use' because it converts its
|
||||
# arguments into a unique spack spec that is then passed to dotkit
|
||||
# commands. This allows the user to use packages without knowing all
|
||||
# their installation details.
|
||||
#
|
||||
# e.g., rather than requring a full spec for libelf, the user can type:
|
||||
#
|
||||
# spack use libelf
|
||||
#
|
||||
# This will first find the available libelf dotkits and use a
|
||||
# matching one. If there are two versions of libelf, the user would
|
||||
# need to be more specific, e.g.:
|
||||
#
|
||||
# spack use libelf@0.8.13
|
||||
#
|
||||
# This is very similar to how regular spack commands work and it
|
||||
# avoids the need to come up with a user-friendly naming scheme for
|
||||
# spack dotfiles.
|
||||
########################################################################
|
||||
function spack {
|
||||
# accumulate initial flags for main spack command
|
||||
_sp_flags=""
|
||||
while [[ "$1" =~ ^- ]]; do
|
||||
_sp_flags="$_sp_flags $1"
|
||||
shift
|
||||
done
|
||||
|
||||
# h and V flags don't require further output parsing.
|
||||
if [[ "$_sp_flags" =~ *h* || "$_sp_flags" =~ *V* ]]; then
|
||||
command spack $_sp_flags "$@"
|
||||
return
|
||||
fi
|
||||
|
||||
_sp_subcommand=$1; shift
|
||||
_sp_spec="$@"
|
||||
|
||||
# Filter out use and unuse. For any other commands, just run the
|
||||
# command.
|
||||
case $_sp_subcommand in
|
||||
"cd")
|
||||
cd $(spack location "$@")
|
||||
return
|
||||
;;
|
||||
"use"|"unuse"|"load"|"unload")
|
||||
# Shift any other args for use off before parsing spec.
|
||||
_sp_module_args=""
|
||||
if [[ "$1" =~ ^- ]]; then
|
||||
_sp_module_args="$1"; shift
|
||||
_sp_spec="$@"
|
||||
fi
|
||||
|
||||
# Here the user has run use or unuse with a spec. Find a matching
|
||||
# spec using 'spack module find', then use the appropriate module
|
||||
# tool's commands to add/remove the result from the environment.
|
||||
# If spack module command comes back with an error, do nothing.
|
||||
case $_sp_subcommand in
|
||||
"use")
|
||||
if _sp_full_spec=$(command spack $_sp_flags module find dotkit $_sp_spec); then
|
||||
use $_sp_module_args $_sp_full_spec
|
||||
fi ;;
|
||||
"unuse")
|
||||
if _sp_full_spec=$(command spack $_sp_flags module find dotkit $_sp_spec); then
|
||||
unuse $_sp_module_args $_sp_full_spec
|
||||
fi ;;
|
||||
"load")
|
||||
if _sp_full_spec=$(command spack $_sp_flags module find dotkit $_sp_spec); then
|
||||
module load $_sp_module_args $_sp_full_spec
|
||||
fi ;;
|
||||
"unload")
|
||||
if _sp_full_spec=$(command spack $_sp_flags module find dotkit $_sp_spec); then
|
||||
module unload $_sp_module_args $_sp_full_spec
|
||||
fi ;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
command spack $_sp_flags $_sp_subcommand $_sp_spec
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Prepends directories to path, if they exist.
|
||||
# pathadd /path/to/dir # add to PATH
|
||||
# or pathadd OTHERPATH /path/to/dir # add to OTHERPATH
|
||||
########################################################################
|
||||
function _spack_pathadd {
|
||||
# If no variable name is supplied, just append to PATH
|
||||
# otherwise append to that variable.
|
||||
_pa_varname=PATH
|
||||
_pa_new_path="$1"
|
||||
if [ -n "$2" ]; then
|
||||
_pa_varname="$1"
|
||||
_pa_new_path="$2"
|
||||
fi
|
||||
|
||||
# Do the actual prepending here.
|
||||
eval "_pa_oldvalue=\$${_pa_varname}"
|
||||
|
||||
if [ -d "$_pa_new_path" ] && [[ ":$_pa_oldvalue:" != *":$_pa_new_path:"* ]]; then
|
||||
if [ -n "$_pa_oldvalue" ]; then
|
||||
eval "export $_pa_varname=\"$_pa_new_path:$_pa_oldvalue\""
|
||||
else
|
||||
export $_pa_varname="$_pa_new_path"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Figure out where this file is. Below code needs to be portable to
|
||||
# bash and zsh.
|
||||
#
|
||||
_sp_source_file="${BASH_SOURCE[0]}" # Bash's location of last sourced file.
|
||||
if [ -z "$_sp_source_file" ]; then
|
||||
_sp_source_file="$0:A" # zsh way to do it
|
||||
if [[ "$_sp_source_file" == *":A" ]]; then
|
||||
# Not zsh either... bail out with plain old $0,
|
||||
# which WILL NOT work if this is sourced indirectly.
|
||||
_sp_source_file="$0"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Set up modules and dotkit search paths in the user environment
|
||||
#
|
||||
_sp_share_dir="$(dirname $_sp_source_file)"
|
||||
_sp_prefix="$(dirname $(dirname $_sp_share_dir))"
|
||||
|
||||
# TODO: fix SYS_TYPE to something non-LLNL-specific
|
||||
_spack_pathadd DK_NODE "$_sp_share_dir/dotkit/$SYS_TYPE"
|
||||
_spack_pathadd MODULEPATH "$_sp_share_dir/modules/$SYS_TYPE"
|
||||
_spack_pathadd PATH "$_sp_prefix/bin"
|
@ -28,9 +28,9 @@ class Callpath(Package):
|
||||
homepage = "https://github.com/tgamblin/callpath"
|
||||
url = "http://github.com/tgamblin/callpath-1.0.tar.gz"
|
||||
|
||||
versions = { 0.8 : 'foobarbaz',
|
||||
0.9 : 'foobarbaz',
|
||||
1.0 : 'foobarbaz' }
|
||||
version(0.8, 'foobarbaz')
|
||||
version(0.9, 'foobarbaz')
|
||||
version(1.0, 'foobarbaz')
|
||||
|
||||
depends_on("dyninst")
|
||||
depends_on("mpi")
|
||||
|
@ -28,7 +28,7 @@ class DirectMpich(Package):
|
||||
homepage = "http://www.example.com"
|
||||
url = "http://www.example.com/direct_mpich-1.0.tar.gz"
|
||||
|
||||
versions = { 1.0 : 'foobarbaz' }
|
||||
version('1.0', 'foobarbaz')
|
||||
|
||||
depends_on('mpich')
|
||||
|
||||
|
@ -29,9 +29,8 @@ class Dyninst(Package):
|
||||
url = "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.1.2/DyninstAPI-8.1.2.tgz"
|
||||
list_url = "http://www.dyninst.org/downloads/dyninst-8.x"
|
||||
|
||||
versions = {
|
||||
'8.1.2' : 'bf03b33375afa66fe0efa46ce3f4b17a',
|
||||
'8.1.1' : '1f8743e3a5662b25ce64a7edf647e77d' }
|
||||
version('8.1.2', 'bf03b33375afa66fe0efa46ce3f4b17a')
|
||||
version('8.1.1', '1f8743e3a5662b25ce64a7edf647e77d')
|
||||
|
||||
depends_on("libelf")
|
||||
depends_on("libdwarf")
|
||||
|
@ -27,7 +27,8 @@
|
||||
class Fake(Package):
|
||||
homepage = "http://www.fake-spack-example.org"
|
||||
url = "http://www.fake-spack-example.org/downloads/fake-1.0.tar.gz"
|
||||
versions = { '1.0' : 'foobarbaz' }
|
||||
|
||||
version('1.0', 'foobarbaz')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
pass
|
||||
|
@ -32,7 +32,7 @@ class IndirectMpich(Package):
|
||||
homepage = "http://www.example.com"
|
||||
url = "http://www.example.com/indirect_mpich-1.0.tar.gz"
|
||||
|
||||
versions = { 1.0 : 'foobarbaz' }
|
||||
version(1.0, 'foobarbaz')
|
||||
|
||||
depends_on('mpi')
|
||||
depends_on('direct_mpich')
|
||||
|
@ -33,10 +33,10 @@ class Libdwarf(Package):
|
||||
url = "http://www.prevanders.net/libdwarf-20130729.tar.gz"
|
||||
list_url = homepage
|
||||
|
||||
versions = { 20130729 : "64b42692e947d5180e162e46c689dfbf",
|
||||
20130207 : 'foobarbaz',
|
||||
20111030 : 'foobarbaz',
|
||||
20070703 : 'foobarbaz' }
|
||||
version(20130729, "64b42692e947d5180e162e46c689dfbf")
|
||||
version(20130207, 'foobarbaz')
|
||||
version(20111030, 'foobarbaz')
|
||||
version(20070703, 'foobarbaz')
|
||||
|
||||
depends_on("libelf")
|
||||
|
||||
|
@ -28,9 +28,9 @@ class Libelf(Package):
|
||||
homepage = "http://www.mr511.de/software/english.html"
|
||||
url = "http://www.mr511.de/software/libelf-0.8.13.tar.gz"
|
||||
|
||||
versions = {'0.8.13' : '4136d7b4c04df68b686570afa26988ac',
|
||||
'0.8.12' : 'e21f8273d9f5f6d43a59878dc274fec7',
|
||||
'0.8.10' : '9db4d36c283d9790d8fa7df1f4d7b4d9' }
|
||||
version('0.8.13', '4136d7b4c04df68b686570afa26988ac')
|
||||
version('0.8.12', 'e21f8273d9f5f6d43a59878dc274fec7')
|
||||
version('0.8.10', '9db4d36c283d9790d8fa7df1f4d7b4d9')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure("--prefix=%s" % prefix,
|
||||
|
@ -30,11 +30,11 @@ class Mpich(Package):
|
||||
list_url = "http://www.mpich.org/static/downloads/"
|
||||
list_depth = 2
|
||||
|
||||
versions = { '3.0.4' : '9c5d5d4fe1e17dd12153f40bc5b6dbc0',
|
||||
'3.0.3' : 'foobarbaz',
|
||||
'3.0.2' : 'foobarbaz',
|
||||
'3.0.1' : 'foobarbaz',
|
||||
'3.0' : 'foobarbaz' }
|
||||
version('3.0.4', '9c5d5d4fe1e17dd12153f40bc5b6dbc0')
|
||||
version('3.0.3', 'foobarbaz')
|
||||
version('3.0.2', 'foobarbaz')
|
||||
version('3.0.1', 'foobarbaz')
|
||||
version('3.0', 'foobarbaz')
|
||||
|
||||
provides('mpi@:3', when='@3:')
|
||||
provides('mpi@:1', when='@1:')
|
||||
|
@ -30,12 +30,12 @@ class Mpich2(Package):
|
||||
list_url = "http://www.mpich.org/static/downloads/"
|
||||
list_depth = 2
|
||||
|
||||
versions = { '1.5' : '9c5d5d4fe1e17dd12153f40bc5b6dbc0',
|
||||
'1.4' : 'foobarbaz',
|
||||
'1.3' : 'foobarbaz',
|
||||
'1.2' : 'foobarbaz',
|
||||
'1.1' : 'foobarbaz',
|
||||
'1.0' : 'foobarbaz' }
|
||||
version('1.5', '9c5d5d4fe1e17dd12153f40bc5b6dbc0')
|
||||
version('1.4', 'foobarbaz')
|
||||
version('1.3', 'foobarbaz')
|
||||
version('1.2', 'foobarbaz')
|
||||
version('1.1', 'foobarbaz')
|
||||
version('1.0', 'foobarbaz')
|
||||
|
||||
provides('mpi@:2.0')
|
||||
provides('mpi@:2.1', when='@1.1:')
|
||||
|
@ -28,10 +28,10 @@ class Mpileaks(Package):
|
||||
homepage = "http://www.llnl.gov"
|
||||
url = "http://www.llnl.gov/mpileaks-1.0.tar.gz"
|
||||
|
||||
versions = { 1.0 : 'foobarbaz',
|
||||
2.1 : 'foobarbaz',
|
||||
2.2 : 'foobarbaz',
|
||||
2.3 : 'foobarbaz' }
|
||||
version(1.0, 'foobarbaz')
|
||||
version(2.1, 'foobarbaz')
|
||||
version(2.2, 'foobarbaz')
|
||||
version(2.3, 'foobarbaz')
|
||||
|
||||
depends_on("mpi")
|
||||
depends_on("callpath")
|
||||
|
@ -30,7 +30,7 @@ class TrivialInstallTestPackage(Package):
|
||||
homepage = "http://www.example.com/trivial_install"
|
||||
url = "http://www.unit-test-should-replace-this-url/trivial_install-1.0.tar.gz"
|
||||
|
||||
versions = { '1.0' : 'foobarbaz' }
|
||||
version('1.0', 'foobarbaz')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure('--prefix=%s' % prefix)
|
||||
|
@ -30,7 +30,7 @@ class Zmpi(Package):
|
||||
homepage = "http://www.spack-fake-zmpi.org"
|
||||
url = "http://www.spack-fake-zmpi.org/downloads/zmpi-1.0.tar.gz"
|
||||
|
||||
versions = { '1.0' : 'foobarbaz' }
|
||||
version('1.0', 'foobarbaz')
|
||||
|
||||
provides('mpi@:10.0')
|
||||
depends_on('fake')
|
||||
|
@ -11,17 +11,15 @@ class Samrai(Package):
|
||||
url = "https://computation-rnd.llnl.gov/SAMRAI/download/SAMRAI-v3.7.3.tar.gz"
|
||||
list_url = homepage
|
||||
|
||||
versions = {
|
||||
'3.7.3' : '12d574eacadf8c9a70f1bb4cd1a69df6',
|
||||
'3.7.2' : 'f6a716f171c9fdbf3cb12f71fa6e2737',
|
||||
'3.6.3-beta' : 'ef0510bf2893042daedaca434e5ec6ce',
|
||||
'3.5.2-beta' : 'd072d9d681eeb9ada15ce91bea784274',
|
||||
'3.5.0-beta' : '1ad18a319fc573e12e2b1fbb6f6b0a19',
|
||||
'3.4.1-beta' : '00814cbee2cb76bf8302aff56bbb385b',
|
||||
'3.3.3-beta' : '1db3241d3e1cab913dc310d736c34388',
|
||||
'3.3.2-beta' : 'e598a085dab979498fcb6c110c4dd26c',
|
||||
'2.4.4' : '04fb048ed0efe7c531ac10c81cc5f6ac',
|
||||
}
|
||||
version('3.7.3', '12d574eacadf8c9a70f1bb4cd1a69df6')
|
||||
version('3.7.2', 'f6a716f171c9fdbf3cb12f71fa6e2737')
|
||||
version('3.6.3-beta', 'ef0510bf2893042daedaca434e5ec6ce')
|
||||
version('3.5.2-beta', 'd072d9d681eeb9ada15ce91bea784274')
|
||||
version('3.5.0-beta', '1ad18a319fc573e12e2b1fbb6f6b0a19')
|
||||
version('3.4.1-beta', '00814cbee2cb76bf8302aff56bbb385b')
|
||||
version('3.3.3-beta', '1db3241d3e1cab913dc310d736c34388')
|
||||
version('3.3.2-beta', 'e598a085dab979498fcb6c110c4dd26c')
|
||||
version('2.4.4', '04fb048ed0efe7c531ac10c81cc5f6ac')
|
||||
|
||||
depends_on("mpi")
|
||||
depends_on("zlib")
|
||||
|
41
var/spack/packages/adept-utils/package.py
Normal file
41
var/spack/packages/adept-utils/package.py
Normal file
@ -0,0 +1,41 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
from spack import *
|
||||
|
||||
class AdeptUtils(Package):
|
||||
"""Utility libraries for LLNL performance tools."""
|
||||
|
||||
homepage = "https://github.com/scalability-llnl/adept-utils"
|
||||
url = "https://github.com/scalability-llnl/adept-utils/archive/v1.0.tar.gz"
|
||||
|
||||
version('1.0', '5c6cd9badce56c945ac8551e34804397')
|
||||
|
||||
depends_on("boost")
|
||||
depends_on("mpi")
|
||||
|
||||
def install(self, spec, prefix):
|
||||
cmake(*std_cmake_args)
|
||||
make()
|
||||
make("install")
|
@ -14,32 +14,31 @@ class Boost(Package):
|
||||
list_url = "http://sourceforge.net/projects/boost/files/boost/"
|
||||
list_depth = 2
|
||||
|
||||
versions = {
|
||||
'1.55.0' : 'd6eef4b4cacb2183f2bf265a5a03a354',
|
||||
'1.54.0' : '15cb8c0803064faef0c4ddf5bc5ca279',
|
||||
'1.53.0' : 'a00d22605d5dbcfb4c9936a9b35bc4c2',
|
||||
'1.52.0' : '3a855e0f919107e0ca4de4d84ad3f750',
|
||||
'1.51.0' : '4b6bd483b692fd138aef84ed2c8eb679',
|
||||
'1.50.0' : '52dd00be775e689f55a987baebccc462',
|
||||
'1.49.0' : '0d202cb811f934282dea64856a175698',
|
||||
'1.48.0' : 'd1e9a7a7f532bb031a3c175d86688d95',
|
||||
'1.47.0' : 'a2dc343f7bc7f83f8941e47ed4a18200',
|
||||
'1.46.1' : '7375679575f4c8db605d426fc721d506',
|
||||
'1.46.0' : '37b12f1702319b73876b0097982087e0',
|
||||
'1.45.0' : 'd405c606354789d0426bc07bea617e58',
|
||||
'1.44.0' : 'f02578f5218f217a9f20e9c30e119c6a',
|
||||
'1.43.0' : 'dd49767bfb726b0c774f7db0cef91ed1',
|
||||
'1.42.0' : '7bf3b4eb841b62ffb0ade2b82218ebe6',
|
||||
'1.41.0' : '8bb65e133907db727a2a825c5400d0a6',
|
||||
'1.40.0' : 'ec3875caeac8c52c7c129802a8483bd7',
|
||||
'1.39.0' : 'a17281fd88c48e0d866e1a12deecbcc0',
|
||||
'1.38.0' : '5eca2116d39d61382b8f8235915cb267',
|
||||
'1.37.0' : '8d9f990bfb7e83769fa5f1d6f065bc92',
|
||||
'1.36.0' : '328bfec66c312150e4c2a78dcecb504b',
|
||||
'1.35.0' : 'dce952a7214e72d6597516bcac84048b',
|
||||
'1.34.1' : '2d938467e8a448a2c9763e0a9f8ca7e5',
|
||||
'1.34.0' : 'ed5b9291ffad776f8757a916e1726ad0'
|
||||
}
|
||||
version('1.55.0', 'd6eef4b4cacb2183f2bf265a5a03a354')
|
||||
version('1.54.0', '15cb8c0803064faef0c4ddf5bc5ca279')
|
||||
version('1.53.0', 'a00d22605d5dbcfb4c9936a9b35bc4c2')
|
||||
version('1.52.0', '3a855e0f919107e0ca4de4d84ad3f750')
|
||||
version('1.51.0', '4b6bd483b692fd138aef84ed2c8eb679')
|
||||
version('1.50.0', '52dd00be775e689f55a987baebccc462')
|
||||
version('1.49.0', '0d202cb811f934282dea64856a175698')
|
||||
version('1.48.0', 'd1e9a7a7f532bb031a3c175d86688d95')
|
||||
version('1.47.0', 'a2dc343f7bc7f83f8941e47ed4a18200')
|
||||
version('1.46.1', '7375679575f4c8db605d426fc721d506')
|
||||
version('1.46.0', '37b12f1702319b73876b0097982087e0')
|
||||
version('1.45.0', 'd405c606354789d0426bc07bea617e58')
|
||||
version('1.44.0', 'f02578f5218f217a9f20e9c30e119c6a')
|
||||
version('1.43.0', 'dd49767bfb726b0c774f7db0cef91ed1')
|
||||
version('1.42.0', '7bf3b4eb841b62ffb0ade2b82218ebe6')
|
||||
version('1.41.0', '8bb65e133907db727a2a825c5400d0a6')
|
||||
version('1.40.0', 'ec3875caeac8c52c7c129802a8483bd7')
|
||||
version('1.39.0', 'a17281fd88c48e0d866e1a12deecbcc0')
|
||||
version('1.38.0', '5eca2116d39d61382b8f8235915cb267')
|
||||
version('1.37.0', '8d9f990bfb7e83769fa5f1d6f065bc92')
|
||||
version('1.36.0', '328bfec66c312150e4c2a78dcecb504b')
|
||||
version('1.35.0', 'dce952a7214e72d6597516bcac84048b')
|
||||
version('1.34.1', '2d938467e8a448a2c9763e0a9f8ca7e5')
|
||||
version('1.34.0', 'ed5b9291ffad776f8757a916e1726ad0')
|
||||
|
||||
|
||||
def url_for_version(self, version):
|
||||
"""Handle Boost's weird URLs, which write the version two different ways."""
|
||||
|
@ -25,13 +25,20 @@
|
||||
from spack import *
|
||||
|
||||
class Callpath(Package):
|
||||
homepage = "https://github.com/tgamblin/callpath"
|
||||
url = "http://github.com/tgamblin/callpath-0.2.tar.gz"
|
||||
"""Library for representing callpaths consistently in
|
||||
distributed-memory performance tools."""
|
||||
|
||||
homepage = "https://github.com/scalability-llnl/callpath"
|
||||
url = "https://github.com/scalability-llnl/callpath/archive/v1.0.1.tar.gz"
|
||||
|
||||
version('1.0.1', '0047983d2a52c5c335f8ba7f5bab2325')
|
||||
|
||||
depends_on("dyninst")
|
||||
depends_on("adept-utils")
|
||||
depends_on("mpi")
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure("--prefix=" + prefix)
|
||||
# TODO: offer options for the walker used.
|
||||
cmake('.', "-DCALLPATH_WALKER=dyninst", *std_cmake_args)
|
||||
make()
|
||||
make("install")
|
||||
|
47
var/spack/packages/clang/package.py
Normal file
47
var/spack/packages/clang/package.py
Normal file
@ -0,0 +1,47 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
from spack import *
|
||||
|
||||
class Clang(Package):
|
||||
"""The goal of the Clang project is to create a new C, C++,
|
||||
Objective C and Objective C++ front-end for the LLVM compiler.
|
||||
"""
|
||||
homepage = "http://clang.llvm.org"
|
||||
url = "http://llvm.org/releases/3.4.2/cfe-3.4.2.src.tar.gz"
|
||||
|
||||
depends_on("llvm")
|
||||
|
||||
version('3.4.2', '87945973b7c73038871c5f849a818588')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
env['CXXFLAGS'] = self.compiler.cxx11_flag
|
||||
|
||||
with working_dir('spack-build', create=True):
|
||||
cmake('..',
|
||||
'-DCLANG_PATH_TO_LLVM_BUILD=%s' % spec['llvm'].prefix,
|
||||
'-DLLVM_MAIN_SRC_DIR=%s' % spec['llvm'].prefix,
|
||||
*std_cmake_args)
|
||||
make()
|
||||
make("install")
|
@ -27,7 +27,8 @@
|
||||
class Cmake(Package):
|
||||
homepage = 'https://www.cmake.org'
|
||||
url = 'http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz'
|
||||
versions = { '2.8.10.2' : '097278785da7182ec0aea8769d06860c' }
|
||||
|
||||
version('2.8.10.2', '097278785da7182ec0aea8769d06860c')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure('--prefix=' + prefix,
|
||||
|
55
var/spack/packages/cube/package.py
Normal file
55
var/spack/packages/cube/package.py
Normal file
@ -0,0 +1,55 @@
|
||||
# FIXME: Add copyright statement
|
||||
#
|
||||
from spack import *
|
||||
from contextlib import closing
|
||||
|
||||
class Cube(Package):
|
||||
"""Cube the profile viewer for Score-P and Scalasca profiles. It
|
||||
displays a multi-dimensional performance space consisting
|
||||
of the dimensions (i) performance metric, (ii) call path,
|
||||
and (iii) system resource."""
|
||||
|
||||
homepage = "http://www.scalasca.org/software/cube-4.x/download.html"
|
||||
url = "http://apps.fz-juelich.de/scalasca/releases/cube/4.2/dist/cube-4.2.3.tar.gz"
|
||||
|
||||
version('4.2.3', '8f95b9531f5a8f8134f279c2767c9b20')
|
||||
|
||||
version('4.3TP1', 'a2090fbc7b2ba394bd5c09ba971e237f',
|
||||
url = 'http://apps.fz-juelich.de/scalasca/releases/cube/4.3/dist/cube-4.3-TP1.tar.gz')
|
||||
|
||||
# Using CC as C++ compiler provides quirky workaround for a Score-P build system attempt
|
||||
# to guess a matching C compiler when configuring scorep-score
|
||||
backend_user_provided = """\
|
||||
CC=cc
|
||||
CXX=CC
|
||||
F77=f77
|
||||
FC=f90
|
||||
#CFLAGS=-fPIC
|
||||
#CXXFLAGS=-fPIC
|
||||
"""
|
||||
frontend_user_provided = """\
|
||||
CC_FOR_BUILD=cc
|
||||
CXX_FOR_BUILD=CC
|
||||
F77_FOR_BUILD=f70
|
||||
FC_FOR_BUILD=f90
|
||||
"""
|
||||
|
||||
def install(self, spec, prefix):
|
||||
# Use a custom compiler configuration, otherwise the score-p
|
||||
# build system messes with spack's compiler settings.
|
||||
# Create these three files in the build directory
|
||||
|
||||
with closing(open("vendor/common/build-config/platforms/platform-backend-user-provided", "w")) as backend_file:
|
||||
backend_file.write(self.backend_user_provided)
|
||||
with closing(open("vendor/common/build-config/platforms/platform-frontend-user-provided", "w")) as frontend_file:
|
||||
frontend_file.write(self.frontend_user_provided)
|
||||
|
||||
configure_args = ["--prefix=%s" % prefix,
|
||||
"--with-custom-compilers",
|
||||
"--without-paraver",
|
||||
"--without-gui"]
|
||||
|
||||
configure(*configure_args)
|
||||
|
||||
make(parallel=False)
|
||||
make("install", parallel=False)
|
20
var/spack/packages/dtcmp/package.py
Normal file
20
var/spack/packages/dtcmp/package.py
Normal file
@ -0,0 +1,20 @@
|
||||
import os
|
||||
from spack import *
|
||||
|
||||
class Dtcmp(Package):
|
||||
"""The Datatype Comparison Library provides comparison operations and
|
||||
parallel sort algorithms for MPI applications."""
|
||||
|
||||
homepage = "https://github.com/hpc/dtcmp"
|
||||
url = "https://github.com/hpc/dtcmp/releases/download/v1.0.3/dtcmp-1.0.3.tar.gz"
|
||||
|
||||
version('1.0.3', 'cdd8ccf71e8ff67de2558594a7fcd317')
|
||||
|
||||
depends_on('mpi')
|
||||
depends_on('lwgrp')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure("--prefix=" + prefix,
|
||||
"--with-lwgrp=" + spec['lwgrp'].prefix)
|
||||
make()
|
||||
make("install")
|
@ -29,8 +29,8 @@ class Dyninst(Package):
|
||||
url = "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.1.2/DyninstAPI-8.1.2.tgz"
|
||||
list_url = "http://www.dyninst.org/downloads/dyninst-8.x"
|
||||
|
||||
versions = {'8.1.2' : 'bf03b33375afa66fe0efa46ce3f4b17a',
|
||||
'8.1.1' : '1f8743e3a5662b25ce64a7edf647e77d' }
|
||||
version('8.1.2', 'bf03b33375afa66fe0efa46ce3f4b17a')
|
||||
version('8.1.1', '1f8743e3a5662b25ce64a7edf647e77d')
|
||||
|
||||
depends_on("libelf")
|
||||
depends_on("libdwarf")
|
||||
|
38
var/spack/packages/extrae/package.py
Normal file
38
var/spack/packages/extrae/package.py
Normal file
@ -0,0 +1,38 @@
|
||||
from spack import *
|
||||
|
||||
class Extrae(Package):
|
||||
"""Extrae is the package devoted to generate tracefiles which can
|
||||
be analyzed later by Paraver. Extrae is a tool that uses
|
||||
different interposition mechanisms to inject probes into the
|
||||
target application so as to gather information regarding the
|
||||
application performance. The Extrae instrumentation package can
|
||||
instrument the MPI programin model, and the following parallel
|
||||
programming models either alone or in conjunction with MPI :
|
||||
OpenMP, CUDA, OpenCL, pthread, OmpSs"""
|
||||
homepage = "http://www.bsc.es/computer-sciences/extrae"
|
||||
url = "http://www.bsc.es/ssl/apps/performanceTools/files/extrae-2.5.1.tar.bz2"
|
||||
version('2.5.1', '422376b9c68243bd36a8a73fa62de106')
|
||||
|
||||
#depends_on("mpi")
|
||||
depends_on("openmpi@:1.6")
|
||||
depends_on("dyninst")
|
||||
depends_on("libunwind")
|
||||
depends_on("boost")
|
||||
depends_on("libdwarf")
|
||||
depends_on("papi")
|
||||
|
||||
def install(self, spec, prefix):
|
||||
if 'openmpi' in spec:
|
||||
mpi = spec['openmpi']
|
||||
#if spec.satisfies('@2.5.1') and spec.satisfies('^openmpi@1.6.5'):
|
||||
# tty.error("Some headers conflict when using OpenMPI 1.6.5. Please use 1.6 instead.")
|
||||
elif 'mpich' in spec:
|
||||
mpi = spec['mpich']
|
||||
elif 'mvapich2' in spec:
|
||||
mpi = spec['mvapich2']
|
||||
|
||||
configure("--prefix=%s" % prefix, "--with-mpi=%s" % mpi.prefix, "--with-unwind=%s" % spec['libunwind'].prefix, "--with-dyninst=%s" % spec['dyninst'].prefix, "--with-boost=%s" % spec['boost'].prefix, "--with-dwarf=%s" % spec['libdwarf'].prefix, "--with-papi=%s" % spec['papi'].prefix, "--with-dyninst-headers=%s" % spec['dyninst'].prefix.include, "--with-dyninst-libs=%s" % spec['dyninst'].prefix.lib)
|
||||
|
||||
make()
|
||||
make("install", parallel=False)
|
||||
|
@ -5,7 +5,7 @@ class Graphlib(Package):
|
||||
homepage = "http://https://github.com/lee218llnl/graphlib"
|
||||
url = "https://github.com/lee218llnl/graphlib/archive/v2.0.0.tar.gz"
|
||||
|
||||
versions = { '2.0.0' : '43c6df84f1d38ba5a5dce0ae19371a70', }
|
||||
version('2.0.0', '43c6df84f1d38ba5a5dce0ae19371a70')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
cmake(".", *std_cmake_args)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user