#!/usr/bin/env bash set -eu set -o pipefail 2> /dev/null || true variety="" args="" pre_command="" post_command="" sep="%" stdin_pipe="" function usage { retval="$1" ( echo "$0: --variety var --args args --pre-command cmd --separator % --stdin-pipe cmd" echo "legal varieties:" echo ' 'fast echo ' 'all-cpythons echo ' 'all echo ' 'minimal-a echo ' 'minimal-b echo ' 'just-a-cython ) 1>&2 exit "$retval" } while [ "$#" -ge 1 ] do case "$1" in --separator) sep="$2" shift ;; --variety) variety="$2" shift ;; --args) shift args="$@" break ;; --stdin-pipe) stdin_pipe="$2" shift ;; --pre-command) pre_command="$2" shift ;; --post-command) post_command="$2" shift ;; *) echo "$0: Illegal option: $1" 1>&2 usage 1 ;; esac shift done if [ "$variety" = "" ] then usage 0 fi # About IronPython: # IronPython 2.6 Beta 2 doesn't work with backshift. It's possible FePy # would - it's supposed to have a patched standard library to facilitate # compatibility with the python standard library. # # ipy (IronPython), at least on Ubuntu 11.04, seems to just use the # system's CPython standard library, which results in tracebacks. # # I see no FePy package for Ubuntu, although there was an IronPython # package for Ubuntu 11.04. case "$(uname -s)" in Darwin) echo "$0: Warning: Darwin detected - /usr/bin/python ignored (because the included CPython 2.5.1 was broken in 10.5.8)" 1>&2 usr_bin_python="" ;; *) usr_bin_python=usr-bin-python"$sep"/usr/bin/python ;; esac function list_interpreter { report_any=False report_all=False interpreters="" expected_major="" require_rcpyxm=False while [ "$#" -ge 1 ] do case "$1" in --require-rcpyxm) require_rcm=True ;; --any) report_any=True ;; --all) report_all=True ;; --major) expected_major="$2" shift ;; --interpreters) shift interpreters="$@" # And eat the arguments still in argv while [ "$#" -ge 1 ] do shift done ;; *) echo "$0: list_interprer: Valid options include --any, --all, --interpreters, but not $1" 1>&2 exit 1 ;; esac shift done if [ "$report_any" = True ] then if [ "$report_all" = True ] then echo "$0: list_interprer: --any and -all are mutually exclusive" 1>&2 exit 1 elif [ "$report_all" = False ] then : Good else echo "$0: list_interprer: report_any is True, but report_all is $report_all" 1>&2 exit 1 fi elif [ "$report_any" = False ] then if [ "$report_all" = True ] then : Good elif [ "$report_all" = False ] then echo "$0: list_interprer: You must give exactly one of --any and -all" 1>&2 exit 1 else echo "$0: list_interprer: report_any is False, but report_all is $report_all" 1>&2 exit 1 fi else echo "$0: list_interprer: report_any should be True or False, but is $report_any" 1>&2 exit 1 fi if [ "$interpreters" = "" ] then echo "$0: list_interprer: --interpreters is a required option" 1>&2 exit 1 fi if [ "$expected_major" = "" ] then echo "$0: list_interprer: --major is a required option" 1>&2 exit 1 fi at_least_one_found=False for record in $interpreters do basename=$(set -eu; echo "$record" | awk -F"$sep" ' { print $1 }') interp=$(set -eu; echo "$record" | awk -F"$sep" ' { print $2 }') if [ -e "$interp" ] then actual_major=$(set -eu; "$interp" -c "import sys; print(sys.version_info[0])") actual_minor=$(set -eu; "$interp" -c "import sys; print(sys.version_info[1])") case "$actual_major" in 2) if [ "$actual_minor" -lt 5 ] then # We only support 2.5 and up. 2.4 is too old. continue fi ;; 3) ;; *) # Could be too old, could be too new echo "$0: list_interprer: actual_major is not 2 or 3: $actual_major" 1>&2 exit 1 ;; esac #echo "actual_major is $actual_major, expected_major is $expected_major" 1>&2 if [ "$actual_major" != "$expected_major" ] then continue fi if [ "$require_rcpyxm" = True ] then if ! "$interp" -c 'import rolling_checksum_pyx_mod' > /dev/null 2>&1 then continue fi fi echo "$basename""$sep""$interp" at_least_one_found=True if [ "$report_any" = True ] then return 0 fi fi done if [ "$at_least_one_found" = True ] then return 0 elif [ "$at_least_one_found" = False ] then return 1 else echo "$0: list_interprer: at_least_one_found is neither True nor False: $at_least_one_found" 1>&2 exit 1 fi } function list_compiler { report_any=False report_all=False compilers="" while [ "$#" -ge 1 ] do case "$1" in --any) report_any=True ;; --all) report_all=True ;; --compilers) shift compilers="$@" while [ "$#" -ge 1 ] do shift done break ;; *) echo "$0: list_compiler: Unrecognized option: $1" 1>&2 exit 1 ;; esac shift done if [ "$report_any" = True ] && [ "$report_all" = True ] then echo "$0: list_compiler: --any and --all are mutually exclusive" 1>&2 exit 1 fi if [ "$report_any" = False ] && [ "$report_all" = False ] then echo "$0: list_compiler: You must specify one of --any and --all" 1>&2 exit 1 fi if [ "$compilers" = "" ] then echo "$0: list_compiler: You must specify --compilers" 1>&2 exit 1 fi at_least_one_found=False for record in $compilers do basename=$(echo "$record" | awk -F"$sep" ' { print $1 }') file=$(echo "$record" | awk -F"$sep" ' { print $2 }') if [ -e "$file" ] then at_least_one_found=True echo "$basename$sep$file" if [ "$report_any" = True ] then break fi fi done if [ "$at_least_one_found" = True ] then return 0 elif [ "$at_least_one_found" = False ] then return 1 else echo "$0: list_compiler: \$at_least_one_found has a strange value: $at_least_one_found" 1>&2 exit 1 fi } function list_cython2 { if [ "$1" = --any ] then quantifier="--any" elif [ "$1" = --all ] then quantifier="--all" else echo "$0: list_cython2: \$1 is not --any or --all" 1>&2 exit 1 fi list_compiler "$quantifier" --compilers \ cython2%/usr/local/cpython-2.7/bin/cython \ cython2%/usr/local/cpython-2.6/bin/cython } function list_cython3 { if [ "$1" = --any ] then quantifier="--any" elif [ "$1" = --all ] then quantifier="--all" else echo "$0: list_cython3: \$1 is not --any or --all" 1>&2 exit 1 fi list_compiler "$quantifier" --compilers \ cython3%/usr/local/cpython-3.4/bin/cython \ cython3%/usr/local/cpython-3.3/bin/cython \ cython3%/usr/local/cpython-3.2/bin/cython \ cython3%/usr/local/cpython-3.1/bin/cython \ cython3%/usr/local/cpython-3.0/bin/cython } function list_pypy3 { if [ "$1" = --any ] then quantifier="--any" elif [ "$1" = --all ] then quantifier="--all" else echo "$0: list_pypy3: \$1 is not --any or --all" 1>&2 exit 1 fi # 1.6 was missing os.stat().st_rdev, but pypy-trunk-2011-08-18, which is almost immediately after 1.6's release, # has it again. # This 5.8.0 isn't really 5.8.0 - it's really a trunk with a necessary os.utime() bugfix. list_interpreter "$quantifier" --major 3 --interpreters \ pypy3-6.0.0"$sep"/usr/local/pypy3-6.0.0/bin/pypy3 \ pypy3-5.10.0"$sep"/usr/local/pypy3-5.10.0/bin/pypy3 \ pypy3-5.9.0"$sep"/usr/local/pypy3-5.9.0/bin/pypy3 } function list_pypy2 { if [ "$1" = --any ] then quantifier="--any" elif [ "$1" = --all ] then quantifier="--all" else echo "$0: list_pypy2: \$1 is not --any or --all" 1>&2 exit 1 fi # 1.6 was missing os.stat().st_rdev, but pypy-trunk-2011-08-18, which is almost immediately after 1.6's release, # has it again. list_interpreter "$quantifier" --major 2 --interpreters \ pypy-6.0.0"$sep"/usr/local/pypy-6.0.0/bin/pypy \ pypy-5.10.0"$sep"/usr/local/pypy-5.10.0/bin/pypy \ pypy-5.9.0"$sep"/usr/local/pypy-5.9.0/bin/pypy } function list_cpython2 { if [ "$1" = --any ] then quantifier="--any" elif [ "$1" = --all ] then quantifier="--all" else echo "$0: list_cpython2: \$1 is not --any or --all" 1>&2 exit 1 fi list_interpreter "$quantifier" --major 2 --interpreters \ cpython-2.7"$sep"/usr/local/cpython-2.7/bin/python \ usr-local-bin-python2.7"$sep"/usr/local/bin/python2.7 \ cpython-2.6"$sep"/usr/local/cpython-2.6/bin/python \ usr-local-bin-python2.6"$sep"/usr/local/bin/python2.6 \ usr-local-bin-python2"$sep"/usr/local/bin/python2 \ usr-local-bin-python"$sep"/usr/local/bin/python \ $usr_bin_python \ usr-bin-python2"$sep"/usr/bin/python2 \ boot-common-bin-python"$sep"/boot/common/bin/python } function list_cpython3 { if [ "$1" = --any ] then quantifier="--any" elif [ "$1" = --all ] then quantifier="--all" else echo "$0: list_cpython3: \$1 is not --any or --all" 1>&2 exit 1 fi list_interpreter "$quantifier" --major 3 --interpreters \ cpython-3.7"$sep"/usr/local/cpython-3.7/bin/python3 \ usr-local-bin-python3.7"$sep"/usr/local/bin/python3.7 \ cpython-3.6"$sep"/usr/local/cpython-3.6/bin/python3 \ usr-local-bin-python3.6"$sep"/usr/local/bin/python3.6 \ cpython-3.5"$sep"/usr/local/cpython-3.5/bin/python3 \ usr-local-bin-python3.5"$sep"/usr/local/bin/python3.5 \ cpython-3.4"$sep"/usr/local/cpython-3.4/bin/python3 \ usr-local-bin-python3.4"$sep"/usr/local/bin/python3.4 \ cpython-3.3"$sep"/usr/local/cpython-3.3/bin/python3 \ usr-local-bin-python3.3"$sep"/usr/local/bin/python3.3 \ cpython-3.2"$sep"/usr/local/cpython-3.2/bin/python3 \ usr-local-bin-python3.2"$sep"/usr/local/bin/python3.2 \ cpython-3.1"$sep"/usr/local/cpython-3.1/bin/python3 \ usr-local-bin-python3.1"$sep"/usr/local/bin/python3.1 \ cpython-3.0"$sep"/usr/local/cpython-3.0/bin/python3 \ usr-local-bin-python3.0"$sep"/usr/local/bin/python3.0 \ usr-local-bin-python3"$sep"/usr/local/bin/python3 \ usr-local-bin-python"$sep"/usr/local/bin/python \ $usr_bin_python \ usr-bin-python3"$sep"/usr/bin/python3 \ boot-common-bin-python"$sep"/boot/common/bin/python } function list_jython2 { if [ "$1" = --any ] then quantifier="--any" elif [ "$1" = --all ] then quantifier="--all" else echo "$0: list_jython2: \$1 is not --any or --all" 1>&2 exit 1 fi # Jython 2.7.0 has problems backing up device files, and problems listing directories containing filenames # containing bytes that do not translate to unicode. So we do not support jython 2.x. I'm hoping the # situation will be better in Jython 3.x. return # list_interpreter "$quantifier" --major 2 --interpreters \ # jython-2.5.3"$sep"/usr/local/jython-2.5.3/bin/jython \ # jython-2.7b1"$sep"/usr/local/jython-2.7b1/bin/jython \ # jython-2.7b2"$sep"/usr/local/jython-2.7b2/bin/jython \ # jython-2.7b3"$sep"/usr/local/jython-2.7b3/bin/jython \ # jython-2.7"$sep"/usr/local/jython-2.7/bin/jython } function list_relevant { case "$variety" in all) list_pypy2 --all list_pypy3 --all list_cpython2 --all list_cpython3 --all list_jython2 --all ;; all-cpythons) list_cpython2 --all list_cpython3 --all ;; fast) # Each of these has a side effect of outputting the interpreter path when something is found if list_pypy2 --any then # PyPy2's always the fastest : elif list_pypy3 --any then # PyPy3's probably fast, though it needs some tuning before GA I'm told : elif list_cpython3 --any --require-rcpyxm then # CPython 3 with Cython is next best : elif list_cpython2 --any --require-rcpyxm then # CPython 2 with Cython is next best : elif list_jython2 --any then # Jython is next best - but only if appropriately patched, of course : elif list_cpython2 --any then # CPython 2 is next best : elif list_cpython3 --any then # CPython 3 is next best : else echo "$0: Wow, no python?" 1>&2 exit 1 fi ;; minimal-a) if list_cpython2 --any then : elif list_pypy2 --any then : elif list_jython2 --any then : elif list_cpython3 --any then : elif list_pypy3 --any then : else echo "$0: no minimal-a?" 1>&2 exit 1 fi ;; minimal-b) if list_cpython3 --any then : elif list_pypy3 --any then : elif list_jython2 --any then : elif list_pypy2 --any then : elif list_cpython2 --any then : else echo "$0: no minimal-b" 1>&2 exit 1 fi ;; just-a-cython) if list_cython2 --any then : elif list_cython3 --any then : else echo "$0: No cytthon's found" 1>&2 exit 1 fi ;; *) echo "$0: unrecognized variety: $variety" 1>&2 exit 1 ;; esac } if [ "$args" = "" ] then # just list the possibilities list_relevant || true else # Execute relevant=$(set -eu; list_relevant || true) if [ "$relevant" = "" ] then echo "$0: No relevant interpreters found" 1>&2 exit 1 else for record in $relevant do export basename=$(set -eu; echo "$record" | awk -F"$sep" ' { print $1 }') interp=$(set -eu; echo "$record" | awk -F"$sep" ' { print $2 }') if [ "$pre_command" != "" ] then eval "$pre_command" fi echo "$0: Running with $interp" 1>&2 if [ "$stdin_pipe" = "" ] then eval "$interp" $(set -eu; eval echo "$args") else eval $(echo "$stdin_pipe") | eval "$interp" $(set -eu; eval echo "$args") fi if [ "$post_command" != "" ] then eval "$post_command" fi done fi fi