spec.py: ensure == is false if true modulo precomputed dag hash (#48889)
This commit is contained in:
parent
8bb5f4faf4
commit
1c93fef160
@ -3855,6 +3855,13 @@ def _cmp_iter(self):
|
||||
for item in self._cmp_node():
|
||||
yield item
|
||||
|
||||
# If there is ever a breaking change to hash computation, whether accidental or purposeful,
|
||||
# two specs can be identical modulo DAG hash, depending on what time they were concretized
|
||||
# From the perspective of many operation in Spack (database, build cache, etc) a different
|
||||
# DAG hash means a different spec. Here we ensure that two otherwise identical specs, one
|
||||
# serialized before the hash change and one after, are considered different.
|
||||
yield self.dag_hash() if self.concrete else None
|
||||
|
||||
# This needs to be in _cmp_iter so that no specs with different process hashes
|
||||
# are considered the same by `__hash__` or `__eq__`.
|
||||
#
|
||||
|
@ -1989,3 +1989,26 @@ def test_equality_discriminate_on_propagation(lhs, rhs):
|
||||
|
||||
def test_comparison_multivalued_variants():
|
||||
assert Spec("x=a") < Spec("x=a,b") < Spec("x==a,b") < Spec("x==a,b,c")
|
||||
|
||||
|
||||
def test_comparison_after_breaking_hash_change():
|
||||
# We simulate a breaking change in DAG hash computation in Spack. We have two specs that are
|
||||
# entirely equal modulo DAG hash. When deserializing these specs, we don't want them to compare
|
||||
# as equal, because DAG hash is used throughout in Spack to distinguish between specs
|
||||
# (e.g. database, build caches, install dir).
|
||||
s = Spec("example@=1.0")
|
||||
s._mark_concrete(True)
|
||||
|
||||
# compute the dag hash and a change to it
|
||||
dag_hash = s.dag_hash()
|
||||
new_dag_hash = f"{'b' if dag_hash[0] == 'a' else 'a'}{dag_hash[1:]}"
|
||||
|
||||
before_breakage = s.to_dict()
|
||||
after_breakage = s.to_dict()
|
||||
after_breakage["spec"]["nodes"][0]["hash"] = new_dag_hash
|
||||
assert before_breakage != after_breakage
|
||||
|
||||
x = Spec.from_dict(before_breakage)
|
||||
y = Spec.from_dict(after_breakage)
|
||||
assert x != y
|
||||
assert len({x, y}) == 2
|
||||
|
Loading…
Reference in New Issue
Block a user