249aacab2e
Swap modernc.org/sqlite for jackc/pgx/v5 with no observable change: same endpoints, same wire format, same updated_at ordering rule. The schema now comes from numbered SQL embedded in the binary and applied on startup, one transaction each, recorded in schema_migrations. That replaces two pieces of SQLite-era machinery, both deleted rather than ported: the column probing (Postgres has ADD COLUMN IF NOT EXISTS, and there is no legacy database left to probe) and the Asura key rewrite, which has run clean on every start for months now that the userscripts strip build hashes before writing. Its regexp survives as latest.asuraBuildHash, where the poller still needs it to scope chapter links to a series whose slug carries a rotating hash. Types get real: favorite is a boolean, chapter numbers double precision, timestamps stay unix-ms bigint. SQLite's null-safe IS NOT becomes IS DISTINCT FROM, which is what implements the rule that only reading progress reorders a list. Inside COALESCE/NULLIF the status and kind parameters need an explicit ::text — there is no target column to infer from and Postgres refuses to guess. Tests lose their free t.TempDir() database, so Docker is now a hard prerequisite for `go test ./...`: internal/pgtest starts one postgres:17-alpine per test binary and hands each test a database of its own. Hand-rolled rather than testcontainers — it is one docker run, one docker port and a ping loop against a module list that is otherwise stdlib. BREAKING CHANGE: DB_PATH is retired for DATABASE_URL, which is required and has no default. Compose gains a postgres service on an internal network with its own volume; POSTGRES_PASSWORD joins .env. The old bookmarks-data volume is deliberately left undeclared so `docker compose down -v` cannot take the pre-migration database with it. Closes #20
31 lines
951 B
Docker
31 lines
951 B
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# --- build stage: compile a static, CGO-free binary ---
|
|
FROM golang:1.26-alpine AS build
|
|
WORKDIR /src
|
|
|
|
# Dependencies first for layer caching (changes rarely).
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
# Then source (changes often). internal/web carries the go:embed'd
|
|
# templates/static assets — missing them turns the embed directive into a
|
|
# build error, so the whole tree must land before `go build`.
|
|
COPY *.go ./
|
|
COPY internal/ ./internal/
|
|
|
|
# Static binary: the Postgres driver (jackc/pgx) is pure Go, so CGO_ENABLED=0
|
|
# leaves no libc dependency.
|
|
# -trimpath + -ldflags strip paths and debug info for a smaller image.
|
|
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/server .
|
|
|
|
# --- runtime stage: distroless static, non-root ---
|
|
FROM gcr.io/distroless/static:nonroot
|
|
WORKDIR /
|
|
COPY --from=build /out/server /server
|
|
|
|
EXPOSE 8080
|
|
USER nonroot:nonroot
|
|
ENV PORT=8080
|
|
ENTRYPOINT ["/server"]
|