Skip to content

Instantly share code, notes, and snippets.

@InternetUnexplorer
Last active March 17, 2024 11:53
Show Gist options
  • Save InternetUnexplorer/58e979642102d66f57188764bbf11701 to your computer and use it in GitHub Desktop.
Save InternetUnexplorer/58e979642102d66f57188764bbf11701 to your computer and use it in GitHub Desktop.
Improved home-manager nix-locate configuration, with an auto-updated index and a better command-not-found handler
# Adapted from https://github.com/bennofs/nix-index/blob/master/command-not-found.sh
command_not_found_handle () {
if [ -n "${MC_SID-}" ] || ! [ -t 1 ]; then
>&2 echo "$1: command not found"
return 127
fi
echo -n "searching nix-index..."
ATTRS=$(@nix-locate@ --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$1")
case `echo -n "$ATTRS" | grep -c "^"` in
0)
>&2 echo -ne "$(@tput@ el1)\r"
>&2 echo "$1: command not found"
;;
*)
>&2 echo -ne "$(@tput@ el1)\r"
>&2 echo "The program ‘$(@tput@ setaf 4)$1$(@tput@ sgr0)’ is currently not installed."
>&2 echo "It is provided by the following derivation(s):"
while read ATTR; do
ATTR=$(echo "$ATTR" | sed 's|\.out$||') # Strip trailing '.out'
>&2 echo " $(@tput@ setaf 12)nixpkgs#$(@tput@ setaf 4)$ATTR$(@tput@ sgr0)"
done <<< "$ATTRS"
esac
return 127
}
command_not_found_handler () {
command_not_found_handle $@
return $?
}
{ config, pkgs, lib, ... }:
let
# Automatically download the latest index from Mic92's nix-index-database.
nix-locate = pkgs.writeShellScriptBin "nix-locate" ''
set -euo pipefail
mkdir -p ~/.cache/nix-index && cd ~/.cache/nix-index
# Check for updates at most once a day
if [ ! -f last-check ] || [ $(find last-check -mtime +1) ]; then
filename="index-x86_64-$(uname | tr A-Z a-z)"
# Prevent partial downloads
[ -f files ] || rm -f $filename
rm -f files
wget -q -N --show-progress \
https://github.com/Mic92/nix-index-database/releases/latest/download/$filename
ln -sf $filename files
touch last-check
fi
exec ${pkgs.nix-index}/bin/nix-locate "$@"
'';
# Modified version of command-not-found.sh that uses our wrapped version of
# nix-locate, makes the output a bit less noisy, and adds color!
command-not-found = pkgs.runCommandLocal "command-not-found.sh" { } ''
mkdir -p $out/etc/profile.d
substitute ${./command-not-found.sh} \
$out/etc/profile.d/command-not-found.sh \
--replace @nix-locate@ ${nix-locate}/bin/nix-locate \
--replace @tput@ ${pkgs.ncurses}/bin/tput
'';
in {
programs.nix-index = {
enable = true;
package = pkgs.symlinkJoin {
name = "nix-index";
# Don't provide 'bin/nix-index', since the index is updated automatically
# and it is easy to forget that. It can always be run manually with
# 'nix run nixpkgs#nix-index' if necessary.
paths = [ nix-locate command-not-found ];
};
};
}
@eyadsibai
Copy link

Very cool idea, just inspired me to do some variation which may interest someone: if you use flakes to manage your system (in my case, with flake-utils-plus and its sharedOverlays option, but you can also use nixpkgs.overlays in normal flakes), it's very interesting to have the database tracked by flake.lock and saved in the nix store. Then, home-manager's home.file can be used to create a symlink in your home:

# flake.nix
{
  inputs.nix-index-database.url = "github:Mic92/nix-index-database";
  ...
  sharedOverlays = [
    (final: prev: {
      nix-index-database = final.runCommandLocal "nix-index-database" {} ''
        mkdir -p $out
        ln -s ${nix-index-database.legacyPackages.${prev.system}.database} $out/files
      '';
    })
  ];
}

# in your user's home-manager
{ pkgs, ... }: {
  programs.nix-index.enable = true;
  home.file.".cache/nix-index".source = pkgs.nix-index-database;
}

With the above, your nix flake update will also update references of @Mic92's database, put it in a folder in store and deterministically link to it in your home-manager generation, instead of non-deterministically pulling it with wget. In my case, I didn't mind much the original nix-locate (although I admit yours is prettier), so I just used HM's default programs.nix-index module.

I am using this solution, but I discovered that the database is not getting updated though I updated the flake.lock

@becknik
Copy link

becknik commented Mar 17, 2024

FYI: there now is a NixOS/home-manager module in the repo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment