Declarative package management for normal users

All approaches @Mic92 described are indeed declarative, however you have to edit file to add new package.

Would you give up imperative nix-env --install behavior for this? If not, then read next.

I’ve written a small (50 lines) bash script, that replaces 50% of nix-env. Here it is Imperative nix-env rewrite (so it becomes declarative) · GitHub. Add an alias (declaratively in NixOS or in ~/.profile)

alias nix-env=/path/to/script

It replaces nix-env with a thing, that supports 3 commands: install, uninstall and list.

$ nix-env list
nixpkgs.htop

$ nix-env uninstall calibre
Not installed

$ nix-env install calibre
scheduled install'n'update
error: undefined variable 'calibre' at /home/danbst/.config/nixpkgs/declarative-env.nix:7:1

$ nix-env install nixpkgs.calibre
scheduled install'n'update
replacing old 'declarative-collection'
installing 'declarative-collection'
building '/nix/store/2cnhxqwxl79qj81mfkrqpl7xr361i3z1-user-environment.drv'...
created 5054 symlinks in user environment
Success

$ nix-env install '(nixpkgs.htop.overrideAttrs (_: { name = "my-override"; }))'
scheduled install'n'update
replacing old 'declarative-collection'
installing 'declarative-collection'
these derivations will be built:
  /nix/store/fbggzpbs91ryysmdzc131vvkg8vm14yz-declarative-collection.drv
building '/nix/store/fbggzpbs91ryysmdzc131vvkg8vm14yz-declarative-collection.drv'...
building '/nix/store/wpb2w7vj3cq4lsl1syac7lhndahqc64r-user-environment.drv'...
created 5054 symlinks in user environment
Success

$ nix-env list
nixpkgs.calibre
(nixpkgs.htop.overrideAttrs (_: { name = "my-override"; }))

# Original nix-env is available as \nix-env

There are 3 distinctions from nix-env here (besides completely new CLI):

  • packages are identified by their attribute, instead of “name”. Just like in nix 2.0
  • it saves it’s installed packages state in simple format: line per package (original nix-env builds a maniphest.nix with lots of metadata, but most importantly, it doesn’t save attribute name in maniphest)
  • as a buildEnv wrapper, it maintains consistency among all installed pacakges (can upgrade/downgrade some unrelated package). Same behavior as for nixos-rebuild

In fact, nix-env list is an alias to cat ~/.config/nixpkgs/declarative. This list is used to build env:

$ cat /home/danbst/.config/nixpkgs/declarative-env.nix
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: /home/danbst/.config/nixpkgs/declarative-env.nix
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ let nixos = import <nixos> { }; in
   2   │ let nixpkgs = import <nixpkgs> { }; in
   3   │ let _pkgs = import <nixpkgs> { }; in
   4   │ rec { _paths = [
   5   │ nixpkgs.calibre
   6   │ (nixpkgs.htop.overrideAttrs (_: { name = "my-override"; }))
   7   │              ];
   8   │       env = _pkgs.buildEnv {
   9   │       name = ''declarative-collection'';
  10   │       paths = _paths;
  11   │ }; }
  12   │ # Updated successfully!
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

And installed atomically with original nix-env. Pretty much declarative’n’imperative now! (I have a feeling that people have done this before…)

10 Likes