Dockerfile: cargo-chef + cargo cache mounts; drop manifest guard
This commit is contained in:
@@ -12,3 +12,12 @@ spa/dist/
|
|||||||
spa/.env
|
spa/.env
|
||||||
spa/.env.local
|
spa/.env.local
|
||||||
.sqlx/
|
.sqlx/
|
||||||
|
.superpowers/
|
||||||
|
.worktrees/
|
||||||
|
.claude/
|
||||||
|
.github/
|
||||||
|
.gitea/
|
||||||
|
imgs/
|
||||||
|
screenshots/
|
||||||
|
test_data/
|
||||||
|
*.md
|
||||||
|
|||||||
@@ -47,4 +47,4 @@ jobs:
|
|||||||
# Layering guards. These live in the Makefile and were previously local-only,
|
# Layering guards. These live in the Makefile and were previously local-only,
|
||||||
# so a PR could go green in CI while violating them.
|
# so a PR could go green in CI while violating them.
|
||||||
- name: guards
|
- name: guards
|
||||||
run: make check-appcontext check-handler-deps check-handler-repos check-http-adapter-deps check-federation-off-social check-sqlite-is-ap-free check-binaries-are-thin check-dockerfile-manifests check-federation-off-deps check-nats-isolated check-no-second-web-stack
|
run: make check-appcontext check-handler-deps check-handler-repos check-http-adapter-deps check-federation-off-social check-sqlite-is-ap-free check-binaries-are-thin check-federation-off-deps check-nats-isolated check-no-second-web-stack
|
||||||
|
|||||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
|||||||
# Layering guards. These live in the Makefile and were previously local-only,
|
# Layering guards. These live in the Makefile and were previously local-only,
|
||||||
# so a PR could go green in CI while violating them.
|
# so a PR could go green in CI while violating them.
|
||||||
- name: guards
|
- name: guards
|
||||||
run: make check-appcontext check-handler-deps check-handler-repos check-http-adapter-deps check-federation-off-social check-sqlite-is-ap-free check-binaries-are-thin check-dockerfile-manifests check-federation-off-deps check-nats-isolated check-no-second-web-stack
|
run: make check-appcontext check-handler-deps check-handler-repos check-http-adapter-deps check-federation-off-social check-sqlite-is-ap-free check-binaries-are-thin check-federation-off-deps check-nats-isolated check-no-second-web-stack
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
name: Build & Push Docker Image
|
name: Build & Push Docker Image
|
||||||
|
|||||||
77
Dockerfile
77
Dockerfile
@@ -6,67 +6,46 @@ RUN npm ci
|
|||||||
COPY spa/ .
|
COPY spa/ .
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# ----- build -----
|
# ----- chef base -----
|
||||||
FROM rust:slim-bookworm AS builder
|
FROM rust:slim-bookworm AS chef
|
||||||
|
|
||||||
WORKDIR /build
|
|
||||||
|
|
||||||
# Cache dependency compilation separately from source
|
|
||||||
#
|
|
||||||
# Every workspace member's Cargo.toml must be listed here by hand — `cargo fetch`
|
|
||||||
# below reads the whole workspace graph, so a missing manifest fails the build with
|
|
||||||
# "failed to read .../Cargo.toml". Adding a crate to crates/ means adding a line here.
|
|
||||||
COPY Cargo.toml Cargo.lock ./
|
|
||||||
COPY .cargo ./.cargo
|
|
||||||
COPY crates/adapters/activitypub/Cargo.toml crates/adapters/activitypub/Cargo.toml
|
|
||||||
COPY crates/adapters/auth/Cargo.toml crates/adapters/auth/Cargo.toml
|
|
||||||
COPY crates/event-payload/Cargo.toml crates/event-payload/Cargo.toml
|
|
||||||
COPY crates/adapters/event-publisher/Cargo.toml crates/adapters/event-publisher/Cargo.toml
|
|
||||||
COPY crates/adapters/nats/Cargo.toml crates/adapters/nats/Cargo.toml
|
|
||||||
COPY crates/adapters/metadata/Cargo.toml crates/adapters/metadata/Cargo.toml
|
|
||||||
COPY crates/adapters/poster-fetcher/Cargo.toml crates/adapters/poster-fetcher/Cargo.toml
|
|
||||||
COPY crates/adapters/object-storage/Cargo.toml crates/adapters/object-storage/Cargo.toml
|
|
||||||
COPY crates/adapters/export/Cargo.toml crates/adapters/export/Cargo.toml
|
|
||||||
COPY crates/adapters/importer/Cargo.toml crates/adapters/importer/Cargo.toml
|
|
||||||
COPY crates/adapters/media-server/Cargo.toml crates/adapters/media-server/Cargo.toml
|
|
||||||
COPY crates/adapters/rss/Cargo.toml crates/adapters/rss/Cargo.toml
|
|
||||||
COPY crates/adapters/sqlite/Cargo.toml crates/adapters/sqlite/Cargo.toml
|
|
||||||
COPY crates/adapters/sqlite-federation/Cargo.toml crates/adapters/sqlite-federation/Cargo.toml
|
|
||||||
COPY crates/api-types/Cargo.toml crates/api-types/Cargo.toml
|
|
||||||
COPY crates/application/Cargo.toml crates/application/Cargo.toml
|
|
||||||
COPY crates/adapters/tmdb-enrichment/Cargo.toml crates/adapters/tmdb-enrichment/Cargo.toml
|
|
||||||
COPY crates/domain/Cargo.toml crates/domain/Cargo.toml
|
|
||||||
COPY crates/bootstrap/Cargo.toml crates/bootstrap/Cargo.toml
|
|
||||||
COPY crates/adapters/http-axum/Cargo.toml crates/adapters/http-axum/Cargo.toml
|
|
||||||
COPY crates/server/Cargo.toml crates/server/Cargo.toml
|
|
||||||
COPY crates/tui/Cargo.toml crates/tui/Cargo.toml
|
|
||||||
COPY crates/adapters/image-converter/Cargo.toml crates/adapters/image-converter/Cargo.toml
|
|
||||||
COPY crates/worker/Cargo.toml crates/worker/Cargo.toml
|
|
||||||
COPY crates/config/Cargo.toml crates/config/Cargo.toml
|
|
||||||
|
|
||||||
# Stub every crate so cargo can resolve and fetch deps
|
|
||||||
RUN find crates -name "Cargo.toml" | sed 's|/Cargo.toml||' | \
|
|
||||||
xargs -I{} sh -c 'mkdir -p {}/src && echo "fn main(){}" > {}/src/main.rs && echo "" > {}/src/lib.rs'
|
|
||||||
|
|
||||||
# libwebp-dev: required at build time by the `webp` crate (C bindings)
|
# libwebp-dev: required at build time by the `webp` crate (C bindings)
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
libwebp-dev \
|
libwebp-dev \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
RUN cargo install cargo-chef --locked --version 0.1.78
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
RUN cargo fetch
|
# ----- planner: dependency recipe (changes only when manifests/lockfile change) -----
|
||||||
|
FROM chef AS planner
|
||||||
|
COPY . .
|
||||||
|
RUN cargo chef prepare --recipe-path recipe.json
|
||||||
|
|
||||||
# Now copy real sources (invalidates cache only on source changes)
|
# ----- build -----
|
||||||
COPY crates ./crates
|
FROM chef AS builder
|
||||||
|
|
||||||
# All sqlx queries use the runtime API (no query! macros), so no database
|
|
||||||
# or .sqlx cache is needed at compile time.
|
|
||||||
#
|
|
||||||
# Features: federation (ActivityPub), nats (EVENT_BUS_BACKEND=nats).
|
# Features: federation (ActivityPub), nats (EVENT_BUS_BACKEND=nats).
|
||||||
# Build without federation: --build-arg FEATURES=
|
# Build without federation: --build-arg FEATURES=
|
||||||
# To add NATS support: --build-arg FEATURES=federation,nats
|
# To add NATS support: --build-arg FEATURES=federation,nats
|
||||||
|
# Declared before cook so cook and build compile identical feature sets.
|
||||||
ARG FEATURES=federation
|
ARG FEATURES=federation
|
||||||
RUN cargo build --release -p server -p worker --no-default-features --features "${FEATURES}"
|
|
||||||
|
# .cargo carries the registry config needed to fetch private crates
|
||||||
|
COPY .cargo ./.cargo
|
||||||
|
COPY --from=planner /build/recipe.json recipe.json
|
||||||
|
# target/ is a normal layer (no cache mount) so the cooked deps live in the image
|
||||||
|
# layer cache; only the registry/git download caches are mounted.
|
||||||
|
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
|
||||||
|
--mount=type=cache,target=/usr/local/cargo/git,sharing=locked \
|
||||||
|
cargo chef cook --release -p server -p worker --no-default-features --features "${FEATURES}" --recipe-path recipe.json
|
||||||
|
|
||||||
|
# All sqlx queries use the runtime API (no query! macros), so no database
|
||||||
|
# or .sqlx cache is needed at compile time.
|
||||||
|
COPY Cargo.toml Cargo.lock ./
|
||||||
|
COPY crates ./crates
|
||||||
|
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
|
||||||
|
--mount=type=cache,target=/usr/local/cargo/git,sharing=locked \
|
||||||
|
cargo build --release -p server -p worker --no-default-features --features "${FEATURES}"
|
||||||
|
|
||||||
# ----- runtime -----
|
# ----- runtime -----
|
||||||
FROM debian:bookworm-slim
|
FROM debian:bookworm-slim
|
||||||
|
|||||||
20
Makefile
20
Makefile
@@ -1,6 +1,6 @@
|
|||||||
.DEFAULT_GOAL := check
|
.DEFAULT_GOAL := check
|
||||||
|
|
||||||
check: fmt-check clippy test test-federation-off check-appcontext check-handler-deps check-handler-repos check-http-adapter-deps check-federation-off-social check-sqlite-is-ap-free check-binaries-are-thin check-dockerfile-manifests check-federation-off-deps check-nats-isolated check-no-second-web-stack
|
check: fmt-check clippy test test-federation-off check-appcontext check-handler-deps check-handler-repos check-http-adapter-deps check-federation-off-social check-sqlite-is-ap-free check-binaries-are-thin check-federation-off-deps check-nats-isolated check-no-second-web-stack
|
||||||
@echo "✅ All checks passed"
|
@echo "✅ All checks passed"
|
||||||
|
|
||||||
check-appcontext:
|
check-appcontext:
|
||||||
@@ -87,22 +87,6 @@ check-sqlite-is-ap-free:
|
|||||||
fi
|
fi
|
||||||
@echo "✅ sqlite crate depends on no k-ap, activitypub, or *-federation crate"
|
@echo "✅ sqlite crate depends on no k-ap, activitypub, or *-federation crate"
|
||||||
|
|
||||||
check-dockerfile-manifests:
|
|
||||||
@members=$$(awk '/^members = \[/{f=1;next} f&&/^\]/{f=0} f' Cargo.toml | sed -n 's/^[[:space:]]*"\(.*\)",\{0,1\}[[:space:]]*$$/\1/p'); \
|
|
||||||
copied=$$(sed -n 's/^COPY \([^[:space:]]*\)\/Cargo\.toml[[:space:]].*/\1/p' Dockerfile | grep -v '^\(Cargo\.toml\|\.\)$$' || true); \
|
|
||||||
bad=""; \
|
|
||||||
for m in $$members; do \
|
|
||||||
echo "$$copied" | grep -qxF "$$m" || bad="$$bad missing-COPY:$$m"; \
|
|
||||||
done; \
|
|
||||||
for c in $$copied; do \
|
|
||||||
echo "$$members" | grep -qxF "$$c" || bad="$$bad not-a-member:$$c"; \
|
|
||||||
done; \
|
|
||||||
if [ -n "$$bad" ]; then \
|
|
||||||
echo "❌ Dockerfile manifest COPY lines out of sync with workspace members:$$bad"; \
|
|
||||||
exit 1; \
|
|
||||||
fi; \
|
|
||||||
echo "✅ Dockerfile copies a manifest for every workspace member"
|
|
||||||
|
|
||||||
CARGO_TREE_NAMES := cargo tree -p server -p worker -e normal --prefix none
|
CARGO_TREE_NAMES := cargo tree -p server -p worker -e normal --prefix none
|
||||||
|
|
||||||
check-federation-off-deps:
|
check-federation-off-deps:
|
||||||
@@ -183,4 +167,4 @@ dev-spa:
|
|||||||
spa-dev:
|
spa-dev:
|
||||||
@npm --prefix spa run dev
|
@npm --prefix spa run dev
|
||||||
|
|
||||||
.PHONY: check fmt fmt-check clippy test test-federation-off fix dev dev-stop dev-worker dev-spa spa-dev check-appcontext check-handler-deps check-handler-repos check-http-adapter-deps check-federation-off-social check-sqlite-is-ap-free check-binaries-are-thin check-dockerfile-manifests check-federation-off-deps check-nats-isolated check-no-second-web-stack
|
.PHONY: check fmt fmt-check clippy test test-federation-off fix dev dev-stop dev-worker dev-spa spa-dev check-appcontext check-handler-deps check-handler-repos check-http-adapter-deps check-federation-off-social check-sqlite-is-ap-free check-binaries-are-thin check-federation-off-deps check-nats-isolated check-no-second-web-stack
|
||||||
|
|||||||
Reference in New Issue
Block a user