# Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Id: $ DESCRIPTION="Manage active Python interpreter" MAINTAINER="python@gentoo.org" SVN_DATE='$Date$' VERSION=$(svn_date_to_version "${SVN_DATE}" ) ENV_D_PATH="${EROOT%/}/etc/env.d" INTERPRETER_PATH="${EROOT%/}/usr/bin/" MAN_PATH="${EROOT%/}/usr/share/man/man1/" PYTHON_INTERPRETERS_GROUP="" # Find a list of Python versions find_targets() { local interpreter interpreters="python?.?@EXEEXT@" if [[ "${PYTHON_INTERPRETERS_GROUP}" == "2" ]]; then interpreters="python2.?@EXEEXT@" elif [[ "${PYTHON_INTERPRETERS_GROUP}" == "3" ]]; then interpreters="python3.?@EXEEXT@" fi # Think twice before adding jython to this list. /usr/bin/jython # is a bash wrapper that calls java-config, which is a Python # script, so you need a valid /usr/bin/python to start jython. for interpreter in "${INTERPRETER_PATH}"${interpreters}; do if [[ -f "${interpreter}" ]]; then echo ${interpreter#${INTERPRETER_PATH}} fi done } set_python_subver() { local target=${1} local subver=${target%.*} mkdir -p "${ENV_D_PATH}/python" echo "${target}" > "${ENV_D_PATH}/python/${subver}" } set_python() { local target="${1}" mkdir -p "${ENV_D_PATH}/python" echo "${target}" > "${ENV_D_PATH}/python/config" } # Try to remove python and python.1 symlinks remove_symlinks() { local symlink symlink_target symlink_target_found if [[ "${SET_MAIN_ACTIVE_PYTHON_INTERPRETER}" == "1" ]]; then rm -f "${MAN_PATH}"python.1{,.gz,.bz2,.lzma,.xz,.lz} &> /dev/null || return 1 fi # Files of Mac OS X framework rm -f "${INTERPRETER_PATH%/bin/}/lib/Python.framework}"/{Headers,Python,Resources} } # Set a man page symlink set_man_symlink() { local target="${1}" x extension for x in ".1" ".1.bz2" ".1.gz" ".1.lzma" ".1.xz" ".1.lz"; do if [[ -e "${MAN_PATH}${target}${x}" ]]; then extension="${x}" break fi done if [[ -z "${extension}" ]]; then echo "Couldn't find a man page for ${target}; skipping." 1>&2 return 1 fi pushd "${MAN_PATH}" 1> /dev/null ln -nfs "${target}${extension}" "python${extension}" popd 1> /dev/null } # Set python-config script and appropriate symlinks set_scripts_and_symlinks() { local target="${1}" targets=($(find_targets)) if is_number "${target}" && [[ ${target} -ge 1 ]]; then target=${targets[$((${target} - 1))]} fi if ! has ${target} "${targets[@]}"; then die -q "Invalid target ${target}" fi if [[ -f "${INTERPRETER_PATH}${target}" ]]; then if ! remove_symlinks; then die -q "Cannot remove symlinks" fi if [[ "${SET_MAIN_ACTIVE_PYTHON_INTERPRETER}" == "1" ]]; then set_man_symlink "${target}" fi pushd "${INTERPRETER_PATH}" 1> /dev/null set_python_subver "${target}" if [[ "${SET_MAIN_ACTIVE_PYTHON_INTERPRETER}" == "1" ]]; then set_python "${target}" # Files of Mac OS X framework local framework_dir="${INTERPRETER_PATH%/bin/}/lib/Python.framework" if [[ -d "${framework_dir}" ]]; then local version="${target#python}" pushd "${framework_dir}" 1> /dev/null ln -nfs "Versions/${version}/Headers" ln -nfs "Versions/${version}/Python" ln -nfs "Versions/${version}/Resources" popd 1> /dev/null fi fi popd 1> /dev/null else die -q "Target \"${1}\" doesn't appear to be valid!" fi } # Set the content of /etc/env.d/65python-docs set_python_docs() { local path target="${1#python}" variable rm -f "${ENV_D_PATH}/65python-docs" if [[ -f "${ENV_D_PATH}/60python-docs-${target}" ]]; then variable="PYTHONDOCS_${target//./_}" path="$(. "${ENV_D_PATH}/60python-docs-${target}"; echo -n "${!variable}")" if [[ -d "${path}" ]]; then echo "PYTHONDOCS=\"${path}\"" > "${ENV_D_PATH}/65python-docs" fi fi } ### show action ### describe_show() { echo "Show main active Python interpreter" } describe_show_options() { echo "--ABI : Show Python ABI in format of PYTHON_ABI variable" echo "--python2 : Show active Python 2 interpreter" echo "--python3 : Show active Python 3 interpreter" } do_show() { local ABI="0" interpreter python2="0" python3="0" while [[ $# > 0 ]]; do case "$1" in --ABI) ABI="1" ;; --python2) python2="1" ;; --python3) python3="1" ;; *) die -q "Unrecognized argument '$1'" ;; esac shift done if [[ "${python2}" == "1" && "${python3}" == "1" ]]; then die -q "'--python2' and '--python3' options cannot be specified simultaneously" fi if [[ "${python2}" == "1" ]]; then if [[ -f ${ENV_D_PATH}/python/python2 ]]; then interpreter="$(<"${ENV_D_PATH}/python/python2")" fi elif [[ "${python3}" == "1" ]]; then if [[ -f ${ENV_D_PATH}/python/python3 ]]; then interpreter="$(<"${ENV_D_PATH}/python/python3")" fi elif [[ -f "${ENV_D_PATH}/python/config" ]]; then interpreter="$(<"${ENV_D_PATH}/python/config")" fi if [[ "${ABI}" == "1" ]]; then echo -n "${interpreter#python}" else echo -n "${interpreter}" fi if [[ -n "${interpreter}" ]]; then echo fi } ### list action ### describe_list() { echo "List installed Python interpreters" } describe_list_options() { echo "--python2 : List installed Python 2 interpreters" echo "--python3 : List installed Python 3 interpreters" } do_list() { local active i python_descriptive_name="Python" python_version_option= python2="0" python3="0" targets=() while [[ $# > 0 ]]; do case "$1" in --python2) python2="1" python_descriptive_name="Python 2" python_version_option="--python2" PYTHON_INTERPRETERS_GROUP="2" ;; --python3) python3="1" python_descriptive_name="Python 3" python_version_option="--python3" PYTHON_INTERPRETERS_GROUP="3" ;; *) die -q "Unrecognized argument '$1'" ;; esac shift done if [[ "${python2}" == "1" && "${python3}" == "1" ]]; then die -q "'--python2' and '--python3' options cannot be specified simultaneously" fi targets=($(find_targets)) write_list_start "Available ${python_descriptive_name} interpreters:" active="$(do_show ${python_version_option})" for ((i = 0; i < ${#targets[@]}; i++)); do if [[ ${targets[${i}]} == ${active} ]]; then targets[${i}]="$(highlight_marker "${targets[${i}]}")" fi done write_numbered_list -m "(none found)" "${targets[@]}" } ### set action ### describe_set() { echo "Set main active Python interpreter" } describe_set_options() { echo "--python2 : Set active Python 2 interpreter without setting of main active Python interpreter if it is not set to Python 2" echo "--python3 : Set active Python 3 interpreter without setting of main active Python interpreter if it is not set to Python 3" } describe_set_parameters() { echo "" } do_set() { local main_active_python_interpreter python2="0" python3="0" SET_MAIN_ACTIVE_PYTHON_INTERPRETER="1" while [[ $# > 0 ]]; do case "$1" in --python2) python2="1" PYTHON_INTERPRETERS_GROUP="2" ;; --python3) python3="1" PYTHON_INTERPRETERS_GROUP="3" ;; *) break ;; esac shift done if [[ "${python2}" == "1" && "${python3}" == "1" ]]; then die -q "'--python2' and '--python3' options cannot be specified simultaneously" fi if [[ $# -lt 1 ]]; then die -q "'eselect python set' requires Python interpreter filename" elif [[ $# -gt 1 ]]; then die -q "'eselect python set' requires 1 argument" else main_active_python_interpreter="$(do_show)" if [[ "${python2}" == "1" && "${main_active_python_interpreter}" != "python2."* ]]; then SET_MAIN_ACTIVE_PYTHON_INTERPRETER="0" elif [[ "${python3}" == "1" && "${main_active_python_interpreter}" != "python3."* ]]; then SET_MAIN_ACTIVE_PYTHON_INTERPRETER="0" fi if ! set_scripts_and_symlinks "${1}"; then die -q "Can't set new provider" fi if [[ "${SET_MAIN_ACTIVE_PYTHON_INTERPRETER}" == "1" ]]; then set_python_docs "${1}" fi fi } ### update action ### describe_update() { echo "Switch to the most recent CPython interpreter" } describe_update_options() { echo "--if-unset : Do not override existing implementation" echo "--ignore SLOT : Ignore SLOT when setting symlinks" echo "--python2 : Set active Python 2 interpreter without setting of main active Python interpreter if it is not set to Python 2" echo "--python3 : Set active Python 3 interpreter without setting of main active Python interpreter if it is not set to Python 3" } do_update() { local if_unset="0" ignored_slots=() interpreters="python?.?@EXEEXT@" python2="0" python3="0" python_version_option= slot= target targets=() while [[ $# > 0 ]]; do case "$1" in --if-unset) if_unset="1" ;; --ignore) ignored_slots+=("${2}") shift;; --python2) python2="1" python_version_option="--python2" ;; --python3) python3="1" python_version_option="--python3" ;; *) die -q "Unrecognized argument '$1'" ;; esac shift done if [[ "${python2}" == "1" && "${python3}" == "1" ]]; then die -q "'--python2' and '--python3' options cannot be specified simultaneously" fi if [[ "${if_unset}" == "1" && -f "${ENV_D_PATH}/python/config" ]]; then if [[ "${python2}" == "1" && -f "${ENV_D_PATH}/python/python2" ]]; then return elif [[ "${python3}" == "1" && -f "${ENV_D_PATH}/python/python3" ]]; then return elif [[ "${python2}" == "0" && "${python3}" == "0" ]]; then return fi fi if [[ "${python2}" == "1" ]]; then interpreters="python2.?@EXEEXT@" elif [[ "${python3}" == "1" ]]; then interpreters="python3.?@EXEEXT@" fi targets=($(cd "${INTERPRETER_PATH}"; ls ${interpreters} 2> /dev/null | sort -r)) # Ignore slots for slot in ${ignored_slots[@]}; do targets=(${targets[@]/python${slot}/}) done if [[ ${#targets[@]} -gt 0 ]]; then target=${targets[0]} echo "Switching to ${target}" do_set ${python_version_option} ${target} else die -q "No Python interpreter available" fi } # vim: set ft=eselect :