diff --git a/pkgs/build-support/fetchurl/builder.sh b/pkgs/build-support/fetchurl/builder.sh index ae6c372208e1..9add2b27a072 100644 --- a/pkgs/build-support/fetchurl/builder.sh +++ b/pkgs/build-support/fetchurl/builder.sh @@ -1,6 +1,16 @@ source "$NIX_ATTRS_SH_FILE" source $mirrorsFile +# Normalize `curlOpts` as a string. +# If defined as a list (deprecated), it would be a bash array. +if [[ "$(declare -p curlOpts 2&>/dev/null || true)" =~ ^"declare -a" ]]; then + unset _temp + _temp="${curlOpts[*]}" + unset curlOpts + curlOpts=$_temp + unset _temp +fi + curlVersion=$(curl -V | head -1 | cut -d' ' -f2) # Curl flags to handle redirects, not use EPSV, handle cookies for @@ -23,17 +33,23 @@ if ! [ -f "$SSL_CERT_FILE" ]; then curl+=(--insecure) fi -curl+=("${curlOptsList[@]}") +# NOTE: +# `netrcPhase` should not attempt to access builder.sh implementation details (e.g., the `${curl[@]}` array), +# The implementation detail could change in any Nixpkgs revision, including backports. +if [[ -n "${netrcPhase-}" ]]; then + runPhase netrcPhase + curl+=(--netrc-file "$PWD/netrc") +fi curl+=( - ${curlOpts[*]} + "${curlOptsList[@]}" + $curlOpts $NIX_CURL_FLAGS ) downloadedFile="$out" if [ -n "$downloadToTemp" ]; then downloadedFile="$TMPDIR/file"; fi - tryDownload() { local url="$1" local target="$2" diff --git a/pkgs/build-support/fetchurl/default.nix b/pkgs/build-support/fetchurl/default.nix index 763bf5429cc1..7747a3a8f0fe 100644 --- a/pkgs/build-support/fetchurl/default.nix +++ b/pkgs/build-support/fetchurl/default.nix @@ -333,15 +333,6 @@ lib.extendMkDerivation { inherit preferLocalBuild; - postHook = - if netrcPhase == null then - null - else - '' - ${netrcPhase} - curlOpts="$curlOpts --netrc-file $PWD/netrc" - ''; - inherit meta; passthru = { inherit url resolvedUrl; diff --git a/pkgs/build-support/fetchurl/tests.nix b/pkgs/build-support/fetchurl/tests.nix index b4baeec9a9e7..c89368a6d209 100644 --- a/pkgs/build-support/fetchurl/tests.nix +++ b/pkgs/build-support/fetchurl/tests.nix @@ -1,11 +1,93 @@ { + lib, testers, fetchurl, + writeShellScriptBin, jq, moreutils, + emptyFile, ... }: +let + testFlagAppending = + args: + testers.invalidateFetcherByDrvHash + (fetchurl.override (previousArgs: { + curl = ( + writeShellScriptBin "curl" '' + set -eu -o pipefail + hasFoo= + hasBar= + echo "curl-mock-expecting-flags: get flags: $*" >&2 + for arg; do + case "$arg" in + -V|--version) + ${lib.getExe previousArgs.curl} "$arg" + exit "$?" + ;; + --foo) + echo "curl-mock-expecting-flags: \`--foo' found in the argument list passed to \`curl'." >&2 + hasFoo=1 + ;; + --bar) + echo "curl-mock-expecting-flags: \`--bar' found in the argument list passed to \`curl'." >&2 + hasBar=1 + ;; + esac + done + if [[ -z "$hasFoo" ]]; then + echo "ERROR: curl-mock-expecting-flags: \`--foo' missing in the argument list passed to \`curl'." >&2 + fi + if [[ -z "$hasBar" ]]; then + echo "ERROR: curl-mock-expecting-flags: \`--bar' missing in the argument list passed to \`curl'." >&2 + fi + if [[ -n "$hasFoo" ]] && [[ -n "$hasBar" ]]; then + touch $out + else + exit 1 + fi + '' + ); + })) + ( + { + url = "https://www.example.com/source"; + hash = emptyFile.outputHash; + recursiveHash = true; # aligned with emptyFile + } + // args + ); +in { + flag-appending-curlOpts = testFlagAppending { + name = "test-fetchurl-flag-appending-curlOpts"; + curlOpts = "--foo --bar"; + }; + + flag-appending-curlOptsList = testFlagAppending { + name = "test-fetchurl-flag-appending-curlOptsList"; + curlOptsList = [ + "--foo" + "--bar" + ]; + }; + + flag-appending-netrcPhase-curlOpts = testFlagAppending { + name = "test-fetchurl-flag-appending-netrcPhase-curlOpts"; + netrcPhase = '' + touch netrc + curlOpts="$curlOpts --foo --bar" + ''; + }; + + flag-appending-netrcPhase-curlOptsList = testFlagAppending { + name = "test-fetchurl-flag-appending-netrcPhase-curlOptsList"; + netrcPhase = '' + touch netrc + curlOptsList+=("--foo" "--bar") + ''; + }; + # Tests that we can send custom headers with spaces in them header = let