FROM ghcr.io/astral-sh/uv:0.13.7 AS uv FROM python:3.14-slim-trixie AS build COPY --from=uv /uv /usr/local/bin/uv ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=never UV_HTTP_RETRIES=10 WORKDIR /app COPY pyproject.toml setup.py uv.lock README.md LICENSE THIRD_PARTY_NOTICES.md ./ COPY pokesim ./pokesim # pokecore is the uv workspace member in packages/pokecore, so the image builds it from this source. COPY packages/pokecore/pyproject.toml packages/pokecore/README.md packages/pokecore/LICENSE \ packages/pokecore/THIRD_PARTY_NOTICES.md ./packages/pokecore/ COPY packages/pokecore/src ./packages/pokecore/src COPY tools/bundle_dependency_sources.py ./tools/bundle_dependency_sources.py # The corresponding pyboy-rs source archive is a release asset next to its wheels. The checksum is # required: an empty value fails the build instead of skipping verification. ARG EMULATOR_SOURCE_URL=https://github.com/afk-sapien/pyboy-rs/releases/download/v0.1.5/pyboy_rs-0.1.5.tar.gz ARG EMULATOR_SOURCE_SHA256=3acc7feafa4811842e1b84123da46495c8499318ce98aefbab4664e41848d050 ADD --checksum=sha256:${EMULATOR_SOURCE_SHA256} ${EMULATOR_SOURCE_URL} /emulator-source/pyboy-rs-source.tar.gz # The locked dependencies are release wheels, so this stage needs no compiler or Rust toolchain. # The acceleration extra compiles route searches with numba. Its lock markers only select it where # wheels exist (amd64 and arm64 Linux here), and navigation falls back to Python without it. RUN uv sync --frozen --no-dev --no-editable --extra acceleration \ && .venv/bin/python tools/bundle_dependency_sources.py /notices --emulator-source /emulator-source/pyboy-rs-source.tar.gz FROM python:3.14-slim-trixie ENV PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1 \ DATA_DIR=/data ROM_PATH=/roms/pokered.gb PORT=8000 HOST=0.0.0.0 \ SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy PATH=/app/.venv/bin:$PATH \ NUMBA_CACHE_DIR=/tmp/numba-cache RUN apt-get update && apt-get upgrade -y \ && apt-get install -y --no-install-recommends git \ && rm -rf /var/lib/apt/lists/* \ && groupadd --gid 10001 pokesim \ && useradd --uid 10001 --gid pokesim --no-create-home pokesim \ && mkdir /data /roms && chown pokesim:pokesim /data RUN python -m pip uninstall --yes pip \ && rm -rf /usr/local/lib/python3.14/ensurepip WORKDIR /app COPY --from=build /app/.venv /app/.venv COPY --from=build /notices /usr/share/pokesim COPY --from=build /app/pokesim /usr/share/pokesim/source/pokesim COPY pyproject.toml setup.py uv.lock LICENSE THIRD_PARTY_NOTICES.md /usr/share/pokesim/source/ COPY packages/pokecore/pyproject.toml packages/pokecore/LICENSE packages/pokecore/THIRD_PARTY_NOTICES.md \ /usr/share/pokesim/source/packages/pokecore/ COPY packages/pokecore/src /usr/share/pokesim/source/packages/pokecore/src COPY licenses /usr/share/pokesim/licenses ARG VERSION=0.7.0.dev0 ARG REVISION=unknown # The PRAGMA user_version of app.sqlite this build writes. tools/deploy_host.sh passes it. ARG SCHEMA=unknown ENV POKESIM_REVISION=$REVISION LABEL io.github.afk-sapien.pokesim.schema=$SCHEMA \ org.opencontainers.image.source="https://github.com/afk-sapien/PokeSim" \ org.opencontainers.image.title="pokesim" \ org.opencontainers.image.version=$VERSION \ org.opencontainers.image.revision=$REVISION \ org.opencontainers.image.licenses="MIT AND LGPL-3.0-only" USER 10001:10001 EXPOSE 8000 HEALTHCHECK --interval=30s --timeout=5s --start-period=30s CMD ["python", "-m", "pokesim.healthcheck", "--manager"] CMD ["python", "-m", "pokesim", "serve", "--data-dir", "/data", "--host", "0.0.0.0"]