Skip to content

Instantly share code, notes, and snippets.

@0atman
Last active July 25, 2024 16:57
Show Gist options
  • Save 0atman/1a5133b842f929ba4c1e195ee67599d5 to your computer and use it in GitHub Desktop.
Save 0atman/1a5133b842f929ba4c1e195ee67599d5 to your computer and use it in GitHub Desktop.
A rebuild script that commits on a successful build
{
config,
pkgs,
options,
...
}: let
hostname = "oatman-pc"; # to alllow per-machine config
in {
networking.hostName = hostname;
imports = [
/etc/nixos/hardware-configuration.nix
(/home/oatman/dotfiles/nixos + "/${hostname}.nix")
];
}
#!/usr/bin/env bash
#
# I believe there are a few ways to do this:
#
# 1. My current way, using a minimal /etc/nixos/configuration.nix that just imports my config from my home directory (see it in the gist)
# 2. Symlinking to your own configuration.nix in your home directory (I think I tried and abandoned this and links made relative paths weird)
# 3. My new favourite way: as @clot27 says, you can provide nixos-rebuild with a path to the config, allowing it to be entirely inside your dotfies, with zero bootstrapping of files required.
# `nixos-rebuild switch -I nixos-config=path/to/configuration.nix`
# 4. If you uses a flake as your primary config, you can specify a path to `configuration.nix` in it and then `nixos-rebuild switch —flake` path/to/directory
# As I hope was clear from the video, I am new to nixos, and there may be other, better, options, in which case I'd love to know them! (I'll update the gist if so)
# A rebuild script that commits on a successful build
set -e
# Edit your config
$EDITOR configuration.nix
# cd to your config dir
pushd ~/dotfiles/nixos/
# Early return if no changes were detected (thanks @singiamtel!)
if git diff --quiet '*.nix'; then
echo "No changes detected, exiting."
popd
exit 0
fi
# Autoformat your nix files
alejandra . &>/dev/null \
|| ( alejandra . ; echo "formatting failed!" && exit 1)
# Shows your changes
git diff -U0 '*.nix'
echo "NixOS Rebuilding..."
# Rebuild, output simplified errors, log trackebacks
sudo nixos-rebuild switch &>nixos-switch.log || (cat nixos-switch.log | grep --color error && exit 1)
# Get current generation metadata
current=$(nixos-rebuild list-generations | grep current)
# Commit all changes witih the generation metadata
git commit -am "$current"
# Back to where you were
popd
# Notify all OK!
notify-send -e "NixOS Rebuilt OK!" --icon=software-update-available
@0atman
Copy link
Author

0atman commented Mar 15, 2024

@singiamtel omg that's genius, I've added it to the gist, works great!

@Lemm1
Copy link

Lemm1 commented Mar 18, 2024

Thanks for sharing this script. Now, I won't ruin my system because I messed up my configuration.nix. One improvement that I made when I started using it was to handle the script itself the nix way by storing is a nixos-rebuild.nix file:

{
  config,
  pkgs,
  ...
}: {
  environment.systemPackages = with pkgs; [
    (writeShellScriptBin "nixos-rebuild.sh" ''
    // Script without shebang
        '')
  ];
}

And just importing it in my managed version of configuration.nix. This way, I don't need to think about shebang and my script is also versioned via NixOS using generations too.

@aikomastboom
Copy link

my changes so far:

alejandra . &>/dev/null \
  || ( alejandra . ; echo "formatting failed!" && exit 1)

and:

SUDO="sudo"
if [ "$(id -u)" == "0" ]; then
  SUDO="" # already root
fi

# $SUDO nixos-rebuild switch --flake .#${HOST} &> nixos-switch.log \
$SUDO nixos-rebuild switch &> nixos-switch.log \
  || (cat nixos-switch.log | grep --color error && false)

not sure why the git diff check is above editing the configuration.nix, I would put it below 🙃.

@0atman
Copy link
Author

0atman commented Mar 19, 2024

One improvement that I made when I started using it was to handle the script itself the nix way by storing is a nixos-rebuild.nix file:
@Lemm1

Very interesting idea! I have a clean division between my system (managed by nixos) and my home directory and dotfiles (managed by ME). So I don't think I'll do this just yet, but everyone else, take note!

@0atman
Copy link
Author

0atman commented Mar 19, 2024

@aikomastboom love the alejandra tweak - added.

Interesting sudo tweak - but on my machine root using sudo is a no-op and can safely run both normal and sudoed commands?

@aikomastboom
Copy link

Yeah, I know.. I came across it when fiddling with a VM that only had root and no sudo installed

I like the idea to nixify the script too ( to ensure those dependency commands are available)

@MvRens
Copy link

MvRens commented Mar 19, 2024

Fellow NixOS noob here thanks to your video! thanks for sharing this script as well.

FYI, I had to surround the two references to '*.nix' in single quotes to prevent bash from expanding the glob which resulted in 'No changes detected' and no diff output. Probably because my configuration is mostly in subfolders.

@0atman
Copy link
Author

0atman commented Mar 20, 2024

@MvRens updated, well spotted!

@mipdableep
Copy link

