From 35c8486b9680febfa605117680b17cd01bc28792 Mon Sep 17 00:00:00 2001 From: Jeff Culverhouse Date: Sun, 2 Nov 2025 20:35:18 -0500 Subject: [PATCH] chore: std Dockerfile and docker-compose, plus a few other fixes --- .github/workflows/deploy.yaml | 12 +----- Dockerfile | 76 ++++++++++++++++++++--------------- pyproject.toml | 3 +- src/amcrest2mqtt/__main__.py | 6 +++ 4 files changed, 53 insertions(+), 44 deletions(-) create mode 100644 src/amcrest2mqtt/__main__.py diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 5ba7207..186f9ce 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -161,22 +161,14 @@ jobs: uses: docker/build-push-action@v6 with: context: . + pull: true push: true build-args: | VERSION=${{ env.VERSION }} tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} platforms: linux/arm64,linux/amd64 cache-from: type=gha cache-to: type=gha,mode=max - labels: | - ${{ steps.meta.outputs.labels }} - org.opencontainers.image.version=${{ env.RELEASE_TAG }} - org.opencontainers.image.title=amcrest2mqtt - org.opencontainers.image.source=${{ github.repository }} - org.opencontainers.image.authors=weirdTangent - org.opencontainers.image.url=https://www.graystorm.com - org.opencontainers.image.documentation=https://github.com/${{ github.repository }}#readme - org.opencontainers.image.description=Publishes Amcrest camera events, snapshots, and status updates via MQTT for Home Assistant auto-discovery - org.opencontainers.image.licenses=MIT sbom: true provenance: true diff --git a/Dockerfile b/Dockerfile index 69718cc..3cb59a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,53 +1,65 @@ # syntax=docker/dockerfile:1.7-labs FROM python:3-slim -WORKDIR /app -COPY pyproject.toml uv.lock ./ +# ===== Project Variables ===== +ARG APP_NAME=amcrest2mqtt +ENV APP_NAME=${APP_NAME} +ARG SERVICE_DESC="Publishes Amcrest camera data to MQTT for Home Assistant" +ARG VERSION=0.0.0 +ARG USER_ID=1000 +ARG GROUP_ID=1000 -# ---- Version injection support ---- -ARG VERSION -ENV AMCREST2MQTT_VERSION=${VERSION} -ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_AMCREST2MQTT=${VERSION} +# ===== Base Setup ===== +WORKDIR /app +ENV DEBIAN_FRONTEND=noninteractive -# Install uv and git - and get updates too -RUN pip install uv -RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* +# Generic pretend version variables (used by setuptools-scm) +# No uppercase substitution; just define a safe fallback +ENV SETUPTOOLS_SCM_PRETEND_VERSION=${VERSION} +ENV APP_PRETEND_VERSION=${VERSION} +# ===== System Dependencies ===== RUN apt-get update && \ - apt-get install -y git && \ + apt-get install -y --no-install-recommends git && \ apt-get upgrade -y && \ + pip install --no-cache-dir uv && \ rm -rf /var/lib/apt/lists/* -# copy source -COPY --exclude=.git . . +# ===== Copy Source and Metadata ===== +COPY pyproject.toml uv.lock ./ +COPY . . -# Install dependencies (uses setup info, now src exists) -RUN uv sync --frozen --no-dev +# ===== Build & Install ===== +# 1. Create isolated virtual environment +RUN uv venv -# Install the package (if needed) -RUN uv pip install . +# 2. Export locked dependencies (with pretend version active) +RUN SETUPTOOLS_SCM_PRETEND_VERSION=${VERSION} uv export --no-dev --format=requirements-txt > /tmp/reqs.all.txt -# Default build arguments (can be overridden at build time) -ARG USER_ID=1000 -ARG GROUP_ID=1000 +# 3. Strip the local project from deps list so setuptools-scm isn’t triggered during deps install +RUN grep -v -E "(^-e\s+file://|^file://|/app)" /tmp/reqs.all.txt > /tmp/reqs.deps.txt || true -# Create the app user and group -RUN groupadd --gid "${GROUP_ID}" appuser && \ - useradd --uid "${USER_ID}" --gid "${GROUP_ID}" --create-home --shell /bin/bash appuser +# 4. Install dependencies +RUN uv pip install --no-cache-dir -r /tmp/reqs.deps.txt -# Ensure /config exists and is writable -RUN mkdir -p /config && chown -R appuser:appuser /config +# 5. Install the app itself (pretend version visible, no deps) +RUN SETUPTOOLS_SCM_PRETEND_VERSION=${VERSION} uv pip install --no-cache-dir . --no-deps -# Optional: fix perms if files already copied there (won’t break if empty) -RUN find /config -type f -exec chmod 0664 {} + || true +# 6. Cleanup +RUN rm -f /tmp/reqs.all.txt /tmp/reqs.deps.txt .git || true -# Ensure /app is owned by the app user -RUN chown -R appuser:appuser /app +# ===== Non-root Runtime User ===== +RUN groupadd -g "${GROUP_ID}" appuser && \ + useradd -u "${USER_ID}" -g "${GROUP_ID}" --create-home --shell /bin/bash appuser && \ + mkdir -p /config && chown -R appuser:appuser /app /config -# Drop privileges USER appuser -# ---- Runtime ---- -ENV SERVICE=amcrest2mqtt -ENTRYPOINT ["/app/.venv/bin/amcrest2mqtt"] +# ===== Runtime ===== +ENV SERVICE=${APP_NAME} +LABEL org.opencontainers.image.title=${APP_NAME} \ + org.opencontainers.image.description=${SERVICE_DESC} \ + org.opencontainers.image.version=${VERSION} + +ENTRYPOINT ["/bin/sh", "-c", "/app/.venv/bin/python -m $APP_NAME \"$@\"", "sh"] CMD ["-c", "/config"] diff --git a/pyproject.toml b/pyproject.toml index f80c25d..682021c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -171,8 +171,7 @@ allow_redefinition = false # Temporarily quiet noisy files or folders [[tool.mypy.overrides]] module = [ - "blinkpy.*", "aiohttp.*", "paho.*", ] -ignore_missing_imports = true \ No newline at end of file +ignore_missing_imports = true diff --git a/src/amcrest2mqtt/__main__.py b/src/amcrest2mqtt/__main__.py new file mode 100644 index 0000000..1e3d4ec --- /dev/null +++ b/src/amcrest2mqtt/__main__.py @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2025 Jeff Culverhouse +from .app import main + +if __name__ == "__main__": + raise SystemExit(main())