From 7596285288dc572d9dece9eba371569badfd2d83 Mon Sep 17 00:00:00 2001 From: mbx30 Date: Mon, 31 Aug 2026 23:46:20 -0700 Subject: [PATCH 01/12] Fix Linux cache and Windows MSI Qt packaging --- .github/workflows/LinuxInstall.yml | 1 + WixInstaller/Product.wxs.in | 3 +++ changes/cdx-ci-packaging-repair.md | 4 ++++ 3 files changed, 8 insertions(+) create mode 100644 changes/cdx-ci-packaging-repair.md diff --git a/.github/workflows/LinuxInstall.yml b/.github/workflows/LinuxInstall.yml index 5d7e9981..e0525402 100644 --- a/.github/workflows/LinuxInstall.yml +++ b/.github/workflows/LinuxInstall.yml @@ -109,6 +109,7 @@ jobs: - name: 'VCPKG: Set up VCPKG' run: | + mkdir -p "$VCPKG_DEFAULT_BINARY_CACHE" VCPKG_COMMIT="$(python3 - <<'PY' import json with open("loupe/vcpkg-configuration.json", encoding="utf-8") as f: diff --git a/WixInstaller/Product.wxs.in b/WixInstaller/Product.wxs.in index ded0b92f..94590703 100644 --- a/WixInstaller/Product.wxs.in +++ b/WixInstaller/Product.wxs.in @@ -254,6 +254,9 @@ ${LOUPE_WIX_QT_STYLES_COMPONENT} + + + diff --git a/changes/cdx-ci-packaging-repair.md b/changes/cdx-ci-packaging-repair.md new file mode 100644 index 00000000..8f8477dd --- /dev/null +++ b/changes/cdx-ci-packaging-repair.md @@ -0,0 +1,4 @@ +Category: fixed +Audience: maintainers +Breaking-Change: no +Summary: Ensure Linux packaging creates the vcpkg binary cache directory and include the staged Qt configuration in the Windows MSI. From 757359ff1fad23758a94f2902f1d67e7cfb0999d Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 14:59:32 -0700 Subject: [PATCH 02/12] Exclude unresolved Mimer driver from AppImage deployment --- .github/workflows/LinuxInstall.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/LinuxInstall.yml b/.github/workflows/LinuxInstall.yml index e0525402..dc40dcf9 100644 --- a/.github/workflows/LinuxInstall.yml +++ b/.github/workflows/LinuxInstall.yml @@ -205,6 +205,16 @@ jobs: evidence_dir="$RUNNER_TEMP/loupe-package-boundary-linux" mkdir -p "$evidence_dir" set -o pipefail + # Qt may ship the proprietary Mimer SQL driver, but its external + # libmimerapi.so is not part of the Loop distribution. linuxdeployqt + # validates every discovered plugin and aborts on that unresolved + # dependency, so remove this non-distributable optional driver from + # the ephemeral Qt installation before deployment. + mimer_driver="$QT_ROOT_DIR/plugins/sqldrivers/libqsqlmimer.so" + if [[ -e "$mimer_driver" ]]; then + rm -f "$mimer_driver" + echo "Removed non-distributable optional Qt SQL driver: $mimer_driver" | tee "$evidence_dir/linuxdeployqt.txt" + fi cp install/usr/share/icons/hicolor/scalable/apps/io.github.mberrys.Loupe-pdf.svg install/io.github.mberrys.Loupe-pdf.svg bash "$GITHUB_WORKSPACE/loupe/scripts/ci/download_verified.sh" \ --gh-asset "probonopd/linuxdeployqt" \ From 5f7422e8eee65dcccd349909ff1f6221840cdd32 Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 15:42:36 -0700 Subject: [PATCH 03/12] Exclude unresolved optional Qt SQL drivers --- .github/workflows/LinuxInstall.yml | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/LinuxInstall.yml b/.github/workflows/LinuxInstall.yml index dc40dcf9..d69f4992 100644 --- a/.github/workflows/LinuxInstall.yml +++ b/.github/workflows/LinuxInstall.yml @@ -210,11 +210,22 @@ jobs: # validates every discovered plugin and aborts on that unresolved # dependency, so remove this non-distributable optional driver from # the ephemeral Qt installation before deployment. - mimer_driver="$QT_ROOT_DIR/plugins/sqldrivers/libqsqlmimer.so" - if [[ -e "$mimer_driver" ]]; then - rm -f "$mimer_driver" - echo "Removed non-distributable optional Qt SQL driver: $mimer_driver" | tee "$evidence_dir/linuxdeployqt.txt" - fi + sqldrivers_dir="$QT_ROOT_DIR/plugins/sqldrivers" + for optional_driver in libqsqlmimer.so libqsqloci.so; do + driver="$sqldrivers_dir/$optional_driver" + if [[ -e "$driver" ]]; then + rm -f "$driver" + echo "Removed non-distributable optional Qt SQL driver: $driver" | tee -a "$evidence_dir/linuxdeployqt.txt" + fi + done + for driver in "$sqldrivers_dir"/*.so; do + [[ -e "$driver" ]] || continue + unresolved="$(ldd "$driver" | awk '/=> not found/ { print $1 }')" + if [[ -n "$unresolved" ]]; then + echo "Removed Qt SQL driver with unresolved dependencies ($unresolved): $driver" | tee -a "$evidence_dir/linuxdeployqt.txt" + rm -f "$driver" + fi + done cp install/usr/share/icons/hicolor/scalable/apps/io.github.mberrys.Loupe-pdf.svg install/io.github.mberrys.Loupe-pdf.svg bash "$GITHUB_WORKSPACE/loupe/scripts/ci/download_verified.sh" \ --gh-asset "probonopd/linuxdeployqt" \ From b31cebd91c87297eb33350ae9236498b6d0a96c8 Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 16:11:42 -0700 Subject: [PATCH 04/12] Include application directory in Windows QML imports --- .github/workflows/WindowsInstall.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/WindowsInstall.yml b/.github/workflows/WindowsInstall.yml index f5c0bb53..92ae3958 100644 --- a/.github/workflows/WindowsInstall.yml +++ b/.github/workflows/WindowsInstall.yml @@ -289,7 +289,7 @@ jobs: [Paths] Prefix=. Plugins=. - Qml2Imports=qml + Qml2Imports=qml;. "@ | Set-Content -LiteralPath (Join-Path $installBin "qt.conf") -Encoding ascii Copy-Item -LiteralPath (Join-Path $installBin "qt.conf") -Destination (Join-Path $evidenceDir "qt.conf") env: From 2f86b42805f5b705833f164b8d6c9f9982d7166c Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 16:29:47 -0700 Subject: [PATCH 05/12] Fix AppImage metadata repository URLs --- Desktop/io.github.mberrys.Loupe-pdf.appdata.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Desktop/io.github.mberrys.Loupe-pdf.appdata.xml b/Desktop/io.github.mberrys.Loupe-pdf.appdata.xml index 788c0d6a..8a4879ea 100644 --- a/Desktop/io.github.mberrys.Loupe-pdf.appdata.xml +++ b/Desktop/io.github.mberrys.Loupe-pdf.appdata.xml @@ -16,9 +16,9 @@ Utility Michael Berry - https://github.com/mberrys/Loupe-pdf - https://github.com/mberrys/Loupe-pdf/issues - https://github.com/mberrys/Loupe-pdf + https://github.com/studio-berry/loop + https://github.com/studio-berry/loop/issues + https://github.com/studio-berry/loop io.github.mberrys.Loupe-pdf.desktop From cbe9bd81959fe8e754c9f0e115cd025896db8dcb Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 17:00:53 -0700 Subject: [PATCH 06/12] Configure Qt paths in Linux AppImage --- .github/workflows/LinuxInstall.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/LinuxInstall.yml b/.github/workflows/LinuxInstall.yml index d69f4992..3e9ddf1f 100644 --- a/.github/workflows/LinuxInstall.yml +++ b/.github/workflows/LinuxInstall.yml @@ -226,6 +226,12 @@ jobs: rm -f "$driver" fi done + cat > install/usr/bin/qt.conf <<'EOF' + [Paths] + Prefix=.. + Plugins=lib + Qml2Imports=lib/qml + EOF cp install/usr/share/icons/hicolor/scalable/apps/io.github.mberrys.Loupe-pdf.svg install/io.github.mberrys.Loupe-pdf.svg bash "$GITHUB_WORKSPACE/loupe/scripts/ci/download_verified.sh" \ --gh-asset "probonopd/linuxdeployqt" \ From bad0bedcf5329edc849a5a9093aec6a8f3ba11a0 Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 17:03:10 -0700 Subject: [PATCH 07/12] Fix Windows Qt configuration indentation --- .github/workflows/WindowsInstall.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/WindowsInstall.yml b/.github/workflows/WindowsInstall.yml index 92ae3958..d6d75557 100644 --- a/.github/workflows/WindowsInstall.yml +++ b/.github/workflows/WindowsInstall.yml @@ -289,7 +289,7 @@ jobs: [Paths] Prefix=. Plugins=. - Qml2Imports=qml;. + Qml2Imports=qml;. "@ | Set-Content -LiteralPath (Join-Path $installBin "qt.conf") -Encoding ascii Copy-Item -LiteralPath (Join-Path $installBin "qt.conf") -Destination (Join-Path $evidenceDir "qt.conf") env: From 57540137382045f3e7c7dde2dae198122a99a446 Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 17:13:47 -0700 Subject: [PATCH 08/12] Stage Qt offscreen platform plugins --- .github/workflows/LinuxInstall.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/LinuxInstall.yml b/.github/workflows/LinuxInstall.yml index 3e9ddf1f..4de5c4f9 100644 --- a/.github/workflows/LinuxInstall.yml +++ b/.github/workflows/LinuxInstall.yml @@ -226,6 +226,18 @@ jobs: rm -f "$driver" fi done + platform_dir="install/usr/lib/platforms" + mkdir -p "$platform_dir" + for platform_plugin in libqoffscreen.so libqminimal.so; do + source_plugin="$QT_ROOT_DIR/plugins/platforms/$platform_plugin" + if [[ -e "$source_plugin" ]]; then + cp -f "$source_plugin" "$platform_dir/$platform_plugin" + echo "Staged Qt platform plugin: $platform_plugin" | tee -a "$evidence_dir/linuxdeployqt.txt" + elif [[ "$platform_plugin" == "libqoffscreen.so" ]]; then + echo "::error::Required Qt platform plugin is missing: $source_plugin" + exit 1 + fi + done cat > install/usr/bin/qt.conf <<'EOF' [Paths] Prefix=.. From 863dea8e00fda1838c0e71190a45925e8df53f3b Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 17:42:49 -0700 Subject: [PATCH 09/12] Fix packaging smoke preflight and diagnostics --- scripts/smoke-test-appimage.sh | 2 +- scripts/smoke-test-install.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/smoke-test-appimage.sh b/scripts/smoke-test-appimage.sh index 6c63ddb5..f4a7d89a 100644 --- a/scripts/smoke-test-appimage.sh +++ b/scripts/smoke-test-appimage.sh @@ -127,7 +127,7 @@ PDF_TOOL="${BIN_DIR}/PdfTool" PROFILE_PATH="${PROFILES_DIR}/loupe-default.json" set +e -PREFLIGHT_OUTPUT="$("$PDF_TOOL" preflight "$TEST_PDF" --profile "$PROFILE_PATH" --console-format text 2>&1)" +PREFLIGHT_OUTPUT="$("$PDF_TOOL" preflight "$TEST_PDF" --profile "$PROFILE_PATH" --console-format json 2>&1)" PREFLIGHT_EXIT=$? set -e diff --git a/scripts/smoke-test-install.ps1 b/scripts/smoke-test-install.ps1 index 4677eebe..fe594430 100644 --- a/scripts/smoke-test-install.ps1 +++ b/scripts/smoke-test-install.ps1 @@ -257,14 +257,14 @@ try { $nativeOutput = @(& $editor --quick-smoke 2>&1) $nativeExit = $LASTEXITCODE if ($nativeExit -ne 0) { - throw "LoupeEditor native Quick startup failed with exit code $($nativeExit): $nativeOutput" + throw "LoupeEditor native Quick startup failed with exit code $($nativeExit): $($nativeOutput -join [Environment]::NewLine)" } Write-Host "OK: LoupeEditor native Quick startup" $env:QT_QUICK_BACKEND = "software" $softwareOutput = @(& $editor --quick-smoke 2>&1) $softwareExit = $LASTEXITCODE if ($softwareExit -ne 0) { - throw "LoupeEditor software Quick startup failed with exit code $($softwareExit): $softwareOutput" + throw "LoupeEditor software Quick startup failed with exit code $($softwareExit): $($softwareOutput -join [Environment]::NewLine)" } Write-Host "OK: LoupeEditor software Quick startup" } finally { From a43799cad83d45591d83ceab875d4234addf31c0 Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 17:44:02 -0700 Subject: [PATCH 10/12] Use JSON output for Windows preflight smoke --- scripts/smoke-test-install.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/smoke-test-install.ps1 b/scripts/smoke-test-install.ps1 index fe594430..6c2b508f 100644 --- a/scripts/smoke-test-install.ps1 +++ b/scripts/smoke-test-install.ps1 @@ -251,7 +251,7 @@ Remove-Item Env:QT_ROOT_DIR -ErrorAction SilentlyContinue Remove-Item Env:Qt6_DIR -ErrorAction SilentlyContinue Remove-Item Env:LOUPE_QT_ROOT -ErrorAction SilentlyContinue try { - $preflightOutput = & $pdfTool preflight $TestPdf --profile $profilePath --console-format text 2>&1 + $preflightOutput = & $pdfTool preflight $TestPdf --profile $profilePath --console-format json 2>&1 $preflightExit = $LASTEXITCODE Remove-Item Env:QT_QUICK_BACKEND -ErrorAction SilentlyContinue $nativeOutput = @(& $editor --quick-smoke 2>&1) From d55491750ca7fd5befff19bb494f6640b7e21132 Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 17:45:10 -0700 Subject: [PATCH 11/12] Stage built QML module in packaging smoke trees --- .github/workflows/LinuxInstall.yml | 8 ++++++++ .github/workflows/WindowsInstall.yml | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/.github/workflows/LinuxInstall.yml b/.github/workflows/LinuxInstall.yml index 4de5c4f9..56cf36da 100644 --- a/.github/workflows/LinuxInstall.yml +++ b/.github/workflows/LinuxInstall.yml @@ -238,6 +238,14 @@ jobs: exit 1 fi done + qml_module_source="LoupeEditor/Loupe/Quick" + qml_module_destination="install/usr/lib/qml/Loupe/Quick" + if [[ ! -d "$qml_module_source" ]]; then + echo "::error::Built Loupe.Quick QML module is missing: $qml_module_source" + exit 1 + fi + mkdir -p "$qml_module_destination" + cp -a "$qml_module_source/." "$qml_module_destination/" cat > install/usr/bin/qt.conf <<'EOF' [Paths] Prefix=.. diff --git a/.github/workflows/WindowsInstall.yml b/.github/workflows/WindowsInstall.yml index d6d75557..6309dd52 100644 --- a/.github/workflows/WindowsInstall.yml +++ b/.github/workflows/WindowsInstall.yml @@ -280,6 +280,13 @@ jobs: throw "windeployqt failed for $name with exit code $exitCode" } } + $qmlModuleSource = Join-Path $env:GITHUB_WORKSPACE "loupeuildLoupeEditorLoupeQuick" + $qmlModuleDestination = Join-Path $installBin "qmlLoupeQuick" + if (-not (Test-Path -LiteralPath $qmlModuleSource -PathType Container)) { + throw "Built Loupe.Quick QML module is missing: $qmlModuleSource" + } + New-Item -ItemType Directory -Force -Path $qmlModuleDestination | Out-Null + Copy-Item -LiteralPath (Join-Path $qmlModuleSource "*") -Destination $qmlModuleDestination -Recurse -Force # The clean installed-artifact smoke intentionally removes developer # Qt environment variables. Make the staged tree self-describing so From 12739946a45f587363f14c82acefb03830407a78 Mon Sep 17 00:00:00 2001 From: mbx30 Date: Tue, 1 Sep 2026 18:11:05 -0700 Subject: [PATCH 12/12] Stage Qt SQLite driver for package smoke --- .github/workflows/LinuxInstall.yml | 7 +++++++ .github/workflows/WindowsInstall.yml | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/.github/workflows/LinuxInstall.yml b/.github/workflows/LinuxInstall.yml index 56cf36da..9a06c253 100644 --- a/.github/workflows/LinuxInstall.yml +++ b/.github/workflows/LinuxInstall.yml @@ -246,6 +246,13 @@ jobs: fi mkdir -p "$qml_module_destination" cp -a "$qml_module_source/." "$qml_module_destination/" + sqlite_driver="$QT_ROOT_DIR/plugins/sqldrivers/libqsqlite.so" + if [[ ! -e "$sqlite_driver" ]]; then + echo "::error::Required Qt SQLite driver is missing: $sqlite_driver" + exit 1 + fi + mkdir -p install/usr/lib/sqldrivers + cp -f "$sqlite_driver" install/usr/lib/sqldrivers/libqsqlite.so cat > install/usr/bin/qt.conf <<'EOF' [Paths] Prefix=.. diff --git a/.github/workflows/WindowsInstall.yml b/.github/workflows/WindowsInstall.yml index 6309dd52..44462bcd 100644 --- a/.github/workflows/WindowsInstall.yml +++ b/.github/workflows/WindowsInstall.yml @@ -287,6 +287,13 @@ jobs: } New-Item -ItemType Directory -Force -Path $qmlModuleDestination | Out-Null Copy-Item -LiteralPath (Join-Path $qmlModuleSource "*") -Destination $qmlModuleDestination -Recurse -Force + $sqliteDriver = Join-Path $env:QT_ROOT_DIR "pluginssqldriversqsqlite.dll" + $sqliteDestination = Join-Path $installBin "sqldriversqsqlite.dll" + if (-not (Test-Path -LiteralPath $sqliteDriver)) { + throw "Required Qt SQLite driver is missing: $sqliteDriver" + } + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $sqliteDestination) | Out-Null + Copy-Item -LiteralPath $sqliteDriver -Destination $sqliteDestination -Force # The clean installed-artifact smoke intentionally removes developer # Qt environment variables. Make the staged tree self-describing so