Add a "sticky" property to variants (#28630)
* Add sticky variants
* Add unit tests for sticky variants
* Add documentation for sticky variants
* Revert "Revert 19736 because conflicts are avoided by clingo by default (#26721)"
This reverts commit 33ef7d57c1.
* Add stickiness to "allow-unsupported-compiler"
			
			
This commit is contained in:
		 Massimiliano Culpo
					Massimiliano Culpo
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							dd7acecf3d
						
					
				
				
					commit
					cd04109e17
				
			| @@ -1441,6 +1441,32 @@ The ``when`` clause follows the same syntax and accepts the same | ||||
| values as the ``when`` argument of | ||||
| :py:func:`spack.directives.depends_on` | ||||
|  | ||||
| ^^^^^^^^^^^^^^^ | ||||
| Sticky Variants | ||||
| ^^^^^^^^^^^^^^^ | ||||
|  | ||||
| The variant directive can be marked as ``sticky`` by setting to ``True`` the | ||||
| corresponding argument: | ||||
|  | ||||
| .. code-block:: python | ||||
|  | ||||
|    variant('bar', default=False, sticky=True) | ||||
|  | ||||
| A ``sticky`` variant differs from a regular one in that it is always set | ||||
| to either: | ||||
|  | ||||
| #. An explicit value appearing in a spec literal or | ||||
| #. Its default value | ||||
|  | ||||
| The concretizer thus is not free to pick an alternate value to work | ||||
| around conflicts, but will error out instead. | ||||
| Setting this property on a variant is useful in cases where the | ||||
| variant allows some dangerous or controversial options (e.g. using unsupported versions | ||||
| of a compiler for a library) and the packager wants to ensure that | ||||
| allowing these options is done on purpose by the user, rather than | ||||
| automatically by the solver. | ||||
|  | ||||
|  | ||||
| ^^^^^^^^^^^^^^^^^^^ | ||||
| Overriding Variants | ||||
| ^^^^^^^^^^^^^^^^^^^ | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| 
 | ||||
| import spack.variant | ||||
| from spack.directives import conflicts, depends_on, variant | ||||
| from spack.multimethod import when | ||||
| from spack.package import PackageBase | ||||
| 
 | ||||
| 
 | ||||
| @@ -88,103 +89,103 @@ def cuda_flags(arch_list): | ||||
| 
 | ||||
|     # Linux x86_64 compiler conflicts from here: | ||||
|     # https://gist.github.com/ax3l/9489132 | ||||
|     with when('^cuda~allow-unsupported-compilers'): | ||||
|         # GCC | ||||
|         # According to | ||||
|         # https://github.com/spack/spack/pull/25054#issuecomment-886531664 | ||||
|         # these conflicts are valid independently from the architecture | ||||
| 
 | ||||
|     # GCC | ||||
|     # According to | ||||
|     # https://github.com/spack/spack/pull/25054#issuecomment-886531664 | ||||
|     # these conflicts are valid independently from the architecture | ||||
|         # minimum supported versions | ||||
|         conflicts('%gcc@:4', when='+cuda ^cuda@11.0:') | ||||
|         conflicts('%gcc@:5', when='+cuda ^cuda@11.4:') | ||||
| 
 | ||||
|     # minimum supported versions | ||||
|     conflicts('%gcc@:4', when='+cuda ^cuda@11.0:') | ||||
|     conflicts('%gcc@:5', when='+cuda ^cuda@11.4:') | ||||
|         # maximum supported version | ||||
|         # NOTE: | ||||
|         # in order to not constrain future cuda version to old gcc versions, | ||||
|         # it has been decided to use an upper bound for the latest version. | ||||
|         # This implies that the last one in the list has to be updated at | ||||
|         # each release of a new cuda minor version. | ||||
|         conflicts('%gcc@10:', when='+cuda ^cuda@:11.0') | ||||
|         conflicts('%gcc@12:', when='+cuda ^cuda@:11.6') | ||||
|         conflicts('%clang@13:', when='+cuda ^cuda@:11.5') | ||||
|         conflicts('%clang@14:', when='+cuda ^cuda@:11.6') | ||||
| 
 | ||||
|     # maximum supported version | ||||
|     # NOTE: | ||||
|     # in order to not constrain future cuda version to old gcc versions, | ||||
|     # it has been decided to use an upper bound for the latest version. | ||||
|     # This implies that the last one in the list has to be updated at | ||||
|     # each release of a new cuda minor version. | ||||
|     conflicts('%gcc@10:', when='+cuda ^cuda@:11.0') | ||||
|     conflicts('%gcc@12:', when='+cuda ^cuda@:11.6') | ||||
|     conflicts('%clang@13:', when='+cuda ^cuda@:11.5') | ||||
|     conflicts('%clang@14:', when='+cuda ^cuda@:11.6') | ||||
|         # https://gist.github.com/ax3l/9489132#gistcomment-3860114 | ||||
|         conflicts('%gcc@10', when='+cuda ^cuda@:11.4.0') | ||||
|         conflicts('%gcc@5:', when='+cuda ^cuda@:7.5 target=x86_64:') | ||||
|         conflicts('%gcc@6:', when='+cuda ^cuda@:8 target=x86_64:') | ||||
|         conflicts('%gcc@7:', when='+cuda ^cuda@:9.1 target=x86_64:') | ||||
|         conflicts('%gcc@8:', when='+cuda ^cuda@:10.0.130 target=x86_64:') | ||||
|         conflicts('%gcc@9:', when='+cuda ^cuda@:10.2.89 target=x86_64:') | ||||
|         conflicts('%pgi@:14.8', when='+cuda ^cuda@:7.0.27 target=x86_64:') | ||||
|         conflicts('%pgi@:15.3,15.5:', when='+cuda ^cuda@7.5 target=x86_64:') | ||||
|         conflicts('%pgi@:16.2,16.0:16.3', when='+cuda ^cuda@8 target=x86_64:') | ||||
|         conflicts('%pgi@:15,18:', when='+cuda ^cuda@9.0:9.1 target=x86_64:') | ||||
|         conflicts('%pgi@:16,19:', when='+cuda ^cuda@9.2.88:10 target=x86_64:') | ||||
|         conflicts('%pgi@:17,20:', when='+cuda ^cuda@10.1.105:10.2.89 target=x86_64:') | ||||
|         conflicts('%pgi@:17,21:', when='+cuda ^cuda@11.0.2:11.1.0 target=x86_64:') | ||||
|         conflicts('%clang@:3.4', when='+cuda ^cuda@:7.5 target=x86_64:') | ||||
|         conflicts('%clang@:3.7,4:', when='+cuda ^cuda@8.0:9.0 target=x86_64:') | ||||
|         conflicts('%clang@:3.7,4.1:', when='+cuda ^cuda@9.1 target=x86_64:') | ||||
|         conflicts('%clang@:3.7,5.1:', when='+cuda ^cuda@9.2 target=x86_64:') | ||||
|         conflicts('%clang@:3.7,6.1:', when='+cuda ^cuda@10.0.130 target=x86_64:') | ||||
|         conflicts('%clang@:3.7,7.1:', when='+cuda ^cuda@10.1.105 target=x86_64:') | ||||
|         conflicts('%clang@:3.7,8.1:', | ||||
|                   when='+cuda ^cuda@10.1.105:10.1.243 target=x86_64:') | ||||
|         conflicts('%clang@:3.2,9:', when='+cuda ^cuda@10.2.89 target=x86_64:') | ||||
|         conflicts('%clang@:5', when='+cuda ^cuda@11.0.2: target=x86_64:') | ||||
|         conflicts('%clang@10:', when='+cuda ^cuda@:11.0.3 target=x86_64:') | ||||
|         conflicts('%clang@11:', when='+cuda ^cuda@:11.1.0 target=x86_64:') | ||||
| 
 | ||||
|     # https://gist.github.com/ax3l/9489132#gistcomment-3860114 | ||||
|     conflicts('%gcc@10', when='+cuda ^cuda@:11.4.0') | ||||
|     conflicts('%gcc@5:', when='+cuda ^cuda@:7.5 target=x86_64:') | ||||
|     conflicts('%gcc@6:', when='+cuda ^cuda@:8 target=x86_64:') | ||||
|     conflicts('%gcc@7:', when='+cuda ^cuda@:9.1 target=x86_64:') | ||||
|     conflicts('%gcc@8:', when='+cuda ^cuda@:10.0.130 target=x86_64:') | ||||
|     conflicts('%gcc@9:', when='+cuda ^cuda@:10.2.89 target=x86_64:') | ||||
|     conflicts('%pgi@:14.8', when='+cuda ^cuda@:7.0.27 target=x86_64:') | ||||
|     conflicts('%pgi@:15.3,15.5:', when='+cuda ^cuda@7.5 target=x86_64:') | ||||
|     conflicts('%pgi@:16.2,16.0:16.3', when='+cuda ^cuda@8 target=x86_64:') | ||||
|     conflicts('%pgi@:15,18:', when='+cuda ^cuda@9.0:9.1 target=x86_64:') | ||||
|     conflicts('%pgi@:16,19:', when='+cuda ^cuda@9.2.88:10 target=x86_64:') | ||||
|     conflicts('%pgi@:17,20:', when='+cuda ^cuda@10.1.105:10.2.89 target=x86_64:') | ||||
|     conflicts('%pgi@:17,21:', when='+cuda ^cuda@11.0.2:11.1.0 target=x86_64:') | ||||
|     conflicts('%clang@:3.4', when='+cuda ^cuda@:7.5 target=x86_64:') | ||||
|     conflicts('%clang@:3.7,4:', when='+cuda ^cuda@8.0:9.0 target=x86_64:') | ||||
|     conflicts('%clang@:3.7,4.1:', when='+cuda ^cuda@9.1 target=x86_64:') | ||||
|     conflicts('%clang@:3.7,5.1:', when='+cuda ^cuda@9.2 target=x86_64:') | ||||
|     conflicts('%clang@:3.7,6.1:', when='+cuda ^cuda@10.0.130 target=x86_64:') | ||||
|     conflicts('%clang@:3.7,7.1:', when='+cuda ^cuda@10.1.105 target=x86_64:') | ||||
|     conflicts('%clang@:3.7,8.1:', | ||||
|               when='+cuda ^cuda@10.1.105:10.1.243 target=x86_64:') | ||||
|     conflicts('%clang@:3.2,9:', when='+cuda ^cuda@10.2.89 target=x86_64:') | ||||
|     conflicts('%clang@:5', when='+cuda ^cuda@11.0.2: target=x86_64:') | ||||
|     conflicts('%clang@10:', when='+cuda ^cuda@:11.0.3 target=x86_64:') | ||||
|     conflicts('%clang@11:', when='+cuda ^cuda@:11.1.0 target=x86_64:') | ||||
|         # x86_64 vs. ppc64le differ according to NVidia docs | ||||
|         # Linux ppc64le compiler conflicts from Table from the docs below: | ||||
|         # https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html | ||||
|         # https://docs.nvidia.com/cuda/archive/9.2/cuda-installation-guide-linux/index.html | ||||
|         # https://docs.nvidia.com/cuda/archive/9.1/cuda-installation-guide-linux/index.html | ||||
|         # https://docs.nvidia.com/cuda/archive/9.0/cuda-installation-guide-linux/index.html | ||||
|         # https://docs.nvidia.com/cuda/archive/8.0/cuda-installation-guide-linux/index.html | ||||
| 
 | ||||
|     # x86_64 vs. ppc64le differ according to NVidia docs | ||||
|     # Linux ppc64le compiler conflicts from Table from the docs below: | ||||
|     # https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html | ||||
|     # https://docs.nvidia.com/cuda/archive/9.2/cuda-installation-guide-linux/index.html | ||||
|     # https://docs.nvidia.com/cuda/archive/9.1/cuda-installation-guide-linux/index.html | ||||
|     # https://docs.nvidia.com/cuda/archive/9.0/cuda-installation-guide-linux/index.html | ||||
|     # https://docs.nvidia.com/cuda/archive/8.0/cuda-installation-guide-linux/index.html | ||||
|         # information prior to CUDA 9 difficult to find | ||||
|         conflicts('%gcc@6:', when='+cuda ^cuda@:9 target=ppc64le:') | ||||
|         conflicts('%gcc@8:', when='+cuda ^cuda@:10.0.130 target=ppc64le:') | ||||
|         conflicts('%gcc@9:', when='+cuda ^cuda@:10.1.243 target=ppc64le:') | ||||
|         # officially, CUDA 11.0.2 only supports the system GCC 8.3 on ppc64le | ||||
|         conflicts('%pgi', when='+cuda ^cuda@:8 target=ppc64le:') | ||||
|         conflicts('%pgi@:16', when='+cuda ^cuda@:9.1.185 target=ppc64le:') | ||||
|         conflicts('%pgi@:17', when='+cuda ^cuda@:10 target=ppc64le:') | ||||
|         conflicts('%clang@4:', when='+cuda ^cuda@:9.0.176 target=ppc64le:') | ||||
|         conflicts('%clang@5:', when='+cuda ^cuda@:9.1 target=ppc64le:') | ||||
|         conflicts('%clang@6:', when='+cuda ^cuda@:9.2 target=ppc64le:') | ||||
|         conflicts('%clang@7:', when='+cuda ^cuda@10.0.130 target=ppc64le:') | ||||
|         conflicts('%clang@7.1:', when='+cuda ^cuda@:10.1.105 target=ppc64le:') | ||||
|         conflicts('%clang@8.1:', when='+cuda ^cuda@:10.2.89 target=ppc64le:') | ||||
|         conflicts('%clang@:5', when='+cuda ^cuda@11.0.2: target=ppc64le:') | ||||
|         conflicts('%clang@10:', when='+cuda ^cuda@:11.0.2 target=ppc64le:') | ||||
|         conflicts('%clang@11:', when='+cuda ^cuda@:11.1.0 target=ppc64le:') | ||||
| 
 | ||||
|     # information prior to CUDA 9 difficult to find | ||||
|     conflicts('%gcc@6:', when='+cuda ^cuda@:9 target=ppc64le:') | ||||
|     conflicts('%gcc@8:', when='+cuda ^cuda@:10.0.130 target=ppc64le:') | ||||
|     conflicts('%gcc@9:', when='+cuda ^cuda@:10.1.243 target=ppc64le:') | ||||
|     # officially, CUDA 11.0.2 only supports the system GCC 8.3 on ppc64le | ||||
|     conflicts('%pgi', when='+cuda ^cuda@:8 target=ppc64le:') | ||||
|     conflicts('%pgi@:16', when='+cuda ^cuda@:9.1.185 target=ppc64le:') | ||||
|     conflicts('%pgi@:17', when='+cuda ^cuda@:10 target=ppc64le:') | ||||
|     conflicts('%clang@4:', when='+cuda ^cuda@:9.0.176 target=ppc64le:') | ||||
|     conflicts('%clang@5:', when='+cuda ^cuda@:9.1 target=ppc64le:') | ||||
|     conflicts('%clang@6:', when='+cuda ^cuda@:9.2 target=ppc64le:') | ||||
|     conflicts('%clang@7:', when='+cuda ^cuda@10.0.130 target=ppc64le:') | ||||
|     conflicts('%clang@7.1:', when='+cuda ^cuda@:10.1.105 target=ppc64le:') | ||||
|     conflicts('%clang@8.1:', when='+cuda ^cuda@:10.2.89 target=ppc64le:') | ||||
|     conflicts('%clang@:5', when='+cuda ^cuda@11.0.2: target=ppc64le:') | ||||
|     conflicts('%clang@10:', when='+cuda ^cuda@:11.0.2 target=ppc64le:') | ||||
|     conflicts('%clang@11:', when='+cuda ^cuda@:11.1.0 target=ppc64le:') | ||||
|         # Intel is mostly relevant for x86_64 Linux, even though it also | ||||
|         # exists for Mac OS X. No information prior to CUDA 3.2 or Intel 11.1 | ||||
|         conflicts('%intel@:11.0', when='+cuda ^cuda@:3.1') | ||||
|         conflicts('%intel@:12.0', when='+cuda ^cuda@5.5:') | ||||
|         conflicts('%intel@:13.0', when='+cuda ^cuda@6.0:') | ||||
|         conflicts('%intel@:13.2', when='+cuda ^cuda@6.5:') | ||||
|         conflicts('%intel@:14.9', when='+cuda ^cuda@7:') | ||||
|         # Intel 15.x is compatible with CUDA 7 thru current CUDA | ||||
|         conflicts('%intel@16.0:', when='+cuda ^cuda@:8.0.43') | ||||
|         conflicts('%intel@17.0:', when='+cuda ^cuda@:8.0.60') | ||||
|         conflicts('%intel@18.0:', when='+cuda ^cuda@:9.9') | ||||
|         conflicts('%intel@19.0:', when='+cuda ^cuda@:10.0') | ||||
|         conflicts('%intel@19.1:', when='+cuda ^cuda@:10.1') | ||||
|         conflicts('%intel@19.2:', when='+cuda ^cuda@:11.1.0') | ||||
| 
 | ||||
|     # Intel is mostly relevant for x86_64 Linux, even though it also | ||||
|     # exists for Mac OS X. No information prior to CUDA 3.2 or Intel 11.1 | ||||
|     conflicts('%intel@:11.0', when='+cuda ^cuda@:3.1') | ||||
|     conflicts('%intel@:12.0', when='+cuda ^cuda@5.5:') | ||||
|     conflicts('%intel@:13.0', when='+cuda ^cuda@6.0:') | ||||
|     conflicts('%intel@:13.2', when='+cuda ^cuda@6.5:') | ||||
|     conflicts('%intel@:14.9', when='+cuda ^cuda@7:') | ||||
|     # Intel 15.x is compatible with CUDA 7 thru current CUDA | ||||
|     conflicts('%intel@16.0:', when='+cuda ^cuda@:8.0.43') | ||||
|     conflicts('%intel@17.0:', when='+cuda ^cuda@:8.0.60') | ||||
|     conflicts('%intel@18.0:', when='+cuda ^cuda@:9.9') | ||||
|     conflicts('%intel@19.0:', when='+cuda ^cuda@:10.0') | ||||
|     conflicts('%intel@19.1:', when='+cuda ^cuda@:10.1') | ||||
|     conflicts('%intel@19.2:', when='+cuda ^cuda@:11.1.0') | ||||
|         # XL is mostly relevant for ppc64le Linux | ||||
|         conflicts('%xl@:12,14:', when='+cuda ^cuda@:9.1') | ||||
|         conflicts('%xl@:12,14:15,17:', when='+cuda ^cuda@9.2') | ||||
|         conflicts('%xl@:12,17:', when='+cuda ^cuda@:11.1.0') | ||||
| 
 | ||||
|     # XL is mostly relevant for ppc64le Linux | ||||
|     conflicts('%xl@:12,14:', when='+cuda ^cuda@:9.1') | ||||
|     conflicts('%xl@:12,14:15,17:', when='+cuda ^cuda@9.2') | ||||
|     conflicts('%xl@:12,17:', when='+cuda ^cuda@:11.1.0') | ||||
| 
 | ||||
|     # Darwin. | ||||
|     # TODO: add missing conflicts for %apple-clang cuda@:10 | ||||
|     conflicts('platform=darwin', when='+cuda ^cuda@11.0.2: ') | ||||
|         # Darwin. | ||||
|         # TODO: add missing conflicts for %apple-clang cuda@:10 | ||||
|         conflicts('platform=darwin', when='+cuda ^cuda@11.0.2: ') | ||||
| 
 | ||||
|     # Make sure cuda_arch can not be used without +cuda | ||||
|     for value in cuda_arch_values: | ||||
|   | ||||
| @@ -562,7 +562,9 @@ def variant( | ||||
|         values=None, | ||||
|         multi=None, | ||||
|         validator=None, | ||||
|         when=None): | ||||
|         when=None, | ||||
|         sticky=False | ||||
| ): | ||||
|     """Define a variant for the package. Packager can specify a default | ||||
|     value as well as a text description. | ||||
| 
 | ||||
| @@ -583,7 +585,8 @@ def variant( | ||||
|             doesn't meet the additional constraints | ||||
|         when (spack.spec.Spec, bool): optional condition on which the | ||||
|             variant applies | ||||
| 
 | ||||
|         sticky (bool): the variant should not be changed by the concretizer to | ||||
|             find a valid concrete spec. | ||||
|     Raises: | ||||
|         DirectiveError: if arguments passed to the directive are invalid | ||||
|     """ | ||||
| @@ -657,7 +660,7 @@ def _execute_variant(pkg): | ||||
|             when_specs += orig_when | ||||
| 
 | ||||
