From 5998f4f7ab12fc0781015ccc0e21ac0978b6c7f4 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Tue, 4 May 2021 04:12:17 +0300 Subject: [PATCH 1/5] Refactoring: make logic more fit for rearrangement With functions, we have more leeway in what to call --- libexec/pyenv-init | 112 +++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 40 deletions(-) diff --git a/libexec/pyenv-init b/libexec/pyenv-init index 7240b4c8..c61c3285 100755 --- a/libexec/pyenv-init +++ b/libexec/pyenv-init @@ -43,7 +43,29 @@ fi root="${0%/*}/.." -if [ -z "$print" ]; then +function main() { + case "$mode" in + "help") + help_ + exit 1 + ;; + "path") + print_path + exit 0 + ;; + "print") + init_dirs + print_env + print_completion + print_shell_function + exit 0 + ;; + esac + # should never get here + exit 2 +} + +function help_() { case "$shell" in bash ) if [ -f "${HOME}/.bashrc" ] && [ ! -f "${HOME}/.bash_profile" ]; then @@ -79,36 +101,41 @@ if [ -z "$print" ]; then esac echo } >&2 +} - exit 1 -fi +function init_dirs() { + mkdir -p "${PYENV_ROOT}/"{shims,versions} +} -mkdir -p "${PYENV_ROOT}/"{shims,versions} +function print_env() { + case "$shell" in + fish ) + echo "set -gx PATH '${PYENV_ROOT}/shims' \$PATH" + echo "set -gx PYENV_SHELL $shell" + ;; + * ) + echo 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' + echo "export PYENV_SHELL=$shell" + ;; + esac +} -case "$shell" in -fish ) - echo "set -gx PATH '${PYENV_ROOT}/shims' \$PATH" - echo "set -gx PYENV_SHELL $shell" -;; -* ) - echo 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' - echo "export PYENV_SHELL=$shell" -;; -esac +function print_completion() { + completion="${root}/completions/pyenv.${shell}" + if [ -r "$completion" ]; then + echo "source '$completion'" + fi -completion="${root}/completions/pyenv.${shell}" -if [ -r "$completion" ]; then - echo "source '$completion'" -fi + if [ -z "$no_rehash" ]; then + echo 'command pyenv rehash 2>/dev/null' + fi +} -if [ -z "$no_rehash" ]; then - echo 'command pyenv rehash 2>/dev/null' -fi - -commands=(`pyenv-commands --sh`) -case "$shell" in -fish ) - cat < Date: Tue, 4 May 2021 20:24:28 +0300 Subject: [PATCH 2/5] Don't print actual PATH in test output --- test/exec.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/exec.bats b/test/exec.bats index 2a7f4856..db78a158 100644 --- a/test/exec.bats +++ b/test/exec.bats @@ -90,7 +90,7 @@ OUT assert_success "${system_python}" } -@test '$PATH is not modified with system Python' { +@test 'PATH is not modified with system Python' { # Create a wrapper executable that verifies PATH. PYENV_VERSION="custom" create_executable "python" '[[ "$PATH" == "${PYENV_TEST_DIR}/root/versions/custom/bin:"* ]] || { echo "unexpected:$PATH"; exit 2;}' From 783870759566a77d09b426e0305bc0993a522765 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Tue, 4 May 2021 04:30:52 +0300 Subject: [PATCH 3/5] Separate startup logic into PATH and the rest PATH manipulation should be done in ~/.profile rather than ~/.*rc since .rc can be sourced multiple times --- README.md | 25 +++++-------------------- libexec/pyenv-init | 43 +++++++++++++++++++++++++++++++++---------- test/init.bats | 8 ++++---- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index add2eefc..b821d602 100644 --- a/README.md +++ b/README.md @@ -208,28 +208,18 @@ easy to fork and contribute any changes back upstream. pyenv repo is cloned and add `$PYENV_ROOT/bin` to your `$PATH` for access to the `pyenv` command-line utility. - - For **bash**: + - For **bash**/**Zsh**: ~~~ bash - echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile - echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile - ~~~ - - - For **Ubuntu Desktop**: - ~~~ bash - echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc - echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc - ~~~ - - - For **Zsh**: - ~~~ zsh - echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc - echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc + echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile + echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile + echo 'eval "$(pyenv init --path)"' >> ~/.profile ~~~ - For **Fish shell**: ~~~ fish set -Ux PYENV_ROOT $HOME/.pyenv set -Ux fish_user_paths $PYENV_ROOT/bin $fish_user_paths + pyenv init --path | source ~~~ - **Proxy note**: If you use a proxy, export `http_proxy` and `https_proxy` too. @@ -239,11 +229,6 @@ easy to fork and contribute any changes back upstream. configuration file since it manipulates `PATH` during the initialization. - For **bash**: - ~~~ bash - echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bash_profile - ~~~ - - - For **Ubuntu Desktop** and **Fedora**: ~~~ bash echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bashrc ~~~ diff --git a/libexec/pyenv-init b/libexec/pyenv-init index c61c3285..60885843 100755 --- a/libexec/pyenv-init +++ b/libexec/pyenv-init @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Summary: Configure the shell environment for pyenv -# Usage: eval "$(pyenv init - [--no-rehash] [])" +# Usage: eval "$(pyenv init [-|--path] [--no-rehash] [])" set -e [ -n "$PYENV_DEBUG" ] && set -x @@ -8,6 +8,7 @@ set -e # Provide pyenv completions if [ "$1" = "--complete" ]; then echo - + echo --path echo --no-rehash echo bash echo fish @@ -16,15 +17,20 @@ if [ "$1" = "--complete" ]; then exit fi -print="" +mode="help" no_rehash="" for args in "$@" do if [ "$args" = "-" ]; then - print=1 + mode="print" shift fi + if [ "$args" = "--path" ]; then + mode="path" + shift + fi + if [ "$args" = "--no-rehash" ]; then no_rehash=1 shift @@ -68,11 +74,7 @@ function main() { function help_() { case "$shell" in bash ) - if [ -f "${HOME}/.bashrc" ] && [ ! -f "${HOME}/.bash_profile" ]; then - profile='~/.bashrc' - else - profile='~/.bash_profile' - fi + profile='~/.bashrc' ;; zsh ) profile='~/.zshrc' @@ -100,6 +102,17 @@ function help_() { ;; esac echo + echo "# And the following to ~/.profile:" + echo + case "$shell" in + fish ) + echo 'pyenv init --path | source' + ;; + * ) + echo 'eval "$(pyenv init --path)"' + ;; + esac + echo } >&2 } @@ -107,14 +120,24 @@ function init_dirs() { mkdir -p "${PYENV_ROOT}/"{shims,versions} } +function print_path() { + # Need to use the login shell rather than the current one + case "$shell" in + fish ) + echo "set -gx PATH '${PYENV_ROOT}/shims' \$PATH" + ;; + * ) + echo 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' + ;; + esac +} + function print_env() { case "$shell" in fish ) - echo "set -gx PATH '${PYENV_ROOT}/shims' \$PATH" echo "set -gx PYENV_SHELL $shell" ;; * ) - echo 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' echo "export PYENV_SHELL=$shell" ;; esac diff --git a/test/init.bats b/test/init.bats index c9fb0a28..bcb937c1 100755 --- a/test/init.bats +++ b/test/init.bats @@ -64,28 +64,28 @@ OUT @test "adds shims to PATH" { export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin" - run pyenv-init - bash + run pyenv-init --path bash assert_success assert_line 0 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' } @test "adds shims to PATH (fish)" { export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin" - run pyenv-init - fish + run pyenv-init --path fish assert_success assert_line 0 "set -gx PATH '${PYENV_ROOT}/shims' \$PATH" } @test "can add shims to PATH more than once" { export PATH="${PYENV_ROOT}/shims:$PATH" - run pyenv-init - bash + run pyenv-init --path bash assert_success assert_line 0 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' } @test "can add shims to PATH more than once (fish)" { export PATH="${PYENV_ROOT}/shims:$PATH" - run pyenv-init - fish + run pyenv-init --path fish assert_success assert_line 0 "set -gx PATH '${PYENV_ROOT}/shims' \$PATH" } From 3e3f40fefcdf2060b421a688168f3dd2f03811ef Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Tue, 4 May 2021 16:59:56 +0300 Subject: [PATCH 4/5] Warn users to add `pyenv init --path` to ~/.profile To facilitate migration --- libexec/pyenv-init | 8 ++++++++ test/init.bats | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/libexec/pyenv-init b/libexec/pyenv-init index 60885843..22e1da02 100755 --- a/libexec/pyenv-init +++ b/libexec/pyenv-init @@ -61,6 +61,7 @@ function main() { ;; "print") init_dirs + warn_path print_env print_completion print_shell_function @@ -132,6 +133,13 @@ function print_path() { esac } +function warn_path() { + if ! perl -ls0x3A -e 'while (<>) { chomp; ($_ eq $d) && exit 0; } exit 1' -- -d="${PYENV_ROOT}/shims" <<<"$PATH" ; then + echo 'echo '\''WARNING: `pyenv init -` no longer sets PATH.'\' + echo 'echo '\''Run `pyenv init` to see the necessary changes to make to your configuration.'\' + fi +} + function print_env() { case "$shell" in fish ) diff --git a/test/init.bats b/test/init.bats index bcb937c1..121c3b62 100755 --- a/test/init.bats +++ b/test/init.bats @@ -90,6 +90,13 @@ OUT assert_line 0 "set -gx PATH '${PYENV_ROOT}/shims' \$PATH" } +@test "prints a warning if shims not in PATH" { + export PATH="$(perl -0x3A -ls -e 'while (<>) { chomp; ($_ ne $d) && print; }' -- -d="${PYENV_ROOT}/shims" <<<"$PATH")" + run pyenv-init - + assert_success + assert_line 0 'echo '\''WARNING: `pyenv init -` no longer sets PATH.'\' +} + @test "outputs sh-compatible syntax" { run pyenv-init - bash assert_success From aab562c696ee7c5cd31a2821a290baaa8fcde7f3 Mon Sep 17 00:00:00 2001 From: Ivan Pozdeev Date: Fri, 7 May 2021 16:21:17 +0300 Subject: [PATCH 5/5] Add a warning about needing to restart the entire login session E.g. for a GUI session, ~/.profile is executed by the GUI login "shell" at its startup so one needs to fully log out and log back in. Before that, the change would only be seen by shells explicitly started as login shells. --- libexec/pyenv-init | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libexec/pyenv-init b/libexec/pyenv-init index 22e1da02..0f06c706 100755 --- a/libexec/pyenv-init +++ b/libexec/pyenv-init @@ -114,6 +114,9 @@ function help_() { ;; esac echo + echo '# Make sure to restart your entire logon session' + echo '# for changes to ~/.profile to take effect.' + echo } >&2 }