NH - A nixos-rebuild and home-manager switch rewrite

viperML/nh: Yet another nix cli helper (github.com)

Hello :wave:

NH is a cli helper that reimplements some common tools:

  • nixos-rebuild {switch,boot,test}
  • home-manager switch
  • nix-collect-garbage -d

Some killer features:

  • Shows a pretty diff thanks to nvd of the rebuild transaction
  • Includes a handy --ask flag, to check the changes before comitting
  • Gets around some problems around specialisations (check README)
  • Automatically uses the env var FLAKE as the path to your system flake, so you don’t have to pass it as an arg

And yes, you could say it is a glorified script wrapper, but it served me to learn some rust.

Let me know if you have any issues or suggestions to improve the UX!

11 Likes

I cannot recommend reimplementing nixos-rebuild. If there are changes to it down the line, especially over multiple stable releases, the system could get into an unexpected state because the out of tree implementations where not considered in the migration path. I have already encountered issues where the system profile were not updated accordingly which lead to reboots reverting changes and gcroots missing.

The same for nix-collect-garbage. It may be stable now and didn’t change a lot in the past but that must not always be true for the future and messing with your nix store database could be dangerous.

Also FYI for version diffing there is already nix store diff-closures or Bryan Gardiner / nvd · GitLab

2 Likes

I cannot recommend reimplementing nixos-rebuild

I can’t even use it in tandem with specialisations, so my only choice is to rewrite it.

Also FYI for version diffing there is already nix store diff-closures or Bryan Gardiner / nvd · GitLab

I mention that I use nvd. I just prefer the format it outputs to its nix counterpart

3 Likes

We can agree on the fact, that there is a risk, though nixos-rebuild is plain broken when it comes to specialisations.

It will always activate the default. You have to manually re-activate the correct one. nh fixes this.

Also, as far as I can tell, some, if not all, remote deployment frameworks for nixos do at least partially re implement it, why not tell those the same?

From what I can tell, nh is more feature complete.

As I really hate the -d/--delete-old flag, do you also have some --delete-older-than equivalent? Perhaps by count even (keep at least 5 entries of the last 7 days)?

Is nh able to delete the GC roots, but not do an actual GC?

Can nh help me, finding auto-roots created by nix build and others? Might it even be able to help me deleting old nix-direnv “generations”?

do you also have some --delete-older-than equivalent?

No, as I don’t really use it, but I will add it to the to-do list.

Perhaps by count even (keep at least 5 entries of the last 7 days)?

This seems like a great idea. A problem I see, is that it would apply to every profile. For example: keep latest 5 entries of the nixos and HM config.

It could also have problems when dealing with HM, as it uses 2 profiles that are not synchronized (/nix/var/nix/profiles/per-user/$USER/{profile,home-manager}. Maybe home-manager-(X-5)-generation is included in profile-(Y-4)-generation, which could lead to a broken state. But it could be inspected with nix path-info, so I will need to investigate it further.

Can nh help me, finding auto-roots created by nix build and others? Might it even be able to help me deleting old nix-direnv “generations”?

My initial idea for nh clean was to clean auto GC roots, but quickly I discovered that I was “cleaning too much”, so I disabled it. A non exhaustive list of what I could find in /nix/var/nix/{gcroots,per-user}:

  • ./result artifacts from nix build
  • nix-direnv gcroots
  • generations gcroots
  • Some runtime roots that I don’t know its purpose, like /home/ayats/.vscode-server/data/User/globalStorage/rust-lang.rust-analyzer/rust-analyzer or /home/ayats/.cache/nix/flake-registry.json

And I don’t know how “smart” I want to make nh clean for this task. Maybe let the user pass a pattern to match against the filenames? Or just include some default presets like cleaning result and .direnv ?

1 Like

Another option would be to fork nixpkgs and adjust nixos-rebuild. I think a specialisation option is something we should add. Maybe we can query the current one and switch to that instead?

That is not quite correct. A missing feature does not make it broken. It’s just that so far no one implemented that feature.

nix-env can do that with the profile flag and using +3 when deleting generations.

Okay, I need some explanation, how does “+3” resolve to “at least 5 entries of the last 7 days”?

It resolves to keep the latest 3, no matter the date.

Thats not what I was asking for.

I was asking for at least 5 of the last 7 days.

If there have been 6 in the last 7 days, keep all, if there have been 4 in the last 7 days, keep one that is older.

I am not sure if this is even possible. If a system generation would keep the build date it would not be reproducible.

As nixos-collect-garbage is able to check by date, the age is possible to check.

Also, the generation doesn’t need to be reproducible, just the build that lead to it.

Even if you omit the date information, you can not reproduce “generation 5”. In best case you can build a “Generation x+1” that uses the same inputs as “Generation 5” back then, and therefore might even be bit-by-bit identical, but it doesn’t necessarily have to.

I agree, the store content shouldn’t know anything about actual time. But the GC-roots may of course know their age.