ASP-based solver: use edge properties for reused specs (#39508)

Since #34821 we are annotating virtual dependencies on
DAG edges, and reconstructing virtuals in memory when
we read a concrete spec from previous formats.

Therefore, we can remove a TODO in asp.py, and rely on
"virtual_on_edge" facts to be imposed.
This commit is contained in:
Massimiliano Culpo 2023-08-22 21:07:51 +02:00 committed by GitHub
parent 9f1a30d3b5
commit 9ae1317e79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 31 deletions

View file

@ -1827,37 +1827,11 @@ class Body:
# skip build dependencies of already-installed specs
if concrete_build_deps or dtype != "build":
clauses.append(fn.attr("depends_on", spec.name, dep.name, dtype))
# TODO: We have to look up info from package.py here, but we'd
# TODO: like to avoid this entirely. We should not need to look
# TODO: up potentially wrong info if we have virtual edge info.
try:
try:
pkg = dep.package
except spack.repo.UnknownNamespaceError:
# Try to look up the package of the same name and use its
# providers. This is as good as we can do without edge info.
pkg_class = spack.repo.PATH.get_pkg_class(dep.name)
spec = spack.spec.Spec(f"{dep.name}@{dep.version}")
pkg = pkg_class(spec)
virtuals = pkg.virtuals_provided
except spack.repo.UnknownPackageError:
# Skip virtual node constriants for renamed/deleted packages,
# so their binaries can still be installed.
# NOTE: with current specs (which lack edge attributes) this
# can allow concretizations with two providers, but it's unlikely.
continue
# Don't concretize with two providers of the same virtual.
# See above for exception for unknown packages.
# TODO: we will eventually record provider information on edges,
# TODO: which avoids the need for the package lookup above.
for virtual in virtuals:
clauses.append(fn.attr("virtual_node", virtual.name))
clauses.append(fn.provider(dep.name, virtual.name))
for virtual_name in dspec.virtuals:
clauses.append(
fn.attr("virtual_on_edge", spec.name, dep.name, virtual_name)
)
clauses.append(fn.attr("virtual_node", virtual_name))
# imposing hash constraints for all but pure build deps of
# already-installed concrete specs.

View file

@ -113,6 +113,7 @@ unification_set(SetID, VirtualNode)
% Node attributes that have multiple node arguments (usually, only the first argument is a node)
multiple_nodes_attribute("node_flag_source").
multiple_nodes_attribute("depends_on").
multiple_nodes_attribute("virtual_on_edge").
% Map constraint on the literal ID to facts on the node
attr(Name, node(min_dupe_id, A1)) :- literal(LiteralID, Name, A1), solve_literal(LiteralID).
@ -367,6 +368,18 @@ attr("node_flag_source", node(X, A1), A2, node(Y, A3))
:- impose(ID, node(X, A1)),
imposed_constraint(ID, "depends_on", A1, A2, A3).
% Reconstruct virtual dependencies for reused specs
attr("virtual_on_edge", node(X, A1), node(Y, A2), Virtual)
:- impose(ID, node(X, A1)),
depends_on(node(X, A1), node(Y, A2)),
imposed_constraint(ID, "virtual_on_edge", A1, A2, Virtual),
not build(node(X, A1)).
virtual_condition_holds(node(Y, A2), Virtual)
:- impose(ID, node(X, A1)),
attr("virtual_on_edge", node(X, A1), node(Y, A2), Virtual),
not build(node(X, A1)).
% we cannot have additional variant values when we are working with concrete specs
:- attr("node", node(ID, Package)),
attr("hash", node(ID, Package), Hash),

View file

@ -2099,6 +2099,21 @@ def test_virtuals_are_annotated_on_edges(self, spec_str, default_mock_concretiza
edges = spec.edges_to_dependencies(name="callpath")
assert len(edges) == 1 and edges[0].virtuals == ()
@pytest.mark.only_clingo("Use case not supported by the original concretizer")
@pytest.mark.db
@pytest.mark.parametrize(
"spec_str,mpi_name",
[("mpileaks", "mpich"), ("mpileaks ^mpich2", "mpich2"), ("mpileaks ^zmpi", "zmpi")],
)
def test_virtuals_are_reconstructed_on_reuse(self, spec_str, mpi_name, database):
"""Tests that when we reuse a spec, virtual on edges are reconstructed correctly"""
with spack.config.override("concretizer:reuse", True):
spec = Spec(spec_str).concretized()
assert spec.installed
mpi_edges = spec.edges_to_dependencies(mpi_name)
assert len(mpi_edges) == 1
assert "mpi" in mpi_edges[0].virtuals
@pytest.fixture()
def duplicates_test_repository():