diff --git a/bin/pyenv-sh-activate b/bin/pyenv-sh-activate index 323c1b1..08c07c9 100755 --- a/bin/pyenv-sh-activate +++ b/bin/pyenv-sh-activate @@ -62,13 +62,43 @@ if [ "${#versions[@]}" -gt 1 ]; then exit 1 fi -if ! pyenv-virtualenv-prefix "${versions}" 1>/dev/null 2>&1; then - [ -n "$NOERROR" ] || echo "pyenv-virtualenv: version \`${versions}' is not a virtualenv" 1>&2 - echo "false" - exit 1 +if pyenv-prefix "${versions}" 1>/dev/null 2>&1; then + if ! pyenv-virtualenv-prefix "${versions}" 1>/dev/null 2>&1; then + [ -n "$NOERROR" ] || echo "pyenv-virtualenv: version \`${versions}' is not a virtualenv" 1>&2 + echo "false" + exit 1 + fi +else + version="$(pyenv-version-name)" + if [[ "${versions}" == "root" ]]; then + versions="${version%/envs/*}" + else + versions="${version%/envs/*}/envs/${versions}" + fi + if ! pyenv-virtualenv-prefix "${versions}" 1>/dev/null 2>&1; then + [ -n "$NOERROR" ] || echo "pyenv-virtualenv: version \`${versions}' is not an environment of anaconda/miniconda" 1>&2 + echo "false" + exit 1 + fi fi shell="${PYENV_SHELL:-${SHELL##*/}}" +prefix="$(pyenv-prefix "${versions}")" + +unset conda_env + +if [ -f "${prefix}/bin/conda" ]; then + if [[ "$shell" != "bash" ]] && [[ "$shell" != "zsh" ]]; then + [ -n "$NOERROR" ] || echo "pyenv-virtualenv: Only bash and zsh are supported by Anaconda/Miniconda" 1>&2 + echo "false" + exit 1 + fi + if [[ "${prefix}" != "${prefix%/envs/*}" ]]; then + conda_env="${prefix##*/envs/}" + else + conda_env="root" + fi +fi # Display setup instruction, if pyenv-virtualenv has not been initialized. # if 'pyenv virtualenv-init -' is not found in "$profile" @@ -94,20 +124,29 @@ if [ -z "$no_shell" ]; then esac fi -prefix="$(pyenv-prefix "${versions}")" -case "$shell" in -fish ) +if [ -n "${conda_env}" ]; then + # anaconda/miniconda cat </dev/null 2>&1; then" - ;; -esac - prefix="${PYENV_ACTIVATE:-${VIRTUAL_ENV}}" +unset conda_env + +if [ -f "${prefix}/bin/conda" ]; then + if [[ "$shell" != "bash" ]] && [[ "$shell" != "zsh" ]]; then + [ -n "$NOERROR" ] || echo "pyenv-virtualenv: Only bash and zsh are supported by Anaconda/Miniconda" 1>&2 + echo "false" + exit 1 + fi + if [[ "${prefix}" != "${prefix%/envs/*}" ]]; then + conda_env="${prefix##*/envs/}" + else + conda_env="root" + fi +fi + +if [ -n "${conda_env}" ]; then + echo "if [ -f \"${prefix%/envs/*}/bin/deactivate\" ]; then" +else + case "$shell" in + fish ) + echo "if functions -q deactivate;" + ;; + * ) + echo "if declare -f deactivate 1>/dev/null 2>&1; then" + ;; + esac +fi + if [ -n "$VERBOSE" ]; then echo " echo \"pyenv-virtualenv: deactivate ${prefix##*/}\" 1>&2;" fi @@ -57,24 +76,33 @@ if [ -n "${PYENV_ACTIVATE_SHELL}" ]; then esac fi -case "$shell" in -fish ) +if [ -n "${conda_env}" ]; then cat <&2;" diff --git a/bin/pyenv-virtualenv-init b/bin/pyenv-virtualenv-init index e1cd065..ab0110e 100755 --- a/bin/pyenv-virtualenv-init +++ b/bin/pyenv-virtualenv-init @@ -115,21 +115,21 @@ if [[ "$shell" != "fish" ]]; then cat </dev/null || true)" = "system" ]; then - pyenv deactivate --no-error --verbose + eval "\$(pyenv sh-deactivate --no-error --verbose)" unset PYENV_DEACTIVATE return 0 fi if [ "\$PYENV_ACTIVATE" != "\$(pyenv prefix 2>/dev/null || true)" ]; then - if pyenv deactivate --no-error --verbose; then + if eval "\$(pyenv sh-deactivate --no-error --verbose)"; then unset PYENV_DEACTIVATE - pyenv activate --no-error --verbose || unset PYENV_DEACTIVATE + eval "\$(pyenv sh-activate --no-error --verbose)" || unset PYENV_DEACTIVATE else - pyenv activate --no-error --verbose + eval "\$(pyenv sh-activate --no-error --verbose)" fi fi else if [ -z "\$VIRTUAL_ENV" ] && [ "\$PYENV_DEACTIVATE" != "\$(pyenv prefix 2>/dev/null || true)" ]; then - pyenv activate --no-error --verbose || true + eval "\$(pyenv sh-activate --no-error --verbose)" || true fi fi }; diff --git a/bin/pyenv-virtualenv-prefix b/bin/pyenv-virtualenv-prefix index a762498..858ff72 100755 --- a/bin/pyenv-virtualenv-prefix +++ b/bin/pyenv-virtualenv-prefix @@ -31,7 +31,8 @@ base_prefix() { # pyvenv } VIRTUALENV_PREFIX_PATHS=() -for version in "${versions[@]}"; do +for version_string in "${versions[@]}"; do + version="${version_string%%/*}" if [ "$version" = "system" ]; then echo "pyenv-virtualenv: version \`${version}' is not a virtualenv" 1>&2 exit 1 @@ -40,8 +41,17 @@ for version in "${versions[@]}"; do if [ -f "${PREFIX}/bin/activate" ]; then # Anaconda has `activate` script nevertheless it is not a virtual environment (#65) if [ -f "${PREFIX}/bin/conda" ]; then - echo "pyenv-virtualenv: version \`${version}' is an anaconda/miniconda" 1>&2 - exit 1 + if [[ "${version_string}" != "${version_string%/envs/*}" ]]; then + conda_env="${version_string##*/envs/}" + if [ -f "${PREFIX}/envs/${conda_env}/bin/conda" ]; then + VIRTUALENV_PREFIX_PATHS=("${VIRTUALENV_PREFIX_PATHS[@]}" "${PREFIX}") + else + echo "pyenv-virtualenv: version \`${version_string}' is not an environment of anaconda/miniconda" 1>&2 + exit 1 + fi + else + VIRTUALENV_PREFIX_PATHS=("${VIRTUALENV_PREFIX_PATHS[@]}" "${PREFIX}") + fi else VIRTUALENV_PREFIX_PATH="$(real_prefix "${version}" || base_prefix "${version}" || true)" VIRTUALENV_PREFIX_PATHS=("${VIRTUALENV_PREFIX_PATHS[@]}" "$VIRTUALENV_PREFIX_PATH") diff --git a/bin/pyenv-virtualenvs b/bin/pyenv-virtualenvs index 614299c..6489565 100755 --- a/bin/pyenv-virtualenvs +++ b/bin/pyenv-virtualenvs @@ -51,6 +51,15 @@ for version in $(pyenv-versions --bare); do virtualenv_prefix="$(pyenv-virtualenv-prefix "${version}" 2>/dev/null || true)" if [ -d "${virtualenv_prefix}" ]; then print_version "${version}" " (created from ${virtualenv_prefix})" + prefix="$(pyenv-prefix "${version}")" + if [ -f "${prefix}/bin/conda" ]; then + # envs of anaconda/miniconda + shopt -s nullglob + for conda_env in "${prefix}/envs/"*; do + print_version "${version##*/}${conda_env#${prefix}}" " (created from ${prefix})" + done + shopt -u nullglob + fi fi fi done diff --git a/test/activate.bats b/test/activate.bats index 897f189..8823749 100644 --- a/test/activate.bats +++ b/test/activate.bats @@ -13,6 +13,7 @@ setup() { stub pyenv-version-name "echo venv" stub pyenv-virtualenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" + stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" PYENV_SHELL="bash" PYENV_VERSION="venv" run pyenv-sh-activate @@ -34,6 +35,7 @@ EOS stub pyenv-version-name "echo venv" stub pyenv-virtualenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" + stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" PYENV_SHELL="bash" PYENV_VERSION="venv" run pyenv-sh-activate --verbose @@ -56,6 +58,7 @@ EOS stub pyenv-version-name "echo venv" stub pyenv-virtualenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" + stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" PYENV_SHELL="bash" PYENV_VERSION="venv" run pyenv-sh-activate @@ -84,6 +87,7 @@ EOS stub pyenv-version-name "echo venv" stub pyenv-virtualenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" + stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" PYENV_SHELL="fish" PYENV_VERSION="venv" run pyenv-sh-activate @@ -105,6 +109,7 @@ EOS stub pyenv-version-name "echo venv" stub pyenv-virtualenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" + stub pyenv-prefix "venv : echo \"${PYENV_ROOT}/versions/venv\"" PYENV_SHELL="fish" PYENV_VERSION="venv" run pyenv-sh-activate @@ -132,6 +137,7 @@ EOS stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" + stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" PYENV_SHELL="bash" PYENV_VERSION="venv" run pyenv-sh-activate "venv27" @@ -153,6 +159,7 @@ EOS stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" + stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" PYENV_SHELL="bash" PYENV_VERSION="venv" run pyenv-sh-activate "venv27" @@ -179,6 +186,7 @@ EOS stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" + stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" PYENV_SHELL="fish" PYENV_VERSION="venv" run pyenv-sh-activate "venv27" @@ -200,6 +208,7 @@ EOS stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" + stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/venv27\"" PYENV_SHELL="fish" PYENV_VERSION="venv" run pyenv-sh-activate "venv27" @@ -232,10 +241,12 @@ EOS @test "should fail if the version is not a virtualenv" { stub pyenv-virtualenv-prefix "3.3.3 : false" + stub pyenv-prefix "3.3.3 : echo \"${PYENV_ROOT}/versions/3.3.3\"" run pyenv-sh-activate "3.3.3" unstub pyenv-virtualenv-prefix + unstub pyenv-prefix assert_failure assert_output <&2; + false; +fi; +EOS +} + +@test "deactivate conda root (fish)" { + export PYENV_ACTIVATE="${PYENV_ROOT}/versions/anaconda-2.3.0" + export PYENV_ACTIVATE_SHELL= + + create_conda "anaconda-2.3.0" + + PYENV_SHELL="fish" run pyenv-sh-deactivate + + assert_failure + assert_output <&2; + false; +fi; +EOS +} diff --git a/test/conda-virtualenv-prefix.bats b/test/conda-virtualenv-prefix.bats new file mode 100644 index 0000000..d7a928b --- /dev/null +++ b/test/conda-virtualenv-prefix.bats @@ -0,0 +1,41 @@ +#!/usr/bin/env bats + +load test_helper + +setup() { + export PYENV_ROOT="${TMP}/pyenv" +} + +@test "display conda root" { + create_conda "anaconda-2.3.0" + + stub pyenv-version-name "echo anaconda-2.3.0" + stub pyenv-prefix "anaconda-2.3.0 : echo \"${PYENV_ROOT}/versions/anaconda-2.3.0\"" + + PYENV_VERSION="anaconda-2.3.0" run pyenv-virtualenv-prefix + + unstub pyenv-version-name + unstub pyenv-prefix + + assert_success + assert_output < ${BATS_TEST_DIRNAME}/script.sh - chmod +x ${BATS_TEST_DIRNAME}/script.sh - run ${BATS_TEST_DIRNAME}/script.sh + printf '#!/bin/sh\necho "$(pyenv-virtualenv-init -)"' > "${TMP}/script.sh" + chmod +x ${TMP}/script.sh + run ${TMP}/script.sh assert_success assert_output_contains_not ' PROMPT_COMMAND="_pyenv_virtualenv_hook;$PROMPT_COMMAND";' + rm -f "${TMP}/script.sh" } @test "detect parent shell from script (bash)" { unset PYENV_SHELL - printf '#!/bin/bash\necho "$(pyenv-virtualenv-init -)"' > ${BATS_TEST_DIRNAME}/script.sh - chmod +x ${BATS_TEST_DIRNAME}/script.sh - run ${BATS_TEST_DIRNAME}/script.sh + printf '#!/bin/bash\necho "$(pyenv-virtualenv-init -)"' > "${TMP}/script.sh" + chmod +x ${TMP}/script.sh + run ${TMP}/script.sh assert_success assert_output_contains ' PROMPT_COMMAND="_pyenv_virtualenv_hook;$PROMPT_COMMAND";' + rm -f "${TMP}/script.sh" } @test "sh-compatible instructions" { @@ -51,21 +53,21 @@ export PYENV_VIRTUALENV_INIT=1; _pyenv_virtualenv_hook() { if [ -n "\$PYENV_ACTIVATE" ]; then if [ "\$(pyenv version-name 2>/dev/null || true)" = "system" ]; then - pyenv deactivate --no-error --verbose + eval "\$(pyenv sh-deactivate --no-error --verbose)" unset PYENV_DEACTIVATE return 0 fi if [ "\$PYENV_ACTIVATE" != "\$(pyenv prefix 2>/dev/null || true)" ]; then - if pyenv deactivate --no-error --verbose; then + if eval "\$(pyenv sh-deactivate --no-error --verbose)"; then unset PYENV_DEACTIVATE - pyenv activate --no-error --verbose || unset PYENV_DEACTIVATE + eval "\$(pyenv sh-activate --no-error --verbose)" || unset PYENV_DEACTIVATE else - pyenv activate --no-error --verbose + eval "\$(pyenv sh-activate --no-error --verbose)" fi fi else if [ -z "\$VIRTUAL_ENV" ] && [ "\$PYENV_DEACTIVATE" != "\$(pyenv prefix 2>/dev/null || true)" ]; then - pyenv activate --no-error --verbose || true + eval "\$(pyenv sh-activate --no-error --verbose)" || true fi fi }; @@ -113,21 +115,21 @@ export PYENV_VIRTUALENV_INIT=1; _pyenv_virtualenv_hook() { if [ -n "\$PYENV_ACTIVATE" ]; then if [ "\$(pyenv version-name 2>/dev/null || true)" = "system" ]; then - pyenv deactivate --no-error --verbose + eval "\$(pyenv sh-deactivate --no-error --verbose)" unset PYENV_DEACTIVATE return 0 fi if [ "\$PYENV_ACTIVATE" != "\$(pyenv prefix 2>/dev/null || true)" ]; then - if pyenv deactivate --no-error --verbose; then + if eval "\$(pyenv sh-deactivate --no-error --verbose)"; then unset PYENV_DEACTIVATE - pyenv activate --no-error --verbose || unset PYENV_DEACTIVATE + eval "\$(pyenv sh-activate --no-error --verbose)" || unset PYENV_DEACTIVATE else - pyenv activate --no-error --verbose + eval "\$(pyenv sh-activate --no-error --verbose)" fi fi else if [ -z "\$VIRTUAL_ENV" ] && [ "\$PYENV_DEACTIVATE" != "\$(pyenv prefix 2>/dev/null || true)" ]; then - pyenv activate --no-error --verbose || true + eval "\$(pyenv sh-activate --no-error --verbose)" || true fi fi }; diff --git a/test/test_helper.bash b/test/test_helper.bash index 3e0c987..7cdb8b4 100644 --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -116,3 +116,19 @@ create_executable() { remove_executable() { rm -f "${PYENV_ROOT}/versions/$1/bin/$2" } + +create_conda() { + local version="$1" + shift 1 + mkdir -p "${PYENV_ROOT}/versions/$version/bin" + touch "${PYENV_ROOT}/versions/$version/bin/activate" + touch "${PYENV_ROOT}/versions/$version/bin/conda" + chmod +x "${PYENV_ROOT}/versions/$version/bin/conda" + local conda_env + for conda_env; do + mkdir -p "${PYENV_ROOT}/versions/$version/envs/$conda_env/bin" + touch "${PYENV_ROOT}/versions/$version/envs/$conda_env/bin/activate" + touch "${PYENV_ROOT}/versions/$version/envs/$conda_env/bin/conda" + chmod +x "${PYENV_ROOT}/versions/$version/envs/$conda_env/bin/conda" + done +} diff --git a/test/virtualenvs.bats b/test/virtualenvs.bats index 80be0d4..62cd813 100644 --- a/test/virtualenvs.bats +++ b/test/virtualenvs.bats @@ -17,12 +17,15 @@ setup() { stub pyenv-virtualenv-prefix "3.3.3 : false" stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/2.7.6\"" stub pyenv-virtualenv-prefix "venv33 : echo \"${PYENV_ROOT}/versions/3.3.3\"" + stub pyenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/2.7.6\"" + stub pyenv-prefix "venv33 : echo \"${PYENV_ROOT}/versions/3.3.3\"" run pyenv-virtualenvs unstub pyenv-version-name unstub pyenv-versions unstub pyenv-virtualenv-prefix + unstub pyenv-prefix assert_success assert_output <