from __future__ import annotations from collections.abc import Iterable from pathlib import Path from vuln_scan.core.models import Ecosystem from vuln_scan.ecosystems.base import EcosystemHandler class EcosystemRegistry: """ Registry that manages ecosystem handlers. Supports: - lookup by ecosystem (O(1)) - lookup by manifest (exact + glob) """ def __init__(self, handlers: Iterable[EcosystemHandler]): handlers = tuple(handlers) if not handlers: raise ValueError("EcosystemRegistry requires at least one handler") self._handlers = handlers by_ecosystem: dict[Ecosystem, EcosystemHandler] = {} for handler in handlers: if handler.ecosystem in by_ecosystem: raise ValueError(f"Duplicate handler for ecosystem {handler.ecosystem}") by_ecosystem[handler.ecosystem] = handler self._by_ecosystem = by_ecosystem # --------------------------------------------------------- # Lookup methods # --------------------------------------------------------- def for_manifest(self, manifest_path: str | Path) -> EcosystemHandler | None: """ Return handler for a manifest file. Supports: - exact filename match - glob patterns """ filename = Path(manifest_path).name for handler in self._handlers: if handler.supports_manifest(filename): return handler return None def for_ecosystem(self, ecosystem: Ecosystem) -> EcosystemHandler | None: return self._by_ecosystem.get(ecosystem) # --------------------------------------------------------- @property def handlers(self) -> tuple[EcosystemHandler, ...]: return self._handlers