summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorScott Wittenburg <scott.wittenburg@kitware.com>2022-03-03 16:23:52 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2022-05-13 10:45:12 -0700
commit9de61c019738c0165b41c6d2ba4dc519b16f8fd5 (patch)
tree7973b1b5c4f5c3a672614f54bbb7f75f4b9fcd89 /lib
parent84cfb3b7fea78f81af5c6c1345a3b3db2d59b9dd (diff)
downloadspack-9de61c019738c0165b41c6d2ba4dc519b16f8fd5.tar.gz
spack-9de61c019738c0165b41c6d2ba4dc519b16f8fd5.tar.bz2
spack-9de61c019738c0165b41c6d2ba4dc519b16f8fd5.tar.xz
spack-9de61c019738c0165b41c6d2ba4dc519b16f8fd5.zip
env: enforce predictable ordering when reading lockfile
Without some enforcement of spec ordering, python 2 produced different results in the affected test than did python 3. This change makes the arbitrary but reproducible decision to sort the specs by their lockfile key alphabetically.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/environment/environment.py6
-rw-r--r--lib/spack/spack/test/cmd/env.py22
2 files changed, 19 insertions, 9 deletions
diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py
index 35e2956fdd..18a39dc1ad 100644
--- a/lib/spack/spack/environment/environment.py
+++ b/lib/spack/spack/environment/environment.py
@@ -1817,9 +1817,11 @@ 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 = d['concrete_specs']
+ 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]
- specs_by_hash = {}
+ specs_by_hash = collections.OrderedDict()
for lockfile_key, node_dict in json_specs_by_hash.items():
specs_by_hash[lockfile_key] = Spec.from_node_dict(node_dict)
diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py
index a0608fecea..48ef699f33 100644
--- a/lib/spack/spack/test/cmd/env.py
+++ b/lib/spack/spack/test/cmd/env.py
@@ -2868,16 +2868,24 @@ def test_environment_query_spec_by_hash(mock_stage, mock_fetch, install_mockery)
def test_read_legacy_lockfile_and_reconcretize(mock_stage, mock_fetch, install_mockery):
"""Make sure that when we read a legacy environment lock file with a hash
conflict (one from before we switched to full hash), the behavior as to
- which of the conflicting specs we pick is deterministic. When we read
- the lockfile, we process root specs in the order they appear in 'roots',
- so we expect the dependencies of the last root in that list to be the
- ones that appear in the environment before we forcefully re-concretize
- the environment. After we force reconcretization, we should see all
- the dependencies again."""
+ which of the conflicting specs we pick is deterministic and reproducible.
+ When we read the lockfile, we (somewhat arbitrarily) process specs in
+ alphabetical order of their lockfile key. Consequently, when reading an
+ old lockfile where two specs have a dag hash conflict we expect to keep the
+ second one we encounter. After we force reconcretization, we should both of
+ the specs that originally conflicted present in the environment again."""
legacy_lockfile_path = os.path.join(
spack.paths.test_path, 'data', 'legacy_env', 'spack.lock'
)
+ # In the legacy lockfile, we have two conflicting specs that differ only
+ # in a build-only dependency. The lockfile keys and conflicting specs
+ # are:
+ # wci7a3a -> dttop ^dtbuild1@0.5
+ # 5zg6wxw -> dttop ^dtbuild1@1.0
+ # So when we initially read the legacy lockfile, we expect to have kept
+ # the version of dttop that depends on dtbuild1@0.5
+
env('create', 'test', legacy_lockfile_path)
test = ev.read('test')
@@ -2888,7 +2896,7 @@ def test_read_legacy_lockfile_and_reconcretize(mock_stage, mock_fetch, install_m
single_root = next(iter(test.specs_by_hash.values()))
- assert single_root['dtbuild1'].version == Version('1.0')
+ assert single_root['dtbuild1'].version == Version('0.5')
# Now forcefully reconcretize
with ev.read('test'):