From 0feb5ec70a379545fbb13206e2a9a2d1dfc622ef Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Fri, 5 Nov 2021 17:52:44 +0100 Subject: Prevent additional properties to be in the answer set when reusing specs (#27240) * Prevent additional properties to be in the answer set when reusing specs fixes #27237 The mechanism to reuse concrete specs relies on imposing the set of constraints stemming from the concrete spec being reused. We also need to prevent that other constraints get added to this set. --- lib/spack/spack/solver/asp.py | 2 +- lib/spack/spack/solver/concretize.lp | 21 +++++++++++++++++++++ lib/spack/spack/test/concretize.py | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py index 4a8a3fbbc5..c1c3cb33a9 100644 --- a/lib/spack/spack/solver/asp.py +++ b/lib/spack/spack/solver/asp.py @@ -1617,7 +1617,7 @@ class SpackSolverSetup(object): index = spack.binary_distribution.update_cache_and_get_specs() for spec in index: self._facts_from_concrete_spec(spec, possible) - except spack.binary_distribution.FetchCacheError: + except (spack.binary_distribution.FetchCacheError, IndexError): # this is raised when no mirrors had indices. # TODO: update mirror configuration so it can indicate that the source cache # TODO: (or any mirror really) doesn't have binaries. diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index d0a8a8a308..8ad2a9a78a 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -7,6 +7,22 @@ % This logic program implements Spack's concretizer %============================================================================= +%----------------------------------------------------------------------------- +% Generic constraints on nodes +%----------------------------------------------------------------------------- + +% each node must have a single version +:- not 1 { version(Package, _) } 1, node(Package). + +% each node must have a single platform, os and target +:- not 1 { node_platform(Package, _) } 1, node(Package). +:- not 1 { node_os(Package, _) } 1, node(Package). +:- not 1 { node_target(Package, _) } 1, node(Package). + +% each node has a single compiler associated with it +:- not 1 { node_compiler(Package, _) } 1, node(Package). +:- not 1 { node_compiler_version(Package, _, _) } 1, node(Package). + %----------------------------------------------------------------------------- % Version semantics %----------------------------------------------------------------------------- @@ -79,6 +95,11 @@ attr(Name, A1) :- impose(ID), imposed_constraint(ID, Name, A1). attr(Name, A1, A2) :- impose(ID), imposed_constraint(ID, Name, A1, A2). attr(Name, A1, A2, A3) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3). +% we cannot have additional variant values when we are working with concrete specs +:- node(Package), hash(Package, Hash), + variant_value(Package, Variant, Value), + not imposed_constraint(Hash, "variant_value", Package, Variant, Value). + #defined condition/1. #defined condition_requirement/3. #defined condition_requirement/4. diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index bbe84b8a7e..54d886a55b 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -1324,3 +1324,23 @@ class TestConcretize(object): if pkg.name == 'low-priority-provider': continue assert pkg not in s + + @pytest.mark.regression('27237') + @pytest.mark.parametrize('spec_str,expect_installed', [ + ('mpich', True), + ('mpich+debug', False), + ('mpich~debug', True) + ]) + def test_concrete_specs_are_not_modified_on_reuse( + self, mutable_database, spec_str, expect_installed + ): + if spack.config.get('config:concretizer') == 'original': + pytest.skip('Original concretizer cannot reuse specs') + + # Test the internal consistency of solve + DAG reconstruction + # when reused specs are added to the mix. This prevents things + # like additional constraints being added to concrete specs in + # the answer set produced by clingo. + s = spack.spec.Spec(spec_str).concretized(reuse=True) + assert s.package.installed is expect_installed + assert s.satisfies(spec_str, strict=True) -- cgit v1.2.3-70-g09d2