nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at devShellTools-shell 175 lines 6.0 kB view raw
1{ 2 lib, 3 runtimeShell, 4 bashInteractive, 5 stdenv, 6 writeTextFile, 7}: 8let 9 inherit (builtins) typeOf; 10in 11rec { 12 # Docs: doc/build-helpers/dev-shell-tools.chapter.md 13 # Tests: ./tests/default.nix 14 # This function closely mirrors what this Nix code does: 15 # https://github.com/NixOS/nix/blob/2.8.0/src/libexpr/primops.cc#L1102 16 # https://github.com/NixOS/nix/blob/2.8.0/src/libexpr/eval.cc#L1981-L2036 17 valueToString = 18 value: 19 # We can't just use `toString` on all derivation attributes because that 20 # would not put path literals in the closure. So we explicitly copy 21 # those into the store here 22 if typeOf value == "path" then 23 "${value}" 24 else if typeOf value == "list" then 25 toString (map valueToString value) 26 else 27 toString value; 28 29 # Docs: doc/build-helpers/dev-shell-tools.chapter.md 30 # Tests: ./tests/default.nix 31 # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L992-L1004 32 unstructuredDerivationInputEnv = 33 { drvAttrs }: 34 # FIXME: this should be `normalAttrs // passAsFileAttrs` 35 lib.mapAttrs' 36 ( 37 name: value: 38 let 39 str = valueToString value; 40 in 41 if lib.elem name (drvAttrs.passAsFile or [ ]) then 42 let 43 nameHash = 44 if builtins ? convertHash then 45 builtins.convertHash { 46 hash = "sha256:" + builtins.hashString "sha256" name; 47 toHashFormat = "nix32"; 48 } 49 else 50 builtins.hashString "sha256" name; 51 basename = ".attr-${nameHash}"; 52 in 53 lib.nameValuePair "${name}Path" "${ 54 writeTextFile { 55 name = "shell-passAsFile-${name}"; 56 text = str; 57 destination = "/${basename}"; 58 } 59 }/${basename}" 60 else 61 lib.nameValuePair name str 62 ) 63 ( 64 removeAttrs drvAttrs [ 65 # TODO: there may be more of these 66 "args" 67 ] 68 ); 69 70 # Docs: doc/build-helpers/dev-shell-tools.chapter.md 71 # Tests: ./tests/default.nix 72 derivationOutputEnv = 73 { outputList, outputMap }: 74 # A mapping from output name to the nix store path where they should end up 75 # https://github.com/NixOS/nix/blob/2.8.0/src/libexpr/primops.cc#L1253 76 lib.genAttrs outputList (output: builtins.unsafeDiscardStringContext outputMap.${output}.outPath); 77 78 toBashEnv = 79 { env }: 80 lib.concatStringsSep "\n" ( 81 lib.mapAttrsToList ( 82 name: value: 83 if lib.isValidPosixName name then ''export ${name}=${lib.escapeShellArg value}'' else "" 84 ) env 85 ); 86 87 buildShellEnv = 88 { 89 drvAttrs, 90 promptPrefix ? "build shell", 91 promptName ? null, 92 }: 93 let 94 name = drvAttrs.pname or drvAttrs.name or "shell"; 95 env = unstructuredDerivationInputEnv { inherit drvAttrs; }; 96 in 97 stdenv.mkDerivation (finalAttrs: { 98 name = "${name}-env"; 99 passAsFile = [ 100 "bashEnv" 101 "bashrc" 102 "runShell" 103 ]; 104 bashEnv = toBashEnv { inherit env; }; 105 bashrc = '' 106 export NIXPKGS_SHELL_TMP="$(mktemp -d --tmpdir nixpkgs-shell-${name}.XXXXXX)" 107 export TMPDIR="$NIXPKGS_SHELL_TMP" 108 export TEMPDIR="$NIXPKGS_SHELL_TMP" 109 export TMP="$NIXPKGS_SHELL_TMP" 110 export TEMP="$NIXPKGS_SHELL_TMP" 111 112 echo "Using TMPDIR=$TMPDIR" 113 114 source @envbash@ 115 116 mkdir -p $TMP/outputs 117 for _output in $outputs; do 118 export "''${_output}=$TMP/outputs/''${_output}" 119 done 120 121 source @stdenv@/setup 122 123 # Set a distinct prompt to make it clear that we are in a build shell 124 case "$PS1" in 125 *"(build shell $name)"*) 126 echo "It looks like your running a build shell inside a build shell." 127 echo "It might work, but this is probably not what you want." 128 echo "You may want to exit your shell before loading a new one." 129 ;; 130 esac 131 132 # Prefix a line to the prompt to indicate that we are in a build shell 133 PS1=$"\n(\[\033[1;33m\]"${lib.escapeShellArg promptPrefix}$": \[\033[1;34m\]"${ 134 if promptName != null then lib.escapeShellArg promptName else ''"$name"'' 135 }"\[\033[1;33m\]\[\033[0m\]) $PS1" 136 137 runHook shellHook 138 ''; 139 buildCommand = '' 140 mkdir -p $out/lib $out/bin 141 bashrc="$out/lib/bashrc" 142 envbash="$out/lib/env.bash" 143 144 mv "$bashEnvPath" "$envbash" 145 substitute "$bashrcPath" "$bashrc" \ 146 --replace-fail "@envbash@" "$envbash" \ 147 --replace-fail "@stdenv@" "$stdenv" \ 148 ; 149 150 substitute ${./run-shell.sh} "$out/bin/run-shell" \ 151 --replace-fail "@bashrc@" "$bashrc" \ 152 --replace-fail "@runtimeShell@" "${runtimeShell}" \ 153 --replace-fail "@bashInteractive@" "${bashInteractive}" \ 154 ; 155 156 # NOTE: most other files are script for the source command, and not 157 # standalone executables, so they should not be made executable. 158 chmod a+x $out/bin/run-shell 159 ''; 160 preferLocalBuild = true; 161 passthru = { 162 # Work this as a shell environment, so that commands like `nix-shell` 163 # will be able to check it and use it correctly. This also lets Nix know 164 # to stop when the user requests pkg.devShell explicitly, or a different 165 # attribute containing a shell environment. 166 isShellEnv = true; 167 devShell = throw "You're trying to access the devShell attribute of a shell environment. We appreciate that this is very \"meta\" and interesting, but it's usually just not what you want. Most likely you've selected one `.devShell` to deep in an expression or on the command line. Try removing the last one."; 168 }; 169 meta = { 170 description = "An environment similar to the build environment of ${name}"; 171 # TODO longDescription 172 mainProgram = "run-shell"; 173 }; 174 }); 175}