diff options
-rw-r--r-- | lib/spack/spack/spec.py | 45 | ||||
-rw-r--r-- | lib/spack/spack/test/spec_semantics.py | 28 | ||||
-rw-r--r-- | lib/spack/spack/variant.py | 16 | ||||
-rw-r--r-- | var/spack/repos/builtin.mock/packages/a/package.py | 2 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/wget/package.py | 10 |
5 files changed, 59 insertions, 42 deletions
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 0cf392a7ce..399f58461f 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -1828,6 +1828,18 @@ class Spec(object): # evaluate when specs to figure out constraints on the dependency. dep = None for when_spec, dep_spec in conditions.items(): + # If self was concrete it would have changed the variants in + # when_spec automatically. As here we are for sure during the + # concretization process, self is not concrete and we must change + # the variants in when_spec on our own to avoid using a + # MultiValuedVariant whe it is instead a SingleValuedVariant + try: + substitute_single_valued_variants(when_spec) + except SpecError as e: + msg = 'evaluating a `when=` statement gives ' + e.message + e.message = msg + raise + sat = self.satisfies(when_spec, strict=True) if sat: if dep is None: @@ -2064,18 +2076,7 @@ class Spec(object): if not_existing: raise UnknownVariantError(spec.name, not_existing) - for name, v in [(x, y) for (x, y) in spec.variants.items()]: - # When parsing a spec every variant of the form - # 'foo=value' will be interpreted by default as a - # multi-valued variant. During validation of the - # variants we use the information in the package - # to turn any variant that needs it to a single-valued - # variant. - pkg_variant = pkg_variants[name] - pkg_variant.validate_or_raise(v, pkg_cls) - spec.variants.substitute( - pkg_variant.make_variant(v._original_value) - ) + substitute_single_valued_variants(spec) def constrain(self, other, deps=True): """Merge the constraints of other with self. @@ -2290,25 +2291,19 @@ class Spec(object): # to substitute every multi-valued variant that needs it with a # single-valued variant. if self.concrete: - for name, v in [(x, y) for (x, y) in other.variants.items()]: + try: # When parsing a spec every variant of the form # 'foo=value' will be interpreted by default as a # multi-valued variant. During validation of the # variants we use the information in the package # to turn any variant that needs it to a single-valued # variant. - pkg_cls = type(other.package) - try: - pkg_variant = other.package.variants[name] - pkg_variant.validate_or_raise(v, pkg_cls) - except (SpecError, KeyError): - # Catch the two things that could go wrong above: - # 1. name is not a valid variant (KeyError) - # 2. the variant is not validated (SpecError) - return False - other.variants.substitute( - pkg_variant.make_variant(v._original_value) - ) + substitute_single_valued_variants(other) + except (SpecError, KeyError): + # Catch the two things that could go wrong above: + # 1. name is not a valid variant (KeyError) + # 2. the variant is not validated (SpecError) + return False var_strict = strict if (not self.name) or (not other.name): diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py index 306a6ad98f..80a2f63bde 100644 --- a/lib/spack/spack/test/spec_semantics.py +++ b/lib/spack/spack/test/spec_semantics.py @@ -280,6 +280,18 @@ class TestSpecSematics(object): assert a.satisfies('foobar=bar') + # Assert that an autospec generated from a literal + # gives the right result for a single valued variant + assert 'foobar=bar' in a + assert 'foobar=baz' not in a + assert 'foobar=fee' not in a + + # ... and for a multi valued variant + assert 'foo=bar' in a + + # Check that conditional dependencies are treated correctly + assert '^b' in a + def test_unsatisfiable_multi_value_variant(self): # Semantics for a multi-valued variant is different @@ -337,22 +349,6 @@ class TestSpecSematics(object): with pytest.raises(MultipleValuesInExclusiveVariantError): a.concretize() - # FIXME: remove after having checked the correctness of the semantics - # check_unsatisfiable('multivalue_variant foo="bar,baz"', - # 'multivalue_variant foo="bar,baz,quux"', - # concrete=True) - # check_unsatisfiable('multivalue_variant foo="bar,baz"', - # 'multivalue_variant foo="bar,baz,quux"', - # concrete=True) - - # but succeed for abstract ones (b/c they COULD satisfy the - # constraint if constrained) - # check_satisfies('multivalue_variant foo="bar"', - # 'multivalue_variant foo="bar,baz"') - - # check_satisfies('multivalue_variant foo="bar,baz"', - # 'multivalue_variant foo="bar,baz,quux"') - def test_unsatisfiable_variant_types(self): # These should fail due to incompatible types check_unsatisfiable('multivalue_variant +foo', diff --git a/lib/spack/spack/variant.py b/lib/spack/spack/variant.py index 2d02ab1253..fe08e4529e 100644 --- a/lib/spack/spack/variant.py +++ b/lib/spack/spack/variant.py @@ -546,6 +546,22 @@ class VariantMap(lang.HashableMap): return string.getvalue() +def substitute_single_valued_variants(spec): + """Uses the information in `spec.package` to turn any variant that needs + it into a SingleValuedVariant. + + Args: + spec: spec on which to operate the substitution + """ + for name, v in spec.variants.items(): + pkg_cls = type(spec.package) + pkg_variant = spec.package.variants[name] + pkg_variant.validate_or_raise(v, pkg_cls) + spec.variants.substitute( + pkg_variant.make_variant(v._original_value) + ) + + class DuplicateVariantError(error.SpecError): """Raised when the same variant occurs in a spec twice.""" diff --git a/var/spack/repos/builtin.mock/packages/a/package.py b/var/spack/repos/builtin.mock/packages/a/package.py index b697f4d2a9..e39ad13bd1 100644 --- a/var/spack/repos/builtin.mock/packages/a/package.py +++ b/var/spack/repos/builtin.mock/packages/a/package.py @@ -49,6 +49,8 @@ class A(AutotoolsPackage): multi=False ) + depends_on('b', when='foobar=bar') + def with_or_without_fee(self, activated): if not activated: return '--no-fee' diff --git a/var/spack/repos/builtin/packages/wget/package.py b/var/spack/repos/builtin/packages/wget/package.py index 10b8c33d31..ff704ca37c 100644 --- a/var/spack/repos/builtin/packages/wget/package.py +++ b/var/spack/repos/builtin/packages/wget/package.py @@ -38,7 +38,15 @@ class Wget(Package): version('1.17', 'c4c4727766f24ac716936275014a0536') version('1.16', '293a37977c41b5522f781d3a3a078426') - depends_on("openssl") + variant( + 'ssl', + default='openssl', + values=('gnutls', 'openssl'), + description='Specify SSL backend' + ) + + depends_on('gnutls', when='ssl=gnutls') + depends_on('openssl', when='ssl=openssl') depends_on("perl@5.12.0:", type='build') def install(self, spec, prefix): |