From ff23551b07c01374b38268f0528563de9c59a17e Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Tue, 29 Sep 2026 05:51:36 +0000 Subject: [PATCH] Install Dockerfile build dependencies through script/bootstrap (closes #95) The Dockerfile lint and build stages and Dockerfile.lint each carried their own apk add list, a copy of what script/bootstrap installs. They now copy script/, go.mod and go.sum and run script/bootstrap, so that layer is reused until one of those changes. script/bootstrap gains a C compiler check: the golang image has none, and cgo needs one. The build adds -trimpath and -s -w; CGO_ENABLED=1 stays, as govips links libvips. ARG VERSION moves to just above the build, so a new version reruns neither script/bootstrap nor the tests. Model: opus-5-5 --- Dockerfile | 33 ++++++++++++++++----------------- Dockerfile.lint | 14 +++++++------- TODO.md | 8 ++++++++ script/bootstrap | 11 +++++++++-- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/Dockerfile b/Dockerfile index 45027be..76d9bac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,13 +3,14 @@ # golangci/golangci-lint:v2.12.2-alpine, 2026-08-07 FROM golangci/golangci-lint:v2.12.2-alpine@sha256:91b27804074a0bacea298707f016911e60cf0cdbc6c7bf5ccacb5f0606d18d60 AS lint -RUN apk add --no-cache make build-base vips-dev libheif-dev pkgconfig - WORKDIR /src -# Copy go mod files first for better layer caching +# script/bootstrap installs the build dependencies and downloads the Go +# modules. Only script/, go.mod and go.sum are copied first, so this +# layer is reused until one of them changes. +COPY script/ ./script/ COPY go.mod go.sum ./ -RUN go mod download +RUN script/bootstrap # Copy source code COPY . . @@ -28,20 +29,12 @@ FROM golang:1.25.4-alpine@sha256:d3f0cf7723f3429e3f9ed846243970b20a2de7bae6a5b66 # Depend on lint stage passing COPY --from=lint /src/go.sum /dev/null -ARG VERSION=dev - -# Install build dependencies for CGO image libraries -RUN apk add --no-cache \ - build-base \ - vips-dev \ - libheif-dev \ - pkgconfig - WORKDIR /src -# Copy go mod files first for better layer caching +# Build dependencies and Go modules, as in the lint stage +COPY script/ ./script/ COPY go.mod go.sum ./ -RUN GOTOOLCHAIN=auto go mod download +RUN script/bootstrap # Copy source code COPY . . @@ -49,8 +42,14 @@ COPY . . # Run tests RUN make test -# Build with CGO enabled -RUN CGO_ENABLED=1 GOTOOLCHAIN=auto go build -ldflags "-X main.Version=${VERSION}" -o /pixad ./cmd/pixad +# VERSION is declared here, not earlier: a new value reruns only the +# build, not script/bootstrap or the tests. CGO stays enabled for +# govips; -trimpath keeps build paths out of the binary, and -s -w +# leave out the symbol table and debug information. +ARG VERSION=dev +RUN CGO_ENABLED=1 GOTOOLCHAIN=auto go build -trimpath \ + -ldflags "-s -w -X main.Version=${VERSION}" \ + -o /pixad ./cmd/pixad # Runtime stage # alpine:3.21, 2026-02-25 diff --git a/Dockerfile.lint b/Dockerfile.lint index a07d8ca..41e350b 100644 --- a/Dockerfile.lint +++ b/Dockerfile.lint @@ -6,16 +6,16 @@ # golangci/golangci-lint:v2.12.2-alpine, 2026-08-07 FROM golangci/golangci-lint:v2.12.2-alpine@sha256:91b27804074a0bacea298707f016911e60cf0cdbc6c7bf5ccacb5f0606d18d60 -# pixa is CGO/libvips: the type-aware linters compile every package, so -# this image needs the same C libraries the build does. -RUN apk add --no-cache build-base vips-dev libheif-dev pkgconfig - WORKDIR /src -# Modules first for layer caching; go.mod/go.sum settle this layer's -# result, so it may safely be reused between runs. +# pixa is CGO/libvips: the type-aware linters compile every package, so +# this image needs the same C libraries the build does. script/bootstrap +# installs them and downloads the Go modules. Only script/, go.mod and +# go.sum are copied first; they settle this layer's result, so it may +# safely be reused between runs. +COPY script/ ./script/ COPY go.mod go.sum ./ -RUN go mod download +RUN script/bootstrap COPY . . diff --git a/TODO.md b/TODO.md index 8f07fa8..1d40436 100644 --- a/TODO.md +++ b/TODO.md @@ -30,6 +30,14 @@ exhaustion # Completed Steps +- 2026-09-29 Dockerfiles install through `script/bootstrap` (closes #95): the + `Dockerfile` lint and build stages and `Dockerfile.lint` copy `script/`, + `go.mod` and `go.sum`, then run `script/bootstrap` in place of their own + `apk add` lines, so the build dependencies are listed in one place; + `script/bootstrap` now also installs a C compiler when `gcc` is missing; the + build uses `-trimpath` and `-s -w` and keeps `CGO_ENABLED=1` for govips; + `ARG VERSION` sits just above the build, so a new version reruns neither + `script/bootstrap` nor the tests. - 2026-09-29 migrations at the path `REPO_POLICIES.md` sets (closes #96): the migration files moved, contents unchanged, from `internal/database/schema/` to `internal/db/migrations/` as `000_migration.sql` and `001_schema.sql`; the diff --git a/script/bootstrap b/script/bootstrap index 83d2fc5..54c04ea 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -5,8 +5,10 @@ # or apk (detected in that order); assumes NOTHING is present (not git, # make, or go). The linter is never installed on the host: golangci-lint # runs only inside a container, Dockerfile.lint or the Dockerfile lint -# stage (see script/lint). CGO image libraries (pkg-config, vips, -# libheif) are installed for the govips bindings. +# stage (see script/lint). A C compiler and the CGO image libraries +# (pkg-config, vips, libheif) are installed for the govips bindings. +# Both Dockerfiles run this script too, so their build dependencies are +# the ones listed here. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" @@ -53,6 +55,11 @@ missing() { # CGO dependencies for govips (image processing) ensure_cgo_deps() { + # cgo compiles with gcc on Linux; build-base and build-essential + # also bring the C library headers. + if missing gcc; then + pkg_install gcc build-essential gcc build-base + fi if missing pkg-config; then pkg_install pkg-config pkg-config pkg-config pkgconfig fi -- 2.54.0