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"); 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) static Array getStrings(const Value & value)
{ {
if (auto str = std::get_if<String>(&value)) if (auto str = std::get_if<String>(&value))
@ -362,13 +370,17 @@ struct Common : InstallableCommand, MixProfile
auto outputs = buildEnvironment.vars.find("outputs"); auto outputs = buildEnvironment.vars.find("outputs");
assert(outputs != buildEnvironment.vars.end()); assert(outputs != buildEnvironment.vars.end());
// FIXME: properly unquote 'outputs'.
StringMap rewrites; StringMap rewrites;
for (auto & outputName : BuildEnvironment::getStrings(outputs->second)) { if (buildEnvironment.providesStructuredAttrs()) {
auto from = buildEnvironment.vars.find(outputName); for (auto & [outputName, from] : BuildEnvironment::getAssociative(outputs->second)) {
assert(from != buildEnvironment.vars.end()); rewrites.insert({from, outputsDir + "/" + outputName});
// FIXME: unquote }
rewrites.insert({BuildEnvironment::getString(from->second), 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. */ /* Substitute redirects. */

View file

@ -128,20 +128,25 @@ __escapeString() {
printf '"%s"' "$__s" printf '"%s"' "$__s"
} }
# In case of `__structuredAttrs = true;` the list of outputs is an associative __dumpEnvToOutput() {
# array with a format like `outname => /nix/store/hash-drvname-outname`, so `__olist` local __output="$1"
# must contain the array's keys (hence `${!...[@]}`) in this case. if [[ -z ${__done-} ]]; then
if [ -e "$NIX_ATTRS_SH_FILE" ]; then __dumpEnv > "$__output"
__olist="${!outputs[@]}"
else
__olist=$outputs
fi
for __output in $__olist; do
if [[ -z $__done ]]; then
__dumpEnv > ${!__output}
__done=1 __done=1
else else
echo -n >> "${!__output}" echo -n >> "$__output"
fi 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 export PATH=$PATH:$pkg/bin
done 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 arr1=(1 2 "3 4" 5)
declare -a arr2=(x $'\n' $'x\ny') declare -a arr2=(x $'\n' $'x\ny')
fun() { 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 '.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')"