diff options
Diffstat (limited to 'pkgs/stdenv/generic/setup.sh')
-rw-r--r-- | pkgs/stdenv/generic/setup.sh | 206 |
1 files changed, 165 insertions, 41 deletions
diff --git a/pkgs/stdenv/generic/setup.sh b/pkgs/stdenv/generic/setup.sh index 45c73d7709c66..fc748aa12a665 100644 --- a/pkgs/stdenv/generic/setup.sh +++ b/pkgs/stdenv/generic/setup.sh @@ -12,7 +12,15 @@ fi shopt -s inherit_errexit -if (( "${NIX_DEBUG:-0}" >= 6 )); then +# $NIX_DEBUG must be a documented integer level, if set, so we can use it safely as an integer. +# See the `Verbosity` enum in the Nix source for these levels. +if ! [[ -z ${NIX_DEBUG-} || $NIX_DEBUG == [0-7] ]]; then + printf 'The `NIX_DEBUG` environment variable has an unexpected value: %s\n' "${NIX_DEBUG}" + echo "It can only be unset or an integer between 0 and 7." + exit 1 +fi + +if [[ ${NIX_DEBUG:-0} -ge 6 ]]; then set -x fi @@ -47,10 +55,109 @@ getAllOutputNames() { fi } +# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. +# Corresponds to `Verbosity::lvlError` in the Nix source. +nixErrorLog() { + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 0 ]]; then return; fi + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} + +# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. +# Corresponds to `Verbosity::lvlWarn` in the Nix source. +nixWarnLog() { + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 1 ]]; then return; fi + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} + +# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. +# Corresponds to `Verbosity::lvlNotice` in the Nix source. +nixNoticeLog() { + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 2 ]]; then return; fi + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} + +# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. +# Corresponds to `Verbosity::lvlInfo` in the Nix source. +nixInfoLog() { + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 3 ]]; then return; fi + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} + +# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. +# Corresponds to `Verbosity::lvlTalkative` in the Nix source. +nixTalkativeLog() { + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 4 ]]; then return; fi + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} + +# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. +# Corresponds to `Verbosity::lvlChatty` in the Nix source. +nixChattyLog() { + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 5 ]]; then return; fi + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} + +# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. +# Corresponds to `Verbosity::lvlDebug` in the Nix source. +nixDebugLog() { + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 6 ]]; then return; fi + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} + +# All provided arguments are joined with a space then directed to $NIX_LOG_FD, if it's set. +# Corresponds to `Verbosity::lvlVomit` in the Nix source. +nixVomitLog() { + if [[ -z ${NIX_LOG_FD-} ]] || [[ ${NIX_DEBUG:-0} -lt 7 ]]; then return; fi + printf "%s\n" "$*" >&"$NIX_LOG_FD" +} + +# Log a hook, to be run before the hook is actually called. +# logging for "implicit" hooks -- the ones specified directly +# in derivation's arguments -- is done in _callImplicitHook instead. +_logHook() { + # Fast path in case nixTalkativeLog is no-op. + if [[ -z ${NIX_LOG_FD-} ]]; then + return + fi + + local hookKind="$1" + local hookExpr="$2" + shift 2 + + if declare -F "$hookExpr" > /dev/null 2>&1; then + nixTalkativeLog "calling '$hookKind' function hook '$hookExpr'" "$@" + elif type -p "$hookExpr" > /dev/null; then + nixTalkativeLog "sourcing '$hookKind' script hook '$hookExpr'" + elif [[ "$hookExpr" != "_callImplicitHook"* ]]; then + # Here we have a string hook to eval. + # Join lines onto one with literal \n characters unless NIX_DEBUG >= 5. + local exprToOutput + if [[ ${NIX_DEBUG:-0} -ge 5 ]]; then + exprToOutput="$hookExpr" + else + # We have `r'\n'.join([line.lstrip() for lines in text.split('\n')])` at home. + local hookExprLine + while IFS= read -r hookExprLine; do + # These lines often have indentation, + # so let's remove leading whitespace. + hookExprLine="${hookExprLine#"${hookExprLine%%[![:space:]]*}"}" + # If this line wasn't entirely whitespace, + # then add it to our output + if [[ -n "$hookExprLine" ]]; then + exprToOutput+="$hookExprLine\\n " + fi + done <<< "$hookExpr" + + # And then remove the final, unnecessary, \n + exprToOutput="${exprToOutput%%\\n }" + fi + nixTalkativeLog "evaling '$hookKind' string hook '$exprToOutput'" + fi +} + ###################################################################### # Hook handling. - # Run all hooks with the specified name in the order in which they # were added, stopping if any fails (returns a non-zero exit # code). The hooks for <hookName> are the shell function or variable @@ -64,6 +171,7 @@ runHook() { # Hack around old bash being bad and thinking empty arrays are # undefined. for hook in "_callImplicitHook 0 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do + _logHook "$hookName" "$hook" "$@" _eval "$hook" "$@" done @@ -81,6 +189,7 @@ runOneHook() { local hook ret=1 # Hack around old bash like above for hook in "_callImplicitHook 1 $hookName" ${!hooksSlice+"${!hooksSlice}"}; do + _logHook "$hookName" "$hook" "$@" if _eval "$hook" "$@"; then ret=0 break @@ -100,10 +209,13 @@ _callImplicitHook() { local def="$1" local hookName="$2" if declare -F "$hookName" > /dev/null; then + nixTalkativeLog "calling implicit '$hookName' function hook" "$hookName" elif type -p "$hookName" > /dev/null; then + nixTalkativeLog "sourcing implicit '$hookName' script hook" source "$hookName" elif [ -n "${!hookName:-}" ]; then + nixTalkativeLog "evaling implicit '$hookName' string hook" eval "${!hookName}" else return "$def" @@ -293,8 +405,10 @@ _accumFlagsArray() { local -n nameref="$name" case "$name" in *Array) + # shellcheck disable=SC2206 flagsArray+=( ${nameref+"${nameref[@]}"} ) ;; *) + # shellcheck disable=SC2206 flagsArray+=( ${nameref-} ) ;; esac done @@ -417,10 +531,7 @@ done unset i -if (( "${NIX_DEBUG:-0}" >= 1 )); then - echo "initial path: $PATH" -fi - +nixWarnLog "initial path: $PATH" # Check that the pre-hook initialised SHELL. if [ -z "${SHELL:-}" ]; then echo "SHELL not set"; exit 1; fi @@ -514,7 +625,9 @@ findInputs() { # Sanity check (( hostOffset <= targetOffset )) || exit 1 + # shellcheck disable=SC1087 local varVar="${pkgAccumVarVars[hostOffset + 1]}" + # shellcheck disable=SC1087 local varRef="$varVar[$((targetOffset - hostOffset))]" local var="${!varRef}" unset -v varVar varRef @@ -523,6 +636,7 @@ findInputs() { # nix-shell doesn't use impure bash. This should replace the O(n) # case with an O(1) hash map lookup, assuming bash is implemented # well :D. + # shellcheck disable=SC1087 local varSlice="$var[*]" # ${..-} to hack around old bash empty array problem case "${!varSlice-}" in @@ -644,6 +758,7 @@ activatePackage() { (( hostOffset <= targetOffset )) || exit 1 if [ -f "$pkg" ]; then + nixTalkativeLog "sourcing setup hook '$pkg'" source "$pkg" fi @@ -667,6 +782,7 @@ activatePackage() { fi if [[ -f "$pkg/nix-support/setup-hook" ]]; then + nixTalkativeLog "sourcing setup hook '$pkg/nix-support/setup-hook'" source "$pkg/nix-support/setup-hook" fi } @@ -778,11 +894,10 @@ fi PATH="${_PATH-}${_PATH:+${PATH:+:}}$PATH" HOST_PATH="${_HOST_PATH-}${_HOST_PATH:+${HOST_PATH:+:}}$HOST_PATH" export XDG_DATA_DIRS="${_XDG_DATA_DIRS-}${_XDG_DATA_DIRS:+${XDG_DATA_DIRS:+:}}${XDG_DATA_DIRS-}" -if (( "${NIX_DEBUG:-0}" >= 1 )); then - echo "final path: $PATH" - echo "final host path: $HOST_PATH" - echo "final data dirs: $XDG_DATA_DIRS" -fi + +nixWarnLog "final path: $PATH" +nixWarnLog "final host path: $HOST_PATH" +nixWarnLog "final data dirs: $XDG_DATA_DIRS" unset _PATH unset _HOST_PATH @@ -830,7 +945,7 @@ substituteStream() { # deprecated 2023-11-22 # this will either get removed, or switch to the behaviour of --replace-fail in the future if ! "$_substituteStream_has_warned_replace_deprecation"; then - echo "substituteStream(): WARNING: '--replace' is deprecated, use --replace-{fail,warn,quiet}. ($description)" >&2 + echo "substituteStream() in derivation $name: WARNING: '--replace' is deprecated, use --replace-{fail,warn,quiet}. ($description)" >&2 _substituteStream_has_warned_replace_deprecation=true fi replace_mode='--replace-warn' @@ -845,9 +960,9 @@ substituteStream() { if [ "$pattern" != "$replacement" ]; then if [ "${!var}" == "$savedvar" ]; then if [ "$replace_mode" == --replace-warn ]; then - printf "substituteStream(): WARNING: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2 + printf "substituteStream() in derivation $name: WARNING: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2 elif [ "$replace_mode" == --replace-fail ]; then - printf "substituteStream(): ERROR: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2 + printf "substituteStream() in derivation $name: ERROR: pattern %q doesn't match anything in %s\n" "$pattern" "$description" >&2 return 1 fi fi @@ -859,11 +974,11 @@ substituteStream() { shift 2 # check if the used nix attribute name is a valid bash name if ! [[ "$varName" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then - echo "substituteStream(): ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." >&2 + echo "substituteStream() in derivation $name: ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." >&2 return 1 fi if [ -z ${!varName+x} ]; then - echo "substituteStream(): ERROR: variable \$$varName is unset" >&2 + echo "substituteStream() in derivation $name: ERROR: variable \$$varName is unset" >&2 return 1 fi pattern="@$varName@" @@ -879,7 +994,7 @@ substituteStream() { ;; *) - echo "substituteStream(): ERROR: Invalid command line argument: $1" >&2 + echo "substituteStream() in derivation $name: ERROR: Invalid command line argument: $1" >&2 return 1 ;; esac @@ -931,16 +1046,13 @@ substituteInPlace() { } _allFlags() { - # export some local variables for the awk below - # so some substitutions such as name don't have to be in the env attrset - # when __structuredAttrs is enabled + # Export some local variables for the `awk` below so some substitutions (such as name) + # don't have to be in the env attrset when `__structuredAttrs` is enabled. export system pname name version - for varName in $(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }'); do - if (( "${NIX_DEBUG:-0}" >= 1 )); then - printf "@%s@ -> %q\n" "${varName}" "${!varName}" >&2 - fi + while IFS='' read -r varName; do + nixTalkativeLog "@${varName}@ -> ${!varName}" args+=("--subst-var" "$varName") - done + done < <(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }') } substituteAllStream() { @@ -981,7 +1093,7 @@ substituteAllInPlace() { # the environment used for building. dumpVars() { if [ "${noDumpEnvVars:-0}" != 1 ]; then - export 2>/dev/null >| "$NIX_BUILD_TOP/env-vars" || true + install -m 0600 <(export 2>/dev/null) "$NIX_BUILD_TOP/env-vars" || true fi } @@ -1111,6 +1223,7 @@ unpackPhase() { if [ -n "$__structuredAttrs" ]; then srcsArray=( "${srcs[@]}" ) else + # shellcheck disable=SC2206 srcsArray=( $srcs ) fi @@ -1178,8 +1291,10 @@ patchPhase() { local -a patchesArray if [ -n "$__structuredAttrs" ]; then + # shellcheck disable=SC2206 patchesArray=( ${patches:+"${patches[@]}"} ) else + # shellcheck disable=SC2206 patchesArray=( ${patches:-} ) fi @@ -1205,7 +1320,7 @@ patchPhase() { if [ -n "$__structuredAttrs" ]; then flagsArray=( "${patchFlags[@]:--p1}" ) else - # shellcheck disable=SC2086 + # shellcheck disable=SC2086,SC2206 flagsArray=( ${patchFlags:--p1} ) fi # "2>&1" is a hack to make patch fail if the decompressor fails (nonexistent patch, etc.) @@ -1318,7 +1433,7 @@ buildPhase() { # shellcheck disable=SC2086 local flagsArray=( ${enableParallelBuilding:+-j${NIX_BUILD_CORES}} - SHELL=$SHELL + SHELL="$SHELL" ) _accumFlagsArray makeFlags makeFlagsArray buildFlags buildFlagsArray @@ -1343,9 +1458,9 @@ checkPhase() { if [[ -z "${checkTarget:-}" ]]; then #TODO(@oxij): should flagsArray influence make -n? if make -n ${makefile:+-f $makefile} check >/dev/null 2>&1; then - checkTarget=check + checkTarget="check" elif make -n ${makefile:+-f $makefile} test >/dev/null 2>&1; then - checkTarget=test + checkTarget="test" fi fi @@ -1356,16 +1471,18 @@ checkPhase() { # shellcheck disable=SC2086 local flagsArray=( ${enableParallelChecking:+-j${NIX_BUILD_CORES}} - SHELL=$SHELL + SHELL="$SHELL" ) _accumFlagsArray makeFlags makeFlagsArray if [ -n "$__structuredAttrs" ]; then flagsArray+=( "${checkFlags[@]:-VERBOSE=y}" ) else + # shellcheck disable=SC2206 flagsArray+=( ${checkFlags:-VERBOSE=y} ) fi _accumFlagsArray checkFlagsArray + # shellcheck disable=SC2206 flagsArray+=( ${checkTarget} ) echoCmd 'check flags' "${flagsArray[@]}" @@ -1397,12 +1514,13 @@ installPhase() { # shellcheck disable=SC2086 local flagsArray=( ${enableParallelInstalling:+-j${NIX_BUILD_CORES}} - SHELL=$SHELL + SHELL="$SHELL" ) _accumFlagsArray makeFlags makeFlagsArray installFlags installFlagsArray if [ -n "$__structuredAttrs" ]; then flagsArray+=( "${installTargets[@]:-install}" ) else + # shellcheck disable=SC2206 flagsArray+=( ${installTargets:-install} ) fi @@ -1484,11 +1602,12 @@ installCheckPhase() { # shellcheck disable=SC2086 local flagsArray=( ${enableParallelChecking:+-j${NIX_BUILD_CORES}} - SHELL=$SHELL + SHELL="$SHELL" ) _accumFlagsArray makeFlags makeFlagsArray \ installCheckFlags installCheckFlagsArray + # shellcheck disable=SC2206 flagsArray+=( ${installCheckTarget:-installcheck} ) echoCmd 'installcheck flags' "${flagsArray[@]}" @@ -1505,6 +1624,7 @@ distPhase() { local flagsArray=() _accumFlagsArray distFlags distFlagsArray + # shellcheck disable=SC2206 flagsArray+=( ${distTarget:-dist} ) echo 'dist flags: %q' "${flagsArray[@]}" @@ -1526,6 +1646,13 @@ distPhase() { showPhaseHeader() { local phase="$1" echo "Running phase: $phase" + + # The Nix structured logger allows derivations to update the phase as they're building, + # which shows up in the terminal UI. See `handleJSONLogMessage` in the Nix source. + if [[ -z ${NIX_LOG_FD-} ]]; then + return + fi + printf "@nix { \"action\": \"setPhase\", \"phase\": \"%s\" }\n" "$phase" >&"$NIX_LOG_FD" } @@ -1558,28 +1685,25 @@ runPhase() { if [[ "$curPhase" = installCheckPhase && -z "${doInstallCheck:-}" ]]; then return; fi if [[ "$curPhase" = distPhase && -z "${doDist:-}" ]]; then return; fi - if [[ -n $NIX_LOG_FD ]]; then - echo "@nix { \"action\": \"setPhase\", \"phase\": \"$curPhase\" }" >&"$NIX_LOG_FD" - fi - showPhaseHeader "$curPhase" dumpVars - local startTime=$(date +"%s") + local startTime endTime + startTime=$(date +"%s") # Evaluate the variable named $curPhase if it exists, otherwise the # function named $curPhase. eval "${!curPhase:-$curPhase}" - local endTime=$(date +"%s") + endTime=$(date +"%s") showPhaseFooter "$curPhase" "$startTime" "$endTime" if [ "$curPhase" = unpackPhase ]; then # make sure we can cd into the directory - [ -n "${sourceRoot:-}" ] && chmod +x "${sourceRoot}" + [ -n "${sourceRoot:-}" ] && chmod +x -- "${sourceRoot}" - cd "${sourceRoot:-.}" + cd -- "${sourceRoot:-.}" fi } |