Add opt-out: nix-shell-shebang-arguments-relative-to-script

This commit is contained in:
Robert Hensing 2024-07-07 00:55:33 +02:00
parent 4c59d6e9f5
commit 63262e78c7
5 changed files with 22 additions and 3 deletions

View file

@ -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. `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 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`.
} }

View file

@ -202,7 +202,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
auto v = state.allocValue(); auto v = state.allocValue();
std::visit(overloaded { std::visit(overloaded {
[&](const AutoArgExpr & arg) { [&](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) { [&](const AutoArgString & arg) {
v->mkString(arg.s); v->mkString(arg.s);

View file

@ -14,6 +14,15 @@ struct CompatibilitySettings : public Config
You may set this to `false` to revert to the Nix 2.3 behavior. You may set this to `false` to revert to the Nix 2.3 behavior.
)"}; )"};
Setting<bool> 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.
)"};
}; };
}; };

View file

@ -293,7 +293,7 @@ static void main_nix_build(int argc, char * * argv)
state->repair = myArgs.repair; state->repair = myArgs.repair;
if (myArgs.repair) buildMode = bmRepair; if (myArgs.repair) buildMode = bmRepair;
if (inShebang) { if (inShebang && compatibilitySettings.nixShellShebangArgumentsRelativeToScript) {
myArgs.setBaseDir(absPath(dirOf(script))); myArgs.setBaseDir(absPath(dirOf(script)));
} }
auto autoArgs = myArgs.getAutoArgs(*state); auto autoArgs = myArgs.getAutoArgs(*state);
@ -345,7 +345,7 @@ static void main_nix_build(int argc, char * * argv)
if (fromArgs) if (fromArgs)
exprs.push_back(state->parseExprFromString( exprs.push_back(state->parseExprFromString(
std::move(i), std::move(i),
inShebang ? lookupFileArg(*state, baseDir) : state->rootPath(".") (inShebang && compatibilitySettings.nixShellShebangArgumentsRelativeToScript) ? lookupFileArg(*state, baseDir) : state->rootPath(".")
)); ));
else { else {
auto absolute = i; auto absolute = i;

View file

@ -76,6 +76,14 @@ echo "cwd: $PWD"
output=$($TEST_ROOT/shell.shebang.expr bar) output=$($TEST_ROOT/shell.shebang.expr bar)
[ "$output" = foo ] [ "$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. # 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. # 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 sed -e "s|@ENV_PROG@|$(type -P env)|" shell.shebang.sh > $TEST_ROOT/spaced\ \\\'\"shell.shebang.sh