Skip to content

Commit 767049d

Browse files
olwangclaude
andcommitted
build: containerized cross-platform dev environment
Add a Docker toolchain image so the workspace builds and tests identically on macOS, Windows, and Linux with no local Rust/C/SQLite install. - Dockerfile: rust:1-bookworm (satisfies edition 2024) + build-essential, cmake, pkg-config (for ring/rustls and bundled rusqlite), clippy/rustfmt, and cargo-nextest (arch-aware prebuilt for amd64/arm64). A profile.d snippet keeps cargo on PATH for login shells too. - compose.yaml: `dev` service bind-mounts the repo at /work; target/ and cargo caches live in named volumes (off the host mount) so builds persist and stay fast on macOS/Windows. - .devcontainer: VS Code / Codespaces reuse the same compose service. - .dockerignore, docs/DOCKER.md, and README/docs-index pointers. Verified on Apple Silicon (OrbStack): image builds, workspace compiles in-container, and `cargo nextest` runs the suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b3b5f57 commit 767049d

7 files changed

Lines changed: 215 additions & 0 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "RSScript Dev",
3+
"dockerComposeFile": ["../compose.yaml"],
4+
"service": "dev",
5+
"workspaceFolder": "/work",
6+
// Reuse the same toolchain image, caches, and system libraries as the
7+
// `docker compose` workflow, so editor and CLI builds are identical across
8+
// macOS, Windows, and Linux (and GitHub Codespaces).
9+
"customizations": {
10+
"vscode": {
11+
"extensions": [
12+
"rust-lang.rust-analyzer",
13+
"tamasfe.even-better-toml",
14+
"vadimcn.vscode-lldb"
15+
],
16+
"settings": {
17+
"rust-analyzer.check.command": "clippy"
18+
}
19+
}
20+
},
21+
// Keep the container running for an attached editor session.
22+
"overrideCommand": true
23+
}

.dockerignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# The dev image bind-mounts the source instead of copying it, so the build
2+
# context only needs to be small. Keep heavy/host-specific paths out of it.
3+
.git/
4+
target/
5+
**/target/
6+
**/Cargo.lock.bak
7+
tests/generated/
8+
benchmarks/**/target/
9+
demos/
10+
*.log
11+
.DS_Store
12+
.claude/

