-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDockerfile
More file actions
191 lines (162 loc) · 7.03 KB
/
Copy pathDockerfile
File metadata and controls
191 lines (162 loc) · 7.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# syntax=docker/dockerfile:1.7-labs
###############################################################################
# jawcode — pi image
#
# Stages:
# natives-builder — Rust + Bun → pi_natives.linux-<arch>.node
# wheel-builder — jwc_rpc Python wheel
# pi-base — python + bun + rustup launcher + natives + jwc_rpc
# + /usr/local/bin/jwc shim
# pi-runtime — pi-base + pi source + bun install (DEFAULT, runnable)
#
# Build:
# docker build -t jawcode/pi:dev . # default = pi-runtime
# docker build --target pi-base -t jawcode/pi-base:dev . # base for derived images
#
# Run:
# docker run --rm jawcode/pi:dev --help
# docker run --rm -it -v "$PWD":/work jawcode/pi:dev cli # interactive jwc
#
# Consume as a base in another Dockerfile (see Dockerfile.robojwc):
# ARG PI_BASE=jawcode/pi:dev
# FROM ${PI_BASE} AS pi-base
###############################################################################
ARG BUN_VERSION=1.3.14
############################
# 1) natives-builder — Rust + Bun → pi_natives.linux-<arch>.node
############################
FROM rust:1.86-slim-bookworm AS natives-builder
ARG BUN_VERSION
ENV BUN_INSTALL=/opt/bun \
PATH=/opt/bun/bin:/usr/local/cargo/bin:/usr/local/bin:/usr/bin:/bin \
CARGO_TERM_COLOR=never
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
curl ca-certificates pkg-config libssl-dev unzip git \
&& rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}" \
&& /opt/bun/bin/bun --version
WORKDIR /pi
# Layer 1 — manifests + lockfiles only. Source edits under packages/*/src and
# crates/*/src won't bust `bun install` below. `--parents` preserves the
# matched path under /pi/ (requires syntax 1.7-labs).
COPY --parents \
package.json bun.lock bunfig.toml \
tsconfig.base.json tsconfig.json \
Cargo.toml Cargo.lock rust-toolchain.toml \
packages/*/package.json \
packages/tsconfig.workspace.json \
python/robojwc/web/package.json \
crates/*/Cargo.toml \
/pi/
# Layer 2 — hydrate node_modules from the manifests above.
RUN bun install --frozen-lockfile --ignore-scripts
# Layer 3 — full source. `Dockerfile.dockerignore` keeps target/, node_modules/,
# dist/, runs/, editor noise, etc. out of the context. node_modules from Layer 2
# is preserved across this COPY because it's never in the build context.
COPY . /pi/
# Layer 4 — compile pi-natives to a Linux N-API addon. Persistent caches keep
# repeat builds incremental: cargo's package index + git-deps + the workspace
# target dir.
RUN --mount=type=cache,target=/root/.cargo/registry \
--mount=type=cache,target=/root/.cargo/git \
--mount=type=cache,target=/pi/target \
set -eux; \
rustup show; \
bun --cwd=packages/natives run build; \
mkdir -p /out; \
cp packages/natives/native/pi_natives.linux-*.node /out/
############################
# 2) wheel-builder — jwc-rpc wheel
############################
FROM python:3.12-slim-bookworm AS wheel-builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/*
RUN pip install --upgrade pip build
WORKDIR /src
COPY python/jwc-rpc /src
RUN python -m build --wheel --outdir /out
############################
# 3) pi-base — python + bun + rustup + natives + jwc_rpc + jwc shim
#
# Sharable runtime base. Derived images (pi-runtime below, Dockerfile.robojwc)
# extend this and overlay their own source tree. Default PI_ROOT=/work/pi is
# friendly to derived images that mount a host pi checkout there; pi-runtime
# overrides it to /pi because its source is baked in.
############################
FROM python:3.12-slim-bookworm AS pi-base
ARG BUN_VERSION
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
BUN_INSTALL=/opt/bun \
PI_ROOT=/work/pi \
CARGO_HOME=/data/cache/cargo \
CARGO_TARGET_DIR=/data/cache/cargo-target \
RUSTUP_HOME=/data/cache/rustup \
PATH=/opt/bun/bin:/usr/local/cargo/bin:/usr/local/bin:/usr/bin:/bin
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
git curl ca-certificates unzip openssh-client tini sqlite3 \
build-essential pkg-config libssl-dev \
&& rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}" \
&& /opt/bun/bin/bun --version
# Rustup launcher only — the real toolchain is fetched lazily into RUSTUP_HOME
# on first cargo invocation, driven by pi's `rust-toolchain.toml`. Keeps the
# image small while sharing the toolchain across reboots when /data is mounted.
RUN curl -fsSL https://sh.rustup.rs -o /tmp/rustup-init.sh \
&& CARGO_HOME=/usr/local/cargo RUSTUP_HOME=/usr/local/rustup-bootstrap \
sh /tmp/rustup-init.sh -y --no-modify-path --default-toolchain none --profile minimal \
&& rm -f /tmp/rustup-init.sh \
&& rm -rf /usr/local/rustup-bootstrap \
&& /usr/local/cargo/bin/rustup --version
# pi-natives addon: pi's loader probes /opt/bun/bin as a fallback path.
COPY --from=natives-builder /out/pi_natives.linux-*.node /opt/bun/bin/
# jwc-rpc Python wheel.
COPY --from=wheel-builder /out/*.whl /tmp/wheels/
RUN pip install /tmp/wheels/jwc_rpc-*.whl && rm -rf /tmp/wheels
# `jwc` shim — runs the coding-agent CLI against $PI_ROOT via Bun. Derived
# images override PI_ROOT to point at wherever their pi source lives.
RUN printf '%s\n' \
'#!/usr/bin/env bash' \
'set -euo pipefail' \
': "${PI_ROOT:=/work/pi}"' \
'if [ ! -d "$PI_ROOT/packages/coding-agent" ]; then' \
' echo "pi: PI_ROOT=$PI_ROOT does not look like a pi checkout" >&2' \
' exit 127' \
'fi' \
'exec bun "$PI_ROOT/packages/coding-agent/src/cli.ts" "$@"' \
> /usr/local/bin/jwc \
&& chmod +x /usr/local/bin/jwc \
&& ln -s jwc /usr/local/bin/gjc
############################
# 4) pi-runtime — pi-base + pi source + bun install (DEFAULT)
#
# A self-contained, runnable jwc image. `docker run jawcode/pi:dev --help`
# Just Works without a host checkout.
############################
FROM pi-base AS pi-runtime
ENV PI_ROOT=/pi
WORKDIR /pi
# Same manifests-only layered install pattern as natives-builder — `bun install`
# only re-runs when a package.json / lockfile changes.
COPY --parents \
package.json bun.lock bunfig.toml \
tsconfig.base.json tsconfig.json \
packages/*/package.json \
packages/tsconfig.workspace.json \
python/robojwc/web/package.json \
/pi/
RUN bun install --frozen-lockfile --ignore-scripts
# Pi source. `Dockerfile.dockerignore` keeps **/node_modules out of the context
# so stale isolated-linker symlinks from a host install can't shadow the
# hoisted node_modules that `bun install` just produced.
COPY . /pi/
# Regenerate the docs index that `--ignore-scripts` skipped above. The root
# package.json's `prepare` script normally handles this on a vanilla install.
RUN bun --cwd=packages/coding-agent run generate-docs-index
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/jwc"]
CMD ["--help"]