concretizer: try hard to obtain all needed variant_possible_value()'s (#20102)
Track all the variant values mentioned when emitting constraints, validate them and emit a fact that allows them as possible values. This modification ensures that open-ended variants (variants accepting any string or any integer) are projected to the finite set of values that are relevant for this concretization.
This commit is contained in:
parent
30a9e6462f
commit
ab3f1b10db
@ -1104,7 +1104,14 @@ def preferred_variants(self, pkg_name):
|
|||||||
if not isinstance(values, tuple):
|
if not isinstance(values, tuple):
|
||||||
values = (values,)
|
values = (values,)
|
||||||
|
|
||||||
|
# perform validation of the variant and values
|
||||||
|
spec = spack.spec.Spec(pkg_name)
|
||||||
|
spec.update_variant_validate(variant_name, values)
|
||||||
|
|
||||||
for value in values:
|
for value in values:
|
||||||
|
self.variant_values_from_specs.add(
|
||||||
|
(pkg_name, variant.name, value)
|
||||||
|
)
|
||||||
self.gen.fact(fn.variant_default_value_from_packages_yaml(
|
self.gen.fact(fn.variant_default_value_from_packages_yaml(
|
||||||
pkg_name, variant.name, value
|
pkg_name, variant.name, value
|
||||||
))
|
))
|
||||||
@ -1692,15 +1699,7 @@ def variant_value(self, pkg, name, value):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
pkg_class = spack.repo.path.get_pkg_class(pkg)
|
self._specs[pkg].update_variant_validate(name, value)
|
||||||
|
|
||||||
variant = self._specs[pkg].variants.get(name)
|
|
||||||
if variant:
|
|
||||||
# it's multi-valued
|
|
||||||
variant.append(value)
|
|
||||||
else:
|
|
||||||
variant = pkg_class.variants[name].make_variant(value)
|
|
||||||
self._specs[pkg].variants[name] = variant
|
|
||||||
|
|
||||||
def version(self, pkg, version):
|
def version(self, pkg, version):
|
||||||
self._specs[pkg].versions = ver([version])
|
self._specs[pkg].versions = ver([version])
|
||||||
|
@ -183,6 +183,9 @@ external_spec(Package, ID) :-
|
|||||||
% if a variant is set to anything, it is considered 'set'.
|
% if a variant is set to anything, it is considered 'set'.
|
||||||
variant_set(Package, Variant) :- variant_set(Package, Variant, _).
|
variant_set(Package, Variant) :- variant_set(Package, Variant, _).
|
||||||
|
|
||||||
|
% A variant cannot have a value that is not also a possible value
|
||||||
|
:- variant_value(Package, Variant, Value), not variant_possible_value(Package, Variant, Value).
|
||||||
|
|
||||||
% variant_set is an explicitly set variant value. If it's not 'set',
|
% variant_set is an explicitly set variant value. If it's not 'set',
|
||||||
% we revert to the default value. If it is set, we force the set value
|
% we revert to the default value. If it is set, we force the set value
|
||||||
variant_value(Package, Variant, Value)
|
variant_value(Package, Variant, Value)
|
||||||
|
@ -2893,6 +2893,40 @@ def ensure_valid_variants(spec):
|
|||||||
if not_existing:
|
if not_existing:
|
||||||
raise vt.UnknownVariantError(spec, not_existing)
|
raise vt.UnknownVariantError(spec, not_existing)
|
||||||
|
|
||||||
|
def update_variant_validate(self, variant_name, values):
|
||||||
|
"""If it is not already there, adds the variant named
|
||||||
|
`variant_name` to the spec `spec` based on the definition
|
||||||
|
contained in the package metadata. Validates the variant and
|
||||||
|
values before returning.
|
||||||
|
|
||||||
|
Used to add values to a variant without being sensitive to the
|
||||||
|
variant being single or multi-valued. If the variant already
|
||||||
|
exists on the spec it is assumed to be multi-valued and the
|
||||||
|
values are appended.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
variant_name: the name of the variant to add or append to
|
||||||
|
values: the value or values (as a tuple) to add/append
|
||||||
|
to the variant
|
||||||
|
"""
|
||||||
|
if not isinstance(values, tuple):
|
||||||
|
values = (values,)
|
||||||
|
|
||||||
|
pkg_variant = self.package_class.variants[variant_name]
|
||||||
|
|
||||||
|
for value in values:
|
||||||
|
if self.variants.get(variant_name):
|
||||||
|
msg = ("Cannot append a value to a single-valued "
|
||||||
|
"variant with an already set value")
|
||||||
|
assert pkg_variant.multi, msg
|
||||||
|
self.variants[variant_name].append(value)
|
||||||
|
else:
|
||||||
|
variant = pkg_variant.make_variant(value)
|
||||||
|
self.variants[variant_name] = variant
|
||||||
|
|
||||||
|
pkg_variant.validate_or_raise(
|
||||||
|
self.variants[variant_name], self.package)
|
||||||
|
|
||||||
def constrain(self, other, deps=True):
|
def constrain(self, other, deps=True):
|
||||||
"""Merge the constraints of other with self.
|
"""Merge the constraints of other with self.
|
||||||
|
|
||||||
|
@ -264,6 +264,10 @@ def concretize_multi_provider(self):
|
|||||||
s.concretize()
|
s.concretize()
|
||||||
assert s['mpi'].version == ver('1.10.3')
|
assert s['mpi'].version == ver('1.10.3')
|
||||||
|
|
||||||
|
def test_concretize_dependent_with_singlevalued_variant_type(self):
|
||||||
|
s = Spec('singlevalue-variant-dependent-type')
|
||||||
|
s.concretize()
|
||||||
|
|
||||||
@pytest.mark.parametrize("spec,version", [
|
@pytest.mark.parametrize("spec,version", [
|
||||||
('dealii', 'develop'),
|
('dealii', 'develop'),
|
||||||
('xsdk', '0.4.0'),
|
('xsdk', '0.4.0'),
|
||||||
|
@ -82,7 +82,9 @@ class TestConcretizePreferences(object):
|
|||||||
{'debug': True, 'opt': True, 'shared': False, 'static': False}),
|
{'debug': True, 'opt': True, 'shared': False, 'static': False}),
|
||||||
# Check a multivalued variant with multiple values set
|
# Check a multivalued variant with multiple values set
|
||||||
('multivalue-variant', ['foo=bar,baz', 'fee=bar'],
|
('multivalue-variant', ['foo=bar,baz', 'fee=bar'],
|
||||||
{'foo': ('bar', 'baz'), 'fee': 'bar'})
|
{'foo': ('bar', 'baz'), 'fee': 'bar'}),
|
||||||
|
('singlevalue-variant', ['fum=why'],
|
||||||
|
{'fum': 'why'})
|
||||||
])
|
])
|
||||||
def test_preferred_variants(
|
def test_preferred_variants(
|
||||||
self, package_name, variant_value, expected_results
|
self, package_name, variant_value, expected_results
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
|
||||||
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
|
|
||||||
|
class SinglevalueVariantDependentType(Package):
|
||||||
|
"""Simple package with one dependency that has a single-valued
|
||||||
|
variant with values=str"""
|
||||||
|
|
||||||
|
homepage = "http://www.example.com"
|
||||||
|
url = "http://www.example.com/archive-1.0.tar.gz"
|
||||||
|
|
||||||
|
version('1.0', '0123456789abcdef0123456789abcdef')
|
||||||
|
|
||||||
|
depends_on('singlevalue-variant fum=nope')
|
@ -0,0 +1,19 @@
|
|||||||
|
# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
|
||||||
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
|
|
||||||
|
class SinglevalueVariant(Package):
|
||||||
|
homepage = "http://www.llnl.gov"
|
||||||
|
url = "http://www.llnl.gov/mpileaks-1.0.tar.gz"
|
||||||
|
|
||||||
|
version(1.0, 'foobarbaz')
|
||||||
|
|
||||||
|
variant(
|
||||||
|
'fum',
|
||||||
|
description='Single-valued variant with type in values',
|
||||||
|
default='bar',
|
||||||
|
values=str,
|
||||||
|
multi=False
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user