Dockerfile

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Cross-platform development image for RSScript.
2+
#
3+
# The workspace is edition 2024, which requires Rust >= 1.85; `rust:1-bookworm`
4+
# tracks the latest stable 1.x and always satisfies that. Pin to a concrete tag
5+
# (e.g. `rust:1.88-bookworm`) if you want a fully reproducible toolchain.
6+
#
7+
# The source tree is NOT copied into the image — it is bind-mounted at runtime
8+
# (see compose.yaml) so edits on the host are seen instantly on every platform.
9+
# This image only provides the toolchain and system libraries.
10+
FROM rust:1-bookworm
11+
12+
# System libraries needed to build the workspace and the Rust packages that
13+
# RSScript lowers to. Everything here uses rustls/ring (no OpenSSL) and a
14+
# source-bundled SQLite, so the list is just a C/C++ toolchain plus the usual
15+
# fetch/build helpers:
16+
# build-essential, cmake -> `ring` (rustls) and `rusqlite` (bundled SQLite)
17+
# pkg-config -> -sys crate probing
18+
# git, curl, ca-certificates -> fetching crates and tools over HTTPS
19+
RUN apt-get update \
20+
&& apt-get install -y --no-install-recommends \
21+
build-essential \
22+
pkg-config \
23+
cmake \
24+
git \
25+
curl \
26+
ca-certificates \
27+
&& rm -rf /var/lib/apt/lists/*
28+
29+
# Toolchain components used by the test/lint flow, and cargo-nextest (the test
30+
# runner the `rss test` command and CI use). Prefer the prebuilt nextest binary
31+
# per architecture (works on amd64 and Apple-Silicon/arm64); fall back to a
32+
# source build on other arches.
33+
RUN rustup component add clippy rustfmt \
34+
&& set -eux; \
35+
case "$(uname -m)" in \
36+
x86_64) url="https://get.nexte.st/latest/linux" ;; \
37+
aarch64) url="https://get.nexte.st/latest/linux-arm" ;; \
38+
*) url="" ;; \
39+
esac; \
40+
if [ -n "$url" ]; then \
41+
curl -LsSf "$url" | tar zxf - -C "${CARGO_HOME:-/usr/local/cargo}/bin"; \
42+
else \
43+
cargo install cargo-nextest --locked; \
44+
fi
45+
46+
# The base image puts the toolchain on PATH via the container environment, but a
47+
# login shell (`bash -l`, some devcontainer setups) re-derives PATH from
48+
# /etc/profile and would drop it. Add a profile snippet so cargo/rustc/nextest
49+
# are on PATH for every shell flavor.
50+
RUN printf 'export PATH="%s/bin:$PATH"\n' "${CARGO_HOME:-/usr/local/cargo}" \
51+
> /etc/profile.d/rust-cargo.sh
52+
53+
WORKDIR /work
54+
55+
# `rss` (and the test suite) compiles generated Rust packages at runtime, so the
56+
# container keeps the full toolchain available. Default to an interactive shell;
57+
# compose overrides the command for one-off runs.
58+
CMD ["bash"]

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,13 @@ fn main() -> Unit {
511511

512512
Development discipline and the full local verification flow live in [DEVELOPMENT.md](docs/DEVELOPMENT.md): spec prerequisites first, self-hosted validation as the main pressure test, no fixture-only shortcuts, and a broad-first testing loop.
513513

514+
Prefer a containerized toolchain? [DOCKER.md](docs/DOCKER.md) gives an identical, reproducible build/test environment on macOS, Windows, and Linux (and VS Code / Codespaces) with no local Rust install:
515+
516+
```sh
517+
docker compose build
518+
docker compose run --rm dev cargo run --bin rss -- test --all
519+
```
520+
514521
---
515522

516523
## Roadmap

compose.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Cross-platform development environment for RSScript.
2+
#
3+
# Quick start:
4+
# docker compose build # build the dev image
5+
# docker compose run --rm dev cargo run --bin rss -- test --all
6+
# docker compose run --rm dev bash # interactive shell
7+
#
8+
# The repo is bind-mounted at /work, so host edits are picked up immediately.
9+
# Build artifacts and crate caches live in named volumes (not on the bind mount)
10+
# so compilation persists between runs and stays fast on macOS/Windows.
11+
services:
12+
dev:
13+
build: .
14+
image: rsscript-dev
15+
working_dir: /work
16+
volumes:
17+
- .:/work
18+
# Keep target/ and the cargo caches off the (slow, host-backed) bind mount
19+
# and out of the host tree. Mounting only the cache subdirs of CARGO_HOME
20+
# preserves the toolchain and nextest installed under /usr/local/cargo/bin.
21+
- target:/work/target
22+
- cargo-registry:/usr/local/cargo/registry
23+
- cargo-git:/usr/local/cargo/git
24+
environment:
25+
CARGO_TERM_COLOR: always
26+
# The workspace target lives in a volume; point every nested build at it
27+
# too so generated-package builds share one warm cache.
28+
CARGO_HOME: /usr/local/cargo
29+
# Keep an interactive TTY for `docker compose run dev bash`.
30+
tty: true
31+
stdin_open: true
32+
command: bash
33+
34+
volumes:
35+
target:
36+
cargo-registry:
37+
cargo-git:

docs/DOCKER.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Containerized development
2+
3+
RSScript builds and runs identically on macOS, Windows, and Linux through a
4+
single Docker toolchain image. The container carries the Rust toolchain, the
5+
test runner, and the system libraries the workspace needs; your checkout is
6+
bind-mounted in, so edits on the host take effect immediately.
7+
8+
This is the recommended setup for contributors who do not want to install the
9+
Rust toolchain and C build dependencies locally, and for keeping builds
10+
reproducible across platforms.
11+
12+
## Prerequisites
13+
14+
- [Docker](https://docs.docker.com/get-docker/) with Compose v2 (`docker
15+
compose`). Docker Desktop (macOS/Windows) or Docker Engine (Linux) both work.
16+
- That's all — no local Rust, C compiler, or SQLite needed.
17+
18+
## Quick start
19+
20+
```sh
21+
# Build the dev image (first run downloads the toolchain; later runs are cached).
22+
docker compose build
23+
24+
# Run the full test suite exactly as CI does.
25+
docker compose run --rm dev cargo run --bin rss -- test --all
26+
27+
# Open an interactive shell in the toolchain.
28+
docker compose run --rm dev bash
29+
```
30+
31+
Inside the shell (or via `docker compose run --rm dev <cmd>`) every normal
32+
workflow is available:
33+
34+
```sh
35+
cargo run --bin rss -- test --all # project test runner (nextest-backed)
36+
cargo nextest run -p rsscript # run one crate's tests
37+
cargo nextest run -p rsscript --features native-jit # Cranelift JIT tier
38+
cargo clippy --all-targets # lints
39+
cargo fmt --all # format
40+
cargo run --bin rss -- <args> # drive the rss CLI
41+
```
42+
43+
## How it is wired
44+
45+
- **Image** (`Dockerfile`): `rust:1-bookworm` plus `build-essential`, `cmake`,
46+
and `pkg-config` (for `ring`/rustls and the bundled-SQLite `rusqlite`),
47+
`clippy`/`rustfmt`, and `cargo-nextest`. The workspace uses rustls/ring
48+
throughout, so no OpenSSL is required.
49+
- **Source** is bind-mounted at `/work` (see `compose.yaml`) — not copied into
50+
the image — so host edits are picked up with no rebuild.
51+
- **Caches** live in named volumes, deliberately kept off the host bind mount so
52+
compilation persists between runs and stays fast on macOS/Windows:
53+
- `target``/work/target`
54+
- `cargo-registry``/usr/local/cargo/registry`
55+
- `cargo-git``/usr/local/cargo/git`
56+
57+
Reset a cache with `docker compose down -v` (removes all three volumes).
58+
59+
## Reproducible toolchain
60+
61+
The image tracks the latest stable Rust 1.x (`rust:1-bookworm`), which always
62+
satisfies the workspace's edition-2024 requirement (Rust ≥ 1.85). For a fully
63+
pinned toolchain, change the base tag in `Dockerfile` to a concrete version such
64+
as `rust:1.88-bookworm` and rebuild.
65+
66+
## VS Code / Codespaces
67+
68+
`.devcontainer/devcontainer.json` reuses the same compose service. In VS Code,
69+
run **Dev Containers: Reopen in Container**; on GitHub, **Create codespace**.
70+
You get rust-analyzer (clippy-backed), TOML, and LLDB wired to the identical
71+
toolchain and caches.
72+
73+
## Apple Silicon and other architectures
74+
75+
The image builds natively on both `amd64` and `arm64` (Apple Silicon); the
76+
nextest install picks the matching prebuilt binary and falls back to a source
77+
build elsewhere. No extra configuration is needed.

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ LLMs); everything else lives here.
1313
| [Review_Evidence_IR_Spec_v0.2.md](Review_Evidence_IR_Spec_v0.2.md) | REIR — the review-evidence IR consumed by `--reir` tooling and CI gates. |
1414
| [ARCHITECTURE.md](ARCHITECTURE.md) | Module boundaries of the checker/lowering implementation. |
1515
| [DEVELOPMENT.md](DEVELOPMENT.md) | Local verification flow and development discipline. |
16+
| [DOCKER.md](DOCKER.md) | Containerized, cross-platform dev environment (Docker / VS Code / Codespaces). |
1617

1718
## Implementation-planning specs (not yet normative)
1819

0 commit comments

Comments
 (0)