diff options
author | Massimiliano Culpo <massimiliano.culpo@gmail.com> | 2024-11-04 07:35:16 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-03 22:35:16 -0800 |
commit | 395c911689d7a3ee426660f3fab334ccee04da1a (patch) | |
tree | 7a348345c3e80e2cfc9f9b52a52ef023fff2f821 /lib | |
parent | 2664303d7acf831f84566e7275d8d4a233ab5a46 (diff) | |
download | spack-395c911689d7a3ee426660f3fab334ccee04da1a.tar.gz spack-395c911689d7a3ee426660f3fab334ccee04da1a.tar.bz2 spack-395c911689d7a3ee426660f3fab334ccee04da1a.tar.xz spack-395c911689d7a3ee426660f3fab334ccee04da1a.zip |
Specs: propagated variants affect `==` equality (#47376)
This PR changes the semantic of == for spec so that:
hdf5++mpi == hdf5+mpi
won't hold true anymore. It also changes the constrain semantic, so that a
non-propagating variant always override a propagating variant. This means:
(hdf5++mpi).constrain(hdf5+mpi) -> hdf5+mpi
Before we had a very weird semantic, that was supposed to be tested by unit-tests:
(libelf++debug).constrain(libelf+debug+foo) -> libelf++debug++foo
This semantic has been dropped, as it was never really tested due to the == bug.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/spec.py | 6 | ||||
-rw-r--r-- | lib/spack/spack/test/spec_semantics.py | 46 | ||||
-rw-r--r-- | lib/spack/spack/variant.py | 5 |
3 files changed, 42 insertions, 15 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 0ec0a3009d..ba3a0f9c37 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -877,8 +877,9 @@ class FlagMap(lang.HashableMap): # Next, if any flags in other propagate, we force them to propagate in our case shared = list(sorted(set(other[flag_type]) - extra_other)) for x, y in _shared_subset_pair_iterate(shared, sorted(self[flag_type])): - if x.propagate: - y.propagate = True + if y.propagate is True and x.propagate is False: + changed = True + y.propagate = False # TODO: what happens if flag groups with a partial (but not complete) # intersection specify different behaviors for flag propagation? @@ -933,6 +934,7 @@ class FlagMap(lang.HashableMap): def flags(): for flag in v: yield flag + yield flag.propagate yield flags diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py index a821c53f2f..1b12a8a803 100644 --- a/lib/spack/spack/test/spec_semantics.py +++ b/lib/spack/spack/test/spec_semantics.py @@ -231,7 +231,7 @@ class TestSpecSemantics: ("mpich+foo", "mpich foo=True", "mpich+foo"), ("mpich++foo", "mpich foo=True", "mpich+foo"), ("mpich foo=true", "mpich+foo", "mpich+foo"), - ("mpich foo==true", "mpich++foo", "mpich+foo"), + ("mpich foo==true", "mpich++foo", "mpich++foo"), ("mpich~foo", "mpich foo=FALSE", "mpich~foo"), ("mpich~~foo", "mpich foo=FALSE", "mpich~foo"), ("mpich foo=False", "mpich~foo", "mpich~foo"), @@ -271,17 +271,17 @@ class TestSpecSemantics: ("mpich+foo", "mpich", "mpich+foo"), ("mpich~foo", "mpich", "mpich~foo"), ("mpich foo=1", "mpich", "mpich foo=1"), - ("mpich", "mpich++foo", "mpich+foo"), + ("mpich", "mpich++foo", "mpich++foo"), ("libelf+debug", "libelf+foo", "libelf+debug+foo"), ("libelf+debug", "libelf+debug+foo", "libelf+debug+foo"), ("libelf debug=2", "libelf foo=1", "libelf debug=2 foo=1"), ("libelf debug=2", "libelf debug=2 foo=1", "libelf debug=2 foo=1"), ("libelf+debug", "libelf~foo", "libelf+debug~foo"), ("libelf+debug", "libelf+debug~foo", "libelf+debug~foo"), - ("libelf++debug", "libelf+debug+foo", "libelf++debug++foo"), - ("libelf debug==2", "libelf foo=1", "libelf debug==2 foo==1"), - ("libelf debug==2", "libelf debug=2 foo=1", "libelf debug==2 foo==1"), - ("libelf++debug", "libelf++debug~foo", "libelf++debug~~foo"), + ("libelf++debug", "libelf+debug+foo", "libelf+debug+foo"), + ("libelf debug==2", "libelf foo=1", "libelf debug==2 foo=1"), + ("libelf debug==2", "libelf debug=2 foo=1", "libelf debug=2 foo=1"), + ("libelf++debug", "libelf++debug~foo", "libelf++debug~foo"), ("libelf foo=bar,baz", "libelf foo=*", "libelf foo=bar,baz"), ("libelf foo=*", "libelf foo=bar,baz", "libelf foo=bar,baz"), ( @@ -367,19 +367,24 @@ class TestSpecSemantics: 'mpich cflags="-O3 -g"', 'mpich cflags=="-O3"', 'mpich cflags="-O3 -g"', + 'mpich cflags="-O3 -g"', + [], + [], + ), + ( + 'mpich cflags=="-O3 -g"', + 'mpich cflags=="-O3"', + 'mpich cflags=="-O3 -g"', 'mpich cflags=="-O3 -g"', - [("cflags", "-O3")], - [("cflags", "-O3")], + [("cflags", "-O3"), ("cflags", "-g")], + [("cflags", "-O3"), ("cflags", "-g")], ), ], ) def test_constrain_compiler_flags( self, lhs, rhs, expected_lhs, expected_rhs, propagated_lhs, propagated_rhs ): - """Constraining is asymmetric for compiler flags. Also note that - Spec equality does not account for flag propagation, so the checks - here are manual. - """ + """Constraining is asymmetric for compiler flags.""" lhs, rhs, expected_lhs, expected_rhs = ( Spec(lhs), Spec(rhs), @@ -1904,3 +1909,20 @@ def test_old_format_strings_trigger_error(default_mock_concretization): s = Spec("pkg-a").concretized() with pytest.raises(SpecFormatStringError): s.format("${PACKAGE}-${VERSION}-${HASH}") + + +@pytest.mark.regression("47362") +@pytest.mark.parametrize( + "lhs,rhs", + [ + ("hdf5 +mpi", "hdf5++mpi"), + ("hdf5 cflags==-g", "hdf5 cflags=-g"), + ("hdf5 +mpi ++shared", "hdf5+mpi +shared"), + ("hdf5 +mpi cflags==-g", "hdf5++mpi cflag=-g"), + ], +) +def test_equality_discriminate_on_propagation(lhs, rhs): + """Tests that == can discriminate abstract specs based on their 'propagation' status""" + s, t = Spec(lhs), Spec(rhs) + assert s != t + assert len({s, t}) == 2 diff --git a/lib/spack/spack/variant.py b/lib/spack/spack/variant.py index a15c760a0a..3cc5ba2e0b 100644 --- a/lib/spack/spack/variant.py +++ b/lib/spack/spack/variant.py @@ -251,7 +251,7 @@ def implicit_variant_conversion(method): def convert(self, other): # We don't care if types are different as long as I can convert other to type(self) try: - other = type(self)(other.name, other._original_value) + other = type(self)(other.name, other._original_value, propagate=other.propagate) except (error.SpecError, ValueError): return False return method(self, other) @@ -379,6 +379,7 @@ class AbstractVariant: def _cmp_iter(self) -> Iterable: yield self.name yield from (str(v) for v in self.value_as_tuple) + yield self.propagate def copy(self) -> "AbstractVariant": """Returns an instance of a variant equivalent to self @@ -453,6 +454,7 @@ class AbstractVariant: values.remove("*") self._value_setter(",".join(str(v) for v in values)) + self.propagate = self.propagate and other.propagate return old_value != self.value def __contains__(self, item: Union[str, bool]) -> bool: @@ -557,6 +559,7 @@ class SingleValuedVariant(AbstractVariant): if self.value != other.value: raise UnsatisfiableVariantSpecError(other.value, self.value) + self.propagate = self.propagate and other.propagate return False def __contains__(self, item: ValueType) -> bool: |