Source code for gyoza.deployment.builder
"""Docker build logic driven by a gyoza.yml configuration.
Generates a temporary ``docker-compose.yml`` from the gyoza config
and delegates to ``docker compose build``.
"""
from __future__ import annotations
import subprocess
import tempfile
from pathlib import Path
from typing import Any
import yaml
from gyoza.deployment.config import load_config
_SERVICE_NAME = "gyoza_build"
_REQUIRED_KEYS = frozenset({"image", "build"})
def _load_build_config(project_path: Path) -> dict[str, Any]:
"""Read and validate the gyoza config for building.
Parameters
----------
project_path : Path
Root directory containing the gyoza config.
Returns
-------
dict[str, Any]
Parsed YAML configuration.
Raises
------
FileNotFoundError
If the config file is not found.
ValueError
If ``image`` or ``build`` keys are missing.
"""
data = load_config(project_path)
missing = _REQUIRED_KEYS - data.keys()
if missing:
msg = f"Missing required keys in gyoza config: {', '.join(sorted(missing))}"
raise ValueError(msg)
return data
[docs]
def build(project_path: Path | str) -> subprocess.CompletedProcess[str]:
"""Run ``docker compose build`` for a gyoza project.
Reads ``gyoza.yml`` from *project_path*, writes a temporary
``docker-compose.yml`` carrying the ``build`` section verbatim,
and invokes ``docker compose build``.
Parameters
----------
project_path : Path | str
Directory containing ``gyoza.yml`` and the build context.
Returns
-------
subprocess.CompletedProcess[str]
Result of the ``docker compose build`` invocation.
Raises
------
FileNotFoundError
If ``gyoza.yml`` is missing.
ValueError
If the config is invalid.
subprocess.CalledProcessError
If ``docker compose build`` exits with a non-zero code.
"""
project_path = Path(project_path).resolve()
data = _load_build_config(project_path)
compose = {
"services": {
_SERVICE_NAME: {
"image": data["image"],
"build": data["build"],
}
}
}
with tempfile.NamedTemporaryFile(
mode="w",
suffix=".yml",
dir=project_path,
prefix=".gyoza-compose-",
delete=True,
) as tmp:
yaml.safe_dump(compose, tmp, default_flow_style=False)
tmp.flush()
cmd = ["docker", "compose", "-f", tmp.name, "build", _SERVICE_NAME]
return subprocess.run(cmd, check=True, text=True, cwd=project_path) # noqa: S603