ASP-based solver: variants set from cli are considered as defaults (#23542)

Variants explicitly set in an abstract root spec are considered
as defaults for the package they refer to, and they override
what is in packages.yaml and in package.py. This is relevant
only for multi-valued variants, where a constraint may extend
an already default value.
This commit is contained in:
Massimiliano Culpo 2021-05-11 21:38:17 +02:00 committed by GitHub
parent fe46a1ce5f
commit 2a509ea0bf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 7 deletions

View file

@ -1393,7 +1393,10 @@ def setup(self, driver, specs, tests=False):
) )
for clause in self.spec_clauses(spec): for clause in self.spec_clauses(spec):
self.gen.fact(clause) self.gen.fact(clause)
if clause.name == 'variant_set':
self.gen.fact(fn.variant_default_value_from_cli(
*clause.args
))
self.gen.h1("Variant Values defined in specs") self.gen.h1("Variant Values defined in specs")
self.define_variant_values() self.define_variant_values()

View file

@ -403,14 +403,23 @@ variant_not_default(Package, Variant, Value, 0)
external_with_variant_set(Package, Variant, Value), external_with_variant_set(Package, Variant, Value),
node(Package). node(Package).
% The default value for a variant in a package is what is written % The default value for a variant in a package is what is prescribed:
% in the package.py file, unless some preference is set in packages.yaml %
% 1. On the command line
% 2. In packages.yaml (if there's no command line settings)
% 3. In the package.py file (if there are no settings in
% packages.yaml and the command line)
%
variant_default_value(Package, Variant, Value) variant_default_value(Package, Variant, Value)
:- variant_default_value_from_package_py(Package, Variant, Value), :- variant_default_value_from_package_py(Package, Variant, Value),
not variant_default_value_from_packages_yaml(Package, Variant, _). not variant_default_value_from_packages_yaml(Package, Variant, _),
not variant_default_value_from_cli(Package, Variant, _).
variant_default_value(Package, Variant, Value) variant_default_value(Package, Variant, Value)
:- variant_default_value_from_packages_yaml(Package, Variant, Value). :- variant_default_value_from_packages_yaml(Package, Variant, Value),
not variant_default_value_from_cli(Package, Variant, _).
variant_default_value(Package, Variant, Value) :- variant_default_value_from_cli(Package, Variant, Value).
% Treat 'none' in a special way - it cannot be combined with other % Treat 'none' in a special way - it cannot be combined with other
% values even if the variant is multi-valued % values even if the variant is multi-valued
@ -435,6 +444,7 @@ variant_single_value(Package, "dev_path")
#defined variant_single_value/2. #defined variant_single_value/2.
#defined variant_default_value/3. #defined variant_default_value/3.
#defined variant_possible_value/3. #defined variant_possible_value/3.
#defined variant_default_value_from_cli/3.
#defined variant_default_value_from_packages_yaml/3. #defined variant_default_value_from_packages_yaml/3.
#defined variant_default_value_from_package_py/3. #defined variant_default_value_from_package_py/3.
#defined variant_value_from_disjoint_sets/4. #defined variant_value_from_disjoint_sets/4.
@ -704,7 +714,7 @@ opt_criterion(14, "number of non-default variants (roots)").
% If the value is a multivalued variant there could be multiple % If the value is a multivalued variant there could be multiple
% values set as default. Since a default value has a weight of 0 we % values set as default. Since a default value has a weight of 0 we
% need to maximize their number below to ensure they're all set % need to maximize their number below to ensure they're all set
opt_criterion(13, "multi-valued variants + preferred providers for roots"). opt_criterion(13, "multi-valued variants").
#minimize{ 0@13 : #true }. #minimize{ 0@13 : #true }.
#maximize { #maximize {
1@13,Package,Variant,Value 1@13,Package,Variant,Value
@ -712,8 +722,10 @@ opt_criterion(13, "multi-valued variants + preferred providers for roots").
not variant_single_value(Package, Variant), not variant_single_value(Package, Variant),
root(Package) root(Package)
}. }.
opt_criterion(12, "preferred providers for roots").
#minimize{ 0@12 : #true }.
#minimize{ #minimize{
Weight@13,Provider Weight@12,Provider
: provider_weight(Provider, Weight), root(Provider) : provider_weight(Provider, Weight), root(Provider)
}. }.

View file

@ -1210,3 +1210,21 @@ def test_compiler_is_unique(self, spec_str, expected_compiler):
for node in s.traverse(): for node in s.traverse():
assert node.satisfies(expected_compiler) assert node.satisfies(expected_compiler)
@pytest.mark.parametrize('spec_str,expected_dict', [
# Check the defaults from the package (libs=shared)
('multivalue-variant', {
'libs=shared': True,
'libs=static': False
}),
# Check that libs=static doesn't extend the default
('multivalue-variant libs=static', {
'libs=shared': False,
'libs=static': True
}),
])
def test_multivalued_variants_from_cli(self, spec_str, expected_dict):
s = Spec(spec_str).concretized()
for constraint, value in expected_dict.items():
assert s.satisfies(constraint) == value

View file

@ -29,6 +29,11 @@ class MultivalueVariant(Package):
multi=False multi=False
) )
variant(
'libs', default='shared', values=('shared', 'static'), multi=True,
description='Type of libraries to install'
)
depends_on('mpi') depends_on('mpi')
depends_on('callpath') depends_on('callpath')
depends_on('a') depends_on('a')