2026-08-24 12:03:08 +01:00
|
|
|
# Alpine because there is nothing to compile and nothing to link against: the
|
|
|
|
|
# application is one Python module with no dependencies outside the standard
|
|
|
|
|
# library, so the base image is almost the whole image.
|
|
|
|
|
FROM python:3.13-alpine AS runtime
|
|
|
|
|
|
|
|
|
|
ENV PYTHONUNBUFFERED=1
|
|
|
|
|
|
|
|
|
|
WORKDIR /app
|
|
|
|
|
COPY pyproject.toml README.md ./
|
|
|
|
|
COPY music_curator.py ./
|
|
|
|
|
RUN pip install --no-cache-dir . \
|
|
|
|
|
&& rm -rf build music_curator.egg-info
|
|
|
|
|
|
|
|
|
|
# The store lives here. Mount a volume over it, or the history is re-downloaded
|
|
|
|
|
# from Last.fm every time the container is recreated.
|
|
|
|
|
ENV MUSIC_CURATOR_DB=/data/curator.db
|
|
|
|
|
VOLUME ["/data"]
|
|
|
|
|
|
|
|
|
|
# Runs as root by default so a bind-mounted dataset of any ownership is
|
|
|
|
|
# writable. Override with `user:` in compose to run as the dataset's owner.
|
|
|
|
|
ENTRYPOINT ["music-curator"]
|
|
|
|
|
|
|
|
|
|
# Test stage: build it with `--target test`; a failing test fails the build.
|
|
|
|
|
# The suite talks to a fake transport, never to Last.fm, so it needs no
|
|
|
|
|
# credentials and no network. The published image is the `runtime` stage above
|
|
|
|
|
# and carries none of this.
|
|
|
|
|
FROM runtime AS test
|
|
|
|
|
|
|
|
|
|
RUN pip install --no-cache-dir pytest
|
|
|
|
|
COPY pytest.ini ./
|
2026-08-24 19:36:06 +01:00
|
|
|
# The host-side tools are not part of the runtime image, but their tests are
|
|
|
|
|
# part of the suite, so they have to be present for it.
|
|
|
|
|
COPY tools ./tools
|
2026-08-24 12:03:08 +01:00
|
|
|
COPY tests ./tests
|
|
|
|
|
RUN python -m pytest
|