Files
qbz/scripts/packaging/desktop_entry_check.sh
T

74 lines
3.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# scripts/packaging/desktop_entry_check.sh — the MPRIS DesktopEntry / .desktop
# / icon invariant, as a gate (qbz-nix-docs/cicd/2026-08-04-desktop-entry-icon-mismatch.md).
#
# GNOME Shell / Plasma resolve the media widget's application icon ONLY through
# the MPRIS `DesktopEntry` property: they look for `<DesktopEntry>.desktop` in
# the XDG application dirs and read its `Icon=`. If the installed basename
# differs from the constant, or `Icon=` names an icon the same package does not
# install, the widget shows no icon — and nothing else breaks, which is why
# this regressed more than once. Two properties, asserted at the SOURCE
# (recipes) and, when `--deb <file>` / `--rpm <file>` / `--appdir <dir>` are
# given, on the ARTIFACT that ships.
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
ENTRY=$(grep -oP 'const DESKTOP_ENTRY: &str = "\K[^"]+' crates/qbz-media-controls/src/linux.rs)
[[ -n "$ENTRY" ]] || { echo "::error::DESKTOP_ENTRY constant not found"; exit 1; }
echo "DesktopEntry = $ENTRY"
fail=0
say_fail() { echo "::error::$*"; fail=1; }
icon_of() { grep -m1 '^Icon=' "$1" | cut -d= -f2-; }
# --- source recipes -----------------------------------------------------
# nfpm (deb/rpm): the installed basename must be the constant; Icon= must be
# one of the hicolor names nfpm installs.
NFPM=packaging/nfpm/nfpm.yaml
dst=$(grep -oP 'dst: /usr/share/applications/\K[^ ]+\.desktop' "$NFPM" | head -1)
[[ "$dst" == "$ENTRY.desktop" ]] || say_fail "nfpm installs $dst, DesktopEntry is $ENTRY"
src=$(grep -B1 "dst: /usr/share/applications/$dst" "$NFPM" | grep -oP 'src: \K\S+')
icon=$(icon_of "$src")
grep -q "dst: /usr/share/icons/hicolor/[0-9x]*/apps/${icon}\.png" "$NFPM" \
|| say_fail "nfpm: $src has Icon=$icon but installs no hicolor/*/apps/$icon.png"
# StartupWMClass must be the constant too (window <-> launcher association).
for f in $(git ls-files 'packaging/*.desktop' 'flatpak/*.desktop'); do
wm=$(grep -m1 '^StartupWMClass=' "$f" | cut -d= -f2-)
[[ "$wm" == "$ENTRY" ]] || say_fail "$f: StartupWMClass=$wm != $ENTRY"
done
# Recipes that ship a reverse-DNS basename must match the constant exactly.
for f in $(git ls-files 'packaging/*.desktop' 'flatpak/*.desktop' | grep -v '/qbz\.desktop$'); do
base=$(basename "$f" .desktop)
[[ "$base" == "$ENTRY" ]] || say_fail "$f: basename $base != $ENTRY"
done
# --- artifacts ------------------------------------------------------------
while [[ $# -gt 0 ]]; do
case "$1" in
--deb)
list=$(dpkg-deb -c "$2" | awk '{print $6}')
grep -qx "./usr/share/applications/$ENTRY.desktop" <<<"$list" \
|| say_fail "$2 does not install /usr/share/applications/$ENTRY.desktop"
grep -q "^./usr/share/icons/hicolor/256x256/apps/${icon}\.png$" <<<"$list" \
|| say_fail "$2 does not install hicolor/256x256/apps/$icon.png"
echo "deb OK: $2"; shift 2 ;;
--rpm)
list=$(rpm -qlp "$2" 2>/dev/null || true)
grep -qx "/usr/share/applications/$ENTRY.desktop" <<<"$list" \
|| say_fail "$2 does not install /usr/share/applications/$ENTRY.desktop"
grep -q "^/usr/share/icons/hicolor/256x256/apps/${icon}\.png$" <<<"$list" \
|| say_fail "$2 does not install hicolor/256x256/apps/$icon.png"
echo "rpm OK: $2"; shift 2 ;;
--appdir)
d="$2"
[[ -f "$d/$ENTRY.desktop" ]] || say_fail "$d has no $ENTRY.desktop at its root"
aicon=$(icon_of "$d/$ENTRY.desktop")
[[ -f "$d/$aicon.png" || -L "$d/$aicon.png" ]] || say_fail "$d: Icon=$aicon but no $aicon.png at the root"
# No .DirIcon assertion: linuxdeploy does not write it (appimagetool
# does, at packaging time) — asserting it here failed a green build.
echo "AppDir OK: $d"; shift 2 ;;
*) echo "unknown arg $1"; exit 2 ;;
esac
done
(( fail == 0 )) && echo "desktop-entry check OK" || exit 1