diff options
author | 2009-08-01 22:36:20 +0000 | |
---|---|---|
committer | 2009-08-01 22:36:20 +0000 | |
commit | 3698f286d79f4234312a74c730ddb27efca1a220 (patch) | |
tree | 380ea33e9195ef293df4758c4cc4e9f6035f0512 /eclass | |
parent | Version bump; experimental ebuild, since the code does not look extremely use... (diff) | |
download | historical-3698f286d79f4234312a74c730ddb27efca1a220.tar.gz historical-3698f286d79f4234312a74c730ddb27efca1a220.tar.bz2 historical-3698f286d79f4234312a74c730ddb27efca1a220.zip |
Add initial support for installation of Python modules for multiple Python versions.
Diffstat (limited to 'eclass')
-rw-r--r-- | eclass/distutils.eclass | 101 | ||||
-rw-r--r-- | eclass/python.eclass | 531 |
2 files changed, 503 insertions, 129 deletions
diff --git a/eclass/distutils.eclass b/eclass/distutils.eclass index 8d9848574ba7..66e78d3d2414 100644 --- a/eclass/distutils.eclass +++ b/eclass/distutils.eclass @@ -1,6 +1,6 @@ -# Copyright 1999-2008 Gentoo Foundation +# Copyright 1999-2009 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-x86/eclass/distutils.eclass,v 1.55 2009/02/18 14:43:31 pva Exp $ +# $Header: /var/cvsroot/gentoo-x86/eclass/distutils.eclass,v 1.56 2009/08/01 22:36:20 arfrever Exp $ # @ECLASS: distutils.eclass # @MAINTAINER: @@ -52,7 +52,7 @@ distutils_src_unpack() { unpack ${A} cd "${S}" - has ${EAPI:-0} 0 1 && distutils_src_prepare + has "${EAPI:-0}" 0 1 && distutils_src_prepare } # @FUNCTION: distutils_src_prepare @@ -69,7 +69,14 @@ distutils_src_prepare() { # @DESCRIPTION: # The distutils src_compile function, this function is exported distutils_src_compile() { - ${python} setup.py build "$@" || die "compilation failed" + if ! has "${EAPI:-0}" 0 1 2 || [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then + build_modules() { + ${python} setup.py build -b "build-${PYTHON_ABI}" "$@" + } + python_execute_function build_modules "$@" + else + ${python} setup.py build "$@" || die "compilation failed" + fi } # @FUNCTION: distutils_src_install @@ -82,80 +89,95 @@ distutils_src_install() { # Mark the package to be rebuilt after a python upgrade. python_need_rebuild - # need this for python-2.5 + setuptools in cases where - # a package uses distutils but does not install anything - # in site-packages. (eg. dev-java/java-config-2.x) - # - liquidx (14/08/2006) - pylibdir="$(${python} -c 'from distutils.sysconfig import get_python_lib; print get_python_lib()')" - [ -n "${pylibdir}" ] && dodir "${pylibdir}" - - if has_version ">=dev-lang/python-2.3"; then - ${python} setup.py install --root="${D}" --no-compile "$@" ||\ - die "python setup.py install failed" + if ! has "${EAPI:-0}" 0 1 2 || [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then + install_modules() { + # need this for python-2.5 + setuptools in cases where + # a package uses distutils but does not install anything + # in site-packages. (eg. dev-java/java-config-2.x) + # - liquidx (14/08/2006) + pylibdir="$(${python} -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())')" + [[ -n "${pylibdir}" ]] && dodir "${pylibdir}" + + echo ${python} setup.py build -b "build-${PYTHON_ABI}" install --root="${D}" --no-compile "$@" + ${python} setup.py build -b "build-${PYTHON_ABI}" install --root="${D}" --no-compile "$@" + } + python_execute_function install_modules "$@" else - ${python} setup.py install --root="${D}" "$@" ||\ - die "python setup.py install failed" + # need this for python-2.5 + setuptools in cases where + # a package uses distutils but does not install anything + # in site-packages. (eg. dev-java/java-config-2.x) + # - liquidx (14/08/2006) + pylibdir="$(${python} -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())')" + [[ -n "${pylibdir}" ]] && dodir "${pylibdir}" + + ${python} setup.py install --root="${D}" --no-compile "$@" || die "python setup.py install failed" fi DDOCS="CHANGELOG KNOWN_BUGS MAINTAINERS PKG-INFO CONTRIBUTORS TODO NEWS" DDOCS="${DDOCS} Change* MANIFEST* README* AUTHORS" + local doc for doc in ${DDOCS}; do - [ -s "$doc" ] && dodoc $doc + [[ -s "$doc" ]] && dodoc $doc done - [ -n "${DOCS}" ] && dodoc ${DOCS} + [[ -n "${DOCS}" ]] && dodoc ${DOCS} } # @FUNCTION: distutils_pkg_postrm # @DESCRIPTION: # Generic pyc/pyo cleanup script. This function is exported. distutils_pkg_postrm() { - local moddir pylibdir pymod + local pylibdir pymod if [[ -z "${PYTHON_MODNAME}" ]]; then for pylibdir in "${ROOT}"/usr/$(get_libdir)/python*; do - if [[ -d "${pylibdir}"/site-packages/${PN} ]]; then - PYTHON_MODNAME=${PN} + if [[ -d "${pylibdir}/site-packages/${PN}" ]]; then + PYTHON_MODNAME="${PN}" fi done fi - if has_version ">=dev-lang/python-2.3"; then - ebegin "Performing Python Module Cleanup .." - if [[ -n "${PYTHON_MODNAME}" ]]; then - for pymod in ${PYTHON_MODNAME}; do - for pylibdir in "${ROOT}"/usr/$(get_libdir)/python*; do - if [[ -d "${pylibdir}"/site-packages/${pymod} ]]; then - python_mod_cleanup "${pylibdir#${ROOT}}"/site-packages/${pymod} + ebegin "Performing cleanup of Python modules..." + if [[ -n "${PYTHON_MODNAME}" ]]; then + for pymod in ${PYTHON_MODNAME}; do + for pylibdir in "${ROOT}"/usr/$(get_libdir)/python*; do + if [[ -d "${pylibdir}/site-packages/${pymod}" ]]; then + if ! has "${EAPI:-0}" 0 1 2 || [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then + python_mod_cleanup "${pymod}" + else + python_mod_cleanup "${pylibdir#${ROOT}}/site-packages/${pymod}" fi - done + fi done - else - python_mod_cleanup - fi - eend 0 + done + else + python_mod_cleanup fi + eend 0 } # @FUNCTION: distutils_pkg_postinst # @DESCRIPTION: # This is a generic optimization, you should override it if your package -# installs things in another directory. This function is exported +# installs modules in another directory. This function is exported. distutils_pkg_postinst() { local pylibdir pymod if [[ -z "${PYTHON_MODNAME}" ]]; then for pylibdir in "${ROOT}"/usr/$(get_libdir)/python*; do - if [[ -d "${pylibdir}"/site-packages/${PN} ]]; then - PYTHON_MODNAME=${PN} + if [[ -d "${pylibdir}/site-packages/${PN}" ]]; then + PYTHON_MODNAME="${PN}" fi done fi - if has_version ">=dev-lang/python-2.3"; then + if ! has "${EAPI:-0}" 0 1 2 || [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then + for pymod in ${PYTHON_MODNAME}; do + python_mod_optimize "${pymod}" + done + else python_version for pymod in ${PYTHON_MODNAME}; do - python_mod_optimize \ - /usr/$(get_libdir)/python${PYVER}/site-packages/${pymod} + python_mod_optimize "/usr/$(get_libdir)/python${PYVER}/site-packages/${pymod}" done fi } @@ -174,4 +196,3 @@ distutils_python_version() { distutils_python_tkinter() { python_tkinter_exists } - diff --git a/eclass/python.eclass b/eclass/python.eclass index 20e59e851565..14320185c7f4 100644 --- a/eclass/python.eclass +++ b/eclass/python.eclass @@ -1,6 +1,6 @@ -# Copyright 1999-2008 Gentoo Foundation +# Copyright 1999-2009 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.55 2009/05/27 22:49:32 betelgeuse Exp $ +# $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.56 2009/08/01 22:36:20 arfrever Exp $ # @ECLASS: python.eclass # @MAINTAINER: @@ -21,6 +21,10 @@ else PYTHON_ATOM="dev-lang/python" fi +if ! has "${EAPI:-0}" 0 1 2 || [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then + DEPEND="${DEPEND} >=app-admin/eselect-python-20090801" +fi + __python_eclass_test() { __python_version_extract 2.3 echo -n "2.3 -> PYVER: $PYVER PYVER_MAJOR: $PYVER_MAJOR" @@ -62,6 +66,227 @@ python_version() { __python_version_extract $PYVER_ALL } +# @FUNCTION: get_python +# @USAGE: [-a|--absolute-path] <Python_ABI="${PYTHON_ABI}"> +# @DESCRIPTION: +# Get Python interpreter filename for specified Python ABI. If Python_ABI argument +# is ommitted, then PYTHON_ABI environment variable must be set and is used. +get_python() { + local absolute_path="0" slot= + + while (($#)); do + case "$1" in + -a|--absolute-path) + absolute_path="1" + ;; + -*) + die "${FUNCNAME}(): Unrecognized option $1" + ;; + *) + break + ;; + esac + shift + done + + if [[ "$#" -eq "0" ]]; then + if [[ -n "${PYTHON_ABI}" ]]; then + slot="${PYTHON_ABI}" + else + die "${FUNCNAME}(): Invalid usage" + fi + elif [[ "$#" -eq "1" ]]; then + slot="$1" + else + die "${FUNCNAME}(): Invalid usage" + fi + + if [[ "${absolute_path}" == "1" ]]; then + echo -n "/usr/bin/python${slot}" + else + echo -n "python${slot}" + fi +} + +# @FUNCTION: validate_PYTHON_ABIS +# @DESCRIPTION: +# Make sure PYTHON_ABIS variable has valid value. +validate_PYTHON_ABIS() { + # USE_${ABI_TYPE^^} and RESTRICT_${ABI_TYPE^^}_ABIS variables hopefully will be included in EAPI >= 4. + if [[ -z "${PYTHON_ABIS}" ]] && has "${EAPI:-0}" 0 1 2 3; then + local ABI support_ABI supported_PYTHON_ABIS= restricted_ABI + PYTHON_ABI_SUPPORTED_VALUES="2.4 2.5 2.6 2.7 3.0 3.1 3.2" + for ABI in ${USE_PYTHON}; do + if ! has "${ABI}" ${PYTHON_ABI_SUPPORTED_VALUES}; then + ewarn "Ignoring unsupported Python ABI '${ABI}'" + continue + fi + support_ABI="1" + for restricted_ABI in ${RESTRICT_PYTHON_ABIS}; do + if python -c "from fnmatch import fnmatch; exit(not fnmatch('${ABI}', '${restricted_ABI}'))"; then + support_ABI="0" + break + fi + done + [[ "${support_ABI}" == "1" ]] && supported_PYTHON_ABIS+=" ${ABI}" + done + export PYTHON_ABIS="${supported_PYTHON_ABIS# }" + fi + + if [[ -z "${PYTHON_ABIS//[${IFS}]/}" ]]; then + python_version + export PYTHON_ABIS="${PYVER}" + fi +} + +# @FUNCTION: python_copy_sources +# @USAGE: [directory] +# @DESCRIPTION: +# Copy unpacked sources of given package for each Python ABI. +python_copy_sources() { + local dir dirs=() PYTHON_ABI + + if [[ "$#" -eq "0" ]]; then + if [[ "${WORKDIR}" == "${S}" ]]; then + die "${FUNCNAME}() cannot be used" + fi + dirs="${S}" + else + dirs="$@" + fi + + validate_PYTHON_ABIS + for PYTHON_ABI in ${PYTHON_ABIS}; do + for dir in "${dirs[@]}"; do + cp -lpr "${dir}" "${dir}-${PYTHON_ABI}" > /dev/null || die "Copying of sources failed" + done + done +} + +# @FUNCTION: python_set_build_dir_symlink +# @USAGE: [directory="build"] +# @DESCRIPTION: +# Create build directory symlink. +python_set_build_dir_symlink() { + local dir="$1" + + [[ -z "${PYTHON_ABIS}" ]] && die "PYTHON_ABIS variable not set" + [[ -z "${dir}" ]] && dir="build" + + # Don't delete preexistent directories. + rm -f "${dir}" || die "Deletion of '${dir}' failed" + ln -s "${dir}-${PYTHON_ABI}" "${dir}" || die "Creation of '${dir}' directory symlink failed" +} + +# @FUNCTION: python_execute_function +# @USAGE: [--action-message message] [--failure-message message] [--nonfatal] [-q|--quiet] [-s|--separate-build-dirs] <function> [arguments] +# @DESCRIPTION: +# Execute specified function for each value of PYTHON_ABIS, optionally passing +# additional arguments. The specified function can use PYTHON_ABI variable. +python_execute_function() { + local action action_message action_message_template= failure_message failure_message_template= function nonfatal="0" PYTHON_ABI quiet="0" separate_build_dirs="0" + + while (($#)); do + case "$1" in + --action-message) + action_message_template="$2" + shift + ;; + --failure-message) + failure_message_template="$2" + shift + ;; + --nonfatal) + nonfatal="1" + ;; + -q|--quiet) + quiet="1" + ;; + -s|--separate-build-dirs) + separate_build_dirs="1" + ;; + -*) + die "${FUNCNAME}(): Unrecognized option $1" + ;; + *) + break + ;; + esac + shift + done + + if [[ "$#" -eq "0" ]]; then + die "${FUNCNAME}(): Missing function name" + fi + function="$1" + shift + + if [[ "${quiet}" == "0" ]]; then + [[ "${EBUILD_PHASE}" == "setup" ]] && action="Setting up" + [[ "${EBUILD_PHASE}" == "unpack" ]] && action="Unpacking" + [[ "${EBUILD_PHASE}" == "prepare" ]] && action="Preparation" + [[ "${EBUILD_PHASE}" == "configure" ]] && action="Configuration" + [[ "${EBUILD_PHASE}" == "compile" ]] && action="Building" + [[ "${EBUILD_PHASE}" == "test" ]] && action="Testing" + [[ "${EBUILD_PHASE}" == "install" ]] && action="Installation" + [[ "${EBUILD_PHASE}" == "preinst" ]] && action="Preinstallation" + [[ "${EBUILD_PHASE}" == "postinst" ]] && action="Postinstallation" + [[ "${EBUILD_PHASE}" == "prerm" ]] && action="Preuninstallation" + [[ "${EBUILD_PHASE}" == "postrm" ]] && action="Postuninstallation" + fi + + local RED GREEN BLUE NORMAL + if [[ "${NOCOLOR:-false}" =~ ^(false|no)$ ]]; then + RED=$'\e[1;31m' + GREEN=$'\e[1;32m' + BLUE=$'\e[1;34m' + NORMAL=$'\e[0m' + else + RED= + GREEN= + BLUE= + NORMAL= + fi + + validate_PYTHON_ABIS + for PYTHON_ABI in ${PYTHON_ABIS}; do + if [[ "${quiet}" == "0" ]]; then + if [[ -n "${action_message_template}" ]]; then + action_message="$(eval echo -n "${action_message_template}")" + else + action_message="${action} of ${CATEGORY}/${PF} with Python ${PYTHON_ABI}..." + fi + echo " ${GREEN}*${NORMAL} ${BLUE}${action_message}${NORMAL}" + fi + if [[ "${separate_build_dirs}" == "1" ]]; then + pushd "${S}-${PYTHON_ABI}" > /dev/null || die "pushd failed" + fi + if ! EPYTHON="$(get_python)" "${function}" "$@"; then + if [[ -n "${failure_message_template}" ]]; then + failure_message="$(eval echo -n "${failure_message_template}")" + else + failure_message="${action} failed with Python ${PYTHON_ABI} in ${function}() function" + fi + if [[ "${nonfatal}" == "1" ]] || has "${PYTHON_ABI}" ${FAILURE_TOLERANT_PYTHON_ABIS}; then + local ABI enabled_PYTHON_ABIS + for ABI in ${PYTHON_ABIS}; do + [[ "${ABI}" != "${PYTHON_ABI}" ]] && enabled_PYTHON_ABIS+=" ${ABI}" + done + export PYTHON_ABIS="${enabled_PYTHON_ABIS# }" + if [[ "${quiet}" == "0" ]]; then + ewarn "${RED}${failure_message}${NORMAL}" + fi + else + die "${failure_message}" + fi + fi + if [[ "${separate_build_dirs}" == "1" ]]; then + popd > /dev/null || die "popd failed" + fi + done +} + + # @ECLASS-VARIABLE: PYTHON_USE_WITH # @DESCRIPTION: # Set this to a space separated list of use flags @@ -166,17 +391,33 @@ python_need_rebuild() { export PYTHON_NEED_REBUILD=${PYVER} } +# @FUNCTION: python_get_includedir +# @DESCRIPTION: +# Run without arguments, returns the Python include directory. +python_get_includedir() { + if [[ -n "${PYTHON_ABI}" ]]; then + echo "/usr/include/python${PYTHON_ABI}" + else + python_version + echo "/usr/include/python${PYVER}" + fi +} + # @FUNCTION: python_get_libdir # @DESCRIPTION: -# Run without arguments, returns the python library dir +# Run without arguments, returns the Python library directory. python_get_libdir() { - python_version - echo "/usr/$(get_libdir)/python${PYVER}" + if [[ -n "${PYTHON_ABI}" ]]; then + echo "/usr/$(get_libdir)/python${PYTHON_ABI}" + else + python_version + echo "/usr/$(get_libdir)/python${PYVER}" + fi } # @FUNCTION: python_get_sitedir # @DESCRIPTION: -# Run without arguments, returns the python site-packages dir +# Run without arguments, returns the Python site-packages directory. python_get_sitedir() { echo "$(python_get_libdir)/site-packages" } @@ -205,7 +446,7 @@ python_tkinter_exists() { } # @FUNCTION: python_mod_exists -# @USAGE: < module > +# @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 @@ -218,11 +459,11 @@ python_tkinter_exists() { # fi python_mod_exists() { [[ "$1" ]] || die "${FUNCNAME} requires an argument!" - python -c "import $1" >/dev/null 2>&1 + python -c "import $1" &>/dev/null } # @FUNCTION: python_mod_compile -# @USAGE: < file > [more files ...] +# @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() @@ -231,6 +472,10 @@ python_mod_exists() { # python_mod_compile /usr/lib/python2.3/site-packages/pygoogle.py # python_mod_compile() { + if ! has "${EAPI:-0}" 0 1 2 || [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then + die "${FUNCNAME}() cannot be used in this EAPI" + fi + local f myroot myfiles=() # Check if phase is pkg_postinst() @@ -261,112 +506,220 @@ python_mod_compile() { } # @FUNCTION: python_mod_optimize -# @USAGE: [ path ] +# @USAGE: [options] [directory|file] # @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 no arguments supplied, it will recompile not recursively all modules +# under sys.path (eg. /usr/lib/python2.6, /usr/lib/python2.6/site-packages). # # If supplied with arguments, it will recompile all modules recursively -# in the supplied directory -# This function should only be run in pkg_postinst() +# in the supplied directory. +# This function should only be run in pkg_postinst(). # -# Options passed to this function are passed to compileall.py +# Options passed to this function are passed to compileall.py. # # Example: -# python_mod_optimize /usr/share/codegen +# python_mod_optimize ctypesgencore 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%/}" + # Check if phase is pkg_postinst(). + [[ ${EBUILD_PHASE} != "postinst" ]] && die "${FUNCNAME} should only be run in pkg_postinst()" + + if ! has "${EAPI:-0}" 0 1 2 || [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then + local dir file options=() other_dirs=() other_files=() PYTHON_ABI return_code root site_packages_absolute_dirs=() site_packages_dirs=() site_packages_absolute_files=() site_packages_files=() + + # Strip trailing slash from ROOT. + root="${ROOT%/}" + + # Respect ROOT and options passed to compileall.py. + while (($#)); do + case "$1" in + -l|-f|-q) + options+=("$1") + ;; + -d|-x) + options+=("$1" "$2") + shift + ;; + -*) + ewarn "${FUNCNAME}: Ignoring compile option $1" + ;; + *) + if [[ "$1" =~ ^/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then + die "${FUNCNAME} doesn't support absolute paths of directories/files in site-packages directories" + elif [[ "$1" =~ ^/ ]]; then + if [[ -d "${root}/$1" ]]; then + other_dirs+=("${root}/$1") + elif [[ -f "${root}/$1" ]]; then + other_files+=("${root}/$1") + elif [[ -e "${root}/$1" ]]; then + ewarn "'${root}/$1' is not a file or a directory!" + else + ewarn "'${root}/$1' doesn't exist!" + fi + else + for PYTHON_ABI in ${PYTHON_ABIS}; do + if [[ -d "${root}/$(python_get_sitedir)/$1" ]]; then + site_packages_dirs+=("$1") + break + elif [[ -f "${root}/$(python_get_sitedir)/$1" ]]; then + site_packages_files+=("$1") + break + elif [[ -e "${root}/$(python_get_sitedir)/$1" ]]; then + ewarn "'$1' is not a file or a directory!" + else + ewarn "'$1' doesn't exist!" + fi + done + fi + ;; + esac + shift + done - # 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!" + # Set additional options. + options+=("-q") + + for PYTHON_ABI in ${PYTHON_ABIS}; do + if ((${#site_packages_dirs[@]})) || ((${#site_packages_files[@]})); then + return_code="0" + ebegin "Compilation and optimization of Python modules for Python ${PYTHON_ABI}" + if ((${#site_packages_dirs[@]})); then + for dir in "${site_packages_dirs[@]}"; do + site_packages_absolute_dirs+=("${root}/$(python_get_sitedir)/${dir}") + done + "$(get_python)" "${root}/$(python_get_libdir)/compileall.py" "${options[@]}" "${site_packages_absolute_dirs[@]}" || return_code="1" + "$(get_python)" -O "${root}/$(python_get_libdir)/compileall.py" "${options[@]}" "${site_packages_absolute_dirs[@]}" || return_code="1" fi - ;; - esac - shift - done + if ((${#site_packages_files[@]})); then + for file in "${site_packages_files[@]}"; do + site_packages_absolute_files+=("${root}/$(python_get_sitedir)/${file}") + done + "$(get_python)" "${root}/$(python_get_libdir)/py_compile.py" "${site_packages_absolute_files[@]}" || return_code="1" + "$(get_python)" -O "${root}/$(python_get_libdir)/py_compile.py" "${site_packages_absolute_files[@]}" || return_code="1" + fi + eend "${return_code}" + fi + unset site_packages_absolute_dirs site_packages_absolute_files + done - # allow compiling for older python versions - if [ -n "${PYTHON_OVERRIDE_PYVER}" ]; then - PYVER=${PYTHON_OVERRIDE_PYVER} + # Don't use PYTHON_ABI in next calls to python_get_libdir(). + unset PYTHON_ABI + + if ((${#other_dirs[@]})) || ((${#other_files[@]})); then + return_code="0" + ebegin "Compilation and optimization of Python modules placed outside of site-packages directories for Python ${PYVER}..." + if ((${#other_dirs[@]})); then + python${PYVER} "${root}/$(python_get_libdir)/compileall.py" "${options[@]}" "${other_dirs[@]}" || return_code="1" + python${PYVER} -O "${root}/$(python_get_libdir)/compileall.py" "${options[@]}" "${other_dirs[@]}" || return_code="1" + fi + if ((${#other_files[@]})); then + python${PYVER} "${root}/$(python_get_libdir)/py_compile.py" "${other_files[@]}" || return_code="1" + python${PYVER} -O "${root}/$(python_get_libdir)/py_compile.py" "${other_files[@]}" || return_code="1" + fi + eend "${return_code}" + fi else - python_version - fi + local myroot mydirs=() myfiles=() myopts=() + + # 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 - # 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 + # allow compiling for older python versions + if [ -n "${PYTHON_OVERRIDE_PYVER}" ]; then + PYVER=${PYTHON_OVERRIDE_PYVER} + else + python_version + fi - if ((${#myfiles[@]})); then - python_mod_compile "${myfiles[@]}" - 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 - eend $? + if ((${#myfiles[@]})); then + python_mod_compile "${myfiles[@]}" + fi + + eend $? + fi } # @FUNCTION: python_mod_cleanup -# @USAGE: [ dir ] +# @USAGE: [directory] # @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] +# 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 +# It will recursively scan all compiled Python modules in the directories and +# determine if they are orphaned (i.e. their corresponding .py files are missing.) +# If they are, then it will remove their corresponding .pyc and .pyo files. # -# This function should only be run in pkg_postrm() +# This function should only be run in pkg_postrm(). python_mod_cleanup() { - local SEARCH_PATH=() myroot src_py + local PYTHON_ABI SEARCH_PATH=() root src_py - # Check if phase is pkg_postrm() - [[ ${EBUILD_PHASE} != postrm ]] &&\ - die "${FUNCNAME} should only be run in pkg_postrm()" + # Check if phase is pkg_postrm(). + [[ ${EBUILD_PHASE} != "postrm" ]] && die "${FUNCNAME} should only be run in pkg_postrm()" - # strip trailing slash - myroot="${ROOT%/}" + # Strip trailing slash from ROOT. + root="${ROOT%/}" if (($#)); then - SEARCH_PATH=("${@#/}") - SEARCH_PATH=("${SEARCH_PATH[@]/#/$myroot/}") + if ! has "${EAPI:-0}" 0 1 2 || [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then + while (($#)); do + if [[ "$1" =~ ^/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then + die "${FUNCNAME} doesn't support absolute paths of directories/files in site-packages directories" + elif [[ "$1" =~ ^/ ]]; then + SEARCH_PATH+=("${root}/${1#/}") + else + for PYTHON_ABI in ${PYTHON_ABIS}; do + SEARCH_PATH+=("${root}/$(python_get_sitedir)/$1") + done + fi + shift + done + else + SEARCH_PATH=("${@#/}") + SEARCH_PATH=("${SEARCH_PATH[@]/#/${root}/}") + fi else - SEARCH_PATH=("${myroot}"/usr/lib*/python*/site-packages) + SEARCH_PATH=("${root}"/usr/lib*/python*/site-packages) fi for path in "${SEARCH_PATH[@]}"; do @@ -378,7 +731,7 @@ python_mod_cleanup() { rm -f "${src_py}"[co] done - # attempt to remove directories that maybe empty + # Attempt to remove directories that may be empty. find "${path}" -type d | sort -r | while read -r dir; do rmdir "${dir}" 2>/dev/null done |