diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..b52fc61c3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +# Heavy build outputs — must never reach the build context. `target/` alone is +# >100 GB on a dev machine. +target/ +node_modules/ +dist/ +runs/ + +# Per-host scratch the pi codebase uses for parallel agents / worktrees. +.fallow/ +.worktrees/ +.wt/ +.opencode/ +.pi_config/ +.omp/plugins/ + +# VCS, editors, IDEs — irrelevant to the build, churn on every IDE keystroke. +.git/ +.npm/ +.vscode/ +.zed/ +.idea/ + +# OS + transient noise. Finder rewrites .DS_Store whenever you peek at a +# folder; profilers drop `CPU.*` blobs at random times. Letting any of these +# into the build context busts BuildKit's content hash and forces a full +# native rebuild for no good reason. +.DS_Store +*.swp +*.swo +*~ +*.tmp + +# Logs + profiling artifacts. +*.log +*.cpuprofile +*.heapprofile +*.heapsnapshot +CPU.* + +# Build / test side outputs. +*.tsbuildinfo +coverage/ +.nyc_output/ +__pycache__/ +compaction-results/ +changes/ + +# Generated files (the in-image build regenerates them). +packages/coding-agent/src/internal-urls/docs-index.generated.ts +packages/natives/native/.build/ +packages/natives/native/pi_natives.darwin-*.node +packages/natives/native/pi_natives.dev.node +packages/ai/test/.temp-images/ +python/omp-rpc/src/omp_rpc.egg-info/ + +# Scratch files the repo creates ad-hoc. +syntax.jsonl +out.jsonl +out.html +pi-*.html + +# Secrets. Should never be in the image regardless. +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..8634a9a07 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,100 @@ +# syntax=docker/dockerfile:1.7 +############################################################################### +# oh-my-pi — build-artifacts image +# +# Produces, in `/out/`, the cross-host build outputs that downstream consumers +# bake into their runtime images: +# +# - pi_natives.linux-.node — N-API addon compiled from `crates/pi-natives` +# - omp_rpc--py3-none-any.whl — Python RPC wheel from `python/omp-rpc` +# +# This image deliberately has no entrypoint and no apt-installed extras: it is +# meant to be referenced as a `COPY --from=` stage by other Dockerfiles. +# +# Build: +# docker build -t oh-my-pi/artifacts:dev . +# +# Consume from another Dockerfile: +# ARG PI_ARTIFACTS_IMAGE=oh-my-pi/artifacts:dev +# FROM ${PI_ARTIFACTS_IMAGE} AS pi-artifacts +# COPY --from=pi-artifacts /out/pi_natives.linux-*.node /opt/bun/bin/ +# COPY --from=pi-artifacts /out/*.whl /tmp/wheels/ +############################################################################### + +############################ +# 1) natives-builder — Rust + Bun → pi_natives.linux-.node +############################ +FROM rust:1.86-slim-bookworm AS natives-builder + +ARG BUN_VERSION=1.3.14 +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: workspace manifests + lockfiles only ─────────────────────────── +# Editing source files (under `packages//src/…` or `crates//src/…`) won't +# bust the `bun install` layer below, because none of those globs match. Only +# touching a `package.json`, `Cargo.toml`, or a root lockfile invalidates this +# layer. `--parents` preserves the matched path under /pi/ (BuildKit 1.7+). +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 \ + crates/*/Cargo.toml \ + /pi/ + +# ─── Layer 2: hydrate node_modules from the manifests above ────────────────── +RUN bun install --frozen-lockfile --ignore-scripts + +# ─── Layer 3: full source ──────────────────────────────────────────────────── +# `.dockerignore` keeps `target/`, `node_modules/`, `dist/`, `runs/`, editor / +# OS noise (`.DS_Store`, `CPU.*`, `*.cpuprofile`, …), and pre-built host-only +# natives output out of the build context. node_modules from Layer 2 is +# preserved across this COPY because it's never in the context to begin with. +COPY . /pi/ + +# ─── Layer 4: compile pi-natives to a Linux N-API addon ────────────────────── +# Persistent caches make repeat builds incremental even when the source layer +# invalidates: cargo's package index + git-deps + the workspace's 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) python-builder — omp-rpc wheel +############################ +FROM python:3.12-slim-bookworm AS python-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/omp-rpc /src +RUN python -m build --wheel --outdir /out + +############################ +# 3) artifacts — final image, nothing but the two outputs. +############################ +FROM scratch AS artifacts +COPY --from=natives-builder /out/pi_natives.linux-*.node /out/ +COPY --from=python-builder /out/*.whl /out/