pyenv verification source
Some checks are pending
macos_build / macos_build (3.10) (push) Waiting to run
macos_build / macos_build (3.11) (push) Waiting to run
macos_build / macos_build (3.12) (push) Waiting to run
macos_build / macos_build (3.13) (push) Waiting to run
macos_build / macos_build (3.14) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-14) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-15) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-15-intel) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-26) (push) Waiting to run
pyenv_tests / pyenv_tests (ubuntu-22.04) (push) Waiting to run
pyenv_tests / pyenv_tests (ubuntu-24.04) (push) Waiting to run
ubuntu_build / ubuntu_build (3.10) (push) Waiting to run
ubuntu_build / ubuntu_build (3.11) (push) Waiting to run
ubuntu_build / ubuntu_build (3.12) (push) Waiting to run
ubuntu_build / ubuntu_build (3.13) (push) Waiting to run
ubuntu_build / ubuntu_build (3.14) (push) Waiting to run
Some checks are pending
macos_build / macos_build (3.10) (push) Waiting to run
macos_build / macos_build (3.11) (push) Waiting to run
macos_build / macos_build (3.12) (push) Waiting to run
macos_build / macos_build (3.13) (push) Waiting to run
macos_build / macos_build (3.14) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-14) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-15) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-15-intel) (push) Waiting to run
pyenv_tests / pyenv_tests (macos-26) (push) Waiting to run
pyenv_tests / pyenv_tests (ubuntu-22.04) (push) Waiting to run
pyenv_tests / pyenv_tests (ubuntu-24.04) (push) Waiting to run
ubuntu_build / ubuntu_build (3.10) (push) Waiting to run
ubuntu_build / ubuntu_build (3.11) (push) Waiting to run
ubuntu_build / ubuntu_build (3.12) (push) Waiting to run
ubuntu_build / ubuntu_build (3.13) (push) Waiting to run
ubuntu_build / ubuntu_build (3.14) (push) Waiting to run
This commit is contained in:
145
libexec/pyenv
Executable file
145
libexec/pyenv
Executable file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
if [ "$1" = "--debug" ]; then
|
||||
export PYENV_DEBUG=1
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -n "$PYENV_DEBUG" ]; then
|
||||
# https://wiki-dev.bash-hackers.org/scripting/debuggingtips#making_xtrace_more_useful
|
||||
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||
set -x
|
||||
fi
|
||||
|
||||
abort() {
|
||||
{ if [ "$#" -eq 0 ]; then cat -
|
||||
else echo "pyenv: $*"
|
||||
fi
|
||||
} >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if enable -f "${BASH_SOURCE%/*}"/../libexec/pyenv-realpath.dylib realpath 2>/dev/null; then
|
||||
abs_dirname() {
|
||||
local path
|
||||
path="$(realpath "$1")"
|
||||
echo "${path%/*}"
|
||||
}
|
||||
else
|
||||
[ -z "$PYENV_NATIVE_EXT" ] || abort "failed to load \`realpath' builtin"
|
||||
|
||||
READLINK=$(type -P readlink)
|
||||
[ -n "$READLINK" ] || abort "cannot find readlink - are you missing GNU coreutils?"
|
||||
|
||||
resolve_link() {
|
||||
$READLINK "$1"
|
||||
}
|
||||
|
||||
abs_dirname() {
|
||||
local path="$1"
|
||||
|
||||
# Use a subshell to avoid changing the current path
|
||||
(
|
||||
while [ -n "$path" ]; do
|
||||
cd_path="${path%/*}"
|
||||
if [[ "$cd_path" != "$path" ]]; then
|
||||
cd "$cd_path"
|
||||
fi
|
||||
name="${path##*/}"
|
||||
path="$(resolve_link "$name" || true)"
|
||||
done
|
||||
|
||||
echo "$PWD"
|
||||
)
|
||||
}
|
||||
fi
|
||||
|
||||
if [ -z "${PYENV_ROOT}" ]; then
|
||||
PYENV_ROOT="${HOME}/.pyenv"
|
||||
else
|
||||
PYENV_ROOT="${PYENV_ROOT%/}"
|
||||
fi
|
||||
export PYENV_ROOT
|
||||
|
||||
if [ -z "${PYENV_DIR}" ]; then
|
||||
PYENV_DIR="$PWD"
|
||||
fi
|
||||
|
||||
if [ ! -d "$PYENV_DIR" ] || [ ! -e "$PYENV_DIR" ]; then
|
||||
abort "cannot change working directory to \`$PYENV_DIR'"
|
||||
fi
|
||||
|
||||
PYENV_DIR=$(cd "$PYENV_DIR" && echo "$PWD")
|
||||
export PYENV_DIR
|
||||
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
_PYENV_INSTALL_PREFIX="$(abs_dirname "$0")"
|
||||
_PYENV_INSTALL_PREFIX="${_PYENV_INSTALL_PREFIX%/*}"
|
||||
|
||||
export _PYENV_INSTALL_PREFIX
|
||||
|
||||
for plugin_bin in "${_PYENV_INSTALL_PREFIX}"/plugins/*/bin; do
|
||||
PATH="${plugin_bin}:${PATH}"
|
||||
done
|
||||
# PYENV_ROOT can be set to anything, so it may happen to be equal to the base path above,
|
||||
# resulting in duplicate PATH entries
|
||||
if [ "${_PYENV_INSTALL_PREFIX}" != "$PYENV_ROOT" ]; then
|
||||
for plugin_bin in "${PYENV_ROOT}"/plugins/*/bin; do
|
||||
PATH="${plugin_bin}:${PATH}"
|
||||
done
|
||||
fi
|
||||
export PATH="${_PYENV_INSTALL_PREFIX}/libexec:${PATH}"
|
||||
|
||||
PYENV_HOOK_PATH="${PYENV_HOOK_PATH}:${PYENV_ROOT}/pyenv.d"
|
||||
if [ "${_PYENV_INSTALL_PREFIX}" != "$PYENV_ROOT" ]; then
|
||||
# Add pyenv's own `pyenv.d` unless pyenv was cloned to PYENV_ROOT
|
||||
PYENV_HOOK_PATH="${PYENV_HOOK_PATH}:${_PYENV_INSTALL_PREFIX}/pyenv.d"
|
||||
fi
|
||||
PYENV_HOOK_PATH="${PYENV_HOOK_PATH}:/usr/etc/pyenv.d:/usr/local/etc/pyenv.d:/etc/pyenv.d:/usr/lib/pyenv/hooks"
|
||||
for plugin_hook in "${PYENV_ROOT}/plugins/"*/etc/pyenv.d; do
|
||||
PYENV_HOOK_PATH="${PYENV_HOOK_PATH}:${plugin_hook}"
|
||||
done
|
||||
PYENV_HOOK_PATH="${PYENV_HOOK_PATH#:}"
|
||||
export PYENV_HOOK_PATH
|
||||
|
||||
shopt -u nullglob
|
||||
|
||||
|
||||
command="$1"
|
||||
case "$command" in
|
||||
"" )
|
||||
{ pyenv---version
|
||||
pyenv-help
|
||||
} | abort
|
||||
;;
|
||||
-v | --version )
|
||||
exec pyenv---version
|
||||
;;
|
||||
-h | --help )
|
||||
exec pyenv-help
|
||||
;;
|
||||
* )
|
||||
command_path="$(command -v "pyenv-$command" || true)"
|
||||
if [ -z "$command_path" ]; then
|
||||
if [ "$command" == "shell" ]; then
|
||||
abort "shell integration not enabled. Run \`pyenv init' for instructions."
|
||||
else
|
||||
abort "no such command \`$command'"
|
||||
fi
|
||||
fi
|
||||
|
||||
shift 1
|
||||
if [ "$1" = --help ]; then
|
||||
if [[ "$command" == "sh-"* ]]; then
|
||||
echo "pyenv help \"$command\""
|
||||
else
|
||||
exec pyenv-help "$command"
|
||||
fi
|
||||
else
|
||||
exec "$command_path" "$@"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
23
libexec/pyenv---version
Executable file
23
libexec/pyenv---version
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Display the version of pyenv
|
||||
#
|
||||
# Displays the version number of this pyenv release, including the
|
||||
# current revision from git, if available.
|
||||
#
|
||||
# The format of the git revision is:
|
||||
# <version>-<num_commits>-<git_sha>
|
||||
# where `num_commits` is the number of commits since `version` was
|
||||
# tagged.
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
version="2.6.31"
|
||||
git_revision=""
|
||||
|
||||
if cd "${BASH_SOURCE%/*}" 2>/dev/null && git remote -v 2>/dev/null | grep -q pyenv; then
|
||||
git_revision="$(git describe --tags HEAD 2>/dev/null || true)"
|
||||
git_revision="${git_revision#v}"
|
||||
fi
|
||||
|
||||
echo "pyenv ${git_revision:-$version}"
|
||||
48
libexec/pyenv-commands
Executable file
48
libexec/pyenv-commands
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: List all available pyenv commands
|
||||
# Usage: pyenv commands [--sh|--no-sh]
|
||||
|
||||
set -e
|
||||
[[ -n $PYENV_DEBUG ]] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [[ $1 = "--complete" ]]; then
|
||||
echo --sh
|
||||
echo --no-sh
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ $1 = "--sh" ]]; then
|
||||
sh=1
|
||||
shift
|
||||
elif [[ $1 = "--no-sh" ]]; then
|
||||
nosh=1
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=: paths=($PATH)
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
{
|
||||
if [[ -n $sh ]]; then
|
||||
for path in "${paths[@]}"; do
|
||||
for command in "${path}"/pyenv-sh-*; do
|
||||
echo "${command##*/pyenv-sh-}"
|
||||
done
|
||||
done
|
||||
else
|
||||
for path in "${paths[@]}"; do
|
||||
for command in "${path}"/pyenv-*; do
|
||||
command="${command##*/pyenv-}"
|
||||
if [[ -n $nosh ]]; then
|
||||
if [[ ${command:0:3} != "sh-" ]]; then
|
||||
echo "$command"
|
||||
fi
|
||||
else
|
||||
echo "${command##sh-}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
} | sort -u
|
||||
26
libexec/pyenv-completions
Executable file
26
libexec/pyenv-completions
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# Usage: pyenv completions <command> [arg1 arg2...]
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
COMMAND="$1"
|
||||
if [ -z "$COMMAND" ]; then
|
||||
pyenv-help --usage completions >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$COMMAND" = "--complete" ]; then
|
||||
exec pyenv-commands
|
||||
fi
|
||||
|
||||
COMMAND_PATH="$(command -v "pyenv-$COMMAND" || command -v "pyenv-sh-$COMMAND")"
|
||||
|
||||
# --help is provided automatically
|
||||
echo --help
|
||||
|
||||
if grep -iE "^([#%]|--|//) provide pyenv completions" "$COMMAND_PATH" >/dev/null; then
|
||||
shift
|
||||
exec "$COMMAND_PATH" --complete "$@"
|
||||
fi
|
||||
57
libexec/pyenv-exec
Executable file
57
libexec/pyenv-exec
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Summary: Run an executable with the selected Python version
|
||||
#
|
||||
# Usage: pyenv exec <command> [arg1 arg2...]
|
||||
#
|
||||
# Runs an executable by first preparing PATH so that the selected Python
|
||||
# version's `bin' directory is at the front.
|
||||
#
|
||||
# For example, if the currently selected Python version is 2.7.6:
|
||||
# pyenv exec pip install -r requirements.txt
|
||||
#
|
||||
# is equivalent to:
|
||||
# PATH="$PYENV_ROOT/versions/2.7.6/bin:$PATH" pip install -r requirements.txt
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
exec pyenv-shims --short
|
||||
fi
|
||||
|
||||
PYENV_VERSION="$(pyenv-version-name -f)"
|
||||
PYENV_COMMAND="$1"
|
||||
|
||||
if [ -z "$PYENV_COMMAND" ]; then
|
||||
pyenv-help --usage exec >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n $_PYENV_SHIM_PATH ]]; then
|
||||
PROGRAM="$(echo "$PYENV_COMMAND" | tr a-z- A-Z_ | sed 's/[^A-Z0-9_]/_/g')"
|
||||
NR_PYENV_SHIM_PATHS_PROGRAM="_PYENV_SHIM_PATHS_${PROGRAM}"
|
||||
export -- "$NR_PYENV_SHIM_PATHS_PROGRAM=$_PYENV_SHIM_PATH${!NR_PYENV_SHIM_PATHS_PROGRAM:+:${!NR_PYENV_SHIM_PATHS_PROGRAM}}"
|
||||
unset PROGRAM NR_PYENV_SHIM_PATHS_PROGRAM
|
||||
unset _PYENV_SHIM_PATH
|
||||
fi
|
||||
|
||||
PYENV_COMMAND_PATH="$(pyenv-which "$PYENV_COMMAND")"
|
||||
PYENV_BIN_PATH="${PYENV_COMMAND_PATH%/*}"
|
||||
|
||||
export PYENV_VERSION
|
||||
|
||||
OLDIFS="$IFS"
|
||||
IFS=$'\n' scripts=(`pyenv-hooks exec`)
|
||||
IFS="$OLDIFS"
|
||||
for script in "${scripts[@]}"; do
|
||||
source "$script"
|
||||
done
|
||||
|
||||
shift 1
|
||||
if [ "${PYENV_BIN_PATH#${PYENV_ROOT}}" != "${PYENV_BIN_PATH}" ]; then
|
||||
# Only add to $PATH for non-system version.
|
||||
export PATH="${PYENV_BIN_PATH}:${PATH}"
|
||||
fi
|
||||
exec "$PYENV_COMMAND_PATH" "$@"
|
||||
49
libexec/pyenv-global
Executable file
49
libexec/pyenv-global
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Summary: Set or show the global Python version(s)
|
||||
#
|
||||
# Usage: pyenv global <version> <version2> <..>
|
||||
#
|
||||
# Sets the global Python version(s). You can override the global version at
|
||||
# any time by setting a directory-specific version with `pyenv local'
|
||||
# or by setting the `PYENV_VERSION' environment variable.
|
||||
#
|
||||
# <version> can be specified multiple times and should be a version
|
||||
# tag known to pyenv. The special version string `system' will use
|
||||
# your default system Python. Run `pyenv versions' for a list of
|
||||
# available Python versions.
|
||||
#
|
||||
# Example: To enable the python2.7 and python3.7 shims to find their
|
||||
# respective executables you could set both versions with:
|
||||
#
|
||||
# 'pyenv global 3.7.0 2.7.15'
|
||||
#
|
||||
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo system
|
||||
exec pyenv-versions --bare
|
||||
fi
|
||||
|
||||
versions=("$@")
|
||||
PYENV_VERSION_FILE="${PYENV_ROOT}/version"
|
||||
|
||||
if [ -n "$versions" ]; then
|
||||
pyenv-version-file-write "$PYENV_VERSION_FILE" "${versions[@]}"
|
||||
else
|
||||
OLDIFS="$IFS"
|
||||
IFS=: versions=($(
|
||||
pyenv-version-file-read "$PYENV_VERSION_FILE" ||
|
||||
pyenv-version-file-read "${PYENV_ROOT}/global" ||
|
||||
pyenv-version-file-read "${PYENV_ROOT}/default" ||
|
||||
echo system
|
||||
))
|
||||
IFS="$OLDIFS"
|
||||
for version in "${versions[@]}"; do
|
||||
echo "$version"
|
||||
done
|
||||
fi
|
||||
173
libexec/pyenv-help
Executable file
173
libexec/pyenv-help
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Summary: Display help for a command
|
||||
#
|
||||
# Usage: pyenv help [--usage] COMMAND
|
||||
#
|
||||
# Parses and displays help contents from a command's source file.
|
||||
#
|
||||
# A command is considered documented if it starts with a comment block
|
||||
# that has a `Summary:' or `Usage:' section. Usage instructions can
|
||||
# span multiple lines as long as subsequent lines are indented.
|
||||
# The remainder of the comment block is displayed as extended
|
||||
# documentation.
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo --usage
|
||||
exec pyenv-commands
|
||||
fi
|
||||
|
||||
command_path() {
|
||||
local command="$1"
|
||||
command -v pyenv-"$command" || command -v pyenv-sh-"$command" || true
|
||||
}
|
||||
|
||||
extract_initial_comment_block() {
|
||||
LC_ALL= \
|
||||
LC_CTYPE=C \
|
||||
sed -ne "
|
||||
/^#/ !{
|
||||
q
|
||||
}
|
||||
|
||||
s/^#$/# /
|
||||
|
||||
/^# / {
|
||||
s/^# //
|
||||
p
|
||||
}
|
||||
"
|
||||
}
|
||||
|
||||
collect_documentation() {
|
||||
# `tail` prevents "broken pipe" errors due to `head` closing the pipe without reading everything
|
||||
# https://superuser.com/questions/554855/how-can-i-fix-a-broken-pipe-error/642932#642932
|
||||
$(type -P gawk awk | tail -n +1 | head -n1) '
|
||||
/^Summary:/ {
|
||||
summary = substr($0, 10)
|
||||
next
|
||||
}
|
||||
|
||||
/^Usage:/ {
|
||||
reading_usage = 1
|
||||
usage = usage "\n" $0
|
||||
next
|
||||
}
|
||||
|
||||
/^( *$| )/ && reading_usage {
|
||||
usage = usage "\n" $0
|
||||
next
|
||||
}
|
||||
|
||||
{
|
||||
reading_usage = 0
|
||||
help = help "\n" $0
|
||||
}
|
||||
|
||||
function escape(str) {
|
||||
gsub(/[`\\$"]/, "\\\\&", str)
|
||||
return str
|
||||
}
|
||||
|
||||
function trim(str) {
|
||||
sub(/^\n*/, "", str)
|
||||
sub(/\n*$/, "", str)
|
||||
return str
|
||||
}
|
||||
|
||||
END {
|
||||
if (usage || summary) {
|
||||
print "summary=\"" escape(summary) "\""
|
||||
print "usage=\"" escape(trim(usage)) "\""
|
||||
print "help=\"" escape(trim(help)) "\""
|
||||
}
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
documentation_for() {
|
||||
local filename
|
||||
filename="$(command_path "$1")"
|
||||
if [ -n "$filename" ]; then
|
||||
extract_initial_comment_block < "$filename" | collect_documentation
|
||||
fi
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
local command="$1"
|
||||
local summary usage help
|
||||
eval "$(documentation_for "$command")"
|
||||
|
||||
if [ -n "$summary" ]; then
|
||||
printf " %-9s %s\n" "$command" "$summary"
|
||||
fi
|
||||
}
|
||||
|
||||
print_summaries() {
|
||||
for command; do
|
||||
print_summary "$command"
|
||||
done
|
||||
}
|
||||
|
||||
print_help() {
|
||||
local command="$1"
|
||||
local summary usage help
|
||||
eval "$(documentation_for "$command")"
|
||||
[ -n "$help" ] || help="$summary"
|
||||
|
||||
if [ -n "$usage" ] || [ -n "$summary" ]; then
|
||||
if [ -n "$usage" ]; then
|
||||
echo "$usage"
|
||||
else
|
||||
echo "Usage: pyenv ${command}"
|
||||
fi
|
||||
if [ -n "$help" ]; then
|
||||
echo
|
||||
echo "$help"
|
||||
echo
|
||||
fi
|
||||
else
|
||||
echo "Sorry, this command isn't documented yet." >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
print_usage() {
|
||||
local command="$1"
|
||||
local summary usage help
|
||||
eval "$(documentation_for "$command")"
|
||||
[ -z "$usage" ] || echo "$usage"
|
||||
}
|
||||
|
||||
unset usage
|
||||
if [ "$1" = "--usage" ]; then
|
||||
usage="1"
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -z "$1" ] || [ "$1" == "pyenv" ]; then
|
||||
echo "Usage: pyenv <command> [<args>]"
|
||||
[ -z "$usage" ] || exit
|
||||
echo
|
||||
echo "Some useful pyenv commands are:"
|
||||
print_summaries $(exec pyenv-commands | sort -u)
|
||||
echo
|
||||
echo "See \`pyenv help <command>' for information on a specific command."
|
||||
echo "For full documentation, see: https://github.com/pyenv/pyenv#readme"
|
||||
else
|
||||
command="$1"
|
||||
if [ -n "$(command_path "$command")" ]; then
|
||||
if [ -n "$usage" ]; then
|
||||
print_usage "$command"
|
||||
else
|
||||
print_help "$command"
|
||||
fi
|
||||
else
|
||||
echo "pyenv: no such command \`$command'" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
63
libexec/pyenv-hooks
Executable file
63
libexec/pyenv-hooks
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: List hook scripts for a given pyenv command
|
||||
# Usage: pyenv hooks <command>
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo exec
|
||||
echo rehash
|
||||
echo version-name
|
||||
echo version-origin
|
||||
echo which
|
||||
exit
|
||||
fi
|
||||
|
||||
PYENV_COMMAND="$1"
|
||||
if [ -z "$PYENV_COMMAND" ]; then
|
||||
pyenv-help --usage hooks >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! enable -f "${BASH_SOURCE%/*}"/pyenv-realpath.dylib realpath 2>/dev/null; then
|
||||
if [ -n "$PYENV_NATIVE_EXT" ]; then
|
||||
echo "pyenv: failed to load \`realpath' builtin" >&2
|
||||
exit 1
|
||||
fi
|
||||
READLINK=$(type -P readlink)
|
||||
if [ -z "$READLINK" ]; then
|
||||
echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
resolve_link() {
|
||||
$READLINK "$1"
|
||||
}
|
||||
|
||||
realpath() {
|
||||
local path="$1"
|
||||
local name
|
||||
# Use a subshell to avoid changing the current path
|
||||
(
|
||||
while [ -n "$path" ]; do
|
||||
name="${path##*/}"
|
||||
[ "$name" = "$path" ] || cd "${path%/*}"
|
||||
path="$(resolve_link "$name" || true)"
|
||||
done
|
||||
|
||||
echo "${PWD}/$name"
|
||||
)
|
||||
}
|
||||
fi
|
||||
|
||||
IFS=: hook_paths=($PYENV_HOOK_PATH)
|
||||
|
||||
shopt -s nullglob
|
||||
for path in "${hook_paths[@]}"; do
|
||||
for script in "$path/$PYENV_COMMAND"/*.bash; do
|
||||
realpath "$script"
|
||||
done
|
||||
done
|
||||
shopt -u nullglob
|
||||
363
libexec/pyenv-init
Executable file
363
libexec/pyenv-init
Executable file
@@ -0,0 +1,363 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Configure the shell environment for pyenv
|
||||
# Usage: eval "$(pyenv init [-|--path] [--no-push-path] [--detect-shell] [--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 --detect-shell
|
||||
echo bash
|
||||
echo fish
|
||||
echo ksh
|
||||
echo pwsh
|
||||
echo zsh
|
||||
exit
|
||||
fi
|
||||
|
||||
mode="help"
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
-)
|
||||
mode="print"
|
||||
;;
|
||||
--path)
|
||||
mode="path"
|
||||
;;
|
||||
--detect-shell)
|
||||
mode="detect-shell"
|
||||
;;
|
||||
--no-push-path)
|
||||
no_push_path=1
|
||||
;;
|
||||
--no-rehash)
|
||||
no_rehash=1
|
||||
;;
|
||||
*)
|
||||
shell="$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# If shell is not provided, detect it.
|
||||
if [ -z "$shell" ]; then
|
||||
if shell=$(tr '\0' ' ' 2>/dev/null </proc/"$PPID"/cmdline);then
|
||||
:
|
||||
else
|
||||
shell=$(ps p "$PPID" -o 'args=' 2>/dev/null || true)
|
||||
fi
|
||||
shell="${shell%% *}"
|
||||
shell="${shell##-}"
|
||||
shell="${shell:-$SHELL}"
|
||||
shell="${shell##*/}"
|
||||
shell="${shell%%-*}"
|
||||
fi
|
||||
|
||||
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
|
||||
;;
|
||||
"detect-shell")
|
||||
detect_profile 1
|
||||
print_detect_shell
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
# should never get here
|
||||
exit 2
|
||||
}
|
||||
|
||||
function detect_profile() {
|
||||
local detect_for_detect_shell="$1"
|
||||
|
||||
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'
|
||||
;;
|
||||
pwsh )
|
||||
profile='~/.config/powershell/profile.ps1'
|
||||
rc='~/.config/powershell/profile.ps1'
|
||||
;;
|
||||
zsh )
|
||||
profile='~/.zprofile'
|
||||
rc='~/.zshrc'
|
||||
;;
|
||||
ksh | ksh93 | mksh )
|
||||
# There are two implementations of Korn shell: AT&T (ksh93) and Mir (mksh).
|
||||
# Systems may have them installed under those names, or as ksh, so those
|
||||
# are recognized here. The obsolete ksh88 (subsumed by ksh93) and pdksh
|
||||
# (subsumed by mksh) are not included, since they are unlikely to still
|
||||
# be in use as interactive shells anywhere.
|
||||
profile='~/.profile'
|
||||
rc='~/.profile'
|
||||
;;
|
||||
* )
|
||||
if [ -n "$detect_for_detect_shell" ]; then
|
||||
profile=
|
||||
rc=
|
||||
else
|
||||
profile='your shell'\''s login startup file'
|
||||
rc='your shell'\''s interactive startup file'
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function print_detect_shell() {
|
||||
echo "PYENV_SHELL_DETECT=$shell"
|
||||
echo "PYENV_PROFILE_DETECT=$profile"
|
||||
echo "PYENV_RC_DETECT=$rc"
|
||||
}
|
||||
|
||||
function help_() {
|
||||
detect_profile
|
||||
{
|
||||
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 - fish | source'
|
||||
echo
|
||||
;;
|
||||
pwsh )
|
||||
echo '# Load pyenv automatically by appending'
|
||||
echo "# the following to $profile :"
|
||||
echo
|
||||
echo '$Env:PYENV_ROOT="$Env:HOME/.pyenv"'
|
||||
echo 'if (Test-Path -LP "$Env:PYENV_ROOT/bin" -PathType Container) {'
|
||||
echo ' $Env:PATH="$Env:PYENV_ROOT/bin:$Env:PATH" }'
|
||||
echo 'iex ((pyenv init -) -join "`n")'
|
||||
;;
|
||||
* )
|
||||
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 '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"'
|
||||
echo 'eval "$(pyenv init - '$shell')"'
|
||||
;;
|
||||
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'
|
||||
;;
|
||||
pwsh )
|
||||
echo 'if ( $Env:PATH -notmatch "'"${PYENV_ROOT}/shims"'" ) {'
|
||||
print_path_prepend_shims
|
||||
echo '}'
|
||||
;;
|
||||
* )
|
||||
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
|
||||
;;
|
||||
pwsh )
|
||||
echo '$Env:PATH="$(($Env:PATH -split '"':'"' | where { -not ($_ -match '"'${PYENV_ROOT}/shims'"') }) -join '"':'"')"'
|
||||
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'
|
||||
;;
|
||||
pwsh )
|
||||
echo '$Env:PATH="'"${PYENV_ROOT}"'/shims:$Env:PATH"'
|
||||
;;
|
||||
* )
|
||||
echo 'export PATH="'"${PYENV_ROOT}"'/shims:${PATH}"'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function print_env() {
|
||||
case "$shell" in
|
||||
fish )
|
||||
echo "set -gx PYENV_SHELL $shell"
|
||||
;;
|
||||
pwsh )
|
||||
echo '$Env:PYENV_SHELL="'"$shell"'"'
|
||||
;;
|
||||
* )
|
||||
echo "export PYENV_SHELL=$shell"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function print_completion() {
|
||||
completion="${_PYENV_INSTALL_PREFIX}/completions/pyenv.${shell}"
|
||||
if [ -r "$completion" ]; then
|
||||
case "$shell" in
|
||||
pwsh )
|
||||
echo "iex (gc $completion -Raw)"
|
||||
;;
|
||||
* )
|
||||
echo "source '$completion'"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
function print_rehash() {
|
||||
if [ -z "$no_rehash" ]; then
|
||||
case "$shell" in
|
||||
pwsh )
|
||||
echo '& pyenv rehash'
|
||||
;;
|
||||
* )
|
||||
echo 'command pyenv rehash'
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
function print_shell_function() {
|
||||
commands=(`pyenv-commands --sh`)
|
||||
case "$shell" in
|
||||
fish )
|
||||
echo \
|
||||
'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'
|
||||
;;
|
||||
pwsh )
|
||||
cat <<EOS
|
||||
function pyenv {
|
||||
\$command=""
|
||||
if ( \$args.Count -gt 0 ) {
|
||||
\$command, \$args = \$args
|
||||
}
|
||||
|
||||
if ( ("${commands[*]}" -split ' ') -contains \$command ) {
|
||||
\$shell_cmds = (& (get-command -commandtype application pyenv) sh-\$command \$args)
|
||||
if ( \$shell_cmds.Count -gt 0 ) {
|
||||
iex (\$shell_cmds -join "\`n")
|
||||
}
|
||||
} else {
|
||||
& (get-command -commandtype application pyenv) \$command \$args
|
||||
}
|
||||
}
|
||||
EOS
|
||||
;;
|
||||
ksh | ksh93 | mksh )
|
||||
echo \
|
||||
'function pyenv {
|
||||
typeset command=${1:-}'
|
||||
;;
|
||||
* )
|
||||
echo \
|
||||
'pyenv() {
|
||||
local command=${1:-}'
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$shell" != "fish" ] && [ "$shell" != "pwsh" ]; then
|
||||
IFS="|"
|
||||
echo \
|
||||
' [ "$#" -gt 0 ] && shift
|
||||
case "$command" in
|
||||
'"${commands[*]:-/}"')
|
||||
eval "$(pyenv "sh-$command" "$@")"
|
||||
;;
|
||||
*)
|
||||
command pyenv "$command" "$@"
|
||||
;;
|
||||
esac
|
||||
}'
|
||||
fi
|
||||
}
|
||||
|
||||
main
|
||||
105
libexec/pyenv-latest
Executable file
105
libexec/pyenv-latest
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Print the latest installed or known version with the given prefix
|
||||
# Usage: pyenv latest [-k|--known] <prefix>
|
||||
#
|
||||
# -k/--known Select from all known versions instead of installed
|
||||
# -b/--bypass (internal) On a resolution failure, do not print an error message
|
||||
# but rather print the argument unchanged
|
||||
# -f/--force (internal) Same as -b but also do not return a failure exit code
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case "$1" in
|
||||
-k|--known)
|
||||
FROM_KNOWN=1
|
||||
shift
|
||||
;;
|
||||
-b|--bypass)
|
||||
BYPASS=1
|
||||
shift
|
||||
;;
|
||||
-f|--force)
|
||||
FORCE=1
|
||||
BYPASS=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
prefix=$1
|
||||
exitcode=0
|
||||
|
||||
IFS=$'\n'
|
||||
|
||||
if [[ -z $FROM_KNOWN ]]; then
|
||||
if [[ -d $PYENV_ROOT/versions/$prefix ]]; then
|
||||
echo "$prefix"
|
||||
exit $exitcode;
|
||||
fi
|
||||
DEFINITION_CANDIDATES=( $(pyenv-versions --bare --skip-envs) )
|
||||
else
|
||||
DEFINITION_CANDIDATES=( $(python-build --definitions ) )
|
||||
fi
|
||||
|
||||
if printf '%s\n' "${DEFINITION_CANDIDATES[@]}" 2>/dev/null | grep -qxFe "$prefix"; then
|
||||
echo "$prefix"
|
||||
exit $exitcode;
|
||||
fi
|
||||
|
||||
suffix=""
|
||||
if [[ $prefix =~ ^(.*[0-9])t$ ]]; then
|
||||
suffix="t"
|
||||
prefix="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
|
||||
# https://stackoverflow.com/questions/11856054/is-there-an-easy-way-to-pass-a-raw-string-to-grep/63483807#63483807
|
||||
prefix_re="$(sed 's/[^\^]/[&]/g;s/[\^]/\\&/g' <<< "$prefix")"
|
||||
suffix_re="$(sed 's/[^\^]/[&]/g;s/[\^]/\\&/g' <<< "$suffix")"
|
||||
# FIXME: more reliable and readable would probably be to loop over them and transform in pure Bash
|
||||
DEFINITION_CANDIDATES=(\
|
||||
$(printf '%s\n' "${DEFINITION_CANDIDATES[@]}" | \
|
||||
grep -Ee "^$prefix_re[-.].*$suffix_re\$" || true))
|
||||
|
||||
DEFINITION_CANDIDATES=(\
|
||||
$(printf '%s\n' "${DEFINITION_CANDIDATES[@]}" | \
|
||||
sed -E -e '/-dev$/d' -e '/-src$/d' -e '/-latest$/d' -e '/(a|b|rc)[0-9]+$/d' \
|
||||
$(if [[ -z $suffix ]]; then echo "-e /[0-9]t\$/d"; fi)
|
||||
));
|
||||
|
||||
# Compose a sorting key, followed by | and original value
|
||||
DEFINITION_CANDIDATES=(\
|
||||
$(printf '%s\n' "${DEFINITION_CANDIDATES[@]}" | \
|
||||
awk \
|
||||
'{ if (match($0,"^[[:alnum:]]+-"))
|
||||
{ print substr($0,0,RLENGTH-1) "." substr($0,RLENGTH+1) "..|" $0; }
|
||||
else
|
||||
{ print $0 "...|" $0; }
|
||||
}'))
|
||||
DEFINITION_CANDIDATES=(\
|
||||
$(printf '%s\n' "${DEFINITION_CANDIDATES[@]}" \
|
||||
| sort -t. -k1,1r -k 2,2nr -k 3,3nr -k4,4nr \
|
||||
| cut -f2 -d $'|' \
|
||||
|| true))
|
||||
DEFINITION="${DEFINITION_CANDIDATES[0]}"
|
||||
|
||||
if [[ -n "$DEFINITION" ]]; then
|
||||
echo "$DEFINITION"
|
||||
else
|
||||
if [[ -z $BYPASS ]]; then
|
||||
echo "pyenv: no $([[ -z $FROM_KNOWN ]] && echo installed || echo known) versions match the prefix \`$prefix'" >&2
|
||||
else
|
||||
echo "$prefix"
|
||||
fi
|
||||
if [[ -z $FORCE ]]; then
|
||||
exitcode=1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit $exitcode
|
||||
70
libexec/pyenv-local
Executable file
70
libexec/pyenv-local
Executable file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Summary: Set or show the local application-specific Python version(s)
|
||||
#
|
||||
# Usage: pyenv local [-f|--force] [<version> [...]]
|
||||
# pyenv local --unset
|
||||
#
|
||||
# -f/--force Do not verify that the versions being set exist
|
||||
#
|
||||
# Sets the local application-specific Python version(s) by writing the
|
||||
# version name to a file named `.python-version'.
|
||||
#
|
||||
# When you run a Python command, pyenv will look for a `.python-version'
|
||||
# file in the current directory and each parent directory. If no such
|
||||
# file is found in the tree, pyenv will use the global Python version
|
||||
# specified with `pyenv global'. A version specified with the
|
||||
# `PYENV_VERSION' environment variable takes precedence over local
|
||||
# and global versions.
|
||||
#
|
||||
# <version> can be specified multiple times and should be a version
|
||||
# tag known to pyenv. The special version string `system' will use
|
||||
# your default system Python. Run `pyenv versions' for a list of
|
||||
# available Python versions.
|
||||
#
|
||||
# Example: To enable the python2.7 and python3.7 shims to find their
|
||||
# respective executables you could set both versions with:
|
||||
#
|
||||
# 'pyenv local 3.7.0 2.7.15'
|
||||
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo --unset
|
||||
echo system
|
||||
exec pyenv-versions --bare
|
||||
fi
|
||||
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case "$1" in
|
||||
-f|--force)
|
||||
FORCE=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
versions=("$@")
|
||||
|
||||
if [ "$versions" = "--unset" ]; then
|
||||
rm -f .python-version
|
||||
elif [ -n "$versions" ]; then
|
||||
pyenv-version-file-write ${FORCE:+-f }.python-version "${versions[@]}"
|
||||
else
|
||||
if version_file="$(pyenv-version-file "$PWD")"; then
|
||||
IFS=: versions=($(pyenv-version-file-read "$version_file"))
|
||||
for version in "${versions[@]}"; do
|
||||
echo "$version"
|
||||
done
|
||||
else
|
||||
echo "pyenv: no local version configured for this directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
62
libexec/pyenv-prefix
Executable file
62
libexec/pyenv-prefix
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Display prefixes for Python versions
|
||||
# Usage: pyenv prefix [<version>...]
|
||||
#
|
||||
# Displays the directories where the given Python versions are installed,
|
||||
# separated by colons. If no version is given, `pyenv prefix' displays the
|
||||
# locations of the currently selected versions.
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo system
|
||||
exec pyenv-versions --bare
|
||||
fi
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
OLDIFS="$IFS"
|
||||
{ IFS=:
|
||||
export PYENV_VERSION="$*"
|
||||
}
|
||||
IFS="$OLDIFS"
|
||||
elif [ -z "$PYENV_VERSION" ]; then
|
||||
PYENV_VERSION="$(pyenv-version-name)"
|
||||
fi
|
||||
|
||||
PYENV_PREFIX_PATHS=()
|
||||
OLDIFS="$IFS"
|
||||
{ IFS=:
|
||||
for version in ${PYENV_VERSION}; do
|
||||
if [ "$version" = "system" ]; then
|
||||
if PYTHON_PATH="$(PYENV_VERSION="${version}" pyenv-which python --skip-advice 2>/dev/null)" || \
|
||||
PYTHON_PATH="$(PYENV_VERSION="${version}" pyenv-which python3 --skip-advice 2>/dev/null)" || \
|
||||
PYTHON_PATH="$(PYENV_VERSION="${version}" pyenv-which python2 --skip-advice 2>/dev/null)"; then
|
||||
shopt -s extglob
|
||||
# In some distros (Arch), Python can be found in sbin as well as bin
|
||||
PYENV_PREFIX_PATH="${PYTHON_PATH%/?(s)bin/*}"
|
||||
PYENV_PREFIX_PATH="${PYENV_PREFIX_PATH:-/}"
|
||||
else
|
||||
echo "pyenv: system version not found in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
version="$(pyenv-latest -f "$version")"
|
||||
PYENV_PREFIX_PATH="${PYENV_ROOT}/versions/${version}"
|
||||
fi
|
||||
if [ -d "$PYENV_PREFIX_PATH" ]; then
|
||||
PYENV_PREFIX_PATHS=("${PYENV_PREFIX_PATHS[@]}" "$PYENV_PREFIX_PATH")
|
||||
else
|
||||
echo "pyenv: version \`${version}' not installed" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
IFS="$OLDIFS"
|
||||
|
||||
OLDIFS="$IFS"
|
||||
{ IFS=:
|
||||
echo "${PYENV_PREFIX_PATHS[*]}"
|
||||
}
|
||||
IFS="$OLDIFS"
|
||||
201
libexec/pyenv-rehash
Executable file
201
libexec/pyenv-rehash
Executable file
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Rehash pyenv shims (run this after installing executables)
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
SHIM_PATH="${PYENV_ROOT}/shims"
|
||||
PROTOTYPE_SHIM_PATH="${SHIM_PATH}/.pyenv-shim"
|
||||
|
||||
# Create the shims directory if it doesn't already exist.
|
||||
mkdir -p "$SHIM_PATH"
|
||||
|
||||
declare last_acquire_error
|
||||
|
||||
acquire_lock() {
|
||||
# Ensure only one instance of pyenv-rehash is running at a time by
|
||||
# setting the shell's `noclobber` option and attempting to write to
|
||||
# the prototype shim file. If the file already exists, print a warning
|
||||
# to stderr and exit with a non-zero status.
|
||||
local ret
|
||||
set -o noclobber
|
||||
last_acquire_error="$( { ( echo -n > "$PROTOTYPE_SHIM_PATH"; ) 2>&1 1>&3 3>&1-; } 3>&1)" || ret=1
|
||||
set +o noclobber
|
||||
[ -z "${ret}" ]
|
||||
}
|
||||
|
||||
remove_prototype_shim() {
|
||||
rm -f "$PROTOTYPE_SHIM_PATH"
|
||||
}
|
||||
|
||||
release_lock() {
|
||||
remove_prototype_shim
|
||||
}
|
||||
|
||||
if [ ! -w "$SHIM_PATH" ]; then
|
||||
echo "pyenv: cannot rehash: $SHIM_PATH isn't writable" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
declare acquired tested_for_other_write_errors
|
||||
declare start=$SECONDS
|
||||
PYENV_REHASH_TIMEOUT=${PYENV_REHASH_TIMEOUT:-60}
|
||||
while (( SECONDS <= start + PYENV_REHASH_TIMEOUT )); do
|
||||
if acquire_lock; then
|
||||
acquired=1
|
||||
|
||||
# If we were able to obtain a lock, register a trap to clean up the
|
||||
# prototype shim when the process exits.
|
||||
trap release_lock EXIT
|
||||
|
||||
break
|
||||
else
|
||||
#Landlock sandbox subsystem in the Linux kernel returns false information in access() as of 6.14.0,
|
||||
# making -w "$SHIM_PATH" not catch the fact that the shims dir is not writable in this case.
|
||||
#Bash doesn't provide access to errno to check for non-EEXIST error code in acquire_lock.
|
||||
#So check for writablity by trying to write to a different file,
|
||||
# in a way that taxes the usual use case as little as possible.
|
||||
if [[ -z $tested_for_other_write_errors ]]; then
|
||||
( t="$(TMPDIR="$SHIM_PATH" mktemp)" && rm "$t" ) && tested_for_other_write_errors=1 ||
|
||||
{ echo "pyenv: cannot rehash: $SHIM_PATH isn't writable" >&2; break; }
|
||||
fi
|
||||
# POSIX sleep(1) doesn't provide subsecond precision, but many others do
|
||||
sleep 0.1 2>/dev/null || sleep 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "${acquired}" ]; then
|
||||
if [[ -n $tested_for_other_write_errors ]]; then
|
||||
echo "pyenv: cannot rehash: couldn't acquire lock"\
|
||||
"$PROTOTYPE_SHIM_PATH for $PYENV_REHASH_TIMEOUT seconds. Last error message:" >&2
|
||||
echo "$last_acquire_error" >&2
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
unset tested_for_other_write_errors
|
||||
|
||||
# The prototype shim file is a script that re-execs itself, passing
|
||||
# its filename and any arguments to `pyenv exec`. This file is
|
||||
# hard-linked for every executable and then removed. The linking
|
||||
# technique is fast, uses less disk space than unique files, and also
|
||||
# serves as a locking mechanism.
|
||||
create_prototype_shim() {
|
||||
cat > "$PROTOTYPE_SHIM_PATH" <<SH
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
[ -n "\$PYENV_DEBUG" ] && set -x
|
||||
|
||||
program="\${0##*/}"
|
||||
|
||||
export PYENV_ROOT="$PYENV_ROOT"
|
||||
SHIM_PATH=\${0%/*}
|
||||
if [[ \$SHIM_PATH != "$PYENV_ROOT/shims" ]]; then
|
||||
export _PYENV_SHIM_PATH="\$SHIM_PATH"
|
||||
fi
|
||||
exec "$(command -v pyenv)" exec "\$program" "\$@"
|
||||
SH
|
||||
chmod +x "$PROTOTYPE_SHIM_PATH"
|
||||
}
|
||||
|
||||
# If the contents of the prototype shim file differ from the contents
|
||||
# of the first shim in the shims directory, assume pyenv has been
|
||||
# upgraded and the existing shims need to be removed.
|
||||
remove_outdated_shims() {
|
||||
local shim
|
||||
for shim in "$SHIM_PATH"/*; do
|
||||
if ! diff "$PROTOTYPE_SHIM_PATH" "$shim" >/dev/null 2>&1; then
|
||||
rm -f "$SHIM_PATH"/*
|
||||
fi
|
||||
break
|
||||
done
|
||||
}
|
||||
|
||||
# The basename of each argument passed to `make_shims` will be
|
||||
# registered for installation as a shim. In this way, plugins may call
|
||||
# `make_shims` with a glob to register many shims at once.
|
||||
make_shims() {
|
||||
local file shim
|
||||
for file; do
|
||||
shim="${file##*/}"
|
||||
register_shim "$shim"
|
||||
done
|
||||
}
|
||||
|
||||
if ((${BASH_VERSINFO[0]} > 3)); then
|
||||
|
||||
declare -A registered_shims
|
||||
|
||||
# Registers the name of a shim to be generated.
|
||||
register_shim() {
|
||||
registered_shims["$1"]=1
|
||||
}
|
||||
|
||||
# Install all shims registered via `make_shims` or `register_shim` directly.
|
||||
install_registered_shims() {
|
||||
local shim file
|
||||
for shim in "${!registered_shims[@]}"; do
|
||||
file="${SHIM_PATH}/${shim}"
|
||||
[ -e "$file" ] || cp "$PROTOTYPE_SHIM_PATH" "$file"
|
||||
done
|
||||
}
|
||||
|
||||
# Once the registered shims have been installed, we make a second pass
|
||||
# over the contents of the shims directory. Any file that is present
|
||||
# in the directory but has not been registered as a shim should be
|
||||
# removed.
|
||||
remove_stale_shims() {
|
||||
local shim
|
||||
for shim in "$SHIM_PATH"/*; do
|
||||
if [[ ! ${registered_shims["${shim##*/}"]} ]]; then
|
||||
rm -f "$shim"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
else # Same for bash < 4.
|
||||
|
||||
registered_shims=" "
|
||||
|
||||
register_shim() {
|
||||
registered_shims="${registered_shims}${1} "
|
||||
}
|
||||
|
||||
install_registered_shims() {
|
||||
local shim file
|
||||
for shim in $registered_shims; do
|
||||
file="${SHIM_PATH}/${shim}"
|
||||
[ -e "$file" ] || cp "$PROTOTYPE_SHIM_PATH" "$file"
|
||||
done
|
||||
}
|
||||
|
||||
remove_stale_shims() {
|
||||
local shim
|
||||
for shim in "$SHIM_PATH"/*; do
|
||||
if [[ "$registered_shims" != *" ${shim##*/} "* ]]; then
|
||||
rm -f "$shim"
|
||||
fi
|
||||
done
|
||||
}
|
||||
fi
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
# Create the prototype shim, then register shims for all known
|
||||
# executables.
|
||||
create_prototype_shim
|
||||
remove_outdated_shims
|
||||
# shellcheck disable=SC2046
|
||||
make_shims $(pyenv-versions --executables)
|
||||
|
||||
|
||||
# Allow plugins to register shims.
|
||||
OLDIFS="$IFS"
|
||||
IFS=$'\n' scripts=(`pyenv-hooks rehash`)
|
||||
IFS="$OLDIFS"
|
||||
|
||||
for script in "${scripts[@]}"; do
|
||||
source "$script"
|
||||
done
|
||||
|
||||
install_registered_shims
|
||||
remove_stale_shims
|
||||
3
libexec/pyenv-root
Executable file
3
libexec/pyenv-root
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Display the root directory where versions and shims are kept
|
||||
echo "$PYENV_ROOT"
|
||||
29
libexec/pyenv-sh-rehash
Executable file
29
libexec/pyenv-sh-rehash
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
exec pyenv-rehash --complete
|
||||
fi
|
||||
|
||||
shell="$(basename "${PYENV_SHELL:-$SHELL}")"
|
||||
|
||||
# When pyenv shell integration is enabled, delegate to pyenv-rehash,
|
||||
# then tell the shell to empty its command lookup cache.
|
||||
case "$shell" in
|
||||
pwsh)
|
||||
echo "& (get-command pyenv -commandtype application) rehash"
|
||||
;;
|
||||
*)
|
||||
echo "command pyenv rehash"
|
||||
esac
|
||||
|
||||
case "$shell" in
|
||||
fish | pwsh )
|
||||
# no executable cache
|
||||
;;
|
||||
* )
|
||||
echo "hash -r 2>/dev/null || true"
|
||||
;;
|
||||
esac
|
||||
137
libexec/pyenv-sh-shell
Executable file
137
libexec/pyenv-sh-shell
Executable file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Summary: Set or show the shell-specific Python version
|
||||
#
|
||||
# Usage: pyenv shell <version>...
|
||||
# pyenv shell -
|
||||
# pyenv shell --unset
|
||||
#
|
||||
# Sets a shell-specific Python version by setting the `PYENV_VERSION'
|
||||
# environment variable in your shell. This version overrides local
|
||||
# application-specific versions and the global version.
|
||||
#
|
||||
# <version> should be a string matching a Python version known to pyenv.
|
||||
# The special version string `system' will use your default system Python.
|
||||
# Run `pyenv versions' for a list of available Python versions.
|
||||
#
|
||||
# When `-` is passed instead of the version string, the previously set
|
||||
# version will be restored. With `--unset`, the `PYENV_VERSION`
|
||||
# environment variable gets unset, restoring the environment to the
|
||||
# state before the first `pyenv shell` call.
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo --unset
|
||||
echo system
|
||||
exec pyenv-versions --bare
|
||||
fi
|
||||
|
||||
versions=("$@")
|
||||
shell="$(basename "${PYENV_SHELL:-$SHELL}")"
|
||||
|
||||
if [ -z "$versions" ]; then
|
||||
if [ -z "$PYENV_VERSION" ]; then
|
||||
echo "pyenv: no shell-specific version configured" >&2
|
||||
exit 1
|
||||
else
|
||||
echo 'echo "$PYENV_VERSION"'
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$versions" = "--unset" ]; then
|
||||
case "$shell" in
|
||||
fish )
|
||||
echo 'set -gu PYENV_VERSION_OLD "$PYENV_VERSION"'
|
||||
echo "set -e PYENV_VERSION"
|
||||
;;
|
||||
pwsh )
|
||||
echo '$Env:PYENV_VERSION, $Env:PYENV_VERSION_OLD = $null, $Env:PYENV_VERSION'
|
||||
;;
|
||||
* )
|
||||
echo 'PYENV_VERSION_OLD="${PYENV_VERSION-}"'
|
||||
echo "unset PYENV_VERSION"
|
||||
;;
|
||||
esac
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ "$versions" = "-" ]; then
|
||||
case "$shell" in
|
||||
fish )
|
||||
cat <<EOS
|
||||
if set -q PYENV_VERSION_OLD
|
||||
if [ -n "\$PYENV_VERSION_OLD" ]
|
||||
set PYENV_VERSION_OLD_ "\$PYENV_VERSION"
|
||||
set -gx PYENV_VERSION "\$PYENV_VERSION_OLD"
|
||||
set -gu PYENV_VERSION_OLD "\$PYENV_VERSION_OLD_"
|
||||
set -e PYENV_VERSION_OLD_
|
||||
else
|
||||
set -gu PYENV_VERSION_OLD "\$PYENV_VERSION"
|
||||
set -e PYENV_VERSION
|
||||
end
|
||||
else
|
||||
echo "pyenv: PYENV_VERSION_OLD is not set" >&2
|
||||
false
|
||||
end
|
||||
EOS
|
||||
;;
|
||||
pwsh )
|
||||
cat <<EOS
|
||||
if ( Get-Item -Path Env:\PYENV_VERSION* ) {
|
||||
\$Env:PYENV_VERSION, \$Env:PYENV_VERSION_OLD = \$Env:PYENV_VERSION_OLD, \$Env:PYENV_VERSION
|
||||
} else {
|
||||
Write-Error "pyenv: Env:PYENV_VERSION_OLD is not set"
|
||||
return \$false
|
||||
}
|
||||
EOS
|
||||
;;
|
||||
* )
|
||||
cat <<EOS
|
||||
if [ -n "\${PYENV_VERSION_OLD+x}" ]; then
|
||||
if [ -n "\$PYENV_VERSION_OLD" ]; then
|
||||
PYENV_VERSION_OLD_="\$PYENV_VERSION"
|
||||
export PYENV_VERSION="\$PYENV_VERSION_OLD"
|
||||
PYENV_VERSION_OLD="\$PYENV_VERSION_OLD_"
|
||||
unset PYENV_VERSION_OLD_
|
||||
else
|
||||
PYENV_VERSION_OLD="\$PYENV_VERSION"
|
||||
unset PYENV_VERSION
|
||||
fi
|
||||
else
|
||||
echo "pyenv: PYENV_VERSION_OLD is not set" >&2
|
||||
false
|
||||
fi
|
||||
EOS
|
||||
;;
|
||||
esac
|
||||
exit
|
||||
fi
|
||||
|
||||
# Make sure the specified version is installed.
|
||||
if pyenv-prefix "${versions[@]}" >/dev/null; then
|
||||
OLDIFS="$IFS"
|
||||
IFS=: version="${versions[*]}"
|
||||
IFS="$OLDIFS"
|
||||
if [ "$version" != "$PYENV_VERSION" ]; then
|
||||
case "$shell" in
|
||||
fish )
|
||||
echo 'set -gu PYENV_VERSION_OLD "$PYENV_VERSION"'
|
||||
echo "set -gx PYENV_VERSION \"$version\""
|
||||
;;
|
||||
pwsh )
|
||||
echo '$Env:PYENV_VERSION, $Env:PYENV_VERSION_OLD = "'"${version}"'", $Env:PYENV_VERSION'
|
||||
;;
|
||||
* )
|
||||
echo 'PYENV_VERSION_OLD="${PYENV_VERSION-}"'
|
||||
echo "export PYENV_VERSION=\"${version}\""
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
echo "false"
|
||||
exit 1
|
||||
fi
|
||||
22
libexec/pyenv-shims
Executable file
22
libexec/pyenv-shims
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: List existing pyenv shims
|
||||
# Usage: pyenv shims [--short]
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo --short
|
||||
exit
|
||||
fi
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
for command in "${PYENV_ROOT}/shims/"*; do
|
||||
if [ "$1" = "--short" ]; then
|
||||
echo "${command##*/}"
|
||||
else
|
||||
echo "$command"
|
||||
fi
|
||||
done | sort
|
||||
36
libexec/pyenv-version
Executable file
36
libexec/pyenv-version
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Show the current Python version(s) and its origin
|
||||
# Usage: pyenv version [--bare]
|
||||
#
|
||||
# --bare show just the version name. An alias to `pyenv version-name'
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
exitcode=0
|
||||
OLDIFS="$IFS"
|
||||
IFS=: PYENV_VERSION_NAMES=($(pyenv-version-name)) || exitcode=$?
|
||||
IFS="$OLDIFS"
|
||||
|
||||
unset bare
|
||||
for arg; do
|
||||
case "$arg" in
|
||||
--complete )
|
||||
echo --bare
|
||||
exit ;;
|
||||
--bare ) bare=1 ;;
|
||||
* )
|
||||
pyenv-help --usage version >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
for PYENV_VERSION_NAME in "${PYENV_VERSION_NAMES[@]}"; do
|
||||
if [[ -n $bare ]]; then
|
||||
echo "$PYENV_VERSION_NAME"
|
||||
else
|
||||
echo "$PYENV_VERSION_NAME (set by $(pyenv-version-origin))"
|
||||
fi
|
||||
done
|
||||
|
||||
exit $exitcode
|
||||
28
libexec/pyenv-version-file
Executable file
28
libexec/pyenv-version-file
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
# Usage: pyenv version-file [<dir>]
|
||||
# Summary: Detect the file that sets the current pyenv version
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
target_dir="$1"
|
||||
|
||||
find_local_version_file() {
|
||||
local root="$1"
|
||||
while ! [[ "$root" =~ ^//[^/]*$ ]]; do
|
||||
if [ -f "${root}/.python-version" ]; then
|
||||
echo "${root}/.python-version"
|
||||
return 0
|
||||
fi
|
||||
[ -n "$root" ] || break
|
||||
root="${root%/*}"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ -n "$target_dir" ]; then
|
||||
find_local_version_file "$target_dir"
|
||||
else
|
||||
find_local_version_file "$PYENV_DIR" || {
|
||||
[ "$PYENV_DIR" != "$PWD" ] && find_local_version_file "$PWD"
|
||||
} || echo "${PYENV_ROOT}/version"
|
||||
fi
|
||||
43
libexec/pyenv-version-file-read
Executable file
43
libexec/pyenv-version-file-read
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# Usage: pyenv version-file-read <file>
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
VERSION_FILE="$1"
|
||||
|
||||
function is_version_safe() {
|
||||
# As needed, check that the constructed path exists as a child path of PYENV_ROOT/versions
|
||||
version="$1"
|
||||
if [[ "$version" == ".." || "$version" == */* ]]; then
|
||||
# Sanity check the value of version to prevent malicious path-traversal
|
||||
(
|
||||
cd "$PYENV_ROOT/versions/$version" &>/dev/null || exit 1
|
||||
[[ "$PWD" == "$PYENV_ROOT/versions/"* ]]
|
||||
)
|
||||
return $?
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -s "$VERSION_FILE" ]; then
|
||||
# Read the first non-whitespace word from the specified version file.
|
||||
# Be careful not to load it whole in case there's something crazy in it.
|
||||
IFS="$IFS"$'\r'
|
||||
sep=
|
||||
while read -n 1024 -r version _ || [[ $version ]]; do
|
||||
if [[ -z "$version" || "$version" == \#* ]]; then
|
||||
# Skip empty lines and comments
|
||||
continue
|
||||
elif ! is_version_safe "$version"; then
|
||||
# CVE-2022-35861 allowed arbitrary code execution in some contexts and is mitigated by is_version_safe.
|
||||
echo "pyenv: invalid version \`$version' ignored in \`$VERSION_FILE'" >&2
|
||||
continue
|
||||
fi
|
||||
printf "%s%s" "$sep" "$version"
|
||||
sep=:
|
||||
done <"$VERSION_FILE"
|
||||
[[ $sep ]] && { echo; exit; }
|
||||
fi
|
||||
|
||||
exit 1
|
||||
40
libexec/pyenv-version-file-write
Executable file
40
libexec/pyenv-version-file-write
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
# Usage: pyenv version-file-write [-f|--force] <file> <version> [...]
|
||||
#
|
||||
# -f/--force Don't verify that the versions exist
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case "$1" in
|
||||
-f|--force)
|
||||
FORCE=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
PYENV_VERSION_FILE="$1"
|
||||
shift || true
|
||||
versions=("$@")
|
||||
|
||||
if [ -z "$versions" ] || [ -z "$PYENV_VERSION_FILE" ]; then
|
||||
pyenv-help --usage version-file-write >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure the specified version is installed.
|
||||
[[ -z $FORCE ]] && pyenv-prefix "${versions[@]}" >/dev/null
|
||||
|
||||
# Write the version out to disk.
|
||||
# Create an empty file. Using "rm" might cause a permission error.
|
||||
> "$PYENV_VERSION_FILE"
|
||||
for version in "${versions[@]}"; do
|
||||
echo "$version" >> "$PYENV_VERSION_FILE"
|
||||
done
|
||||
80
libexec/pyenv-version-name
Executable file
80
libexec/pyenv-version-name
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Show the current Python version
|
||||
#
|
||||
# -f/--force (Internal) If a version doesn't exist, print it as is rather than produce an error
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case "$1" in
|
||||
-f|--force)
|
||||
FORCE=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
if [ -z "$PYENV_VERSION" ]; then
|
||||
PYENV_VERSION_FILE="$(pyenv-version-file)"
|
||||
PYENV_VERSION="$(pyenv-version-file-read "$PYENV_VERSION_FILE" || true)"
|
||||
fi
|
||||
|
||||
OLDIFS="$IFS"
|
||||
IFS=$'\n' scripts=(`pyenv-hooks version-name`)
|
||||
IFS="$OLDIFS"
|
||||
for script in "${scripts[@]}"; do
|
||||
source "$script"
|
||||
done
|
||||
|
||||
if [ -z "$PYENV_VERSION" ] || [ "$PYENV_VERSION" = "system" ]; then
|
||||
echo "system"
|
||||
exit
|
||||
fi
|
||||
|
||||
version_exists() {
|
||||
local version="$1"
|
||||
[ -d "${PYENV_ROOT}/versions/${version}" ]
|
||||
}
|
||||
|
||||
versions=()
|
||||
OLDIFS="$IFS"
|
||||
{ IFS=:
|
||||
any_not_installed=0
|
||||
for version in ${PYENV_VERSION}; do
|
||||
# Remove the explicit 'python-' prefix from versions like 'python-3.12'.
|
||||
normalised_version="${version#python-}"
|
||||
if version_exists "${version}" || [ "$version" = "system" ]; then
|
||||
versions+=("${version}")
|
||||
elif version_exists "${normalised_version}"; then
|
||||
versions+=("${normalised_version}")
|
||||
elif resolved_version="$(pyenv-latest -b "${version}")"; then
|
||||
versions+=("${resolved_version}")
|
||||
elif resolved_version="$(pyenv-latest -b "${normalised_version}")"; then
|
||||
versions+=("${resolved_version}")
|
||||
else
|
||||
if [[ -n $FORCE ]]; then
|
||||
versions+=("${normalised_version}")
|
||||
else
|
||||
echo "pyenv: version \`$version' is not installed (set by $(pyenv-version-origin))" >&2
|
||||
any_not_installed=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
IFS="$OLDIFS"
|
||||
|
||||
OLDIFS="$IFS"
|
||||
{ IFS=:
|
||||
echo "${versions[*]}"
|
||||
}
|
||||
IFS="$OLDIFS"
|
||||
|
||||
if [ "$any_not_installed" = 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
21
libexec/pyenv-version-origin
Executable file
21
libexec/pyenv-version-origin
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: Explain how the current Python version is set
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
unset PYENV_VERSION_ORIGIN
|
||||
|
||||
OLDIFS="$IFS"
|
||||
IFS=$'\n' scripts=(`pyenv-hooks version-origin`)
|
||||
IFS="$OLDIFS"
|
||||
for script in "${scripts[@]}"; do
|
||||
source "$script"
|
||||
done
|
||||
|
||||
if [ -n "$PYENV_VERSION_ORIGIN" ]; then
|
||||
echo "$PYENV_VERSION_ORIGIN"
|
||||
elif [ -n "$PYENV_VERSION" ]; then
|
||||
echo "PYENV_VERSION environment variable"
|
||||
else
|
||||
pyenv-version-file
|
||||
fi
|
||||
195
libexec/pyenv-versions
Executable file
195
libexec/pyenv-versions
Executable file
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: List all Python versions available to pyenv
|
||||
# Usage: pyenv versions [--bare] [--skip-aliases] [--skip-envs] [--executables]
|
||||
#
|
||||
# Lists all Python versions found in `$PYENV_ROOT/versions/*'.
|
||||
#
|
||||
# --bare List just the names, omit `system'
|
||||
# --skip-aliases Skip symlinks to other versions and to virtual environments
|
||||
# --skip-envs Skip virtual environments (under <version>/envs)
|
||||
# --executables Internal. Overrides other options.
|
||||
# Optimally get a deduplicated list of all executable names in Pyenv-managed
|
||||
# versions and environments for `pyenv rehash'
|
||||
#
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
unset bare skip_aliases skip_envs executables
|
||||
# Provide pyenv completions
|
||||
for arg; do
|
||||
case "$arg" in
|
||||
--complete )
|
||||
echo --bare
|
||||
echo --skip-aliases
|
||||
echo --skip-envs
|
||||
exit ;;
|
||||
--executables ) executables=1; break ;;
|
||||
--bare ) bare=1 ;;
|
||||
--skip-aliases ) skip_aliases=1 ;;
|
||||
--skip-envs ) skip_envs=1 ;;
|
||||
* )
|
||||
pyenv-help --usage versions >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
versions_dir="${PYENV_ROOT}/versions"
|
||||
|
||||
# Fast path for rehash: skip filtering and link resolution
|
||||
if [[ -n "$executables" ]]; then
|
||||
if [ -d "$versions_dir" ]; then
|
||||
shopt -s dotglob nullglob
|
||||
# MacOS 12+ and FreeBSD 15 support `xargs -r -0' and `basename -a'
|
||||
# `sort -u` is simpler and a bit faster than `awk '!seen[$0]++'`, with the same result for rehash purposes
|
||||
printf '%s\0' "$versions_dir"/*/bin/* "$versions_dir"/*/envs/*/bin/* | xargs -0 -r basename -a | sort -u
|
||||
shopt -u dotglob nullglob
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! enable -f "${BASH_SOURCE%/*}"/pyenv-realpath.dylib realpath 2>/dev/null; then
|
||||
if [ -n "$PYENV_NATIVE_EXT" ]; then
|
||||
echo "pyenv: failed to load \`realpath' builtin" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
READLINK=$(type -P readlink)
|
||||
if [ -z "$READLINK" ]; then
|
||||
echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
resolve_link() {
|
||||
$READLINK "$1"
|
||||
}
|
||||
|
||||
realpath() {
|
||||
local path="$1"
|
||||
local name
|
||||
|
||||
# Use a subshell to avoid changing the current path
|
||||
(
|
||||
while [ -n "$path" ]; do
|
||||
name="${path##*/}"
|
||||
[ "$name" = "$path" ] || cd "${path%/*}"
|
||||
path="$(resolve_link "$name" || true)"
|
||||
done
|
||||
|
||||
echo "${PWD}/$name"
|
||||
)
|
||||
}
|
||||
fi
|
||||
|
||||
if [ -d "$versions_dir" ]; then
|
||||
versions_dir="$(realpath "$versions_dir")"
|
||||
fi
|
||||
|
||||
if ((${BASH_VERSINFO[0]} > 3)); then
|
||||
declare -A current_versions
|
||||
else
|
||||
current_versions=()
|
||||
fi
|
||||
if [ -n "$bare" ]; then
|
||||
include_system=""
|
||||
else
|
||||
hit_prefix="* "
|
||||
miss_prefix=" "
|
||||
OLDIFS="$IFS"
|
||||
IFS=:
|
||||
if ((${BASH_VERSINFO[0]} > 3)); then
|
||||
for i in $(pyenv-version-name || true); do
|
||||
current_versions["$i"]="1"
|
||||
done
|
||||
else
|
||||
current_versions=($(pyenv-version-name || true))
|
||||
fi
|
||||
IFS="$OLDIFS"
|
||||
include_system="1"
|
||||
fi
|
||||
|
||||
num_versions=0
|
||||
|
||||
exists() {
|
||||
local car="$1"
|
||||
local cdar
|
||||
shift
|
||||
for cdar in "$@"; do
|
||||
if [ "${car}" == "${cdar}" ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
print_version() {
|
||||
local version="${1:?}"
|
||||
if [[ -n $bare ]]; then
|
||||
echo "$version"
|
||||
return
|
||||
fi
|
||||
local path="${2:?}"
|
||||
if [[ -L "$path" ]]; then
|
||||
# Only resolve the link itself for printing, do not resolve further.
|
||||
# Doing otherwise would misinform the user of what the link contains.
|
||||
version_repr="$version --> $(readlink "$path")"
|
||||
else
|
||||
version_repr="$version"
|
||||
fi
|
||||
if [[ ${BASH_VERSINFO[0]} -ge 4 && ${current_versions["$1"]} ]]; then
|
||||
echo "${hit_prefix}${version_repr} (set by $(pyenv-version-origin))"
|
||||
elif (( ${BASH_VERSINFO[0]} <= 3 )) && exists "$1" "${current_versions[@]}"; then
|
||||
echo "${hit_prefix}${version_repr} (set by $(pyenv-version-origin))"
|
||||
else
|
||||
echo "${miss_prefix}${version_repr}"
|
||||
fi
|
||||
num_versions=$((num_versions + 1))
|
||||
}
|
||||
|
||||
# Include "system" in the non-bare output, if it exists
|
||||
if [ -n "$include_system" ] && \
|
||||
(PYENV_VERSION=system pyenv-which python --skip-advice >/dev/null 2>&1 || \
|
||||
PYENV_VERSION=system pyenv-which python3 --skip-advice >/dev/null 2>&1 || \
|
||||
PYENV_VERSION=system pyenv-which python2 --skip-advice >/dev/null 2>&1) ; then
|
||||
print_version system "/"
|
||||
fi
|
||||
|
||||
shopt -s dotglob nullglob
|
||||
versions_dir_entries=("$versions_dir"/*)
|
||||
if sort --version-sort </dev/null >/dev/null 2>&1; then
|
||||
# system sort supports version sorting
|
||||
OLDIFS="$IFS"
|
||||
IFS=$'\n'
|
||||
versions_dir_entries=($(
|
||||
printf "%s\n" "${versions_dir_entries[@]}" |
|
||||
sort --version-sort
|
||||
))
|
||||
IFS="$OLDIFS"
|
||||
fi
|
||||
|
||||
for path in "${versions_dir_entries[@]}"; do
|
||||
if [ -d "$path" ]; then
|
||||
if [ -n "$skip_aliases" ] && [ -L "$path" ]; then
|
||||
target="$(realpath "$path")"
|
||||
[ "${target%/*}" == "$versions_dir" ] && continue
|
||||
[ "${target%/*/envs/*}" == "$versions_dir" ] && continue
|
||||
fi
|
||||
print_version "${path##*/}" "$path"
|
||||
# virtual environments created by anaconda/miniconda/pyenv-virtualenv
|
||||
if [[ -z $skip_envs ]]; then
|
||||
for env_path in "${path}/envs/"*; do
|
||||
if [ -d "${env_path}" ]; then
|
||||
print_version "${env_path#${PYENV_ROOT}/versions/}" "${env_path}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
shopt -u dotglob nullglob
|
||||
|
||||
if [ "$num_versions" -eq 0 ] && [ -n "$include_system" ]; then
|
||||
echo "Warning: no Python detected on the system" >&2
|
||||
exit 1
|
||||
fi
|
||||
38
libexec/pyenv-whence
Executable file
38
libexec/pyenv-whence
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# Summary: List all Python versions that contain the given executable
|
||||
# Usage: pyenv whence [--path] <command>
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo --path
|
||||
exec pyenv-shims --short
|
||||
fi
|
||||
|
||||
if [ "$1" = "--path" ]; then
|
||||
print_paths="1"
|
||||
shift
|
||||
else
|
||||
print_paths=""
|
||||
fi
|
||||
|
||||
whence() {
|
||||
local command="$1"
|
||||
pyenv-versions --bare | while read -r version; do
|
||||
path="$(pyenv-prefix "$version")/bin/${command}"
|
||||
if [ -x "$path" ]; then
|
||||
[ "$print_paths" ] && echo "$path" || echo "$version"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
PYENV_COMMAND="$1"
|
||||
if [ -z "$PYENV_COMMAND" ]; then
|
||||
pyenv-help --usage whence >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
result="$(whence "$PYENV_COMMAND")"
|
||||
[ -n "$result" ] && echo "$result"
|
||||
122
libexec/pyenv-which
Executable file
122
libexec/pyenv-which
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Summary: Display the full path to an executable
|
||||
#
|
||||
# Usage: pyenv which <command> [--nosystem] [--skip-advice]
|
||||
#
|
||||
# Displays the full path to the executable that pyenv will invoke when
|
||||
# you run the given command.
|
||||
# Use --nosystem argument in case when you don't need to search command in the
|
||||
# system environment.
|
||||
# Internal switch --skip-advice used to skip printing an error message on a
|
||||
# failed search.
|
||||
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
exec pyenv-shims --short
|
||||
fi
|
||||
|
||||
system="system"
|
||||
SKIP_ADVICE=""
|
||||
PYENV_COMMAND="$1"
|
||||
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case "$1" in
|
||||
--skip-advice)
|
||||
SKIP_ADVICE=1
|
||||
shift
|
||||
;;
|
||||
--nosystem)
|
||||
system=""
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
remove_from_path() {
|
||||
local -a paths_to_remove
|
||||
IFS=: paths_to_remove=($1)
|
||||
local path_to_remove path_before
|
||||
local result=":${PATH//\~/$HOME}:"
|
||||
for path_to_remove in "${paths_to_remove[@]}"; do
|
||||
while true; do
|
||||
path_before="$result"
|
||||
result="${result//:$path_to_remove:/:}"
|
||||
if [[ ${#path_before} == "${#result}" ]]; then break; fi
|
||||
done
|
||||
done
|
||||
result="${result:1:${#result}-2}"
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
if [ -z "$PYENV_COMMAND" ]; then
|
||||
pyenv-help --usage which >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OLDIFS="$IFS"
|
||||
IFS=: versions=(${PYENV_VERSION:-$(pyenv-version-name -f)})
|
||||
IFS="$OLDIFS"
|
||||
|
||||
declare -a nonexistent_versions
|
||||
|
||||
for version in "${versions[@]}" "$system"; do
|
||||
if [ "$version" = "system" ]; then
|
||||
PROGRAM="$(echo "$PYENV_COMMAND" | tr a-z- A-Z_ | sed 's/[^A-Z0-9_]/_/g')"
|
||||
NR_CUSTOM_SHIM_PATHS="_PYENV_SHIM_PATHS_$PROGRAM"
|
||||
SEARCH_PATH="$(remove_from_path "${PYENV_ROOT}/shims${!NR_CUSTOM_SHIM_PATHS:+:${!NR_CUSTOM_SHIM_PATHS}}")"
|
||||
PYENV_COMMAND_PATH="$(PATH="$SEARCH_PATH" command -v "$PYENV_COMMAND" || true)"
|
||||
else
|
||||
# $version may be a prefix to be resolved by pyenv-latest
|
||||
version_path="$(pyenv-prefix "${version}" 2>/dev/null)" || \
|
||||
{ nonexistent_versions+=("$version"); continue; }
|
||||
# resolve $version for hooks
|
||||
version="$(basename "$version_path")"
|
||||
PYENV_COMMAND_PATH="$version_path/bin/${PYENV_COMMAND}"
|
||||
unset version_path
|
||||
fi
|
||||
if [ -x "$PYENV_COMMAND_PATH" ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
OLDIFS="$IFS"
|
||||
IFS=$'\n' scripts=(`pyenv-hooks which`)
|
||||
IFS="$OLDIFS"
|
||||
for script in "${scripts[@]}"; do
|
||||
source "$script"
|
||||
done
|
||||
|
||||
if [ -x "$PYENV_COMMAND_PATH" ]; then
|
||||
echo "$PYENV_COMMAND_PATH"
|
||||
else
|
||||
if (( ${#nonexistent_versions[@]} )); then
|
||||
for version in "${nonexistent_versions[@]}"; do
|
||||
echo "pyenv: version \`$version' is not installed (set by $(pyenv-version-origin))" >&2
|
||||
done
|
||||
fi
|
||||
|
||||
echo "pyenv: $PYENV_COMMAND: command not found" >&2
|
||||
if [ -z "$SKIP_ADVICE" ]; then
|
||||
versions="$(pyenv-whence "$PYENV_COMMAND" || true)"
|
||||
if [ -n "$versions" ]; then
|
||||
{ echo
|
||||
echo "The \`$PYENV_COMMAND' command exists in these Python versions:"
|
||||
echo "$versions" | sed 's/^/ /g'
|
||||
echo
|
||||
echo "Note: See 'pyenv help global' for tips on allowing multiple"
|
||||
echo " Python versions to be found at the same time."
|
||||
} >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 127
|
||||
fi
|
||||
Reference in New Issue
Block a user