diff --git a/update-notify b/update-notify old mode 100755 new mode 100644 index 321c923..586291b --- a/update-notify +++ b/update-notify @@ -1,69 +1,117 @@ #!/bin/bash +set -u -# Default threshold or user argument +# --------------------------------------------------------------------------- +# Config +# --------------------------------------------------------------------------- threshold=${1:-30} +AUR_REPO="aur-local" +# stock kernel package -> your custom build of it. Add or remove entries freely. +declare -A KERNELS=( + [linux]="linux-custom" + [linux-lts]="linux-lts-custom" + [linux-zen]="linux-zen-custom" +) +state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/check-updates" -# Fetch checkupdates once to prevent multiple network/disk calls -mapfile -t arch_list < <(checkupdates 2>/dev/null) -arch_updates=${#arch_list[@]} +[[ $threshold =~ ^[0-9]+$ ]] || { echo "Threshold must be a number" >&2; exit 1; } +mkdir -p "$state_dir" -# Count AUR updates safely -aur_updates=$(aur repo -u -d aur-local 2>/dev/null | wc -l) -updates=$((arch_updates + aur_updates)) +# notify-send from cron/systemd needs the session bus address +export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=/run/user/$(id -u)/bus}" -# Check kernel running environment -running_kernel=$(uname -r) -is_lts=0; [[ $running_kernel == *lts* ]] && is_lts=1 +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- -# Convert the array to a single string for quick regex matching -arch_str="${arch_list[*]}" - -# Check for custom package updates in the list -has_custom=0; [[ $arch_str == *linux-custom* ]] && has_custom=1 -has_custom_lts=0; [[ $arch_str == *linux-lts-custom* ]] && has_custom_lts=1 - -# Define localized logic for kernel checking -check_kernel_update() { - local pkg=$1 - local item - - # Precise array element matching (avoids false-positive substring matches) - for item in "${arch_list[@]}"; do - if [[ "$item" == "$pkg "* ]]; then - return 0 # Package found in the updates array, update is definitely available - fi - done - - # Fallback to vercmp if running kernel doesn't match the sync repo - local repo_ver - repo_ver=$(pacman -Si "$pkg" 2>/dev/null | awk -F': ' '/Version/ {print $2}') - - # Crucial Fix: vercmp returns > 0 ONLY if repo_ver is strictly newer than running_kernel - if [[ -n $repo_ver ]] && (( $(vercmp "$repo_ver" "$running_kernel") > 0 )); then +# Send a notification only if its body changed since last time for this key. +notify_once() { + local key=$1 title=$2 body=$3 + local file="$state_dir/$key" + if [[ -f $file && $(<"$file") == "$body" ]]; then return 0 fi + printf '%s' "$body" > "$file" + notify-send "$title" "$body" +} + +# Forget a key so the next occurrence notifies again. +clear_state() { + rm -f "$state_dir/$1" +} + +# If $1 has a pending update, print its new version and return 0. +# checkupdates lines look like: "pkgname oldver -> newver" +pending_version() { + local pkg=$1 item new + for item in "${arch_list[@]}"; do + if [[ $item == "$pkg "* ]]; then + read -r _ _ _ new <<< "$item" + printf '%s\n' "$new" + return 0 + fi + done return 1 } -# Evaluate Kernel notifications based on environment -if (( is_lts == 0 && has_custom == 0 )); then - check_kernel_update "linux" && notify-send "Kernel update available" "Rebuild custom kernel" -elif (( is_lts == 1 && has_custom_lts == 0 )); then - check_kernel_update "linux-lts" && notify-send "LTS Kernel update available" "Rebuild custom kernel" +# --------------------------------------------------------------------------- +# Gather updates +# --------------------------------------------------------------------------- + +# Fetch checkupdates once. Exit codes: 0 = updates, 2 = none, 1 = error. +checkupdates_out=$(checkupdates 2>/dev/null) +checkupdates_rc=$? +if (( checkupdates_rc == 1 )); then + echo "checkupdates failed (network or sync problem?)" >&2 fi +arch_list=() +if [[ -n $checkupdates_out ]]; then + mapfile -t arch_list <<< "$checkupdates_out" +fi +arch_updates=${#arch_list[@]} -# Main updates notification threshold logic +aur_updates=0 +if command -v aur >/dev/null 2>&1; then + aur_updates=$(aur repo -u -d "$AUR_REPO" 2>/dev/null | wc -l) +fi +updates=$((arch_updates + aur_updates)) + +# --------------------------------------------------------------------------- +# Kernel check: the stock kernel updated, but your custom build didn't +# --------------------------------------------------------------------------- +for stock_pkg in "${!KERNELS[@]}"; do + custom_pkg=${KERNELS[$stock_pkg]} + + # Only relevant if the custom kernel is installed and has no pending update itself + if pacman -Q "$custom_pkg" >/dev/null 2>&1 && ! pending_version "$custom_pkg" >/dev/null; then + if stock_ver=$(pending_version "$stock_pkg"); then + notify_once "kernel-$stock_pkg" "Kernel update available: $stock_pkg" \ + "Rebuild $custom_pkg ($stock_pkg $stock_ver)" + continue + fi + fi + clear_state "kernel-$stock_pkg" +done + +# --------------------------------------------------------------------------- +# General updates threshold +# --------------------------------------------------------------------------- if (( updates >= threshold )); then - notify-send "Updates available" "Arch: $arch_updates, AUR: $aur_updates" + notify_once "updates" "Updates available" "Arch: $arch_updates, AUR: $aur_updates" - # Directly check command availability inline (no function needed) - if command -v git-monitor >/dev/null 2>&1; then - notify-send "Check git packages" "Use git-monitor for git packages updates" - fi - - if command -v fwupdmgr >/dev/null 2>&1; then - notify-send "Check firmware" "Use fwupdmgr to check for firmware updates" - fi + hints=( + "git-monitor|Check git packages|Use git-monitor for git packages updates" + "fwupdmgr|Check firmware|Use fwupdmgr to check for firmware updates" + ) + for hint in "${hints[@]}"; do + IFS='|' read -r cmd title body <<< "$hint" + if command -v "$cmd" >/dev/null 2>&1; then + notify_once "hint-$cmd" "$title" "$body" + fi + done +else + clear_state "updates" + clear_state "hint-git-monitor" + clear_state "hint-fwupdmgr" fi -