Using direnv + guix to create environments / profiles

I’ve been using direnv to manage guix profiles / environments, having found some resources on it and wanted to share:

  • The guix cookbook includes an example of how to use direnv though it seems out of date

  • use_guix is in the direnv stdlib, and should just pass arguments directly to guix shell. Though the direnv wiki is out of date and says guix environment.

  • The direnv wiki also provides a good example of how to use a “local cache” of the guix shell profile to speed up subsequent loadings once built. It relies on the -r/--root= option which creates a link to resulting profile at FILE and registers it as a garbage collector root. However, once the “root” is created, subsequent calls build the profile but fails at creating the link since it already exists.

This can at least be improved on I think by deleting the “cache directory”/“gc root” if the manifest is newer.

use_guix() {
  local cache_dir=".guix-profile"
  # delete =.guix-profile= if =manifest.scm= is newer
  # bash test builtin dereferences links, using =find=
  if [[ -e $cache_dir && $(find manifest.scm -prune -newer $cache_dir) ]]; then
    rm $cache_dir
  if [[ -e "$cache_dir/etc/profile" ]]; then
    source "$cache_dir/etc/profile"
    echo "direnvrc: building $cache_dir"
    eval "$(guix shell -m manifest.scm -r "$cache_dir" "$@" --search-paths)"

But this presumes manifest.scm and not guix.scm and only rebuilds when the manifest changes and not if guix has changed. Nor does it account for channels.scm or do anything fancy with guix time-machine. Anyway, I’d be interested to hear about how other have approached this since there must be a better way of doing this even if it’s a separate guile script.

1 Like

From General to Guix

Sorry I have nothing to contribute here, I’ve been holding off on doing this because I haven’t used direnv before, but these are some great pointers. I’m going to have to look at all this to get this working soon, because it does seem great :grin:

I’m following a similar approach for creating environments, using a manifest.scm, direnv and guix shell (guix shell uses manifest.scm by default).

eval $(guix shell --search-paths)

I haven’t had issues with the loading times (maybe because I don’t use guix gc often). I will try using the local cache approach, seems interesting.

I’m mainly living in Emacs, and I like to use buffer-env to handle the activation of manifest.scm files when I enter the directory.

Thou direnv is a more general (and probably better) solution, but there is a charm with having it all in Emacs. :slight_smile:

I use emacs-envrc for emacs integration, but I didn’t realize that buffer-env has guix support built in, thanks for sharing it.