pyenv/libexec/pyenv-init
Isaac Levy cc56f76733
Add --no-push-path option (#2526)
In some advanced shell setups, the order of custom-added PATH entries is important.
We disregard it by default, always pushing shims to the front of PATH,
to ensure that Pyenv works even in poorly maintained shell environments
and with minimal hassle for non-export users
(an attempt to do the opposite (#1898) has ended in a disaster).
Some advanced users are however ready and able to carefully maintain their environment
and deal with breakages and inconvenience. This option is for them.
2022-11-19 00:01:59 +03:00

280 lines
5.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# Summary: Configure the shell environment for pyenv
# Usage: eval "$(pyenv init [-|--path] [--no-push-path] [--no-rehash] [<shell>])"
set -e
[ -n "$PYENV_DEBUG" ] && set -x
# Provide pyenv completions
if [ "$1" = "--complete" ]; then
echo -
echo --path
echo --no-push-path
echo --no-rehash
echo bash
echo fish
echo ksh
echo zsh
exit
fi
mode="help"
no_rehash=""
no_push_path=""
for args in "$@"
do
if [ "$args" = "-" ]; then
mode="print"
shift
fi
if [ "$args" = "--path" ]; then
mode="path"
shift
fi
if [ "$args" = "--no-push-path" ]; then
no_push_path=1
shift
fi
if [ "$args" = "--no-rehash" ]; then
no_rehash=1
shift
fi
done
shell="$1"
if [ -z "$shell" ]; then
shell="$(ps -p "$PPID" -o 'args=' 2>/dev/null || true)"
shell="${shell%% *}"
shell="${shell##-}"
shell="${shell:-$SHELL}"
shell="${shell##*/}"
shell="${shell%%-*}"
fi
root="${0%/*}/.."
function main() {
case "$mode" in
"help")
help_
exit 1
;;
"path")
print_path
print_rehash
exit 0
;;
"print")
init_dirs
print_path
print_env
print_completion
print_rehash
print_shell_function
exit 0
;;
esac
# should never get here
exit 2
}
function help_() {
case "$shell" in
bash )
if [ -e '~/.bash_profile' ]; then
profile='~/.bash_profile'
else
profile='~/.profile'
fi
profile_explain="~/.bash_profile if it exists, otherwise ~/.profile"
rc='~/.bashrc'
;;
zsh )
profile='~/.zprofile'
rc='~/.zshrc'
;;
ksh )
profile='~/.profile'
rc='~/.profile'
;;
* )
profile='your shell'\''s login startup file'
rc='your shell'\''s interactive startup file'
;;
esac
{
case "$shell" in
fish )
echo "# Add pyenv executable to PATH by running"
echo "# the following interactively:"
echo
echo 'set -Ux PYENV_ROOT $HOME/.pyenv'
echo 'set -U fish_user_paths $PYENV_ROOT/bin $fish_user_paths'
echo
echo "# Load pyenv automatically by appending"
echo "# the following to ~/.config/fish/config.fish:"
echo
echo 'pyenv init - | source'
echo
;;
* )
echo '# Load pyenv automatically by appending'
echo -n "# the following to "
if [ "$profile" == "$rc" ]; then
echo "$profile :"
else
echo
echo "${profile_explain:-$profile} (for login shells)"
echo "and $rc (for interactive shells) :"
fi
echo
echo 'export PYENV_ROOT="$HOME/.pyenv"'
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"'
echo 'eval "$(pyenv init -)"'
;;
esac
echo
echo '# Restart your shell for the changes to take effect.'
echo
} >&2
}
function init_dirs() {
mkdir -p "${PYENV_ROOT}/"{shims,versions}
}
function print_path() {
# if no_push_path is set, guard the PATH manipulation with a check on whether
# the shim is already in the PATH.
if [ -n "$no_push_path" ]; then
case "$shell" in
fish )
echo 'if not contains -- "'"${PYENV_ROOT}/shims"'" $PATH'
print_path_prepend_shims
echo 'end'
;;
* )
echo 'if [[ ":$PATH:" != *'\':"${PYENV_ROOT}"/shims:\''* ]]; then'
print_path_prepend_shims
echo 'fi'
;;
esac
else
case "$shell" in
fish )
echo 'while set pyenv_index (contains -i -- "'"${PYENV_ROOT}/shims"'" $PATH)'
echo 'set -eg PATH[$pyenv_index]; end; set -e pyenv_index'
print_path_prepend_shims
;;
* )
# Some distros (notably Debian-based) set Bash's SSH_SOURCE_BASHRC compilation option
# that makes it source `bashrc` under SSH even when not interactive.
# This is inhibited by a guard in Debian's stock `bashrc` but some people remove it
# in order to get proper environment for noninteractive remote commands
# (SSH provides /etc/ssh/sshrc and ~/.ssh/rc for that but no-one seems to use them for some reason).
# This has caused an infinite `bashrc` execution loop for those people in the below nested Bash invocation (#2367).
# --norc negates this behavior of such a customized Bash.
echo 'PATH="$(bash --norc -ec '\''IFS=:; paths=($PATH); '
echo 'for i in ${!paths[@]}; do '
echo 'if [[ ${paths[i]} == "'\'\'"${PYENV_ROOT}/shims"\'\''" ]]; then unset '\'\\\'\''paths[i]'\'\\\'\''; '
echo 'fi; done; '
echo 'echo "${paths[*]}"'\'')"'
print_path_prepend_shims
;;
esac
fi
}
function print_path_prepend_shims() {
case "$shell" in
fish )
echo 'set -gx PATH '\'"${PYENV_ROOT}/shims"\'' $PATH'
;;
* )
echo 'export PATH="'"${PYENV_ROOT}"'/shims:${PATH}"'
;;
esac
}
function print_env() {
case "$shell" in
fish )
echo "set -gx PYENV_SHELL $shell"
;;
* )
echo "export PYENV_SHELL=$shell"
;;
esac
}
function print_completion() {
completion="${root}/completions/pyenv.${shell}"
if [ -r "$completion" ]; then
echo "source '$completion'"
fi
}
function print_rehash() {
if [ -z "$no_rehash" ]; then
echo 'command pyenv rehash 2>/dev/null'
fi
}
function print_shell_function() {
commands=(`pyenv-commands --sh`)
case "$shell" in
fish )
cat <<EOS
function pyenv
set command \$argv[1]
set -e argv[1]
switch "\$command"
case ${commands[*]}
source (pyenv "sh-\$command" \$argv|psub)
case '*'
command pyenv "\$command" \$argv
end
end
EOS
;;
ksh )
cat <<EOS
function pyenv {
typeset command
EOS
;;
* )
cat <<EOS
pyenv() {
local command
EOS
;;
esac
if [ "$shell" != "fish" ]; then
IFS="|"
cat <<EOS
command="\${1:-}"
if [ "\$#" -gt 0 ]; then
shift
fi
case "\$command" in
${commands[*]})
eval "\$(pyenv "sh-\$command" "\$@")"
;;
*)
command pyenv "\$command" "\$@"
;;
esac
}
EOS
fi
}
main