|         pkg.variants[name] = (spack.variant.Variant( | ||||
|             name, default, description, values, multi, validator | ||||
|             name, default, description, values, multi, validator, sticky | ||||
|         ), when_specs) | ||||
|     return _execute_variant | ||||
| 
 | ||||
|   | ||||
| @@ -852,6 +852,9 @@ def pkg_rules(self, pkg, tests): | ||||
|             for value in sorted(values): | ||||
|                 self.gen.fact(fn.variant_possible_value(pkg.name, name, value)) | ||||
| 
 | ||||
|             if variant.sticky: | ||||
|                 self.gen.fact(fn.variant_sticky(pkg.name, name)) | ||||
| 
 | ||||
|             self.gen.newline() | ||||
| 
 | ||||
|         # conflicts | ||||
|   | ||||
| @@ -402,6 +402,14 @@ variant(Package, Variant) :- variant_condition(ID, Package, Variant), | ||||
|    build(Package), | ||||
|    error("Unsatisfied conditional variants cannot take on a variant value"). | ||||
|  | ||||
| % if a variant is sticky and not set its value is the default value | ||||
| variant_value(Package, Variant, Value) :- | ||||
|   variant(Package, Variant), | ||||
|   not variant_set(Package, Variant), | ||||
|   variant_sticky(Package, Variant), | ||||
|   variant_default_value(Package, Variant, Value), | ||||
|   build(Package). | ||||
|  | ||||
| % one variant value for single-valued variants. | ||||
| 1 { | ||||
|   variant_value(Package, Variant, Value) | ||||
| @@ -523,6 +531,7 @@ variant_single_value(Package, "dev_path") | ||||
| % spec or some package sets it, and without this, clingo will give | ||||
| % warnings like 'info: atom does not occur in any rule head'. | ||||
| #defined variant/2. | ||||
| #defined variant_sticky/2. | ||||
| #defined variant_set/3. | ||||
| #defined variant_condition/3. | ||||
| #defined variant_single_value/2. | ||||
|   | ||||
| @@ -1357,3 +1357,21 @@ def test_concrete_specs_are_not_modified_on_reuse( | ||||
|         s = spack.spec.Spec(spec_str).concretized(reuse=True) | ||||
|         assert s.package.installed is expect_installed | ||||
|         assert s.satisfies(spec_str, strict=True) | ||||
| 
 | ||||
|     @pytest.mark.regression('26721,19736') | ||||
|     def test_sticky_variant_in_package(self): | ||||
|         if spack.config.get('config:concretizer') == 'original': | ||||
|             pytest.skip('Original concretizer cannot use sticky variants') | ||||
| 
 | ||||
|         # Here we test that a sticky variant cannot be changed from its default value | ||||
|         # by the ASP solver if not set explicitly. The package used in the test needs | ||||
|         # to have +allow-gcc set to be concretized with %gcc and clingo is not allowed | ||||
|         # to change the default ~allow-gcc | ||||
|         with pytest.raises(spack.error.SpackError): | ||||
|             spack.spec.Spec('sticky-variant %gcc').concretized() | ||||
| 
 | ||||
|         s = spack.spec.Spec('sticky-variant+allow-gcc %gcc').concretized() | ||||
|         assert s.satisfies('%gcc') and s.satisfies('+allow-gcc') | ||||
| 
 | ||||
|         s = spack.spec.Spec('sticky-variant %clang').concretized() | ||||
|         assert s.satisfies('%clang') and s.satisfies('~allow-gcc') | ||||
|   | ||||
| @@ -416,3 +416,13 @@ def test_multivalued_variants_are_lower_priority_than_providers(self): | ||||
|         ): | ||||
|             s = Spec('somevirtual').concretized() | ||||
|             assert s.name == 'some-virtual-preferred' | ||||
| 
 | ||||
|     @pytest.mark.regression('26721,19736') | ||||
|     def test_sticky_variant_accounts_for_packages_yaml(self): | ||||
|         with spack.config.override( | ||||
|                 'packages:sticky-variant', { | ||||
|                     'variants': '+allow-gcc' | ||||
|                 } | ||||
|         ): | ||||
|             s = Spec('sticky-variant %gcc').concretized() | ||||
|             assert s.satisfies('%gcc') and s.satisfies('+allow-gcc') | ||||
|   | ||||
| @@ -37,7 +37,9 @@ def __init__( | ||||
|             description, | ||||
|             values=(True, False), | ||||
|             multi=False, | ||||
|             validator=None): | ||||
|             validator=None, | ||||
|             sticky=False | ||||
|     ): | ||||
|         """Initialize a package variant. | ||||
| 
 | ||||
|         Args: | ||||
| @@ -51,6 +53,8 @@ def __init__( | ||||
|             multi (bool): whether multiple CSV are allowed | ||||
|             validator (callable): optional callable used to enforce | ||||
|                 additional logic on the set of values being validated | ||||
|             sticky (bool): if true the variant is set to the default value at | ||||
|                 concretization time | ||||
|         """ | ||||
|         self.name = name | ||||
|         self.default = default | ||||
| @@ -83,6 +87,7 @@ def isa_type(v): | ||||
| 
 | ||||
|         self.multi = multi | ||||
|         self.group_validator = validator | ||||
|         self.sticky = sticky | ||||
| 
 | ||||
|     def validate_or_raise(self, vspec, pkg=None): | ||||
|         """Validate a variant spec against this package variant. Raises an | ||||
|   | ||||
		Reference in New Issue
	
	Block a user