patchShebangs: rewrite ".../bin/env python" to /nix/store/.../python

Currently "/usr/bin/env python" is rewritten to "/nix/store/.../env
python". That doesn't really improve anything because the interpreter
still have to be located in $PATH at runtime. The result is that many
nix package expressions do .../bin/env fixup themselves.

Instead of everyone having to do this patching locally, add the
functionality to the standard environment patchShebangs function so that
everyone can benefit.
This commit is contained in:
Bjørn Forsman 2013-11-30 11:03:35 +01:00 committed by Peter Simons
parent 29c11ef8a5
commit 7bf209db50

View File

@ -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/<hash>-some-bash/bin/sh.
# /usr/bin/env gets special treatment so that ".../bin/env python" is
# rewritten to /nix/store/<hash>/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
}