# syntax=docker/dockerfile:1.6 # # ecu-tests image — mock-only by default, hardware variant via: # --build-arg INCLUDE_MELEXIS=1 # # Build context = repository root. Always invoke from there: # # docker build -f docker/Dockerfile -t ecu-tests:mock . # # DOCKER_BUILDKIT=1 docker build \ # -f docker/Dockerfile -t ecu-tests:hw \ # --build-arg INCLUDE_MELEXIS=1 \ # --secret id=melexis_tarball,src=./melexis-pkgs.tar.gz \ # . # # See docs/20_docker_image.md for the full reference, including how # to produce melexis-pkgs.tar.gz from a licensed Melexis IDE install. ARG PYTHON_VERSION=3.11 # ────────────────────────────────────────────────────────────────────── # Stage 1: builder — install deps into a venv under /opt/venv # ────────────────────────────────────────────────────────────────────── FROM python:${PYTHON_VERSION}-slim AS builder ARG INCLUDE_MELEXIS=0 # Build-time OS deps: # build-essential, libffi-dev — for any wheel that needs to compile # libusb-1.0-0 — pyserial uses it on some adapters # git — VCS deps in requirements.txt (if any) RUN apt-get update \ && apt-get install -y --no-install-recommends \ build-essential \ libffi-dev \ libusb-1.0-0 \ git \ && rm -rf /var/lib/apt/lists/* ENV PYTHONDONTWRITEBYTECODE=1 \ PIP_NO_CACHE_DIR=1 \ PIP_DISABLE_PIP_VERSION_CHECK=1 RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:${PATH}" WORKDIR /build COPY requirements.txt ./ RUN pip install --upgrade pip wheel \ && pip install -r requirements.txt # Melexis packages — passed in via BuildKit secret so the proprietary # tarball never lands in an image layer. Skipped entirely when # INCLUDE_MELEXIS=0 (the mock-only path). RUN --mount=type=secret,id=melexis_tarball,required=false \ if [ "$INCLUDE_MELEXIS" = "1" ]; then \ set -e; \ test -s /run/secrets/melexis_tarball \ || { echo 'INCLUDE_MELEXIS=1 but no melexis_tarball secret bound'; exit 2; }; \ SITE_PACKAGES=$(python -c "import site; print(site.getsitepackages()[0])"); \ tar -xzf /run/secrets/melexis_tarball -C "$SITE_PACKAGES"; \ python -c "import pylin, pymumclient; print('melexis pkgs OK')"; \ fi # ────────────────────────────────────────────────────────────────────── # Stage 2: runtime — slim image with the venv + repo # ────────────────────────────────────────────────────────────────────── FROM python:${PYTHON_VERSION}-slim AS runtime # Runtime-only OS deps. tini handles signal forwarding so Ctrl-C tears # pytest down cleanly. RUN apt-get update \ && apt-get install -y --no-install-recommends \ libusb-1.0-0 \ ca-certificates \ tini \ && rm -rf /var/lib/apt/lists/* # Pull the prebuilt venv (with Melexis pkgs if requested) from builder. COPY --from=builder /opt/venv /opt/venv ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PATH="/opt/venv/bin:${PATH}" # The repo. .dockerignore at the build-context root excludes .venv, # reports/, vendor/BabyLIN*, __pycache__, etc. WORKDIR /workspace COPY . /workspace # Reports volume so artifacts survive the container's lifetime. RUN mkdir -p /reports VOLUME ["/reports"] # Drop root. Inherit the host's serial group at runtime via # `--group-add dialout` when you bind-mount /dev/ttyUSB*. RUN useradd -m -u 1000 -s /bin/bash tester \ && chown -R tester:tester /workspace /reports USER tester ENTRYPOINT ["/usr/bin/tini", "--"] # Safe default: collect-only of the non-hardware suite. An accidental # `docker run ecu-tests:hw` will list tests, not fire bench actions. CMD ["pytest", "-m", "not hardware", "--collect-only", "-q"]