Skip to content
quarry Artifact [764d142012]
Login

Artifact [764d142012]

Artifact 764d142012a604d451e64978f34b7b29473ebdad935b4e3236ab4344f7db8a5d:


# syntax=docker/dockerfile:1
#
# quarry ships WITH zit, deliberately.
#
# 0001 §2 makes the zit CLI the entire store interface: every read and
# every write is a subprocess call. So zit's behaviour IS quarry's
# behaviour, and the two cannot be allowed to drift. On 2026-08-16 alone,
# three zit builds changed what quarry does — `frames` got 31% faster,
# a card-parsing fix changed which artifacts parse AT ALL (before it,
# sqlite's 794 tickets were invisible), and a new `stat -R` let quarry
# serve a bare store. An image that resolved zit at run time from
# whatever happened to be on PATH would reintroduce exactly the class of
# silent divergence that cost a day to find.
#
# Hence: ZIT_REF is a build argument, the built binary is copied in, and
# `quarry version` is recorded next to `zit version` at build time so a
# running container can answer "which zit is this?".
#
#   docker build --build-arg ZIT_REF=<commit> -t quarry .

# ---- zit builder ---------------------------------------------------------
# Zig rather than Go: zit is a Zig program, which is why this stage cannot
# simply be another golang builder.
FROM alpine:3.21 AS zit-builder
ARG ZIG_VERSION=0.16.0
ARG ZIT_REPO=https://github.com/danmestas/zit
# ZIT_REF pins the store implementation. Override it to move; do not
# leave it floating, or two deploys of the same quarry can disagree
# about what parses.
ARG ZIT_REF=trunk
RUN apk add --no-cache curl git xz
RUN case "$(uname -m)" in \
      aarch64) ZIG_ARCH=aarch64 ;; \
      x86_64)  ZIG_ARCH=x86_64 ;; \
      *) echo "unsupported architecture $(uname -m)" >&2; exit 1 ;; \
    esac && \
    curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-${ZIG_ARCH}-${ZIG_VERSION}.tar.xz" \
      -o /tmp/zig.tar.xz && \
    mkdir -p /opt/zig && tar -xJf /tmp/zig.tar.xz -C /opt/zig --strip-components=1 && \
    ln -s /opt/zig/zig /usr/local/bin/zig
WORKDIR /src
RUN git clone "${ZIT_REPO}" zit && cd zit && git checkout "${ZIT_REF}"
# --release=fast, not -Doptimize: zit's build.zig uses Zig 0.16's spelling.
RUN cd zit && zig build --release=fast && ./zig-out/bin/zit version

# ---- quarry builder ------------------------------------------------------
# CGO stays off: quarry's SQLite is ncruces/go-sqlite3 (WASM, no C) and
# Pikchr runs on wazero, so the whole binary is pure Go and static.
FROM golang:1.26 AS quarry-builder
ARG VERSION=0.0.0-dev
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
ENV CGO_ENABLED=0
RUN go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" -o /out/quarry ./cmd/quarry

# ---- runtime -------------------------------------------------------------
# busybox wget is present so compose and k8s health checks work, matching
# the notify image's posture.
FROM alpine:3.21
RUN apk add --no-cache ca-certificates && adduser -D -u 10001 quarry
COPY --from=zit-builder    /src/zit/zig-out/bin/zit /usr/local/bin/zit
COPY --from=quarry-builder /out/quarry              /usr/local/bin/quarry
# The pair, recorded together. `docker run <image> cat /etc/quarry-build`
# answers which zit a given quarry was shipped against without starting it.
RUN printf 'quarry: %s\nzit: %s\n' "$(quarry version)" "$(zit version)" > /etc/quarry-build && \
    cat /etc/quarry-build
USER quarry
# /repos holds the zit stores quarry serves; /data holds derived state
# (indexes, embedded NATS, the OLTP database) and is disposable by 0001
# §11 — wiping it and re-ingesting must converge to identical state.
VOLUME ["/repos", "/data"]
EXPOSE 8080
ENTRYPOINT ["quarry"]
CMD ["serve", "--addr", "0.0.0.0:8080", "--data", "/data"]