Open mzabani opened 3 years ago
Yep, there are some differences in behavior caused by shell hooks.
However, the 100% correct behavior would be more complicated than the way that you described, because:
shellHook
is not the only hook that gets executed when you run nix-shell
. Another hook is setup-hook
.
In the following example, $PYTHONPATH
variable is set by the setup-hook of python3
.
$ cat ./shell-with-python3.nix
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell { buildInputs = [ pkgs.python3 ]; }
$ nix-shell ./shell-with-python3.nix --run 'echo $PYTHONPATH'
/nix/store/fjgnz0xfl04hsblsi4ym5y5akfh6mlmy-python3-3.8.5/lib/python3.8/site-packages:/nix/store/fjgnz0xfl04hsblsi4ym5y5akfh6mlmy-python3-3.8.5/lib/python3.8/site-packages
$ PYTHONPATH=/somedir nix-shell ./shell-with-python3.nix --run 'echo $PYTHONPATH'
/somedir:/nix/store/fjgnz0xfl04hsblsi4ym5y5akfh6mlmy-python3-3.8.5/lib/python3.8/site-packages:/nix/store/fjgnz0xfl04hsblsi4ym5y5akfh6mlmy-python3-3.8.5/lib/python3.8/site-packages
$ PYTHONPATH=/somedir dontAddPythonPath=1 nix-shell ./shell-with-python3.nix --run 'echo $PYTHONPATH'
/somedir
Shell hook may access not only the exported environment variables (which are currently cached by c-n-s) but also bash functions defined by setup hooks or setup.sh
(which are not).
In the following example stripHash
is a bash function defined in setup.sh
.
$ cat ./shell-print-stripHash.nix
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell { shellHook = "stripHash $NIX_CC"; }
$ nix-shell ./shell-print-stripHash.nix --run :
gcc-wrapper-9.3.0
If you need a workaround for this particular use case, you might add these lines to your bashrc:
if [ "$IN_CACHED_NIX_SHELL" ]; then
eval "$shellHook"
unset shellHook
fi
Or, if you'll need just the variable, you'll have to pass it with --keep
:
$ OTHERVAR=201 cached-nix-shell --keep OTHERVAR cached-shell.nix
Oh, I see, things are indeed more complicated than I thought. Thanks for explaining. The workaround you suggested works really well too. Thanks!
I wonder though if it wouldn't still be better/more expected to not cache shellHook and run it upon invocation. It certainly is what I expected, and from what I understand cached-nix-shell is already insensitive to environment variables which might alter what setuphook does (so your examples are with PYTHONPATH
would already be different with c-n-s, and like that they'd remain), so this change would be an improvement? Although of course, a drastic/possibly breaking change in behaviour.
Given the following
cached-shell.nix
:This is how
nix-shell
behaves:And this is
cached-nix-shell
(theecho
command outputs nothing both with a cached shell and when caching it the first time):So I think there's a difference in behavior. Would it be correct to say that the correct behavior for
cached-nix-shell
should be:shellHook
attribute. However, take care to cache dependencies that might be brought in by${some-nix-var}
inshellHook
's body.shellHook
everytimecached-nix-shell
runs.Thanks in advance!