blob: b96732e4a0b145d035ce38277195ef9ce5caf612 [file] [log] [blame]
#
# Copyright (C) 2019 Codethink Limited
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
#
# Authors:
# Valentin David <valentin.david@codethink.co.uk>
"""
Dependency Loader
=================
A dependency loader can extract extra dependencies from an element
configuration. In this case, An :class:`Element
<buildstream.element.Element>` will define a class member
`DEPENDENCY_LOADER` to a class implementing :class:`DependencyLoader
<buildstream.dependency_loader.DependencyLoader>`.
This :class:`DependencyLoader
<buildstream.dependency_loader.DependencyLoader>` will provide through
implementation of :func:`DependencyLoader.get_dependencies
<buildstream.dependency_loader.DependencyLoader.get_dependencies>` a
list of :class:`Dependency
<buildstream.dependency_loader.Dependency>`.
Class Reference
---------------
"""
import os
from collections.abc import Mapping
from . import _yaml
from .plugin import Plugin
from ._exceptions import LoadError, LoadErrorReason, ImplError
class Dependency():
"""Dependency()
A simple object describing a dependency
Args:
name (str): The element name
dep_type (str): The type of dependency, can be
Symbol.ALL, Symbol.BUILD, or Symbol.RUNTIME
junction (str): The element name of the junction, or None
provenance (Provenance): The YAML node provenance of where this
dependency was declared
"""
def __init__(self, name,
dep_type=None, junction=None, provenance=None):
self.name = name
assert dep_type in (None, 'build', 'runtime', 'all')
self.dep_type = dep_type
self.junction = junction
self.provenance = provenance
class DependencyLoader(Plugin):
"""DependencyLoader()
Base class for element dependency loaders.
"""
def __init__(self, name, context, project, default_conf):
super().__init__(name, context, project, None, "dependency_loader")
defaults = {}
try:
defaults = _yaml.load(default_conf, os.path.basename(default_conf))
except LoadError as e:
if e.reason != LoadErrorReason.MISSING_FILE:
raise e
elements = project.element_overrides
overrides = elements.get(self.get_kind())
if overrides:
_yaml.composite(defaults, overrides)
self.__defaults = defaults
def get_dependencies(self, node):
"""Return the list of extra dependencies given a configuration node
Args:
node (dict): The configuration node
Returns:
(list of Dependency): The extra dependencies found
This is an abstract method. Implementations of
DependencyLoader are required to implement this method.
"""
raise ImplError("DependencyLoader plugin for element '{kind}' does not implement get_dependencies()".format(
kind=self.get_kind()))
# _get_dependencies()
#
# Get dependencies given a raw config node
#
# Args:
# node (dict): The configuration node
#
# Returns:
# (list of Dependency): The extra dependencies found
#
# This method will call DependencyLoader.get_dependencies()
# after applying default configuration for the plugin. The
# defaults come from the corresponding element plugin.
def _get_dependencies(self, node):
default_config = _yaml.node_get(self.__defaults, Mapping, 'config', default_value={})
default_config = _yaml.node_chain_copy(default_config)
_yaml.composite(default_config, node)
return self.get_dependencies(default_config)