From 8afbd0afed3518613fbd197097835d1b75fae9db Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:01:10 +0000 Subject: [PATCH] Docker use latest libreoffice and fonts (#5482) # Description of Changes --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- .github/workflows/PR-Auto-Deploy-V2.yml | 116 +++++++----------------- docker/embedded/Dockerfile | 25 ++++- docker/embedded/Dockerfile.fat | 29 +++++- docker/embedded/Dockerfile.ultra-lite | 3 + 4 files changed, 83 insertions(+), 90 deletions(-) diff --git a/.github/workflows/PR-Auto-Deploy-V2.yml b/.github/workflows/PR-Auto-Deploy-V2.yml index fab61b71d..ef59dfbe0 100644 --- a/.github/workflows/PR-Auto-Deploy-V2.yml +++ b/.github/workflows/PR-Auto-Deploy-V2.yml @@ -194,81 +194,44 @@ jobs: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_API }} - - name: Get commit hashes for frontend and backend - id: commit-hashes + - name: Get commit hash for app + id: commit-hash run: | - # Get last commit that touched the frontend folder, docker/frontend, or docker/compose - FRONTEND_HASH=$(git log -1 --format="%H" -- frontend/ docker/frontend/ docker/compose/ 2>/dev/null || echo "") - if [ -z "$FRONTEND_HASH" ]; then - FRONTEND_HASH="no-frontend-changes" + # Get last commit that touched the application code + APP_HASH=$(git log -1 --format="%H" -- . 2>/dev/null || echo "") + if [ -z "$APP_HASH" ]; then + APP_HASH="no-changes" fi - # Get last commit that touched backend code, docker/backend, or docker/compose - BACKEND_HASH=$(git log -1 --format="%H" -- app/ docker/backend/ docker/compose/ 2>/dev/null || echo "") - if [ -z "$BACKEND_HASH" ]; then - BACKEND_HASH="no-backend-changes" - fi + echo "App hash: $APP_HASH" + echo "app_hash=$APP_HASH" >> $GITHUB_OUTPUT - echo "Frontend hash: $FRONTEND_HASH" - echo "Backend hash: $BACKEND_HASH" - - echo "frontend_hash=$FRONTEND_HASH" >> $GITHUB_OUTPUT - echo "backend_hash=$BACKEND_HASH" >> $GITHUB_OUTPUT - - # Short hashes for tags - if [ "$FRONTEND_HASH" = "no-frontend-changes" ]; then - echo "frontend_short=no-frontend" >> $GITHUB_OUTPUT + # Short hash for tags + if [ "$APP_HASH" = "no-changes" ]; then + echo "app_short=no-changes" >> $GITHUB_OUTPUT else - echo "frontend_short=${FRONTEND_HASH:0:8}" >> $GITHUB_OUTPUT + echo "app_short=${APP_HASH:0:8}" >> $GITHUB_OUTPUT fi - if [ "$BACKEND_HASH" = "no-backend-changes" ]; then - echo "backend_short=no-backend" >> $GITHUB_OUTPUT - else - echo "backend_short=${BACKEND_HASH:0:8}" >> $GITHUB_OUTPUT - fi - - - name: Check if frontend image exists - id: check-frontend + - name: Check if image exists + id: check-image run: | - if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} >/dev/null 2>&1; then + if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }} >/dev/null 2>&1; then echo "exists=true" >> $GITHUB_OUTPUT - echo "Frontend image already exists, skipping build" + echo "Image already exists, skipping build" else echo "exists=false" >> $GITHUB_OUTPUT - echo "Frontend image needs to be built" + echo "Image needs to be built" fi - - name: Check if backend image exists - id: check-backend - run: | - if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} >/dev/null 2>&1; then - echo "exists=true" >> $GITHUB_OUTPUT - echo "Backend image already exists, skipping build" - else - echo "exists=false" >> $GITHUB_OUTPUT - echo "Backend image needs to be built" - fi - - - name: Build and push V2 frontend image - if: steps.check-frontend.outputs.exists == 'false' + - name: Build and push V2 image + if: steps.check-image.outputs.exists == 'false' uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: context: . - file: ./docker/frontend/Dockerfile + file: ./docker/embedded/Dockerfile push: true - tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} - build-args: VERSION_TAG=v2-alpha - platforms: linux/amd64 - - - name: Build and push V2 backend image - if: steps.check-backend.outputs.exists == 'false' - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 - with: - context: . - file: ./docker/backend/Dockerfile - push: true - tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }} build-args: VERSION_TAG=v2-alpha platforms: linux/amd64 @@ -283,17 +246,16 @@ jobs: run: | # Use same port strategy as regular PRs - just the PR number V2_PORT=${{ needs.check-pr.outputs.pr_number }} - BACKEND_PORT=$((V2_PORT + 10000)) # Backend on higher port to avoid conflicts - # Create docker-compose for V2 with separate frontend and backend + # Create docker-compose for V2 with unified embedded image cat > docker-compose.yml << EOF version: '3.3' services: - stirling-pdf-v2-backend: - container_name: stirling-pdf-v2-backend-pr-${{ needs.check-pr.outputs.pr_number }} - image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} + stirling-pdf-v2: + container_name: stirling-pdf-v2-pr-${{ needs.check-pr.outputs.pr_number }} + image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }} ports: - - "${BACKEND_PORT}:8080" # Backend API port + - "${V2_PORT}:8080" volumes: - /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/data:/usr/share/tessdata:rw - /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/config:/configs:rw @@ -305,7 +267,7 @@ jobs: SECURITY_INITIALLOGIN_PASSWORD: "${{ secrets.TEST_LOGIN_PASSWORD }}" SYSTEM_DEFAULTLOCALE: en-GB UI_APPNAME: "Stirling-PDF V2 PR#${{ needs.check-pr.outputs.pr_number }}" - UI_HOMEDESCRIPTION: "V2 PR#${{ needs.check-pr.outputs.pr_number }} - Frontend/Backend Split Architecture" + UI_HOMEDESCRIPTION: "V2 PR#${{ needs.check-pr.outputs.pr_number }} - Embedded Architecture" UI_APPNAMENAVBAR: "V2 PR#${{ needs.check-pr.outputs.pr_number }}" SYSTEM_MAXFILESIZE: "100" METRICS_ENABLED: "true" @@ -313,17 +275,6 @@ jobs: SWAGGER_SERVER_URL: "https://${V2_PORT}.ssl.stirlingpdf.cloud" baseUrl: "https://${V2_PORT}.ssl.stirlingpdf.cloud" restart: on-failure:5 - - stirling-pdf-v2-frontend: - container_name: stirling-pdf-v2-frontend-pr-${{ needs.check-pr.outputs.pr_number }} - image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} - ports: - - "${V2_PORT}:80" # Frontend port (same as regular PRs) - environment: - VITE_API_BASE_URL: "http://${{ secrets.NEW_VPS_HOST }}:${BACKEND_PORT}" - depends_on: - - stirling-pdf-v2-backend - restart: on-failure:5 EOF # Deploy to VPS @@ -339,15 +290,15 @@ jobs: # Stop any existing container and clean up cd /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }} docker-compose down --remove-orphans 2>/dev/null || true - + # Start the new container docker-compose pull docker-compose up -d - + # Clean up unused Docker resources to save space docker system prune -af --volumes || true - # Clean up old backend/frontend images (older than 2 weeks) + # Clean up old images (older than 2 weeks) docker image prune -af --filter "until=336h" --filter "label!=keep=true" || true ENDSSH @@ -383,7 +334,7 @@ jobs: const httpsUrl = `https://${v2Port}.ssl.stirlingpdf.cloud`; const commentBody = `## 🚀 V2 Auto-Deployment Complete!\n\n` + - `Your V2 PR with the new frontend/backend split architecture has been deployed!\n\n` + + `Your V2 PR with embedded architecture has been deployed!\n\n` + `🔗 **Direct Test URL (non-SSL)** [${deploymentUrl}](${deploymentUrl})\n\n` + `🔐 **Secure HTTPS URL**: [${httpsUrl}](${httpsUrl})\n\n` + `_This deployment will be automatically cleaned up when the PR is closed._\n\n` + @@ -473,9 +424,8 @@ jobs: # Remove V2 PR-specific directories rm -rf /stirling/V2-PR-${{ github.event.pull_request.number }} - # Clean up V2 containers by name (in case compose cleanup missed them) - docker rm -f stirling-pdf-v2-frontend-pr-${{ github.event.pull_request.number }} || true - docker rm -f stirling-pdf-v2-backend-pr-${{ github.event.pull_request.number }} || true + # Clean up V2 container by name (in case compose cleanup missed it) + docker rm -f stirling-pdf-v2-pr-${{ github.event.pull_request.number }} || true echo "V2 cleanup completed" else diff --git a/docker/embedded/Dockerfile b/docker/embedded/Dockerfile index 4ad1e1050..4691b709b 100644 --- a/docker/embedded/Dockerfile +++ b/docker/embedded/Dockerfile @@ -42,6 +42,9 @@ FROM debian:stable-slim@sha256:f6681102cd18b4c0c4720a77b602498f4bdcf701c8fc02776 SHELL ["/bin/bash", "-o", "pipefail", "-c"] ENV DEBIAN_FRONTEND=noninteractive +ENV LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 + ENV TESS_BASE_PATH=/usr/share/tesseract-ocr/5/tessdata # Install core runtime dependencies + tools required by Stirling-PDF features @@ -49,7 +52,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates tzdata tini bash fontconfig \ openjdk-21-jre-headless \ ffmpeg poppler-utils ocrmypdf imagemagick fontforge ghostscript \ - libreoffice-nogui libreoffice-java-common \ + fonts-dejavu \ + fonts-liberation fonts-liberation2 \ + fonts-crosextra-caladea fonts-crosextra-carlito \ + fonts-linuxlibertine \ + fonts-noto-core fonts-noto-cjk fonts-noto-mono fonts-noto-ui-core \ + fonts-noto-color-emoji \ + ttf-wqy-zenhei \ + fonts-arphic-ukai fonts-arphic-uming \ python3 python3-venv python3-uno \ tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \ tesseract-ocr-por tesseract-ocr-chi-sim \ @@ -75,6 +85,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* +RUN set -eux; \ + . /etc/os-release; \ + echo "deb http://deb.debian.org/debian ${VERSION_CODENAME}-backports main" > /etc/apt/sources.list.d/backports.list; \ + apt-get update; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends -t ${VERSION_CODENAME}-backports \ + libreoffice libreoffice-java-common; \ + rm -rf /var/lib/apt/lists/*; \ + libreoffice --version + # Make ebook-convert available in PATH RUN ln -sf /opt/calibre/ebook-convert /usr/bin/ebook-convert \ && /opt/calibre/ebook-convert --version @@ -140,6 +159,7 @@ ENV VERSION_TAG=$VERSION_TAG \ PGID=${PGID} \ UMASK=022 \ UNO_PATH=/usr/lib/libreoffice/program \ + LIBREOFFICE_BIN_PATH=/usr/lib/libreoffice/program/soffice.bin \ STIRLING_TEMPFILES_DIRECTORY=/tmp/stirling-pdf \ TMPDIR=/tmp/stirling-pdf \ TEMP=/tmp/stirling-pdf \ @@ -153,8 +173,9 @@ RUN python3 -m venv /opt/venv --system-site-packages \ && /opt/venv/bin/python -c "import cv2; print('OpenCV version:', cv2.__version__)" # Separate venv for unoserver (keeps it isolated) +ARG UNOSERVER_VERSION=3.6 RUN python3 -m venv /opt/unoserver-venv --system-site-packages \ - && /opt/unoserver-venv/bin/pip install --no-cache-dir unoserver + && /opt/unoserver-venv/bin/pip install --no-cache-dir "unoserver==${UNOSERVER_VERSION}" # Make unoserver tools available in main venv PATH RUN ln -sf /opt/unoserver-venv/bin/unoconvert /opt/venv/bin/unoconvert \ diff --git a/docker/embedded/Dockerfile.fat b/docker/embedded/Dockerfile.fat index 45a314b3a..d66304abe 100644 --- a/docker/embedded/Dockerfile.fat +++ b/docker/embedded/Dockerfile.fat @@ -42,6 +42,9 @@ FROM debian:stable-slim@sha256:f6681102cd18b4c0c4720a77b602498f4bdcf701c8fc02776 SHELL ["/bin/bash", "-o", "pipefail", "-c"] ENV DEBIAN_FRONTEND=noninteractive +ENV LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 + ENV TESS_BASE_PATH=/usr/share/tesseract-ocr/5/tessdata # Install core runtime dependencies + tools required by Stirling-PDF features + extra fonts for fat version @@ -49,15 +52,20 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates tzdata tini bash fontconfig \ openjdk-21-jre-headless \ ffmpeg poppler-utils ocrmypdf imagemagick fontforge ghostscript \ - libreoffice-nogui libreoffice-java-common \ + fonts-dejavu \ + fonts-liberation fonts-liberation2 \ + fonts-crosextra-caladea fonts-crosextra-carlito \ + fonts-linuxlibertine \ + fonts-noto-core fonts-noto-cjk fonts-noto-mono fonts-noto-ui-core \ + fonts-noto-color-emoji \ + ttf-wqy-zenhei \ + fonts-arphic-ukai fonts-arphic-uming \ + fonts-freefont-ttf fonts-terminus \ python3 python3-venv python3-uno \ tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \ tesseract-ocr-por tesseract-ocr-chi-sim \ libcairo2 libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 \ gosu unpaper qpdf \ - # Extra fonts for fat/air-gapped version - fonts-dejavu fonts-liberation fonts-noto fonts-noto-cjk fonts-noto-color-emoji \ - fonts-freefont-ttf fonts-terminus fonts-linuxlibertine \ # AWT headless support (required for some Java graphics operations) libfreetype6 libfontconfig1 libx11-6 libxt6 libxext6 libxrender1 libxtst6 libxi6 \ libxinerama1 libxkbcommon0 libxkbfile1 libsm6 libice6 \ @@ -78,6 +86,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* +RUN set -eux; \ + . /etc/os-release; \ + echo "deb http://deb.debian.org/debian ${VERSION_CODENAME}-backports main" > /etc/apt/sources.list.d/backports.list; \ + apt-get update; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends -t ${VERSION_CODENAME}-backports \ + libreoffice libreoffice-java-common; \ + rm -rf /var/lib/apt/lists/*; \ + libreoffice --version + # Make ebook-convert available in PATH RUN ln -sf /opt/calibre/ebook-convert /usr/bin/ebook-convert \ && /opt/calibre/ebook-convert --version @@ -145,6 +162,7 @@ ENV VERSION_TAG=$VERSION_TAG \ FAT_DOCKER=true \ INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \ UNO_PATH=/usr/lib/libreoffice/program \ + LIBREOFFICE_BIN_PATH=/usr/lib/libreoffice/program/soffice.bin \ STIRLING_TEMPFILES_DIRECTORY=/tmp/stirling-pdf \ TMPDIR=/tmp/stirling-pdf \ TEMP=/tmp/stirling-pdf \ @@ -158,8 +176,9 @@ RUN python3 -m venv /opt/venv --system-site-packages \ && /opt/venv/bin/python -c "import cv2; print('OpenCV version:', cv2.__version__)" # Separate venv for unoserver (keeps it isolated) +ARG UNOSERVER_VERSION=3.6 RUN python3 -m venv /opt/unoserver-venv --system-site-packages \ - && /opt/unoserver-venv/bin/pip install --no-cache-dir unoserver + && /opt/unoserver-venv/bin/pip install --no-cache-dir "unoserver==${UNOSERVER_VERSION}" # Make unoserver tools available in main venv PATH RUN ln -sf /opt/unoserver-venv/bin/unoconvert /opt/venv/bin/unoconvert \ diff --git a/docker/embedded/Dockerfile.ultra-lite b/docker/embedded/Dockerfile.ultra-lite index e6e686b1f..96575a17e 100644 --- a/docker/embedded/Dockerfile.ultra-lite +++ b/docker/embedded/Dockerfile.ultra-lite @@ -38,6 +38,9 @@ RUN DISABLE_ADDITIONAL_FEATURES=true \ # Stage 2: Runtime image FROM alpine:3.23.2@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 +ENV LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 + ARG VERSION_TAG # Labels