mecha10-cli 0.1.47

Mecha10 CLI tool
Documentation
# Dockerfile for cross-compiling mecha10 robot projects
#
# FAST BUILDS: Framework nodes (@mecha10/*) are NOT compiled here.
# They are downloaded as pre-built binaries at runtime by the robot binary.
# This dramatically reduces build time (from ~15min to ~2min).
#
# What gets compiled:
#   - The thin orchestrator binary
#   - Custom nodes (if any in your project)
#   - mecha10-node-resolver (for runtime node downloads)
#
# What does NOT get compiled (downloaded at runtime instead):
#   - @mecha10/speaker, @mecha10/motor, @mecha10/teleop, etc.
#
# Supports multiple architectures:
#   - x86_64 (linux/amd64) - Desktop, servers
#   - aarch64 (linux/arm64) - Raspberry Pi 4/5, Jetson, Apple Silicon
#
# Uses cargo-chef for dependency caching (faster rebuilds)
# See docs/guides/FASTER_BUILDS.md
#
# Usage:
#   # Build for x86_64 (default)
#   docker build -f docker/robot-builder.Dockerfile -t {{project_name}}-builder .
#
#   # Build for aarch64
#   docker build -f docker/robot-builder.Dockerfile \
#     --build-arg TARGET_ARCH=aarch64 \
#     --platform linux/arm64 \
#     -t {{project_name}}-builder .
#
#   # Extract binary
#   docker create --name extract {{project_name}}-builder
#   docker cp extract:/output/{{project_name}} ./dist/{{project_name}}
#   docker cp extract:/output/mecha10.json ./dist/mecha10.json
#   docker rm extract
#
# The binary will be at ./dist/{{project_name}}

# syntax=docker/dockerfile:1

ARG TARGET_ARCH=x86_64

# ==============================================================================
# Chef stage - install cargo-chef
# ==============================================================================
FROM --platform=$BUILDPLATFORM rustlang/rust:nightly-bookworm AS chef

ARG TARGET_ARCH

WORKDIR /build

# Install minimal dependencies (no heavy ML libs needed - nodes are pre-built)
RUN apt-get update && apt-get install -y \
    pkg-config \
    libssl-dev \
    mold \
    && rm -rf /var/lib/apt/lists/*

# Install cross-compilation toolchain for aarch64 if needed
RUN if [ "$TARGET_ARCH" = "aarch64" ]; then \
        dpkg --add-architecture arm64 && \
        apt-get update && apt-get install -y \
            gcc-aarch64-linux-gnu \
            g++-aarch64-linux-gnu \
            libc6-dev-arm64-cross \
            libssl-dev:arm64 \
        && rm -rf /var/lib/apt/lists/* \
        && rustup target add aarch64-unknown-linux-gnu; \
    fi

# Set up cross-compilation environment for aarch64
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
ENV PKG_CONFIG_ALLOW_CROSS=1
ENV PKG_CONFIG_PATH_aarch64_unknown_linux_gnu=/usr/lib/aarch64-linux-gnu/pkgconfig

# Install cargo-chef
RUN cargo install cargo-chef

# ==============================================================================
# Planner stage - generate dependency recipe
# ==============================================================================
FROM chef AS planner

# Copy project files for recipe generation
COPY Cargo.toml Cargo.lock ./
COPY src/ src/
COPY build.rs ./

RUN cargo chef prepare --recipe-path recipe.json

# ==============================================================================
# Builder stage - compile the Rust binary
# ==============================================================================
FROM chef AS builder

ARG TARGET_ARCH
ARG TARGETPLATFORM

# Copy recipe and build dependencies only (this layer is cached)
COPY --from=planner /build/recipe.json recipe.json

# Build dependencies - this is cached unless Cargo.toml/lock changes
# FAST: Only builds mecha10-core, mecha10-node-resolver, and standard libs
# NO framework nodes compiled (they're downloaded at runtime)
RUN --mount=type=cache,target=/usr/local/cargo/registry \
    if [ "$TARGET_ARCH" = "aarch64" ]; then \
        cargo chef cook --release --recipe-path recipe.json --target aarch64-unknown-linux-gnu; \
    else \
        cargo chef cook --release --recipe-path recipe.json; \
    fi

# Copy project files
COPY Cargo.toml Cargo.lock ./
COPY src/ src/
COPY build.rs ./
COPY mecha10.json ./

# Copy optional directories if they exist (will be skipped if not present)
COPY behavior[s]/ behaviors/
COPY config[s]/ configs/
COPY node[s]/ nodes/

# Build for robot target with release optimizations
# FAST: Only compiles thin orchestrator + custom nodes
# Framework nodes are NOT compiled - they're downloaded at runtime
RUN --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/build/target \
    if [ "$TARGET_ARCH" = "aarch64" ]; then \
        cargo build --release --no-default-features --features target-robot \
            --target aarch64-unknown-linux-gnu && \
        mkdir -p /output && \
        cp /build/target/aarch64-unknown-linux-gnu/release/{{project_name}} /output/; \
    else \
        cargo build --release --no-default-features --features target-robot && \
        mkdir -p /output && \
        cp /build/target/release/{{project_name}} /output/; \
    fi

# Copy mecha10.json and configs to output
RUN cp /build/mecha10.json /output/ && \
    if [ -d /build/configs ]; then cp -r /build/configs /output/; fi

# ==============================================================================
# Output stage - minimal image with just the binary
# ==============================================================================
FROM debian:bookworm-slim

ARG TARGET_ARCH

# Minimal runtime dependencies
# Note: Framework nodes have their own dependencies and are downloaded separately
RUN apt-get update && apt-get install -y \
    ca-certificates \
    libssl3 \
    && rm -rf /var/lib/apt/lists/*

# Copy binary and config from builder
COPY --from=builder /output/ /output/

# For runtime use (optional - mainly for extraction)
WORKDIR /output
RUN chmod +x /output/{{project_name}}

# Note: On first run, the binary will download framework nodes to ~/.mecha10/bin/
# This happens automatically and nodes are cached for subsequent runs.
ENTRYPOINT ["/output/{{project_name}}"]