Coverage for src/mafw/devtools/toolchain/filtering.py: 100%
26 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-26 09:13 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-26 09:13 +0000
1# Copyright 2026 European Union
2# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
3# SPDX-License-Identifier: EUPL-1.2
4"""
5Tool filtering utility for the toolchain command group.
7This module provides :func:`resolve_tools`, a shared function used by all CLI
8subcommands to determine which tools to process based on the ``--include-host``,
9``-i``/``--include``, and ``-e``/``--exclude`` options. It enforces mutual
10exclusivity between include and exclude filters, warns on unrecognized tool
11names, and preserves the original registration order from the registry.
12"""
14from __future__ import annotations
16import warnings
18from mafw.devtools import DevtoolsError
19from mafw.devtools.toolchain.base import ToolChainTool
20from mafw.devtools.toolchain.registry import ToolRegistry
23def resolve_tools(
24 registry: ToolRegistry,
25 *,
26 include: tuple[str, ...] = (),
27 exclude: tuple[str, ...] = (),
28 include_host: bool = False,
29) -> list[ToolChainTool]:
30 """Filter the registry based on CLI options.
32 The filtering pipeline proceeds in order:
34 1. Reject mutually exclusive ``include`` and ``exclude`` arguments.
35 2. Start with all tools from the registry (preserving insertion order).
36 3. If *include_host* is ``False``, remove tools with category ``"host"``.
37 4. If *include* is non-empty, keep only tools whose name is in the set
38 (emit a warning for each unrecognized name).
39 5. If *exclude* is non-empty, remove tools whose name is in the set
40 (emit a warning for each unrecognized name).
42 :param registry: The central tool registry to query.
43 :param include: Tool names to include exclusively. Only tools whose
44 ``name`` matches one of these values will be returned.
45 :param exclude: Tool names to exclude. Tools whose ``name`` matches one
46 of these values will be removed from the result.
47 :param include_host: When ``False`` (the default), tools with
48 ``category="host"`` are excluded before any name-based filtering.
49 :return: A list of tools in their original registration order.
50 :raises DevtoolsError: If both *include* and *exclude* are non-empty
51 (mutual exclusivity violation).
52 """
53 # Step 1: Enforce mutual exclusivity of include and exclude.
54 if include and exclude:
55 raise DevtoolsError('--include and --exclude are mutually exclusive; specify one or the other, not both.')
57 # Step 2: Start with all registered tools.
58 tools = registry.all()
60 # Step 3: Filter out host tools unless explicitly included.
61 if not include_host:
62 tools = [t for t in tools if t.category != 'host']
64 # Step 4: Apply include filter (keep only named tools).
65 if include:
66 include_set = set(include)
67 # Gather the set of known tool names from the current (possibly host-filtered) list.
68 known_names = {t.name for t in tools}
69 for name in include_set:
70 if name not in known_names:
71 warnings.warn(
72 f'Unrecognized tool name in --include: {name!r}',
73 stacklevel=2,
74 )
75 tools = [t for t in tools if t.name in include_set]
77 # Step 5: Apply exclude filter (remove named tools).
78 if exclude:
79 exclude_set = set(exclude)
80 # Gather the set of known tool names from the current (possibly host-filtered) list.
81 known_names = {t.name for t in tools}
82 for name in exclude_set:
83 if name not in known_names:
84 warnings.warn(
85 f'Unrecognized tool name in --exclude: {name!r}',
86 stacklevel=2,
87 )
88 tools = [t for t in tools if t.name not in exclude_set]
90 return tools