blob: 22fddd14f5015b93778551aa1dd145662a8fb441 [file] [log] [blame]
# Copyright (C) 2018 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
# 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 <>.
# Authors:
# Jonathan Maw <>
filter - Extract a subset of files from another element
This filters another element by producing an output that is a subset of
the filtered element.
To specify the element to filter, specify it as the one and only build
dependency to filter. See :ref:`Dependencies <format_dependencies>`
for what dependencies are and how to specify them.
Dependencies aside from the filtered element may be specified, but
they must be runtime dependencies only. This can be useful to propagate
runtime dependencies forward from this filter element onto its reverse
When workspaces are opened, closed or reset on this element, or this
element is tracked, instead of erroring due to a lack of sources, this
element will transparently pass on the command to its sole build-dependency.
The default configuration and possible options are as such:
.. literalinclude:: ../../../buildstream/plugins/elements/filter.yaml
:language: yaml
from buildstream import Element, ElementError, Scope
class FilterElement(Element):
# pylint: disable=attribute-defined-outside-init
# The filter element's output is it's dependencies, so
# we must rebuild if the dependencies change even when
# not in strict build plans.
# This element ignores sources, so we should forbid them from being
# added, to reduce the potential for confusion
def configure(self, node):
self.node_validate(node, [
'include', 'exclude', 'include-orphans'
self.include = self.node_get_member(node, list, 'include')
self.exclude = self.node_get_member(node, list, 'exclude')
self.include_orphans = self.node_get_member(node, bool, 'include-orphans')
def preflight(self):
# Exactly one build-depend is permitted
build_deps = list(self.dependencies(Scope.BUILD, recurse=False))
if len(build_deps) != 1:
detail = "Full list of build-depends:\n"
deps_list = " \n".join([ for x in build_deps])
detail += deps_list
raise ElementError("{}: {} element must have exactly 1 build-dependency, actually have {}"
.format(self, type(self).__name__, len(build_deps)),
detail=detail, reason="filter-bdepend-wrong-count")
# That build-depend must not also be a runtime-depend
runtime_deps = list(self.dependencies(Scope.RUN, recurse=False))
if build_deps[0] in runtime_deps:
detail = "Full list of runtime depends:\n"
deps_list = " \n".join([ for x in runtime_deps])
detail += deps_list
raise ElementError("{}: {} element's build dependency must not also be a runtime dependency"
.format(self, type(self).__name__),
detail=detail, reason="filter-bdepend-also-rdepend")
def get_unique_key(self):
key = {
'include': sorted(self.include),
'exclude': sorted(self.exclude),
'orphans': self.include_orphans,
return key
def configure_sandbox(self, sandbox):
def stage(self, sandbox):
def assemble(self, sandbox):
with self.timed_activity("Staging artifact", silent_nested=True):
for dep in self.dependencies(Scope.BUILD):
dep.stage_artifact(sandbox, include=self.include,
exclude=self.exclude, orphans=self.include_orphans)
return ""
def _get_source_element(self):
# Filter elements act as proxies for their sole build-dependency
build_deps = list(self.dependencies(Scope.BUILD, recurse=False))
assert len(build_deps) == 1
output_elm = build_deps[0]._get_source_element()
return output_elm
def setup():
return FilterElement