Source code for mafw.devtools.toolchain.filtering
# Copyright 2026 European Union
# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
# SPDX-License-Identifier: EUPL-1.2
"""
Tool filtering utility for the toolchain command group.
This module provides :func:`resolve_tools`, a shared function used by all CLI
subcommands to determine which tools to process based on the ``--include-host``,
``-i``/``--include``, and ``-e``/``--exclude`` options. It enforces mutual
exclusivity between include and exclude filters, warns on unrecognized tool
names, and preserves the original registration order from the registry.
"""
from __future__ import annotations
import warnings
from mafw.devtools import DevtoolsError
from mafw.devtools.toolchain.base import ToolChainTool
from mafw.devtools.toolchain.registry import ToolRegistry
[docs]
def resolve_tools(
registry: ToolRegistry,
*,
include: tuple[str, ...] = (),
exclude: tuple[str, ...] = (),
include_host: bool = False,
) -> list[ToolChainTool]:
"""Filter the registry based on CLI options.
The filtering pipeline proceeds in order:
1. Reject mutually exclusive ``include`` and ``exclude`` arguments.
2. Start with all tools from the registry (preserving insertion order).
3. If *include_host* is ``False``, remove tools with category ``"host"``.
4. If *include* is non-empty, keep only tools whose name is in the set
(emit a warning for each unrecognized name).
5. If *exclude* is non-empty, remove tools whose name is in the set
(emit a warning for each unrecognized name).
:param registry: The central tool registry to query.
:param include: Tool names to include exclusively. Only tools whose
``name`` matches one of these values will be returned.
:param exclude: Tool names to exclude. Tools whose ``name`` matches one
of these values will be removed from the result.
:param include_host: When ``False`` (the default), tools with
``category="host"`` are excluded before any name-based filtering.
:return: A list of tools in their original registration order.
:raises DevtoolsError: If both *include* and *exclude* are non-empty
(mutual exclusivity violation).
"""
# Step 1: Enforce mutual exclusivity of include and exclude.
if include and exclude:
raise DevtoolsError('--include and --exclude are mutually exclusive; specify one or the other, not both.')
# Step 2: Start with all registered tools.
tools = registry.all()
# Step 3: Filter out host tools unless explicitly included.
if not include_host:
tools = [t for t in tools if t.category != 'host']
# Step 4: Apply include filter (keep only named tools).
if include:
include_set = set(include)
# Gather the set of known tool names from the current (possibly host-filtered) list.
known_names = {t.name for t in tools}
for name in include_set:
if name not in known_names:
warnings.warn(
f'Unrecognized tool name in --include: {name!r}',
stacklevel=2,
)
tools = [t for t in tools if t.name in include_set]
# Step 5: Apply exclude filter (remove named tools).
if exclude:
exclude_set = set(exclude)
# Gather the set of known tool names from the current (possibly host-filtered) list.
known_names = {t.name for t in tools}
for name in exclude_set:
if name not in known_names:
warnings.warn(
f'Unrecognized tool name in --exclude: {name!r}',
stacklevel=2,
)
tools = [t for t in tools if t.name not in exclude_set]
return tools