From 7cad6c62a37128f7324597b8e414a350b9312f0b Mon Sep 17 00:00:00 2001 From: Massimiliano Culpo Date: Thu, 18 Apr 2024 17:27:12 +0200 Subject: [PATCH] Associate condition sets from cli to root node (#43710) This PR prevents a condition_set from having nodes that are not associated with the corresponding root node through some (transitive) dependencies. --- lib/spack/spack/solver/concretize.lp | 22 +++++++++++++++++++--- lib/spack/spack/test/concretize.py | 23 +++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp index 5cabd60be3..022c6abe78 100644 --- a/lib/spack/spack/solver/concretize.lp +++ b/lib/spack/spack/solver/concretize.lp @@ -127,10 +127,12 @@ trigger_node(TriggerID, Node, Node) :- trigger_condition_holds(TriggerID, Node), literal(TriggerID). -% Since we trigger the existence of literal nodes from a condition, we need to construct -% the condition_set/2 manually below +% Since we trigger the existence of literal nodes from a condition, we need to construct the condition_set/2 mentioned_in_literal(Root, Mentioned) :- mentioned_in_literal(TriggerID, Root, Mentioned), solve_literal(TriggerID). -condition_set(node(min_dupe_id, Root), node(min_dupe_id, Mentioned)) :- mentioned_in_literal(Root, Mentioned). +condition_set(node(min_dupe_id, Root), node(min_dupe_id, Root)) :- mentioned_in_literal(Root, Root). + +1 { condition_set(node(min_dupe_id, Root), node(0..Y-1, Mentioned)) : max_dupes(Mentioned, Y) } 1 :- + mentioned_in_literal(Root, Mentioned), Mentioned != Root. % Discriminate between "roots" that have been explicitly requested, and roots that are deduced from "virtual roots" explicitly_requested_root(node(min_dupe_id, Package)) :- @@ -138,6 +140,20 @@ explicitly_requested_root(node(min_dupe_id, Package)) :- trigger_and_effect(Package, TriggerID, EffectID), imposed_constraint(EffectID, "root", Package). + +% Keep track of which nodes are associated with which root DAG +associated_with_root(RootNode, RootNode) :- attr("root", RootNode). + +associated_with_root(RootNode, ChildNode) :- + depends_on(ParentNode, ChildNode), + associated_with_root(RootNode, ParentNode). + +% We cannot have a node in the root condition set, that is not associated with that root +:- attr("root", RootNode), + condition_set(RootNode, node(X, Package)), + not virtual(Package), + not associated_with_root(RootNode, node(X, Package)). + #defined concretize_everything/0. #defined literal/1. diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index acc2d0f4e5..f897230088 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -2536,6 +2536,29 @@ def test_no_multiple_solutions_with_different_edges_same_nodes(self): assert len(edges) == 1 assert edges[0].spec.satisfies("@=60") + @pytest.mark.regression("43647") + def test_specifying_different_versions_build_deps(self): + """Tests that we can concretize a spec with nodes using the same build + dependency pinned at different versions, when the constraint is specified + in the root spec. + + o hdf5@1.0 + |\ + o | pinned-gmake@1.0 + o | gmake@3.0 + / + o gmake@4.1 + + """ + hdf5_str = "hdf5@1.0 ^gmake@4.1" + pinned_str = "pinned-gmake@1.0 ^gmake@3.0" + input_specs = [Spec(hdf5_str), Spec(pinned_str)] + solver = spack.solver.asp.Solver() + result = solver.solve(input_specs) + + assert any(x.satisfies(hdf5_str) for x in result.specs) + assert any(x.satisfies(pinned_str) for x in result.specs) + @pytest.mark.parametrize( "v_str,v_opts,checksummed",