| # SPDX-License-Identifier: Apache-2.0 |
| # Copyright © 2021 Intel Corporation |
| |
| """Helpers for strict type checking.""" |
| |
| import typing as T |
| |
| from .. import compilers |
| from ..coredata import UserFeatureOption |
| from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo |
| from ..mesonlib import FileMode, MachineChoice |
| |
| |
| def _language_validator(l: T.List[str]) -> T.Optional[str]: |
| """Validate language keyword argument. |
| |
| Particularly for functions like `add_compiler()`, and `add_*_args()` |
| """ |
| diff = {a.lower() for a in l}.difference(compilers.all_languages) |
| if diff: |
| return f'unknown languages: {", ".join(diff)}' |
| return None |
| |
| |
| def _install_mode_validator(mode: T.List[T.Union[str, bool, int]]) -> T.Optional[str]: |
| """Validate the `install_mode` keyword argument. |
| |
| This is a rather odd thing, it's a scalar, or an array of 3 values in the form: |
| [(str | False), (str | int | False) = False, (str | int | False) = False] |
| Where the second and third arguments are not required, and are considered to |
| default to False. |
| """ |
| if not mode: |
| return None |
| if True in mode: |
| return 'can only be a string or false, not true' |
| if len(mode) > 3: |
| return 'may have at most 3 elements' |
| |
| perms = mode[0] |
| if not isinstance(perms, (str, bool)): |
| return 'permissions part must be a string or false' |
| |
| if isinstance(perms, str): |
| if not len(perms) == 9: |
| return (f'permissions string must be exactly 9 characters, got "{len(perms)}" ' |
| 'in the form rwxr-xr-x') |
| for i in [0, 3, 6]: |
| if perms[i] not in {'-', 'r'}: |
| return f'bit {i} must be "-" or "r", not {perms[i]}' |
| for i in [1, 4, 7]: |
| if perms[i] not in {'-', 'w'}: |
| return f'bit {i} must be "-" or "w", not {perms[i]}' |
| for i in [2, 5]: |
| if perms[i] not in {'-', 'x', 's', 'S'}: |
| return f'bit {i} must be "-", "s", "S", or "x", not {perms[i]}' |
| if perms[8] not in {'-', 'x', 't', 'T'}: |
| return f'bit 8 must be "-", "t", "T", or "x", not {perms[8]}' |
| |
| if len(mode) >= 2 and not isinstance(mode[1], (int, str, bool)): |
| return 'second componenent must be a string, number, or False if provided' |
| if len(mode) >= 3 and not isinstance(mode[2], (int, str, bool)): |
| return 'third componenent must be a string, number, or False if provided' |
| |
| return None |
| |
| |
| def _install_mode_convertor(mode: T.Optional[T.List[T.Union[str, bool, int]]]) -> FileMode: |
| """Convert the DSL form of the `install_mode` keyword arugment to `FileMode` |
| |
| This is not required, and if not required returns None |
| |
| TODO: It's not clear to me why this needs to be None and not just return an |
| emtpy FileMode. |
| """ |
| # this has already been validated by the validator |
| return FileMode(*[m if isinstance(m, str) else None for m in mode]) |
| |
| |
| def _lower_strlist(input: T.List[str]) -> T.List[str]: |
| """Lower a list of strings. |
| |
| mypy (but not pyright) gets confused about using a lambda as the convertor function |
| """ |
| return [i.lower() for i in input] |
| |
| |
| NATIVE_KW = KwargInfo( |
| 'native', bool, |
| default=False, |
| convertor=lambda n: MachineChoice.BUILD if n else MachineChoice.HOST) |
| |
| LANGUAGE_KW = KwargInfo( |
| 'language', ContainerTypeInfo(list, str, allow_empty=False), |
| listify=True, |
| required=True, |
| validator=_language_validator, |
| convertor=_lower_strlist) |
| |
| INSTALL_MODE_KW: KwargInfo[T.List[T.Union[str, bool, int]]] = KwargInfo( |
| 'install_mode', |
| ContainerTypeInfo(list, (str, bool, int)), |
| listify=True, |
| default=[], |
| validator=_install_mode_validator, |
| convertor=_install_mode_convertor, |
| ) |
| |
| REQUIRED_KW: KwargInfo[T.Union[bool, UserFeatureOption]] = KwargInfo( |
| 'required', |
| (bool, UserFeatureOption), |
| default=True, |
| # TODO: extract_required_kwarg could be converted to a convertor |
| ) |