diff --git a/pkgs/stdenv/generic/setup.sh b/pkgs/stdenv/generic/setup.sh index a50596985ec..3cc84c9db5e 100644 --- a/pkgs/stdenv/generic/setup.sh +++ b/pkgs/stdenv/generic/setup.sh @@ -655,20 +655,57 @@ patchShebangs() { # Rewrite all script interpreter file names (`#! /path') under the # specified directory tree to paths found in $PATH. E.g., # /bin/sh will be rewritten to /nix/store/-some-bash/bin/sh. + # /usr/bin/env gets special treatment so that ".../bin/env python" is + # rewritten to /nix/store//bin/python. # Interpreters that are already in the store are left untouched. header "patching script interpreter paths" local dir="$1" local f + local oldPath + local newPath + local arg0 + local args + local oldInterpreterLine + local newInterpreterLine + for f in $(find "$dir" -type f -perm +0100); do - local oldPath=$(sed -ne '1 s,^#![ ]*\([^ ]*\).*$,\1,p' "$f") + if [ $(head -1 "$f" | head -c +2) != '#!' ]; then + # missing shebang => not a script + continue + fi + + oldInterpreterLine=$(head -1 "$f" | tail -c +3) + read oldPath arg0 args <<< "$oldInterpreterLine" + + if $(echo "$oldPath" | grep -q "/bin/env$"); then + # Check for unsupported 'env' functionality: + # - options: something starting with a '-' + # - environment variables: foo=bar + if $(echo "$arg0" | grep -q -- "^-.*\|.*=.*"); then + echo "unsupported interpreter directive \"$oldInterpreterLine\" (set dontPatchShebangs=1 and handle shebang patching yourself)" + exit 1 + fi + newPath="$(command -v "$arg0")" + else + if [ "$oldPath" = "" ]; then + # If no interpreter is specified linux will use /bin/sh. Set + # oldpath="/bin/sh" so that we get /nix/store/.../sh. + oldPath="/bin/sh" + fi + newPath="$(command -v "$(basename "$oldPath")")" + args="$arg0 $args" + fi + + newInterpreterLine="$newPath $args" + if [ -n "$oldPath" -a "${oldPath:0:${#NIX_STORE}}" != "$NIX_STORE" ]; then - local newPath=$(type -P $(basename $oldPath) || true) if [ -n "$newPath" -a "$newPath" != "$oldPath" ]; then - echo "$f: interpreter changed from $oldPath to $newPath" - sed -i -e "1 s,$oldPath,$newPath," "$f" + echo "$f: interpreter directive changed from \"$oldInterpreterLine\" to \"$newInterpreterLine\"" + sed -i -e "1 s|.*|#\!$newInterpreterLine|" "$f" fi fi done + stopNest }