From 1bfbbe241553881a6416364ccc9a5af2a1fd7f13 Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Thu, 27 Nov 2025 15:55:53 +0100 Subject: [PATCH] nix-shell: Add NIX_SHELL_LEVEL variable This contains the depth of nix shells nesting. Fixes #826 Co-authored-by: Qyriad Change-Id: If584c9d02730d6c857636dafdeab0c01f4ec8e0f --- doc/manual/rl-next/nix-shell-level.md | 9 +++++++++ lix/legacy/nix-build.cc | 9 +++++++++ lix/nix/develop.cc | 4 ++++ lix/nix/run.cc | 11 +++++++++++ 4 files changed, 33 insertions(+) create mode 100644 doc/manual/rl-next/nix-shell-level.md diff --git a/doc/manual/rl-next/nix-shell-level.md b/doc/manual/rl-next/nix-shell-level.md new file mode 100644 index 000000000..8c2661db0 --- /dev/null +++ b/doc/manual/rl-next/nix-shell-level.md @@ -0,0 +1,9 @@ +--- +synopsis: "Add an indication of nix-shell nesting depth" +cls: [4657] +issues: [fj#826] +category: "Improvements" +credits: [thubrecht] +--- + +When in a nix shell (either via a `nix-shell` or a `nix develop` invocation), a variable `NIX_SHELL_LEVEL` is exported to indicate the nesting depth of nix shells. diff --git a/lix/legacy/nix-build.cc b/lix/legacy/nix-build.cc index 71bf426e1..e0f0916e8 100644 --- a/lix/legacy/nix-build.cc +++ b/lix/legacy/nix-build.cc @@ -25,6 +25,7 @@ #include "lix/libutil/shlex.hh" #include "nix-build.hh" #include "lix/libstore/temporary-dir.hh" +#include "lix/libutil/strings.hh" extern char * * environ __attribute__((weak)); // Man what even is this @@ -425,6 +426,14 @@ static int main_nix_build(AsyncIoRoot & aio, std::string programName, Strings ar env["__ETC_PROFILE_SOURCED"] = "1"; } + // Set NIX_SHELL_LEVEL + env["NIX_SHELL_LEVEL"] = std::to_string( + getEnvNonEmpty("NIX_SHELL_LEVEL") + .and_then([](std::string lvl) { return string2Int(lvl); }) + .value_or(0) + + 1 + ); + // Don't use defaultTempDir() here! We want to preserve the user's TMPDIR for the shell env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = getEnvNonEmpty("TMPDIR").value_or(buildTopTmpDir); diff --git a/lix/nix/develop.cc b/lix/nix/develop.cc index b9640d2e2..264286e0c 100644 --- a/lix/nix/develop.cc +++ b/lix/nix/develop.cc @@ -356,6 +356,10 @@ struct Common : InstallableCommand, MixProfile buildEnvironment.toBash(out, ignoreVars); + // Add NIX_SHELL_LEVEL + out << "printf -v NIX_SHELL_LEVEL \"%d\" \"${NIX_SHELL_LEVEL:-0}\" || NIX_SHELL_LEVEL=0\n"; + out << "export NIX_SHELL_LEVEL=$(( NIX_SHELL_LEVEL + 1 ))\n"; + for (auto & var : savedVars) out << fmt("%s=\"$%s${nix_saved_%s:+:$nix_saved_%s}\"\n", var, var, var, var); diff --git a/lix/nix/run.cc b/lix/nix/run.cc index aeada699b..e58eb2d26 100644 --- a/lix/nix/run.cc +++ b/lix/nix/run.cc @@ -150,6 +150,17 @@ struct CmdShell : InstallablesCommand, MixEnvironment auto unixPathString = concatStringsSep(":", unixPath); (void) sys::setenv("PATH", unixPathString, 1); (void) sys::setenv("IN_NIX_SHELL", ignoreEnvironment ? "pure" : "impure", 1); + // Set NIX_SHELL_LEVEL + (void) sys::setenv( + "NIX_SHELL_LEVEL", + std::to_string( + getEnvNonEmpty("NIX_SHELL_LEVEL") + .and_then([](std::string lvl) { return string2Int(lvl); }) + .value_or(0) + + 1 + ), + 1 + ); Strings args; for (auto & arg : command) args.push_back(arg);