diff --git a/share/chpython/auto.sh b/share/chpython/auto.sh new file mode 100644 index 0000000..5089f7b --- /dev/null +++ b/share/chpython/auto.sh @@ -0,0 +1,33 @@ +unset PYTHON_AUTO_VERSION + +function chpython_auto() { + local dir="$PWD/" version + + until [[ -z "$dir" ]]; do + dir="${dir%/*}" + + if { read -r version < "$dir/.python-version"; } 2>/dev/null || [[ -n "$version" ]]; then + version="${version%%[[:space:]]}" + + if [[ "$version" == "$PYTHON_AUTO_VERSION" ]]; then return + else + PYTHON_AUTO_VERSION="$version" + chpython "$version" + return $? + fi + fi + done + + if [[ -n "$PYTHON_AUTO_VERSION" ]]; then + chpython_reset + unset PYTHON_AUTO_VERSION + fi +} + +if [[ -n "$ZSH_VERSION" ]]; then + if [[ ! "$preexec_functions" == *chpython_auto* ]]; then + preexec_functions+=("chpython_auto") + fi +elif [[ -n "$BASH_VERSION" ]]; then + trap '[[ "$BASH_COMMAND" != "$PROMPT_COMMAND" ]] && chpython_auto' DEBUG +fi diff --git a/share/chpython/chpython.sh b/share/chpython/chpython.sh old mode 100644 new mode 100755 index a99ed0e..801e1c2 --- a/share/chpython/chpython.sh +++ b/share/chpython/chpython.sh @@ -1,94 +1,57 @@ CHPYTHON_VERSION='0.1.0.dev' PYTHONS=() -[ -d "${HOME}/.pythons" ] && PYTHONS+=("${HOME}/.pythons"/*) +for dir in "$PREFIX/opt/pythons" "$HOME/.pythons"; do + [[ -d "$dir" && -n "$(ls -A "$dir")" ]] && PYTHONS+=("$dir"/*) +done +unset dir -function _chpython_exec { - local python - python=$1 - shift - # TODO: Clear path so invoking `chpython 3.5 python -V` when - # $CHPYTHON_VERSION is set to a 2.x Python gives a command not - # found error instead of running $CHPYTHON_VERSION/bin/python. - env PATH="$python/bin:$PATH" $* -} - -function _chpython_reset { +function chpython_reset() { [ -z "$CHPYTHON_ROOT" ] && return - PATH=":$PATH:" - PATH=${PATH//:$CHPYTHON_ROOT\/bin:/:} - PATH=${PATH#:}; PATH=${PATH%:} + + PATH=":$PATH:"; PATH=${PATH//:$CHPYTHON_ROOT\/bin:/:} + PATH="${PATH#:}"; PATH="${PATH%:}" unset CHPYTHON_ROOT hash -r - type python || type python3 } -function _chpython_select { - local dir python match - for dir in ${PYTHONS[@]}; do - dir=${dir%%/} - python=${dir##*/} - case "$python" in - "$1") - # Match using 3-part version number, e.g. `chruby 2.7.10` - match=$dir && break - ;; - "$1"*) - # Match best using 2-part version number, e.g., `chpython 2.7` - match=$dir - ;; - esac - done - echo "$match" -} -function _chpython_use { - if [[ ! -x "$1/bin/python" && ! -x "$1/bin/python3" ]]; then - echo "chpython: neither $1/bin/python nor $1/bin/python3 are executable" >&2 +function _chpython_use() { + if [[ ! -x "$1/bin/python" ]]; then + echo "chpython: $1/bin/python is not executable" >&2 return 1 fi - # TODO: Alias *3 stuff to base name, so, e.g., `python` can be called - # instead of `python3` + [[ -n "$CHPYTHON_ROOT" ]] && chpython_reset - export CHPYTHON_ROOT=$1 + export CHPYTHON_ROOT="$1" export PATH="${CHPYTHON_ROOT}/bin:${PATH}" + local python_version + if [[ -e "$1/bin/python3" ]]; then + PYTHON_VERSION="$($1/bin/python --version)" + else + PYTHON_VERSION="$($1/bin/python --version 2>&1 | awk '{print $2}')" + fi hash -r - type python || type python3 } -function chpython { + +function chpython() { case "$1" in -h|--help) cat <&2 - return 1 - fi - - shift - _chpython_exec $match $* - ;; - system) - _chpython_reset - ;; + system) chpython_reset ;; '') local dir python - for dir in ${PYTHONS[@]}; do - dir="${dir%%/}" - python=${dir##*/} + for dir in "${PYTHONS[@]}"; do + dir="${dir%%/}"; python="${dir##*/}" if [[ "$dir" == "$CHPYTHON_ROOT" ]]; then echo " * ${python}" else @@ -97,15 +60,27 @@ EOS done ;; *) - local match - match=$(_chpython_select $1) + local dir python match + for dir in "${PYTHONS[@]}"; do + dir="${dir%%/}"; python="${dir##*/}" + case "$python" in + "$1") + # Match using 3-part version number, e.g. `chruby 2.7.10` + match="$dir" && break + ;; + "$1"*) + # Match best using 2-part version number, e.g., `chpython 2.7` + match="$dir" + ;; + esac + done if [ -z "$match" ]; then echo "chpython: unknown Python: $1" >&2 return 1 fi shift - _chpython_use $match $* + _chpython_use "$match" ;; esac }