Skip to content

Commit

Permalink
Add new array type option
Browse files Browse the repository at this point in the history
This exposes the already existing UserStringArrayOption class through
the meson_options.txt. The intention is to provide a way for projects to
take list/array type arguments and validate that all of the elements in
that array are valid without using complex looping constructrs.

The Mesa project would like to use this feature for passing lists of
drivers to be be built.
  • Loading branch information
dcbaker committed Oct 25, 2017
1 parent ddc2a1a commit 9866346
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 11 deletions.
5 changes: 4 additions & 1 deletion docs/markdown/Build-options.md
Expand Up @@ -16,9 +16,10 @@ Here is a simple option file.
option('someoption', type : 'string', value : 'optval', description : 'An option')
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'three'], value : 'three')
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one', 'two'])
```

This demonstrates the three basic option types and their usage. String
This demonstrates the four basic option types and their usage. String
option is just a free form string and a boolean option is,
unsurprisingly, true or false. The combo option can have any value
from the strings listed in argument `choices`. If `value` is not set,
Expand All @@ -29,6 +30,8 @@ name.

These options are accessed in Meson code with the `get_option` function.

The array type is new in 0.44.0

```meson
optval = get_option('opt_name')
```
Expand Down
17 changes: 17 additions & 0 deletions docs/markdown/snippets/option-array-type.md
@@ -0,0 +1,17 @@
# An array type for user options

Previously to have an option that took more than one value a string value would
have to be created and split, but validating this was difficult. A new array type
has been added to the meson_options.txt for this case. It works like a 'combo', but
allows more than one option to be passed. When used on the command line (with -D),
values are passed as a comma separated list.

```meson
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : 'one')
```

These can be overwritten on the command line,

```meson
meson _build -Darray_opt=two,three
```
33 changes: 23 additions & 10 deletions mesonbuild/coredata.py
Expand Up @@ -139,24 +139,37 @@ def validate_value(self, value):
class UserStringArrayOption(UserOption):
def __init__(self, name, description, value, **kwargs):
super().__init__(name, description, kwargs.get('choices', []))
self.set_value(value)

def validate(self, value):
if isinstance(value, str):
if not value.startswith('['):
raise MesonException('Valuestring does not define an array: ' + value)
newvalue = ast.literal_eval(value)
self.set_value(value, user_input=False)

def validate(self, value, user_input):
# User input is for options defined on the command line (via -D
# options). Users should put their input in as a comma separated
# string, but for defining options in meson_options.txt the format
# should match that of a combo
if not user_input:
if isinstance(value, str):
if not value.startswith('['):
raise MesonException('Valuestring does not define an array: ' + value)
newvalue = ast.literal_eval(value)
else:
newvalue = value
else:
newvalue = value
assert isinstance(value, str)
newvalue = [v.strip() for v in value.split(',')]
if not isinstance(newvalue, list):
raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
for i in newvalue:
if not isinstance(i, str):
raise MesonException('String array element "{0}" is not a string.'.format(str(newvalue)))
if self.choices:
bad = [x for x in newvalue if x not in self.choices]
if bad:
raise MesonException('Options "{}" are not in allowed choices: "{}"'.format(
', '.join(bad), ', '.join(self.choices)))
return newvalue

def set_value(self, newvalue):
self.value = self.validate(newvalue)
def set_value(self, newvalue, user_input=True):
self.value = self.validate(newvalue, user_input)

def validate_value(self, value):
self.validate(value)
Expand Down
15 changes: 15 additions & 0 deletions mesonbuild/optinterpreter.py
Expand Up @@ -84,9 +84,24 @@ def ComboParser(name, description, kwargs):
raise OptionException('Combo choice elements must be strings.')
return coredata.UserComboOption(name, description, choices, kwargs.get('value', choices[0]))

def string_array_parser(name, description, kwargs):
if 'choices' not in kwargs:
raise OptionException('Array option missing "choices" keyword.')
choices = kwargs['choices']
if not isinstance(choices, list):
raise OptionException('Array choices must be an array.')
for i in choices:
if not isinstance(i, str):
raise OptionException('Array choice elements must be strings.')
value = kwargs.get('value', choices[0])
if not isinstance(value, list):
value = [value]
return coredata.UserStringArrayOption(name, description, value, choices=choices)

option_types = {'string': StringParser,
'boolean': BooleanParser,
'combo': ComboParser,
'array': string_array_parser,
}

class OptionInterpreter:
Expand Down
9 changes: 9 additions & 0 deletions test cases/common/47 options/meson.build
Expand Up @@ -12,6 +12,15 @@ if get_option('combo_opt') != 'combo'
error('Incorrect value to combo option.')
endif

if get_option('array_opt') != ['one', 'two']
message(get_option('array_opt'))
error('Incorrect value for array option (default >1 element)')
endif

if get_option('array_opt2') != ['one']
error('Incorrect value for array option (default 1 element)')
endif

# If the default changes, update test cases/unit/13 reconfigure
if get_option('b_lto') != false
error('Incorrect value in base option.')
Expand Down
2 changes: 2 additions & 0 deletions test cases/common/47 options/meson_options.txt
@@ -1,3 +1,5 @@
option('testoption', type : 'string', value : 'optval', description : 'An option to do something')
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'combo'], value : 'combo')
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one', 'two'])
option('array_opt2', type : 'array', choices : ['one', 'two', 'three'], value : 'one')

0 comments on commit 9866346

Please sign in to comment.