utils/env/handlers π§©ΒΆ
Per-variable mapping logic for the .env generator.
For the packageβs overall role see README.md.
For general README conventions see documentation.md.
Purpose π―ΒΆ
Each module in this directory owns exactly one variable, or one tightly-coupled group resolved by a single helper call.
The orchestrator in builder.py iterates the registry in init.py and calls each handlerβs apply(eb, ctx) in order.
File Naming π·οΈΒΆ
A handler module name MUST match the lowercase of the variable it owns:
INFINITO_CONTAINER->infinito/container.pyINFINITO_GHCR_MIRROR_PREFIX->infinito/ghcr_mirror_prefix.py
The
infinito_prefix in the filename MUST be present iff the owned key carries theINFINITO_prefix.Aggregate handlers (one helper call resolves several keys at once) MUST take the singular topic name without a key suffix. Example:
infinito/inventory.pyresolvesINFINITO_INVENTORY_DIR,INFINITO_INVENTORY_FILE, andINFINITO_INVENTORY_HOST_VARS_FILEfrom onescripts/inventory/resolve.shinvocation.The trivial static passthroughs live in two collector files:
passthrough.py(always emitted) andgha_passthrough.py(emitted only whenctx.on_ghais true).
Module Shape πΒΆ
Every handler module MUST expose the same surface so the registry can call it uniformly:
"""<one-line docstring: what variable, what it derives from>."""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from utils.env.builder import BuildContext, EnvBuilder
KEY = "INFINITO_..."
COMMENT = "<single-line per-key comment, mirrors default.env style>"
def apply(eb: EnvBuilder, ctx: BuildContext) -> None: ...
KEYMUST be the owned variableβs name.COMMENTMUST be a single line, no em dashes, that ends up above the key in the generated.env.applyMUST take(eb, ctx)and returnNone.A handler that targets a conditional branch (GHA-only, NIX-only, β¦) MUST self-check the relevant
ctxflag and return early. The registry calls every handler unconditionally.
Import Rules πΒΆ
A handler MUST NOT import another handler. Cross-handler data flows through
eb.get(...)/eb.set(...)only.A handler MAY import stdlib, parser.py, runtime.py, and any repo module whose own import closure is stdlib-only. The whole closure MUST import and run on the bare bootstrap python, before any dependency is installed.
utils.cache.filesand yaml_bootstrap.py qualify;utils.cache.yamldoes not, because it imports PyYAML. Read SPOT files withutils.cache.files.read_textplusutils.yaml_bootstrap.load_blockor a stdlib line parse.load_blockaccepts block mappings, block lists and string scalars only, and raisesBootstrapYamlErroron everything else, so a SPOT file read this way MUST stay inside that subset. test_bare_bootstrap.py enforces this by running the generator with every non-stdlib import blocked.A handler MUST NOT import from writer.py or builder.py at runtime. The
EnvBuilderandBuildContexttypes MAY be referenced underTYPE_CHECKINGfor annotations only.
Registry πΒΆ
init.py MUST list every handler module in
ORDERED_HANDLERS.The order in
ORDERED_HANDLERSMUST respect data dependencies. Example:infinito_containerruns afterpassthroughso it can read the resolvedINFINITO_DISTRO.Adding a handler MUST also bump the relevant baseline test in test_dotenv_generator.py when the new key is a static-default in default.env, so the drift test stays honest.