Upgrading Ubuntu’s Nix
I’ve been changing my Nix repos to use git-hashing, but this requires
a recent version of Nix (at least 2.27, to (a) support
git-hashing, (b) support the git:sha1 hash
algorithm, and (c) avoid some bugs in the implementation).
This can lead to some difficulties if we try updating a system that’s on an older version of Nix; e.g. we can’t get the newer Nix by switching to an upgraded NixOS configuration, if that NixOS configuration is using git-hashing somewhere! This isn’t too bad if we make sure to define the newer Nix in a way that can be built separately to our full system (e.g. I’ve done this in an overlay); then we can update a NixOS system in two steps: first adding the newer Nix, so we get a system that can use git-hashing; then using that to upgrade to the git-hashing-using NixOS configuration.
One place this won’t work, however, is when our Nix
installation is not being managed by Nix. This is the case on one of my
systems: an Ubuntu VM I use for work. In this case, I’ve installed the
nix-bin and nix-setup-systemd packages from
the Ubuntu repos.
nix bundle
A few years ago I used nix bundle to solve a similar
issue: using Nix to put a known-good JVM on to a non-Nix system. I ran
nix bundle to create a standalone Arx file (a tarball, made
self-extracting by prefixing it with a shell script), containing the
“runtime closure” of the desired JVM commands, so that all of its
dependencies would be extracted into place before the JVM was
invoked.
This time I want a similar thing, but using Dpkg (Ubuntu’s native
package manager) instead of Arx. Thankfully nix bundle is
modular, and there is already a toDEB bundler which can do
this, so I ran the following to make a package containing the newer
Nix:
nix bundle \
--bundler github:NixOS/bundlers#toDEB \
--impure \
--expr '{ nix = (import ./myPinnedNixpkgs.nix {
config = {};
overlays = [ (import ./myNixOverlay.nix) ];
}).nix-backport; }' \
nixThis created a deb-single-nix symlink (rather than the
result that nix-build usually makes)
containing our package, which can be installed like
sudo dpkg -i deb-single-nix/nix_1.0_amd64.deb and,
surprisingly, the resulting Nix works! (You may want to
systemctl restart nix-daemon too)
Why it works
There are a few reasons why this is enough to make our newer Nix work:
- Firstly, our package has a different name (
nix) than Ubuntu’s (nix-bin), so the latter won’t get replaced; we’ll have both packages installed. - Secondly, the
/bin/nixexecutable provided by our package will replace the old version installed bynix-bin. Since the path doesn’t change, all existing references (inPATH, etc.) will see our new version. - Finally, the
nix-binpackage provides a symlink/bin/nix-daemon -> /bin/nix. Since that just points to/bin/nix, it means our SystemD service will also use our new version, despite ournixpackage not providing anynix-daemoncommand itself!