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
|
```bash
|
||||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
|
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
|
||||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.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.
|
If you have none of these, create a `~/.profile` and add the commands there.
|
||||||
|
|
||||||
* to add to `~/.profile`:
|
* to add to `~/.profile`:
|
||||||
``` bash
|
``` bash
|
||||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
|
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
|
||||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.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`:
|
* to add to `~/.bash_profile`:
|
||||||
```bash
|
```bash
|
||||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
|
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
|
||||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.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
|
**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
|
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.
|
may observe strange behaviour, such as `pyenv` getting into an infinite loop.
|
||||||
See [#264](https://github.com/pyenv/pyenv/issues/264) for details.
|
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
|
```zsh
|
||||||
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
|
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
|
||||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.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`.
|
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`:
|
3. Now, add this to `~/.config/fish/config.fish`:
|
||||||
~~~ fish
|
~~~ fish
|
||||||
pyenv init - | source
|
pyenv init - fish | source
|
||||||
~~~
|
~~~
|
||||||
</details>
|
</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
|
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:
|
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.
|
and redirect invocations of `python`, `pip` etc. transparently.
|
||||||
It prepends `$(pyenv root)/shims` to your `$PATH`.
|
It prepends `$(pyenv root)/shims` to your `$PATH`.
|
||||||
It also deletes any other instances of `$(pyenv root)/shims` on `PATH`
|
It also deletes any other instances of `$(pyenv root)/shims` on `PATH`
|
||||||
which allows to invoke `eval "$(pyenv init -)"` multiple times without
|
which allows to invoke `eval "$(pyenv init -)"` multiple times without
|
||||||
getting duplicate `PATH` entries.
|
getting duplicate `PATH` entries.
|
||||||
|
|
||||||
2. **Installs autocompletion.** This is entirely optional but pretty
|
3. **Installs autocompletion.** This is entirely optional but pretty
|
||||||
useful. Sourcing `$(pyenv root)/completions/pyenv.bash` will set that
|
useful. Sourcing `<pyenv installation prefix>/completions/pyenv.bash` will set that
|
||||||
up. There are also completions for Zsh and Fish.
|
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
|
shim files. Doing this on init makes sure everything is up to
|
||||||
date. You can always run `pyenv rehash` manually.
|
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
|
This bit is also optional, but allows
|
||||||
pyenv and plugins to change variables in your current shell.
|
pyenv and plugins to change variables in your current shell.
|
||||||
This is required for some commands like `pyenv shell` to work.
|
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
|
for some reason you need `pyenv` to be a real script rather than a
|
||||||
shell function, you can safely skip it.
|
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 -`
|
To see exactly what happens under the hood for yourself, run `pyenv init -`
|
||||||
or `pyenv init --path`.
|
or `pyenv init --path`.
|
||||||
|
@ -20,37 +20,32 @@ if [ "$1" = "--complete" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
mode="help"
|
mode="help"
|
||||||
no_rehash=""
|
|
||||||
no_push_path=""
|
|
||||||
for args in "$@"
|
|
||||||
do
|
|
||||||
if [ "$args" = "-" ]; then
|
|
||||||
mode="print"
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$args" = "--path" ]; then
|
while [ "$#" -gt 0 ]; do
|
||||||
mode="path"
|
case "$1" in
|
||||||
shift
|
-)
|
||||||
fi
|
mode="print"
|
||||||
|
;;
|
||||||
if [ "$args" = "--detect-shell" ]; then
|
--path)
|
||||||
mode="detect-shell"
|
mode="path"
|
||||||
shift
|
;;
|
||||||
fi
|
--detect-shell)
|
||||||
|
mode="detect-shell"
|
||||||
if [ "$args" = "--no-push-path" ]; then
|
;;
|
||||||
no_push_path=1
|
--no-push-path)
|
||||||
shift
|
no_push_path=1
|
||||||
fi
|
;;
|
||||||
|
--no-rehash)
|
||||||
if [ "$args" = "--no-rehash" ]; then
|
no_rehash=1
|
||||||
no_rehash=1
|
;;
|
||||||
shift
|
*)
|
||||||
fi
|
shell="$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
shell="$1"
|
# If shell is not provided, detect it.
|
||||||
if [ -z "$shell" ]; then
|
if [ -z "$shell" ]; then
|
||||||
shell="$(ps -p "$PPID" -o 'args=' 2>/dev/null || true)"
|
shell="$(ps -p "$PPID" -o 'args=' 2>/dev/null || true)"
|
||||||
shell="${shell%% *}"
|
shell="${shell%% *}"
|
||||||
@ -60,8 +55,6 @@ if [ -z "$shell" ]; then
|
|||||||
shell="${shell%%-*}"
|
shell="${shell%%-*}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
root="${0%/*}/.."
|
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
case "$mode" in
|
case "$mode" in
|
||||||
"help")
|
"help")
|
||||||
@ -150,7 +143,7 @@ function help_() {
|
|||||||
echo "# Load pyenv automatically by appending"
|
echo "# Load pyenv automatically by appending"
|
||||||
echo "# the following to ~/.config/fish/config.fish:"
|
echo "# the following to ~/.config/fish/config.fish:"
|
||||||
echo
|
echo
|
||||||
echo 'pyenv init - | source'
|
echo 'pyenv init - fish | source'
|
||||||
echo
|
echo
|
||||||
;;
|
;;
|
||||||
* )
|
* )
|
||||||
@ -166,7 +159,7 @@ function help_() {
|
|||||||
echo
|
echo
|
||||||
echo 'export PYENV_ROOT="$HOME/.pyenv"'
|
echo 'export PYENV_ROOT="$HOME/.pyenv"'
|
||||||
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"'
|
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"'
|
||||||
echo 'eval "$(pyenv init -)"'
|
echo 'eval "$(pyenv init -'$shell')"'
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
echo
|
echo
|
||||||
@ -244,7 +237,7 @@ function print_env() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function print_completion() {
|
function print_completion() {
|
||||||
completion="${root}/completions/pyenv.${shell}"
|
completion="${0%/*/*}/completions/pyenv.${shell}"
|
||||||
if [ -r "$completion" ]; then
|
if [ -r "$completion" ]; then
|
||||||
echo "source '$completion'"
|
echo "source '$completion'"
|
||||||
fi
|
fi
|
||||||
@ -260,52 +253,44 @@ function print_shell_function() {
|
|||||||
commands=(`pyenv-commands --sh`)
|
commands=(`pyenv-commands --sh`)
|
||||||
case "$shell" in
|
case "$shell" in
|
||||||
fish )
|
fish )
|
||||||
cat <<EOS
|
echo \
|
||||||
function pyenv
|
'function pyenv
|
||||||
set command \$argv[1]
|
set command $argv[1]
|
||||||
set -e argv[1]
|
set -e argv[1]
|
||||||
|
|
||||||
switch "\$command"
|
switch "$command"
|
||||||
case ${commands[*]}
|
case '"${commands[*]}"'
|
||||||
source (pyenv "sh-\$command" \$argv|psub)
|
source (pyenv "sh-$command" $argv|psub)
|
||||||
case '*'
|
case "*"
|
||||||
command pyenv "\$command" \$argv
|
command pyenv "$command" $argv
|
||||||
end
|
end
|
||||||
end
|
end'
|
||||||
EOS
|
|
||||||
;;
|
;;
|
||||||
ksh | ksh93 | mksh )
|
ksh | ksh93 | mksh )
|
||||||
cat <<EOS
|
echo \
|
||||||
function pyenv {
|
'function pyenv {
|
||||||
typeset command
|
typeset command=${1:-}'
|
||||||
EOS
|
|
||||||
;;
|
;;
|
||||||
* )
|
* )
|
||||||
cat <<EOS
|
echo \
|
||||||
pyenv() {
|
'pyenv() {
|
||||||
local command
|
local command=${1:-}'
|
||||||
EOS
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ "$shell" != "fish" ]; then
|
if [ "$shell" != "fish" ]; then
|
||||||
IFS="|"
|
IFS="|"
|
||||||
cat <<EOS
|
echo \
|
||||||
command="\${1:-}"
|
' [ "$#" -gt 0 ] && shift
|
||||||
if [ "\$#" -gt 0 ]; then
|
case "$command" in
|
||||||
shift
|
'"${commands[*]:-/}"')
|
||||||
fi
|
eval "$(pyenv "sh-$command" "$@")"
|
||||||
|
|
||||||
case "\$command" in
|
|
||||||
${commands[*]:-/})
|
|
||||||
eval "\$(pyenv "sh-\$command" "\$@")"
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
command pyenv "\$command" "\$@"
|
command pyenv "$command" "$@"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}'
|
||||||
EOS
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,12 +35,11 @@ create_executable() {
|
|||||||
assert_line "command pyenv rehash 2>/dev/null"
|
assert_line "command pyenv rehash 2>/dev/null"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@test "setup shell completions" {
|
@test "setup shell completions" {
|
||||||
root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
|
exec_root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
|
||||||
run pyenv-init - bash
|
run pyenv-init - bash
|
||||||
assert_success
|
assert_success
|
||||||
assert_line "source '${root}/test/../libexec/../completions/pyenv.bash'"
|
assert_line "source '${exec_root}/completions/pyenv.bash'"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "detect parent shell" {
|
@test "detect parent shell" {
|
||||||
@ -63,16 +62,16 @@ OUT
|
|||||||
}
|
}
|
||||||
|
|
||||||
@test "setup shell completions (fish)" {
|
@test "setup shell completions (fish)" {
|
||||||
root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
|
exec_root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
|
||||||
run pyenv-init - fish
|
run pyenv-init - fish
|
||||||
assert_success
|
assert_success
|
||||||
assert_line "source '${root}/test/../libexec/../completions/pyenv.fish'"
|
assert_line "source '${exec_root}/completions/pyenv.fish'"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "fish instructions" {
|
@test "fish instructions" {
|
||||||
run pyenv-init fish
|
run pyenv-init fish
|
||||||
assert [ "$status" -eq 1 ]
|
assert [ "$status" -eq 1 ]
|
||||||
assert_line 'pyenv init - | source'
|
assert_line 'pyenv init - fish | source'
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "shell detection for installer" {
|
@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=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
|
||||||
PATH="${PYENV_TEST_DIR}/bin:$PATH"
|
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="${BATS_TEST_DIRNAME}/libexec:$PATH"
|
||||||
PATH="${PYENV_ROOT}/shims:$PATH"
|
PATH="${PYENV_ROOT}/shims:$PATH"
|
||||||
export PATH
|
export PATH
|
||||||
|
Loading…
x
Reference in New Issue
Block a user