# Build the site from the podpack distribution rather than from a loose
# directory of source: the image then contains exactly what `uv sync --frozen`
# resolves from the committed lockfile, which is the same thing a developer
# gets locally and the same thing a deployment gets.
#
# Two stages, because three things are needed to *build* the venv and none of
# them to run it: git, uv, and uv's download cache. Together they are half the
# image -- 398MB single-stage against 203MB here -- so the runtime stage takes
# the finished venv and leaves the toolchain behind.

FROM docker.io/library/python:3.12-slim AS builder

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    UV_COMPILE_BYTECODE=1 \
    UV_LINK_MODE=copy

# uv is copied from its own pinned image rather than pip-installed, so the
# build has one fewer network fetch to go wrong and one fewer version to drift.
COPY --from=ghcr.io/astral-sh/uv:0.10 /uv /usr/local/bin/uv

# uv shells out to a real `git` to fetch a dependency locked to a git source,
# and the slim base has none. An app installed straight from its repository --
# the ordinary case for one not published to an index -- therefore fails the
# build with "Git executable not found" rather than anything about the app.
# Its own layer, before the lockfile is copied, so that adding an app does not
# also reinstall git.
#
# Note that removing it later in a single-stage build would not have helped:
# the layer above still carries the files, and the deletion only adds another
# layer on top. Not shipping it at all is what the second stage is for.
RUN apt-get update \
 && apt-get install --yes --no-install-recommends git \
 && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Dependencies first, in their own layer keyed on the lockfile, so that editing
# the source does not reinstall the world on every rebuild.
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev

COPY src/ ./src/
COPY README.md ./
RUN uv sync --frozen --no-dev


FROM docker.io/library/python:3.12-slim

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1

# The same WORKDIR as the builder, and not by coincidence. The venv's
# console-script shebangs carry an absolute interpreter path, so a venv built
# under one directory and copied to another leaves every entry point -- gunicorn,
# alembic -- failing to spawn with a bare "no such file or directory". It is the
# same trap as renaming the project directory on the host.
WORKDIR /app

COPY --from=builder /app/.venv ./.venv

# The project is installed into that venv as an editable pointing at ./src, so
# the source has to come too -- the venv alone is not a complete installation.
COPY src/ ./src/

# The migration environment ships in the image because the `migrate` service
# runs from it: the schema a build expects and the code that expects it then
# travel together and cannot be deployed out of step.
COPY alembic.ini ./
COPY alembic/ ./alembic/

# The container healthcheck runs this. It is a file rather than a `python -c`
# one-liner because podman splits ["CMD", ...] arguments on whitespace; see the
# module docstring.
COPY container/healthcheck.py ./healthcheck.py

ENV PATH="/app/.venv/bin:${PATH}"

# Which commit this image was built from, reported by /_status. It arrives as a
# build argument because the image cannot work it out for itself: `.git` is
# excluded from the build context, and the runtime stage has no git anyway.
# `unknown` when built by hand rather than through scripts/up.sh.
ARG GIT_SHA=unknown
ENV PODPACK_BUILD_COMMIT=${GIT_SHA}

# Run unprivileged. The uid/gid are fixed so the compose init-storage service
# knows who to hand the bind-mounted host directories to.
#
# The home directory is not decoration: gunicorn's control server puts its
# socket under $HOME and refuses to start quietly if it cannot write there.
RUN groupadd --gid 10001 app \
 && useradd --uid 10001 --gid 10001 --create-home --shell /usr/sbin/nologin app
ENV HOME=/home/app
USER 10001:10001

EXPOSE 8000

CMD ["sh", "-c", "exec gunicorn --bind 0.0.0.0:8000 --workers ${GUNICORN_WORKERS:-2} --access-logfile - '@@SITE_PACKAGE@@:create_app()'"]
