Hello,

Instead of the floating patches and p-d-ng modifications I sent
earlier, here are the two complete (so far, well, initial :P) eclasses
for review.

They are designed as 'mostly' drop-in python-distutils-ng replacement.

-- 
Best regards,
Michał Górny
# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

# @ECLASS: python-r1
# @MAINTAINER:
# Python herd <pyt...@gentoo.org>
# @AUTHOR:
# Author: Michał Górny <mgo...@gentoo.org>
# Based on work of: Krzysztof Pawlik <nelch...@gentoo.org>
# @BLURB: A common, simple eclass for Python packages.
# @DESCRIPTION:
# A common eclass providing helper functions to build and install
# packages supporting being installed for multiple Python
# implementations.
#
# This eclass sets correct IUSE and REQUIRED_USE. It exports PYTHON_DEPS
# and PYTHON_USEDEP so you can create correct dependencies for your
# package easily. It also provides methods to easily run a command for
# each enabled Python implementation and duplicate the sources for them.

case "${EAPI}" in
        0|1|2|3)
                die "Unsupported EAPI=${EAPI} (too old) for ${ECLASS}"
                ;;
        4)
                # EAPI=4 needed for REQUIRED_USE
                ;;
        *)
                die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
                ;;
esac

# @ECLASS-VARIABLE: _PYTHON_ALL_IMPLS
# @INTERNAL
# @DESCRIPTION:
# All supported Python implementations, most preferred last.
_PYTHON_ALL_IMPLS=(
        jython2_5
        pypy1_8 pypy1_9
        python3_1 python3_2
        python2_5 python2_6 python2_7
)

# @ECLASS-VARIABLE: PYTHON_COMPAT
# @DESCRIPTION:
# This variable contains a space separated list of Python
# implementations a package supports. It must be set before
# the `inherit' call.  The default is to enable all implementations.
#
# PYTHON_COMPAT can be either a scalar or an array. If it's a scalar,
# the eclass will implicitly convert it to an array.
: ${PYTHON_COMPAT:=${_PYTHON_ALL_IMPLS[@]}}

# @ECLASS-VARIABLE: PYTHON_REQ_USE
# @DEFAULT_UNSET
# @DESCRIPTION:
# The list of USEflags required to be enabled on the chosen Python
# implementations, formed as a USE-dependency string. It should be valid
# for all implementations in PYTHON_COMPAT, so it may be necessary to
# use USE defaults.
#
# Example:
# @CODE
# PYTHON_REQ_USE="gdbm,ncurses(-)?"
# @CODE
#
# Will cause the Python dependencies to look like:
# @CODE
# python_targets_pythonX_Y? (
#   dev-lang/python:X_Y[gdbm,ncurses(-)?] )
# @CODE

# @ECLASS-VARIABLE: PYTHON_DEPS
# @DESCRIPTION:
# This is an eclass-generated Python dependency string for all
# implementations listed in PYTHON_COMPAT. It should be used
# in RDEPEND and/or DEPEND like:
#
# @CODE
# RDEPEND="${PYTHON_DEPS}
#   dev-foo/mydep"
# DEPEND="${RDEPEND}"
# @CODE

# @ECLASS-VARIABLE: PYTHON_USEDEP
# @DESCRIPTION:
# This is an eclass-generated USE-dependency string which can be used to
# depend on another Python package being built for the same Python
# implementations. It should be used like:
#
# @CODE
# RDEPEND="dev-python/foo[${PYTHON_USEDEP}]"
# @CODE

PYTHON_COMPAT=( ${PYTHON_COMPAT[@]} )

_python_set_globals() {
        local flags=( "${PYTHON_COMPAT[@]/#/python_targets_}" )
        local optflags=${flags[@]/%/?}

        IUSE=${flags[*]}
        REQUIRED_USE="|| ( ${flags[*]} )"
        PYTHON_USEDEP=${optflags// /,}

        PYTHON_DEPS=
        local i
        for i in ${PYTHON_COMPAT[@]}; do
                local d
                case ${i} in
                        python*)
                                d='dev-lang/python';;
                        jython*)
                                d='dev-java/jython';;
                        pypy*)
                                d='dev-python/pypy';;
                        *)
                                die "Invalid implementation: ${i}"
                esac

                local v=${i##*[a-z]}
                local usestr
                [[ ${PYTHON_REQ_USE} ]] && usestr="[${PYTHON_REQ_USE}]"
                PYTHON_DEPS+=" python_targets_${i}? (
                        ${d}:${v/_/.}${usestr} )"
        done
}
_python_set_globals

