diff options
author | Daniel Mensinger <daniel@mensinger-ka.de> | 2021-05-31 19:46:09 +0200 |
---|---|---|
committer | Dylan Baker <dylan@pnwbakers.com> | 2021-06-03 10:23:27 -0700 |
commit | 95b70bcb97afa9177645e4926afdf3792fb73eb5 (patch) | |
tree | dea7c5ec83a7b2a90b533f58d50ad88b8961bc8f /mesonbuild/dependencies/factory.py | |
parent | 201dc6422683858f9656c8b572530237c810feef (diff) | |
download | meson-95b70bcb97afa9177645e4926afdf3792fb73eb5.zip meson-95b70bcb97afa9177645e4926afdf3792fb73eb5.tar.gz meson-95b70bcb97afa9177645e4926afdf3792fb73eb5.tar.bz2 |
deps: Split dependencies.base
Split the Factory and dependency classes out
of the base.py script to improve maintainability.
Diffstat (limited to 'mesonbuild/dependencies/factory.py')
-rw-r--r-- | mesonbuild/dependencies/factory.py | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/mesonbuild/dependencies/factory.py b/mesonbuild/dependencies/factory.py new file mode 100644 index 0000000..760dba2 --- /dev/null +++ b/mesonbuild/dependencies/factory.py @@ -0,0 +1,125 @@ +# Copyright 2013-2021 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from .base import Dependency, ExternalDependency +from .base import DependencyException, DependencyMethods +from .base import process_method_kw +from .cmake import CMakeDependency +from .framework import ExtraFrameworkDependency +from .pkgconfig import PkgConfigDependency +from ..mesonlib import MachineChoice +import functools +import typing as T + +if T.TYPE_CHECKING: + from ..environment import Environment + from .base import DependencyType + from .configtool import ConfigToolDependency + FactoryType = T.TypeVar('FactoryType', bound=T.Callable[..., T.List[T.Callable[[], 'Dependency']]]) + +class DependencyFactory: + + """Factory to get dependencies from multiple sources. + + This class provides an initializer that takes a set of names and classes + for various kinds of dependencies. When the initialized object is called + it returns a list of callables return Dependency objects to try in order. + + :name: The name of the dependency. This will be passed as the name + parameter of the each dependency unless it is overridden on a per + type basis. + :methods: An ordered list of DependencyMethods. This is the order + dependencies will be returned in unless they are removed by the + _process_method function + :*_name: This will overwrite the name passed to the coresponding class. + For example, if the name is 'zlib', but cmake calls the dependency + 'Z', then using `cmake_name='Z'` will pass the name as 'Z' to cmake. + :*_class: A *type* or callable that creates a class, and has the + signature of an ExternalDependency + :system_class: If you pass DependencyMethods.SYSTEM in methods, you must + set this argument. + """ + + def __init__(self, name: str, methods: T.List[DependencyMethods], *, + extra_kwargs: T.Optional[T.Dict[str, T.Any]] = None, + pkgconfig_name: T.Optional[str] = None, + pkgconfig_class: 'T.Type[PkgConfigDependency]' = PkgConfigDependency, + cmake_name: T.Optional[str] = None, + cmake_class: 'T.Type[CMakeDependency]' = CMakeDependency, + configtool_class: 'T.Optional[T.Type[ConfigToolDependency]]' = None, + framework_name: T.Optional[str] = None, + framework_class: 'T.Type[ExtraFrameworkDependency]' = ExtraFrameworkDependency, + system_class: 'T.Type[ExternalDependency]' = ExternalDependency): + + if DependencyMethods.CONFIG_TOOL in methods and not configtool_class: + raise DependencyException('A configtool must have a custom class') + + self.extra_kwargs = extra_kwargs or {} + self.methods = methods + self.classes = { + # Just attach the correct name right now, either the generic name + # or the method specific name. + DependencyMethods.EXTRAFRAMEWORK: functools.partial(framework_class, framework_name or name), + DependencyMethods.PKGCONFIG: functools.partial(pkgconfig_class, pkgconfig_name or name), + DependencyMethods.CMAKE: functools.partial(cmake_class, cmake_name or name), + DependencyMethods.SYSTEM: functools.partial(system_class, name), + DependencyMethods.CONFIG_TOOL: None, + } + if configtool_class is not None: + self.classes[DependencyMethods.CONFIG_TOOL] = functools.partial(configtool_class, name) + + @staticmethod + def _process_method(method: DependencyMethods, env: 'Environment', for_machine: MachineChoice) -> bool: + """Report whether a method is valid or not. + + If the method is valid, return true, otherwise return false. This is + used in a list comprehension to filter methods that are not possible. + + By default this only remove EXTRAFRAMEWORK dependencies for non-mac platforms. + """ + # Extra frameworks are only valid for macOS and other apple products + if (method is DependencyMethods.EXTRAFRAMEWORK and + not env.machines[for_machine].is_darwin()): + return False + return True + + def __call__(self, env: 'Environment', for_machine: MachineChoice, + kwargs: T.Dict[str, T.Any]) -> T.List['DependencyType']: + """Return a list of Dependencies with the arguments already attached.""" + methods = process_method_kw(self.methods, kwargs) + nwargs = self.extra_kwargs.copy() + nwargs.update(kwargs) + + return [functools.partial(self.classes[m], env, nwargs) for m in methods + if self._process_method(m, env, for_machine)] + + +def factory_methods(methods: T.Set[DependencyMethods]) -> T.Callable[['FactoryType'], 'FactoryType']: + """Decorator for handling methods for dependency factory functions. + + This helps to make factory functions self documenting + >>> @factory_methods([DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE]) + >>> def factory(env: Environment, for_machine: MachineChoice, kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List[T.Callable[[], 'Dependency']]: + >>> pass + """ + + def inner(func: 'FactoryType') -> 'FactoryType': + + @functools.wraps(func) + def wrapped(env: 'Environment', for_machine: MachineChoice, kwargs: T.Dict[str, T.Any]) -> T.List[T.Callable[[], 'Dependency']]: + return func(env, for_machine, kwargs, process_method_kw(methods, kwargs)) + + return T.cast('FactoryType', wrapped) + + return inner |