mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
A module that dies on an unhandled exception carries no msg: the AnsiballZ wrapper returns only failed and exception, whose event holds the sole account of what went wrong. The aggregation defaulted to the literal string package install failed and discarded it, so an AUR fetch that threw in run 30713666732 reported nothing at all and took a full investigation to place. Walk msg, exception.event.msg, exception, module_stderr, stderr instead, and tag every result with the module that produced it. This applies to apt, dnf, pacman and every other module the plugin drives, not only to the AUR. The aur module fetches the RPC record and the snapshot tarball through bare open_url calls with no error handling, so one blip kills a deploy; distribution repositories need none of this because apt, dnf and pacman retry inside their own transport. Give the calls that reach an endpoint of their own a single shared policy. Only the AUR path is declared today; copr, ppa and build carry it against the day they are. Split the result along its responsibilities so no file passes 250 lines: calls.py holds the vocabulary, sources.py one builder per acquisition path, plan.py only the dispatcher, outcome.py the reporting and facts.py the fact shapes. The action plugin is left with executing modules. Tests follow the code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
"""Install plans for the package registry.
|
|
|
|
Turns a resolved :class:`~utils.packages.registry.PackageSpec` into the
|
|
ordered module calls that acquire it. Keeping this pure means every
|
|
acquisition path - distribution repository, AUR, COPR, PPA, source build -
|
|
is unit-testable without an Ansible connection; the action plugin only
|
|
executes what it is handed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from utils.packages.calls import (
|
|
STATE_ABSENT,
|
|
STATE_PRESENT,
|
|
ModuleCall,
|
|
package_call,
|
|
)
|
|
from utils.packages.schema import (
|
|
SOURCE_AUR,
|
|
SOURCE_BUILD,
|
|
SOURCE_COPR,
|
|
SOURCE_PPA,
|
|
PackageSpec,
|
|
)
|
|
from utils.packages.sources import aur_calls, build_calls, repository_calls
|
|
|
|
|
|
def build_plan(spec: PackageSpec, state: str) -> list[ModuleCall]:
|
|
"""Return the ordered module calls that bring ``spec`` into ``state``."""
|
|
names = list(spec.names)
|
|
if not names:
|
|
return []
|
|
|
|
if state == STATE_ABSENT:
|
|
return [package_call(names, STATE_ABSENT)]
|
|
|
|
if spec.source == SOURCE_AUR:
|
|
return aur_calls(names)
|
|
|
|
if spec.source == SOURCE_BUILD:
|
|
if not spec.build:
|
|
raise ValueError("source 'build' requires a 'build' block")
|
|
return build_calls(spec.build)
|
|
|
|
if spec.source in (SOURCE_COPR, SOURCE_PPA) and not spec.repo:
|
|
raise ValueError(f"source '{spec.source}' requires a 'repo' block")
|
|
|
|
if spec.repo:
|
|
return repository_calls(spec.repo, names)
|
|
return [package_call(names, STATE_PRESENT)]
|