Chapter 10 describes the directory structure of
~/.nix-profile, and explains how rollbacks work.
The chapter starts with a sort of complicated drawing of multi-user directories with like default profiles and custom ones and it’s way too much for me to follow and I don’t really care. I think it’s easier to just look at some examples on my current system, and imagine how I would generalize them to multiple users.
$ readlink ~/.nix-profile /nix/var/nix/profiles/per-user/ian/profile $ readlink /nix/var/nix/profiles/per-user/ian/profile profile-18-link $ readlink /nix/var/nix/profiles/per-user/ian/profile-18-link /nix/store/0hq28alc5ywci03nz2imv8rl0wv6nnyj-user-environment
That number in
profile-18-link seems to be the way that
rollback works – if we want to roll back, we just point the
profile symlink to
profile-17-link. In fact we can see everything that I’ve done so far:
$ ls -l /nix/var/nix/profiles/per-user/ian channels@ -> channels-1-link channels-1-link@ -> /nix/store/98kbm9c2p7m8h1mjppvc0sam1vvkpz85-user-environment profile@ -> profile-18-link profile-10-link@ -> /nix/store/jql328aa79xk37fnj4jvikdsv1g04hp0-user-environment profile-11-link@ -> /nix/store/4n1jlahyami9rzdfgc4x1w3i1niik3r7-user-environment profile-12-link@ -> /nix/store/jql328aa79xk37fnj4jvikdsv1g04hp0-user-environment profile-13-link@ -> /nix/store/4n1jlahyami9rzdfgc4x1w3i1niik3r7-user-environment profile-14-link@ -> /nix/store/jql328aa79xk37fnj4jvikdsv1g04hp0-user-environment profile-15-link@ -> /nix/store/0hq28alc5ywci03nz2imv8rl0wv6nnyj-user-environment profile-16-link@ -> /nix/store/jql328aa79xk37fnj4jvikdsv1g04hp0-user-environment profile-17-link@ -> /nix/store/4n1jlahyami9rzdfgc4x1w3i1niik3r7-user-environment profile-18-link@ -> /nix/store/0hq28alc5ywci03nz2imv8rl0wv6nnyj-user-environment profile-6-link@ -> /nix/store/r2rlv43ijmxh56ng799zqkm471jbvr7x-user-environment profile-7-link@ -> /nix/store/2ia4kf2kbhp4888jm9sawk8gzg5b4v4r-user-environment profile-8-link@ -> /nix/store/jql328aa79xk37fnj4jvikdsv1g04hp0-user-environment profile-9-link@ -> /nix/store/4n1jlahyami9rzdfgc4x1w3i1niik3r7-user-environment
I don’t have any profiles before 6 because I did a garbage collection during the quick start guide, which cleaned them up.
This is very neat. We can see that not only are profiles “versioned” when we run
nix-env commands, but channels appear to be versioned as well. We can also see that there are very few unique environments in this list – because I’ve mostly just been installing and uninstalling the
hello package, which reverts me back to a version that I’ve had before. And by the virtue of content-addressed file paths, we don’t need to duplicate those user environments. Love it.
I had previously suspected that this involved something called the “Nix database,” but it seems like it’s just names of symlinks. Or maybe that’s what the manual means by “Nix database” – just the files and directories that are in
/nix/var. I do not know yet.
If it is just stored on the file system, I have an unimportant question.
I learned previously that if I went from generation 10 to generation 1 (say), and then did something, I would create a generation 11. How does that work? Does Nix list all the files and find the biggest one? Doesn’t that mean that creating a new profile generation would use time and memory linear to the number of generations present? It could start from the current generation, and check forward until it found an empty space, since the common case is being very close to the top – that gives you constant memory, but now you’re performing a linear number of syscalls in the degenerate case, and if you ever had a sparse list you could end up with illogical numbering – so it could have a hybrid approach where– none of this matters. With frequent garbage collection, there is no universe in which this becomes a problem worth actually thinking about. But I’ve had to do this exact thing before in some hacky script and I always felt gross about it. Even though I know it doesn’t matter… it just feels like there should be some better way that I don’t know about.
I guess a better question is: if I switch to an earlier profile, then install something, then roll back, does it take me to the earlier profile? Or just
$ nix-env --switch-generation 10 switching from generation 18 to 10 $ nix-env -iA nixpkgs.hello installing 'hello-2.10' $ nix-env --rollback switching from generation 19 to 18
Okay. So yeah,
--rollback is just “do the obvious simple thing.” There is no separate history; we aren’t making a DAG where new generations know what they’re based on or something. Just file names. In fact…
$ nix-env --switch-generation 10 switching from generation 18 to 10 $ rm /nix/var/nix/profiles/per-user/ian/profile-15-link $ nix-env -iA nixpkgs.hello installing 'hello-2.10' $ readlink $(readlink ~/.nix-profile) profile-19-link
Huhhhh. That’s weird, right? I already had a generation 19. I rolled back to 18, then switched to ten, then made a new one… and got back to 19? Is it using like… some kind of start and length to decide what the next profile should be? I don’t know.
I can’t imagine this ever mattering. Let’s get back on track.
I look inside the profile, to see what I can see.
$ tree /nix/store/0hq28alc5ywci03nz2imv8rl0wv6nnyj-user-environment /nix/store/0hq28alc5ywci03nz2imv8rl0wv6nnyj-user-environment ├── Library -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/Library ├── bin │ ├── hello -> /nix/store/pakmb65sf3g2hkbm1fdgk2fh6hiij720-hello-2.10/bin/hello │ ├── nix -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix │ ├── nix-build -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-build │ ├── nix-channel -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-channel │ ├── nix-collect-garbage -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-collect-garbage │ ├── nix-copy-closure -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-copy-closure │ ├── nix-daemon -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-daemon │ ├── nix-env -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-env │ ├── nix-hash -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-hash │ ├── nix-instantiate -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-instantiate │ ├── nix-prefetch-url -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-prefetch-url │ ├── nix-shell -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-shell │ └── nix-store -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/bin/nix-store ├── etc │ ├── profile.d -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/etc/profile.d │ └── ssl -> /nix/store/ki7gssifc0xracrah8ygm63xj23wkjdz-nss-cacert-3.60/etc/ssl ├── lib -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/lib ├── libexec -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/libexec ├── manifest.nix -> /nix/store/1d6n6cw1ab1qk0d4vq1hw37rlg14zpcy-env-manifest.nix └── share ├── info -> /nix/store/pakmb65sf3g2hkbm1fdgk2fh6hiij720-hello-2.10/share/info ├── man │ ├── man1 │ │ ├── hello.1.gz -> /nix/store/pakmb65sf3g2hkbm1fdgk2fh6hiij720-hello-2.10/share/man/man1/hello.1.gz │ │ ├── nix-build.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-build.1.gz │ │ ├── nix-channel.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-channel.1.gz │ │ ├── nix-collect-garbage.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-collect-garbage.1.gz │ │ ├── nix-copy-closure.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-copy-closure.1.gz │ │ ├── nix-env.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-env.1.gz │ │ ├── nix-hash.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-hash.1.gz │ │ ├── nix-instantiate.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-instantiate.1.gz │ │ ├── nix-prefetch-url.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-prefetch-url.1.gz │ │ ├── nix-shell.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-shell.1.gz │ │ └── nix-store.1.gz -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man1/nix-store.1.gz │ ├── man5 -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man5 │ └── man8 -> /nix/store/1s7qdbi6fprms0hljsx9rq2fwr3fz1gi-nix-2.3.10-man/share/man/man8 └── nix -> /nix/store/q0z2kvkgrpvaipa87jl98qh7g5pym5fj-nix-2.3.10/share/nix
I can see
bin – that’s the directory that ultimately winds up in my
PATH, after following this somewhat tangled web of symlinks. As well as
share/man in my
nix.sh, which is sourced in my
nix-daemon.sh, which I assume is only relevant for multi-user Nix installations.
I tried to look at
manifest.nix but it was not pretty printed and I don’t know how to pretty print it yet so I just gave up.
lib seems to be what you’d guess – I recognize the string “boost” in some of the
Library is a macOS thing; it currently contains the equivalent of a systemd unit file for the Nix daemon – again, only relevant for multi-user Nix, I think. Don’t know what
libexec is. It contains a binary called
resolve-system-dependencies and a symlink back to
bin/nix. Probably not going to ever think about it.
The only other interesting thing in here is
# tree /nix/store/0hq28alc5ywci03nz2imv8rl0wv6nnyj-user-environment/share/nix /nix/store/0hq28alc5ywci03nz2imv8rl0wv6nnyj-user-environment/share/nix ├── corepkgs │ ├── buildenv.nix │ ├── config.nix │ ├── derivation.nix │ ├── fetchurl.nix │ ├── imported-drv-to-derivation.nix │ └── unpack-channel.nix └── sandbox ├── sandbox-defaults.sb ├── sandbox-minimal.sb └── sandbox-network.sb
I don’t know what all this is. Are these, like, built-in Nix functions? Or I suppose… semi-built-in? I don’t know. I don’t know what these are. I could read them. But I am tired, and I do not want to read them now.
Lastly, I learn that I can temporarily override my
~/.nix-profile by setting
nix-env --profile my/custom/path. Unlike
--file, this seems perfectly straightforward, and I will accept it without question.
- How do I pretty print Nix files?
- What are all those