Nix expressions
A Nix expression is like any programming language expression: anything that evaluates to a value or a function. A value in this case can also be a list or a set. As a Nix module (file with extension .nix
) can contain any Nix expression, you would expect the NixOS configuration file (/etc/nixos/configuration.nix
) to contain a single Nix expression as its file contents.
The NixOS configuration file contains a Nix expression of the form:
{config, pkgs, ...}: { /* various configuration options */ }
If you look closely, you can see it's a function, because functions follow the form pattern: form
. You can also see it's a function that accepts a set and returns a set. E.g., if you have a function f = {x, y}: {a = x + y;}
, then you could call it as f {x=1; y=2;}
and get back a set {a=3;}
.
So that means that when you call nixos-rebuild switch
, something calls the function inside the NixOS configuration file with the set that must contain attributes config
and pkgs
.
imports
Following example of ./hardware-configuration.nix
, the simple way to extract the list of packages into a separate module packages.nix
is just to rip the environment.systemPackages
option out and put ./packages.nix
into imports
option. Your /etc/nixos/configuration.nix
would look like:
{ config, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
# Include the package list.
./packages.nix
];
# SOME STUFF
# SOME STUFF
}
Your /etc/nixos/packages.nix
would look like:
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [ emacs gitFull ];
}
How does that work? When you run nixos-rebuild switch
, the process that evaluates Nix expressions and decides to install packages and so on calls configuration.nix
with a set of attributes, some of which are config
and pkgs
.
It finds attribute imports
inside the returned set, so it evaluates every Nix expression in the modules that imports
contains with the same arguments (config
, pkgs
, etc).
You must have pkgs
as an argument (or, technically speaking, an attribute of a set, which itself is an argument) of a function in packages.nix
, because, from a Nix language perspective, the process might or might not call the function with the set that contains pkgs
. If it doesn't, what attribute would you refer to, when running with pkgs
?
You also must have ellipsis, because the function might be called with other attributes, not just pkgs
.
Why isn't there pkgs
in configuration.nix
? You can have it, but if you don't refer to it anywhere in the file, you can safely omit it, as the ellipsis would include them anyway.
Updating an attribute by calling an external function
Another way is just to make a function that returns a set with some attribute, and the value of that attribute you would put inside environment.systemPackages
. This is your configuration.nix
:
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
];
# SOME STUFF
environment.systemPackages = import ./packages.nix pkgs;
# SOME STUFF
}
Your packages.nix
:
pkgs: with pkgs; [ emacs gitFull ]
import ./packages.nix pkgs
means: load and return the Nix expression in ./packages.nix
and as it is a function, call it with an argument pkgs
. with pkgs; [ emacs gitFull ]
is a with-expression, it brings the scope of the expression before semicolon to the expression after semicolon. Without it, it would be [ pkgs.emacs pkgs.gitFull ]
.
Looking at the source it seems very likely you have another nixpkgs
directory somewhere in ~
.
nix-env
searches (recursively) all directories for default.nix
adding the parent directory as a top level attribute.
Using nix-env -f ~
seems like a bad idea - very much to search and chances for such collisions. Unless there's something I'm missing symlinking ~/nixpkgs
into ~/.nix-defexpr
seems like a good solution.
There's nothing wrong with simply using nix-env -f nixpkgs -iA exercism
. In this form nix sees a default.nix
directly in the -f
argument and uses that as the top level attribute set.
If you can't find another nixpkgs directory, I'd try using the --show-trace
option.
Best Answer
To upgrade NixOS:
nixos
: and update the channel (nix-channel --update
).If things go wrong you can reboot, select the previous generation, use
nix-channel
to add the old channel, and thennixos-rebuild boot
to make the working generation the default; I think it's more reliable to rebuild than to usenixos-rebuild --rollback
.Alternative process
If you want to try the upgrade without messing around with channels, you can use a GIT clone of the nixpkgs repo:
If all is well...
The downside to this approach is that subsequent calls to Nix tools, such as
nixos-rebuild
, require the-I
flag to specify the correct nixpkgs. That is, until you update the channel.