ASP-based solver: fix rules on version weights selection (#31153)
* ASP: sort and deduplicate version weights from installed specs * Pick version weights according to provenance * Add unit test
This commit is contained in:
parent
392b548312
commit
267358a799
@ -748,7 +748,13 @@ def key_fn(version):
|
||||
|
||||
pkg = packagize(pkg)
|
||||
declared_versions = self.declared_versions[pkg.name]
|
||||
most_to_least_preferred = sorted(declared_versions, key=key_fn)
|
||||
partially_sorted_versions = sorted(set(declared_versions), key=key_fn)
|
||||
|
||||
most_to_least_preferred = []
|
||||
for _, group in itertools.groupby(partially_sorted_versions, key=key_fn):
|
||||
most_to_least_preferred.extend(list(sorted(
|
||||
group, reverse=True, key=lambda x: spack.version.ver(x.version)
|
||||
)))
|
||||
|
||||
for weight, declared_version in enumerate(most_to_least_preferred):
|
||||
self.gen.fact(fn.version_declared(
|
||||
|
@ -107,10 +107,28 @@ possible_version_weight(Package, Weight)
|
||||
:- version(Package, Version),
|
||||
version_declared(Package, Version, Weight).
|
||||
|
||||
version_weight(Package, Weight)
|
||||
% we can't use the weight for an external version if we don't use the
|
||||
% corresponding external spec.
|
||||
:- version(Package, Version),
|
||||
node(Package),
|
||||
Weight = #min{W : version_declared(Package, Version, W)}.
|
||||
version_weight(Package, Weight),
|
||||
version_declared(Package, Version, Weight, "external"),
|
||||
not external(Package).
|
||||
|
||||
% we can't use a weight from an installed spec if we are building it
|
||||
% and vice-versa
|
||||
:- version(Package, Version),
|
||||
version_weight(Package, Weight),
|
||||
version_declared(Package, Version, Weight, "installed"),
|
||||
build(Package).
|
||||
|
||||
:- version(Package, Version),
|
||||
version_weight(Package, Weight),
|
||||
not version_declared(Package, Version, Weight, "installed"),
|
||||
not build(Package).
|
||||
|
||||
1 { version_weight(Package, Weight) : version_declared(Package, Version, Weight) } 1
|
||||
:- version(Package, Version),
|
||||
node(Package).
|
||||
|
||||
% node_version_satisfies implies that exactly one of the satisfying versions
|
||||
% is the package's version, and vice versa.
|
||||
|
@ -1753,3 +1753,36 @@ def test_misleading_error_message_on_version(self, mutable_database):
|
||||
with pytest.raises(spack.solver.asp.UnsatisfiableSpecError,
|
||||
match="'dep-with-variants' satisfies '@999'"):
|
||||
solver.driver.solve(setup, [root_spec], reuse=reusable_specs)
|
||||
|
||||
@pytest.mark.regression('31148')
|
||||
def test_version_weight_and_provenance(self):
|
||||
"""Test package preferences during coconcretization."""
|
||||
import spack.solver.asp
|
||||
if spack.config.get('config:concretizer') == 'original':
|
||||
pytest.skip('Original concretizer cannot reuse')
|
||||
|
||||
reusable_specs = [
|
||||
spack.spec.Spec(spec_str).concretized()
|
||||
for spec_str in ('b@0.9', 'b@1.0')
|
||||
]
|
||||
root_spec = spack.spec.Spec('a foobar=bar')
|
||||
|
||||
with spack.config.override("concretizer:reuse", True):
|
||||
solver = spack.solver.asp.Solver()
|
||||
setup = spack.solver.asp.SpackSolverSetup()
|
||||
result = solver.driver.solve(
|
||||
setup, [root_spec], reuse=reusable_specs, out=sys.stdout
|
||||
)
|
||||
# The result here should have a single spec to build ('a')
|
||||
# and it should be using b@1.0 with a version badness of 2
|
||||
# The provenance is:
|
||||
# version_declared("b","1.0",0,"package_py").
|
||||
# version_declared("b","0.9",1,"package_py").
|
||||
# version_declared("b","1.0",2,"installed").
|
||||
# version_declared("b","0.9",3,"installed").
|
||||
for criterion in [
|
||||
(1, None, 'number of packages to build (vs. reuse)'),
|
||||
(2, 0, 'version badness')
|
||||
]:
|
||||
assert criterion in result.criteria
|
||||
assert result.specs[0].satisfies('^b@1.0')
|
||||
|
Loading…
Reference in New Issue
Block a user