mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-15 06:14:57 +01:00
1efcffa700
The previously used pattern was introduced in #318614, but technically leaked the default flags into the global scope. While this would probably not make much of a practical difference, making concatTo support default values is a much cleaner approach.
428 lines
16 KiB
Nix
428 lines
16 KiB
Nix
# To run these tests:
|
|
# nix-build -A tests.stdenv
|
|
|
|
{ stdenv
|
|
, pkgs
|
|
, lib
|
|
, testers
|
|
}:
|
|
|
|
let
|
|
# early enough not to rebuild gcc but late enough to have patchelf
|
|
earlyPkgs = stdenv.__bootPackages.stdenv.__bootPackages;
|
|
earlierPkgs = stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages;
|
|
# use a early stdenv so when hacking on stdenv this test can be run quickly
|
|
bootStdenv = stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv;
|
|
pkgsStructured = import pkgs.path { config = { structuredAttrsByDefault = true; }; inherit (stdenv.hostPlatform) system; };
|
|
bootStdenvStructuredAttrsByDefault = pkgsStructured.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv.__bootPackages.stdenv;
|
|
|
|
runCommand = earlierPkgs.runCommand;
|
|
|
|
|
|
ccWrapperSubstitutionsTest = { name, stdenv', extraAttrs ? { } }:
|
|
|
|
stdenv'.cc.overrideAttrs (previousAttrs: ({
|
|
inherit name;
|
|
|
|
postFixup = previousAttrs.postFixup + ''
|
|
declare -p wrapperName
|
|
echo "env.wrapperName = $wrapperName"
|
|
[[ $wrapperName == "CC_WRAPPER" ]] || (echo "'\$wrapperName' was not 'CC_WRAPPER'" && false)
|
|
declare -p suffixSalt
|
|
echo "env.suffixSalt = $suffixSalt"
|
|
[[ $suffixSalt == "${stdenv'.cc.suffixSalt}" ]] || (echo "'\$suffxSalt' was not '${stdenv'.cc.suffixSalt}'" && false)
|
|
|
|
grep -q "@out@" $out/bin/cc || echo "@out@ in $out/bin/cc was substituted"
|
|
grep -q "@suffixSalt@" $out/bin/cc && (echo "$out/bin/cc contains unsubstituted variables" && false)
|
|
|
|
touch $out
|
|
'';
|
|
} // extraAttrs));
|
|
|
|
testEnvAttrset = { name, stdenv', extraAttrs ? { } }:
|
|
stdenv'.mkDerivation
|
|
({
|
|
inherit name;
|
|
env = {
|
|
string = "testing-string";
|
|
};
|
|
|
|
passAsFile = [ "buildCommand" ];
|
|
buildCommand = ''
|
|
declare -p string
|
|
echo "env.string = $string"
|
|
[[ $string == "testing-string" ]] || (echo "'\$string' was not 'testing-string'" && false)
|
|
[[ "$(declare -p string)" == 'declare -x string="testing-string"' ]] || (echo "'\$string' was not exported" && false)
|
|
touch $out
|
|
'';
|
|
} // extraAttrs);
|
|
|
|
testPrependAndAppendToVar = { name, stdenv', extraAttrs ? { } }:
|
|
stdenv'.mkDerivation
|
|
({
|
|
inherit name;
|
|
env = {
|
|
string = "testing-string";
|
|
};
|
|
|
|
passAsFile = [ "buildCommand" ] ++ lib.optionals (extraAttrs ? extraTest) [ "extraTest" ];
|
|
buildCommand = ''
|
|
declare -p string
|
|
appendToVar string hello
|
|
# test that quoted strings work
|
|
prependToVar string "world"
|
|
declare -p string
|
|
|
|
declare -A associativeArray=(["X"]="Y")
|
|
[[ $(appendToVar associativeArray "fail" 2>&1) =~ "trying to use" ]] || (echo "appendToVar did not throw appending to associativeArray" && false)
|
|
[[ $(prependToVar associativeArray "fail" 2>&1) =~ "trying to use" ]] || (echo "prependToVar did not throw prepending associativeArray" && false)
|
|
|
|
[[ $string == "world testing-string hello" ]] || (echo "'\$string' was not 'world testing-string hello'" && false)
|
|
|
|
# test appending to a unset variable
|
|
appendToVar nonExistant created hello
|
|
declare -p nonExistant
|
|
if [[ -n $__structuredAttrs ]]; then
|
|
[[ "''${nonExistant[@]}" == "created hello" ]]
|
|
else
|
|
# there's a extra " " in front here and a extra " " in the end of prependToVar
|
|
# shouldn't matter because these functions will mostly be used for $*Flags and the Flag variable will in most cases already exist
|
|
[[ "$nonExistant" == " created hello" ]]
|
|
fi
|
|
|
|
eval "$extraTest"
|
|
|
|
touch $out
|
|
'';
|
|
} // extraAttrs);
|
|
|
|
testConcatTo = { name, stdenv', extraAttrs ? { } }:
|
|
stdenv'.mkDerivation
|
|
({
|
|
inherit name;
|
|
|
|
string = "a b";
|
|
list = ["c" "d"];
|
|
|
|
passAsFile = [ "buildCommand" ] ++ lib.optionals (extraAttrs ? extraTest) [ "extraTest" ];
|
|
buildCommand = ''
|
|
declare -A associativeArray=(["X"]="Y")
|
|
[[ $(concatTo nowhere associativeArray 2>&1) =~ "trying to use" ]] || (echo "concatTo did not throw concatenating associativeArray" && false)
|
|
|
|
empty_array=()
|
|
empty_string=""
|
|
|
|
declare -a flagsArray
|
|
concatTo flagsArray string list notset=e=f empty_array=g empty_string=h
|
|
declare -p flagsArray
|
|
[[ "''${flagsArray[0]}" == "a" ]] || (echo "'\$flagsArray[0]' was not 'a'" && false)
|
|
[[ "''${flagsArray[1]}" == "b" ]] || (echo "'\$flagsArray[1]' was not 'b'" && false)
|
|
[[ "''${flagsArray[2]}" == "c" ]] || (echo "'\$flagsArray[2]' was not 'c'" && false)
|
|
[[ "''${flagsArray[3]}" == "d" ]] || (echo "'\$flagsArray[3]' was not 'd'" && false)
|
|
[[ "''${flagsArray[4]}" == "e=f" ]] || (echo "'\$flagsArray[4]' was not 'e=f'" && false)
|
|
[[ "''${flagsArray[5]}" == "g" ]] || (echo "'\$flagsArray[5]' was not 'g'" && false)
|
|
[[ "''${flagsArray[6]}" == "h" ]] || (echo "'\$flagsArray[6]' was not 'h'" && false)
|
|
|
|
# test concatenating to unset variable
|
|
concatTo nonExistant string list notset=e=f empty_array=g empty_string=h
|
|
declare -p nonExistant
|
|
[[ "''${nonExistant[0]}" == "a" ]] || (echo "'\$nonExistant[0]' was not 'a'" && false)
|
|
[[ "''${nonExistant[1]}" == "b" ]] || (echo "'\$nonExistant[1]' was not 'b'" && false)
|
|
[[ "''${nonExistant[2]}" == "c" ]] || (echo "'\$nonExistant[2]' was not 'c'" && false)
|
|
[[ "''${nonExistant[3]}" == "d" ]] || (echo "'\$nonExistant[3]' was not 'd'" && false)
|
|
[[ "''${nonExistant[4]}" == "e=f" ]] || (echo "'\$nonExistant[4]' was not 'e=f'" && false)
|
|
[[ "''${nonExistant[5]}" == "g" ]] || (echo "'\$nonExistant[5]' was not 'g'" && false)
|
|
[[ "''${nonExistant[6]}" == "h" ]] || (echo "'\$nonExistant[6]' was not 'h'" && false)
|
|
|
|
eval "$extraTest"
|
|
|
|
touch $out
|
|
'';
|
|
} // extraAttrs);
|
|
|
|
testConcatStringsSep = { name, stdenv' }:
|
|
stdenv'.mkDerivation
|
|
{
|
|
inherit name;
|
|
|
|
# NOTE: Testing with "&" as separator is intentional, because unquoted
|
|
# "&" has a special meaning in the "${var//pattern/replacement}" syntax.
|
|
# Cf. https://github.com/NixOS/nixpkgs/pull/318614#discussion_r1706191919
|
|
passAsFile = [ "buildCommand" ];
|
|
buildCommand = ''
|
|
declare -A associativeArray=(["X"]="Y")
|
|
[[ $(concatStringsSep ";" associativeArray 2>&1) =~ "trying to use" ]] || (echo "concatStringsSep did not throw concatenating associativeArray" && false)
|
|
|
|
string="lorem ipsum dolor sit amet"
|
|
stringWithSep="$(concatStringsSep "&" string)"
|
|
[[ "$stringWithSep" == "lorem&ipsum&dolor&sit&amet" ]] || (echo "'\$stringWithSep' was not 'lorem&ipsum&dolor&sit&amet'" && false)
|
|
|
|
array=("lorem ipsum" "dolor" "sit amet")
|
|
arrayWithSep="$(concatStringsSep "&" array)"
|
|
[[ "$arrayWithSep" == "lorem ipsum&dolor&sit amet" ]] || (echo "'\$arrayWithSep' was not 'lorem ipsum&dolor&sit amet'" && false)
|
|
|
|
touch $out
|
|
'';
|
|
};
|
|
in
|
|
|
|
{
|
|
# Disable on Darwin due to assumptions with __bootPackages
|
|
__attrsFailEvaluation = stdenv.isDarwin;
|
|
|
|
# tests for hooks in `stdenv.defaultNativeBuildInputs`
|
|
hooks = lib.recurseIntoAttrs (import ./hooks.nix { stdenv = bootStdenv; pkgs = earlyPkgs; inherit lib; });
|
|
|
|
outputs-no-out = runCommand "outputs-no-out-assert" {
|
|
result = earlierPkgs.testers.testBuildFailure (bootStdenv.mkDerivation {
|
|
NIX_DEBUG = 1;
|
|
name = "outputs-no-out";
|
|
outputs = ["foo"];
|
|
buildPhase = ":";
|
|
installPhase = ''
|
|
touch $foo
|
|
'';
|
|
});
|
|
|
|
# Assumption: the first output* variable to be configured is
|
|
# _overrideFirst outputDev "dev" "out"
|
|
expectedMsg = "error: _assignFirst: could not find a non-empty variable whose name to assign to outputDev.\n The following variables were all unset or empty:\n dev out";
|
|
} ''
|
|
grep -F "$expectedMsg" $result/testBuildFailure.log >/dev/null
|
|
touch $out
|
|
'';
|
|
|
|
test-env-attrset = testEnvAttrset { name = "test-env-attrset"; stdenv' = bootStdenv; };
|
|
|
|
# Test compatibility with derivations using `env` as a regular variable.
|
|
test-env-derivation = bootStdenv.mkDerivation rec {
|
|
name = "test-env-derivation";
|
|
env = bootStdenv.mkDerivation {
|
|
name = "foo";
|
|
buildCommand = ''
|
|
mkdir "$out"
|
|
touch "$out/bar"
|
|
'';
|
|
};
|
|
|
|
passAsFile = [ "buildCommand" ];
|
|
buildCommand = ''
|
|
declare -p env
|
|
[[ $env == "${env}" ]]
|
|
touch "$out"
|
|
'';
|
|
};
|
|
|
|
# Check that mkDerivation rejects MD5 hashes
|
|
rejectedHashes = lib.recurseIntoAttrs {
|
|
md5 =
|
|
let drv = runCommand "md5 outputHash rejected" {
|
|
outputHash = "md5-fPt7dxVVP7ffY3MxkQdwVw==";
|
|
} "true";
|
|
in assert !(builtins.tryEval drv).success; {};
|
|
};
|
|
|
|
test-inputDerivation = let
|
|
inherit (stdenv.mkDerivation {
|
|
dep1 = derivation { name = "dep1"; builder = "/bin/sh"; args = [ "-c" ": > $out" ]; system = builtins.currentSystem; };
|
|
dep2 = derivation { name = "dep2"; builder = "/bin/sh"; args = [ "-c" ": > $out" ]; system = builtins.currentSystem; };
|
|
passAsFile = [ "dep2" ];
|
|
}) inputDerivation;
|
|
in
|
|
runCommand "test-inputDerivation" {
|
|
exportReferencesGraph = [ "graph" inputDerivation ];
|
|
} ''
|
|
grep ${inputDerivation.dep1} graph
|
|
grep ${inputDerivation.dep2} graph
|
|
touch $out
|
|
'';
|
|
|
|
test-inputDerivation-fixed-output = let
|
|
inherit (stdenv.mkDerivation {
|
|
dep1 = derivation { name = "dep1"; builder = "/bin/sh"; args = [ "-c" ": > $out" ]; system = builtins.currentSystem; };
|
|
dep2 = derivation { name = "dep2"; builder = "/bin/sh"; args = [ "-c" ": > $out" ]; system = builtins.currentSystem; };
|
|
name = "meow";
|
|
outputHash = "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=";
|
|
outputHashMode = "flat";
|
|
outputHashAlgo = "sha256";
|
|
buildCommand = ''
|
|
touch $out
|
|
'';
|
|
passAsFile = [ "dep2" ];
|
|
}) inputDerivation;
|
|
in
|
|
runCommand "test-inputDerivation" {
|
|
exportReferencesGraph = [ "graph" inputDerivation ];
|
|
} ''
|
|
grep ${inputDerivation.dep1} graph
|
|
grep ${inputDerivation.dep2} graph
|
|
touch $out
|
|
'';
|
|
|
|
test-prepend-append-to-var = testPrependAndAppendToVar {
|
|
name = "test-prepend-append-to-var";
|
|
stdenv' = bootStdenv;
|
|
};
|
|
|
|
test-concat-to = testConcatTo {
|
|
name = "test-concat-to";
|
|
stdenv' = bootStdenv;
|
|
};
|
|
|
|
test-concat-strings-sep = testConcatStringsSep {
|
|
name = "test-concat-strings-sep";
|
|
stdenv' = bootStdenv;
|
|
};
|
|
|
|
test-structured-env-attrset = testEnvAttrset {
|
|
name = "test-structured-env-attrset";
|
|
stdenv' = bootStdenv;
|
|
extraAttrs = { __structuredAttrs = true; };
|
|
};
|
|
|
|
test-cc-wrapper-substitutions = ccWrapperSubstitutionsTest {
|
|
name = "test-cc-wrapper-substitutions";
|
|
stdenv' = bootStdenv;
|
|
};
|
|
|
|
structuredAttrsByDefault = lib.recurseIntoAttrs {
|
|
|
|
hooks = lib.recurseIntoAttrs (import ./hooks.nix { stdenv = bootStdenvStructuredAttrsByDefault; pkgs = earlyPkgs; inherit lib; });
|
|
|
|
test-cc-wrapper-substitutions = ccWrapperSubstitutionsTest {
|
|
name = "test-cc-wrapper-substitutions-structuredAttrsByDefault";
|
|
stdenv' = bootStdenvStructuredAttrsByDefault;
|
|
};
|
|
|
|
test-structured-env-attrset = testEnvAttrset {
|
|
name = "test-structured-env-attrset-structuredAttrsByDefault";
|
|
stdenv' = bootStdenvStructuredAttrsByDefault;
|
|
};
|
|
|
|
test-prepend-append-to-var = testPrependAndAppendToVar {
|
|
name = "test-prepend-append-to-var-structuredAttrsByDefault";
|
|
stdenv' = bootStdenvStructuredAttrsByDefault;
|
|
extraAttrs = {
|
|
# will be a bash indexed array in attrs.sh
|
|
# declare -a list=('a' 'b' )
|
|
# and a json array in attrs.json
|
|
# "list":["a","b"]
|
|
list = [ "a" "b" ];
|
|
# will be a bash associative array(dictionary) in attrs.sh
|
|
# declare -A array=(['a']='1' ['b']='2' )
|
|
# and a json object in attrs.json
|
|
# {"array":{"a":"1","b":"2"}
|
|
array = { a = "1"; b = "2"; };
|
|
extraTest = ''
|
|
declare -p array
|
|
array+=(["c"]="3")
|
|
declare -p array
|
|
|
|
[[ "''${array[c]}" == "3" ]] || (echo "c element of '\$array' was not '3'" && false)
|
|
|
|
declare -p list
|
|
prependToVar list hello
|
|
# test that quoted strings work
|
|
appendToVar list "world"
|
|
declare -p list
|
|
|
|
[[ "''${list[0]}" == "hello" ]] || (echo "first element of '\$list' was not 'hello'" && false)
|
|
[[ "''${list[1]}" == "a" ]] || (echo "first element of '\$list' was not 'a'" && false)
|
|
[[ "''${list[-1]}" == "world" ]] || (echo "last element of '\$list' was not 'world'" && false)
|
|
'';
|
|
};
|
|
};
|
|
|
|
test-concat-to = testConcatTo {
|
|
name = "test-concat-to-structuredAttrsByDefault";
|
|
stdenv' = bootStdenvStructuredAttrsByDefault;
|
|
extraAttrs = {
|
|
# test that whitespace is kept in the bash array for structuredAttrs
|
|
listWithSpaces = [ "c c" "d d" ];
|
|
extraTest = ''
|
|
declare -a flagsWithSpaces
|
|
concatTo flagsWithSpaces string listWithSpaces
|
|
declare -p flagsWithSpaces
|
|
[[ "''${flagsWithSpaces[0]}" == "a" ]] || (echo "'\$flagsWithSpaces[0]' was not 'a'" && false)
|
|
[[ "''${flagsWithSpaces[1]}" == "b" ]] || (echo "'\$flagsWithSpaces[1]' was not 'b'" && false)
|
|
[[ "''${flagsWithSpaces[2]}" == "c c" ]] || (echo "'\$flagsWithSpaces[2]' was not 'c c'" && false)
|
|
[[ "''${flagsWithSpaces[3]}" == "d d" ]] || (echo "'\$flagsWithSpaces[3]' was not 'd d'" && false)
|
|
'';
|
|
};
|
|
};
|
|
|
|
test-concat-strings-sep = testConcatStringsSep {
|
|
name = "test-concat-strings-sep-structuredAttrsByDefault";
|
|
stdenv' = bootStdenvStructuredAttrsByDefault;
|
|
};
|
|
|
|
test-golden-example-structuredAttrs =
|
|
let
|
|
goldenSh = earlyPkgs.writeText "goldenSh" ''
|
|
declare -A EXAMPLE_ATTRS=(['foo']='bar' )
|
|
declare EXAMPLE_BOOL_FALSE=
|
|
declare EXAMPLE_BOOL_TRUE=1
|
|
declare EXAMPLE_INT=123
|
|
declare EXAMPLE_INT_NEG=-123
|
|
declare -a EXAMPLE_LIST=('foo' 'bar' )
|
|
declare EXAMPLE_STR='foo bar'
|
|
'';
|
|
goldenJson = earlyPkgs.writeText "goldenSh" ''
|
|
{
|
|
"EXAMPLE_ATTRS": {
|
|
"foo": "bar"
|
|
},
|
|
"EXAMPLE_BOOL_FALSE": false,
|
|
"EXAMPLE_BOOL_TRUE": true,
|
|
"EXAMPLE_INT": 123,
|
|
"EXAMPLE_INT_NEG": -123,
|
|
"EXAMPLE_LIST": [
|
|
"foo",
|
|
"bar"
|
|
],
|
|
"EXAMPLE_NESTED_ATTRS": {
|
|
"foo": {
|
|
"bar": "baz"
|
|
}
|
|
},
|
|
"EXAMPLE_NESTED_LIST": [
|
|
[
|
|
"foo",
|
|
"bar"
|
|
],
|
|
[
|
|
"baz"
|
|
]
|
|
],
|
|
"EXAMPLE_STR": "foo bar"
|
|
}
|
|
'';
|
|
in
|
|
bootStdenvStructuredAttrsByDefault.mkDerivation {
|
|
name = "test-golden-example-structuredAttrsByDefault";
|
|
nativeBuildInputs = [ earlyPkgs.jq ];
|
|
|
|
EXAMPLE_BOOL_TRUE = true;
|
|
EXAMPLE_BOOL_FALSE = false;
|
|
EXAMPLE_INT = 123;
|
|
EXAMPLE_INT_NEG = -123;
|
|
EXAMPLE_STR = "foo bar";
|
|
EXAMPLE_LIST = [ "foo" "bar" ];
|
|
EXAMPLE_NESTED_LIST = [ [ "foo" "bar" ] [ "baz" ] ];
|
|
EXAMPLE_ATTRS = { foo = "bar"; };
|
|
EXAMPLE_NESTED_ATTRS = { foo.bar = "baz"; };
|
|
|
|
inherit goldenSh;
|
|
inherit goldenJson;
|
|
|
|
buildCommand = ''
|
|
mkdir -p $out
|
|
cat $NIX_ATTRS_SH_FILE | grep "EXAMPLE" | grep -v -E 'installPhase|jq' > $out/sh
|
|
jq 'with_entries(select(.key|match("EXAMPLE")))' $NIX_ATTRS_JSON_FILE > $out/json
|
|
diff $out/sh $goldenSh
|
|
diff $out/json $goldenJson
|
|
'';
|
|
};
|
|
|
|
};
|
|
}
|