From 2457419b4acb65b76dd40d55f51b33a4a9e2f1e9 Mon Sep 17 00:00:00 2001 From: Yamashita Yuu Date: Fri, 31 Aug 2012 15:23:41 +0900 Subject: [PATCH] created new project. modified rbenv source for Python and renamed to pyenv. --- .gitignore | 4 + LICENSE | 21 +++++ README.md | 152 +++++++++++++++++++++++++++++++ bin/pyenv | 1 + bin/python-local-exec | 16 ++++ completions/pyenv.bash | 14 +++ completions/pyenv.zsh | 19 ++++ libexec/pyenv | 75 +++++++++++++++ libexec/pyenv-commands | 38 ++++++++ libexec/pyenv-completions | 15 +++ libexec/pyenv-exec | 25 +++++ libexec/pyenv-global | 21 +++++ libexec/pyenv-help | 99 ++++++++++++++++++++ libexec/pyenv-hooks | 44 +++++++++ libexec/pyenv-init | 101 ++++++++++++++++++++ libexec/pyenv-local | 24 +++++ libexec/pyenv-prefix | 29 ++++++ libexec/pyenv-rehash | 150 ++++++++++++++++++++++++++++++ libexec/pyenv-root | 2 + libexec/pyenv-sh-shell | 32 +++++++ libexec/pyenv-shims | 17 ++++ libexec/pyenv-version | 5 + libexec/pyenv-version-file | 24 +++++ libexec/pyenv-version-file-read | 24 +++++ libexec/pyenv-version-file-write | 17 ++++ libexec/pyenv-version-name | 22 +++++ libexec/pyenv-version-origin | 9 ++ libexec/pyenv-versions | 27 ++++++ libexec/pyenv-whence | 35 +++++++ libexec/pyenv-which | 77 ++++++++++++++++ 30 files changed, 1139 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 120000 bin/pyenv create mode 100755 bin/python-local-exec create mode 100644 completions/pyenv.bash create mode 100644 completions/pyenv.zsh create mode 100755 libexec/pyenv create mode 100755 libexec/pyenv-commands create mode 100755 libexec/pyenv-completions create mode 100755 libexec/pyenv-exec create mode 100755 libexec/pyenv-global create mode 100755 libexec/pyenv-help create mode 100755 libexec/pyenv-hooks create mode 100755 libexec/pyenv-init create mode 100755 libexec/pyenv-local create mode 100755 libexec/pyenv-prefix create mode 100755 libexec/pyenv-rehash create mode 100755 libexec/pyenv-root create mode 100755 libexec/pyenv-sh-shell create mode 100755 libexec/pyenv-shims create mode 100755 libexec/pyenv-version create mode 100755 libexec/pyenv-version-file create mode 100755 libexec/pyenv-version-file-read create mode 100755 libexec/pyenv-version-file-write create mode 100755 libexec/pyenv-version-name create mode 100755 libexec/pyenv-version-origin create mode 100755 libexec/pyenv-versions create mode 100755 libexec/pyenv-whence create mode 100755 libexec/pyenv-which diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7e2eb978 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/plugins +/shims +/version +/versions diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..e59f3556 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2011 Sam Stephenson +Copyright (c) 2012 Yamashita, Yuu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..3768b933 --- /dev/null +++ b/README.md @@ -0,0 +1,152 @@ +# Simple Python Version Management: pyenv + +pyenv lets you easily switch between multiple versions of Python. It's +simple, unobtrusive, and follows the UNIX tradition of single-purpose +tools that do one thing well. + +This project was forked from [rbenv](https://github.com/sstephenson/rbenv) and. +[ruby-build](https://github.com/sstephenson/ruby-build) and modified for Python. + +### pyenv _does…_ + +* Let you **change the global Python version** on a per-user basis. +* Provide support for **per-project Python versions**. +* Allow you to **override the Python version** with an environment + variable. + +## Table of Contents + + * [1 How It Works](#section_1) + * [2 Installation](#section_2) + * [2.1 Basic GitHub Checkout](#section_2.1) + * [2.1.1 Upgrading](#section_2.1.1) + * [3 Usage](#section_3) + * [4 Development](#section_4) + * [4.1 Version History](#section_4.1) + * [4.2 License](#section_4.2) + +## 1 How It Works + +pyenv operates on the per-user directory `~/.pyenv`. Version names in +pyenv correspond to subdirectories of `~/.pyenv/versions`. For +example, you might have `~/.pyenv/versions/2.7.3` and +`~/.pyenv/versions/2.7.3`. + +Each version is a working tree with its own binaries, like +`~/.pyenv/versions/2.7.3/bin/python2.7` and +`~/.pyenv/versions/3.2.3/bin/python3.2`. pyenv makes _shim binaries_ +for every such binary across all installed versions of Python. + +These shims are simple wrapper scripts that live in `~/.pyenv/shims` +and detect which Python version you want to use. They insert the +directory for the selected version at the beginning of your `$PATH` +and then execute the corresponding binary. + +Because of the simplicity of the shim approach, all you need to use +pyenv is `~/.pyenv/shims` in your `$PATH`. + +## 2 Installation + +### 2.1 Basic GitHub Checkout + +This will get you going with the latest version of pyenv and make it +easy to fork and contribute any changes back upstream. + +1. Check out pyenv into `~/.pyenv`. + + $ cd + $ git clone git://github.com/yyuu/pyenv.git .pyenv + +2. Add `~/.pyenv/bin` to your `$PATH` for access to the `pyenv` + command-line utility. + + $ echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bash_profile + + **Zsh note**: Modify your `~/.zshenv` file instead of `~/.bash_profile`. + +3. Add pyenv init to your shell to enable shims and autocompletion. + + $ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile + + **Zsh note**: Modify your `~/.zshenv` file instead of `~/.bash_profile`. + +4. Restart your shell so the path changes take effect. You can now + begin using pyenv. + + $ exec $SHELL + +5. Install Python versions into `~/.pyenv/versions`. For example, to + install Python 2.7.3, download and unpack the source, then run: + + $ pyenv install 2.7.3 + +6. Rebuild the shim binaries. You should do this any time you install + a new Python binary (for example, when installing a new Python version, + or when installing a gem that provides a binary). + + $ pyenv rehash + +#### 2.1.1 Upgrading + +If you've installed pyenv using the instructions above, you can +upgrade your installation at any time using git. + +To upgrade to the latest development version of pyenv, use `git pull`: + + $ cd ~/.pyenv + $ git pull + +To upgrade to a specific release of pyenv, check out the corresponding +tag: + + $ cd ~/.pyenv + $ git fetch + $ git tag + v0.1.0 + v0.1.1 + v0.1.2 + v0.2.0 + $ git checkout v0.2.0 + +## 3 Usage + +## 4 Development + +The pyenv source code is [hosted on +GitHub](https://github.com/yyuu/pyenv). It's clean, modular, +and easy to understand, even if you're not a shell hacker. + +Please feel free to submit pull requests and file bugs on the [issue +tracker](https://github.com/yyuu/pyenv/issues). + +### 4.1 Version History + +**0.1.0** (August 31, 2012) + +* Initial public release. + +### 4.2 License + +(The MIT license) + +Copyright (c) 2011 Sam Stephenson +Copyright (c) 2012 Yamashita, Yuu + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bin/pyenv b/bin/pyenv new file mode 120000 index 00000000..06bee778 --- /dev/null +++ b/bin/pyenv @@ -0,0 +1 @@ +../libexec/pyenv \ No newline at end of file diff --git a/bin/python-local-exec b/bin/python-local-exec new file mode 100755 index 00000000..a3068f67 --- /dev/null +++ b/bin/python-local-exec @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# +# `python-local-exec` is a drop-in replacement for the standard Python +# shebang line: +# +# #!/usr/bin/env python-local-exec +# +# Use it for scripts inside a project with an `.pyenv-version` +# file. When you run the scripts, they'll use the project-specified +# Python version, regardless of what directory they're run from. Useful +# for e.g. running project tasks in cron scripts without needing to +# `cd` into the project first. + +set -e +export PYENV_DIR="${1%/*}" +exec python "$@" diff --git a/completions/pyenv.bash b/completions/pyenv.bash new file mode 100644 index 00000000..cd6ddb1c --- /dev/null +++ b/completions/pyenv.bash @@ -0,0 +1,14 @@ +_pyenv() { + COMPREPLY=() + local word="${COMP_WORDS[COMP_CWORD]}" + + if [ "$COMP_CWORD" -eq 1 ]; then + COMPREPLY=( $(compgen -W "$(pyenv commands)" -- "$word") ) + else + local command="${COMP_WORDS[1]}" + local completions="$(pyenv completions "$command")" + COMPREPLY=( $(compgen -W "$completions" -- "$word") ) + fi +} + +complete -F _pyenv pyenv diff --git a/completions/pyenv.zsh b/completions/pyenv.zsh new file mode 100644 index 00000000..f27cdbbc --- /dev/null +++ b/completions/pyenv.zsh @@ -0,0 +1,19 @@ +if [[ ! -o interactive ]]; then + return +fi + +compctl -K _pyenv pyenv + +_pyenv() { + local word words completions + read -cA words + word="${words[2]}" + + if [ "${#words}" -eq 2 ]; then + completions="$(pyenv commands)" + else + completions="$(pyenv completions "${word}")" + fi + + reply=("${(ps:\n:)completions}") +} diff --git a/libexec/pyenv b/libexec/pyenv new file mode 100755 index 00000000..b619d25a --- /dev/null +++ b/libexec/pyenv @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +resolve_link() { + $(type -p greadlink readlink | head -1) "$1" +} + +abs_dirname() { + local cwd="$(pwd)" + local path="$1" + + while [ -n "$path" ]; do + cd "${path%/*}" + local name="${path##*/}" + path="$(resolve_link "$name" || true)" + done + + pwd + cd "$cwd" +} + +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)" +else + cd "$PYENV_DIR" 2>/dev/null || { + echo "pyenv: cannot change working directory to \`$PYENV_DIR'" + exit 1 + } >&2 + PYENV_DIR="$(pwd)" + cd "$OLDPWD" +fi +export PYENV_DIR + + +shopt -s nullglob + +bin_path="$(abs_dirname "$0")" +for plugin_bin in "${PYENV_ROOT}/plugins/"*/bin; do + bin_path="${bin_path}:${plugin_bin}" +done +export PATH="${bin_path}:${PATH}" + +hook_path="${PYENV_HOOK_PATH}:${PYENV_ROOT}/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 + hook_path="${hook_path}:${plugin_hook}" +done +export PYENV_HOOK_PATH="$hook_path" + +shopt -u nullglob + + +command="$1" +case "$command" in +"" | "-h" | "--help" ) + echo -e "pyenv 0.1.0\n$(pyenv-help)" >&2 + ;; +* ) + command_path="$(command -v "pyenv-$command" || true)" + if [ -z "$command_path" ]; then + echo "pyenv: no such command \`$command'" >&2 + exit 1 + fi + + shift 1 + exec "$command_path" "$@" + ;; +esac diff --git a/libexec/pyenv-commands b/libexec/pyenv-commands new file mode 100755 index 00000000..f526515a --- /dev/null +++ b/libexec/pyenv-commands @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +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 + +shopt -s nullglob + +{ for path in ${PATH//:/$'\n'}; do + for command in "${path}/pyenv-"*; do + command="${command##*pyenv-}" + if [ -n "$sh" ]; then + if [ ${command:0:3} = "sh-" ]; then + echo ${command##sh-} + fi + elif [ -n "$nosh" ]; then + if [ ${command:0:3} != "sh-" ]; then + echo ${command##sh-} + fi + else + echo ${command##sh-} + fi + done + done +} | sort | uniq diff --git a/libexec/pyenv-completions b/libexec/pyenv-completions new file mode 100755 index 00000000..bd2dbb43 --- /dev/null +++ b/libexec/pyenv-completions @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +COMMAND="$1" +if [ -z "$COMMAND" ]; then + echo "usage: pyenv completions COMMAND [arg1 arg2...]" >&2 + exit 1 +fi + +COMMAND_PATH="$(command -v "pyenv-$COMMAND" || command -v "pyenv-sh-$COMMAND")" +if grep -i "^# provide pyenv completions" "$COMMAND_PATH" >/dev/null; then + shift + exec "$COMMAND_PATH" --complete "$@" +fi diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec new file mode 100755 index 00000000..0b07db8f --- /dev/null +++ b/libexec/pyenv-exec @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +# Provide pyenv completions +if [ "$1" = "--complete" ]; then + exec pyenv shims --short +fi + +PYENV_COMMAND="$1" +if [ -z "$PYENV_COMMAND" ]; then + echo "usage: pyenv exec COMMAND [arg1 arg2...]" >&2 + exit 1 +fi + +PYENV_COMMAND_PATH="$(pyenv-which "$PYENV_COMMAND")" +PYENV_BIN_PATH="${PYENV_COMMAND_PATH%/*}" + +for script in $(pyenv-hooks exec); do + source "$script" +done + +shift 1 +export PATH="${PYENV_BIN_PATH}:${PATH}" +exec -a "$PYENV_COMMAND" "$PYENV_COMMAND_PATH" "$@" diff --git a/libexec/pyenv-global b/libexec/pyenv-global new file mode 100755 index 00000000..b89d0220 --- /dev/null +++ b/libexec/pyenv-global @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +# Provide pyenv completions +if [ "$1" = "--complete" ]; then + echo system + exec pyenv-versions --bare +fi + +PYENV_VERSION="$1" +PYENV_VERSION_FILE="${PYENV_ROOT}/version" + +if [ -n "$PYENV_VERSION" ]; then + pyenv-version-file-write "$PYENV_VERSION_FILE" "$PYENV_VERSION" +else + pyenv-version-file-read "$PYENV_VERSION_FILE" || + pyenv-version-file-read "${PYENV_ROOT}/global" || + pyenv-version-file-read "${PYENV_ROOT}/default" || + echo system +fi diff --git a/libexec/pyenv-help b/libexec/pyenv-help new file mode 100755 index 00000000..05629d94 --- /dev/null +++ b/libexec/pyenv-help @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +print_set_version() { + echo " should be a string matching a Python version known by pyenv." + + local versions="$(pyenv-versions --bare)" + if [ -z "$versions" ]; then + echo "There are currently no Python versions installed for pyenv." + else + echo "The currently installed Python versions are:" + echo "$versions" | sed 's/^/ /' + fi + + echo + echo "The special version string 'system' will use your default system Python" +} + +case "$1" in +"") echo "usage: pyenv [] + +Some useful pyenv commands are: + commands List all pyenv commands + rehash Rehash pyenv shims (run this after installing binaries) + global Set or show the global Python version + local Set or show the local directory-specific Python version + shell Set or show the shell-specific Python version + version Show the current Python version + versions List all Python versions known by pyenv + which Show the full path for the given Python command + whence List all Python versions with the given command + +See 'pyenv help ' for information on a specific command. +For full documentation, see: https://github.com/sstephenson/pyenv#readme" +;; +commands) echo "usage: pyenv commands + pyenv commands --sh + pyenv commands --no-sh + +List all pyenv commands." +;; +global) echo "usage: pyenv global + +Sets the global Python version. 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. + +$(print_set_version)" +;; +local) echo "usage: pyenv local + pyenv local --unset + +Sets the local directory-specific Python version by writing the version +name to a file named '.pyenv-version'. + +When you run a Python command, pyenv will look for an '.pyenv-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', or the version specified in the +PYENV_VERSION environment variable. + +$(print_set_version)" +;; +shell) echo "usage: pyenv shell + pyenv shell --unset + +Sets a shell-specific Python version by setting the 'PYENV_VERSION' +environment variable in your shell. This version overrides both +project-specific versions and the global version. + +$(print_set_version)" +;; +versions) echo "usage: pyenv versions + pyenv versions --bare + +Lists all Python versions known by pyenv." +;; +which) echo "usage: pyenv which + +Displays the full path to the binary that pyenv will execute when you +run the given command." +;; +whence) echo "usage: pyenv whence + +Lists all Python versions with the given command installed." +;; +*) + command_path="$(command -v "pyenv-$1" || true)" + if [ -n "$command_path" ]; then + echo "Sorry, the \`$1' command isn't documented yet." + echo + echo "You can view the command's source here:" + echo "$command_path" + echo + else + echo "pyenv: no such command \`$1'" + fi +esac diff --git a/libexec/pyenv-hooks b/libexec/pyenv-hooks new file mode 100755 index 00000000..ec98a545 --- /dev/null +++ b/libexec/pyenv-hooks @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +# Provide pyenv completions +if [ "$1" = "--complete" ]; then + echo exec + echo rehash + echo which + exit +fi + +PYENV_COMMAND="$1" +if [ -z "$PYENV_COMMAND" ]; then + echo "usage: pyenv hooks COMMAND" >&2 + exit 1 +fi + +resolve_link() { + $(type -p greadlink readlink | head -1) $1 +} + +realpath() { + local cwd="$(pwd)" + local base="$(basename $1)" + local path="$1" + + while [ -n "$path" ]; do + cd "${path%/*}" + local name="${path##*/}" + path="$(resolve_link "$name" || true)" + done + + echo "$(pwd)/$base" + cd "$cwd" +} + +shopt -s nullglob +for path in ${PYENV_HOOK_PATH//:/$'\n'}; do + for script in $path/"$PYENV_COMMAND"/*.bash; do + echo $(realpath $script) + done +done +shopt -u nullglob diff --git a/libexec/pyenv-init b/libexec/pyenv-init new file mode 100755 index 00000000..c5bb3a1e --- /dev/null +++ b/libexec/pyenv-init @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +print="" +no_rehash="" +for args in "$@" +do + if [ "$args" = "-" ]; then + print=1 + shift + fi + + if [ "$args" = "--no-rehash" ]; then + no_rehash=1 + shift + fi +done + +shell="$1" +if [ -z "$shell" ]; then + shell="$(basename "$SHELL")" +fi + +resolve_link() { + $(type -p greadlink readlink | head -1) $1 +} + +abs_dirname() { + local cwd="$(pwd)" + local path="$1" + + while [ -n "$path" ]; do + cd "${path%/*}" + local name="${path##*/}" + path="$(resolve_link "$name" || true)" + done + + pwd + cd "$cwd" +} + +root="$(abs_dirname "$0")/.." + +if [ -z "$print" ]; then + case "$shell" in + bash ) + profile='~/.bash_profile' + ;; + zsh ) + profile='~/.zshrc' + ;; + ksh ) + profile='~/.profile' + ;; + * ) + profile='your profile' + ;; + esac + + { echo "# Load pyenv automatically by adding" + echo "# the following to ${profile}:" + echo + echo 'eval "$(pyenv init -)"' + echo + } >&2 + + exit 1 +fi + +mkdir -p "${PYENV_ROOT}/"{shims,versions} + +echo 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' + +case "$shell" in +bash | zsh ) + echo "source \"$root/completions/pyenv.${shell}\"" + ;; +esac + +if [ -z "$no_rehash" ]; then + echo 'pyenv rehash 2>/dev/null' +fi + +commands=(`pyenv commands --sh`) +IFS="|" +cat <&2 +fi diff --git a/libexec/pyenv-prefix b/libexec/pyenv-prefix new file mode 100755 index 00000000..b87c9d28 --- /dev/null +++ b/libexec/pyenv-prefix @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +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 + export PYENV_VERSION="$1" +elif [ -z "$PYENV_VERSION" ]; then + PYENV_VERSION="$(pyenv-version-name)" +fi + +if [ "$PYENV_VERSION" = "system" ]; then + PYTHON_PATH="$(pyenv-which python)" + echo "${PYTHON_PATH%/*}" + exit +fi + +PYENV_PREFIX_PATH="${PYENV_ROOT}/versions/${PYENV_VERSION}" +if [ ! -d "$PYENV_PREFIX_PATH" ]; then + echo "pyenv: version \`${PYENV_VERSION}' not installed" >&2 + exit 1 +fi + +echo "$PYENV_PREFIX_PATH" diff --git a/libexec/pyenv-rehash b/libexec/pyenv-rehash new file mode 100755 index 00000000..d76f862d --- /dev/null +++ b/libexec/pyenv-rehash @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +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" + +# 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. +set -o noclobber +{ echo > "$PROTOTYPE_SHIM_PATH" +} 2>/dev/null || +{ echo "pyenv: cannot rehash: $PROTOTYPE_SHIM_PATH exists" + exit 1 +} >&2 +set +o noclobber + +# If we were able to obtain a lock, register a trap to clean up the +# prototype shim when the process exits. +trap remove_prototype_shim EXIT + +remove_prototype_shim() { + rm -f "$PROTOTYPE_SHIM_PATH" +} + +# 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 binary 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" <&2 + exit 1 + else + echo "echo \"\$PYENV_VERSION\"" + exit + fi +fi + +if [ "$version" = "--unset" ]; then + echo "unset PYENV_VERSION" + exit 1 +fi + +# Make sure the specified version is installed. +pyenv-prefix "$version" >/dev/null + +echo "export PYENV_VERSION=\"${version}\"" diff --git a/libexec/pyenv-shims b/libexec/pyenv-shims new file mode 100755 index 00000000..f4fb8b86 --- /dev/null +++ b/libexec/pyenv-shims @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +# Provide pyenv completions +if [ "$1" = "--complete" ]; then + echo --short + exit +fi + +for command in "${PYENV_ROOT}/shims/"*; do + if [ "$1" = "--short" ]; then + echo "${command##*/}" + else + echo "$command" + fi +done | sort diff --git a/libexec/pyenv-version b/libexec/pyenv-version new file mode 100755 index 00000000..25794212 --- /dev/null +++ b/libexec/pyenv-version @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +echo "$(pyenv-version-name) (set by $(pyenv-version-origin))" diff --git a/libexec/pyenv-version-file b/libexec/pyenv-version-file new file mode 100755 index 00000000..ddd88076 --- /dev/null +++ b/libexec/pyenv-version-file @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +root="$PYENV_DIR" +while [ -n "$root" ]; do + if [ -e "${root}/.pyenv-version" ]; then + echo "${root}/.pyenv-version" + exit + fi + root="${root%/*}" +done + +global_version_file="${PYENV_ROOT}/version" + +if [ -e "$global_version_file" ]; then + echo "$global_version_file" +elif [ -e "${PYENV_ROOT}/global" ]; then + echo "${PYENV_ROOT}/global" +elif [ -e "${PYENV_ROOT}/default" ]; then + echo "${PYENV_ROOT}/default" +else + echo "$global_version_file" +fi diff --git a/libexec/pyenv-version-file-read b/libexec/pyenv-version-file-read new file mode 100755 index 00000000..8c775b56 --- /dev/null +++ b/libexec/pyenv-version-file-read @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +VERSION_FILE="$1" + +if [ -e "$VERSION_FILE" ]; then + # Read and print the first non-whitespace word from the specified + # version file. + version="" + while read -a words; do + word="${words[0]}" + if [ -z "$version" ] && [ -n "$word" ]; then + version="$word" + fi + done < <( cat "$VERSION_FILE" && echo ) + + if [ -n "$version" ]; then + echo "$version" + exit + fi +fi + +exit 1 diff --git a/libexec/pyenv-version-file-write b/libexec/pyenv-version-file-write new file mode 100755 index 00000000..d9e21b5a --- /dev/null +++ b/libexec/pyenv-version-file-write @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +PYENV_VERSION_FILE="$1" +PYENV_VERSION="$2" + +if [ -z "$PYENV_VERSION" ] || [ -z "$PYENV_VERSION_FILE" ]; then + echo "usage: pyenv write-version-file FILENAME VERSION" >&2 + exit 1 +fi + +# Make sure the specified version is installed. +pyenv-prefix "$PYENV_VERSION" >/dev/null + +# Write the version out to disk. +echo "$PYENV_VERSION" > "$PYENV_VERSION_FILE" diff --git a/libexec/pyenv-version-name b/libexec/pyenv-version-name new file mode 100755 index 00000000..8a8d317d --- /dev/null +++ b/libexec/pyenv-version-name @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +if [ -z "$PYENV_VERSION" ]; then + PYENV_VERSION_FILE="$(pyenv-version-file)" + PYENV_VERSION="$(pyenv-version-file-read "$PYENV_VERSION_FILE" || true)" +fi + +if [ -z "$PYENV_VERSION" ] || [ "$PYENV_VERSION" = "system" ]; then + echo "system" + exit +fi + +PYENV_VERSION_PATH="${PYENV_ROOT}/versions/${PYENV_VERSION}" + +if [ -d "$PYENV_VERSION_PATH" ]; then + echo "$PYENV_VERSION" +else + echo "pyenv: version \`$PYENV_VERSION' is not installed" >&2 + exit 1 +fi diff --git a/libexec/pyenv-version-origin b/libexec/pyenv-version-origin new file mode 100755 index 00000000..2c826b15 --- /dev/null +++ b/libexec/pyenv-version-origin @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +if [ -n "$PYENV_VERSION" ]; then + echo "PYENV_VERSION environment variable" +else + pyenv-version-file +fi diff --git a/libexec/pyenv-versions b/libexec/pyenv-versions new file mode 100755 index 00000000..d920649c --- /dev/null +++ b/libexec/pyenv-versions @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +PYENV_VERSION_NAME="$(pyenv-version-name)" + +if [ "$1" = "--bare" ]; then + hit_prefix="" + miss_prefix="" + print_version="$PYENV_VERSION_NAME" +else + hit_prefix="* " + miss_prefix=" " + print_version="$(pyenv-version)" +fi + +for path in "${PYENV_ROOT}/versions/"*; do + if [ -d "$path" ]; then + version="${path##*/}" + + if [ "$version" == "$PYENV_VERSION_NAME" ]; then + echo "${hit_prefix}${print_version}" + else + echo "${miss_prefix}${version}" + fi + fi +done diff --git a/libexec/pyenv-whence b/libexec/pyenv-whence new file mode 100755 index 00000000..b9ba8381 --- /dev/null +++ b/libexec/pyenv-whence @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +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 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 + echo "usage: pyenv whence [--path] COMMAND" >&2 + exit 1 +fi + +result="$(whence "$PYENV_COMMAND")" +[ -n "$result" ] && echo "$result" diff --git a/libexec/pyenv-which b/libexec/pyenv-which new file mode 100755 index 00000000..0f78c136 --- /dev/null +++ b/libexec/pyenv-which @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -e +[ -n "$PYENV_DEBUG" ] && set -x + +# Provide pyenv completions +if [ "$1" = "--complete" ]; then + exec pyenv shims --short +fi + +expand_path() { + if [ ! -d "$1" ]; then + return 1 + fi + + local cwd="$(pwd)" + cd "$1" + pwd + cd "$cwd" +} + +remove_from_path() { + local path_to_remove="$(expand_path "$1")" + local result="" + + if [ -z "$path_to_remove" ]; then + echo "${PATH}" + return + fi + + local paths + IFS=: paths=($PATH) + + for path in "${paths[@]}"; do + path="$(expand_path "$path" || true)" + if [ -n "$path" ] && [ "$path" != "$path_to_remove" ]; then + result="${result}${path}:" + fi + done + + echo "${result%:}" +} + +PYENV_VERSION="$(pyenv-version-name)" +PYENV_COMMAND="$1" + +if [ -z "$PYENV_COMMAND" ]; then + echo "usage: pyenv which COMMAND" >&2 + exit 1 +fi + +if [ "$PYENV_VERSION" = "system" ]; then + PATH="$(remove_from_path "${PYENV_ROOT}/shims")" + PYENV_COMMAND_PATH="$(command -v "$PYENV_COMMAND")" +else + PYENV_COMMAND_PATH="${PYENV_ROOT}/versions/${PYENV_VERSION}/bin/${PYENV_COMMAND}" +fi + +for script in $(pyenv-hooks which); do + source "$script" +done + +if [ -x "$PYENV_COMMAND_PATH" ]; then + echo "$PYENV_COMMAND_PATH" +else + echo "pyenv: $PYENV_COMMAND: command not found" >&2 + + versions="$(pyenv-whence "$PYENV_COMMAND" || true)" + if [ -n "$versions" ]; then + { echo + echo "The \`$1' command exists in these Python versions:" + echo "$versions" | sed 's/^/ /g' + echo + } >&2 + fi + + exit 127 +fi