# syntax=docker/dockerfile:1
#
# Spark Lab container image.
#
# sparklab is not published to PyPI or npm yet (see docs/09-docker-and-packaging.md
# for the publish checklist), so this image builds the package FROM THIS
# CHECKOUT rather than resolving it from a registry -- the same gap that
# makes `npx sparklab` only work from inside a repo clone (see
# npm/bin/sparklab.js's NO_PROJECT_MESSAGE) applies here too, and this
# Dockerfile is the container-shaped fix: it COPYs the source in and
# installs it locally with uv, using the committed uv.lock for a
# reproducible dependency set.
#
# Target platform: linux/arm64 (the DGX Spark is aarch64 Grace Blackwell),
# verified by actually building and running this image there. linux/amd64
# is intended to work too -- pyproject.toml's dependencies (duckdb, psutil,
# fastapi, uvicorn, qrcode, httpx) all publish prebuilt amd64 wheels, and
# nothing here is CUDA- or arch-specific at the container-build level --
# but that is an expectation, not a measurement: no amd64 build was run in
# this environment (see docs/09-docker-and-packaging.md's multi-arch
# section). GPU access on either arch comes entirely from the NVIDIA
# Container Toolkit at RUN time (`--gpus all`), not from anything baked
# into this image; see the capability matrix in
# docs/09-docker-and-packaging.md for what that toolkit does and does not
# make visible in-container.
#
# Multi-arch build: this environment (a Mac running Docker via Colima, an
# aarch64 Linux VM under Virtualization.framework) has no `docker buildx`
# plugin installed, so only a native linux/arm64 build was actually run and
# verified here -- see the report for the exact command and output. To
# publish both arches for real:
#
#   docker buildx create --use
#   docker buildx build --platform linux/amd64,linux/arm64 \
#     -t sparklab:latest --push .
#
# buildx cross-builds linux/amd64 under QEMU emulation from this arm64
# host (slow but works) or, better, use two native builders (one per arch)
# behind `docker buildx build --platform linux/amd64,linux/arm64` with a
# builder that has both as nodes, and `docker manifest create` to fuse the
# two single-arch images into one multi-arch manifest list if not using
# buildx's built-in push.

FROM python:3.12-slim AS base

# uv, copied from Astral's own distroless image rather than curled at
# build time -- keeps the build hermetic-ish (no shell-pipe-to-sh step)
# and pins the exact uv version.
COPY --from=ghcr.io/astral-sh/uv:0.11.7 /uv /usr/local/bin/uv

# ca-certificates: uv/pip need it to fetch dependency wheels over TLS from
# PyPI at build time (sparklab's own DEPENDENCIES -- duckdb, fastapi, etc.
# -- are public PyPI packages already; only the `sparklab` package itself
# is unpublished and comes from the COPY below, not a registry).
RUN apt-get update \
    && apt-get install -y --no-install-recommends ca-certificates \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Dependency layer first, cached independently of source changes.
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev

# Now the actual source, then install sparklab itself into the same venv.
COPY sparklab ./sparklab
RUN uv sync --frozen --no-dev

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

# Where `--results-dir` (default: benchmarks/results, relative to cwd)
# lands. Created here so a bind-mounted host directory (see
# docker-compose.yml) has somewhere to land even before the first run
# writes to it, and so an anonymous-volume run still has a writable dir
# owned by the image's default (root) user.
RUN mkdir -p /app/benchmarks/results

# sparklab up's default bind is 0.0.0.0 with network access on (see
# cli.py's up_p --host default) -- that is also the ONLY sensible default
# inside a container, since 127.0.0.1 in-container is unreachable from
# outside it regardless of -p/--network flags. EXPOSE is documentation
# only; the actual publish/host-network decision is made at `docker run`
# time (see docker-compose.yml and the capability-matrix doc for why).
EXPOSE 7788

ENTRYPOINT ["sparklab"]
# No subcommand by default: `docker run sparklab-image` alone prints
# argparse's own help (main()'s `ap.print_help()` fallback for a missing
# command) rather than silently starting a long-running server.
CMD []