# @FUNCTION: python_get_PYTHON
# @USAGE: <impl>
# @DESCRIPTION:
# Get the Python executable name for the given implementation. Please
# note that this this function returns the 'basename' only.
# If using it for a hashbang, please use #!/usr/bin/env.
python_get_PYTHON() {
        local impl=${1/_/.}

        case "${impl}" in
                python*|jython*)
                        echo ${impl}
                        ;;
                pypy*)
                        echo pypy-c${impl#pypy}
                        ;;
                *)
                        die "Invalid argument to python_get_PYTHON: ${1}"
                        ;;
        esac
}

# @FUNCTION: python_copy_sources
# @DESCRIPTION:
# Create a single copy of the package sources (${S}) for each enabled
# Python implementation.
python_copy_sources() {
        local impl
        local bdir=${BUILD_DIR:-${S}}

        einfo "Will copy sources from ${S}"
        # the order is irrelevant here
        for impl in ${PYTHON_COMPAT[@]}; do
                if use python_targets_${impl}
                then
                        local BUILD_DIR=${bdir%%/}-${impl}

                        einfo "${impl}: copying to ${BUILD_DIR}"
                        cp -pr "${S}" "${BUILD_DIR}" || die
                fi
        done
}

# @FUNCTION: python_foreach_impl
# @USAGE: <command> [<args>...]
# @DESCRIPTION:
# Run the given command for each of the enabled Python implementations.
# If additional parameters are passed, they will be passed through
# to the command. If the command fails, python_foreach_impl dies.
# If necessary, use ':' to force a successful return.
#
# Before the command is run, EPYTHON is set to the name of the current
# Python implementation, PYTHON is set to the correct Python executable
# name and exported, and BUILD_DIR is set to a 'default' build directory
# for given implementation (e.g. ${BUILD_DIR:-${S}}-python2_7).
#
# The command is run inside the build directory. If it doesn't exist
# yet, it is created (as an empty directory!). If your build system does
# not support out-of-source builds, you will likely want to use
# python_copy_sources first.
python_foreach_impl() {
        local impl
        local bdir=${BUILD_DIR:-${S}}

        for impl in ${_PYTHON_ALL_IMPLS[@]}; do
                if has ${impl} ${PYTHON_COMPAT[@]} && use python_targets_${impl}
                then
                        local PYTHON=$(python_get_PYTHON "${impl}")
                        local EPYTHON=${impl}
                        local BUILD_DIR=${bdir%%/}-${impl}
                        export PYTHON

                        mkdir -p "${BUILD_DIR}" || die
                        pushd "${BUILD_DIR}" &>/dev/null || die
                        einfo "${EPYTHON}: running ${@}"
                        "${@}" || die "${EPYTHON}: ${1} failed"
                        popd || die
                fi
        done
}
# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

# @ECLASS: distutils-r1
# @MAINTAINER:
# Python herd <pyt...@gentoo.org>
# @AUTHOR:
# Author: Michał Górny <mgo...@gentoo.org>
# Based on the work of: Krzysztof Pawlik <nelch...@gentoo.org>
# @BLURB: A simple eclass to build Python packages using distutils.
# @DESCRIPTION:
# A simple eclass providing functions to build Python packages using
# the distutils build system. It exports phase functions for all
# the src_* phases. Each of the phases runs two pseudo-phases:
# python_..._all() (e.g. python_prepare_all()) once in ${S}, then
# python_...() (e.g. python_prepare()) for each implementation
# (see: python_foreach_impl() in python-r1).
#
# In distutils-r1_src_prepare(), the 'all' function is run before
# per-implementation ones (because it creates the implementations),
# per-implementation functions are run in a random order.
#
# In remaining phase functions, the per-implementation functions are run
# before the 'all' one, and they are ordered from the least to the most
# preferred implementation (so that 'better' files overwrite 'worse'
# ones).
#
# If the ebuild doesn't specify a particular pseudo-phase function,
# the default one will be used (distutils-r1_...). Defaults are provided
# for all per-implementation pseudo-phases, python_prepare_all()
# and python_install_all(); whenever writing your own pseudo-phase
# functions, you should consider calling the defaults (and especially
# distutils-r1_python_prepare_all).
#
# Please note that distutils-r1 sets RDEPEND and DEPEND for you.

case "${EAPI}" in
        0|1|2|3)
                die "Unsupported EAPI=${EAPI} (too old) for ${ECLASS}"
                ;;
        4)
                ;;
        *)
                die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
                ;;
esac

inherit eutils python-r1

EXPORT_FUNCTIONS src_prepare src_configure src_compile src_test src_install

RDEPEND=${PYTHON_DEPS}
DEPEND=${PYTHON_DEPS}

