optinterpreter: Add deprecated kwarg

It can be either:
- boolean: the option is completely deprecated.
- list: some choices are deprecated.
- dict: some choices are deprecated and replaced by another.

Fixes: #7444
pull/9382/head
Xavier Claessens 3 years ago committed by Xavier Claessens
parent 953bbf5e19
commit 77ef437cc4
  1. 26
      docs/markdown/Build-options.md
  2. 30
      mesonbuild/coredata.py
  3. 4
      mesonbuild/optinterpreter.py
  4. 15
      test cases/common/245 deprecated option/meson.build
  5. 15
      test cases/common/245 deprecated option/meson_options.txt
  6. 29
      test cases/common/245 deprecated option/test.json

@ -123,6 +123,32 @@ only the few they don't want, if any.
This type is available since version 0.47.0 This type is available since version 0.47.0
## Deprecated options
Since *0.60.0*
Project options can be marked as deprecated and Meson will warn when user sets a
value to it. It is also possible to deprecate only some of the choices, and map
deprecated values to a new value.
```meson
# Option fully deprecated, it warns when any value is set.
option('o1', type: 'boolean', deprecated: true)
# One of the choices is deprecated, it warns only when 'a' is in the list of values.
option('o2', type: 'array', choices: ['a', 'b'], deprecated: ['a'])
# One of the choices is deprecated, it warns only when 'a' is in the list of values
# and replace it by 'c'.
option('o3', type: 'array', choices: ['a', 'b', 'c'], deprecated: {'a': 'c'})
# A boolean option has been replaced by a feature, old true/false values are remapped.
option('o4', type: 'feature', deprecated: {'true': 'enabled', 'false': 'disabled'})
# A feature option has been replaced by a boolean, enabled/disabled/auto values are remapped.
option('o5', type: 'boolean', deprecated: {'enabled': 'true', 'disabled': 'false', 'auto': 'false'})
```
## Using build options ## Using build options
```meson ```meson

@ -72,6 +72,10 @@ class UserOption(T.Generic[_T], HoldableObject):
if not isinstance(yielding, bool): if not isinstance(yielding, bool):
raise MesonException('Value of "yielding" must be a boolean.') raise MesonException('Value of "yielding" must be a boolean.')
self.yielding = yielding self.yielding = yielding
self.deprecated: T.Union[bool, T.Dict[str, str], T.List[str]] = False
def listify(self, value: T.Any) -> T.List[T.Any]:
return [value]
def printable_value(self) -> T.Union[str, int, bool, T.List[T.Union[str, int, bool]]]: def printable_value(self) -> T.Union[str, int, bool, T.List[T.Union[str, int, bool]]]:
assert isinstance(self.value, (str, int, bool, list)) assert isinstance(self.value, (str, int, bool, list))
@ -205,7 +209,7 @@ class UserArrayOption(UserOption[T.List[str]]):
self.allow_dups = allow_dups self.allow_dups = allow_dups
self.value = self.validate_value(value, user_input=user_input) self.value = self.validate_value(value, user_input=user_input)
def validate_value(self, value: T.Union[str, T.List[str]], user_input: bool = True) -> T.List[str]: def listify(self, value: T.Union[str, T.List[str]], user_input: bool = True) -> T.List[str]:
# User input is for options defined on the command line (via -D # User input is for options defined on the command line (via -D
# options). Users can put their input in as a comma separated # options). Users can put their input in as a comma separated
# string, but for defining options in meson_options.txt the format # string, but for defining options in meson_options.txt the format
@ -230,6 +234,10 @@ class UserArrayOption(UserOption[T.List[str]]):
newvalue = value newvalue = value
else: else:
raise MesonException(f'"{newvalue}" should be a string array, but it is not') raise MesonException(f'"{newvalue}" should be a string array, but it is not')
return newvalue
def validate_value(self, value: T.Union[str, T.List[str]], user_input: bool = True) -> T.List[str]:
newvalue = self.listify(value, user_input)
if not self.allow_dups and len(set(newvalue)) != len(newvalue): if not self.allow_dups and len(set(newvalue)) != len(newvalue):
msg = 'Duplicated values in array option is deprecated. ' \ msg = 'Duplicated values in array option is deprecated. ' \
@ -629,10 +637,28 @@ class CoreData:
value = self.sanitize_dir_option_value(prefix, key, value) value = self.sanitize_dir_option_value(prefix, key, value)
try: try:
self.options[key].set_value(value) opt = self.options[key]
except KeyError: except KeyError:
raise MesonException(f'Tried to set unknown builtin option {str(key)}') raise MesonException(f'Tried to set unknown builtin option {str(key)}')
if opt.deprecated is True:
mlog.deprecation(f'Option {key.name!r} is deprecated')
elif isinstance(opt.deprecated, list):
for v in opt.listify(value):
if v in opt.deprecated:
mlog.deprecation(f'Option {key.name!r} value {v!r} is deprecated')
elif isinstance(opt.deprecated, dict):
def replace(v):
newvalue = opt.deprecated.get(v)
if newvalue is not None:
mlog.deprecation(f'Option {key.name!r} value {v!r} is replaced by {newvalue!r}')
return newvalue
return v
newvalue = [replace(v) for v in opt.listify(value)]
value = ','.join(newvalue)
opt.set_value(value)
if key.name == 'buildtype': if key.name == 'buildtype':
self._set_others_from_buildtype(value) self._set_others_from_buildtype(value)
elif key.name in {'wrap_mode', 'force_fallback_for'}: elif key.name in {'wrap_mode', 'force_fallback_for'}:

