Updating NixOS flake with Elisp
- As a nixos-unstable branch user, there are frequent updates to my system
- Since I use Nix Flakes, I can and want to keep detailed log of what changes came in with any update
- Doing so manually gets boring fast
My current flow looks like this:
cd /etc/nixos && nix flake update
- Copy the 'relevant' part of command output
- Open magit commit dialogue
floto trigger a `yasnippet' which adds a handy commit message by using current date and copied command output.
This generates a nice commit message that looks something like this:
flake.lock: 2023_09_15 • Updated input 'agenix': 'github:ryantm/agenix/d8c973fd228949736dedf61b7f8cc1ece3236792' (2023-07-24) → 'github:ryantm/agenix/20deb735cc405831ba04a0088fecb3887aa255c0' (2023-09-14) • Updated input 'home-manager': 'github:nix-community/home-manager/5171f5ef654425e09d9c2100f856d887da595437' (2023-09-11) → 'github:nix-community/home-manager/d9b88b43524db1591fb3d9410a21428198d75d49' (2023-09-13) • Updated input 'nixos-hardware': 'github:NixOS/nixos-hardware/ca41b8a227dd235b1b308217f116c7e6e84ad779' (2023-09-11) → 'github:NixOS/nixos-hardware/570256327eb6ca6f7bebe8d93af49459092a0c43' (2023-09-14) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/3a2786eea085f040a66ecde1bc3ddc7099f6dbeb' (2023-09-11) → 'github:nixos/nixpkgs/f2ea252d23ebc9a5336bf6a61e0644921f64e67c' (2023-09-14)
But these are still too many manual steps for me, especially for something I tend to run at least couple times a week.
So, with help of ChatGPT and amazing Emacs introspectability, I created an interactive function that does everything for me!
1(defun bhankas-nixos-flake-update () 2 "Update NixOS flake and commit changes to git with message." 3 (interactive) 4 5 (let ((command "cd /etc/nixos && sudo nix flake update") ;; the command 6 (regex (pcre-to-elisp "((^• Updated input .*)|(^\s+(→ )?'[^']+' \(.*\)$))")) ;; the regex for command output 7 (filtered-output "")) 8 9 ;; Step 1: Run the command 10 (setq command-output (shell-command-to-string command)) 11 12 ;; Step 2: Create a temporary buffer and copy the command output 13 (with-temp-buffer 14 (insert command-output) 15 16 ;; Step 3: Create commit message by appending matching lines to filtered-output 17 (goto-char (point-min)) 18 (while (re-search-forward regex nil t) 19 (setq filtered-output (concat filtered-output "\n" (match-string 0)))) 20 21 ;; Step 4: Create a git commit message with prepared filtered-output 22 (vc-git-checkin '("flake.lock") (concat "flake.lock: " (format-time-string "%Y_%m_%d") "\n\n" filtered-output)))))
This function relies on awesome pcre2el package, because I know PCRE and Elisp regex1 syntax is just similar enough but not quite that I can never remember it. The other dependency being built-in
vc package, which shouldn't be a problem for any modern distro user2