Do not rely on $stdenv/setup to set output variables

Instead of relying on setup script to set output variables when
structured attributes are enabled, iterate over the values of an
outputs associative array.

See also
374fa3532e/pkgs/stdenv/generic/setup.sh (L23-L26)
This commit is contained in:
Ivan Trubach 2024-04-10 13:34:17 +03:00
parent 65d711351e
commit 664532c533
4 changed files with 38 additions and 29 deletions

View File

@ -177,6 +177,14 @@ struct BuildEnvironment
throw Error("bash variable is not a string");
}
static Associative getAssociative(const Value & value)
{
if (auto assoc = std::get_if<Associative>(&value))
return *assoc;
else
throw Error("bash variable is not an associative array");
}
static Array getStrings(const Value & value)
{
if (auto str = std::get_if<String>(&value))
@ -362,13 +370,17 @@ struct Common : InstallableCommand, MixProfile
auto outputs = buildEnvironment.vars.find("outputs");
assert(outputs != buildEnvironment.vars.end());
// FIXME: properly unquote 'outputs'.
StringMap rewrites;
for (auto & outputName : BuildEnvironment::getStrings(outputs->second)) {
auto from = buildEnvironment.vars.find(outputName);
assert(from != buildEnvironment.vars.end());
// FIXME: unquote
rewrites.insert({BuildEnvironment::getString(from->second), outputsDir + "/" + outputName});
if (buildEnvironment.providesStructuredAttrs()) {
for (auto & [outputName, from] : BuildEnvironment::getAssociative(outputs->second)) {
rewrites.insert({from, outputsDir + "/" + outputName});
}
} else {
for (auto & outputName : BuildEnvironment::getStrings(outputs->second)) {
auto from = buildEnvironment.vars.find(outputName);
assert(from != buildEnvironment.vars.end());
rewrites.insert({BuildEnvironment::getString(from->second), outputsDir + "/" + outputName});
}
}
/* Substitute redirects. */

View File

@ -128,20 +128,25 @@ __escapeString() {
printf '"%s"' "$__s"
}
# In case of `__structuredAttrs = true;` the list of outputs is an associative
# array with a format like `outname => /nix/store/hash-drvname-outname`, so `__olist`
# must contain the array's keys (hence `${!...[@]}`) in this case.
if [ -e "$NIX_ATTRS_SH_FILE" ]; then
__olist="${!outputs[@]}"
else
__olist=$outputs
fi
for __output in $__olist; do
if [[ -z $__done ]]; then
__dumpEnv > ${!__output}
__dumpEnvToOutput() {
local __output="$1"
if [[ -z ${__done-} ]]; then
__dumpEnv > "$__output"
__done=1
else
echo -n >> "${!__output}"
echo -n >> "$__output"
fi
done
}
# In case of `__structuredAttrs = true;` the list of outputs is an associative
# array with a format like `outname => /nix/store/hash-drvname-outname`.
# Otherwise it is a space-separated list of output variable names.
if [ -e "$NIX_ATTRS_SH_FILE" ]; then
for __output in "${outputs[@]}"; do
__dumpEnvToOutput "$__output"
done
else
for __outname in $outputs; do
__dumpEnvToOutput "${!__outname}"
done
fi

View File

@ -21,14 +21,6 @@ let pkgs = rec {
export PATH=$PATH:$pkg/bin
done
# mimic behavior of stdenv for `$out` etc. for structured attrs.
if [ -n "''${NIX_ATTRS_SH_FILE}" ]; then
for o in "''${!outputs[@]}"; do
eval "''${o}=''${outputs[$o]}"
export "''${o}"
done
fi
declare -a arr1=(1 2 "3 4" 5)
declare -a arr2=(x $'\n' $'x\ny')
fun() {

View File

@ -32,4 +32,4 @@ jsonOut="$(nix print-dev-env -f structured-attrs-shell.nix --json)"
test "$(<<<"$jsonOut" jq '.structuredAttrs|keys|.[]' -r)" = "$(printf ".attrs.json\n.attrs.sh")"
test "$(<<<"$jsonOut" jq '.variables.out.value' -r)" = "$(<<<"$jsonOut" jq '.structuredAttrs.".attrs.json"' -r | jq -r '.outputs.out')"
test "$(<<<"$jsonOut" jq '.variables.outputs.value.out' -r)" = "$(<<<"$jsonOut" jq '.structuredAttrs.".attrs.json"' -r | jq -r '.outputs.out')"