I also want a “pending updates” notification in my status bar (swaybar with i3blocks).
How often do you run the script?
I’m a bit hesitant to run it too often, due to performance impact during build.
What is your experience? / What do you think is a good practice?
This operation is indeed kind of a heavy command. Currently, I run this on a regular timer but I ensure that my laptop is connected to a power source before invoking the command. When I do run the script, I cache the results to a file in ~/.cache to have a last-run result in case I want to check things quickly.
Building a system derivation kind of depends on how heavily customized your configuration is. For example, a stock nixos system on the nixos-23.05 channel can probably check without too much overhead, but if you (like me) rely on something like emacs-overlay then you may end up compiling a lot of programs.
I brought this up in the nvd project and got some helpful feedback from the author. You may want to take a look at that issue; the tl;dr is that you have the option of tweaking this example slightly to look at the derivations themselves rather than the built derivations to save on compile cycles. There haven’t been any changes in nvd yet, but it seems like there are options for a more lightweight system diff.
This config causes the build to run once a day (and also run immediately, if the task was missed), so impact will be pretty low I think.
Added NixOS specific code -heavily inspired by your post- to my already existing ‘updates.sh’ script, which I use with i3blocks:
case "$distro" in
arch)
# check for pending updates
if ping -q -c 1 -W 1 1.1.1.1 >/dev/null 2>&1; then
pending_updates="$(checkupdates)"
else
exit 0
fi
# check if a reboot is required
if [ "$(pacman -Q linux | sed 's/^linux //')" = "$(uname -r | sed 's/-arch/.arch/')" ]; then
reboot_required="false"
else
reboot_required="true"
fi
;;
nixos)
# check for pending updates
# - heavily inspired by this post: https://blog.tjll.net/previewing-nixos-system-updates/
nixos_current_system="/run/current-system"
nixos_system="/nix/var/nix/profiles/system"
if [ -d "$nixos_current_system" ] && [ -d "$nixos_system" ]; then
nixos_current_system_hash="$(basename $(readlink -f "$nixos_current_system") | cut -d- -f1)"
nixos_system_hash="$(basename $(readlink -f "$nixos_system") | cut -d- -f1)"
if [ "$nixos_current_system_hash" != "$nixos_system_hash" ]; then
nvd_output_file="/tmp/.nvd-${nixos_current_system_hash}-${nixos_system_hash}"
if [ ! -f "$nvd_output_file" ] ; then
nvd_command="nvd diff "$nixos_current_system" "$nixos_system""
if [ -x "$(command -v nvd)" ] >/dev/null 2>&1; then
nvd_diff="$(eval "$nvd_command")"
else
nvd_diff="$(nix-shell --quiet -p nvd --command "$nvd_command")"
fi
echo "$nvd_diff" > "$nvd_output_file"
fi
if [ -r "$nvd_output_file" ] ; then
pending_updates="$(cat "$nvd_output_file" | tail -n +3 | grep -E "^\[(U|D|C).\]" | sed -e 's/\\/\\\\/g' -e 's/&/\&/g' -e 's/</\</g' -e 's/>/\>/g')"
else
exit 0
fi
else
pending_updates=""
fi
else
exit 0
fi
# check if a reboot is required
if diff <(readlink /run/booted-system/{initrd,kernel,kernel-modules}) <(readlink /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules}) >/dev/null 2>&1; then
reboot_required="false"
else
reboot_required="true"
fi
;;
esac
The script reuses the cached output of nvd if the hashes (of the current system and the system that will be activated on a switch or on the next reboot) have not (yet) changed.
Perhaps there’s a smarter way and/or some parts of the code can be simplified, but for me at the moment this seems to work nicely.
Thanks for pointing out the nvd issue, looks interesting I’ll be checking this out soon.