@ -32,6 +32,7 @@ if T.TYPE_CHECKING:
'value': object, 'value': object,
'min': T.Optional[int], 'min': T.Optional[int],
'max': T.Optional[int], 'max': T.Optional[int],
'deprecated': T.Union[bool, T.Dict[str, str], T.List[str]],
}) })
ParserArgs = TypedDict('ParserArgs', { ParserArgs = TypedDict('ParserArgs', {
'yield': bool, 'yield': bool,
@ -167,6 +168,8 @@ class OptionInterpreter:
KwargInfo('value', object), KwargInfo('value', object),
KwargInfo('min', (int, type(None))), KwargInfo('min', (int, type(None))),
KwargInfo('max', (int, type(None))), KwargInfo('max', (int, type(None))),
KwargInfo('deprecated', (bool, ContainerTypeInfo(dict, str), ContainerTypeInfo(list, str)),
default=False, since='0.60.0')
) )
@typed_pos_args('option', str) @typed_pos_args('option', str)
def func_option(self, args: T.Tuple[str], kwargs: 'FuncOptionArgs') -> None: def func_option(self, args: T.Tuple[str], kwargs: 'FuncOptionArgs') -> None:
@ -187,6 +190,7 @@ class OptionInterpreter:
known_parser_kwargs = {'value', 'choices', 'yield', 'min', 'max'} known_parser_kwargs = {'value', 'choices', 'yield', 'min', 'max'}
parser_kwargs = {k: v for k, v in kwargs.items() if k in known_parser_kwargs and v is not None} parser_kwargs = {k: v for k, v in kwargs.items() if k in known_parser_kwargs and v is not None}
opt = parser(description, T.cast('ParserArgs', parser_kwargs)) opt = parser(description, T.cast('ParserArgs', parser_kwargs))
opt.deprecated = kwargs['deprecated']
key = mesonlib.OptionKey(opt_name, self.subproject) key = mesonlib.OptionKey(opt_name, self.subproject)
if key in self.options: if key in self.options:

@ -0,0 +1,15 @@
project('deprecated options',
default_options: [
'o1=false',
'o2=a,b',
'o3=a,b',
'o4=true',
'o5=auto',
]
)
assert(get_option('o1') == false)
assert(get_option('o2') == ['a', 'b'])
assert(get_option('o3') == ['c', 'b'])
assert(get_option('o4').enabled())
assert(get_option('o5') == false)

@ -0,0 +1,15 @@
# Option fully deprecated, it warns when any value is set.
option('o1', type: 'boolean', deprecated: true)
# One of the choices is deprecated, it warns only when 'a' is in the list of values.
option('o2', type: 'array', choices: ['a', 'b'], deprecated: ['a'])
# One of the choices is deprecated, it warns only when 'a' is in the list of values
# and replace it by 'c'.
option('o3', type: 'array', choices: ['a', 'b', 'c'], deprecated: {'a': 'c'})
# A boolean option has been replaced by a feature, old true/false values are remapped.
option('o4', type: 'feature', deprecated: {'true': 'enabled', 'false': 'disabled'})
# A feature option has been replaced by a boolean, enabled/disabled/auto values are remapped.
option('o5', type: 'boolean', deprecated: {'enabled': 'true', 'disabled': 'false', 'auto': 'false'})

@ -0,0 +1,29 @@
{
"stdout": [
{
"line": ".*DEPRECATION: Option 'o1' is deprecated",
"match": "re",
"count": 1
},
{
"line": ".*DEPRECATION: Option 'o2' value 'a' is deprecated",
"match": "re",
"count": 1
},
{
"line": ".*DEPRECATION: Option 'o3' value 'a' is replaced by 'c'",
"match": "re",
"count": 1
},
{
"line": ".*DEPRECATION: Option 'o4' value 'true' is replaced by 'enabled'",
"match": "re",
"count": 1
},
{
"line": ".*DEPRECATION: Option 'o5' value 'auto' is replaced by 'false'",
"match": "re",
"count": 1
}
]
}
Loading…
Cancel
Save