From 63262e78c7fd281b813e858640adbaa6f6b3d826 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Sun, 7 Jul 2024 00:55:33 +0200 Subject: [PATCH] Add opt-out: nix-shell-shebang-arguments-relative-to-script --- doc/manual/rl-next/shebang-relative.md | 2 ++ src/libcmd/common-eval-args.cc | 2 +- src/libcmd/compatibility-settings.hh | 9 +++++++++ src/nix-build/nix-build.cc | 4 ++-- tests/functional/nix-shell.sh | 8 ++++++++ 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/doc/manual/rl-next/shebang-relative.md b/doc/manual/rl-next/shebang-relative.md index e6ab9346f..ab39a359c 100644 --- a/doc/manual/rl-next/shebang-relative.md +++ b/doc/manual/rl-next/shebang-relative.md @@ -5,4 +5,6 @@ description: { `nix-shell` shebangs use the script file's relative location to resolve relative paths to files passed as command line arguments, but expression arguments were still evaluated using the current working directory as a base path. The new behavior is that evaluations are performed relative to the script. +The old behavior can be opted into by setting the option [`nix-shell-shebang-arguments-relative-to-script`](@docroot@/command-ref/conf-file.md#conf-nix-shell-shebang-arguments-relative-to-script) to `false`. + } diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index ffc1ebd59..a243b8c49 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -202,7 +202,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state) auto v = state.allocValue(); std::visit(overloaded { [&](const AutoArgExpr & arg) { - state.mkThunk_(*v, state.parseExprFromString(arg.expr, true ? state.rootPath(absPath(getCommandBaseDir())) : state.rootPath("."))); + state.mkThunk_(*v, state.parseExprFromString(arg.expr, compatibilitySettings.nixShellShebangArgumentsRelativeToScript ? state.rootPath(absPath(getCommandBaseDir())) : state.rootPath("."))); }, [&](const AutoArgString & arg) { v->mkString(arg.s); diff --git a/src/libcmd/compatibility-settings.hh b/src/libcmd/compatibility-settings.hh index 5dc0eaf2b..961001080 100644 --- a/src/libcmd/compatibility-settings.hh +++ b/src/libcmd/compatibility-settings.hh @@ -14,6 +14,15 @@ struct CompatibilitySettings : public Config You may set this to `false` to revert to the Nix 2.3 behavior. )"}; + + Setting nixShellShebangArgumentsRelativeToScript{ + this, true, "nix-shell-shebang-arguments-relative-to-script", R"( + Before Nix 2.24, the arguments in a `nix-shell` shebang - as well as `--arg` - were relative to working directory. + + Since Nix 2.24, the arguments are relative to the [base directory](@docroot@/glossary.md#gloss-base-directory) defined as the script's directory. + + You may set this to `false` to revert to the Nix 2.3 behavior. + )"}; }; }; diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index cfe183888..f4af3fd04 100644 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -293,7 +293,7 @@ static void main_nix_build(int argc, char * * argv) state->repair = myArgs.repair; if (myArgs.repair) buildMode = bmRepair; - if (inShebang) { + if (inShebang && compatibilitySettings.nixShellShebangArgumentsRelativeToScript) { myArgs.setBaseDir(absPath(dirOf(script))); } auto autoArgs = myArgs.getAutoArgs(*state); @@ -345,7 +345,7 @@ static void main_nix_build(int argc, char * * argv) if (fromArgs) exprs.push_back(state->parseExprFromString( std::move(i), - inShebang ? lookupFileArg(*state, baseDir) : state->rootPath(".") + (inShebang && compatibilitySettings.nixShellShebangArgumentsRelativeToScript) ? lookupFileArg(*state, baseDir) : state->rootPath(".") )); else { auto absolute = i; diff --git a/tests/functional/nix-shell.sh b/tests/functional/nix-shell.sh index 596ac5951..fd3edf81a 100755 --- a/tests/functional/nix-shell.sh +++ b/tests/functional/nix-shell.sh @@ -76,6 +76,14 @@ echo "cwd: $PWD" output=$($TEST_ROOT/shell.shebang.expr bar) [ "$output" = foo ] +# Test nix-shell shebang mode with an alternate working directory +sed -e "s|@ENV_PROG@|$(type -P env)|" shell.shebang.legacy.expr > $TEST_ROOT/shell.shebang.legacy.expr +chmod a+rx $TEST_ROOT/shell.shebang.legacy.expr +# Should fail due to expressions using relative path +mkdir -p "$TEST_ROOT/somewhere-unrelated" +output="$(cd "$TEST_ROOT/somewhere-unrelated"; $TEST_ROOT/shell.shebang.legacy.expr bar;)" +[[ $(realpath "$output") = $(realpath "$TEST_ROOT/somewhere-unrelated") ]] + # Test nix-shell shebang mode again with metacharacters in the filename. # First word of filename is chosen to not match any file in the test root. sed -e "s|@ENV_PROG@|$(type -P env)|" shell.shebang.sh > $TEST_ROOT/spaced\ \\\'\"shell.shebang.sh