Source code for animedex.config.buildmeta

"""
Optional build-metadata loader for animedex.

Loads :mod:`animedex.config.build_info` if it has been generated by
``tools/generate_build_info.py`` (or by ``make build_info``) and
exposes a single dictionary, :data:`BUILD_INFO`, that the CLI banner
and the self-diagnostic both consume.

When ``build_info.py`` is missing (the file is git-ignored, so this is
the normal case in a fresh checkout) :data:`BUILD_INFO` still exists
but ``available`` is ``False``. Every consumer should branch on
``BUILD_INFO["available"]`` rather than catching ``ImportError`` itself.

The fields, mirrored from the generator:

* ``commit`` - full HEAD SHA, ``"unknown"`` if git was unavailable.
* ``commit_short`` - 7-character HEAD SHA, ``"unknown"`` otherwise.
* ``describe`` - ``git describe --tags --always --dirty`` output.
* ``tag`` - tag at HEAD when HEAD is exactly on a tag; ``None`` otherwise.
* ``dirty`` - bool; ``True`` if the working tree had uncommitted changes.
* ``build_time`` - UTC ISO-8601 timestamp.
* ``build_host`` - hostname captured at generation time.
* ``available`` - ``True`` if the values came from the generated file,
  ``False`` if they are placeholders.
"""

from __future__ import annotations

from typing import Any, Dict, Optional


def _load() -> Dict[str, Any]:
    """Attempt to import ``animedex.config.build_info`` and produce the
    canonical :data:`BUILD_INFO` shape.

    :return: A dictionary describing the build, with ``available=True``
             on success or ``available=False`` when the generated module
             is missing or malformed.
    :rtype: Dict[str, Any]
    """
    try:
        from animedex.config import build_info as _bi  # type: ignore[import-not-found]
    except Exception:
        return {
            "available": False,
            "commit": "unknown",
            "commit_short": "unknown",
            "describe": "unknown",
            "tag": None,
            "dirty": False,
            "build_time": "unknown",
            "build_host": "unknown",
        }

    def _attr(name: str, default: Any) -> Any:
        return getattr(_bi, name, default)

    return {
        "available": True,
        "commit": _attr("__COMMIT__", "unknown"),
        "commit_short": _attr("__COMMIT_SHORT__", "unknown"),
        "describe": _attr("__GIT_DESCRIBE__", "unknown"),
        "tag": _attr("__TAG__", None),
        "dirty": bool(_attr("__DIRTY__", False)),
        "build_time": _attr("__BUILD_TIME__", "unknown"),
        "build_host": _attr("__BUILD_HOST__", "unknown"),
    }


#: Canonical build-metadata mapping. Always populated; check
#: ``BUILD_INFO["available"]`` to distinguish a real build from a
#: placeholder.
BUILD_INFO: Dict[str, Any] = _load()


[docs] def format_short(prefix: str = "") -> str: """Return a short single-line description suitable for ``--version``. Examples: * ``"a2f7fa1 (clean) built 2026-05-07T03:35:00Z"`` when generated. * ``"build info not generated"`` when not. :param prefix: Optional leading string included before the short form. :type prefix: str, optional :return: A single line describing the build. :rtype: str """ if not BUILD_INFO["available"]: return f"{prefix}build info not generated" parts = [BUILD_INFO["commit_short"]] if BUILD_INFO["tag"]: parts.append(f"tag {BUILD_INFO['tag']}") parts.append("dirty" if BUILD_INFO["dirty"] else "clean") parts.append(f"built {BUILD_INFO['build_time']}") return prefix + " ".join(parts)
[docs] def format_block() -> str: """Return a multi-line block suitable for selftest output. :return: Pre-formatted, indented diagnostic block. The trailing newline is *not* included. :rtype: str """ if not BUILD_INFO["available"]: return " (not generated) - run `make build_info` to populate" lines = [ f" Commit: {BUILD_INFO['commit_short']} ({BUILD_INFO['commit']})", f" Describe: {BUILD_INFO['describe']}", f" Tag: {BUILD_INFO['tag'] if BUILD_INFO['tag'] else '<none>'}", f" Dirty: {BUILD_INFO['dirty']}", f" Built at: {BUILD_INFO['build_time']}", f" Built on: {BUILD_INFO['build_host']}", ] return "\n".join(lines)
[docs] def get_build_info() -> Dict[str, Any]: """Return a copy of :data:`BUILD_INFO` so callers cannot mutate it. :return: A shallow copy of the canonical build-info dict. :rtype: Dict[str, Any] """ return dict(BUILD_INFO)
# ``Optional`` is exported for callers that wish to use type hints on # ``tag`` (which can legitimately be ``None``). __all__ = ["BUILD_INFO", "format_short", "format_block", "get_build_info", "Optional"]