2020-07-23 00:17:48 +03:00
|
|
|
|
# Profiles
|
|
|
|
|
|
|
|
|
|
Profiles and user environments are Nix’s mechanism for implementing the
|
|
|
|
|
ability to allow different users to have different configurations, and
|
|
|
|
|
to do atomic upgrades and rollbacks. To understand how they work, it’s
|
|
|
|
|
useful to know a bit about how Nix works. In Nix, packages are stored in
|
|
|
|
|
unique locations in the *Nix store* (typically, `/nix/store`). For
|
|
|
|
|
instance, a particular version of the Subversion package might be stored
|
|
|
|
|
in a directory
|
|
|
|
|
`/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3/`, while
|
|
|
|
|
another version might be stored in
|
|
|
|
|
`/nix/store/5mq2jcn36ldlmh93yj1n8s9c95pj7c5s-subversion-1.1.2`. The long
|
2020-07-24 12:43:44 +03:00
|
|
|
|
strings prefixed to the directory names are cryptographic hashes (to be
|
|
|
|
|
precise, 160-bit truncations of SHA-256 hashes encoded in a base-32
|
|
|
|
|
notation) of *all* inputs involved in building the package — sources,
|
|
|
|
|
dependencies, compiler flags, and so on. So if two packages differ in
|
|
|
|
|
any way, they end up in different locations in the file system, so they
|
|
|
|
|
don’t interfere with each other. Here is what a part of a typical Nix
|
|
|
|
|
store looks like:
|
2020-07-23 00:17:48 +03:00
|
|
|
|
|
2020-07-23 15:16:46 +03:00
|
|
|
|
![](../figures/user-environments.png)
|
2020-07-23 00:17:48 +03:00
|
|
|
|
|
|
|
|
|
Of course, you wouldn’t want to type
|
|
|
|
|
|
|
|
|
|
$ /nix/store/dpmvp969yhdq...-subversion-1.1.3/bin/svn
|
|
|
|
|
|
|
|
|
|
every time you want to run Subversion. Of course we could set up the
|
2020-07-23 11:44:54 +03:00
|
|
|
|
`PATH` environment variable to include the `bin` directory of every
|
2020-07-23 00:17:48 +03:00
|
|
|
|
package we want to use, but this is not very convenient since changing
|
2020-07-23 11:44:54 +03:00
|
|
|
|
`PATH` doesn’t take effect for already existing processes. The solution
|
2020-07-23 00:17:48 +03:00
|
|
|
|
Nix uses is to create directory trees of symlinks to *activated*
|
|
|
|
|
packages. These are called *user environments* and they are packages
|
|
|
|
|
themselves (though automatically generated by `nix-env`), so they too
|
2020-07-23 15:16:46 +03:00
|
|
|
|
reside in the Nix store. For instance, in the figure above, the user
|
|
|
|
|
environment `/nix/store/0c1p5z4kda11...-user-env` contains a symlink to
|
|
|
|
|
just Subversion 1.1.2 (arrows in the figure indicate symlinks). This
|
|
|
|
|
would be what we would obtain if we had done
|
2020-07-23 00:17:48 +03:00
|
|
|
|
|
|
|
|
|
$ nix-env -i subversion
|
|
|
|
|
|
|
|
|
|
on a set of Nix expressions that contained Subversion 1.1.2.
|
|
|
|
|
|
|
|
|
|
This doesn’t in itself solve the problem, of course; you wouldn’t want
|
|
|
|
|
to type `/nix/store/0c1p5z4kda11...-user-env/bin/svn` either. That’s why
|
|
|
|
|
there are symlinks outside of the store that point to the user
|
|
|
|
|
environments in the store; for instance, the symlinks `default-42-link`
|
|
|
|
|
and `default-43-link` in the example. These are called *generations*
|
|
|
|
|
since every time you perform a `nix-env` operation, a new user
|
|
|
|
|
environment is generated based on the current one. For instance,
|
|
|
|
|
generation 43 was created from generation 42 when we did
|
|
|
|
|
|
|
|
|
|
$ nix-env -i subversion firefox
|
|
|
|
|
|
|
|
|
|
on a set of Nix expressions that contained Firefox and a new version of
|
|
|
|
|
Subversion.
|
|
|
|
|
|
|
|
|
|
Generations are grouped together into *profiles* so that different users
|
|
|
|
|
don’t interfere with each other if they don’t want to. For example:
|
|
|
|
|
|
|
|
|
|
$ ls -l /nix/var/nix/profiles/
|
|
|
|
|
...
|
|
|
|
|
lrwxrwxrwx 1 eelco ... default-42-link -> /nix/store/0c1p5z4kda11...-user-env
|
|
|
|
|
lrwxrwxrwx 1 eelco ... default-43-link -> /nix/store/3aw2pdyx2jfc...-user-env
|
|
|
|
|
lrwxrwxrwx 1 eelco ... default -> default-43-link
|
|
|
|
|
|
|
|
|
|
This shows a profile called `default`. The file `default` itself is
|
|
|
|
|
actually a symlink that points to the current generation. When we do a
|
|
|
|
|
`nix-env` operation, a new user environment and generation link are
|
|
|
|
|
created based on the current one, and finally the `default` symlink is
|
|
|
|
|
made to point at the new generation. This last step is atomic on Unix,
|
|
|
|
|
which explains how we can do atomic upgrades. (Note that the
|
|
|
|
|
building/installing of new packages doesn’t interfere in any way with
|
|
|
|
|
old packages, since they are stored in different locations in the Nix
|
|
|
|
|
store.)
|
|
|
|
|
|
|
|
|
|
If you find that you want to undo a `nix-env` operation, you can just do
|
|
|
|
|
|
|
|
|
|
$ nix-env --rollback
|
|
|
|
|
|
|
|
|
|
which will just make the current generation link point at the previous
|
|
|
|
|
link. E.g., `default` would be made to point at `default-42-link`. You
|
|
|
|
|
can also switch to a specific generation:
|
|
|
|
|
|
|
|
|
|
$ nix-env --switch-generation 43
|
|
|
|
|
|
|
|
|
|
which in this example would roll forward to generation 43 again. You can
|
|
|
|
|
also see all available generations:
|
|
|
|
|
|
|
|
|
|
$ nix-env --list-generations
|
|
|
|
|
|
|
|
|
|
You generally wouldn’t have `/nix/var/nix/profiles/some-profile/bin` in
|
2020-07-23 11:44:54 +03:00
|
|
|
|
your `PATH`. Rather, there is a symlink `~/.nix-profile` that points to
|
2020-07-23 00:17:48 +03:00
|
|
|
|
your current profile. This means that you should put
|
2020-07-23 11:44:54 +03:00
|
|
|
|
`~/.nix-profile/bin` in your `PATH` (and indeed, that’s what the
|
2020-07-23 00:17:48 +03:00
|
|
|
|
initialisation script `/nix/etc/profile.d/nix.sh` does). This makes it
|
|
|
|
|
easier to switch to a different profile. You can do that using the
|
|
|
|
|
command `nix-env --switch-profile`:
|
|
|
|
|
|
|
|
|
|
$ nix-env --switch-profile /nix/var/nix/profiles/my-profile
|
|
|
|
|
|
|
|
|
|
$ nix-env --switch-profile /nix/var/nix/profiles/default
|
|
|
|
|
|
|
|
|
|
These commands switch to the `my-profile` and default profile,
|
|
|
|
|
respectively. If the profile doesn’t exist, it will be created
|
|
|
|
|
automatically. You should be careful about storing a profile in another
|
|
|
|
|
location than the `profiles` directory, since otherwise it might not be
|
2020-07-24 15:31:33 +03:00
|
|
|
|
used as a root of the [garbage collector](garbage-collection.md).
|
2020-07-23 00:17:48 +03:00
|
|
|
|
|
|
|
|
|
All `nix-env` operations work on the profile pointed to by
|
|
|
|
|
`~/.nix-profile`, but you can override this using the `--profile` option
|
|
|
|
|
(abbreviation `-p`):
|
|
|
|
|
|
|
|
|
|
$ nix-env -p /nix/var/nix/profiles/other-profile -i subversion
|
|
|
|
|
|
|
|
|
|
This will *not* change the `~/.nix-profile` symlink.
|