pyenv-init | performance improvements (#3136)
* perf: replace a series of if statements with a case block. Add error handling for case where unknown option is provided. Same setup as rbenv-init for reading arguments. * perf, docs: Recommend users to specify the shell for `pyenv init -` Speeds up the startup by about 40% (in local testing, from ~50ms to ~30ms). Reflect this in `pyenv init` hint text. * style: remove unnecessary `root` variable in pyenv-init * style: remove unnecessary variable declarations at the top of file in pyenv-init. * perf: replace `cat <<` calls with `echo` The builtin `echo` is about 100x faster. In tests, saves about 2-3ms. * docs: document the `pyenv init - <shell>` performance boost in the Advanced Configuration section. * style: test_helper.bash: avoid unnecessary ".." in produced PATH * docs: fix a false statement about completions location in the Advanced Configuration section.
This commit is contained in:
parent
38421ba6aa
commit
c6973391f3
28
README.md
28
README.md
@ -191,27 +191,27 @@ See [Advanced configuration](#advanced-configuration) for details and more confi
|
||||
```bash
|
||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
|
||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
|
||||
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
|
||||
echo 'eval "$(pyenv init - bash)"' >> ~/.bashrc
|
||||
```
|
||||
3. Then, if you have `~/.profile`, `~/.bash_profile` or `~/.bash_login`, add the commands there as well.
|
||||
2. Then, if you have `~/.profile`, `~/.bash_profile` or `~/.bash_login`, add the commands there as well.
|
||||
If you have none of these, create a `~/.profile` and add the commands there.
|
||||
|
||||
* to add to `~/.profile`:
|
||||
``` bash
|
||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
|
||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
|
||||
echo 'eval "$(pyenv init -)"' >> ~/.profile
|
||||
echo 'eval "$(pyenv init - bash)"' >> ~/.profile
|
||||
```
|
||||
* to add to `~/.bash_profile`:
|
||||
```bash
|
||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
|
||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
|
||||
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
|
||||
echo 'eval "$(pyenv init - bash)"' >> ~/.bash_profile
|
||||
```
|
||||
|
||||
**Bash warning**: There are some systems where the `BASH_ENV` variable is configured
|
||||
to point to `.bashrc`. On such systems, you should almost certainly put the
|
||||
`eval "$(pyenv init -)"` line into `.bash_profile`, and **not** into `.bashrc`. Otherwise, you
|
||||
`eval "$(pyenv init - bash)"` line into `.bash_profile`, and **not** into `.bashrc`. Otherwise, you
|
||||
may observe strange behaviour, such as `pyenv` getting into an infinite loop.
|
||||
See [#264](https://github.com/pyenv/pyenv/issues/264) for details.
|
||||
|
||||
@ -224,7 +224,7 @@ See [Advanced configuration](#advanced-configuration) for details and more confi
|
||||
```zsh
|
||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
|
||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
|
||||
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
|
||||
echo 'eval "$(pyenv init - zsh)"' >> ~/.zshrc
|
||||
```
|
||||
|
||||
If you wish to get Pyenv in noninteractive login shells as well, also add the commands to `~/.zprofile` or `~/.zlogin`.
|
||||
@ -248,7 +248,7 @@ See [Advanced configuration](#advanced-configuration) for details and more confi
|
||||
|
||||
3. Now, add this to `~/.config/fish/config.fish`:
|
||||
~~~ fish
|
||||
pyenv init - | source
|
||||
pyenv init - fish | source
|
||||
~~~
|
||||
</details>
|
||||
|
||||
@ -656,23 +656,25 @@ for the environment variables that control Pyenv's behavior.
|
||||
extra commands into your shell. Coming from RVM, some of you might be
|
||||
opposed to this idea. Here's what `eval "$(pyenv init -)"` actually does:
|
||||
|
||||
1. **Finds current shell.**
|
||||
`pyenv init` figures out what shell you are using, as the exact commands of `eval "$(pyenv init -)"` vary depending on shell. Specifying which shell you are using (e.g. `eval "$(pyenv init - bash)"`) is preferred, because it reduces launch time significantly.
|
||||
|
||||
1. **Sets up the shims path.** This is what allows Pyenv to intercept
|
||||
2. **Sets up the shims path.** This is what allows Pyenv to intercept
|
||||
and redirect invocations of `python`, `pip` etc. transparently.
|
||||
It prepends `$(pyenv root)/shims` to your `$PATH`.
|
||||
It also deletes any other instances of `$(pyenv root)/shims` on `PATH`
|
||||
which allows to invoke `eval "$(pyenv init -)"` multiple times without
|
||||
getting duplicate `PATH` entries.
|
||||
|
||||
2. **Installs autocompletion.** This is entirely optional but pretty
|
||||
useful. Sourcing `$(pyenv root)/completions/pyenv.bash` will set that
|
||||
3. **Installs autocompletion.** This is entirely optional but pretty
|
||||
useful. Sourcing `<pyenv installation prefix>/completions/pyenv.bash` will set that
|
||||
up. There are also completions for Zsh and Fish.
|
||||
|
||||
3. **Rehashes shims.** From time to time you'll need to rebuild your
|
||||
4. **Rehashes shims.** From time to time you'll need to rebuild your
|
||||
shim files. Doing this on init makes sure everything is up to
|
||||
date. You can always run `pyenv rehash` manually.
|
||||
|
||||
4. **Installs `pyenv` into the current shell as a shell function.**
|
||||
5. **Installs `pyenv` into the current shell as a shell function.**
|
||||
This bit is also optional, but allows
|
||||
pyenv and plugins to change variables in your current shell.
|
||||
This is required for some commands like `pyenv shell` to work.
|
||||
@ -681,7 +683,7 @@ opposed to this idea. Here's what `eval "$(pyenv init -)"` actually does:
|
||||
for some reason you need `pyenv` to be a real script rather than a
|
||||
shell function, you can safely skip it.
|
||||
|
||||
`eval "$(pyenv init --path)"` only does items 1 and 3.
|
||||
`eval "$(pyenv init --path)"` only does items 2 and 4.
|
||||
|
||||
To see exactly what happens under the hood for yourself, run `pyenv init -`
|
||||
or `pyenv init --path`.
|
||||
|
@ -20,37 +20,32 @@ if [ "$1" = "--complete" ]; then
|
||||
fi
|
||||
|
||||
mode="help"
|
||||
no_rehash=""
|
||||
no_push_path=""
|
||||
for args in "$@"
|
||||
do
|
||||
if [ "$args" = "-" ]; then
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
-)
|
||||
mode="print"
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$args" = "--path" ]; then
|
||||
;;
|
||||
--path)
|
||||
mode="path"
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$args" = "--detect-shell" ]; then
|
||||
;;
|
||||
--detect-shell)
|
||||
mode="detect-shell"
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$args" = "--no-push-path" ]; then
|
||||
;;
|
||||
--no-push-path)
|
||||
no_push_path=1
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$args" = "--no-rehash" ]; then
|
||||
;;
|
||||
--no-rehash)
|
||||
no_rehash=1
|
||||
;;
|
||||
*)
|
||||
shell="$1"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
fi
|
||||
done
|
||||
|
||||
shell="$1"
|
||||
# If shell is not provided, detect it.
|
||||
if [ -z "$shell" ]; then
|
||||
shell="$(ps -p "$PPID" -o 'args=' 2>/dev/null || true)"
|
||||
shell="${shell%% *}"
|
||||
@ -60,8 +55,6 @@ if [ -z "$shell" ]; then
|
||||
shell="${shell%%-*}"
|
||||
fi
|
||||
|
||||
root="${0%/*}/.."
|
||||
|
||||
function main() {
|
||||
case "$mode" in
|
||||
"help")
|
||||
@ -150,7 +143,7 @@ function help_() {
|
||||
echo "# Load pyenv automatically by appending"
|
||||
echo "# the following to ~/.config/fish/config.fish:"
|
||||
echo
|
||||
echo 'pyenv init - | source'
|
||||
echo 'pyenv init - fish | source'
|
||||
echo
|
||||
;;
|
||||
* )
|
||||
@ -166,7 +159,7 @@ function help_() {
|
||||
echo
|
||||
echo 'export PYENV_ROOT="$HOME/.pyenv"'
|
||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"'
|
||||
echo 'eval "$(pyenv init -)"'
|
||||
echo 'eval "$(pyenv init -'$shell')"'
|
||||
;;
|
||||
esac
|
||||
echo
|
||||
@ -244,7 +237,7 @@ function print_env() {
|
||||
}
|
||||
|
||||
function print_completion() {
|
||||
completion="${root}/completions/pyenv.${shell}"
|
||||
completion="${0%/*/*}/completions/pyenv.${shell}"
|
||||
if [ -r "$completion" ]; then
|
||||
echo "source '$completion'"
|
||||
fi
|
||||
@ -260,52 +253,44 @@ function print_shell_function() {
|
||||
commands=(`pyenv-commands --sh`)
|
||||
case "$shell" in
|
||||
fish )
|
||||
cat <<EOS
|
||||
function pyenv
|
||||
set command \$argv[1]
|
||||
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
|
||||
switch "$command"
|
||||
case '"${commands[*]}"'
|
||||
source (pyenv "sh-$command" $argv|psub)
|
||||
case "*"
|
||||
command pyenv "$command" $argv
|
||||
end
|
||||
end
|
||||
EOS
|
||||
end'
|
||||
;;
|
||||
ksh | ksh93 | mksh )
|
||||
cat <<EOS
|
||||
function pyenv {
|
||||
typeset command
|
||||
EOS
|
||||
echo \
|
||||
'function pyenv {
|
||||
typeset command=${1:-}'
|
||||
;;
|
||||
* )
|
||||
cat <<EOS
|
||||
pyenv() {
|
||||
local command
|
||||
EOS
|
||||
echo \
|
||||
'pyenv() {
|
||||
local command=${1:-}'
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$shell" != "fish" ]; then
|
||||
IFS="|"
|
||||
cat <<EOS
|
||||
command="\${1:-}"
|
||||
if [ "\$#" -gt 0 ]; then
|
||||
shift
|
||||
fi
|
||||
|
||||
case "\$command" in
|
||||
${commands[*]:-/})
|
||||
eval "\$(pyenv "sh-\$command" "\$@")"
|
||||
echo \
|
||||
' [ "$#" -gt 0 ] && shift
|
||||
case "$command" in
|
||||
'"${commands[*]:-/}"')
|
||||
eval "$(pyenv "sh-$command" "$@")"
|
||||
;;
|
||||
*)
|
||||
command pyenv "\$command" "\$@"
|
||||
command pyenv "$command" "$@"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
EOS
|
||||
}'
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,11 @@ create_executable() {
|
||||
assert_line "command pyenv rehash 2>/dev/null"
|
||||
}
|
||||
|
||||
|
||||
@test "setup shell completions" {
|
||||
root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
|
||||
exec_root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
|
||||
run pyenv-init - bash
|
||||
assert_success
|
||||
assert_line "source '${root}/test/../libexec/../completions/pyenv.bash'"
|
||||
assert_line "source '${exec_root}/completions/pyenv.bash'"
|
||||
}
|
||||
|
||||
@test "detect parent shell" {
|
||||
@ -63,16 +62,16 @@ OUT
|
||||
}
|
||||
|
||||
@test "setup shell completions (fish)" {
|
||||
root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
|
||||
exec_root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
|
||||
run pyenv-init - fish
|
||||
assert_success
|
||||
assert_line "source '${root}/test/../libexec/../completions/pyenv.fish'"
|
||||
assert_line "source '${exec_root}/completions/pyenv.fish'"
|
||||
}
|
||||
|
||||
@test "fish instructions" {
|
||||
run pyenv-init fish
|
||||
assert [ "$status" -eq 1 ]
|
||||
assert_line 'pyenv init - | source'
|
||||
assert_line 'pyenv init - fish | source'
|
||||
}
|
||||
|
||||
@test "shell detection for installer" {
|
||||
|
@ -21,7 +21,7 @@ if [ -z "$PYENV_TEST_DIR" ]; then
|
||||
|
||||
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
|
||||
PATH="${PYENV_TEST_DIR}/bin:$PATH"
|
||||
PATH="${BATS_TEST_DIRNAME}/../libexec:$PATH"
|
||||
PATH="${BATS_TEST_DIRNAME%/*}/libexec:$PATH"
|
||||
PATH="${BATS_TEST_DIRNAME}/libexec:$PATH"
|
||||
PATH="${PYENV_ROOT}/shims:$PATH"
|
||||
export PATH
|
||||
|
Loading…
x
Reference in New Issue
Block a user