"""Source registry and dispatch.""" from __future__ import annotations import logging from ..models import Item, VersionCheck from .base import Context, error from .blackmagic import BlackmagicSource from .generic import HtmlSource, JsonSource, ManualSource, RssSource from .github_releases import GithubSource from .websearch import WebSearchSource log = logging.getLogger(__name__) _SOURCES = { s.kind: s() for s in ( BlackmagicSource, GithubSource, HtmlSource, JsonSource, RssSource, WebSearchSource, ManualSource, ) } KINDS = sorted(_SOURCES) def check_item(item: Item, ctx: Context) -> VersionCheck: """Resolve the latest available version for one item. Never raises -- an adapter blowing up must not abort a 90-item scan.""" # An unconfirmed placeholder must not be searched on. A query built from # a guessed vendor returns a real, correct-looking version for the WRONG # product, and the team then acts on it. Silence is the safe answer until # somebody names the actual model. if not item.is_confirmed: return VersionCheck( item_id=item.id, status="unconfigured", detail=("Make/model not confirmed, so no version lookup is " "attempted -- a guessed vendor would return the wrong " "product's version. Set status: confirmed once you have " "filled in the real make and model."), ) kind = item.source_kind # Nothing to decide, so nothing worth looking up. if item.update_class == "do_not_touch": return VersionCheck( item_id=item.id, status="unconfigured", detail=("Marked do_not_touch, so no version is looked up -- this " "is a licensed contractor's to update, never ours. " "Tracked for visibility only."), ) # Vendor-pushed items update on someone else's schedule. A paid lookup # buys a version number nobody can act on, so skip it -- but keep free # sources (GitHub, the Blackmagic feed), which cost nothing and do at # least tell us a change landed. if item.update_class == "vendor_pushed" and kind == "websearch": return VersionCheck( item_id=item.id, status="unconfigured", detail=("Marked vendor_pushed, so the paid version lookup is " "skipped -- it updates on the supplier's schedule and " "there is no install decision to inform. Watch for " "breaking-change notices instead."), ) source = _SOURCES.get(kind) if source is None: return error(item, f"unknown source kind {kind!r}; known: {', '.join(KINDS)}") try: return source.check(item, ctx) except Exception as exc: # noqa: BLE001 - deliberate isolation boundary log.exception("source %s failed for %s", kind, item.id) return error(item, f"{type(exc).__name__}: {exc}")