Hi! First of all, great video and an amazing script!
A weird problem i got stuck with is the fact that the nixos-rebuild hashing would not rebuild if the git repo was dirty - this blog post helped but i realized that staging the files fixed it - git add ./*.nix before the rebuild stage.
Aside from that, i found that using sudo nix-env -p /nix/var/nix/profiles/system --list-generations | grep "current" gave a cleaner output then nixos-rebuild list-generations

@JustCoderdev
Copy link

I added a bit where if a rebuild fails it asks if you want to open the logs or not

# In my case I use flakes but here it checks whether it fails or not
if sudo nixos-rebuild switch --flake ".#$1" &>.nixos-switch.log; then
	echo -e "Done\n"
else
	echo ""
	cat .nixos-switch.log | grep --color error

	# this is needed otherwise the script would not start next time telling you "no changes detected"
	# (The weird patter is to include all subdirectories)
	sudo git restore --staged ./**/*.nix

	if read -p "Open log? (y/N): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]]; then
		cat .nixos-switch.log | vim - 	
	fi

	# Clean stuff and exit
	shopt -u globstar
	popd > /dev/null
	exit 1
fi

thx @0atman for the *hem inspiration ;)

@0atman
Copy link
Author

0atman commented Mar 26, 2024

Very cool!

@taiwithers
Copy link

Here's a version that's I edited to work with Home Manager and custom *.nix file locations, I've also added a segment to check for untracked *.nix files since these don't get picked up by git diff
Not sure if ether of those things are useful to anyone else but shrug

@Mjb141
Copy link

Mjb141 commented May 25, 2024

Thanks for sharing this script. Now, I won't ruin my system because I messed up my configuration.nix. One improvement that I made when I started using it was to handle the script itself the nix way by storing is a nixos-rebuild.nix file:

{
  config,
  pkgs,
  ...
}: {
  environment.systemPackages = with pkgs; [
    (writeShellScriptBin "nixos-rebuild.sh" ''
    // Script without shebang
        '')
  ];
}

And just importing it in my managed version of configuration.nix. This way, I don't need to think about shebang and my script is also versioned via NixOS using generations too.

Can you link how you've done this? I've imported such a file into my configuration.nix but it's not making the script findable on PATH.

@Lemm1
Copy link

Lemm1 commented May 26, 2024

Can you link how you've done this? I've imported such a file into my configuration.nix but it's not making the script findable on PATH.

You need to rebuild the system first use simple nixos-rebuild switch once so script is generated by nix and added to PATH

@Mjb141
Copy link

Mjb141 commented May 26, 2024

Yeah all good, got it working shortly afterwards. Added to it with a Home-Manager step as well, very useful script!

@ArgumentumAdUlgenum
Copy link

Hi Tris, thanks to you I benefit from NixOS and I recently stumbled to a tool called nh that can be integrated to your workflow, you might want to check it out.

@0atman
Copy link
Author

0atman commented Jul 15, 2024

@ArgumentumAdUlgenum yeah! I also recently discovered nh (thanks to the #nix channel on my discord) - and really like it.

HOWEVER, I recently switched my whole setup away from flakes to get back unattended upgrade (and some other reasons) , which means I can't use nh (it requires flakes). However, as there are only 3 main features, according to the readme:

  • Tree of builds with nix-output-monitor
  • Visualization of the upgrade diff with nvd
  • Asking for confirmation before performing activation

... The only one of those features I didn't really have (due to my git diff printing) was the build tree visualising using nom, which is easy enough to add on to this existing script! 😁

For those who want it, the line is

sudo nixos-rebuild --upgrade switch --log-format internal-json |& nom --json

which outputs the log in json, that nom consumes.

@ArgumentumAdUlgenum
Copy link

So, I tried to make a flake free configuration and arrived at conclusion flakes makes it far easier to deal with dependencies to other nix projects like home-manager or nixvim.

As far as I know you use Nix to just configure your computer, your dotfiles are managed outside of Nix. If you ever decide to change from this paradigm, you might want to give flakes another chance.

See you later Tris.

@0atman
Copy link
Author

0atman commented Jul 25, 2024

Yeah, I actually abandoned not having flakes enabled after a day - so many tools assume you've got a flakes system. The rust flake works very well, for instance. I'm down to use it for links to these other projects - but not core system stuff.

I'm sad though: My dream of unattended upgrades seems dead. By design, flakes don't update their lockfile without user input, right?
The difference between me and many nix folks is that I don't care about reproducibility. I care about stability and bleeding-edge features. Lucky for me, Nixos gives me that!

I did indeed trynixvim for a while, but lazynvim is turnkey, so I'm simply using that. Home Assistant is fine, but I don't think it makes sense for my low-stress life. I want my config to instantly change when I change a config file, not requiring a hm switch - an symlinks work great for that!
Using GNU Stow I run stow . on my dotfiles directory, and with no config, everything's symlinked into my home directory. I get config rollback with git, and given that neither HM or Stow is linked to my nixos system generations... feels like I'm not missing anything?

@taiwithers
Copy link

I'm sad though: My dream of unattended upgrades seems dead. By design, flakes don't update their lockfile without user input, right? The difference between me and many nix folks is that I don't care about reproducibility. I care about stability and bleeding-edge features. Lucky for me, Nixos gives me that!

Ditto on the reproducability (I want reproducability in my package set and configs but versions are unimportant to me). It's not quite "unattended", but you could add a nix flake update line into your rebuild script and update lock files that way

@0atman
Copy link
Author

0atman commented Jul 25, 2024

Very good point. I could perhaps run that on a cron?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment