Merge branch 'features/python-2.6-compatibility' into develop

- Changed 'import argparse' to 'from external import argparse' in conflicts.

Conflicts:
	lib/spack/spack/cmd/dotkit.py
	lib/spack/spack/cmd/unuse.py
	lib/spack/spack/cmd/use.py
This commit is contained in:
Todd Gamblin 2014-08-20 09:30:40 -07:00
commit 8cc2298181
44 changed files with 3375 additions and 187 deletions

View file

@ -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(

6
lib/spack/env/cc vendored
View file

@ -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
View 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

File diff suppressed because it is too large Load diff

30
lib/spack/external/functools.py vendored Normal file
View 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
View 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
View 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)

View file

@ -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)

View file

@ -24,7 +24,7 @@
##############################################################################
import os
import re
import argparse
from external import argparse
import hashlib
from pprint import pprint
from subprocess import CalledProcessError

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -24,7 +24,7 @@
##############################################################################
import sys
import collections
import argparse
from external import argparse
from StringIO import StringIO
import llnl.util.tty as tty

View file

@ -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

View file

@ -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.modules
description ="Add package to environment using modules."

View file

@ -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

View file

@ -25,7 +25,7 @@
import sys
import os
import shutil
import argparse
from external import argparse
import llnl.util.tty as tty
from llnl.util.lang import partition_list

View file

@ -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

View file

@ -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

View file

@ -25,7 +25,7 @@
import os
import sys
import code
import argparse
from external import argparse
import platform
from contextlib import closing

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.modules
description ="Remove package from environment using module."

View file

@ -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.modules
description ="Remove package from environment using dotkit."

View file

@ -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.modules
description ="Add package to environment using dotkit."

View file

@ -189,7 +189,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):

View file

@ -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)

View file

@ -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):

View file

@ -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

View file

@ -360,7 +360,7 @@ def sanity_check_dict(attr_name):
# 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)

View file

@ -72,7 +72,6 @@ class Mpileaks(Package):
import re
import inspect
import importlib
from llnl.util.lang import *

View file

@ -838,7 +838,7 @@ def normalize(self, **kwargs):
# 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()]

View file

@ -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.

View file

@ -46,7 +46,8 @@
'install',
'package_sanity',
'config',
'directory_layout']
'directory_layout',
'python_version']
def list_tests():
@ -71,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
@ -82,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)

View file

@ -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):

View file

@ -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

View 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)

View file

@ -57,10 +57,10 @@ def test_preorder_node_traversal(self):
pairs = zip([0,1,2,3,4,2,3], names)
traversal = dag.traverse()
self.assertListEqual([x.name for x in traversal], names)
self.assertEqual([x.name for x in traversal], names)
traversal = dag.traverse(depth=True)
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
def test_preorder_edge_traversal(self):
@ -72,10 +72,10 @@ def test_preorder_edge_traversal(self):
pairs = zip([0,1,2,3,4,3,2,3,1], names)
traversal = dag.traverse(cover='edges')
self.assertListEqual([x.name for x in traversal], names)
self.assertEqual([x.name for x in traversal], names)
traversal = dag.traverse(cover='edges', depth=True)
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
def test_preorder_path_traversal(self):
@ -87,10 +87,10 @@ def test_preorder_path_traversal(self):
pairs = zip([0,1,2,3,4,3,2,3,1,2], names)
traversal = dag.traverse(cover='paths')
self.assertListEqual([x.name for x in traversal], names)
self.assertEqual([x.name for x in traversal], names)
traversal = dag.traverse(cover='paths', depth=True)
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
def test_postorder_node_traversal(self):
@ -102,10 +102,10 @@ def test_postorder_node_traversal(self):
pairs = zip([4,3,2,3,2,1,0], names)
traversal = dag.traverse(order='post')
self.assertListEqual([x.name for x in traversal], names)
self.assertEqual([x.name for x in traversal], names)
traversal = dag.traverse(depth=True, order='post')
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
def test_postorder_edge_traversal(self):
@ -117,10 +117,10 @@ def test_postorder_edge_traversal(self):
pairs = zip([4,3,3,2,3,2,1,1,0], names)
traversal = dag.traverse(cover='edges', order='post')
self.assertListEqual([x.name for x in traversal], names)
self.assertEqual([x.name for x in traversal], names)
traversal = dag.traverse(cover='edges', depth=True, order='post')
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
def test_postorder_path_traversal(self):
@ -132,10 +132,10 @@ def test_postorder_path_traversal(self):
pairs = zip([4,3,3,2,3,2,1,2,1,0], names)
traversal = dag.traverse(cover='paths', order='post')
self.assertListEqual([x.name for x in traversal], names)
self.assertEqual([x.name for x in traversal], names)
traversal = dag.traverse(cover='paths', depth=True, order='post')
self.assertListEqual([(x, y.name) for x,y in traversal], pairs)
self.assertEqual([(x, y.name) for x,y in traversal], pairs)
def test_conflicting_spec_constraints(self):
@ -199,13 +199,13 @@ def test_normalize_with_virtual_spec(self):
def check_links(self, spec_to_check):
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))
@ -385,13 +385,13 @@ 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):

View file

@ -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)

View file

@ -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):

View file

@ -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