Enter Environment
Welcome to the third Nix pill. In the previous second pill we have
installed Nix on our running system. Now we can finally play with it a
little, things also apply to NixOS users.
Enter the environment
In the previous pill we created a nix user, so let's start by switching
user with su - nix. If your
~/.profile got evaluated, then your should now be able
to run commands like nix-env and
nix-store.
If that's not the case:
I remind you, ~/.nix-profile/etc points to the nix-1.7
derivation. At this point, we are in our nix user profile.
Install something
Finally something practical! Installation in the nix environment is an
interesting process. Let's install nix-repl, a simple command line tool
for playing with the Nix language. Yes, Nix is a
pure, lazy, functional language, not only a set of tools to
manage derivations.
Back to the installation:
Now you can run nix-repl. Things to notice:
We did install software as user, only for the nix user.
It created a new user environment. That's a new generation of our
nix user profile.
The nix-env
tool manages environments, profiles and their generations.
We installed nix-repl by derivation name minus the version. I repeat:
we did specify the derivation name
(minus the version) to install.
We can list generations without walking through the /nix hierarchy:
List installed derivations:
So, where did nix-repl really get installed?
which nix-repl is
~/.nix-profile.bin.nix-repl which points to the store.
We can also list the derivation paths with nix-env -q --out-path. So
that's how those derivation paths are called: the
output of a build.
Path merging
At this point you sure have the necessity to run "man". Even if you
already have man system-wide outside of the nix environment, you can
install and use it within nix with nix-env -i man. As
usual, a new generation will be created, and ~/.nix-profile will point to
it.
Lets inspect the profile
a bit:
Now that's interesting. When only nix-1.7 was installed, bin/ was a
symlink to nix-1.7. Now it's a real directory, no symlink.
All clear. nix-env merged the paths from the installed derivations.
which man points to the nix profile, rather than the
system man, because ~/.nix-profile/bin is at the head
of $PATH.
Rollback / switch generation
The last command installed "man". We should be at generation #3, unless
you changed something in the middle. Let's say we want to rollback to the
old generation:
Now nix-env -q does not list "man" anymore.
ls -l `which man` should now be your system installed
one.
Enough with the joke, let's go back to the last generation:
I invite you to read the manpage of nix-env. nix-env requires an operation
to perform, then there are common options for all operations, and there
are options specific to an operation.
You can of course also
uninstall and upgrade packages.
Querying the store
So far we learned how to query and manipulate the environment. But all
of the environment components point to the store.
To query and manipulate the store, there's the
nix-store command. We can do neat things, but we'll
only see some queries for now.
Show direct runtime dependencies of nix-repl:
The argument to nix-store can be anything as long as it points to the
nix store. It will follow symlinks.
It may not make sense for you right now, but let's print reverse
dependencies of nix-repl:
Did you expect it? Our environments depend upon nix-repl. Yes, the
environments are in the store, and since there are symlinks to nix-repl,
therefore the environment depends upon nix-repl
It lists two environments, generation 2 and generation 3.
The manifest.nix file contains metadata about the environment, such as
which derivations are installed. So that nix-env can list them, upgrade
or remove them. Guess what, the current manifest.nix can be found in
~/.nix-profile/manifest.nix.
Closures
The closures of a derivation is a list of all dependencies, recursively,
down to the bare minimum necessary to use that derivation.
Copying all those derivations to the nix store of another machine makes
you able to run "man" out of the box on that other machine. That's the
base of nix deployment, you can already foresee the potential when
deploying software in the cloud (hint:
nix-copy-closures and
nix-store --export).
A nicer view of the closure:
With the above command, you can know exactly why a
runtime dependency, being it direct or
indirect, has been picked for a given derivation.
Same applies to environments of course. As an exercise run
nix-store -q --tree ~/.nix-profile, see that the
first children are direct dependencies of the user environment:
the installed derivations, and the manifest.nix.
Dependency resolution
There isn't anything like apt which solves a SAT problem in order to
satisfy dependencies with lower and upper bounds on versions. Because
there's no need. A derivation X depends on derivation Y, always.
Fancy disrupt
Ops, that uninstalled all derivations from the environment, including
nix. We are not able to run nix-env, what now?
Environments are a convenience for the user, but Nix is still there, in
the store!
First pick one nix-1.7 derivation:
ls /nix/store/*nix-1.7, say
/nix/store/g21di262aql6xskx15z3qiw3zh3wmjlb-nix-1.7.
The first possibility is to rollback:
The second possibility is to install nix, thus creating a new generation:
Channels
So where are we getting packages from? We said something already in
pill 2.
There's a list of channels from which we get packages, usually we use a
single channel. The tool to manage channels is
nix-channel.
That's basically the contents of ~/.nix-channels.
Note: ~/.nix-channels is not a symlink to the
nix store!
To update the channel run nix-channel --update.
It will download the new nix expressions (descriptions of the packages),
create a new generation of the channels profile and unpack under
~/.nix-defexpr/channels.
That's much similar to apt-get update.
Conclusion
We learned how to query the user environment and to manipulate it by
installing and uninstalling software. Upgrading software is as straight
as it gets by reading
the manual
(nix-env -u '*' will upgrade all packages in the
environment).
Everytime we change the environment, a new generation gets created.
Switching between generations is easy and immediate.
Then we queried the store. We inspected the dependencies and reverse
dependencies of store paths.
We still see symlinks to compose paths from the nix store, our lovely
trick.
Quick analogy with programming languages. You have the heap with all the
objects, that's the nix store. You have objects that point to other
objects, those are the derivations. Will be this the right path?
Next pill
...we will learn the basics of the Nix language. The Nix language is used
to describe how to build derivations, and it's the base for everything
else including NixOS. Therefore it's very important to understand the
syntax and the semantics.