summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rwxr-xr-xlib/spack/external/pyqver2.py3
-rw-r--r--lib/spack/spack/cmd/extensions.py8
-rw-r--r--lib/spack/spack/cmd/python.py10
-rw-r--r--lib/spack/spack/cmd/uninstall.py9
-rw-r--r--lib/spack/spack/database.py5
-rw-r--r--lib/spack/spack/directory_layout.py4
-rw-r--r--lib/spack/spack/hooks/extensions.py4
-rw-r--r--lib/spack/spack/modules.py4
-rw-r--r--lib/spack/spack/package.py28
-rw-r--r--lib/spack/spack/packages.py15
-rw-r--r--lib/spack/spack/spec.py32
-rw-r--r--lib/spack/spack/test/python_version.py4
-rw-r--r--lib/spack/spack/test/spec_dag.py8
13 files changed, 93 insertions, 41 deletions
diff --git a/lib/spack/external/pyqver2.py b/lib/spack/external/pyqver2.py
index 4a16e2811e..4690239748 100755
--- a/lib/spack/external/pyqver2.py
+++ b/lib/spack/external/pyqver2.py
@@ -30,7 +30,8 @@ import sys
StandardModules = {
"__future__": (2, 1),
"abc": (2, 6),
- "argparse": (2, 7),
+# skip argparse now that it's in lib/spack/external
+# "argparse": (2, 7),
"ast": (2, 6),
"atexit": (2, 0),
"bz2": (2, 3),
diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py
index c2cf288877..2ce6f406ca 100644
--- a/lib/spack/spack/cmd/extensions.py
+++ b/lib/spack/spack/cmd/extensions.py
@@ -54,7 +54,9 @@ def extensions(parser, args):
if not args.spec:
tty.die("extensions requires a package spec.")
+ #
# Checks
+ #
spec = spack.cmd.parse_specs(args.spec)
if len(spec) > 1:
tty.die("Can only list extensions for one package.")
@@ -70,7 +72,9 @@ def extensions(parser, args):
if not args.mode:
args.mode = 'short'
+ #
# List package names of extensions
+ #
extensions = spack.db.extensions_for(spec)
if not extensions:
tty.msg("%s has no extensions." % spec.cshort_spec)
@@ -79,7 +83,9 @@ def extensions(parser, args):
tty.msg("%d extensions:" % len(extensions))
colify(ext.name for ext in extensions)
+ #
# List specs of installed extensions.
+ #
installed = [s.spec for s in spack.installed_db.installed_extensions_for(spec)]
print
if not installed:
@@ -88,7 +94,9 @@ def extensions(parser, args):
tty.msg("%d installed:" % len(installed))
spack.cmd.find.display_specs(installed, mode=args.mode)
+ #
# List specs of activated extensions.
+ #
activated = spack.install_layout.extension_map(spec)
print
if not activated:
diff --git a/lib/spack/spack/cmd/python.py b/lib/spack/spack/cmd/python.py
index e26b8d3e79..5325e8fd9a 100644
--- a/lib/spack/spack/cmd/python.py
+++ b/lib/spack/spack/cmd/python.py
@@ -32,13 +32,16 @@ import spack
def setup_parser(subparser):
subparser.add_argument(
+ '-c', dest='python_command', help='Command to execute.')
+ subparser.add_argument(
'python_args', nargs=argparse.REMAINDER, help="File to run plus arguments.")
description = "Launch an interpreter as spack would launch a command"
def python(parser, args):
# Fake a main python shell by setting __name__ to __main__.
- console = code.InteractiveConsole({'__name__' : '__main__'})
+ console = code.InteractiveConsole({'__name__' : '__main__',
+ 'spack' : spack})
if "PYTHONSTARTUP" in os.environ:
startup_file = os.environ["PYTHONSTARTUP"]
@@ -47,7 +50,10 @@ def python(parser, args):
console.runsource(startup.read(), startup_file, 'exec')
python_args = args.python_args
- if python_args:
+ python_command = args.python_command
+ if python_command:
+ console.runsource(python_command)
+ elif python_args:
sys.argv = python_args
with open(python_args[0]) as file:
console.runsource(file.read(), python_args[0], 'exec')
diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py
index 191d9d88e8..03873bb5f8 100644
--- a/lib/spack/spack/cmd/uninstall.py
+++ b/lib/spack/spack/cmd/uninstall.py
@@ -42,9 +42,9 @@ def setup_parser(subparser):
help="Remove regardless of whether other packages depend on this one.")
subparser.add_argument(
'-a', '--all', action='store_true', dest='all',
- help="USE CAREFULLY. Remove ALL installed packages that match each supplied spec. " +
- "i.e., if you say uninstall libelf, ALL versions of libelf are uninstalled. " +
- "This is both useful and dangerous, like rm -r.")
+ help="USE CAREFULLY. Remove ALL installed packages that match each " +
+ "supplied spec. i.e., if you say uninstall libelf, ALL versions of " +
+ "libelf are uninstalled. This is both useful and dangerous, like rm -r.")
subparser.add_argument(
'packages', nargs=argparse.REMAINDER, help="specs of packages to uninstall")
@@ -81,7 +81,8 @@ def uninstall(parser, args):
pkgs.append(s.package)
except spack.packages.UnknownPackageError, e:
- # The package.py file has gone away -- but still want to uninstall.
+ # 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
diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py
index d62a47547d..a6f1cc5077 100644
--- a/lib/spack/spack/database.py
+++ b/lib/spack/spack/database.py
@@ -54,6 +54,7 @@ import spack.spec
from spack.version import Version
from spack.spec import Spec
from spack.error import SpackError
+from spack.packages import UnknownPackageError
# DB goes in this directory underneath the root
_db_dirname = '.spack-db'
@@ -211,6 +212,10 @@ class Database(object):
child = self._read_spec_from_yaml(dep_hash, installs, hash_key)
spec._add_dependency(child)
+ # Specs from the database need to be marked concrete because
+ # they represent actual installations.
+ spec._mark_concrete()
+
return spec
diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py
index 056606b429..d91fbe9f4e 100644
--- a/lib/spack/spack/directory_layout.py
+++ b/lib/spack/spack/directory_layout.py
@@ -212,8 +212,8 @@ class YamlDirectoryLayout(DirectoryLayout):
spec = Spec.from_yaml(f)
# Specs read from actual installations are always concrete
- spec._normal = True
- spec._concrete = True
+ spec._mark_concrete()
+
return spec
diff --git a/lib/spack/spack/hooks/extensions.py b/lib/spack/spack/hooks/extensions.py
index b4847d697f..627184cabd 100644
--- a/lib/spack/spack/hooks/extensions.py
+++ b/lib/spack/spack/hooks/extensions.py
@@ -27,9 +27,7 @@ import spack
def pre_uninstall(pkg):
- # Need to do this b/c uninstall does not automatically do it.
- # TODO: store full graph info in stored .spec file.
- pkg.spec.normalize()
+ assert(pkg.spec.concrete)
if pkg.is_extension:
if pkg.activated:
diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py
index 59ed9f893e..7036626e29 100644
--- a/lib/spack/spack/modules.py
+++ b/lib/spack/spack/modules.py
@@ -29,11 +29,11 @@ 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:
+number of 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
+ * /man* and /share/man* directories for MANPATH
* the package prefix for CMAKE_PREFIX_PATH
This module also includes logic for coming up with unique names for
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index daba5cd352..4d75726e06 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -487,9 +487,15 @@ class Package(object):
if name == dep.name:
return dep
- # Otherwise return the spec from the extends() directive
- spec, kwargs = self.extendees[name]
- return spec
+ # if the spec is concrete already, then it extends something
+ # that is an *optional* dependency, and the dep isn't there.
+ if self.spec._concrete:
+ return None
+ else:
+ # If it's not concrete, then return the spec from the
+ # extends() directive since that is all we know so far.
+ spec, kwargs = self.extendees[name]
+ return spec
@property
@@ -497,18 +503,28 @@ class Package(object):
"""Spec of the extendee of this package, or None if it is not an extension."""
if not self.extendees:
return None
+
+ # TODO: allow multiple extendees.
name = next(iter(self.extendees))
return self.extendees[name][1]
@property
def is_extension(self):
- return len(self.extendees) > 0
+ # if it is concrete, it's only an extension if it actually
+ # dependes on the extendee.
+ if self.spec._concrete:
+ return self.extendee_spec is not None
+ else:
+ # If not, then it's an extension if it *could* be an extension
+ return bool(self.extendees)
def extends(self, spec):
- return (spec.name in self.extendees and
- spec.satisfies(self.extendees[spec.name][0]))
+ if not spec.name in self.extendees:
+ return False
+ s = self.extendee_spec
+ return s and s.satisfies(spec)
@property
diff --git a/lib/spack/spack/packages.py b/lib/spack/spack/packages.py
index f6f4cbf025..080644fb90 100644
--- a/lib/spack/spack/packages.py
+++ b/lib/spack/spack/packages.py
@@ -67,27 +67,28 @@ class PackageDB(object):
if spec.virtual:
raise UnknownPackageError(spec.name)
+ key = hash(spec)
if kwargs.get('new', False):
- if spec in self.instances:
- del self.instances[spec]
+ if key in self.instances:
+ del self.instances[key]
- if not spec in self.instances:
+ if not key in self.instances:
package_class = self.get_class_for_package_name(spec.name)
try:
- copy = spec.copy()
- self.instances[copy] = package_class(copy)
+ copy = spec.copy() # defensive copy. Package owns its spec.
+ self.instances[key] = package_class(copy)
except Exception, e:
if spack.debug:
sys.excepthook(*sys.exc_info())
raise FailedConstructorError(spec.name, e)
- return self.instances[spec]
+ return self.instances[key]
@_autospec
def delete(self, spec):
"""Force a package to be recreated."""
- del self.instances[spec]
+ del self.instances[spec.dag_hash()]
def purge(self):
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index f62182ce76..037ec97a5e 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -833,7 +833,18 @@ class Spec(object):
changed = any(changes)
force=True
- self._concrete = True
+ self._mark_concrete()
+
+
+ def _mark_concrete(self):
+ """Mark this spec and its dependencies as concrete.
+
+ Only for internal use -- client code should use "concretize"
+ unless there is a need to force a spec to be concrete.
+ """
+ for s in self.traverse():
+ s._normal = True
+ s._concrete = True
def concretized(self):
@@ -1481,8 +1492,11 @@ class Spec(object):
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)
+ return (self.name,
+ self.versions,
+ self.variants,
+ self.architecture,
+ self.compiler)
def eq_node(self, other):
@@ -1496,11 +1510,15 @@ class Spec(object):
def _cmp_key(self):
- """Comparison key for this node and all dependencies *without*
- considering structure. This is the default, as
- normalization will restore structure.
+ """This returns a key for the spec *including* DAG structure.
+
+ The key is the concatenation of:
+ 1. A tuple describing this node in the DAG.
+ 2. The hash of each of this node's dependencies' cmp_keys.
"""
- return self._cmp_node() + (self.sorted_deps(),)
+ return self._cmp_node() + (
+ tuple(hash(self.dependencies[name])
+ for name in sorted(self.dependencies)),)
def colorized(self):
diff --git a/lib/spack/spack/test/python_version.py b/lib/spack/spack/test/python_version.py
index ba570b416f..2ea5febb11 100644
--- a/lib/spack/spack/test/python_version.py
+++ b/lib/spack/spack/test/python_version.py
@@ -63,10 +63,6 @@ class PythonVersionTest(unittest.TestCase):
all_issues = {}
for fn in files:
- if fn != '/Users/gamblin2/src/spack/var/spack/packages/vim/package.py':
- continue
- print fn
-
with open(fn) as pyfile:
versions = pyqver2.get_versions(pyfile.read())
for ver, reasons in versions.items():
diff --git a/lib/spack/spack/test/spec_dag.py b/lib/spack/spack/test/spec_dag.py
index 94438b6a0c..d3a4d77b32 100644
--- a/lib/spack/spack/test/spec_dag.py
+++ b/lib/spack/spack/test/spec_dag.py
@@ -340,16 +340,18 @@ class SpecDagTest(MockPackagesTest):
self.assertEqual(spec, expected_flat)
self.assertTrue(spec.eq_dag(expected_flat))
- self.assertEqual(spec, expected_normalized)
+ # Normalized has different DAG structure, so NOT equal.
+ self.assertNotEqual(spec, expected_normalized)
self.assertFalse(spec.eq_dag(expected_normalized))
- self.assertEqual(spec, non_unique_nodes)
+ # Again, different DAG structure so not equal.
+ self.assertNotEqual(spec, non_unique_nodes)
self.assertFalse(spec.eq_dag(non_unique_nodes))
spec.normalize()
# After normalizing, spec_dag_equal should match the normalized spec.
- self.assertEqual(spec, expected_flat)
+ self.assertNotEqual(spec, expected_flat)
self.assertFalse(spec.eq_dag(expected_flat))
self.assertEqual(spec, expected_normalized)