summaryrefslogtreecommitdiff
path: root/eclass/python-any-r1.eclass
diff options
context:
space:
mode:
Diffstat (limited to 'eclass/python-any-r1.eclass')
-rw-r--r--eclass/python-any-r1.eclass356
1 files changed, 356 insertions, 0 deletions
diff --git a/eclass/python-any-r1.eclass b/eclass/python-any-r1.eclass
new file mode 100644
index 000000000000..e4d2d46bc706
--- /dev/null
+++ b/eclass/python-any-r1.eclass
@@ -0,0 +1,356 @@
+# Copyright 1999-2017 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: python-any-r1.eclass
+# @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 packages having build-time dependency on Python.
+# @DESCRIPTION:
+# A minimal eclass for packages which need any Python interpreter
+# installed without a need for explicit choice and invariability.
+# This usually involves packages requiring Python at build-time
+# but having no other relevance to it.
+#
+# This eclass provides a minimal PYTHON_DEPS variable with a dependency
+# string on any of the supported Python implementations. It also exports
+# pkg_setup() which finds the best supported implementation and sets it
+# as the active one.
+#
+# Optionally, you can define a python_check_deps() function. It will
+# be called by the eclass with EPYTHON set to each matching Python
+# implementation and it is expected to check whether the implementation
+# fulfills the package requirements. You can use the locally exported
+# PYTHON_USEDEP to check USE-dependencies of relevant packages. It
+# should return a true value (0) if the Python implementation fulfills
+# the requirements, a false value (non-zero) otherwise.
+#
+# Please note that python-any-r1 will always inherit python-utils-r1
+# as well. Thus, all the functions defined there can be used in the
+# packages using python-any-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-any-r1
+
+case "${EAPI:-0}" in
+ 0|1|2|3|4|5|6)
+ ;;
+ *)
+ die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
+ ;;
+esac
+
+if [[ ! ${_PYTHON_ANY_R1} ]]; then
+
+if [[ ${_PYTHON_R1} ]]; then
+ die 'python-any-r1.eclass can not be used with python-r1.eclass.'
+elif [[ ${_PYTHON_SINGLE_R1} ]]; then
+ die 'python-any-r1.eclass can not be used with python-single-r1.eclass.'
+fi
+
+inherit python-utils-r1
+
+fi
+
+EXPORT_FUNCTIONS pkg_setup
+
+# @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
+
+# @ECLASS-VARIABLE: PYTHON_COMPAT_OVERRIDE
+# @INTERNAL
+# @DESCRIPTION:
+# This variable can be used when working with ebuilds to override
+# the in-ebuild PYTHON_COMPAT. It is a string naming the implementation
+# which will be used to build the package. It needs to be specified
+# in the calling environment, and not in ebuilds.
+#
+# It should be noted that in order to preserve metadata immutability,
+# PYTHON_COMPAT_OVERRIDE does not affect dependencies. The value of
+# EPYTHON and eselect-python preferences are ignored. Dependencies need
+# to be satisfied manually.
+#
+# Example:
+# @CODE
+# PYTHON_COMPAT_OVERRIDE='pypy' emerge -1v dev-python/bar
+# @CODE
+
+# @ECLASS-VARIABLE: PYTHON_REQ_USE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# The list of USEflags required to be enabled on the 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
+#
+# It will cause the Python dependencies to look like:
+# @CODE
+# || ( 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.
+#
+# Any of the supported interpreters will satisfy the dependency.
+#
+# Example use:
+# @CODE
+# DEPEND="${RDEPEND}
+# ${PYTHON_DEPS}"
+# @CODE
+#
+# Example value:
+# @CODE
+# || ( dev-lang/python:2.7[gdbm]
+# dev-lang/python:2.6[gdbm] )
+# @CODE
+
+# @ECLASS-VARIABLE: PYTHON_USEDEP
+# @DESCRIPTION:
+# An eclass-generated USE-dependency string for the currently tested
+# implementation. It is set locally for python_check_deps() call.
+#
+# 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
+# python_check_deps() {
+# has_version "dev-python/foo[${PYTHON_USEDEP}]"
+# }
+# @CODE
+#
+# Example value:
+# @CODE
+# python_targets_python2_7(-)?,python_single_target_python2_7(+)?
+# @CODE
+
+_python_any_set_globals() {
+ local usestr deps i PYTHON_PKG_DEP
+ [[ ${PYTHON_REQ_USE} ]] && usestr="[${PYTHON_REQ_USE}]"
+
+ _python_set_impls
+
+ for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
+ python_export "${i}" PYTHON_PKG_DEP
+
+ # note: need to strip '=' slot operator for || deps
+ deps="${PYTHON_PKG_DEP%=} ${deps}"
+ done
+ deps="|| ( ${deps})"
+
+ if [[ ${PYTHON_DEPS+1} ]]; then
+ if [[ ${PYTHON_DEPS} != "${deps}" ]]; then
+ eerror "PYTHON_DEPS have changed between inherits (PYTHON_REQ_USE?)!"
+ eerror "Before: ${PYTHON_DEPS}"
+ eerror "Now : ${deps}"
+ die "PYTHON_DEPS integrity check failed"
+ fi
+ else
+ PYTHON_DEPS=${deps}
+ readonly PYTHON_DEPS
+ fi
+}
+_python_any_set_globals
+unset -f _python_any_set_globals
+
+if [[ ! ${_PYTHON_ANY_R1} ]]; then
+
+# @FUNCTION: python_gen_any_dep
+# @USAGE: <dependency-block>
+# @DESCRIPTION:
+# Generate an any-of dependency that enforces a version match between
+# the Python interpreter and Python packages. <dependency-block> needs
+# to list one or more dependencies with verbatim '${PYTHON_USEDEP}'
+# references (quoted!) that will get expanded inside the function.
+#
+# This should be used along with an appropriate python_check_deps()
+# that checks which of the any-of blocks were matched.
+#
+# Example use:
+# @CODE
+# DEPEND="$(python_gen_any_dep '
+# dev-python/foo[${PYTHON_USEDEP}]
+# || ( dev-python/bar[${PYTHON_USEDEP}]
+# dev-python/baz[${PYTHON_USEDEP}] )')"
+#
+# python_check_deps() {
+# has_version "dev-python/foo[${PYTHON_USEDEP}]" \
+# && { has_version "dev-python/bar[${PYTHON_USEDEP}]" \
+# || has_version "dev-python/baz[${PYTHON_USEDEP}]"; }
+# }
+# @CODE
+#
+# Example value:
+# @CODE
+# || (
+# (
+# dev-lang/python:2.7
+# dev-python/foo[python_targets_python2_7(-)?,python_single_target_python2_7(+)?]
+# || ( dev-python/bar[python_targets_python2_7(-)?,python_single_target_python2_7(+)?]
+# dev-python/baz[python_targets_python2_7(-)?,python_single_target_python2_7(+)?] )
+# )
+# (
+# dev-lang/python:3.3
+# dev-python/foo[python_targets_python3_3(-)?,python_single_target_python3_3(+)?]
+# || ( dev-python/bar[python_targets_python3_3(-)?,python_single_target_python3_3(+)?]
+# dev-python/baz[python_targets_python3_3(-)?,python_single_target_python3_3(+)?] )
+# )
+# )
+# @CODE
+python_gen_any_dep() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ local depstr=${1}
+ [[ ${depstr} ]] || die "No dependency string provided"
+
+ local i PYTHON_PKG_DEP out=
+ for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
+ local PYTHON_USEDEP="python_targets_${i}(-),python_single_target_${i}(+)"
+ python_export "${i}" PYTHON_PKG_DEP
+
+ local i_depstr=${depstr//\$\{PYTHON_USEDEP\}/${PYTHON_USEDEP}}
+ # note: need to strip '=' slot operator for || deps
+ out="( ${PYTHON_PKG_DEP%=} ${i_depstr} ) ${out}"
+ done
+ echo "|| ( ${out})"
+}
+
+# @FUNCTION: _python_EPYTHON_supported
+# @USAGE: <epython>
+# @INTERNAL
+# @DESCRIPTION:
+# Check whether the specified implementation is supported by package
+# (specified in PYTHON_COMPAT). Calls python_check_deps() if declared.
+_python_EPYTHON_supported() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ local EPYTHON=${1}
+ local i=${EPYTHON/./_}
+
+ case "${i}" in
+ python*|jython*|pypy*)
+ ;;
+ *)
+ ewarn "Invalid EPYTHON: ${EPYTHON}"
+ return 1
+ ;;
+ esac
+
+ if has "${i}" "${_PYTHON_SUPPORTED_IMPLS[@]}"; then
+ if python_is_installed "${i}"; then
+ if declare -f python_check_deps >/dev/null; then
+ local PYTHON_USEDEP="python_targets_${i}(-),python_single_target_${i}(+)"
+ python_check_deps
+ return ${?}
+ fi
+
+ return 0
+ fi
+ elif ! has "${i}" "${_PYTHON_ALL_IMPLS[@]}"; then
+ ewarn "Invalid EPYTHON: ${EPYTHON}"
+ fi
+ return 1
+}
+
+# @FUNCTION: python_setup
+# @DESCRIPTION:
+# Determine what the best installed (and supported) Python
+# implementation is, and set the Python build environment up for it.
+#
+# This function will call python_check_deps() if defined.
+python_setup() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ # support developer override
+ if [[ ${PYTHON_COMPAT_OVERRIDE} ]]; then
+ local impls=( ${PYTHON_COMPAT_OVERRIDE} )
+ [[ ${#impls[@]} -eq 1 ]] || die "PYTHON_COMPAT_OVERRIDE must name exactly one implementation for python-any-r1"
+
+ ewarn "WARNING: PYTHON_COMPAT_OVERRIDE in effect. The following Python"
+ ewarn "implementation will be used:"
+ ewarn
+ ewarn " ${PYTHON_COMPAT_OVERRIDE}"
+ ewarn
+ ewarn "Dependencies won't be satisfied, and EPYTHON/eselect-python will be ignored."
+
+ python_export "${impls[0]}" EPYTHON PYTHON
+ python_wrapper_setup
+ return
+ fi
+
+ # first, try ${EPYTHON}... maybe it's good enough for us.
+ if [[ ${EPYTHON} ]]; then
+ if _python_EPYTHON_supported "${EPYTHON}"; then
+ python_export EPYTHON PYTHON
+ python_wrapper_setup
+ return
+ fi
+ fi
+
+ # then, try eselect-python
+ local variant i
+ for variant in '' '--python2' '--python3'; do
+ i=$(eselect python --show ${variant} 2>/dev/null)
+
+ if [[ ! ${i} ]]; then
+ # no eselect-python?
+ break
+ elif _python_EPYTHON_supported "${i}"; then
+ python_export "${i}" EPYTHON PYTHON
+ python_wrapper_setup
+ return
+ fi
+ done
+
+ # fallback to best installed impl.
+ # (reverse iteration over _PYTHON_SUPPORTED_IMPLS)
+ for (( i = ${#_PYTHON_SUPPORTED_IMPLS[@]} - 1; i >= 0; i-- )); do
+ python_export "${_PYTHON_SUPPORTED_IMPLS[i]}" EPYTHON PYTHON
+ if _python_EPYTHON_supported "${EPYTHON}"; then
+ python_wrapper_setup
+ return
+ fi
+ done
+
+ eerror "No Python implementation found for the build. This is usually"
+ eerror "a bug in the ebuild. Please report it to bugs.gentoo.org"
+ eerror "along with the build log."
+ echo
+ die "No supported Python implementation installed."
+}
+
+# @FUNCTION: python-any-r1_pkg_setup
+# @DESCRIPTION:
+# Runs python_setup during from-source installs.
+#
+# In a binary package installs is a no-op. If you need Python in pkg_*
+# phases of a binary package, call python_setup directly.
+python-any-r1_pkg_setup() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ [[ ${MERGE_TYPE} != binary ]] && python_setup
+}
+
+_PYTHON_ANY_R1=1
+fi