Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shellHook behavior #18

Open
mzabani opened this issue Sep 26, 2020 · 3 comments
Open

shellHook behavior #18

mzabani opened this issue Sep 26, 2020 · 3 comments

Comments

@mzabani
Copy link

mzabani commented Sep 26, 2020

Given the following cached-shell.nix:

{ pkgs ? import <nixpkgs> {} }:
    pkgs.mkShell {
        shellHook = ''
            echo "Initialize something here (maybe a Postgres Database, for example)"
            export SOMEVAR="$OTHERVAR"
        '';
    }

This is how nix-shell behaves:

$ OTHERVAR=201 nix-shell cached-shell.nix 
Initialize something here (maybe a Postgres Database, for example)

$ echo $SOMEVAR
201

And this is cached-nix-shell (the echo command outputs nothing both with a cached shell and when caching it the first time):

$ OTHERVAR=201 cached-nix-shell cached-shell.nix 

$ echo $SOMEVAR

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:

  1. Cache a derivation which is the shell derivation without its shellHook attribute. However, take care to cache dependencies that might be brought in by ${some-nix-var} in shellHook's body.
  2. Run shellHook everytime cached-nix-shell runs.

Thanks in advance!

@mzabani mzabani changed the title shellHook behaviour shellHook behavior Sep 26, 2020
@xzfc
Copy link
Owner

xzfc commented Sep 26, 2020

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:

  1. 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
  2. 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

@xzfc
Copy link
Owner

xzfc commented Sep 27, 2020

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

@mzabani
Copy link
Author

mzabani commented Oct 1, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants