Source code for mafw.devtools.toolchain.registry
# Copyright 2026 European Union
# Author: Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
# SPDX-License-Identifier: EUPL-1.2
"""
Central registry for ToolChainTool instances.
The :class:`ToolRegistry` maintains an ordered collection of all registered
development tools, enabling discovery and iteration by the CLI commands.
Tools are stored in insertion order and can be retrieved by name or filtered
by category.
"""
from __future__ import annotations
from mafw.devtools.toolchain.base import Category, ToolChainTool
[docs]
class ToolRegistry:
"""Central registry that maintains all registered ToolChainTool instances.
Tools are stored in insertion order and indexed by name for O(1) lookup.
Duplicate names are rejected to ensure each tool has a unique identifier
within the registry.
Usage::
registry = ToolRegistry()
registry.register(my_tool)
all_tools = registry.all()
project_tools = registry.filter_by_category('project')
specific = registry.get('ruff')
"""
def __init__(self) -> None:
# Ordered list preserving insertion order (Requirement 19.1).
self._tools: list[ToolChainTool] = []
# Name-indexed lookup for O(1) retrieval and duplicate detection.
self._by_name: dict[str, ToolChainTool] = {}
[docs]
def register(self, tool: ToolChainTool) -> None:
"""Add a tool to the registry.
The tool is appended to the internal list and indexed by name.
If a tool with the same name already exists, a :exc:`ValueError`
is raised and the registry state remains unchanged.
:param tool: The tool instance to register.
:raises ValueError: If a tool with the same name is already
registered.
"""
if tool.name in self._by_name:
raise ValueError(f'Duplicate tool name: {tool.name!r}')
self._tools.append(tool)
self._by_name[tool.name] = tool
[docs]
def all(self) -> list[ToolChainTool]:
"""Return all registered tools in insertion order.
:return: A new list containing all tools in the order they were
registered.
:rtype: list[toolchain.ToolChainTool]
"""
return list(self._tools)
[docs]
def filter_by_category(self, category: Category) -> list[ToolChainTool]:
"""Return tools matching the given category, preserving insertion order.
:param category: The category to filter by (``"host"`` or ``"project"``).
:return: A list of matching tools, or an empty list if none match.
:rtype: list[toolchain.ToolChainTool]
"""
return [t for t in self._tools if t.category == category]
[docs]
def get(self, name: str) -> ToolChainTool:
"""Retrieve a tool by its exact name (case-sensitive).
:param name: The tool name to look up.
:return: The matching :class:`.toolchain.ToolChainTool` instance.
:rtype: toolchain.ToolChainTool
:raises KeyError: If no tool with the given name is registered.
"""
if name not in self._by_name:
raise KeyError(f'Tool not found: {name!r}')
return self._by_name[name]