'with_or_without' accepts bool variants

Fixes #4112

This commit extends the support of the AutotoolsPackage methods
`with_or_without` and `enable_or_disable` to bool-valued variants. It
also defines for those functions a convenience short-cut if the
activation parameter is the prefix of a spec (like in
`--with-{pkg}={prefix}`).

This commit also includes:

* Updates to viennarna and adios accordingly: they have been modified to
  use `enable_or_disable` and `with_or_without`
* Improved docstrings in `autotools.py`. Raise `KeyError` if name is
  not a variant.
This commit is contained in:
Massimiliano Culpo
2017-09-12 01:20:49 +02:00
committed by scheibelp
parent f502de4725
commit 32117c22de
5 changed files with 203 additions and 110 deletions

View File

@@ -291,49 +291,161 @@ def check(self):
self._if_make_target_execute('test')
self._if_make_target_execute('check')
def _activate_or_not(self, active, inactive, name, active_parameters=None):
def _activate_or_not(
self,
name,
activation_word,
deactivation_word,
activation_value=None
):
"""This function contains the current implementation details of
:py:meth:`~.AutotoolsPackage.with_or_without` and
:py:meth:`~.AutotoolsPackage.enable_or_disable`.
Args:
name (str): name of the variant that is being processed
activation_word (str): the default activation word ('with' in the
case of ``with_or_without``)
deactivation_word (str): the default deactivation word ('without'
in the case of ``with_or_without``)
activation_value (callable): callable that accepts a single
value. This value is either one of the allowed values for a
multi-valued variant or the name of a bool-valued variant.
Returns the parameter to be used when the value is activated.
The special value 'prefix' can also be assigned and will return
``spec[name].prefix`` as activation parameter.
Examples:
Given a package with:
.. code-block:: python
variant('foo', values=('x', 'y'), description='')
variant('bar', default=True, description='')
calling this function like:
.. code-block:: python
_activate_or_not(
'foo', 'with', 'without', activation_value='prefix'
)
_activate_or_not('bar', 'with', 'without')
will generate the following configuration options:
.. code-block:: console
--with-x=<prefix-to-x> --without-y --with-bar
for ``<spec-name> foo=x +bar``
Returns:
list of strings that corresponds to the activation/deactivation
of the variant that has been processed
Raises:
KeyError: if name is not among known variants
"""
spec = self.spec
args = []
if activation_value == 'prefix':
activation_value = lambda x: spec[x].prefix
# Defensively look that the name passed as argument is among
# variants
if name not in self.variants:
msg = '"{0}" is not a variant of "{1}"'
raise KeyError(msg.format(name, self.name))
# Create a list of pairs. Each pair includes a configuration
# option and whether or not that option is activated
if set(self.variants[name].values) == set((True, False)):
# BoolValuedVariant carry information about a single option.
# Nonetheless, for uniformity of treatment we'll package them
# in an iterable of one element.
condition = '+{name}'.format(name=name)
options = [(name, condition in spec)]
else:
condition = '{name}={value}'
options = [
(value, condition.format(name=name, value=value) in spec)
for value in self.variants[name].values
]
# For each allowed value in the list of values
for value in self.variants[name].values:
# Check if the value is active in the current spec
condition = '{name}={value}'.format(name=name, value=value)
activated = condition in spec
for option_value, activated in options:
# Search for an override in the package for this value
override_name = '{0}_or_{1}_{2}'.format(active, inactive, value)
override_name = '{0}_or_{1}_{2}'.format(
activation_word, deactivation_word, option_value
)
line_generator = getattr(self, override_name, None)
# If not available use a sensible default
if line_generator is None:
def _default_generator(is_activated):
if is_activated:
line = '--{0}-{1}'.format(active, value)
if active_parameters is not None and active_parameters(value): # NOQA=ignore=E501
line += '={0}'.format(active_parameters(value))
line = '--{0}-{1}'.format(
activation_word, option_value
)
if activation_value is not None and activation_value(option_value): # NOQA=ignore=E501
line += '={0}'.format(
activation_value(option_value)
)
return line
return '--{0}-{1}'.format(inactive, value)
return '--{0}-{1}'.format(deactivation_word, option_value)
line_generator = _default_generator
args.append(line_generator(activated))
return args
def with_or_without(self, name, active_parameters=None):
"""Inspects the multi-valued variant 'name' and returns the configure
arguments that activate / deactivate the selected feature.
def with_or_without(self, name, activation_value=None):
"""Inspects a variant and returns the arguments that activate
or deactivate the selected feature(s) for the configure options.
:param str name: name of a valid multi-valued variant
:param callable active_parameters: if present accepts a single value
and returns the parameter to be used leading to an entry of the
type '--with-{name}={parameter}
This function works on all type of variants. For bool-valued variants
it will return by default ``--with-{name}`` or ``--without-{name}``.
For other kinds of variants it will cycle over the allowed values and
return either ``--with-{value}`` or ``--without-{value}``.
If activation_value is given, then for each possible value of the
variant, the option ``--with-{value}=activation_value(value)`` or
``--without-{value}`` will be added depending on whether or not
``variant=value`` is in the spec.
Args:
name (str): name of a valid multi-valued variant
activation_value (callable): callable that accepts a single
value and returns the parameter to be used leading to an entry
of the type ``--with-{name}={parameter}``.
The special value 'prefix' can also be assigned and will return
``spec[name].prefix`` as activation parameter.
Returns:
list of arguments to configure
"""
return self._activate_or_not(name, 'with', 'without', activation_value)
def enable_or_disable(self, name, activation_value=None):
"""Same as :py:meth:`~.AutotoolsPackage.with_or_without` but substitute
``with`` with ``enable`` and ``without`` with ``disable``.
Args:
name (str): name of a valid multi-valued variant
activation_value (callable): if present accepts a single value
and returns the parameter to be used leading to an entry of the
type ``--enable-{name}={parameter}``
The special value 'prefix' can also be assigned and will return
``spec[name].prefix`` as activation parameter.
Returns:
list of arguments to configure
"""
return self._activate_or_not(
'with', 'without', name, active_parameters
)
def enable_or_disable(self, name, active_parameters=None):
"""Inspects the multi-valued variant 'name' and returns the configure
arguments that activate / deactivate the selected feature.
"""
return self._activate_or_not(
'enable', 'disable', name, active_parameters
name, 'enable', 'disable', activation_value
)
run_after('install')(PackageBase._run_default_install_time_test_callbacks)

View File

@@ -53,20 +53,23 @@ def test_with_or_without(self):
pkg = spack.repo.get(s)
# Called without parameters
l = pkg.with_or_without('foo')
assert '--with-bar' in l
assert '--without-baz' in l
assert '--no-fee' in l
options = pkg.with_or_without('foo')
assert '--with-bar' in options
assert '--without-baz' in options
assert '--no-fee' in options
def activate(value):
return 'something'
l = pkg.with_or_without('foo', active_parameters=activate)
assert '--with-bar=something' in l
assert '--without-baz' in l
assert '--no-fee' in l
options = pkg.with_or_without('foo', activation_value=activate)
assert '--with-bar=something' in options
assert '--without-baz' in options
assert '--no-fee' in options
l = pkg.enable_or_disable('foo')
assert '--enable-bar' in l
assert '--disable-baz' in l
assert '--disable-fee' in l
options = pkg.enable_or_disable('foo')
assert '--enable-bar' in options
assert '--disable-baz' in options
assert '--disable-fee' in options
options = pkg.with_or_without('bvv')
assert '--with-bvv' in options