#!/bin/bash
# build_builder_image.sh — build and publish the DP-007 CI builder image to the
# Gitea container registry.
#
# TRACES: DP-007 | PR-004
#
# Usage:
#   scripts/ci/build_builder_image.sh                  # build only, tag v1
#   scripts/ci/build_builder_image.sh --push           # build and push
#   scripts/ci/build_builder_image.sh --tag v2 --push  # bump the pinned tag
#   scripts/ci/build_builder_image.sh --no-cache       # force a clean rebuild
#
# The tag is the contract with CI. .gitea/workflows/unit-tests.yml names an
# explicit tag in its `container:` block and never `latest`, so that rebuilding
# the image cannot silently change what a previous green build meant. Bumping
# the dependency set means bumping the tag AND editing the workflow — the two
# edits landing in the same commit is the point, not an inconvenience.
#
# Registry auth: this script does not log in. Do it once, out of band:
#   docker login gitea.tourolle.paris
# The CI host is already authenticated this way (its cached credentials in
# ~/.docker/config.json are what the kpnpp-builder push relies on), so a
# workflow that calls this script needs no secret plumbing.
set -euo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"

REGISTRY="gitea.tourolle.paris"
OWNER="dtourolle"
IMAGE="sae-builder-cpu"
DOCKERFILE="Dockerfile.builder-cpu"

# The tag CI pins to today. Keep this in step with the `container.image` line in
# .gitea/workflows/unit-tests.yml; the workflow asserts at run time that the
# image it landed in reports this same version, so a drift shows up as a failed
# job rather than as a build against the wrong toolchain.
TAG="v1"

PUSH=0
EXTRA_ARGS=()

while [ $# -gt 0 ]; do
    case "$1" in
        --push)     PUSH=1 ;;
        --tag)      TAG="${2:?--tag needs a value}"; shift ;;
        --no-cache) EXTRA_ARGS+=(--no-cache) ;;
        -h|--help)  sed -n '2,30p' "${BASH_SOURCE[0]}"; exit 0 ;;
        *)          echo "error: unknown argument '$1'" >&2; exit 2 ;;
    esac
    shift
done

if [ "$TAG" = "latest" ]; then
    echo "error: refusing to build the tag 'latest'." >&2
    echo "DP-007 requires CI to pin an immutable tag. A moving 'latest' means a" >&2
    echo "rebuild retroactively changes what every earlier green build proved." >&2
    exit 2
fi

REF="${REGISTRY}/${OWNER}/${IMAGE}:${TAG}"
# A second tag carrying the commit that produced the image. The workflow pins
# the human-readable tag; this one is the audit trail — given any image you can
# recover the Dockerfile that built it.
SHA="$(git -C "$REPO_ROOT" rev-parse --short HEAD)"
REF_SHA="${REGISTRY}/${OWNER}/${IMAGE}:${TAG}-${SHA}"

# The Dockerfile COPYs nothing from the repository on purpose (see its closing
# comment), so the build context is an empty directory rather than the repo
# root. Sending ~1 GB of models, fixtures and experiment data to the daemon for
# a build that reads none of it is pure latency.
CONTEXT="$(mktemp -d)"
trap 'rm -rf "$CONTEXT"' EXIT

echo "=== building ${REF}"
echo "    dockerfile: ${REPO_ROOT}/${DOCKERFILE}"
echo "    context:    (empty — the image embeds no repository content)"
echo
echo "    Expect this to take a while: OpenCV 5 is compiled from source because"
echo "    no Debian release ships it. That cost is paid once per image, which is"
echo "    the entire reason DP-007 asks for a prebuilt image instead of"
echo "    installing dependencies inside each CI run."
echo

docker build \
    "${EXTRA_ARGS[@]}" \
    --build-arg "IMAGE_TAG=${TAG}" \
    -f "${REPO_ROOT}/${DOCKERFILE}" \
    -t "${REF}" \
    -t "${REF_SHA}" \
    "${CONTEXT}"

echo
echo "=== built"
docker image inspect "${REF}" --format '    {{.RepoTags}}  {{.Size}} bytes'
docker run --rm "${REF}" sh -c 'echo "    SAE_BUILDER=$SAE_BUILDER version=$SAE_BUILDER_VERSION ort=$SAE_ORT_VERSION opencv=$SAE_OPENCV_VERSION"'

if [ "$PUSH" -eq 0 ]; then
    echo
    echo "Not pushed. Re-run with --push, or push by hand:"
    echo "    docker push ${REF}"
    echo "    docker push ${REF_SHA}"
    exit 0
fi

echo
echo "=== pushing"
# No `latest` tag is pushed, by design. Publishing one invites a workflow to use
# it, and DP-007 exists to prevent exactly that.
docker push "${REF}"
docker push "${REF_SHA}"

echo
echo "=== published ${REF}"
echo "If this was a dependency-set change, bump the tag in"
echo "    .gitea/workflows/unit-tests.yml   (container.image)"
echo "    scripts/ci/build_builder_image.sh (TAG, above)"
echo "in the same commit, so no run can build against an image the repository"
echo "does not describe."
