summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/spack/database.py134
-rw-r--r--lib/spack/spack/spec.py8
2 files changed, 73 insertions, 69 deletions
diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py
index 3c7dff96db..02eae97f3f 100644
--- a/lib/spack/spack/database.py
+++ b/lib/spack/spack/database.py
@@ -59,7 +59,11 @@ import spack.traverse as tr
import spack.util.lock as lk
import spack.util.spack_json as sjson
import spack.version as vn
-from spack.directory_layout import DirectoryLayoutError, InconsistentInstallDirectoryError
+from spack.directory_layout import (
+ DirectoryLayout,
+ DirectoryLayoutError,
+ InconsistentInstallDirectoryError,
+)
from spack.error import SpackError
from spack.util.crypto import bit_length
@@ -950,13 +954,17 @@ class Database:
raise
def _construct_entry_from_directory_layout(
- self, directory_layout, old_data, spec, deprecator=None
+ self,
+ directory_layout: DirectoryLayout,
+ old_data: Dict[str, InstallRecord],
+ spec: "spack.spec.Spec",
+ deprecator: Optional["spack.spec.Spec"] = None,
):
# Try to recover explicit value from old DB, but
# default it to True if DB was corrupt. This is
# just to be conservative in case a command like
# "autoremove" is run by the user after a reindex.
- tty.debug("RECONSTRUCTING FROM SPEC.YAML: {0}".format(spec))
+ tty.debug(f"Reconstructing from spec file: {spec}")
explicit = True
inst_time = os.stat(spec.prefix).st_ctime
if old_data is not None:
@@ -965,17 +973,17 @@ class Database:
explicit = old_info.explicit
inst_time = old_info.installation_time
- extra_args = {"explicit": explicit, "installation_time": inst_time}
- self._add(spec, directory_layout, **extra_args)
+ self._add(spec, directory_layout, explicit=explicit, installation_time=inst_time)
if deprecator:
self._deprecate(spec, deprecator)
- def _construct_from_directory_layout(self, directory_layout, old_data):
- # Read first the `spec.yaml` files in the prefixes. They should be
- # considered authoritative with respect to DB reindexing, as
- # entries in the DB may be corrupted in a way that still makes
- # them readable. If we considered DB entries authoritative
- # instead, we would perpetuate errors over a reindex.
+ def _construct_from_directory_layout(
+ self, directory_layout: DirectoryLayout, old_data: Dict[str, InstallRecord]
+ ):
+ # Read first the spec files in the prefixes. They should be considered authoritative with
+ # respect to DB reindexing, as entries in the DB may be corrupted in a way that still makes
+ # them readable. If we considered DB entries authoritative instead, we would perpetuate
+ # errors over a reindex.
with directory_layout.disable_upstream_check():
# Initialize data in the reconstructed DB
self._data = {}
@@ -994,34 +1002,29 @@ class Database:
)
processed_specs.add(spec)
- for key, entry in old_data.items():
- # We already took care of this spec using
- # `spec.yaml` from its prefix.
+ for entry in old_data.values():
+ # We already took care of this spec using spec file from its prefix.
if entry.spec in processed_specs:
- msg = "SKIPPING RECONSTRUCTION FROM OLD DB: {0}"
- msg += " [already reconstructed from spec.yaml]"
- tty.debug(msg.format(entry.spec))
+ tty.debug(
+ f"Skipping reconstruction from old db: {entry.spec}"
+ " [already reconstructed from spec file]"
+ )
continue
- # If we arrived here it very likely means that
- # we have external specs that are not dependencies
- # of other specs. This may be the case for externally
- # installed compilers or externally installed
- # applications.
- tty.debug("RECONSTRUCTING FROM OLD DB: {0}".format(entry.spec))
+ # If we arrived here it very likely means that we have external specs that are not
+ # dependencies of other specs. This may be the case for externally installed
+ # compilers or externally installed applications.
+ tty.debug(f"Reconstructing from old db: {entry.spec}")
try:
- layout = None if entry.spec.external else directory_layout
- kwargs = {
- "spec": entry.spec,
- "directory_layout": layout,
- "explicit": entry.explicit,
- "installation_time": entry.installation_time,
- }
- self._add(**kwargs)
+ self._add(
+ spec=entry.spec,
+ directory_layout=None if entry.spec.external else directory_layout,
+ explicit=entry.explicit,
+ installation_time=entry.installation_time,
+ )
processed_specs.add(entry.spec)
except Exception as e:
- # Something went wrong, so the spec was not restored
- # from old data
+ # Something went wrong, so the spec was not restored from old data
tty.debug(e)
self._check_ref_counts()
@@ -1117,29 +1120,27 @@ class Database:
def _add(
self,
- spec,
- directory_layout=None,
- explicit=False,
- installation_time=None,
- allow_missing=False,
+ spec: "spack.spec.Spec",
+ directory_layout: Optional[DirectoryLayout] = None,
+ explicit: bool = False,
+ installation_time: Optional[float] = None,
+ allow_missing: bool = False,
):
"""Add an install record for this spec to the database.
Assumes spec is installed in ``directory_layout.path_for_spec(spec)``.
- Also ensures dependencies are present and updated in the DB as
- either installed or missing.
+ Also ensures dependencies are present and updated in the DB as either installed or missing.
Args:
- spec (spack.spec.Spec): spec to be added
+ spec: spec to be added
directory_layout: layout of the spec installation
explicit:
Possible values: True, False, any
- A spec that was installed following a specific user
- request is marked as explicit. If instead it was
- pulled-in as a dependency of a user requested spec
- it's considered implicit.
+ A spec that was installed following a specific user request is marked as explicit.
+ If instead it was pulled-in as a dependency of a user requested spec it's
+ considered implicit.
installation_time:
Date and time of installation
@@ -1150,29 +1151,25 @@ class Database:
raise NonConcreteSpecAddError("Specs added to DB must be concrete.")
key = spec.dag_hash()
- spec_pkg_hash = spec._package_hash
+ spec_pkg_hash = spec._package_hash # type: ignore[attr-defined]
upstream, record = self.query_by_spec_hash(key)
if upstream:
return
- # Retrieve optional arguments
installation_time = installation_time or _now()
for edge in spec.edges_to_dependencies(depflag=_TRACKED_DEPENDENCIES):
if edge.spec.dag_hash() in self._data:
continue
- # allow missing build-only deps. This prevents excessive
- # warnings when a spec is installed, and its build dep
- # is missing a build dep; there's no need to install the
- # build dep's build dep first, and there's no need to warn
- # about it missing.
- dep_allow_missing = allow_missing or edge.depflag == dt.BUILD
self._add(
edge.spec,
directory_layout,
explicit=False,
installation_time=installation_time,
- allow_missing=dep_allow_missing,
+ # allow missing build-only deps. This prevents excessive warnings when a spec is
+ # installed, and its build dep is missing a build dep; there's no need to install
+ # the build dep's build dep first, and there's no need to warn about it missing.
+ allow_missing=allow_missing or edge.depflag == dt.BUILD,
)
# Make sure the directory layout agrees whether the spec is installed
@@ -1185,13 +1182,12 @@ class Database:
self._installed_prefixes.add(path)
except DirectoryLayoutError as e:
if not (allow_missing and isinstance(e, InconsistentInstallDirectoryError)):
- msg = (
- "{0} is being {1} in the database with prefix {2}, "
+ action = "updated" if key in self._data else "registered"
+ tty.warn(
+ f"{spec.short_spec} is being {action} in the database with prefix {path}, "
"but this directory does not contain an installation of "
- "the spec, due to: {3}"
+ f"the spec, due to: {e}"
)
- action = "updated" if key in self._data else "registered"
- tty.warn(msg.format(spec.short_spec, action, path, str(e)))
elif spec.external_path:
path = spec.external_path
installed = True
@@ -1202,23 +1198,27 @@ class Database:
if key not in self._data:
# Create a new install record with no deps initially.
new_spec = spec.copy(deps=False)
- extra_args = {"explicit": explicit, "installation_time": installation_time}
- # Commands other than 'spack install' may add specs to the DB,
- # we can record the source of an installed Spec with 'origin'
- if hasattr(spec, "origin"):
- extra_args["origin"] = spec.origin
- self._data[key] = InstallRecord(new_spec, path, installed, ref_count=0, **extra_args)
+ self._data[key] = InstallRecord(
+ new_spec,
+ path=path,
+ installed=installed,
+ ref_count=0,
+ explicit=explicit,
+ installation_time=installation_time,
+ origin=None if not hasattr(spec, "origin") else spec.origin,
+ )
# Connect dependencies from the DB to the new copy.
for dep in spec.edges_to_dependencies(depflag=_TRACKED_DEPENDENCIES):
dkey = dep.spec.dag_hash()
upstream, record = self.query_by_spec_hash(dkey)
+ assert record, f"Missing dependency {dep.spec} in DB"
new_spec._add_dependency(record.spec, depflag=dep.depflag, virtuals=dep.virtuals)
if not upstream:
record.ref_count += 1
- # Mark concrete once everything is built, and preserve
- # the original hashes of concrete specs.
+ # Mark concrete once everything is built, and preserve the original hashes of concrete
+ # specs.
new_spec._mark_concrete()
new_spec._hash = key
new_spec._package_hash = spec_pkg_hash
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 92e70e90da..0e7746603d 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -1552,7 +1552,9 @@ class Spec:
raise spack.error.SpecError(err_msg.format(name, len(deps)))
return deps[0]
- def edges_from_dependents(self, name=None, depflag: dt.DepFlag = dt.ALL):
+ def edges_from_dependents(
+ self, name=None, depflag: dt.DepFlag = dt.ALL
+ ) -> List[DependencySpec]:
"""Return a list of edges connecting this node in the DAG
to parents.
@@ -1562,7 +1564,9 @@ class Spec:
"""
return [d for d in self._dependents.select(parent=name, depflag=depflag)]
- def edges_to_dependencies(self, name=None, depflag: dt.DepFlag = dt.ALL):
+ def edges_to_dependencies(
+ self, name=None, depflag: dt.DepFlag = dt.ALL
+ ) -> List[DependencySpec]:
"""Return a list of edges connecting this node in the DAG
to children.