f7e35652a9
Previously cmake --install populated both AppDirs with both binaries, causing the batch AppImage (57MB) to be larger than the GUI AppImage (47MB). Add rm lines after the sanity-check block to strip the unwanted binary from each AppDir before linuxdeploy runs. Also prune the upstream GUI desktop files from the batch AppDir (they reference Exec=glabels-qt which is now absent) and supply --icon-file + --icon-filename so --create-desktop-file resolves the icon lookup. Both AppImages now contain only their respective binary (~33-34MB each). Also document the QMAKE=/usr/bin/qmake6 workaround (Debian 13 Qt6 qmake discovery failure in linuxdeploy-plugin-qt). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
177 lines
7.1 KiB
Bash
Executable File
177 lines
7.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build sethLabels AppImages (GUI + batch).
|
|
#
|
|
# Pipeline (spec §5.3):
|
|
# 1. sanity / guardrail / version-compute (same as build-deb.sh)
|
|
# 2. out-of-tree cmake build with CMAKE_INSTALL_PREFIX=/usr
|
|
# 3. cmake --install to staging AppDir
|
|
# 4. linuxdeploy bundle GUI AppImage
|
|
# 5. re-stage AppDir for batch-only, linuxdeploy bundle batch AppImage
|
|
# 6. inline smoke tests T3, T4
|
|
# 7. print artifact paths
|
|
#
|
|
# Spec: sethlabels-docs/specs/2026-04-29-packaging-design.md §5.3
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$REPO_ROOT"
|
|
|
|
echo "==> [1/6] Sanity check build host"
|
|
"$REPO_ROOT/scripts/lib/deps-debian.sh"
|
|
echo "==> [1/6] Strict-zero guardrail"
|
|
"$REPO_ROOT/scripts/check-no-upstream-edits.sh"
|
|
echo "==> [1/6] Compute version"
|
|
VERSION="$("$REPO_ROOT/scripts/compute-version.sh")"
|
|
echo " VERSION = $VERSION"
|
|
|
|
# Bootstrap linuxdeploy + plugin-qt; defines $LINUXDEPLOY_BIN and $LINUXDEPLOY_PLUGIN_QT_BIN.
|
|
# shellcheck disable=SC1091
|
|
source "$REPO_ROOT/scripts/lib/linuxdeploy.sh"
|
|
# linuxdeploy looks for the plugin in PATH; symlink into the cache dir suffices.
|
|
PLUGIN_DIR="$(dirname "$LINUXDEPLOY_PLUGIN_QT_BIN")"
|
|
PATH="$PLUGIN_DIR:$PATH"
|
|
# Plugin file must be named exactly `linuxdeploy-plugin-qt` (no version suffix).
|
|
PLUGIN_LINK="$PLUGIN_DIR/linuxdeploy-plugin-qt"
|
|
ln -sf "$LINUXDEPLOY_PLUGIN_QT_BIN" "$PLUGIN_LINK"
|
|
chmod +x "$PLUGIN_LINK"
|
|
# Debian 13 has Qt6 only; linuxdeploy-plugin-qt's default qmake lookup looks
|
|
# for `qmake` (Qt5 era) or `/usr/lib/qt5/bin/qmake` (neither exists). Force it
|
|
# to the Qt6 binary explicitly so plugin staging works.
|
|
export QMAKE=/usr/bin/qmake6
|
|
|
|
echo "==> [2/6] Out-of-tree cmake build (install prefix /usr)"
|
|
BUILD_DIR="$REPO_ROOT/build/appimage"
|
|
APPDIR_GUI="$BUILD_DIR/AppDir-gui"
|
|
APPDIR_BATCH="$BUILD_DIR/AppDir-batch"
|
|
rm -rf "${BUILD_DIR:?BUILD_DIR must not be empty}"
|
|
mkdir -p "$BUILD_DIR"
|
|
cmake -S "$REPO_ROOT" -B "$BUILD_DIR" -G Ninja \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_INSTALL_PREFIX=/usr
|
|
cmake --build "$BUILD_DIR" --parallel
|
|
|
|
echo "==> [3/6] Stage install tree to AppDirs"
|
|
DESTDIR="$APPDIR_GUI" cmake --install "$BUILD_DIR"
|
|
# Batch AppDir gets its own copy so we can prune Qt plugins that GUI needs but batch doesn't.
|
|
DESTDIR="$APPDIR_BATCH" cmake --install "$BUILD_DIR"
|
|
|
|
# Sanity: both AppDirs must contain both binaries (we strip later, not here).
|
|
test -x "$APPDIR_GUI/usr/bin/glabels-qt" || { echo "ERROR: GUI binary missing in AppDir-gui" >&2; exit 1; }
|
|
test -x "$APPDIR_BATCH/usr/bin/glabels-batch-qt" || { echo "ERROR: batch binary missing in AppDir-batch" >&2; exit 1; }
|
|
|
|
# Prune the unwanted binary from each AppDir so linuxdeploy bundles only the
|
|
# libs needed by the remaining binary (otherwise both AppImages carry both
|
|
# binaries; spec §5.3 step 3 implies "AppDir-batch" should be batch-only).
|
|
rm "$APPDIR_GUI/usr/bin/glabels-batch-qt"
|
|
rm "$APPDIR_BATCH/usr/bin/glabels-qt"
|
|
# Also prune the GUI desktop files from the batch AppDir: linuxdeploy's
|
|
# --create-desktop-file doesn't suppress pre-existing desktop files, and
|
|
# the upstream desktop files reference Exec=glabels-qt (now pruned).
|
|
find "$APPDIR_BATCH/usr/share/applications" -name '*.desktop' -delete
|
|
|
|
echo "==> [4/6] Bundle GUI AppImage"
|
|
DESKTOP_FILE="$APPDIR_GUI/usr/share/applications/glabels-qt.desktop"
|
|
ICON_FILE="$APPDIR_GUI/usr/share/icons/hicolor/scalable/apps/glabels.svg"
|
|
# Upstream's actual desktop filename may vary — list what's there if missing.
|
|
if [ ! -f "$DESKTOP_FILE" ]; then
|
|
ALT_DESKTOP=$(find "$APPDIR_GUI/usr/share/applications" -name '*.desktop' | head -1)
|
|
if [ -n "$ALT_DESKTOP" ]; then
|
|
DESKTOP_FILE="$ALT_DESKTOP"
|
|
else
|
|
echo "ERROR: no .desktop file found in $APPDIR_GUI/usr/share/applications" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
cd "$BUILD_DIR"
|
|
APPIMAGE_EXTRACT_AND_RUN=1 \
|
|
"$LINUXDEPLOY_BIN" \
|
|
--appdir "$APPDIR_GUI" \
|
|
--plugin qt \
|
|
--executable "$APPDIR_GUI/usr/bin/glabels-qt" \
|
|
--desktop-file "$DESKTOP_FILE" \
|
|
--icon-file "$ICON_FILE" \
|
|
--output appimage
|
|
|
|
# linuxdeploy names the AppImage from the desktop file's Name= field (spaces→underscores).
|
|
# For this upstream desktop file (Name=gLabels Label Designer 4) that produces
|
|
# gLabels_Label_Designer_4-x86_64.AppImage. Use a broad glob and exclude *batch*.
|
|
GUI_RAW=$(ls "$BUILD_DIR"/*.AppImage 2>/dev/null | grep -v batch | head -1)
|
|
GUI_OUT="$REPO_ROOT/sethlabels-gui-${VERSION}-x86_64.AppImage"
|
|
mv "$GUI_RAW" "$GUI_OUT"
|
|
chmod +x "$GUI_OUT"
|
|
cd "$REPO_ROOT"
|
|
|
|
echo "==> [5/6] Bundle batch AppImage"
|
|
# Batch is CLI-only; reuse the upstream SVG icon so --create-desktop-file has
|
|
# an icon to reference (linuxdeploy errors if the Icon= entry has no match).
|
|
BATCH_ICON_FILE="$APPDIR_BATCH/usr/share/icons/hicolor/scalable/apps/glabels.svg"
|
|
cd "$BUILD_DIR"
|
|
APPIMAGE_EXTRACT_AND_RUN=1 \
|
|
"$LINUXDEPLOY_BIN" \
|
|
--appdir "$APPDIR_BATCH" \
|
|
--plugin qt \
|
|
--executable "$APPDIR_BATCH/usr/bin/glabels-batch-qt" \
|
|
--icon-file "$BATCH_ICON_FILE" \
|
|
--icon-filename glabels-batch-qt \
|
|
--create-desktop-file \
|
|
--output appimage
|
|
|
|
# linuxdeploy names the batch AppImage using the first desktop file it finds (the upstream
|
|
# GUI desktop), producing the same name as the GUI build. Since we already moved the GUI
|
|
# AppImage out, only one .AppImage remains in BUILD_DIR at this point — pick it directly.
|
|
BATCH_RAW=$(ls "$BUILD_DIR"/*.AppImage 2>/dev/null | head -1)
|
|
BATCH_OUT="$REPO_ROOT/sethlabels-batch-${VERSION}-x86_64.AppImage"
|
|
mv "$BATCH_RAW" "$BATCH_OUT"
|
|
chmod +x "$BATCH_OUT"
|
|
cd "$REPO_ROOT"
|
|
|
|
echo "==> [6/6] Smoke tests"
|
|
|
|
# Both AppImages bundle only the xcb Qt platform plugin (linuxdeploy-plugin-qt does not
|
|
# include offscreen/minimal). We need a real X display. Use Xvfb if available; if not,
|
|
# require DISPLAY to be set by the caller.
|
|
SMOKE_XVFB_PID=""
|
|
if ! xdpyinfo -display "${DISPLAY:-}" >/dev/null 2>&1; then
|
|
if command -v Xvfb >/dev/null 2>&1; then
|
|
echo " (starting Xvfb :99 for headless smoke tests)"
|
|
Xvfb :99 -screen 0 800x600x24 &
|
|
SMOKE_XVFB_PID=$!
|
|
export DISPLAY=:99
|
|
sleep 1
|
|
else
|
|
echo "WARNING: no DISPLAY and Xvfb not found — smoke tests may fail on xcb platform" >&2
|
|
fi
|
|
fi
|
|
cleanup_xvfb() { [ -n "$SMOKE_XVFB_PID" ] && kill "$SMOKE_XVFB_PID" 2>/dev/null || true; }
|
|
trap cleanup_xvfb EXIT
|
|
|
|
# T3: batch AppImage --version exits 0 with non-empty output.
|
|
echo " T3: batch --version"
|
|
T3_OUT=$(APPIMAGE_EXTRACT_AND_RUN=1 "$BATCH_OUT" --version 2>&1) || {
|
|
echo "ERROR: T3 failed — batch AppImage --version exited non-zero" >&2
|
|
echo "$T3_OUT" >&2
|
|
exit 1
|
|
}
|
|
# Strip EGL/DRM warnings (libEGL warning: failed to open /dev/dri/...) which are advisory.
|
|
T3_VERSION=$(echo "$T3_OUT" | grep -v 'libEGL warning' | head -1)
|
|
if [ -z "$T3_VERSION" ]; then
|
|
echo "ERROR: T3 failed — batch AppImage --version produced no version line" >&2
|
|
exit 1
|
|
fi
|
|
echo " T3: PASS ($T3_VERSION)"
|
|
|
|
# T4: GUI AppImage --help exits 0 under headless Xvfb display.
|
|
echo " T4: gui --help (DISPLAY=$DISPLAY)"
|
|
APPIMAGE_EXTRACT_AND_RUN=1 "$GUI_OUT" --help >"$BUILD_DIR/sethlabels-gui-help.txt" 2>&1 || {
|
|
echo "ERROR: T4 failed — GUI AppImage --help exited non-zero" >&2
|
|
cat "$BUILD_DIR/sethlabels-gui-help.txt" >&2
|
|
exit 1
|
|
}
|
|
echo " T4: PASS"
|
|
|
|
echo ""
|
|
echo "Artifacts:"
|
|
echo " $GUI_OUT"
|
|
echo " $BATCH_OUT"
|