Reusable helpers
A recipe is plain Python, so factor repeated setup into a function. A @contextmanager that composes stage scopes drops into a with line next to the built-in scopes.
Wrap repeated mounts in a helper
This recipe defines a cargo helper that opens two cache mounts, then reuses it around the build:
from __future__ import annotations
from collections.abc import Iterator
from contextlib import contextmanager
from docker_dsl import Stage
from docker_dsl import context as ctx
from docker_dsl.stage import Stage as StageType
ctx.register("dev", bool)
@contextmanager
def cargo(stage: StageType) -> Iterator[None]:
with stage.cache("/root/.cargo/registry"), stage.cache("/app/target"):
yield
with Stage("rust:1.83-slim") as s:
s.workdir("/app")
s.copy(".", ".")
with cargo(s), s.run() as r:
r.cargo("build", "--release")
if ctx.dev:
r.cargo("test")Render it with --dev=true:
# syntax=docker/dockerfile:1
FROM rust:1.83-slim AS base
WORKDIR /app
COPY . .
RUN --mount=type=cache,target=/root/.cargo/registry,sharing=shared --mount=type=cache,target=/app/target,sharing=shared \
cargo build --release \
&& cargo testHow it composes
cargo(s) is a context manager that opens s.cache(...) twice and yields. In the with cargo(s), s.run() as r: line it sits alongside s.run(), so both cache mounts apply to every command in the block. Drop the helper into any stage that needs the same caches.
Helpers can take more than a stage, branch on config, or wrap secrets and binds. They are ordinary Python. Reach for current_stage() when a helper should act on whichever stage is open without taking it as an argument.