Add mise tasks, desktop entry, and app icon
mise run install builds a release binary and installs it into ~/.local with a desktop entry and a hicolor icon. Two wrinkles specific to a Nix-built GTK app installed outside the dev shell: the launcher is a generated script rather than a symlink, because a desktop launcher provides a minimal environment and GTK still needs to be pointed at its GSettings schemas and icon themes; and install registers Nix GC roots for every store path in the binary's RPATH, so nix-collect-garbage cannot delete GTK out from under the installed app. The runtime paths are exported from the flake's shellHook and read back at install time, so they cannot drift from what the binary was built against.
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# Nix supplies the whole toolchain (Zig, GTK, libadwaita), so there is
|
||||
# nothing for mise to install; these tasks just drive it.
|
||||
|
||||
[tasks.build]
|
||||
description = "Build a release binary into zig-out/bin"
|
||||
run = "nix develop --command zig build -Doptimize=ReleaseFast"
|
||||
|
||||
[tasks.build-debug]
|
||||
description = "Build a debug binary (leak checking, safety checks)"
|
||||
run = "nix develop --command zig build"
|
||||
|
||||
[tasks.run]
|
||||
description = "Build and run vtabs"
|
||||
run = "nix develop --command zig build run"
|
||||
|
||||
[tasks.fmt]
|
||||
description = "Format all Zig source"
|
||||
run = "nix develop --command zig fmt build.zig src"
|
||||
|
||||
[tasks.screenshot]
|
||||
description = "Screenshot vtabs in a throwaway headless compositor"
|
||||
depends = ["build-debug"]
|
||||
run = "nix develop --command ./shot.sh"
|
||||
|
||||
[tasks.install]
|
||||
description = "Install vtabs into ~/.local with a desktop entry and icon"
|
||||
depends = ["build"]
|
||||
run = '''
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
data="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
bindir="$HOME/.local/bin"
|
||||
libexec="$HOME/.local/libexec/vtabs"
|
||||
apps="$data/applications"
|
||||
icons="$data/icons/hicolor/scalable/apps"
|
||||
gcroots="$data/vtabs/gcroots"
|
||||
|
||||
# The binary carries an RPATH into the Nix store, so it runs anywhere, but it
|
||||
# still has to be told where GTK's GSettings schemas and icon themes live or
|
||||
# it aborts on a missing schema. Read those paths back out of the dev shell
|
||||
# that built it rather than hardcoding store hashes.
|
||||
schemas="$(nix develop --command printenv VTABS_GSETTINGS_SCHEMA_DIR)"
|
||||
datadirs="$(nix develop --command printenv VTABS_RUNTIME_DATA_DIRS)"
|
||||
|
||||
mkdir -p "$bindir" "$libexec" "$apps" "$icons" "$gcroots"
|
||||
|
||||
install -m755 zig-out/bin/vtabs "$libexec/vtabs"
|
||||
|
||||
# A launcher script rather than a symlink: a desktop launcher starts the app
|
||||
# with a minimal environment, so the GTK runtime paths must be set here.
|
||||
# Existing values are preserved so this composes with the rest of the session.
|
||||
cat > "$bindir/vtabs" <<EOF
|
||||
#!/bin/sh
|
||||
# Generated by \`mise run install\` — re-run that instead of editing.
|
||||
export GSETTINGS_SCHEMA_DIR="$schemas\${GSETTINGS_SCHEMA_DIR:+:\$GSETTINGS_SCHEMA_DIR}"
|
||||
export XDG_DATA_DIRS="$datadirs:\${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
|
||||
exec "$libexec/vtabs" "\$@"
|
||||
EOF
|
||||
chmod 755 "$bindir/vtabs"
|
||||
|
||||
sed "s|@EXEC@|$bindir/vtabs|" dist/dev.greyson.vtabs.desktop.in \
|
||||
> "$apps/dev.greyson.vtabs.desktop"
|
||||
install -m644 dist/dev.greyson.vtabs.svg "$icons/dev.greyson.vtabs.svg"
|
||||
|
||||
# Pin the store paths the installed binary links against. Without this a
|
||||
# later `nix-collect-garbage` deletes GTK and the installed app stops
|
||||
# starting, with no obvious connection to the command that broke it.
|
||||
# Nix roots are transitive, so rooting each RPATH entry covers its closure.
|
||||
rm -f "$gcroots"/*
|
||||
if command -v readelf >/dev/null; then
|
||||
readelf -d "$libexec/vtabs" \
|
||||
| sed -n 's/.*R\(UN\)\?PATH.*\[\(.*\)\]/\2/p' \
|
||||
| tr ':' '\n' \
|
||||
| sed -n 's|^\(/nix/store/[^/]*\).*|\1|p' \
|
||||
| sort -u \
|
||||
| while read -r path; do
|
||||
nix-store --realise --add-root "$gcroots/$(basename "$path")" \
|
||||
--indirect "$path" >/dev/null 2>&1 || true
|
||||
done
|
||||
echo "pinned $(find "$gcroots" -maxdepth 1 -type l | wc -l) store paths against garbage collection"
|
||||
else
|
||||
echo "warning: readelf not found; store paths left unpinned (nix-collect-garbage may break the install)" >&2
|
||||
fi
|
||||
|
||||
# Let the desktop notice the new entry and icon right away.
|
||||
command -v update-desktop-database >/dev/null && update-desktop-database -q "$apps" || true
|
||||
command -v gtk-update-icon-cache >/dev/null && gtk-update-icon-cache -qtf "$data/icons/hicolor" 2>/dev/null || true
|
||||
|
||||
echo "installed $bindir/vtabs"
|
||||
case ":$PATH:" in
|
||||
*":$bindir:"*) ;;
|
||||
*) echo "note: $bindir is not on your PATH; the desktop entry still works" >&2 ;;
|
||||
esac
|
||||
'''
|
||||
|
||||
[tasks.uninstall]
|
||||
description = "Remove everything `install` put into ~/.local"
|
||||
run = '''
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
data="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
apps="$data/applications"
|
||||
|
||||
rm -f "$HOME/.local/bin/vtabs"
|
||||
rm -rf "$HOME/.local/libexec/vtabs"
|
||||
rm -f "$apps/dev.greyson.vtabs.desktop"
|
||||
rm -f "$data/icons/hicolor/scalable/apps/dev.greyson.vtabs.svg"
|
||||
# Dropping the roots lets Nix reclaim the runtime closure on its next GC.
|
||||
rm -rf "$data/vtabs"
|
||||
|
||||
command -v update-desktop-database >/dev/null && update-desktop-database -q "$apps" || true
|
||||
command -v gtk-update-icon-cache >/dev/null && gtk-update-icon-cache -qtf "$data/icons/hicolor" 2>/dev/null || true
|
||||
|
||||
echo "uninstalled vtabs"
|
||||
'''
|
||||
Reference in New Issue
Block a user