diff options
author | Dylan Baker <dylan@pnwbakers.com> | 2020-12-03 11:37:52 -0800 |
---|---|---|
committer | Dylan Baker <dylan@pnwbakers.com> | 2021-01-04 12:20:40 -0800 |
commit | f9b19e73a5b87a2f3c8506cf19cfd5bbc468e938 (patch) | |
tree | 62a822655f89133babd261a18adc40e3cb44a0fe /mesonbuild/coredata.py | |
parent | fe973d9fc45581f20fefc41fc0b8eb0066c0129d (diff) | |
download | meson-f9b19e73a5b87a2f3c8506cf19cfd5bbc468e938.zip meson-f9b19e73a5b87a2f3c8506cf19cfd5bbc468e938.tar.gz meson-f9b19e73a5b87a2f3c8506cf19cfd5bbc468e938.tar.bz2 |
move OptionKey to mesonlib
There's starting to be a lot of things including coredata that coredata
needs to itself include. putting it in mesonlib makes more sense
Diffstat (limited to 'mesonbuild/coredata.py')
-rw-r--r-- | mesonbuild/coredata.py | 198 |
1 files changed, 2 insertions, 196 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 97f5fff..f09c398 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -20,7 +20,8 @@ from pathlib import PurePath from collections import OrderedDict, defaultdict from .mesonlib import ( MesonException, EnvironmentException, MachineChoice, PerMachine, - default_libdir, default_libexecdir, default_prefix, split_args + default_libdir, default_libexecdir, default_prefix, split_args, + OptionKey, ) from .wrap import WrapMode import ast @@ -49,201 +50,6 @@ default_yielding = False _T = T.TypeVar('_T') -class OptionType(enum.Enum): - - """Enum used to specify what kind of argument a thing is.""" - - BUILTIN = 0 - BASE = 1 - COMPILER = 2 - PROJECT = 3 - BACKEND = 4 - - -def classify_argument(key: 'OptionKey') -> OptionType: - """Classify arguments into groups so we know which dict to assign them to.""" - - from .compilers import base_options - all_builtins = set(BUILTIN_OPTIONS) | set(BUILTIN_OPTIONS_PER_MACHINE) | set(builtin_dir_noprefix_options) - - if key.name in base_options: - assert key.machine is MachineChoice.HOST, str(key) - return OptionType.BASE - elif key.lang is not None: - return OptionType.COMPILER - elif key.name in all_builtins: - return OptionType.BUILTIN - elif key.name.startswith('backend_'): - assert key.machine is MachineChoice.HOST, str(key) - return OptionType.BACKEND - else: - assert key.machine is MachineChoice.HOST, str(key) - return OptionType.PROJECT - - -class OptionKey: - - """Represents an option key in the various option dictionaries. - - This provides a flexible, powerful way to map option names from their - external form (things like subproject:build.option) to something that - internally easier to reason about and produce. - """ - - __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'type'] - - name: str - subproject: str - machine: MachineChoice - lang: T.Optional[str] - _hash: int - type: OptionType - - def __init__(self, name: str, subproject: str = '', - machine: MachineChoice = MachineChoice.HOST, - lang: T.Optional[str] = None, _type: T.Optional[OptionType] = None): - # the _type option to the constructor is kinda private. We want to be - # able tos ave the state and avoid the lookup function when - # pickling/unpickling, but we need to be able to calculate it when - # constructing a new OptionKey - object.__setattr__(self, 'name', name) - object.__setattr__(self, 'subproject', subproject) - object.__setattr__(self, 'machine', machine) - object.__setattr__(self, 'lang', lang) - object.__setattr__(self, '_hash', hash((name, subproject, machine, lang))) - if _type is None: - _type = classify_argument(self) - object.__setattr__(self, 'type', _type) - - def __setattr__(self, key: str, value: T.Any) -> None: - raise AttributeError('OptionKey instances do not support mutation.') - - def __getstate__(self) -> T.Dict[str, T.Any]: - return { - 'name': self.name, - 'subproject': self.subproject, - 'machine': self.machine, - 'lang': self.lang, - '_type': self.type, - } - - def __setstate__(self, state: T.Dict[str, T.Any]) -> None: - """De-serialize the state of a pickle. - - This is very clever. __init__ is not a constructor, it's an - initializer, therefore it's safe to call more than once. We create a - state in the custom __getstate__ method, which is valid to pass - unsplatted to the initializer. - """ - self.__init__(**state) - - def __hash__(self) -> int: - return self._hash - - def __eq__(self, other: object) -> bool: - if isinstance(other, OptionKey): - return ( - self.name == other.name and - self.subproject == other.subproject and - self.machine is other.machine and - self.lang == other.lang) - return NotImplemented - - def __str__(self) -> str: - out = self.name - if self.lang: - out = f'{self.lang}_{out}' - if self.machine is MachineChoice.BUILD: - out = f'build.{out}' - if self.subproject: - out = f'{self.subproject}:{out}' - return out - - def __repr__(self) -> str: - return f'OptionKey({repr(self.name)}, {repr(self.subproject)}, {repr(self.machine)}, {repr(self.lang)})' - - @classmethod - def from_string(cls, raw: str) -> 'OptionKey': - """Parse the raw command line format into a three part tuple. - - This takes strings like `mysubproject:build.myoption` and Creates an - OptionKey out of them. - """ - - try: - subproject, raw2 = raw.split(':') - except ValueError: - subproject, raw2 = '', raw - - if raw2.startswith('build.'): - raw3 = raw2.lstrip('build.') - for_machine = MachineChoice.BUILD - else: - raw3 = raw2 - for_machine = MachineChoice.HOST - - from .compilers import all_languages - if any(raw3.startswith(f'{l}_') for l in all_languages): - lang, opt = raw3.split('_', 1) - else: - lang, opt = None, raw3 - assert ':' not in opt - assert 'build.' not in opt - - return cls(opt, subproject, for_machine, lang) - - def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = None, - machine: T.Optional[MachineChoice] = None, lang: T.Optional[str] = '') -> 'OptionKey': - """Create a new copy of this key, but with alterted members. - - For example: - >>> a = OptionKey('foo', '', MachineChoice.Host) - >>> b = OptionKey('foo', 'bar', MachineChoice.Host) - >>> b == a.evolve(subproject='bar') - True - """ - # We have to be a little clever with lang here, because lang is valid - # as None, for non-compiler options - return OptionKey( - name if name is not None else self.name, - subproject if subproject is not None else self.subproject, - machine if machine is not None else self.machine, - lang if lang != '' else self.lang, - ) - - def as_root(self) -> 'OptionKey': - """Convenience method for key.evolve(subproject='').""" - return self.evolve(subproject='') - - def as_build(self) -> 'OptionKey': - """Convenience method for key.evolve(machine=MachinceChoice.BUILD).""" - return self.evolve(machine=MachineChoice.BUILD) - - def as_host(self) -> 'OptionKey': - """Convenience method for key.evolve(machine=MachinceChoice.HOST).""" - return self.evolve(machine=MachineChoice.HOST) - - def is_backend(self) -> bool: - """Convenience method to check if this is a backend option.""" - return self.type is OptionType.BACKEND - - def is_builtin(self) -> bool: - """Convenience method to check if this is a builtin option.""" - return self.type is OptionType.BUILTIN - - def is_compiler(self) -> bool: - """Convenience method to check if this is a builtin option.""" - return self.type is OptionType.COMPILER - - def is_project(self) -> bool: - """Convenience method to check if this is a project option.""" - return self.type is OptionType.PROJECT - - def is_base(self) -> bool: - """Convenience method to check if this is a base option.""" - return self.type is OptionType.BASE - - class MesonVersionMismatchException(MesonException): '''Build directory generated with Meson version is incompatible with current version''' def __init__(self, old_version: str, current_version: str) -> None: |