# syntax=docker/dockerfile:1.6
# Multi-stage Dockerfile for RustFS - LOCAL DEVELOPMENT ONLY
#
# IMPORTANT: This Dockerfile builds RustFS from source for local development and testing.
# CI/CD uses the production Dockerfile with prebuilt binaries instead.
#
# Example:
#   docker build -f Dockerfile.source -t rustfs:dev-local .
#   docker run --rm -p 9000:9000 rustfs:dev-local
#
# Supports cross-compilation for amd64 and arm64 via TARGETPLATFORM.

ARG TARGETPLATFORM
ARG BUILDPLATFORM

# -----------------------------
# Build stage
# -----------------------------
FROM rust:1.88-bookworm AS builder

# Re-declare args after FROM
ARG TARGETPLATFORM
ARG BUILDPLATFORM

# Debug: print platforms
RUN echo "Build info -> BUILDPLATFORM=${BUILDPLATFORM}, TARGETPLATFORM=${TARGETPLATFORM}"

# Install build toolchain and headers
# Use distro packages for protoc/flatc to avoid host-arch mismatch
RUN set -eux; \
    export DEBIAN_FRONTEND=noninteractive; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
    build-essential \
    ca-certificates \
    curl \
    git \
    pkg-config \
    libssl-dev \
    lld \
    protobuf-compiler \
    flatbuffers-compiler; \
    rm -rf /var/lib/apt/lists/*

# Optional: cross toolchain for aarch64 (only when targeting linux/arm64)
RUN set -eux; \
    if [ "${TARGETPLATFORM:-linux/amd64}" = "linux/arm64" ]; then \
    export DEBIAN_FRONTEND=noninteractive; \
    apt-get update; \
    apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu; \
    rm -rf /var/lib/apt/lists/*; \
    fi

# Add Rust targets based on TARGETPLATFORM
RUN set -eux; \
    case "${TARGETPLATFORM:-linux/amd64}" in \
    linux/amd64) rustup target add x86_64-unknown-linux-gnu ;; \
    linux/arm64) rustup target add aarch64-unknown-linux-gnu ;; \
    *) echo "Unsupported TARGETPLATFORM=${TARGETPLATFORM}" >&2; exit 1 ;; \
    esac

# Cross-compilation environment (used only when targeting aarch64)
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
ENV CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
ENV CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++

WORKDIR /usr/src/rustfs

# Layered copy to maximize caching:
# 1) top-level manifests
COPY Cargo.toml Cargo.lock ./
# 2) workspace member manifests (adjust if workspace layout changes)
COPY rustfs/Cargo.toml rustfs/Cargo.toml
COPY crates/*/Cargo.toml crates/
COPY cli/rustfs-gui/Cargo.toml cli/rustfs-gui/Cargo.toml

# Pre-fetch dependencies for better caching
RUN --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/usr/local/cargo/git \
    cargo fetch --locked || true

# 3) copy full sources (this is the main cache invalidation point)
COPY . .

# Cargo build configuration for lean release artifacts
ENV CARGO_NET_GIT_FETCH_WITH_CLI=true \
    CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse \
    CARGO_INCREMENTAL=0 \
    CARGO_PROFILE_RELEASE_DEBUG=false \
    CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off \
    CARGO_PROFILE_RELEASE_STRIP=symbols

# Generate protobuf/flatbuffers code (uses protoc/flatc from distro)
RUN --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/usr/local/cargo/git \
    --mount=type=cache,target=/usr/src/rustfs/target \
    cargo run --bin gproto

# Build RustFS (target depends on TARGETPLATFORM)
RUN --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/usr/local/cargo/git \
    --mount=type=cache,target=/usr/src/rustfs/target \
    set -eux; \
    case "${TARGETPLATFORM:-linux/amd64}" in \
    linux/amd64) \
    echo "Building for x86_64-unknown-linux-gnu"; \
    cargo build --release --locked --target x86_64-unknown-linux-gnu --bin rustfs -j "$(nproc)"; \
    install -m 0755 target/x86_64-unknown-linux-gnu/release/rustfs /usr/local/bin/rustfs \
    ;; \
    linux/arm64) \
    echo "Building for aarch64-unknown-linux-gnu"; \
    cargo build --release --locked --target aarch64-unknown-linux-gnu --bin rustfs -j "$(nproc)"; \
    install -m 0755 target/aarch64-unknown-linux-gnu/release/rustfs /usr/local/bin/rustfs \
    ;; \
    *) \
    echo "Unsupported TARGETPLATFORM=${TARGETPLATFORM}" >&2; exit 1 \
    ;; \
    esac

# -----------------------------
# Runtime stage (Ubuntu minimal)
# -----------------------------
FROM ubuntu:22.04

ARG BUILD_DATE
ARG VCS_REF

LABEL name="RustFS (dev-local)" \
    maintainer="RustFS Team" \
    build-date="${BUILD_DATE}" \
    vcs-ref="${VCS_REF}" \
    description="RustFS - local development image built from source (NOT for production)."

# Minimal runtime deps: certificates + tzdata + coreutils (for chroot --userspec)
RUN set -eux; \
    export DEBIAN_FRONTEND=noninteractive; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
    ca-certificates \
    tzdata \
    coreutils; \
    rm -rf /var/lib/apt/lists/*

# Create a conventional runtime user/group (final switch happens in entrypoint via chroot --userspec)
RUN set -eux; \
    groupadd -g 1000 rustfs; \
    useradd -u 1000 -g rustfs -M -s /usr/sbin/nologin rustfs

WORKDIR /app

# Prepare data/log directories with sane defaults
RUN set -eux; \
    mkdir -p /data /logs; \
    chown -R rustfs:rustfs /data /logs /app; \
    chmod 0750 /data /logs

# Copy the freshly built binary and the entrypoint
COPY --from=builder /usr/local/bin/rustfs /usr/bin/rustfs
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /usr/bin/rustfs /entrypoint.sh

# Default environment (override in docker run/compose as needed)
ENV RUSTFS_ADDRESS=":9000" \
    RUSTFS_ACCESS_KEY="rustfsadmin" \
    RUSTFS_SECRET_KEY="rustfsadmin" \
    RUSTFS_CONSOLE_ENABLE="true" \
    RUSTFS_VOLUMES="/data" \
    RUST_LOG="warn" \
    RUSTFS_OBS_LOG_DIRECTORY="/logs" \
    RUSTFS_SINKS_FILE_PATH="/logs" \
    RUSTFS_USERNAME="rustfs" \
    RUSTFS_GROUPNAME="rustfs" \
    RUSTFS_UID="1000" \
    RUSTFS_GID="1000"

EXPOSE 9000
VOLUME ["/data", "/logs"]

# Keep root here; entrypoint will drop privileges using chroot --userspec
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/usr/bin/rustfs"]
