summaryrefslogtreecommitdiff
path: root/lib/spack/spack/environment/environment.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/spack/environment/environment.py')
-rw-r--r--lib/spack/spack/environment/environment.py32
1 files changed, 24 insertions, 8 deletions
diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py
index 18a39dc1ad..c3d4c67c49 100644
--- a/lib/spack/spack/environment/environment.py
+++ b/lib/spack/spack/environment/environment.py
@@ -1817,31 +1817,47 @@ class Environment(object):
roots = d['roots']
self.concretized_user_specs = [Spec(r['spec']) for r in roots]
self.concretized_order = [r['hash'] for r in roots]
- json_specs_by_hash = collections.OrderedDict()
- for lockfile_key in sorted(d['concrete_specs']):
- json_specs_by_hash[lockfile_key] = d['concrete_specs'][lockfile_key]
+ json_specs_by_hash = d['concrete_specs']
- specs_by_hash = collections.OrderedDict()
+ # Track specs by their lockfile key. Currently spack uses the finest
+ # grained hash as the lockfile key, while older formats used the build
+ # hash or a previous incarnation of the DAG hash (one that did not
+ # include build deps or package hash).
+ specs_by_hash = {}
+ # Track specs by their DAG hash, allows handling DAG hash collisions
+ first_seen = {}
+
+ # First pass: Put each spec in the map ignoring dependencies
for lockfile_key, node_dict in json_specs_by_hash.items():
specs_by_hash[lockfile_key] = Spec.from_node_dict(node_dict)
+ # Second pass: For each spec, get its dependencies from the node dict
+ # and add them to the spec
for lockfile_key, node_dict in json_specs_by_hash.items():
for _, dep_hash, deptypes, _ in (
Spec.dependencies_from_node_dict(node_dict)):
specs_by_hash[lockfile_key]._add_dependency(
specs_by_hash[dep_hash], deptypes)
+ # Traverse the root specs one at a time in the order they appear.
+ # The first time we see each DAG hash, that's the one we want to
+ # keep. This is only required as long as we support older lockfile
+ # formats where the mapping from DAG hash to lockfile key is possibly
+ # one-to-many.
+ for lockfile_key in self.concretized_order:
+ for s in specs_by_hash[lockfile_key].traverse():
+ if s.dag_hash() not in first_seen:
+ first_seen[s.dag_hash()] = s
+
# Now make sure concretized_order and our internal specs dict
# contains the keys used by modern spack (i.e. the dag_hash
# that includes build deps and package hash).
self.concretized_order = [specs_by_hash[h_key].dag_hash()
for h_key in self.concretized_order]
- for _, env_spec in specs_by_hash.items():
- spec_dag_hash = env_spec.dag_hash()
- if spec_dag_hash in self.concretized_order:
- self.specs_by_hash[spec_dag_hash] = env_spec
+ for spec_dag_hash in self.concretized_order:
+ self.specs_by_hash[spec_dag_hash] = first_seen[spec_dag_hash]
def write(self, regenerate=True):
"""Writes an in-memory environment to its location on disk.