purcell / envrc

Emacs support for direnv which operates buffer-locally
378 stars 35 forks source link

`envrc-reload` should do `direnv reload` #61

Open glasserc opened 1 year ago

glasserc commented 1 year ago

I'm working on a project packaged with Nix. My development environment includes an .envrc file which contains use flake, which is defined by https://github.com/nix-community/nix-direnv.

Periodically when I pull from master, new dependencies are introduced. Recompiling the project fails until I regenerate the Nix environment. The command direnv reload definitely causes this regeneration to happen. direnv allow does not. I'm not sure if this is because nix-direnv tries to be efficient and caches the Nix environment (per https://github.com/nix-community/nix-direnv#tracked-files) or if this is typical for direnv usage in general.

envrc does not offer a way to invoke direnv reload. There are functions envrc-reload and envrc-reload-all, but they do not directly invoke direnv reload. Instead, they do direnv export. direnv export also does not cause the Nix environment to be rebuilt. I'm not sure if it's supposed to? However, I feel that the name reload in these functions is a little confusing since it appears to parallel functions like envrc-allow (-> direnv allow) and envrc-deny (-> direnv deny).

I'd like a way to refresh my envrcs when I need to. I'm not exactly sure if that means fixing export to regenerate the environment when necessary, adding some functionality to envrc to call direnv reload somehow, or something else entirely. Your opinion eagerly solicited.

This is still a little fuzzy for me, so thanks for bearing with me. If this isn't sufficiently clear, let me know and I will try to put together a minimal repo to play with.

Thanks for your work on envrc! It's a lifesaver!

purcell commented 1 year ago

That's a good point, and I'm inclined to agree. I've seen the same need to reload direnv, but you can handle much of that by watching *.nix etc. in your project-local .envrc.

There are two types of caching here, essentially: Emacs caches the results of direnv invocations, and that cache is only refreshed when envrc-reload or envrc-reload-all is called. And at the same time, direnv has its own caching which direnv reload defeats.

What I've done for now is make envrc-reload call direnv reload, but I haven't yet made envrc-reload-all do what you'd expect, because that's a little more involved. I think this should mostly address your use case though.

glasserc commented 1 year ago

Ah, thanks, this is super helpful. I guess direnv reload just touches the .envrc file to bust the cache. I guess there's also a third layer of caching which is that nix-direnv has a set of files that it watches too, but it seems like nix_direnv_watch_file also adds them to direnv's built in caching here. So probably I should be using that for any files that could be dependencies of the Nix logic. I think if I do that, then the existing behavior of envrc-reload-all would be sufficient for my purposes.

Another thought I had is that the existing envrc-reload and envrc-reload-all might be better renamed envrc-refresh and envrc-refresh-all or something like that. I think they do useful things, I just think we should disambiguate them from the direnv commands. But doing that has backwards compatibility consequences so I understand if that's not a priority.

Thanks for the change! This is super helpful!