# @FUNCTION: distutils-r1_python_prepare_all
# @DESCRIPTION:
# The default python_prepare_all(). It applies the patches from PATCHES
# array, then user patches and finally calls python_copy_sources to
# create copies of resulting sources for each Python implementation.
distutils-r1_python_prepare_all() {
        [[ ${PATCHES} ]] && epatch "${PATCHES[@]}"

        epatch_user

        # create source copies for each implementation
        python_copy_sources
}

# @FUNCTION: distutils-r1_python_prepare
# @DESCRIPTION:
# The default python_prepare(). Currently it is a no-op
# but in the future it may apply implementation-specific quirks
# to the build system.
distutils-r1_python_prepare() {
        :
}

# @FUNCTION: distutils-r1_python_configure
# @DESCRIPTION:
# The default python_configure(). Currently a no-op.
distutils-r1_python_configure() {
        :
}

# @FUNCTION: distutils-r1_python_compile
# @DESCRIPTION:
# The default python_compile(). Runs 'setup.py build' using the correct
# Python implementation.
distutils-r1_python_compile() {
        cd "${BUILD_DIR}" || die
        "${PYTHON}" setup.py build || die
}

# @FUNCTION: distutils-r1_python_test
# @DESCRIPTION:
# The default python_test(). Currently a no-op.
distutils-r1_python_test() {
        :
}

# @FUNCTION: distutils-r1_rename_scripts
# @DESCRIPTION:
# Renames installed Python scripts to be implementation-suffixed.
# ${PYTHON} has to be set to the expected Python executable (which
# hashbang will be grepped for), and ${EPYTHON} to the implementation
# name (for new name).
distutils-r1_rename_scripts() {
        local dir f
        local wrapdir=${T}/distutils_wrappers

        # XXX: change this if we ever allow directories in bin/sbin
        for dir in bin sbin usr/bin usr/sbin; do
                for f in "${D}"/${dir}/*; do
                        if [[ -x ${f} ]]; then
                                if [[ "$(head -n 1 "${f}")" == '#!'*${PYTHON}* 
]]
                                then
                                        local newf=${f}-${EPYTHON}
                                        mv "${f}" "${newf}" || die

                                        mkdir -p "${wrapdir}"/${dir}
                                        ln -fs "${newf##*/}" \
                                                "${wrapdir}"/${dir}/"${f##*/}" 
|| die
                                fi
                        fi
                done
        done
}

# @FUNCTION: distutils-r1_python_install
# @DESCRIPTION:
# The default python_install(). Runs 'setup.py install' using
# the correct Python implementation, and appending the optimization
# flags. Then calls distutils-r1_rename_scripts.
distutils-r1_python_install() {
        local flags

        case "${EPYTHON}" in
                jython*)
                        flags='--compile';;
                *)
                        flags='--compile -O2';;
        esac

        # XXX: where does it come from?!
        unset PYTHONDONTWRITEBYTECODE

        cd "${BUILD_DIR}" || die
        "${PYTHON}" setup.py install ${flags} --root="${D}" || die

        distutils-r1_rename_scripts
}

# @FUNCTION: distutils-r1_python_install_all
# @DESCRIPTION:
# The default python_install_all(). It creates wrappers
# for the implementation-suffixed executables.
distutils-r1_python_install_all() {
        local wrapdir=${T}/distutils_wrappers

        if [[ -d ${wrapdir} ]]; then
                cp -r "${wrapdir}/." "${D}" || die
        fi
}

distutils-r1_src_prepare() {
        # common preparations
        if declare -f python_prepare_all >/dev/null; then
                python_prepare_all
        else
                distutils-r1_python_prepare_all
        fi

        if declare -f python_prepare >/dev/null; then
                python_foreach_impl python_prepare
        else
                distutils-r1_python_prepare
        fi
}

distutils-r1_src_configure() {
        if declare -f python_configure >/dev/null; then
                python_foreach_impl python_configure
        else
                distutils-r1_python_configure
        fi

        if declare -f python_configure_all >/dev/null; then
                python_configure_all
        fi
}

distutils-r1_src_compile() {
        if declare -f python_compile >/dev/null; then
                python_foreach_impl python_compile
        else
                python_foreach_impl distutils-r1_python_compile
        fi

        if declare -f python_compile_all >/dev/null; then
                python_compile_all
        fi
}

distutils-r1_src_test() {
        if declare -f python_test >/dev/null; then
                python_foreach_impl python_test
        else
                distutils-r1_python_test
        fi

        if declare -f python_test_all >/dev/null; then
                python_test_all
        fi
}

distutils-r1_src_install() {
        if declare -f python_install >/dev/null; then
                python_foreach_impl python_install
        else
                python_foreach_impl distutils-r1_python_install
        fi

        if declare -f python_install_all >/dev/null; then
                python_install_all
        else
                distutils-r1_python_install_all
        fi
}

Attachment: signature.asc
Description: PGP signature

Reply via email to