Files
nixpkgs/pkgs/build-support/trivial-builders/test/writeShellApplication.nix
rti 3c031f3f8a writeShellApplication: fix inheritPath without runtimeInputs
inheritPath false should be also followed when runtimeInputs is empty.

Writing a shell application without any dependencies that does not
inherit the environments $PATH was not possible before this change,
because inheritPath was only taken into account when runtimeInputs was
non-empty. Shell applications that do not depend on any additional
packages might still want to run with a clean $PATH in order to not
accidentally rely on packages available in the execution environment.

Co-authored-by: Jeremy Fleischman <jeremyfleischman@gmail.com>
2026-03-17 12:17:25 +07:00

192 lines
4.8 KiB
Nix

# Run with:
# nix-build -A tests.trivial-builders.writeShellApplication
{
writeShellApplication,
writeTextFile,
runCommand,
lib,
linkFarm,
diffutils,
hello,
}:
let
checkShellApplication =
args@{ name, expected, ... }:
let
writeShellApplicationArgs = removeAttrs args [ "expected" ];
script = writeShellApplication writeShellApplicationArgs;
executable = lib.getExe script;
expected' = writeTextFile {
name = "${name}-expected";
text = expected;
};
actual = "${name}-actual";
in
runCommand name { } ''
echo "Running test executable ${name}"
${executable} > ${actual}
echo "Got output from test executable:"
cat ${actual}
echo "Checking test output against expected output:"
${diffutils}/bin/diff --color --unified ${expected'} ${actual}
touch $out
'';
in
linkFarm "writeShellApplication-tests" {
test-meta =
let
args = {
name = "test-meta";
text = "";
meta.description = "Test for the `writeShellApplication` `meta` argument";
};
script = writeShellApplication args;
in
assert script.meta.mainProgram == args.name;
assert script.meta.description == args.meta.description;
script;
test-runtime-inputs = checkShellApplication {
name = "test-runtime-inputs";
text = ''
hello
'';
runtimeInputs = [ hello ];
expected = "Hello, world!\n";
};
test-runtime-env = checkShellApplication {
name = "test-runtime-env";
runtimeEnv = {
MY_COOL_ENV_VAR = "my-cool-env-value";
MY_OTHER_COOL_ENV_VAR = "my-other-cool-env-value";
# Check that we can serialize a bunch of different types:
BOOL = true;
INT = 1;
LIST = [
1
2
3
];
MAP = {
a = "a";
b = "b";
};
};
text = ''
echo "$MY_COOL_ENV_VAR"
echo "$MY_OTHER_COOL_ENV_VAR"
'';
expected = ''
my-cool-env-value
my-other-cool-env-value
'';
};
test-no-inherit-path-no-runtimeInputs = checkShellApplication {
name = "test-no-inherit-path-no-runtimeInputs";
inheritPath = false;
runtimeInputs = [ ];
text = ''
if [[ ''${#PATH} -eq 0 ]]; then
echo -n "PATH is empty"
fi
'';
expected = "PATH is empty";
};
test-no-inherit-path-runtimeInputs = checkShellApplication {
name = "test-no-inherit-path-runtimeInputs";
inheritPath = false;
runtimeInputs = [ hello ];
text = ''
extra_colon_pattern='(^:|:$)'
if [[ ''${PATH} =~ $extra_colon_pattern ]]; then
echo "PATH should not start or end with a colon: $PATH"
fi
if [[ ''${#PATH} -gt 0 ]]; then
echo -n "PATH is not empty"
fi
'';
expected = "PATH is not empty";
};
test-inherit-path-no-runtimeInputs = checkShellApplication {
name = "test-inherit-path-no-runtimeInputs";
inheritPath = true;
runtimeInputs = [ ];
text = ''
extra_colon_pattern='(^:|:$)'
if [[ ''${PATH} =~ $extra_colon_pattern ]]; then
echo "PATH should not start or end with a colon: $PATH"
fi
if [[ ''${#PATH} -gt 0 ]]; then
echo -n "PATH is not empty"
fi
'';
expected = "PATH is not empty";
};
test-check-phase = checkShellApplication {
name = "test-check-phase";
text = "";
checkPhase = ''
echo "echo -n hello" > $target
'';
expected = "hello";
};
test-argument-forwarding = checkShellApplication {
name = "test-argument-forwarding";
text = "";
derivationArgs.MY_BUILD_TIME_VARIABLE = "puppy";
derivationArgs.postCheck = ''
if [[ "$MY_BUILD_TIME_VARIABLE" != puppy ]]; then
echo "\$MY_BUILD_TIME_VARIABLE is not set to 'puppy'!"
exit 1
fi
'';
meta.description = "Test checking that `writeShellApplication` forwards extra arguments to `stdenv.mkDerivation`";
expected = "";
};
test-exclude-shell-checks = writeShellApplication {
name = "test-exclude-shell-checks";
excludeShellChecks = [ "SC2016" ];
text = ''
# Triggers SC2016: Expressions don't expand in single quotes, use double
# quotes for that.
echo '$SHELL'
'';
};
test-bash-options-pipefail = checkShellApplication {
name = "test-bash-options-pipefail";
text = ''
touch my-test-file
echo puppy | grep doggy | sed 's/doggy/puppy/g'
# ^^^^^^^^^^ This will fail.
true
'';
# Don't use `pipefail`:
bashOptions = [
"errexit"
"nounset"
];
expected = "";
};
test-bash-options-nounset = checkShellApplication {
name = "test-bash-options-nounset";
text = ''
echo -n "$someUndefinedVariable"
'';
# Don't use `nounset`:
bashOptions = [ ];
# Don't warn about the undefined variable at build time:
excludeShellChecks = [ "SC2154" ];
expected = "";
};
}