Nix expression for home packages

Sorry if this is a basic question, but I could not find the answer in Nix documentation.

I would like to install a set of “home” packages with Nix on several (Mac and Linux) computers. Instead of installing these packages with nix-env -i package1, nix-env -i package2, etc., I would prefer to write a nix expression containing the list of packages that I want to install. How can I do that?

Sébastien M nixos1@discoursemail.com writes:

Sorry if this is a basic question, but I could not find the answer in
Nix documentation.

I would like to install a set of “home” packages with Nix on several
(Mac and Linux) computers. Instead of installing these packages with
nix-env -i package1, nix-env -i package2, etc., I would prefer to
write a nix expression containing the list of packages that I want to
install. How can I do that?

I use ‘buildEnv’, with something like the following:

{ buildEnv, pkg1, pkg2, pkg3 }:

buildEnv {
  name  = "my-favourite-packages";
  paths = [ pkg1 pkg2 pkg3 ];
}

If this is in a file like ./my-favourite-packages.nix then we can do
‘(import {}).callPackage ./my-favourite-packages.nix {}’, e.g.
as the ‘-E’ argument to nix-env. An alternative is to use a file like
~/.nixpkgs/config.nix or ~/.config/nixpkgs/config.nix

Thanks for the suggestion. I’ve created a mypackages.nix file containing the following lines:

{ buildEnv, bash-completion, bash-interactive, coreutils, emacs }:

buildEnv {
  name  = "my-favourite-packages";
  paths = [ bash-completion bash-interactive coreutils emacs ];
}

but when I install the packages, I get the following error:

nix-env -i -E '(import {}).callPackage ./mypackages.nix {}'
error: cannot coerce a set to a string, at (string):1:2

It should be import <nixpkgs> {} – I suppose the html-tag-like part was lost in the message.

BTW, you don’t need to use the buildEnv indirection, as even plain attribute sets can be “installed” (all attributes get installed).

I get a different error:

nix-env -i -E '(import <nixpkgs> {}).callPackage ./mypackages.nix {}'
error: anonymous function at /Users/smaret/.nixpkgs/mypackages.nix:1:1 called without required argument 'bash-interactive', at /Users/smaret/Documents/Software/nixpkgs/lib/customisation.nix:69:12

I think you might want to replace the hyphenated names for the camelCase attribute names like so:

{ buildEnv, bashCompletion, bashInteractive, coreutils, emacs }:

buildEnv {
	name  = "my-favourite-packages";
	paths = [ bashCompletion bashInteractive coreutils emacs ];
}

Hope that helps.

Note: the names of the derivations that can be used to install/remove/update on the command-line are not necessarily the same as the nixpkgs attribute names.

$ nix repl
Welcome to Nix version 2.0.4. Type :? for help.

nix-repl> :l <nixpkgs>
Added 9307 variables.

nix-repl> bash<TAB>
bash               bash-supergenpass  bashInteractive    bashburn           bashmount
bash-completion    bashCompletion     bashSnippets       bashdb             bashplotlib

Above you see that bash-completion and bashCompletion exists in the nixpkgs attribute names, whereas bash-interactive does not exist (the source of the original error message above). So, I didn’t actually need to change bash-completion to bashCompletion in my modification, I merely did it due to learned convention.

2 Likes

I often import nixpkgs as a default argument, like this:

{pkgs ? import <nixpkgs> {}, ...}:
with pkgs; buildEnv { name = "environment"; paths = [bashInteractive]; }

Then the callPackage boilerplate is not needed when installing the file:

nix-env -i -E 'import ./mypackages.nix'

or nix-build can make a link to the user environment:

nix-build mypackages.nix -o myenv

Not sure if I understood your situation correctly, but I thought you might potentially be interested in home-manager.

you can also install per user packages from your configuration.nix via users.users.USER.packages = [] IIRC (search in man configuration.nix to make sure)

1 Like

I am surprised to learn about the users.users.USER.packages option!

When I first installed NixOS, I did a dumb and used an imperative command to create my non-root user. If I now add a users.users.USER section to my configuration.nix file, am I in danger of damaging my user or my home directory in some way?

roni

Nothing wrong with this :slight_smile:

I think this should be fine, though I would recommend setting users.users.<username>.uid to the existing UID. NixOS definitely shouldn’t touch your home directory if it already exists though.
EDIT: also isNormalUser = true;