NobbZ' Blog

Flakes and "command-not-found"

Close-up of a snowflake on black whool

2023-02-27

Darius Cotoi on Unsplash

You might have realized already, that after you switched to flakes fully and removed all the channels, you will see some errors about the missing file /nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite.

This is due to the command not found database being expected at a certain location tied to a default channel based setup.

There are some ways to mitigate this, with more or less obvious downsides.

Disable command-not-found

Simply disabling command-not-found might be the easiest solution to this problem, though results in a quite obvious downside:

You won't find missing programs anymore.

If you still want to do it, it is as easy as:

programs.command-not-found.enable = false;

Keep roots nixos-channel

Another solution is to simply keep a bitrotting nixos channel for root.

"Bitrotting" already implies, it will sooner or later run out of sync if (and you will) forget about it. You can assume, that after 3 to 6 months you will hit siome occasion when you get displayed a package that got removed, or you will see a message about an unknown program about which you are perfectly sure that it should be known, as you use it in another terminal just fine via nix shell.

I will not go into details how to set up this variant and take it granted that everyone who would "keep" the channel would know how to use them.

Use the pre-generated database as input directly

In theory you can use the pregenerated database directly as a flake input and set it as the database URL then.

It would roughly look like this:

inputs.programs-db.url = "https://channels.nixos.org/nixos-22.05/nixexprs.tar.xz";
programs.command-not-found.dbPath = "${inputs.programs-db}/programs.sqlite";

This has the big downside, that the everchanging hash of the tar-ball is persisted in the flake.lock and will cause regular hash-mismatch when trying to build such a flake on a host that does not yet have the tarball with the correct content hash on the disk.

Use the flake-programs-sqlite-flake

There is a user who maintains a mapping from nixpkgs-commits to exact database URLs and their NAR-hashes.

Its set up is quite easy:

programsdb.url = "github:wamserma/flake-programs-sqlite";
programsdb.inputs.nixpkgs.follows = "nixpkgs";
programs.command-not-found.dbPath = inputs.programsdb.packages.${pkgs.system}.programs-sqlite;

The major downside is, you need to update this flake in conjunction with the flake you set to follow.

Using environment.etc to improve the last 2 approaches

The last 2 approaches have the problem that they will only access the new database in a new shell, as the location is hardcoded in the generated command-not-found script.

A way to easily mitigate is to use a redirection via environment.etc.

# Adjust the value for the nixexpr.tar.xz if necessary
environment.etc."programs.sqlite".source = inputs.programsdb.packages.${pkgs.system}.programs-sqlite;
programs.command-not-found.dbPath = "/etc/programs.sqlite";