# Copyright 1999-2008 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.54 2008/10/30 05:21:46 zmedico Exp $ # @ECLASS: python.eclass # @MAINTAINER: # python@gentoo.org # # original author: Alastair Tse # @BLURB: A Utility Eclass that should be inherited by anything that deals with Python or Python modules. # @DESCRIPTION: # Some useful functions for dealing with python. inherit alternatives multilib if [[ -n "${NEED_PYTHON}" ]] ; then DEPEND=">=dev-lang/python-${NEED_PYTHON}" RDEPEND="${DEPEND}" fi __python_eclass_test() { __python_version_extract 2.3 echo -n "2.3 -> PYVER: $PYVER PYVER_MAJOR: $PYVER_MAJOR" echo " PYVER_MINOR: $PYVER_MINOR PYVER_MICRO: $PYVER_MICRO" __python_version_extract 2.3.4 echo -n "2.3.4 -> PYVER: $PYVER PYVER_MAJOR: $PYVER_MAJOR" echo " PYVER_MINOR: $PYVER_MINOR PYVER_MICRO: $PYVER_MICRO" __python_version_extract 2.3.5 echo -n "2.3.5 -> PYVER: $PYVER PYVER_MAJOR: $PYVER_MAJOR" echo " PYVER_MINOR: $PYVER_MINOR PYVER_MICRO: $PYVER_MICRO" __python_version_extract 2.4 echo -n "2.4 -> PYVER: $PYVER PYVER_MAJOR: $PYVER_MAJOR" echo " PYVER_MINOR: $PYVER_MINOR PYVER_MICRO: $PYVER_MICRO" __python_version_extract 2.5b3 echo -n "2.5b3 -> PYVER: $PYVER PYVER_MAJOR: $PYVER_MAJOR" echo " PYVER_MINOR: $PYVER_MINOR PYVER_MICRO: $PYVER_MICRO" } # @FUNCTION: python_version # @DESCRIPTION: # Run without arguments and it will export the version of python # currently in use as $PYVER; sets PYVER/PYVER_MAJOR/PYVER_MINOR __python_version_extract() { local verstr=$1 export PYVER_MAJOR=${verstr:0:1} export PYVER_MINOR=${verstr:2:1} if [[ ${verstr:3:1} == . ]]; then export PYVER_MICRO=${verstr:4} fi export PYVER="${PYVER_MAJOR}.${PYVER_MINOR}" } python_version() { [[ -n "${PYVER}" ]] && return 0 local tmpstr python=${python:-/usr/bin/python} tmpstr="$(${python} -V 2>&1 )" export PYVER_ALL="${tmpstr#Python }" __python_version_extract $PYVER_ALL } # @FUNCTION: python_disable_pyc # @DESCRIPTION: # Tells python not to automatically recompile modules to .pyc/.pyo # even if the timestamps/version stamps don't match. This is done # to protect sandbox. # # note: supported by >=dev-lang/python-2.2.3-r3 only. # python_disable_pyc() { export PYTHONDONTWRITEBYTECODE=1 # For 2.6 and above export PYTHON_DONTCOMPILE=1 # For 2.5 and below } # @FUNCTION: python_enable_pyc # @DESCRIPTION: # Tells python to automatically recompile modules to .pyc/.pyo if the # timestamps/version stamps change python_enable_pyc() { unset PYTHONDONTWRITEBYTECODE unset PYTHON_DONTCOMPILE } python_disable_pyc # @FUNCTION: python_need_rebuild # @DESCRIPTION: Run without arguments, specifies that the package should be # rebuilt after a python upgrade. python_need_rebuild() { python_version export PYTHON_NEED_REBUILD=${PYVER} } # @FUNCTION: python_get_libdir # @DESCRIPTION: # Run without arguments, returns the python library dir python_get_libdir() { python_version echo "/usr/$(get_libdir)/python${PYVER}" } # @FUNCTION: python_get_sitedir # @DESCRIPTION: # Run without arguments, returns the python site-packages dir python_get_sitedir() { echo "$(python_get_libdir)/site-packages" } # @FUNCTION: python_makesym # @DESCRIPTION: # Run without arguments, it will create the /usr/bin/python symlinks # to the latest installed version python_makesym() { alternatives_auto_makesym "/usr/bin/python" "python[0-9].[0-9]" alternatives_auto_makesym "/usr/bin/python2" "python2.[0-9]" } # @FUNCTION: python_tkinter_exists # @DESCRIPTION: # Run without arguments, checks if python was compiled with Tkinter # support. If not, prints an error message and dies. python_tkinter_exists() { if ! python -c "import Tkinter" >/dev/null 2>&1; then eerror "You need to recompile python with Tkinter support." eerror "Try adding: 'dev-lang/python tk'" eerror "in to /etc/portage/package.use" echo die "missing tkinter support with installed python" fi } # @FUNCTION: python_mod_exists # @USAGE: < module > # @DESCRIPTION: # Run with the module name as an argument. it will check if a # python module is installed and loadable. it will return # TRUE(0) if the module exists, and FALSE(1) if the module does # not exist. # # Example: # if python_mod_exists gtk; then # echo "gtk support enabled" # fi python_mod_exists() { [[ "$1" ]] || die "${FUNCNAME} requires an argument!" python -c "import $1" >/dev/null 2>&1 } # @FUNCTION: python_mod_compile # @USAGE: < file > [more files ...] # @DESCRIPTION: # Given filenames, it will pre-compile the module's .pyc and .pyo. # This function should only be run in pkg_postinst() # # Example: # python_mod_compile /usr/lib/python2.3/site-packages/pygoogle.py # python_mod_compile() { local f myroot myfiles=() # Check if phase is pkg_postinst() [[ ${EBUILD_PHASE} != postinst ]] &&\ die "${FUNCNAME} should only be run in pkg_postinst()" # allow compiling for older python versions if [[ "${PYTHON_OVERRIDE_PYVER}" ]]; then PYVER=${PYTHON_OVERRIDE_PYVER} else python_version fi # strip trailing slash myroot="${ROOT%/}" # respect ROOT for f in "$@"; do [[ -f "${myroot}/${f}" ]] && myfiles+=("${myroot}/${f}") done if ((${#myfiles[@]})); then python${PYVER} ${myroot}/usr/$(get_libdir)/python${PYVER}/py_compile.py "${myfiles[@]}" python${PYVER} -O ${myroot}/usr/$(get_libdir)/python${PYVER}/py_compile.py "${myfiles[@]}" else ewarn "No files to compile!" fi } # @FUNCTION: python_mod_optimize # @USAGE: [ path ] # @DESCRIPTION: # If no arguments supplied, it will recompile all modules under # sys.path (eg. /usr/lib/python2.3, /usr/lib/python2.3/site-packages/ ..) # no recursively # # If supplied with arguments, it will recompile all modules recursively # in the supplied directory # This function should only be run in pkg_postinst() # # Options passed to this function are passed to compileall.py # # Example: # python_mod_optimize /usr/share/codegen python_mod_optimize() { local myroot mydirs=() myfiles=() myopts=() # Check if phase is pkg_postinst() [[ ${EBUILD_PHASE} != postinst ]] &&\ die "${FUNCNAME} should only be run in pkg_postinst()" # strip trailing slash myroot="${ROOT%/}" # respect ROOT and options passed to compileall.py while (($#)); do case $1 in -l|-f|-q) myopts+=("$1") ;; -d|-x) myopts+=("$1" "$2") shift ;; -*) ewarn "${FUNCNAME}: Ignoring compile option $1" ;; *) if [[ -d "${myroot}"/$1 ]]; then mydirs+=("${myroot}/$1") elif [[ -f "${myroot}"/$1 ]]; then # Files are passed to python_mod_compile which is ROOT-aware myfiles+=("$1") elif [[ -e "${myroot}/$1" ]]; then ewarn "${myroot}/$1 is not a file or directory!" else ewarn "${myroot}/$1 doesn't exist!" fi ;; esac shift done # allow compiling for older python versions if [ -n "${PYTHON_OVERRIDE_PYVER}" ]; then PYVER=${PYTHON_OVERRIDE_PYVER} else python_version fi # set additional opts myopts+=(-q) ebegin "Byte compiling python modules for python-${PYVER} .." if ((${#mydirs[@]})); then python${PYVER} \ "${myroot}"/usr/$(get_libdir)/python${PYVER}/compileall.py \ "${myopts[@]}" "${mydirs[@]}" python${PYVER} -O \ "${myroot}"/usr/$(get_libdir)/python${PYVER}/compileall.py \ "${myopts[@]}" "${mydirs[@]}" fi if ((${#myfiles[@]})); then python_mod_compile "${myfiles[@]}" fi eend $? } # @FUNCTION: python_mod_cleanup # @USAGE: [ dir ] # @DESCRIPTION: # Run with optional arguments, where arguments are directories of # python modules. if none given, it will look in /usr/lib/python[0-9].[0-9] # # It will recursively scan all compiled python modules in the directories # and determine if they are orphaned (eg. their corresponding .py is missing.) # if they are, then it will remove their corresponding .pyc and .pyo # # This function should only be run in pkg_postrm() python_mod_cleanup() { local SEARCH_PATH=() myroot src_py # Check if phase is pkg_postrm() [[ ${EBUILD_PHASE} != postrm ]] &&\ die "${FUNCNAME} should only be run in pkg_postrm()" # strip trailing slash myroot="${ROOT%/}" if (($#)); then SEARCH_PATH=("${@#/}") SEARCH_PATH=("${SEARCH_PATH[@]/#/$myroot/}") else SEARCH_PATH=("${myroot}"/usr/lib*/python*/site-packages) fi for path in "${SEARCH_PATH[@]}"; do einfo "Cleaning orphaned Python bytecode from ${path} .." find "${path}" -name '*.py[co]' -print0 | while read -rd ''; do src_py="${REPLY%[co]}" [[ -f "${src_py}" ]] && continue einfo "Purging ${src_py}[co]" rm -f "${src_py}"[co] done # attempt to remove directories that maybe empty find "${path}" -type d | sort -r | while read -r dir; do rmdir "${dir}" 2>/dev/null done done }