xzfc / cached-nix-shell

Instant startup time for nix-shell
https://xzfc.github.io/cached-nix-shell/cached-nix-shell.1
The Unlicense
195 stars 16 forks source link

`cached-nix-shell` blocks certain environment variables that `nix-shell` doesn't. #26

Closed uri-canva closed 1 year ago

uri-canva commented 1 year ago

The list of environment variables that cached-nix-shell keeps (https://sourcegraph.com/github.com/xzfc/cached-nix-shell@1955b9d0aaaf90337541ab799d5071eeaac2360c/-/blob/src/main.rs?L172-184) and that nix-shell keeps (https://sourcegraph.com/github.com/NixOS/nix@2.10.3/-/blob/src/nix-build/nix-build.cc?L107-110) are not in sync. The environment variables that cached-nix-shell keeps in addition are not an issue since the --pure will have the nix-shell invocation strip them anyway if needed, but the ones that are missing lead to a difference in behaviour when using cached-nix-shell as a drop in replacement of nix-shell. For example not keeping TERM results in bash defaulting to dumb and setting it in the environment (https://sourcegraph.com/github.com/bminor/bash@bash-5.1/-/blob/variables.c?L496), leading to programs disabling ncurses and similar terminal UIs.

zopsicle commented 1 year ago

Rather than trying to replicate all the behavior of nix-shell, wouldn’t it be easier to record the path to the shell’s .drv file in the cache (instead of the environment variables), and then simply exec nix-shell <drv path> "$@"? nix-shell will then handle the details of setting up the environment, and the behavior would be identical but without the slow expression evaluation.

xzfc commented 1 year ago

The environment variables that cached-nix-shell keeps in addition are not an issue since the --pure will have the nix-shell invocation strip them anyway if needed

cached-nix-shell strips as much of environment variables as possible before passing it to nix-shell --pure to avoid cache invalidation on every possible variable change. E.g. $GNOME_TERMINAL_SCREEN is different in every terminal tab, so it would be inconvenient not to reuse the cache every time you open a tab. Some of the variables may affect the evaluation result, so cache invalidation is required if any of the passed variables are changed.

I've added the logic to fetch TERM and others from the environment before running the user shell. These are still not passed to nix-shell --pure during the first invocation (slow path). I think it should cover the listed use cases.

Rather than trying to replicate all the behavior of nix-shell, wouldn’t it be easier to record the path to the shell’s .drv file in the cache (instead of the environment variables), and then simply exec nix-shell <drv path> "$@"? nix-shell will then handle the details of setting up the environment, and the behavior would be identical but without the slow expression evaluation.

No, it would still be slow. This way you'll get rid of the nix expression evaluation stage (which is slow), but you still have to run setup.sh (which is slow too). cached-nix-shell caches both stages at once.

$ drv=$(nix show-derivation $(nix-shell --pure -p i3.buildInputs --run 'echo $out') | jq -r 'keys[0]')
$ time NIX_BUILD_SHELL=bash nix-shell $drv\!out --run ':'

real    0m0.744s
user    0m0.528s
sys 0m0.092s