-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathDockerfile.rust
More file actions
158 lines (136 loc) · 7.12 KB
/
Dockerfile.rust
File metadata and controls
158 lines (136 loc) · 7.12 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
# syntax=docker/dockerfile:1.4
# deva.sh - Rust Developer Image
# Extends main deva image with Rust toolchain and ecosystem tools
ARG BASE_IMAGE=ghcr.io/thevibeworks/deva:latest
FROM ${BASE_IMAGE}
LABEL org.opencontainers.image.title="deva-rust"
LABEL org.opencontainers.image.description="Rust development environment with full toolchain"
ARG CLAUDE_CODE_VERSION=2.1.143
ARG CLAUDE_TRACE_VERSION=1.0.9
ARG CODEX_VERSION=0.131.0
ARG GEMINI_CLI_VERSION=0.42.0
ARG ATLAS_CLI_VERSION=v0.1.4
ARG PLAYWRIGHT_VERSION=1.60.0
ARG RUST_TOOLCHAINS="stable"
ARG RUST_DEFAULT_TOOLCHAIN="stable"
ARG RUST_TARGETS="wasm32-unknown-unknown"
LABEL org.opencontainers.image.claude_code_version=${CLAUDE_CODE_VERSION}
LABEL org.opencontainers.image.claude_trace_version=${CLAUDE_TRACE_VERSION}
LABEL org.opencontainers.image.codex_version=${CODEX_VERSION}
LABEL org.opencontainers.image.gemini_cli_version=${GEMINI_CLI_VERSION}
LABEL org.opencontainers.image.atlas_cli_version=${ATLAS_CLI_VERSION}
LABEL org.opencontainers.image.playwright_version=${PLAYWRIGHT_VERSION}
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ENV RUSTUP_HOME=/opt/rustup \
CARGO_HOME=/opt/cargo \
PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright \
PATH=/opt/cargo/bin:$PATH
USER root
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends \
libpq-dev postgresql-client \
libmysqlclient-dev mysql-client \
libsqlite3-dev sqlite3 \
libssl-dev \
libcurl4-openssl-dev \
libpng-dev libjpeg-dev \
libudev-dev \
libproc2-dev \
libzmq3-dev libzmq5 libczmq-dev && \
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg && \
ARCH=$(dpkg --print-architecture) && \
echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg arch=${ARCH}] https://packages.clickhouse.com/deb stable main" > /etc/apt/sources.list.d/clickhouse.list && \
apt-get update && \
apt-get install -y --no-install-recommends clickhouse-client
# Playwright/Chromium runtime system libs (Ubuntu 24.04 noble t64 variants).
# Installed here as root so `playwright install chromium` can run as deva user
# without --with-deps (which requires root apt).
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends \
libnss3 libnspr4 libdbus-1-3 libexpat1 \
libatk1.0-0t64 libatk-bridge2.0-0t64 libatspi2.0-0t64 \
libcups2t64 libdrm2 \
libxcomposite1 libxdamage1 libxext6 libxfixes3 libxrandr2 libxkbcommon0 libxcb1 \
libgbm1 libpango-1.0-0 libcairo2 libasound2t64 \
fonts-liberation xdg-utils
RUN --mount=type=cache,target=/tmp/rust-cache,sharing=locked \
set -euxo pipefail && \
mkdir -p "$RUSTUP_HOME" "$CARGO_HOME" && \
mkdir -p "$CARGO_HOME/registry/cache" "$CARGO_HOME/registry/index" "$CARGO_HOME/git" && \
chown -R "$DEVA_UID:$DEVA_GID" "$RUSTUP_HOME" "$CARGO_HOME" && \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
sh -s -- -y --default-toolchain none --profile default --no-modify-path && \
rustup set auto-self-update disable && \
rustup toolchain install --no-self-update ${RUST_TOOLCHAINS} && \
for tc in ${RUST_TOOLCHAINS}; do \
rustup component add --toolchain "$tc" rustfmt clippy rust-analyzer; \
done && \
if [ -n "${RUST_TARGETS}" ]; then \
for tc in ${RUST_TOOLCHAINS}; do \
rustup target add --toolchain "$tc" ${RUST_TARGETS}; \
done; \
fi && \
rustup default "${RUST_DEFAULT_TOOLCHAIN}" && \
chown -R "$DEVA_UID:$DEVA_GID" "$RUSTUP_HOME" "$CARGO_HOME"
RUN echo 'export PATH="/opt/cargo/bin:$PATH"' >> "$DEVA_HOME/.zshrc" && \
echo 'export RUSTUP_HOME=/opt/rustup' >> "$DEVA_HOME/.zshrc" && \
echo 'export CARGO_HOME=/opt/cargo' >> "$DEVA_HOME/.zshrc" && \
echo 'export PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright' >> "$DEVA_HOME/.zshrc" && \
sed -i 's/plugins=(git docker python golang node npm aws/plugins=(git docker python golang rust node npm aws/' "$DEVA_HOME/.zshrc" && \
echo '# Rust aliases' >> "$DEVA_HOME/.zshrc" && \
echo 'alias cr="cargo run"' >> "$DEVA_HOME/.zshrc" && \
echo 'alias cb="cargo build"' >> "$DEVA_HOME/.zshrc" && \
echo 'alias ct="cargo test"' >> "$DEVA_HOME/.zshrc" && \
echo 'alias cc="cargo check"' >> "$DEVA_HOME/.zshrc" && \
echo 'alias cw="cargo watch -x check -x test -x run"' >> "$DEVA_HOME/.zshrc" && \
echo 'alias cf="cargo fmt"' >> "$DEVA_HOME/.zshrc" && \
echo 'alias cl="cargo clippy"' >> "$DEVA_HOME/.zshrc"
RUN mkdir -p "$PLAYWRIGHT_BROWSERS_PATH" && \
chown -R "$DEVA_UID:$DEVA_GID" "$PLAYWRIGHT_BROWSERS_PATH"
USER $DEVA_USER
COPY --chown=deva:deva scripts/install-agent-tooling.sh /tmp/install-agent-tooling.sh
RUN --mount=type=cache,target=/home/deva/.npm,uid=${DEVA_UID},gid=${DEVA_GID},sharing=locked \
bash /tmp/install-agent-tooling.sh && \
rm -f /tmp/install-agent-tooling.sh
# Install Playwright + both chromium binaries. Runs after install-agent-tooling.sh
# so npm prefix ($DEVA_HOME/.npm-global) is already configured. System deps are
# pre-installed above, so we skip --with-deps (which would need root).
#
# Two browsers installed: `chromium` (headed) + `chromium-headless-shell`
# (headless-only, lighter). Playwright 1.49+ uses the shell for `headless: true`
# which is what Playwright MCP and most agent tools call — missing it gives
# "Executable doesn't exist at .../chromium_headless_shell-XXXX/..." at runtime.
RUN --mount=type=cache,target=/home/deva/.npm,uid=${DEVA_UID},gid=${DEVA_GID},sharing=locked \
set -eux && \
cd "$DEVA_HOME" && \
for i in 1 2 3; do \
if npm install -g --no-audit --no-fund \
"playwright@${PLAYWRIGHT_VERSION}" \
"@playwright/test@${PLAYWRIGHT_VERSION}"; then break; fi; \
if [ "$i" -ge 3 ]; then echo "playwright npm install failed" >&2; exit 1; fi; \
echo "playwright npm install attempt $i failed; retrying" >&2; \
sleep $((i * 3)); \
done && \
for i in 1 2 3; do \
if npx --yes playwright install chromium chromium-headless-shell; then break; fi; \
if [ "$i" -ge 3 ]; then echo "playwright browser install failed" >&2; exit 1; fi; \
echo "playwright browser install attempt $i failed; retrying" >&2; \
sleep $((i * 5)); \
done && \
npx playwright --version && \
ls "$PLAYWRIGHT_BROWSERS_PATH" && \
test -d "$(find "$PLAYWRIGHT_BROWSERS_PATH" -maxdepth 1 -type d -name 'chromium_headless_shell-*' -print -quit)" && \
npm cache clean --force
USER root
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
COPY scripts/deva-bridge-tmux /usr/local/bin/deva-bridge-tmux
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh && \
chmod 755 /usr/local/bin/deva-bridge-tmux && \
chmod -R 755 /usr/local/bin/scripts || true
WORKDIR /root
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"]
CMD ["claude"]