188 lines
6.9 KiB
Docker
188 lines
6.9 KiB
Docker
# ---- Stage 0: QEMU .so + ROM binaries ----
|
|
# Two modes:
|
|
# 1. Local: place files in prebuilt/qemu/ (from build-qemu.sh or manual copy)
|
|
# 2. CI/CD: downloads from GitHub Release (requires qemu-lcgamboa repo to be public)
|
|
# The COPY always runs; the RUN only downloads missing files.
|
|
FROM ubuntu:22.04 AS qemu-provider
|
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
ARG QEMU_RELEASE_URL=https://github.com/davidmonterocrespo24/velxio/releases/download/qemu-prebuilt
|
|
|
|
# Copy the prebuilt directory (may contain .so+ROM files or just the .gitkeep)
|
|
RUN mkdir -p /qemu
|
|
COPY prebuilt/qemu/ /qemu/
|
|
|
|
# Download any missing files from GitHub Release
|
|
RUN cd /qemu \
|
|
&& for f in libqemu-xtensa.so libqemu-riscv32.so esp32-v3-rom.bin esp32-v3-rom-app.bin esp32c3-rom.bin; do \
|
|
if [ ! -f "$f" ]; then \
|
|
echo "Downloading $f from release..." ; \
|
|
curl -fSL -o "$f" "${QEMU_RELEASE_URL}/$f" ; \
|
|
else \
|
|
echo "Using local $f ($(stat -c%s "$f") bytes)" ; \
|
|
fi ; \
|
|
done \
|
|
&& ls -lh /qemu/
|
|
|
|
|
|
# ---- Stage 0.5: ESP-IDF toolchain for ESP32 compilation ----
|
|
FROM debian:bookworm-slim AS espidf-builder
|
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
git wget flex bison gperf python3 python3-pip python3-venv \
|
|
cmake ninja-build ccache libffi-dev libssl-dev \
|
|
libusb-1.0-0 ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install ESP-IDF 4.4.7 (matches Arduino ESP32 core 2.0.17 / lcgamboa QEMU ROM)
|
|
RUN git clone -b v4.4.7 --recursive --depth=1 --shallow-submodules \
|
|
https://github.com/espressif/esp-idf.git /opt/esp-idf
|
|
|
|
WORKDIR /opt/esp-idf
|
|
|
|
# Install toolchains for esp32 (Xtensa) and esp32c3 (RISC-V) only
|
|
RUN ./install.sh esp32,esp32c3
|
|
|
|
# Clean up large unnecessary files to reduce image size
|
|
RUN rm -rf .git docs examples \
|
|
&& find /root/.espressif -name '*.tar.*' -delete 2>/dev/null || true
|
|
|
|
# Install Arduino-as-component for full Arduino API support in ESP-IDF builds
|
|
RUN git clone --branch 2.0.17 --depth=1 --recursive --shallow-submodules \
|
|
https://github.com/espressif/arduino-esp32.git /opt/arduino-esp32 \
|
|
&& rm -rf /opt/arduino-esp32/.git
|
|
|
|
|
|
# ---- Stage 1: Build frontend and wokwi-libs ----
|
|
FROM node:20 AS frontend-builder
|
|
|
|
WORKDIR /app
|
|
|
|
# Clone wokwi-libs fresh from upstream to avoid stale submodule pointers.
|
|
# git is pre-installed in the node:20 Debian image.
|
|
RUN git clone --depth=1 https://github.com/wokwi/avr8js.git wokwi-libs/avr8js \
|
|
&& git clone --depth=1 https://github.com/wokwi/rp2040js.git wokwi-libs/rp2040js \
|
|
&& git clone --depth=1 https://github.com/wokwi/wokwi-elements.git wokwi-libs/wokwi-elements \
|
|
&& git clone --depth=1 https://github.com/wokwi/wokwi-boards.git wokwi-libs/wokwi-boards
|
|
|
|
# Build avr8js
|
|
WORKDIR /app/wokwi-libs/avr8js
|
|
RUN npm install && npm run build --if-present
|
|
|
|
# Build rp2040js (may have no build script on some commits)
|
|
WORKDIR /app/wokwi-libs/rp2040js
|
|
RUN npm install && npm run build --if-present
|
|
|
|
# Build wokwi-elements
|
|
WORKDIR /app/wokwi-libs/wokwi-elements
|
|
RUN npm install && npm run build --if-present
|
|
|
|
# Build frontend
|
|
# components-metadata.json is already committed; skip generate:metadata
|
|
# (it requires wokwi-elements/src which isn't needed at runtime)
|
|
#
|
|
# VITE_BASE_PATH: sub-path prefix for assets (default "/" for standalone)
|
|
# VITE_API_BASE: API endpoint prefix (default "/api" for standalone)
|
|
ARG VITE_BASE_PATH=/
|
|
ARG VITE_API_BASE=/api
|
|
ENV VITE_BASE_PATH=${VITE_BASE_PATH}
|
|
ENV VITE_API_BASE=${VITE_API_BASE}
|
|
|
|
WORKDIR /app
|
|
COPY frontend/ frontend/
|
|
WORKDIR /app/frontend
|
|
RUN npm install && npm run build:docker
|
|
|
|
|
|
# ---- Stage 2: Final Production Image ----
|
|
FROM python:3.12-slim
|
|
|
|
# Install system dependencies, nginx, and QEMU .so runtime libraries
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
curl \
|
|
ca-certificates \
|
|
nginx \
|
|
libglib2.0-0 \
|
|
libgcrypt20 \
|
|
libslirp0 \
|
|
libpixman-1-0 \
|
|
libfdt1 \
|
|
cmake \
|
|
ninja-build \
|
|
libusb-1.0-0 \
|
|
git \
|
|
&& apt-get clean \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
&& pip install --no-cache-dir packaging
|
|
|
|
# Install arduino-cli into /usr/local/bin directly (avoids touching /bin)
|
|
RUN curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh \
|
|
| BINDIR=/usr/local/bin sh
|
|
|
|
# Only install arduino-cli binary here. Core installation (arduino:avr,
|
|
# rp2040:rp2040) is done at first boot by entrypoint.sh and persisted
|
|
# in the mounted /root/.arduino15 volume.
|
|
# ESP32 compilation uses ESP-IDF instead of arduino-cli.
|
|
|
|
WORKDIR /app
|
|
|
|
# Data directory for persistent SQLite database (mounted as a volume at runtime)
|
|
RUN mkdir -p /app/data
|
|
|
|
# Install Python backend dependencies
|
|
COPY backend/requirements.txt .
|
|
RUN pip install --no-cache-dir -r requirements.txt
|
|
|
|
# Copy backend application code
|
|
COPY backend/app/ ./app/
|
|
|
|
# Setup Nginx configuration — remove default site so our config is the only server
|
|
RUN rm -f /etc/nginx/sites-enabled/default
|
|
COPY deploy/nginx.conf /etc/nginx/conf.d/default.conf
|
|
|
|
# Copy built frontend assets from builder stage
|
|
COPY --from=frontend-builder /app/frontend/dist /usr/share/nginx/html
|
|
|
|
# Copy and configure entrypoint script (fix Windows CRLF → LF)
|
|
COPY deploy/entrypoint.sh /app/entrypoint.sh
|
|
RUN sed -i 's/\r$//' /app/entrypoint.sh && chmod +x /app/entrypoint.sh
|
|
|
|
# ── ESP32 emulation: pre-built QEMU .so + ROM binaries ──────────────────────
|
|
# Downloaded from GitHub Release (public — no access to qemu-lcgamboa needed)
|
|
# libqemu-xtensa.so → ESP32 / ESP32-S3 (Xtensa LX6/LX7)
|
|
# libqemu-riscv32.so → ESP32-C3 (RISC-V RV32IMC)
|
|
# esp32-v3-rom*.bin → boot/app ROM images required by esp32-picsimlab machine
|
|
# esp32c3-rom.bin → ROM image required by esp32c3-picsimlab machine
|
|
# NOTE: ROM files must live in the same directory as the .so (worker passes -L
|
|
# to QEMU pointing at os.path.dirname(lib_path))
|
|
RUN mkdir -p /app/lib
|
|
COPY --from=qemu-provider /qemu/ /app/lib/
|
|
|
|
# Activate ESP32 emulation
|
|
# QEMU_ESP32_LIB → Xtensa library (ESP32, ESP32-S3)
|
|
# QEMU_RISCV32_LIB → RISC-V library (ESP32-C3 and variants)
|
|
ENV QEMU_ESP32_LIB=/app/lib/libqemu-xtensa.so
|
|
ENV QEMU_RISCV32_LIB=/app/lib/libqemu-riscv32.so
|
|
|
|
# ── ESP-IDF toolchain for ESP32 compilation ──────────────────────────────────
|
|
# Copied from espidf-builder stage: IDF framework + cross-compiler toolchains
|
|
COPY --from=espidf-builder /opt/esp-idf /opt/esp-idf
|
|
COPY --from=espidf-builder /root/.espressif /root/.espressif
|
|
|
|
COPY --from=espidf-builder /opt/arduino-esp32 /opt/arduino-esp32
|
|
|
|
ENV IDF_PATH=/opt/esp-idf
|
|
ENV IDF_TOOLS_PATH=/root/.espressif
|
|
ENV ARDUINO_ESP32_PATH=/opt/arduino-esp32
|
|
|
|
# Install ESP-IDF Python dependencies using the final image's Python
|
|
# The requirements.txt has version constraints required by ESP-IDF 4.4.x
|
|
RUN grep -v 'esp-windows-curses' /opt/esp-idf/requirements.txt \
|
|
| pip install --no-cache-dir -r /dev/stdin
|
|
|
|
EXPOSE 80
|
|
|
|
CMD ["/app/entrypoint.sh"]
|