Declarative package management for normal users


#1

Hi. One of the first things that amazes me about Nixos is how convenient it is to manage packages from a .nix file. But this is restricted only to the super user. To install my personal packages, packages that would not make sense to be available in the whole system, I have to use nix-env in the terminal, and it’s a pain in the ass when there are many packages.

It would be great to have something like enviroment.userPackages; with pkgs; [];
It would also be great to have something nixos-rebuild for normal users.


#2

There are multiple ways of managing declarative profiles. 1) Attrset, compatible with imperative use of nix-env https://git.io/fAQHW ; 2) buildEnv, providing more control over the paths that are linked into the profile https://git.io/fp0aU ; 3) home-manager, providing nixos-like config for your ~ https://github.com/rycee/home-manager


#3

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 https://gist.github.com/danbst/f07d9760ed15dd844e141177cf7dd478. 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…)


#4

Thanks for the info, but the ways you show me are from third parties. They are not official. I imagined that there would be a way similar to how some packages can be configured in .nixpkgs / conf.nix.

I think the best thing will be that or report as a suggestion on Github.


#5

There exists an option for configuration.nix, but it requires root to apply changes:
https://nixos.org/nixos/options.html#users.users.<name%3F>.packages

The “official” way to support declarative user package collection is indeed via buildEnv:
https://nixos.org/nixpkgs/manual/#sec-declarative-package-management

(note that packageOverrides was superseded by overlays recently)


#6

I use the -f and -r flags of nix-env, along with a custom configuration file, for this purpose.

I have a file, ~/.config/nixpkgs/packages.nix, with contents like the following:

{ pkgs ? import <nixos> {}}:
with pkgs;
{
  # Packages go here
}

I then run nix-env -irf ~/.config/nixpkgs/packages.nix to make my profile match what is declared in that file. I leave it to you decide which set of tradeoffs you think are worthwhile.


#7

perhaps some more or less; relevant links discussion @ Pocnix: a proof-of-concept Nix CLI


#8

Thanks for the info, but the ways you show me are from third parties. They are not official.

Welcome to Nix. :stuck_out_tongue:

The “third parties” are often the same people who make NixOS, and a lot of tools that are integral to Nixpkgs don’t live in the NixOS organisation. It’s just the way things are. Often there’s no “official” way because there’s no point — somebody else has already addressed the need.