mirror of
https://github.com/foo-dogsquared/website.git
synced 2025-01-31 10:58:33 +00:00
266 lines
11 KiB
Plaintext
266 lines
11 KiB
Plaintext
---
|
||
title: "Speeding up NixOS package search on the terminal"
|
||
publishdate: 2023-11-10T00:00:00+00:00
|
||
---
|
||
|
||
= Speeding up NixOS package search on the terminal
|
||
Gabriel Arazas <foodogsquared@foodogsquared.one>
|
||
v1.1.0, 2023-11-10: Fix erroneous code
|
||
|
||
:doccontentref: refs/heads/content/posts/2023-11-10-speeding-up-nix-package-search-on-the-terminal
|
||
|
||
|
||
For those who are using the new command-line interface of Nix, you've most likely went through to pain of searching packages through `nix search`.
|
||
For reference, here's what the experience looks like searching for a package from nixpkgs except it always like that every time you run the command. footnote:[Not necessarily, just every few hours as you'll see why.]
|
||
|
||
[#video:nix-search-demo]
|
||
.A part of the `nix search nixpkgs` experience which took 8 minutes in total to complete the whole search
|
||
video::./assets/nix-search-part-demo.mp4[]
|
||
|
||
It's painful to use to the point where people tend to recommend https://search.nixos.org/packages[search.nixos.org] or https://mynixos.com/[MyNixOS] for searching packages. footnote:[They also include searching for NixOS options so that may be another reason these tools are always recommended.]
|
||
Ideally, searching packages for your system shouldn't rely on online services.
|
||
Luckily for us, there are ways how to mitigate against that.
|
||
|
||
[chat, Ezran]
|
||
====
|
||
I'm just going to say it.
|
||
That package search result looks ugly.
|
||
====
|
||
|
||
[chat, foodogsquared, role=reversed]
|
||
====
|
||
That might be another reason why `nix search` is not much used.
|
||
====
|
||
|
||
[WARNING]
|
||
====
|
||
We're using Nix v2.18 for this post.
|
||
Everything that is featured here is considered to be experimental: from flakes, the command-line interface, and even the referenced manual may change over time.
|
||
|
||
In order to enable them in the first place, you'll have to add `experimental-features = nix-command flake` into the Nix configuration (see https://nixos.org/manual/nix/stable/command-ref/conf-file[`nix.conf` options] for more details).
|
||
====
|
||
|
||
|
||
|
||
|
||
[#whats-happening-with-nix-search]
|
||
== What's happening with `nix search`
|
||
|
||
But first, let's take a closer inspection as to why `nix search` is behaving like that.
|
||
Let's look at the following command which is https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-search[one of the examples from the manual].
|
||
|
||
[source, shell]
|
||
----
|
||
nix search nixpkgs blender
|
||
----
|
||
|
||
At first glance, most people expect `nix search nixpkgs blender` searches for package `blender` from their nixpkgs instance.
|
||
It does work as intended which is searching through packages from nixpkgs containing the word `blender`.
|
||
Just not our own nixpkgs instance.
|
||
It just doesn't behave to how most people expect as they overlook one thing about flakes: the registry.
|
||
Per https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-registry[the manual]:
|
||
|
||
[#quote:flake-registry-intro]
|
||
[quote, Nix manual]
|
||
____
|
||
Flake registries are a convenience feature that allows you to refer to flakes using symbolic identifiers such as `nixpkgs`, rather than full URLs such as `git://github.com/NixOS/nixpkgs`.
|
||
You can use these identifiers on the command line (e.g. when you do `nix run nixpkgs#hello`) or in flake input specifications in `flake.nix` files.
|
||
The latter are automatically resolved to full URLs and recorded in the flake’s `flake.lock` file.
|
||
____
|
||
|
||
In short, `nixpkgs` from `nix search nixpkgs blender` points to a flake from the registry.
|
||
We can view what `nixpkgs` points to by running `nix registry list`.
|
||
|
||
[#lst:cmd-nix-registry-list]
|
||
.Results from `nix registry list | grep flake:nixpkgs`
|
||
[source]
|
||
----
|
||
global flake:nixpkgs github:NixOS/nixpkgs/nixpkgs-unstable
|
||
----
|
||
|
||
As stated from https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-registry-list[the manual], the format from the `nix registry list` output comes in the form of `<type> <from> <to>` where...
|
||
|
||
* `type` denotes which registry it came from (which we'll discuss shortly later in this post).
|
||
* `from` typically has the flake identifier.
|
||
* `to` refers to the flake reference it points to (e.g., `github:NixOS/nixpkgs`, `github:nixos-community/home-manager`).
|
||
|
||
We can see that nixpkgs points to the github:NixOS/nixpkgs[nixpkgs-unstable branch, rev=nixpkgs-unstable].
|
||
That is, `nix search nixpkgs blender` is pretty much the same as the following command.
|
||
|
||
[source, shell]
|
||
----
|
||
nix search github:NixOS/nixpkgs/nixpkgs-unstable blender
|
||
----
|
||
|
||
This seems fine except the flake reference isn't pointing to a fixed point like a specific commit, it points to a branch of a remote Git repo which can change over time.
|
||
|
||
So every time you run the command, `nixpkgs` resolves to the most recent version of nixpkgs-unstable.
|
||
This is why it downloads and evaluates a new nixpkgs instance every time it runs (or between every few hours, which is the pace for nixpkgs-unstable updates).
|
||
Not exactly a good experience for a system package search compared to other operating systems like Arch Linux, Fedora, or OpenSUSE.
|
||
|
||
[chat, Ezran]
|
||
====
|
||
Seem like flake registry is not a convenience feature at all.
|
||
More like a hindrance, really.
|
||
====
|
||
|
||
[chat, foodogsquared, role=reversed]
|
||
====
|
||
It is a CONVENIENCE FEATURE!
|
||
I use it to quickly test and run packages from my nixpkgs instance as well as other projects with flake.
|
||
|
||
It's just that most NixOS systems are not properly configured with it by default.
|
||
You'll see what I mean.
|
||
====
|
||
|
||
|
||
|
||
|
||
[#pinning-nixpkgs-to-the-registry]
|
||
== Pinning nixpkgs to the registry
|
||
|
||
Most would expect to search packages in their nixpkgs instance of their NixOS system.
|
||
As hinted from the previous section, we can make use of multiple registries.
|
||
As stated right after the <<quote:flake-registry-intro, previous excerpt from the manual>>:
|
||
|
||
[#quote:manual-multiple-flake-registries]
|
||
[quote, Nix manual]
|
||
____
|
||
There are multiple registries.
|
||
These are, in order from lowest to highest precedence:
|
||
|
||
* The global registry, which is a file downloaded from the URL specified by the setting `flake-registry`.
|
||
It is cached locally and updated automatically when it's older than `tarball-ttl` seconds.
|
||
The default global registry is kept in https://github.com/NixOS/flake-registry[a GitHub repository].
|
||
|
||
* The system registry, which is shared by all users.
|
||
The default location is `/etc/nix/registry.json`.
|
||
On NixOS, the system registry can be specified using the NixOS option `nix.registry`.
|
||
|
||
* The user registry `~/.config/nix/registry.json`.
|
||
This registry can be modified by commands such as `nix registry pin`.
|
||
|
||
* Overrides specified on the command line using the option `--override-flake`.
|
||
____
|
||
|
||
A quick way to show this would be pinning `nixpkgs` from the global registry to the user registry with `nix registry pin nixpkgs`.
|
||
|
||
.Results from `nix registry list | grep 'flake:nixpkgs'` after pinning
|
||
[source, shell]
|
||
----
|
||
user flake:nixpkgs github:NixOS/nixpkgs/ec750fd01963ab6b20ee1f0cb488754e8036d89d
|
||
global flake:nixpkgs github:NixOS/nixpkgs/nixpkgs-unstable
|
||
----
|
||
|
||
[NOTE]
|
||
====
|
||
Since we're going to show configuring the system registry with NixOS, don't forget to remove the entry from the user registry with `nix registry remove nixpkgs`.
|
||
====
|
||
|
||
Both the global and system registry can be configured in the NixOS system.
|
||
In this case, we'll be focusing on adding our flake inputs of our NixOS system into the system registry.
|
||
|
||
`nix.registry` expects an attribute set of flake inputs.
|
||
And the `outputs` attribute from our flake can be a function that expects an attribute set of flake inputs returning an attribute set.
|
||
We can basically set the system registry like so.
|
||
|
||
[#lst:nixos-set-system-registry]
|
||
.Showing how to set `nix.registry`
|
||
[source, nix]
|
||
----
|
||
include::git:{doccontentref}~2[path=flake.nix]
|
||
----
|
||
|
||
Once we rebuild our NixOS system with `nixos-rebuild`, we should now see our flake inputs included in the system registry.
|
||
|
||
[#lst:nix-registry-with-system-registry]
|
||
.Results from `nix registry list | grep '^system'`
|
||
[source]
|
||
----
|
||
system flake:nixpkgs path:/nix/store/kcmipm57ph9bpzz8bs80iiijiwbyzwy3-source?lastModified=1699099776&narHash=sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU%3D&rev=85f1ba3e51676fa8cc604a3d863d729026a6b8eb
|
||
system flake:nixpkgs-stable path:/nix/store/3s69yxbbl116zwga3i6cy7prplywq0bn-source?lastModified=1699291058&narHash=sha256-5ggduoaAMPHUy4riL%2BOrlAZE14Kh7JWX4oLEs22ZqfU%3D&rev=41de143fda10e33be0f47eab2bfe08a50f234267
|
||
system flake:nixpkgs-unstable path:/nix/store/mj0hy52z22q5gpsf33akndxiclxd8ray-source?lastModified=1699343069&narHash=sha256-s7BBhyLA6MI6FuJgs4F/SgpntHBzz40/qV0xLPW6A1Q%3D&rev=ec750fd01963ab6b20ee1f0cb488754e8036d89d
|
||
system flake:self path:/nix/store/v68idbapq3m8sz0fds66vzgg7agg10g9-source?lastModified=1699449415&narHash=sha256-Whc5OQzHTJtyBbnFsDAzdjICWK2BnCDCBP6s%2Bk/oLGQ%3D&rev=e1a0efea49b2e22055d2454e76f3d01ae42fde07&revCount=3
|
||
----
|
||
|
||
[#sidebar:self-flake-input]
|
||
.The `self` flake input
|
||
****
|
||
Setting flake inputs to the system registry <<lst:nixos-set-system-registry, that way>> is convenient.
|
||
But <<lst:nix-registry-with-system-registry, as shown from the results>>, there is a slight oversight with the flake input `self` which is a special named flake input for the current flake.
|
||
Depending on your case, this can be convenient or not.
|
||
At most, it is just left there... existing.
|
||
|
||
If you want, you can remove it like in the following snippet.
|
||
|
||
[source, nix]
|
||
----
|
||
nixpkgs.lib.nixosSystem {
|
||
modules = [
|
||
({ config, lib, ... }: {
|
||
nix.registry = lib.mapAttrs
|
||
(_: flake: { inherit flake; })
|
||
(lib.attrsets.removeAttrs inputs [ "self" ]);
|
||
})
|
||
];
|
||
}
|
||
----
|
||
|
||
Otherwise, you'll have to give the `self` flake input from the registry a different name if you want to use it in your other flakes like in the following snippet.
|
||
|
||
.Different `flake.nix`
|
||
[source, nix]
|
||
----
|
||
{
|
||
inputs.config.url = "self";
|
||
inputs.nixpkgs.url = "nixpkgs/nixos-unstable";
|
||
|
||
# outputs...
|
||
}
|
||
----
|
||
****
|
||
|
||
If we run `nix search nixpkgs blender` once again, it should still evaluate but it should be done only once since:
|
||
|
||
* We have `nixpkgs` pinned to our nixpkgs instance.
|
||
* We're fully taking advantage of https://www.tweag.io/blog/2020-06-25-eval-cache/[flake evaluation caching] meaning subsequent package searches should be (almost) instantaneous.
|
||
|
||
By configuring our registry through NixOS, we're only evaluating nixpkgs once until we update our flake inputs with `nix flake update`.
|
||
|
||
[chat, Ezran, role=full]
|
||
====
|
||
So instead of suffering every time you run the command like in the <<video:nix-search-demo, video at the beginning>>, you suffer at least once every update.
|
||
====
|
||
|
||
As another bonus, we can now take advantage of other `nix` subcommands such as `nix build`, `nix shell`, or `nix develop`.
|
||
|
||
[source, shell]
|
||
----
|
||
# These commands should now use our nixpkgs instance. Hoorah!
|
||
nix run nixpkgs#neofetch
|
||
nix develop nixpkgs#gcc
|
||
nix build nixpkgs#vale
|
||
nix search nixpkgs asciidoctor
|
||
|
||
# From the previous example, we can quickly run packages from other nixpkgs
|
||
# branch easily.
|
||
nix shell nixpkgs-stable#hugo
|
||
nix shell nixpkgs-unstable#hugo
|
||
----
|
||
|
||
[#sidebar:setting-user-registry-in-home-manager]
|
||
.Setting user registry in home-manager
|
||
****
|
||
We could also set the user registry with github:nixos-community/home-manager[opts=repo].
|
||
It even has the same option attribute as the NixOS system (i.e., `nix.registry`) so you could just set it once like in the following snippet.
|
||
|
||
[#lst:nixos-and-home-manager-set-registry]
|
||
.`flake.nix`
|
||
[source, nix]
|
||
----
|
||
include::git:{doccontentref}[path=flake.nix]
|
||
----
|
||
|
||
Take note, you cannot modify the user registry with `nix registry` subcommands once home-manager fully manages it.
|
||
****
|