diff --git a/lib/spack/spack/relocate.py b/lib/spack/spack/relocate.py index c81fdb91ba6..a80135e66c1 100644 --- a/lib/spack/spack/relocate.py +++ b/lib/spack/spack/relocate.py @@ -686,7 +686,7 @@ def is_relocatable(spec): Raises: ValueError: if the spec is not installed """ - if not spec.install_status(): + if not spec.installed: raise ValueError("spec is not installed [{0}]".format(str(spec))) if spec.external or spec.virtual: diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 16051524509..158657b38b4 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -50,6 +50,7 @@ """ import collections import collections.abc +import enum import io import itertools import os @@ -173,6 +174,16 @@ SPECFILE_FORMAT_VERSION = 3 +# InstallStatus is used to map install statuses to symbols for display +# Options are artificially disjoint for dispay purposes +class InstallStatus(enum.Enum): + installed = "@g{[+]} " + upstream = "@g{[^]} " + external = "@g{[e]} " + absent = "@K{ - } " + missing = "@r{[-]} " + + def colorize_spec(spec): """Returns a spec colorized according to the colors specified in color_formats.""" @@ -4401,12 +4412,20 @@ def __str__(self): def install_status(self): """Helper for tree to print DB install status.""" if not self.concrete: - return None - try: - record = spack.store.db.get_record(self) - return record.installed - except KeyError: - return None + return InstallStatus.absent + + if self.external: + return InstallStatus.external + + upstream, record = spack.store.db.query_by_spec_hash(self.dag_hash()) + if not record: + return InstallStatus.absent + elif upstream and record.installed: + return InstallStatus.upstream + elif record.installed: + return InstallStatus.installed + else: + return InstallStatus.missing def _installed_explicitly(self): """Helper for tree to print DB install status.""" @@ -4420,7 +4439,10 @@ def _installed_explicitly(self): def tree(self, **kwargs): """Prints out this spec and its dependencies, tree-formatted - with indentation.""" + with indentation. + + Status function may either output a boolean or an InstallStatus + """ color = kwargs.pop("color", clr.get_color_when()) depth = kwargs.pop("depth", False) hashes = kwargs.pop("hashes", False) @@ -4452,14 +4474,12 @@ def tree(self, **kwargs): if status_fn: status = status_fn(node) - if node.installed_upstream: - out += clr.colorize("@g{[^]} ", color=color) - elif status is None: - out += clr.colorize("@K{ - } ", color=color) # !installed + if status in list(InstallStatus): + out += clr.colorize(status.value, color=color) elif status: - out += clr.colorize("@g{[+]} ", color=color) # installed + out += clr.colorize("@g{[+]} ", color=color) else: - out += clr.colorize("@r{[-]} ", color=color) # missing + out += clr.colorize("@r{[-]} ", color=color) if hashes: out += clr.colorize("@K{%s} ", color=color) % node.dag_hash(hlen)