diff options
Diffstat (limited to 'eclass/python-single-r1.eclass')
-rw-r--r-- | eclass/python-single-r1.eclass | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/eclass/python-single-r1.eclass b/eclass/python-single-r1.eclass new file mode 100644 index 000000000000..0f21fb7e354b --- /dev/null +++ b/eclass/python-single-r1.eclass @@ -0,0 +1,468 @@ +# Copyright 1999-2015 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ + +# @ECLASS: python-single-r1 +# @MAINTAINER: +# Python team <python@gentoo.org> +# @AUTHOR: +# Author: Michał Górny <mgorny@gentoo.org> +# Based on work of: Krzysztof Pawlik <nelchael@gentoo.org> +# @BLURB: An eclass for Python packages not installed for multiple implementations. +# @DESCRIPTION: +# An extension of the python-r1 eclass suite for packages which +# don't support being installed for multiple Python implementations. +# This mostly includes tools embedding Python. +# +# This eclass extends the IUSE and REQUIRED_USE set by python-r1 +# to request the PYTHON_SINGLE_TARGET when the inheriting ebuild +# can be supported by more than one Python implementation. It also +# replaces PYTHON_USEDEP and PYTHON_DEPS with a more suitable form. +# +# Please note that packages support multiple Python implementations +# (using python-r1 eclass) can not depend on packages not supporting +# them (using this eclass). +# +# Please note that python-single-r1 will always inherit python-utils-r1 +# as well. Thus, all the functions defined there can be used +# in the packages using python-single-r1, and there is no need ever +# to inherit both. +# +# For more information, please see the wiki: +# https://wiki.gentoo.org/wiki/Project:Python/python-single-r1 + +case "${EAPI:-0}" in + 0|1|2|3) + die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" + ;; + 4) + # EAPI=4 is only allowed on legacy packages + if [[ ${CATEGORY}/${P} == app-arch/threadzip-1.2 ]]; then + : + elif [[ ${CATEGORY}/${P} == media-libs/lv2-1.8.0 ]]; then + : + elif [[ ${CATEGORY}/${P} == media-libs/lv2-1.10.0 ]]; then + : + elif [[ ${CATEGORY}/${P} == sys-apps/paludis-1* ]]; then + : + elif [[ ${CATEGORY}/${P} == sys-apps/paludis-2.[02].0 ]]; then + : + elif [[ ${CATEGORY}/${P} == sys-apps/util-linux-2.2[456]* ]]; then + : + elif [[ ${CATEGORY}/${P} == */gdb-7.[78]* ]]; then + : + else + die "Unsupported EAPI=${EAPI:-4} (too old, allowed only on restricted set of packages) for ${ECLASS}" + fi + ;; + 5) + # EAPI=5 is required for sane USE_EXPAND dependencies + ;; + *) + die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" + ;; +esac + +if [[ ! ${_PYTHON_SINGLE_R1} ]]; then + +if [[ ${_PYTHON_R1} ]]; then + die 'python-single-r1.eclass can not be used with python-r1.eclass.' +elif [[ ${_PYTHON_ANY_R1} ]]; then + die 'python-single-r1.eclass can not be used with python-any-r1.eclass.' +fi + +inherit python-utils-r1 + +fi + +EXPORT_FUNCTIONS pkg_setup + +if [[ ! ${_PYTHON_SINGLE_R1} ]]; then + +# @ECLASS-VARIABLE: PYTHON_COMPAT +# @REQUIRED +# @DESCRIPTION: +# This variable contains a list of Python implementations the package +# supports. It must be set before the `inherit' call. It has to be +# an array. +# +# Example: +# @CODE +# PYTHON_COMPAT=( python{2_5,2_6,2_7} ) +# @CODE +if ! declare -p PYTHON_COMPAT &>/dev/null; then + die 'PYTHON_COMPAT not declared.' +fi + +# @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. +# +# This should be set before calling `inherit'. +# +# Example: +# @CODE +# PYTHON_REQ_USE="gdbm,ncurses(-)?" +# @CODE +# +# It will cause the Python dependencies to look like: +# @CODE +# python_single_target_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. +# +# The dependency string is conditional on PYTHON_SINGLE_TARGET. +# +# Example use: +# @CODE +# RDEPEND="${PYTHON_DEPS} +# dev-foo/mydep" +# DEPEND="${RDEPEND}" +# @CODE +# +# Example value: +# @CODE +# dev-lang/python-exec:= +# python_single_target_python2_6? ( dev-lang/python:2.6[gdbm] ) +# python_single_target_python2_7? ( dev-lang/python:2.7[gdbm] ) +# @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. +# +# The generate USE-flag list is compatible with packages using python-r1, +# python-single-r1 and python-distutils-ng eclasses. It must not be used +# on packages using python.eclass. +# +# Example use: +# @CODE +# RDEPEND="dev-python/foo[${PYTHON_USEDEP}]" +# @CODE +# +# Example value: +# @CODE +# python_targets_python2_7(-)?,python_single_target_python2_7(+)? +# @CODE + +# @ECLASS-VARIABLE: PYTHON_REQUIRED_USE +# @DESCRIPTION: +# This is an eclass-generated required-use expression which ensures the following +# when more than one python implementation is possible: +# 1. Exactly one PYTHON_SINGLE_TARGET value has been enabled. +# 2. The selected PYTHON_SINGLE_TARGET value is enabled in PYTHON_TARGETS. +# +# This expression should be utilized in an ebuild by including it in +# REQUIRED_USE, optionally behind a use flag. +# +# Example use: +# @CODE +# REQUIRED_USE="python? ( ${PYTHON_REQUIRED_USE} )" +# @CODE +# +# Example value: +# @CODE +# python_single_target_python2_6? ( python_targets_python2_6 ) +# python_single_target_python2_7? ( python_targets_python2_7 ) +# ^^ ( python_single_target_python2_6 python_single_target_python2_7 ) +# @CODE + +_python_single_set_globals() { + local impls=() + local unimpls=() + + PYTHON_DEPS= + local i PYTHON_PKG_DEP + for i in "${_PYTHON_ALL_IMPLS[@]}"; do + has "${i}" "${PYTHON_COMPAT[@]}" \ + && impls+=( "${i}" ) \ + || unimpls+=( "${i}" ) + done + + if [[ ${#impls[@]} -eq 0 ]]; then + die "No supported implementation in PYTHON_COMPAT." + fi + + local flags_mt=( "${impls[@]/#/python_targets_}" ) + local flags=( "${impls[@]/#/python_single_target_}" ) + local unflags=( "${unimpls[@]/#/-python_single_target_}" ) + + local optflags=${flags_mt[@]/%/(-)?},${unflags[@]/%/(-)} + + IUSE="${flags_mt[*]}" + + if [[ ${#impls[@]} -eq 1 ]]; then + # There is only one supported implementation; set IUSE and other + # variables without PYTHON_SINGLE_TARGET. + PYTHON_REQUIRED_USE="${flags_mt[*]}" + python_export "${impls[0]}" PYTHON_PKG_DEP + PYTHON_DEPS="${PYTHON_PKG_DEP} " + # Force on the python_single_target_* flag for this impl, so + # that any dependencies that inherit python-single-r1 and + # happen to have multiple implementations will still need + # to bound by the implementation used by this package. + optflags+=,${flags[0]/%/(+)} + else + # Multiple supported implementations; honor PYTHON_SINGLE_TARGET. + IUSE+=" ${flags[*]}" + PYTHON_REQUIRED_USE="^^ ( ${flags[*]} )" + # Ensure deps honor the same python_single_target_* flag as is set + # on this package. + optflags+=,${flags[@]/%/(+)?} + + for i in "${impls[@]}"; do + # The chosen targets need to be in PYTHON_TARGETS as well. + # This is in order to enforce correct dependencies on packages + # supporting multiple implementations. + PYTHON_REQUIRED_USE+=" python_single_target_${i}? ( python_targets_${i} )" + + python_export "${i}" PYTHON_PKG_DEP + PYTHON_DEPS+="python_single_target_${i}? ( ${PYTHON_PKG_DEP} ) " + done + fi + PYTHON_USEDEP=${optflags// /,} + + # 1) well, python-exec would suffice as an RDEP + # but no point in making this overcomplex, BDEP doesn't hurt anyone + # 2) python-exec should be built with all targets forced anyway + # but if new targets were added, we may need to force a rebuild + # 3) use whichever python-exec slot installed in EAPI 5. For EAPI 4, + # just fix :2 since := deps are not supported. + if [[ ${_PYTHON_WANT_PYTHON_EXEC2} == 0 ]]; then + die "python-exec:0 is no longer supported, please fix your ebuild to work with python-exec:2" + elif [[ ${EAPI} != 4 ]]; then + PYTHON_DEPS+=">=dev-lang/python-exec-2:=[${PYTHON_USEDEP}]" + else + PYTHON_DEPS+="dev-lang/python-exec:2[${PYTHON_USEDEP}]" + fi +} +_python_single_set_globals + +# @FUNCTION: python_gen_usedep +# @USAGE: <pattern> [...] +# @DESCRIPTION: +# Output a USE dependency string for Python implementations which +# are both in PYTHON_COMPAT and match any of the patterns passed +# as parameters to the function. +# +# Remember to escape or quote the patterns to prevent shell filename +# expansion. +# +# When all implementations are requested, please use ${PYTHON_USEDEP} +# instead. Please also remember to set an appropriate REQUIRED_USE +# to avoid ineffective USE flags. +# +# Example: +# @CODE +# PYTHON_COMPAT=( python{2_7,3_4} ) +# DEPEND="doc? ( dev-python/epydoc[$(python_gen_usedep 'python2*')] )" +# @CODE +# +# It will cause the dependency to look like: +# @CODE +# DEPEND="doc? ( dev-python/epydoc[python_targets_python2_7(-)?,...] )" +# @CODE +python_gen_usedep() { + debug-print-function ${FUNCNAME} "${@}" + + local impl pattern + local matches=() + + for impl in "${PYTHON_COMPAT[@]}"; do + _python_impl_supported "${impl}" || continue + + for pattern; do + if [[ ${impl} == ${pattern} ]]; then + matches+=( + "python_targets_${impl}(-)?" + "python_single_target_${impl}(+)?" + ) + break + fi + done + done + + [[ ${matches[@]} ]] || die "No supported implementations match python_gen_usedep patterns: ${@}" + + local out=${matches[@]} + echo "${out// /,}" +} + +# @FUNCTION: python_gen_useflags +# @USAGE: <pattern> [...] +# @DESCRIPTION: +# Output a list of USE flags for Python implementations which +# are both in PYTHON_COMPAT and match any of the patterns passed +# as parameters to the function. +# +# Example: +# @CODE +# PYTHON_COMPAT=( python{2_7,3_4} ) +# REQUIRED_USE="doc? ( ^^ ( $(python_gen_useflags 'python2*') ) )" +# @CODE +# +# It will cause the variable to look like: +# @CODE +# REQUIRED_USE="doc? ( ^^ ( python_single_target_python2_7 ) )" +# @CODE +python_gen_useflags() { + debug-print-function ${FUNCNAME} "${@}" + + local impl pattern + local matches=() + + for impl in "${PYTHON_COMPAT[@]}"; do + _python_impl_supported "${impl}" || continue + + for pattern; do + if [[ ${impl} == ${pattern} ]]; then + matches+=( "python_single_target_${impl}" ) + break + fi + done + done + + echo "${matches[@]}" +} + +# @FUNCTION: python_gen_cond_dep +# @USAGE: <dependency> <pattern> [...] +# @DESCRIPTION: +# Output a list of <dependency>-ies made conditional to USE flags +# of Python implementations which are both in PYTHON_COMPAT and match +# any of the patterns passed as the remaining parameters. +# +# In order to enforce USE constraints on the packages, verbatim +# '${PYTHON_USEDEP}' (quoted!) may be placed in the dependency +# specification. It will get expanded within the function into a proper +# USE dependency string. +# +# Example: +# @CODE +# PYTHON_COMPAT=( python{2_5,2_6,2_7} ) +# RDEPEND="$(python_gen_cond_dep \ +# 'dev-python/unittest2[${PYTHON_USEDEP}]' python{2_5,2_6})" +# @CODE +# +# It will cause the variable to look like: +# @CODE +# RDEPEND="python_single_target_python2_5? ( +# dev-python/unittest2[python_targets_python2_5(-)?,...] ) +# python_single_target_python2_6? ( +# dev-python/unittest2[python_targets_python2_6(-)?,...] )" +# @CODE +python_gen_cond_dep() { + debug-print-function ${FUNCNAME} "${@}" + + local impl pattern + local matches=() + + local dep=${1} + shift + + for impl in "${PYTHON_COMPAT[@]}"; do + _python_impl_supported "${impl}" || continue + + for pattern; do + if [[ ${impl} == ${pattern} ]]; then + # substitute ${PYTHON_USEDEP} if used + # (since python_gen_usedep() will not return ${PYTHON_USEDEP} + # the code is run at most once) + if [[ ${dep} == *'${PYTHON_USEDEP}'* ]]; then + local PYTHON_USEDEP=$(python_gen_usedep "${@}") + dep=${dep//\$\{PYTHON_USEDEP\}/${PYTHON_USEDEP}} + fi + + matches+=( "python_single_target_${impl}? ( ${dep} )" ) + break + fi + done + done + + echo "${matches[@]}" +} + +# @FUNCTION: python_setup +# @DESCRIPTION: +# Determine what the selected Python implementation is and set +# the Python build environment up for it. +python_setup() { + debug-print-function ${FUNCNAME} "${@}" + + unset EPYTHON + + local impl impls=() + for impl in "${PYTHON_COMPAT[@]}"; do + _python_impl_supported "${impl}" || continue + impls+=( "${impl}" ) + done + + if [[ ${#impls[@]} -eq 1 ]]; then + if use "python_targets_${impls[0]}"; then + # Only one supported implementation, enable it explicitly + python_export "${impls[0]}" EPYTHON PYTHON + python_wrapper_setup + fi + else + for impl in "${impls[@]}"; do + if use "python_single_target_${impl}"; then + if [[ ${EPYTHON} ]]; then + eerror "Your PYTHON_SINGLE_TARGET setting lists more than a single Python" + eerror "implementation. Please set it to just one value. If you need" + eerror "to override the value for a single package, please use package.env" + eerror "or an equivalent solution (man 5 portage)." + echo + die "More than one implementation in PYTHON_SINGLE_TARGET." + fi + + if ! use "python_targets_${impl}"; then + eerror "The implementation chosen as PYTHON_SINGLE_TARGET must be added" + eerror "to PYTHON_TARGETS as well. This is in order to ensure that" + eerror "dependencies are satisfied correctly. We're sorry" + eerror "for the inconvenience." + echo + die "Build target (${impl}) not in PYTHON_TARGETS." + fi + + python_export "${impl}" EPYTHON PYTHON + python_wrapper_setup + fi + done + fi + + if [[ ! ${EPYTHON} ]]; then + eerror "No Python implementation selected for the build. Please set" + if [[ ${#impls[@]} -eq 1 ]]; then + eerror "the PYTHON_TARGETS variable in your make.conf to include one" + else + eerror "the PYTHON_SINGLE_TARGET variable in your make.conf to one" + fi + eerror "of the following values:" + eerror + eerror "${impls[@]}" + echo + die "No supported Python implementation in PYTHON_SINGLE_TARGET/PYTHON_TARGETS." + fi +} + +# @FUNCTION: python-single-r1_pkg_setup +# @DESCRIPTION: +# Runs python_setup. +python-single-r1_pkg_setup() { + debug-print-function ${FUNCNAME} "${@}" + + [[ ${MERGE_TYPE} != binary ]] && python_setup +} + +_PYTHON_SINGLE_R1=1 +fi |