diff --git a/.github/workflows/LinuxInstall.yml b/.github/workflows/LinuxInstall.yml index 5d7e99816..9a06c253b 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: @@ -204,6 +205,60 @@ 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. + 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 + 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 + 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/" + 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=.. + 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" \ diff --git a/.github/workflows/WindowsInstall.yml b/.github/workflows/WindowsInstall.yml index f5c0bb53e..44462bcd5 100644 --- a/.github/workflows/WindowsInstall.yml +++ b/.github/workflows/WindowsInstall.yml @@ -280,6 +280,20 @@ 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 + $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 @@ -289,7 +303,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: diff --git a/Desktop/io.github.mberrys.Loupe-pdf.appdata.xml b/Desktop/io.github.mberrys.Loupe-pdf.appdata.xml index 788c0d6a1..8a4879ea3 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 diff --git a/WixInstaller/Product.wxs.in b/WixInstaller/Product.wxs.in index ded0b92f7..945907039 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 000000000..8f8477ddb --- /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. diff --git a/scripts/smoke-test-appimage.sh b/scripts/smoke-test-appimage.sh index 6c63ddb5d..f4a7d89a9 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 4677eebef..6c2b508fe 100644 --- a/scripts/smoke-test-install.ps1 +++ b/scripts/smoke-test-install.ps1 @@ -251,20 +251,20 @@ 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) $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 {