17

I'm learning about nixos and nix expressions. In a project folder I created a shell.nix and I when I run nix-shell I want it to preset an environment variable for me. For example to set the PGDATA env var.

I know there are several ways to write nix expression files (I'm not yet used to most of them). Here is my sample:

shell.nix

let 
  pkgs = import <nixpkgs> {};
  name = "test";
in pkgs.myEnvFun {
  buildInputs = [
    pkgs.python
    pkgs.libxml2
  ];
  inherit name;
  extraCmds = ''
    export TEST="ABC"
  '';
 }
monk
  • 640
  • 1
  • 5
  • 17

4 Answers4

16

Use buildPythonPackage function (that uses mkDerivation). Passing anything to it will set env variables in bash shell:

with import <nixpkgs> {};

buildPythonPackage {
  name = "test";

  buildInputs = [ pkgs.python pkgs.libxml2 ];

  src = null;

  PGDATA = "...";
}
iElectric
  • 5,633
  • 1
  • 29
  • 31
  • 1
    Thanks for the suggestion. I used python in my example merely as a sample. I usually use it for haskell projects. I guess I can use this function for my haskell projects as well although looks a bit odd. Why does does work in the buildPythonPackage but not in myEnvFun? Is it a bug for myEnvFun (or a feature request)? – monk Jan 03 '15 at 22:49
  • myEnvFun is not a package, build a build environment. It doesn't work with nix-shell. – iElectric Jan 10 '15 at 21:52
  • It appears you can use `shellHook` for doing this if you use the `stdenv.mkDerivation` function. – CMCDragonkai Jul 17 '17 at 08:23
  • I was wondering that while setting environment variables via the attributes works for `nix-shell` how does it interact with `nix-build` when building `buildPythonPackage` or `buildPythonApplication`? That is when you are building the actual output, and you want all of the scripts (specified by `setup.py`) to have that environment variable set when executed? Surely it's not using `makeWrapper` on everything right? – CMCDragonkai Jul 18 '18 at 03:50
6

To set environment variable for a nix-shell without creating a new package, shellHook option can be used. As shown in the example from the manual:

shellHook =
  ''
    echo "Hello shell"
    export SOME_API_TOKEN="$(cat ~/.config/some-app/api-token)"
  '';

A full shell.nix example based on my use-case - with go of version 1.18 from unstable channel:

let
  pkgs = import <nixpkgs> {};

  unstable = import <nixos-unstable> { config = { allowUnfree = true; }; };

in pkgs.mkShell rec {
  name = "go-1.18";

  buildInputs = with pkgs; [
    unstable.go_1_18
  ];

  shellHook = ''
    export PATH="$HOME/go/bin:$PATH"
  '';
}

The script also sets name option, which is then shown in the shell prompt (works nicely with Starship shell prompt).

kravemir
  • 10,636
  • 17
  • 64
  • 111
5

You may also use pkgs.stdenv.mkDerivation.shellHook.

let 
  pkgs = import <nixpkgs> {};
  name = "test";
in pkgs.stdenv.mkDerivation {
  buildInputs = [
    pkgs.python
    pkgs.libxml2
  ];
  inherit name;
  shellHook = ''
    export TEST="ABC"
  '';
 }
Abdillah
  • 982
  • 11
  • 28
  • shellHook is not called for nix-build, is it? – Daniil Iaitskov May 24 '21 at 19:37
  • No, it's only called on nix-shell.. If you need to modify env var on build script, just add / overwrite specific phases https://nixos.org/manual/nixpkgs/stable/#build-phase – Abdillah May 25 '21 at 02:11
  • how to overwrite phase if overlay is used? – Daniil Iaitskov May 25 '21 at 03:33
  • You're modifying an existing derivation? Since what I mean above is overwriting default mkDerivation build phase which is just `make`. If that's the case I'm not sure but with overlay it should be as usual. You should refer to a way on overriding existing derivation. – Abdillah May 26 '21 at 00:54
0
{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {

  # environment variable declaration
  ENV_VAR="lofa";

  shellHook = ''

    # shell variable declaration
    SHELL_VAR=27

    # environment variable declaration
    export ENV_VAR2="miez"
  '';
}

To test it as a one-liner:

$ nix-shell -E '{ pkgs ? import <nixpkgs> {} }: pkgs.mkShell { ENV_VAR="lofa";  shellHook = "SHELL_VAR=27; export ENV_VAR2=\"miez\""; }'`

[nix-shell:~]$ env | grep ENV_VAR
shellHook=SHELL_VAR=27; export ENV_VAR2="miez"
ENV_VAR=lofa
ENV_VAR2=miez

[nix-shell:~]$ echo $SHELL_VAR 
27

See discussion on NixOS discourse as I don't think this behaviour is documented - yet. (Also, you may want to unset shellHook if you are planning to nest nix-shells; see Nix issue #8257.)

toraritte
  • 6,300
  • 3
  • 46
  • 67