From 048c446b26bbc03475ce236a50987419f94c13c3 Mon Sep 17 00:00:00 2001 From: vikingowl Date: Wed, 13 May 2026 03:52:20 +0200 Subject: [PATCH] feat(aur/install-hook): proactive legacy-cruft detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Common upgrade snags from pre-v2 setups that the 2.0.0 hook didn't catch in time. Both detected read-only and reported with precise remediation; the hook never modifies user files. 1. Stale ~/.config/systemd/user/owlry{,d}.{service,socket} overrides. systemd-user gives precedence to ~/.config/systemd/user/* over /usr/lib/systemd/user/*. A leftover dev-time override (e.g. from 'just install-local' in a 1.x tree) silently masks the AUR-shipped unit. We classify them: - references the deleted owlryd binary - points at a dev-time target/debug or target/release path - redundant override of the canonical /usr/bin/owlry - non-standard ExecStart (flagged for review) 2. Compositor autostart referencing 'owlryd': ~/.config/hypr/hyprland.conf and any *.conf / *.hyprlang in hypr/ ~/.config/sway/config ~/.config/i3/config ~/.config/river/init ~/.config/niri/config.kdl Each affected user gets a banner with the exact rm + systemctl --user commands to run (and what to replace 'owlryd' with in compositor configs). The hook reads only — it never executes the cleanup itself. Runs on: - 1.x -> 2.x upgrades (alongside the existing rename banner) - 2.0.0 -> 2.0.1 upgrade (re-runs the detection idempotently for users who missed cleanup the first time around) The 1.x banner copy is touched lightly: bookmarks now appears in the 'deferred' line alongside the widgets (D22). --- aur/owlry/owlry.install | 152 ++++++++++++++++++++++++++++++++++------ 1 file changed, 131 insertions(+), 21 deletions(-) diff --git a/aur/owlry/owlry.install b/aur/owlry/owlry.install index 66108b0..ae8cc6c 100644 --- a/aur/owlry/owlry.install +++ b/aur/owlry/owlry.install @@ -1,8 +1,127 @@ ## owlry .install hook ## ## v2.0 renamed the systemd user units (owlryd.{service,socket} → owlry.{service,socket}) -## and consolidated 14 separate packages into one. Handle the unit migration so users -## upgrading from 1.x don't end up with an enabled-but-missing owlryd.service. +## and consolidated 14 separate packages into one. +## +## 2.0.1 extends this hook with proactive detection of two common upgrade snags: +## 1. Stale ~/.config/systemd/user/owlry{,d}.{service,socket} overrides pointing +## at a deleted dev-time build path or the removed `owlryd` binary. systemd-user +## gives precedence to user-level units over /usr/lib/systemd/user/*, so a +## stale override silently breaks the AUR-shipped unit. +## 2. Compositor configs (Hyprland, Sway, i3, river, niri) with `exec owlryd` / +## `exec-once = owlryd` lines that won't resolve anymore. +## +## The hook only DETECTS and REPORTS — it never touches user homedirs from a root +## pacman context. Each affected user gets a precise remediation command. + +_owlry_for_each_user() { + # Apply $1 (function name) to each logged-in user's home directory. + # Falls back silently if loginctl/getent aren't available. + local fn="$1" + command -v loginctl >/dev/null 2>&1 || return 0 + command -v getent >/dev/null 2>&1 || return 0 + local user home + while read -r user; do + [ -n "$user" ] || continue + home="$(getent passwd "$user" 2>/dev/null | awk -F: '{print $6}')" + [ -d "$home" ] || continue + "$fn" "$user" "$home" + done < <(loginctl list-users --no-legend 2>/dev/null | awk '{print $2}') +} + +_owlry_check_unit() { + # Inspect a user-level systemd unit; emit a remediation hint if it's stale. + # Args: $1=user, $2=home, $3=unit-filename (e.g. owlry.service) + local user="$1" home="$2" unit="$3" + local svc="$home/.config/systemd/user/$unit" + [ -f "$svc" ] || return 1 + local exec_line + exec_line="$(grep -E '^ExecStart=' "$svc" 2>/dev/null | head -1 | sed 's/^ExecStart=//')" + case "$exec_line" in + */owlryd|*/owlryd\ *) + printf ' %s -> references deleted owlryd binary: %s\n' "$svc" "$exec_line" + return 0 + ;; + */target/debug/*|*/target/release/*) + printf ' %s -> points at a dev-time build path: %s\n' "$svc" "$exec_line" + return 0 + ;; + */owlry|*/owlry\ *|/usr/bin/owlry|/usr/bin/owlry\ *) + # If the override matches the canonical /usr/bin/owlry, it's harmless + # but redundant. Flag it gently. + printf ' %s -> user-level override (redundant; AUR ships this unit)\n' "$svc" + return 0 + ;; + *) + # Unknown ExecStart — flag it so the user can review. + printf ' %s -> non-standard ExecStart: %s\n' "$svc" "$exec_line" + return 0 + ;; + esac +} + +_owlry_check_compositors() { + # Args: $1=user, $2=home + local user="$1" home="$2" + local found=0 f + # Single-file configs + for f in \ + "$home/.config/sway/config" \ + "$home/.config/i3/config" \ + "$home/.config/river/init" \ + "$home/.config/niri/config.kdl"; do + if [ -f "$f" ] && grep -qE '\bowlryd\b' "$f" 2>/dev/null; then + printf ' %s -> contains `owlryd` reference\n' "$f" + found=1 + fi + done + # Hyprland — main file + include directory + if [ -d "$home/.config/hypr" ]; then + while IFS= read -r f; do + if grep -qE '\bowlryd\b' "$f" 2>/dev/null; then + printf ' %s -> contains `owlryd` reference\n' "$f" + found=1 + fi + done < <(find "$home/.config/hypr" -type f \( -name '*.conf' -o -name '*.hyprlang' \) 2>/dev/null) + fi + return $((1 - found)) +} + +_owlry_per_user_migration_check() { + local user="$1" home="$2" + # Collect all check output in one subshell so internal newlines are + # preserved (only the trailing newline gets stripped by $()). + local out + out="$({ + _owlry_check_unit "$user" "$home" owlry.service + _owlry_check_unit "$user" "$home" owlry.socket + _owlry_check_unit "$user" "$home" owlryd.service + _owlry_check_unit "$user" "$home" owlryd.socket + _owlry_check_compositors "$user" "$home" + })" + + [ -z "$out" ] && return 0 + + echo + echo " ── user '$user' ─────────────────────────────────────────────" + echo "$out" + echo + echo " Suggested cleanup (run as '$user'):" + echo + cat </dev/null || true + + # 2. Replace any \`owlryd\` autostart line in your compositor config: + # exec-once = owlryd -> exec-once = owlry -d + # exec owlryd -> exec owlry -d + # (Usually unnecessary now — owlry.service / owlry.socket replace autostart.) +EOF +} post_upgrade() { local old_pkgver="$2" @@ -20,31 +139,22 @@ post_upgrade() { │ owlryd.service -> owlry.service │ │ owlryd.socket -> owlry.socket │ │ │ - │ If you had the old service enabled, run: │ - │ systemctl --user disable --now owlryd.service │ - │ systemctl --user enable --now owlry.service │ - │ │ │ Plugin packages (bookmarks, systemd, clipboard, …) are now │ │ built into owlry by default — they were dropped from AUR and │ │ replaced via this package. │ │ │ - │ Widget providers (weather, media, pomodoro) are not in 2.0; │ - │ they return in a later 2.x release. See: │ - │ docs/RESTRUCTURE-V2.md (decisions D20, section 8) │ + │ Widget providers (weather, media, pomodoro) and bookmarks │ + │ are not in 2.0; they return in a later 2.x release. See: │ + │ docs/RESTRUCTURE-V2.md (decisions D20, D22) │ ╰─────────────────────────────────────────────────────────────────╯ - EOF - # Best-effort transition: if the old owlryd.service is enabled or - # active for the invoking user, stop it and disable it so the new - # owlry.service can take over. Errors are non-fatal — pacman runs - # as root, so we can only inspect, not toggle user units here. - if command -v loginctl >/dev/null 2>&1; then - local invoking_user - invoking_user="$(loginctl list-users --no-legend 2>/dev/null | awk 'NR==1 {print $2}')" - if [ -n "$invoking_user" ]; then - echo " (Run the systemctl --user commands above as user '$invoking_user'.)" - fi - fi + _owlry_for_each_user _owlry_per_user_migration_check + ;; + 2.0|2.0.0) + # 2.0.0 → 2.0.1: re-run the migration check; some users may have + # missed cleanup the first time. Idempotent — only prints when + # there's still something to flag. + _owlry_for_each_user _owlry_per_user_migration_check ;; esac }