From dc7b6abfde3fb322cd716c787a3752359d8c440b Mon Sep 17 00:00:00 2001 From: Yamashita Yuu Date: Sat, 18 Jan 2014 18:00:59 +0900 Subject: [PATCH 1/6] Display messages only on verbose mode --- bin/pyenv-virtualenv | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/bin/pyenv-virtualenv b/bin/pyenv-virtualenv index 6909b17..e820de2 100755 --- a/bin/pyenv-virtualenv +++ b/bin/pyenv-virtualenv @@ -131,7 +131,9 @@ venv() { install_setuptools() { local version="$1" { if [ "${EZ_SETUP+defined}" ] && [ -f "${EZ_SETUP}" ]; then - echo "Installing setuptools from ${EZ_SETUP}..." 1>&2 + if [ -n "$VERBOSE" ]; then + echo "Installing setuptools from ${EZ_SETUP}..." 1>&2 + fi cat "${EZ_SETUP}" else [ -n "${EZ_SETUP_URL}" ] || { @@ -141,7 +143,9 @@ install_setuptools() { EZ_SETUP_URL="https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py" fi } - echo "Installing setuptools from ${EZ_SETUP_URL}..." 1>&2 + if [ -n "$VERBOSE" ]; then + echo "Installing setuptools from ${EZ_SETUP_URL}..." 1>&2 + fi http get "${EZ_SETUP_URL}" fi } | PYENV_VERSION="${version}" pyenv-exec python @@ -150,7 +154,9 @@ install_setuptools() { install_pip() { local version="$1" { if [ "${GET_PIP+defined}" ] && [ -f "${GET_PIP}" ]; then - echo "Installing pip from ${GET_PIP}..." 1>&2 + if [ -n "$VERBOSE" ]; then + echo "Installing pip from ${GET_PIP}..." 1>&2 + fi cat "${GET_PIP}" else [ -n "${GET_PIP_URL}" ] || { @@ -160,7 +166,9 @@ install_pip() { GET_PIP_URL="https://raw.github.com/pypa/pip/master/contrib/get-pip.py" fi } - echo "Installing pip from ${GET_PIP_URL}..." 1>&2 + if [ -n "$VERBOSE" ]; then + echo "Installing pip from ${GET_PIP_URL}..." 1>&2 + fi http get "${GET_PIP_URL}" fi } | PYENV_VERSION="${version}" pyenv-exec python From e7cc57acb8b1211e3781283e6893d8d55a360fd4 Mon Sep 17 00:00:00 2001 From: Yamashita Yuu Date: Sat, 18 Jan 2014 18:01:34 +0900 Subject: [PATCH 2/6] Preserve original IFS --- bin/pyenv-virtualenv | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/pyenv-virtualenv b/bin/pyenv-virtualenv index e820de2..ea12d25 100755 --- a/bin/pyenv-virtualenv +++ b/bin/pyenv-virtualenv @@ -309,9 +309,10 @@ after_virtualenv() { } # Load plugin hooks. -for script in $(pyenv-hooks virtualenv); do - source "$script" -done +OLDIFS="$IFS" +IFS=$'\n' scripts=(`pyenv-hooks virtualenv`) +IFS="$OLDIFS" +for script in "${scripts[@]}"; do source "$script"; done [ -d "${VIRTUALENV_PATH}" ] && PREFIX_EXISTS=1 From 1cbcee3fc8f3256b64e42bf0ab5be251acaa5155 Mon Sep 17 00:00:00 2001 From: Yamashita Yuu Date: Sat, 18 Jan 2014 18:03:14 +0900 Subject: [PATCH 3/6] Add `HAS_VIRTUALENV`, `HAS_PYVENV` and `USE_PYVENV` --- bin/pyenv-virtualenv | 57 ++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/bin/pyenv-virtualenv b/bin/pyenv-virtualenv index ea12d25..50f85f0 100755 --- a/bin/pyenv-virtualenv +++ b/bin/pyenv-virtualenv @@ -111,20 +111,15 @@ usage() { [ -z "$1" ] || exit "$1" } -virtualenv_is_pyvenv() { - # Use pyvenv only if virtualenv is not installed and there is pyvenv - if pyenv-which "virtualenv" 1>/dev/null 2>&1; then - return 1 - else - pyenv-which "pyvenv" 1>/dev/null 2>&1 - fi -} - venv() { - if virtualenv_is_pyvenv; then - pyenv-exec pyvenv "$@" + local args=("$@") + if [ -n "${USE_PYVENV}" ]; then + pyenv-exec pyvenv "${args[@]}" + + local last="${args[${#args[@]}-1]}" + ensurepip "${last##*/}" else - pyenv-exec virtualenv "$@" + pyenv-exec virtualenv "${args[@]}" fi } @@ -174,6 +169,12 @@ install_pip() { } | PYENV_VERSION="${version}" pyenv-exec python } +install_virtualenv() { + local version="$1" + VIRTUALENV_VERSION="==${VIRTUALENV_VERSION}" + PYENV_VERSION="${version}" pyenv-exec pip install $QUIET $VERBOSE "virtualenv${VIRTUALENV_VERSION%==}" +} + ensurepip() { local version="$1" if PYENV_VERSION="${version}" pyenv-exec python -m ensurepip 2>/dev/null; then @@ -272,7 +273,22 @@ UPGRADE_LIST="${TMP}/pyenv-virtualenv.${SEED}.txt" VIRTUALENV_PATH="${PYENV_ROOT}/versions/${VIRTUALENV_NAME}" -if virtualenv_is_pyvenv; then +unset HAS_VIRTUALENV +unset HAS_PYVENV +unset USE_PYVENV + +if pyenv-which "virtualenv" 1>/dev/null 2>&1; then + HAS_VIRTUALENV=1 +fi +if pyenv-which "pyvenv" 1>/dev/null 2>&1; then + HAS_PYVENV=1 +fi +# Use pyvenv only if virtualenv is not installed and there is pyvenv +if [ -n "${HAS_PYVENV}" ] && [ -z "${HAS_VIRTUALENV}" ]; then + USE_PYVENV=1 +fi + +if [ -n "${USE_PYVENV}" ]; then # Unset some arguments not supported by pyvenv unset QUIET unset VERBOSE @@ -281,11 +297,10 @@ if virtualenv_is_pyvenv; then VIRTUALENV_OPTIONS[${#VIRTUALENV_OPTIONS[*]}]="--upgrade" fi else - pyenv-which "virtualenv" 1>/dev/null 2>&1 || { - VIRTUALENV_VERSION="==${VIRTUALENV_VERSION}" - pyenv-exec pip install $QUIET $VERBOSE "virtualenv${VIRTUALENV_VERSION%==}" - pyenv-rehash - } + if [ -z "${HAS_VIRTUALENV}" ]; then + install_virtualenv "${PYENV_VERSION}" + HAS_VIRTUALENV=1 + fi fi # Unset environment variables which starts with `VIRTUALENV_`. @@ -352,11 +367,7 @@ STATUS=0 # change to cache directory to reuse them between invocation. mkdir -p "${PYENV_VIRTUALENV_CACHE_PATH}" cd "${PYENV_VIRTUALENV_CACHE_PATH}" -venv $QUIET $VERBOSE "${VIRTUALENV_OPTIONS[@]}" "${VIRTUALENV_PATH}" && { - if virtualenv_is_pyvenv; then - ensurepip "${VIRTUALENV_NAME}" - fi -} 1>&2 || STATUS="$?" +venv $QUIET $VERBOSE "${VIRTUALENV_OPTIONS[@]}" "${VIRTUALENV_PATH}" || STATUS="$?" ## Migrate previously installed packages from requirements.txt if [ -n "$UPGRADE" ]; then From 2aa207ede0ba30626e62a4e385ff8b8f2da4f15e Mon Sep 17 00:00:00 2001 From: Yamashita Yuu Date: Sat, 18 Jan 2014 18:04:59 +0900 Subject: [PATCH 4/6] Add `prepare_upgrade` and `upgrade` --- bin/pyenv-virtualenv | 46 +++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/bin/pyenv-virtualenv b/bin/pyenv-virtualenv index 50f85f0..1cfd449 100755 --- a/bin/pyenv-virtualenv +++ b/bin/pyenv-virtualenv @@ -195,6 +195,32 @@ ensurepip() { fi } +prepare_upgrade() { + local version="$1" + local prefix="$2" + PYENV_VERSION="${version}" pyenv-exec pip freeze >"${UPGRADE_LIST}" + mv -f "${prefix}" "${UPGRADE_PATH}" +} + +upgrade() { + local version="$1" + local prefix="$2" + ## Migrate previously installed packages from requirements.txt + if ! PYENV_VERSION="${version}" pyenv-exec pip install $QUIET $VERBOSE --requirement "${UPGRADE_LIST}"; then + { echo + echo "UPGRADE FAILED" + echo + echo "Inspect or clean up the original tree at ${UPGRADE_PATH}" + echo + echo "Package list:" + cat "${UPGRADE_LIST}" + } 1>&2 + return 1 + fi + rm -f "${UPGRADE_LIST}" + rm -fr "${UPGRADE_PATH}" +} + PYENV_VIRTUALENV_ROOT="$(abs_dirname "$0")/.." if [ -z "${PYENV_VIRTUALENV_CACHE_PATH}" ]; then PYENV_VIRTUALENV_CACHE_PATH="${PYTHON_BUILD_CACHE_PATH:-${PYENV_ROOT}/cache}" @@ -346,8 +372,7 @@ if [ -d "${VIRTUALENV_PATH}/bin" ]; then fi if [ -n "$UPGRADE" ]; then - PYENV_VERSION="${VIRTUALENV_NAME}" pyenv-exec pip freeze >"${UPGRADE_LIST}" - mv -f "${VIRTUALENV_PATH}" "${UPGRADE_PATH}" + prepare_upgrade "${VIRTUALENV_NAME}" "${VIRTUALENV_PATH}" fi fi @@ -371,22 +396,7 @@ venv $QUIET $VERBOSE "${VIRTUALENV_OPTIONS[@]}" "${VIRTUALENV_PATH}" || STATUS=" ## Migrate previously installed packages from requirements.txt if [ -n "$UPGRADE" ]; then - UPGRADE_STATUS=0 - PYENV_VERSION="${VIRTUALENV_NAME}" pyenv-exec pip install $QUIET $VERBOSE --requirement "${UPGRADE_LIST}" || UPGRADE_STATUS=$? - if [ "$UPGRADE_STATUS" == "0" ]; then - rm -f "${UPGRADE_LIST}" - rm -fr "${UPGRADE_PATH}" - else - { echo - echo "UPGRADE FAILED" - echo - echo "Inspect or clean up the original tree at ${UPGRADE_PATH}" - echo - echo "Package list:" - cat "${UPGRADE_LIST}" - } 1>&2 - STATUS="$UPGRADE_STATUS" - fi + upgrade "${VIRTUALENV_NAME}" "${VIRTUALENV_PATH}" || STATUS="$?" fi # Execute `after_virtualenv` hooks From dcd3b12a97af02746ed8fcef029bdac09502e6d9 Mon Sep 17 00:00:00 2001 From: Yamashita Yuu Date: Sat, 18 Jan 2014 10:39:52 +0900 Subject: [PATCH 5/6] Add unittest --- test/hooks.bats | 33 +++++++++++ test/installer.bats | 45 +++++++++++++++ test/pyvenv.bats | 128 ++++++++++++++++++++++++++++++++++++++++++ test/stubs/stub | 109 +++++++++++++++++++++++++++++++++++ test/test_helper.bash | 98 ++++++++++++++++++++++++++++++++ test/virtualenv.bats | 94 +++++++++++++++++++++++++++++++ 6 files changed, 507 insertions(+) create mode 100644 test/hooks.bats create mode 100644 test/installer.bats create mode 100644 test/pyvenv.bats create mode 100755 test/stubs/stub create mode 100644 test/test_helper.bash create mode 100644 test/virtualenv.bats diff --git a/test/hooks.bats b/test/hooks.bats new file mode 100644 index 0000000..e96a2f8 --- /dev/null +++ b/test/hooks.bats @@ -0,0 +1,33 @@ +#!/usr/bin/env bats + +load test_helper + +setup() { + export PYENV_ROOT="${TMP}/pyenv" + export HOOK_PATH="${TMP}/i has hooks" + mkdir -p "$HOOK_PATH" +} + +@test "pyenv-virtualenv hooks" { + cat > "${HOOK_PATH}/virtualenv.bash" <&${!_STUB_DEBUG} +fi + +[ -e "${!_STUB_PLAN}" ] || exit 1 +[ -n "${!_STUB_RUN}" ] || eval "${_STUB_RUN}"="${TMPDIR}/${program}-stub-run" + + +# Initialize or load the stub run information. +eval "${_STUB_INDEX}"=1 +eval "${_STUB_RESULT}"=0 +[ ! -e "${!_STUB_RUN}" ] || source "${!_STUB_RUN}" + + +# Loop over each line in the plan. +index=0 +while IFS= read -r line; do + index=$(($index + 1)) + + if [ -z "${!_STUB_END}" ] && [ $index -eq "${!_STUB_INDEX}" ]; then + # We found the plan line we're interested in. + # Start off by assuming success. + result=0 + + # Split the line into an array of arguments to + # match and a command to run to produce output. + command=" $line" + if [ "$command" != "${command/ : }" ]; then + patterns="${command%% : *}" + command="${command#* : }" + fi + + # Naively split patterns by whitespace for now. + # In the future, use a sed script to split while + # respecting quoting. + set -f + patterns=($patterns) + set +f + arguments=("$@") + + # Match the expected argument patterns to actual + # arguments. + for (( i=0; i<${#patterns[@]}; i++ )); do + pattern="${patterns[$i]}" + argument="${arguments[$i]}" + + case "$argument" in + $pattern ) ;; + * ) result=1 ;; + esac + done + + # If the arguments matched, evaluate the command + # in a subshell. Otherwise, log the failure. + if [ $result -eq 0 ] ; then + set +e + ( eval "$command" ) + status="$?" + set -e + else + eval "${_STUB_RESULT}"=1 + fi + fi +done < "${!_STUB_PLAN}" + + +if [ -n "${!_STUB_END}" ]; then + # Clean up the run file. + rm -f "${!_STUB_RUN}" + + # If the number of lines in the plan is larger than + # the requested index, we failed. + if [ $index -ge "${!_STUB_INDEX}" ]; then + eval "${_STUB_RESULT}"=1 + fi + + # Return the result. + exit "${!_STUB_RESULT}" + +else + # If the requested index is larger than the number + # of lines in the plan file, we failed. + if [ "${!_STUB_INDEX}" -gt $index ]; then + eval "${_STUB_RESULT}"=1 + fi + + # Write out the run information. + { echo "${_STUB_INDEX}=$((${!_STUB_INDEX} + 1))" + echo "${_STUB_RESULT}=${!_STUB_RESULT}" + } > "${!_STUB_RUN}" + + exit "$status" + +fi diff --git a/test/test_helper.bash b/test/test_helper.bash new file mode 100644 index 0000000..f6e9a07 --- /dev/null +++ b/test/test_helper.bash @@ -0,0 +1,98 @@ +export TMP="$BATS_TEST_DIRNAME/tmp" + +PATH=/usr/bin:/usr/sbin:/bin/:/sbin +PATH="$BATS_TEST_DIRNAME/../bin:$PATH" +PATH="$TMP/bin:$PATH" +export PATH + +teardown() { + rm -fr "$TMP"/* +} + +stub() { + local program="$1" + local prefix="$(echo "$program" | tr a-z- A-Z_)" + shift + + export "${prefix}_STUB_PLAN"="${TMP}/${program}-stub-plan" + export "${prefix}_STUB_RUN"="${TMP}/${program}-stub-run" + export "${prefix}_STUB_END"= + + mkdir -p "${TMP}/bin" + ln -sf "${BATS_TEST_DIRNAME}/stubs/stub" "${TMP}/bin/${program}" + + touch "${TMP}/${program}-stub-plan" + for arg in "$@"; do printf "%s\n" "$arg" >> "${TMP}/${program}-stub-plan"; done +} + +unstub() { + local program="$1" + local prefix="$(echo "$program" | tr a-z- A-Z_)" + local path="${TMP}/bin/${program}" + + export "${prefix}_STUB_END"=1 + + local STATUS=0 + "$path" || STATUS="$?" + + rm -f "$path" + rm -f "${TMP}/${program}-stub-plan" "${TMP}/${program}-stub-run" + return "$STATUS" +} + +assert() { + if ! "$@"; then + flunk "failed: $@" + fi +} + +flunk() { + { if [ "$#" -eq 0 ]; then cat - + else echo "$@" + fi + } | sed "s:${TMP}:\${TMP}:g" >&2 + return 1 +} + +assert_success() { + if [ "$status" -ne 0 ]; then + { echo "command failed with exit status $status" + echo "output: $output" + } | flunk + elif [ "$#" -gt 0 ]; then + assert_output "$1" + fi +} + +assert_failure() { + if [ "$status" -eq 0 ]; then + flunk "expected failed exit status" + elif [ "$#" -gt 0 ]; then + assert_output "$1" + fi +} + +assert_equal() { + if [ "$1" != "$2" ]; then + { echo "expected: $1" + echo "actual: $2" + } | flunk + fi +} + +assert_output() { + local expected + if [ $# -eq 0 ]; then expected="$(cat -)" + else expected="$1" + fi + assert_equal "$expected" "$output" +} + +assert_output_contains() { + local expected="$1" + echo "$output" | grep -F "$expected" >/dev/null || { + { echo "expected output to contain $expected" + echo "actual: $output" + } | flunk + } +} diff --git a/test/virtualenv.bats b/test/virtualenv.bats new file mode 100644 index 0000000..0f6d098 --- /dev/null +++ b/test/virtualenv.bats @@ -0,0 +1,94 @@ +#!/usr/bin/env bats + +load test_helper + +setup() { + export PYENV_ROOT="${TMP}/pyenv" +} + +stub_pyenv() { + export PYENV_VERSION="$1" + stub pyenv-prefix " : echo '${PYENV_ROOT}/versions/\${PYENV_VERSION}'" + stub pyenv-which "virtualenv : echo '${PYENV_ROOT}/versions/bin/virtualenv'" \ + "pyvenv : false" + stub pyenv-hooks "virtualenv : echo" + stub pyenv-rehash " : echo rehashed" +} + +unstub_pyenv() { + unset PYENV_VERSION + unstub pyenv-prefix + unstub pyenv-which + unstub pyenv-hooks + unstub pyenv-rehash +} + +@test "create virtualenv from given version" { + stub_pyenv "3.2.1" + stub pyenv-exec "echo PYENV_VERSION=\${PYENV_VERSION} \"\$@\"" + + run pyenv-virtualenv "3.2.1" "venv" + + unstub_pyenv + unstub pyenv-exec + + assert_success + assert_output < Date: Sat, 18 Jan 2014 18:21:01 +0900 Subject: [PATCH 6/6] Add .travis.yml --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..1eaa4a9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +install: git clone https://github.com/sstephenson/bats.git +script: bats/bin/bats --tap test +language: c +notifications: + email: + on_success: never