eclass/distutils-r1: Sync with gentoo

It's from gentoo commit 5ab05a55e2ec1b127d37df3fd7fdfb89633b95ab.
This commit is contained in:
Krzesimir Nowak 2021-11-30 17:19:51 +01:00
parent aad03a8242
commit 2aa09b1761

View File

@ -1,4 +1,4 @@
# Copyright 1999-2020 Gentoo Authors # Copyright 1999-2021 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2 # Distributed under the terms of the GNU General Public License v2
# @ECLASS: distutils-r1.eclass # @ECLASS: distutils-r1.eclass
@ -7,7 +7,8 @@
# @AUTHOR: # @AUTHOR:
# Author: Michał Górny <mgorny@gentoo.org> # Author: Michał Górny <mgorny@gentoo.org>
# Based on the work of: Krzysztof Pawlik <nelchael@gentoo.org> # Based on the work of: Krzysztof Pawlik <nelchael@gentoo.org>
# @SUPPORTED_EAPIS: 5 6 7 # @SUPPORTED_EAPIS: 6 7 8
# @PROVIDES: python-r1 python-single-r1
# @BLURB: A simple eclass to build Python packages using distutils. # @BLURB: A simple eclass to build Python packages using distutils.
# @DESCRIPTION: # @DESCRIPTION:
# A simple eclass providing functions to build Python packages using # A simple eclass providing functions to build Python packages using
@ -33,8 +34,8 @@
# functions, you should consider calling the defaults (and especially # functions, you should consider calling the defaults (and especially
# distutils-r1_python_prepare_all). # distutils-r1_python_prepare_all).
# #
# Please note that distutils-r1 sets RDEPEND and DEPEND unconditionally # Please note that distutils-r1 sets RDEPEND and BDEPEND (or DEPEND
# for you. # in earlier EAPIs) unconditionally for you.
# #
# Also, please note that distutils-r1 will always inherit python-r1 # Also, please note that distutils-r1 will always inherit python-r1
# as well. Thus, all the variables defined and documented there are # as well. Thus, all the variables defined and documented there are
@ -44,10 +45,10 @@
# https://dev.gentoo.org/~mgorny/python-guide/ # https://dev.gentoo.org/~mgorny/python-guide/
case "${EAPI:-0}" in case "${EAPI:-0}" in
0|1|2|3|4) [0-5])
die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
;; ;;
5|6|7) [6-8])
;; ;;
*) *)
die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
@ -85,10 +86,10 @@ esac
# #
# - no -- do not add the dependency (pure distutils package) # - no -- do not add the dependency (pure distutils package)
# - bdepend -- add it to BDEPEND (the default) # - bdepend -- add it to BDEPEND (the default)
# - rdepend -- add it to BDEPEND+RDEPEND (when using entry_points) # - rdepend -- add it to BDEPEND+RDEPEND (e.g. when using pkg_resources)
# - pyproject.toml -- use pyproject2setuptools to install a project # - pyproject.toml -- use pyproject2setuptools to install a project
# using pyproject.toml (flit, poetry...) # using pyproject.toml (flit, poetry...)
# - manual -- do not add the depedency and suppress the checks # - manual -- do not add the dependency and suppress the checks
# (assumes you will take care of doing it correctly) # (assumes you will take care of doing it correctly)
# #
# This variable is effective only if DISTUTILS_OPTIONAL is disabled. # This variable is effective only if DISTUTILS_OPTIONAL is disabled.
@ -97,8 +98,7 @@ esac
if [[ ! ${_DISTUTILS_R1} ]]; then if [[ ! ${_DISTUTILS_R1} ]]; then
[[ ${EAPI} == [456] ]] && inherit eutils [[ ${EAPI} == 6 ]] && inherit eutils xdg-utils
[[ ${EAPI} == [56] ]] && inherit xdg-utils
inherit multiprocessing toolchain-funcs inherit multiprocessing toolchain-funcs
if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
@ -130,7 +130,7 @@ _distutils_set_globals() {
rdep+=" ${setuptools_dep}" rdep+=" ${setuptools_dep}"
;; ;;
pyproject.toml) pyproject.toml)
bdep+=' dev-python/pyproject2setuppy[${PYTHON_USEDEP}]' bdep+=' >=dev-python/pyproject2setuppy-18[${PYTHON_USEDEP}]'
;; ;;
*) *)
die "Invalid DISTUTILS_USE_SETUPTOOLS=${DISTUTILS_USE_SETUPTOOLS}" die "Invalid DISTUTILS_USE_SETUPTOOLS=${DISTUTILS_USE_SETUPTOOLS}"
@ -146,7 +146,7 @@ _distutils_set_globals() {
fi fi
RDEPEND="${PYTHON_DEPS} ${rdep}" RDEPEND="${PYTHON_DEPS} ${rdep}"
if [[ ${EAPI} != [56] ]]; then if [[ ${EAPI} != 6 ]]; then
BDEPEND="${PYTHON_DEPS} ${bdep}" BDEPEND="${PYTHON_DEPS} ${bdep}"
else else
DEPEND="${PYTHON_DEPS} ${bdep}" DEPEND="${PYTHON_DEPS} ${bdep}"
@ -202,26 +202,6 @@ unset -f _distutils_set_globals
# HTML_DOCS=( doc/html/. ) # HTML_DOCS=( doc/html/. )
# @CODE # @CODE
# @ECLASS-VARIABLE: EXAMPLES
# @DEFAULT_UNSET
# @DESCRIPTION:
# OBSOLETE: this variable is deprecated and banned in EAPI 6
#
# An array containing examples installed into 'examples' doc
# subdirectory. The files and directories listed there must exist
# in the directory from which distutils-r1_python_install_all() is run
# (${S} by default).
#
# The 'examples' subdirectory will be marked not to be compressed
# automatically.
#
# If unset, no examples will be installed.
#
# Example:
# @CODE
# EXAMPLES=( examples/. demos/. )
# @CODE
# @ECLASS-VARIABLE: DISTUTILS_IN_SOURCE_BUILD # @ECLASS-VARIABLE: DISTUTILS_IN_SOURCE_BUILD
# @DEFAULT_UNSET # @DEFAULT_UNSET
# @DESCRIPTION: # @DESCRIPTION:
@ -269,15 +249,16 @@ unset -f _distutils_set_globals
# } # }
# @CODE # @CODE
# @ECLASS-VARIABLE: mydistutilsargs # @ECLASS-VARIABLE: DISTUTILS_ARGS
# @DEFAULT_UNSET # @DEFAULT_UNSET
# @DESCRIPTION: # @DESCRIPTION:
# An array containing options to be passed to setup.py. # An array containing options to be passed to setup.py. They are passed
# before the default arguments, i.e. before the first command.
# #
# Example: # Example:
# @CODE # @CODE
# python_configure_all() { # python_configure_all() {
# mydistutilsargs=( --enable-my-hidden-option ) # DISTUTILS_ARGS=( --enable-my-hidden-option )
# } # }
# @CODE # @CODE
@ -316,22 +297,25 @@ distutils_enable_sphinx() {
_DISTUTILS_SPHINX_PLUGINS=( "${@}" ) _DISTUTILS_SPHINX_PLUGINS=( "${@}" )
local deps autodoc=1 d local deps autodoc=1 d
deps="dev-python/sphinx[\${PYTHON_USEDEP}]"
for d; do for d; do
if [[ ${d} == --no-autodoc ]]; then if [[ ${d} == --no-autodoc ]]; then
autodoc= autodoc=
else else
deps+=" deps+="
${d}[\${PYTHON_USEDEP}]" ${d}[\${PYTHON_USEDEP}]"
if [[ ! ${autodoc} ]]; then
die "${FUNCNAME}: do not pass --no-autodoc if external plugins are used"
fi
fi fi
done done
if [[ ! ${autodoc} && -n ${deps} ]]; then
die "${FUNCNAME}: do not pass --no-autodoc if external plugins are used"
fi
if [[ ${autodoc} ]]; then if [[ ${autodoc} ]]; then
deps="$(python_gen_any_dep " if [[ ${DISTUTILS_SINGLE_IMPL} ]]; then
dev-python/sphinx[\${PYTHON_USEDEP}] deps="$(python_gen_cond_dep "${deps}")"
${deps}")" else
deps="$(python_gen_any_dep "${deps}")"
fi
python_check_deps() { python_check_deps() {
use doc || return 0 use doc || return 0
@ -366,7 +350,7 @@ distutils_enable_sphinx() {
python_compile_all() { sphinx_compile_all; } python_compile_all() { sphinx_compile_all; }
IUSE+=" doc" IUSE+=" doc"
if [[ ${EAPI} == [56] ]]; then if [[ ${EAPI} == 6 ]]; then
DEPEND+=" doc? ( ${deps} )" DEPEND+=" doc? ( ${deps} )"
else else
BDEPEND+=" doc? ( ${deps} )" BDEPEND+=" doc? ( ${deps} )"
@ -385,8 +369,11 @@ distutils_enable_sphinx() {
# of RDEPEND to test?-BDEPEND. The test-runner argument must be one of: # of RDEPEND to test?-BDEPEND. The test-runner argument must be one of:
# #
# - nose: nosetests (dev-python/nose) # - nose: nosetests (dev-python/nose)
#
# - pytest: dev-python/pytest # - pytest: dev-python/pytest
#
# - setup.py: setup.py test (no deps included) # - setup.py: setup.py test (no deps included)
#
# - unittest: for built-in Python unittest module # - unittest: for built-in Python unittest module
# #
# Additionally, if --install is passed as the first parameter, # Additionally, if --install is passed as the first parameter,
@ -403,10 +390,10 @@ distutils_enable_sphinx() {
distutils_enable_tests() { distutils_enable_tests() {
debug-print-function ${FUNCNAME} "${@}" debug-print-function ${FUNCNAME} "${@}"
local do_install= _DISTUTILS_TEST_INSTALL=
case ${1} in case ${1} in
--install) --install)
do_install=1 _DISTUTILS_TEST_INSTALL=1
shift shift
;; ;;
esac esac
@ -416,76 +403,36 @@ distutils_enable_tests() {
case ${1} in case ${1} in
nose) nose)
test_pkg=">=dev-python/nose-1.3.7-r4" test_pkg=">=dev-python/nose-1.3.7-r4"
if [[ ${do_install} ]]; then
python_test() {
distutils_install_for_testing --via-root
nosetests -v || die "Tests fail with ${EPYTHON}"
}
else
python_test() {
nosetests -v || die "Tests fail with ${EPYTHON}"
}
fi
;; ;;
pytest) pytest)
test_pkg=">=dev-python/pytest-4.5.0" test_pkg=">=dev-python/pytest-4.5.0"
if [[ ${do_install} ]]; then
python_test() {
distutils_install_for_testing --via-root
pytest -vv || die "Tests fail with ${EPYTHON}"
}
else
python_test() {
pytest -vv || die "Tests fail with ${EPYTHON}"
}
fi
;; ;;
setup.py) setup.py)
if [[ ${do_install} ]]; then
python_test() {
distutils_install_for_testing --via-root
nonfatal esetup.py test --verbose ||
die "Tests fail with ${EPYTHON}"
}
else
python_test() {
nonfatal esetup.py test --verbose ||
die "Tests fail with ${EPYTHON}"
}
fi
;; ;;
unittest) unittest)
if [[ ${do_install} ]]; then test_pkg="dev-python/unittest-or-fail"
python_test() {
distutils_install_for_testing --via-root
"${EPYTHON}" -m unittest discover -v ||
die "Tests fail with ${EPYTHON}"
}
else
python_test() {
"${EPYTHON}" -m unittest discover -v ||
die "Tests fail with ${EPYTHON}"
}
fi
;; ;;
*) *)
die "${FUNCNAME}: unsupported argument: ${1}" die "${FUNCNAME}: unsupported argument: ${1}"
esac esac
_DISTUTILS_TEST_RUNNER=${1}
python_test() { distutils-r1_python_test; }
local test_deps=${RDEPEND} local test_deps=${RDEPEND}
if [[ -n ${test_pkg} ]]; then if [[ -n ${test_pkg} ]]; then
if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
test_deps+=" ${test_pkg}[${PYTHON_USEDEP}]" test_deps+=" ${test_pkg}[${PYTHON_USEDEP}]"
else else
test_deps+=" $(python_gen_cond_dep " test_deps+=" $(python_gen_cond_dep "
${test_pkg}[\${PYTHON_MULTI_USEDEP}] ${test_pkg}[\${PYTHON_USEDEP}]
")" ")"
fi fi
fi fi
if [[ -n ${test_deps} ]]; then if [[ -n ${test_deps} ]]; then
IUSE+=" test" IUSE+=" test"
RESTRICT+=" !test? ( test )" RESTRICT+=" !test? ( test )"
if [[ ${EAPI} == [56] ]]; then if [[ ${EAPI} == 6 ]]; then
DEPEND+=" test? ( ${test_deps} )" DEPEND+=" test? ( ${test_deps} )"
else else
BDEPEND+=" test? ( ${test_deps} )" BDEPEND+=" test? ( ${test_deps} )"
@ -504,8 +451,9 @@ distutils_enable_tests() {
# (if ${EPYTHON} is set; fallback 'python' otherwise). # (if ${EPYTHON} is set; fallback 'python' otherwise).
# #
# setup.py will be passed the following, in order: # setup.py will be passed the following, in order:
# 1. ${mydistutilsargs[@]} # 1. ${DISTUTILS_ARGS[@]}
# 2. additional arguments passed to the esetup.py function. # 2. ${mydistutilsargs[@]} (deprecated)
# 3. additional arguments passed to the esetup.py function.
# #
# Please note that setup.py will respect defaults (unless overridden # Please note that setup.py will respect defaults (unless overridden
# via command-line options) from setup.cfg that is created # via command-line options) from setup.cfg that is created
@ -515,26 +463,35 @@ distutils_enable_tests() {
esetup.py() { esetup.py() {
debug-print-function ${FUNCNAME} "${@}" debug-print-function ${FUNCNAME} "${@}"
local die_args=() _python_check_EPYTHON
[[ ${EAPI} != [45] ]] && die_args+=( -n )
[[ ${BUILD_DIR} ]] && _distutils-r1_create_setup_cfg [[ ${BUILD_DIR} ]] && _distutils-r1_create_setup_cfg
set -- "${EPYTHON:-python}" setup.py "${mydistutilsargs[@]}" "${@}" local setup_py=( setup.py )
if [[ ${DISTUTILS_USE_SETUPTOOLS} == pyproject.toml ]]; then
setup_py=( -m pyproject2setuppy )
fi
if [[ ${EAPI} != [67] && ${mydistutilsargs[@]} ]]; then
die "mydistutilsargs is banned in EAPI ${EAPI} (use DISTUTILS_ARGS)"
fi
set -- "${EPYTHON}" "${setup_py[@]}" "${DISTUTILS_ARGS[@]}" \
"${mydistutilsargs[@]}" "${@}"
echo "${@}" >&2 echo "${@}" >&2
"${@}" || die "${die_args[@]}" "${@}" || die -n
local ret=${?} local ret=${?}
if [[ ${BUILD_DIR} ]]; then if [[ ${BUILD_DIR} ]]; then
rm "${HOME}"/.pydistutils.cfg || die "${die_args[@]}" rm "${HOME}"/.pydistutils.cfg || die -n
fi fi
return ${ret} return ${ret}
} }
# @FUNCTION: distutils_install_for_testing # @FUNCTION: distutils_install_for_testing
# @USAGE: [--via-root|--via-home] [<args>...] # @USAGE: [--via-root|--via-home|--via-venv] [<args>...]
# @DESCRIPTION: # @DESCRIPTION:
# Install the package into a temporary location for running tests. # Install the package into a temporary location for running tests.
# Update PYTHONPATH appropriately and set TEST_DIR to the test # Update PYTHONPATH appropriately and set TEST_DIR to the test
@ -546,35 +503,40 @@ esetup.py() {
# PYTHONPATH) or tests rely on the results of install command. # PYTHONPATH) or tests rely on the results of install command.
# For most of the packages, tests built in BUILD_DIR are good enough. # For most of the packages, tests built in BUILD_DIR are good enough.
# #
# The function supports two install modes. The current default is # The function supports three install modes. These are:
# the legacy --via-home mode. However, it has problems with newer #
# versions of setuptools (50.3.0+). The --via-root mode generally # --via-root (the default) that uses 'setup.py install --root=...'
# works for these packages, and it will probably become the default # combined with PYTHONPATH and is recommended for the majority
# in the future, once we test all affected packages. Please note # of packages.
# that proper testing sometimes requires unmerging the package first. #
# --via-venv that creates a (non-isolated) venv and installs the package
# into it via 'setup.py install'. This mode does not use PYTHONPATH
# but requires python to be called via PATH. It may solve a few corner
# cases that --via-root do not support.
#
# --via-home that uses 'setup.py install --home=...'. This is
# a historical mode that was mostly broken by setuptools 50.3.0+.
# If your package does not work with the other two modes but works with
# this one, please report a bug.
#
# Please note that in order to test the solution properly you need
# to unmerge the package first.
distutils_install_for_testing() { distutils_install_for_testing() {
debug-print-function ${FUNCNAME} "${@}" debug-print-function ${FUNCNAME} "${@}"
# A few notes: # A few notes about --via-home mode:
# 1) because of namespaces, we can't use 'install --root' # 1) 'install --home' is terribly broken on pypy, so we need
# (NB: this is probably no longer true with py3),
# 2) 'install --home' is terribly broken on pypy, so we need
# to override --install-lib and --install-scripts, # to override --install-lib and --install-scripts,
# 3) non-root 'install' complains about PYTHONPATH and missing dirs, # 2) non-root 'install' complains about PYTHONPATH and missing dirs,
# so we need to set it properly and mkdir them, # so we need to set it properly and mkdir them,
# 4) it runs a bunch of commands which write random files to cwd, # 3) it runs a bunch of commands which write random files to cwd,
# in order to avoid that, we add the necessary path overrides # in order to avoid that, we add the necessary path overrides
# in _distutils-r1_create_setup_cfg. # in _distutils-r1_create_setup_cfg.
TEST_DIR=${BUILD_DIR}/test local install_method=root
local bindir=${TEST_DIR}/scripts
local libdir=${TEST_DIR}/lib
PATH=${bindir}:${PATH}
PYTHONPATH=${libdir}:${PYTHONPATH}
local install_method=home
case ${1} in case ${1} in
--via-home) --via-home)
[[ ${EAPI} == [67] ]] || die "${*} is banned in EAPI ${EAPI}"
install_method=home install_method=home
shift shift
;; ;;
@ -582,30 +544,50 @@ distutils_install_for_testing() {
install_method=root install_method=root
shift shift
;; ;;
--via-venv)
install_method=venv
shift
;;
esac esac
local -a add_args TEST_DIR=${BUILD_DIR}/test
case ${install_method} in local add_args=()
home)
add_args=( if [[ ${install_method} == venv ]]; then
install "${EPYTHON}" -m venv --system-site-packages --without-pip \
"${TEST_DIR}" || die
# we only do the minimal necessary subset of activate script
PATH=${TEST_DIR}/bin:${PATH}
# unset PYTHONPATH in order to prevent BUILD_DIR from overriding
# venv packages
unset PYTHONPATH
else
local bindir=${TEST_DIR}/scripts
local libdir=${TEST_DIR}/lib
PATH=${bindir}:${PATH}
PYTHONPATH=${libdir}:${PYTHONPATH}
case ${install_method} in
home)
add_args=(
--home="${TEST_DIR}" --home="${TEST_DIR}"
--install-lib="${libdir}" --install-lib="${libdir}"
--install-scripts="${bindir}" --install-scripts="${bindir}"
) )
mkdir -p "${libdir}" || die mkdir -p "${libdir}" || die
;; ;;
root) root)
add_args=( add_args=(
install
--root="${TEST_DIR}" --root="${TEST_DIR}"
--install-lib=lib --install-lib=lib
--install-scripts=scripts --install-scripts=scripts
) )
;; ;;
esac esac
fi
esetup.py "${add_args[@]}" "${@}" esetup.py install "${add_args[@]}" "${@}"
} }
# @FUNCTION: _distutils-r1_disable_ez_setup # @FUNCTION: _distutils-r1_disable_ez_setup
@ -628,15 +610,10 @@ _distutils-r1_disable_ez_setup() {
# @DESCRIPTION: # @DESCRIPTION:
# Generate setup.py for pyproject.toml if requested. # Generate setup.py for pyproject.toml if requested.
_distutils-r1_handle_pyproject_toml() { _distutils-r1_handle_pyproject_toml() {
[[ ${DISTUTILS_USE_SETUPTOOLS} == manual ]] && return
if [[ ! -f setup.py && -f pyproject.toml ]]; then if [[ ! -f setup.py && -f pyproject.toml ]]; then
if [[ ${DISTUTILS_USE_SETUPTOOLS} == pyproject.toml ]]; then if [[ ${DISTUTILS_USE_SETUPTOOLS} != pyproject.toml ]]; then
cat > setup.py <<-EOF || die
#!/usr/bin/env python
from pyproject2setuppy.main import main
main()
EOF
chmod +x setup.py || die
else
eerror "No setup.py found but pyproject.toml is present. In order to enable" eerror "No setup.py found but pyproject.toml is present. In order to enable"
eerror "pyproject.toml support in distutils-r1, set:" eerror "pyproject.toml support in distutils-r1, set:"
eerror " DISTUTILS_USE_SETUPTOOLS=pyproject.toml" eerror " DISTUTILS_USE_SETUPTOOLS=pyproject.toml"
@ -645,6 +622,21 @@ _distutils-r1_handle_pyproject_toml() {
fi fi
} }
# @FUNCTION: _distutils-r1_check_all_phase_mismatch
# @INTERNAL
# @DESCRIPTION:
# Verify whether *_all phase impls is not called from from non-*_all
# subphase.
_distutils-r1_check_all_phase_mismatch() {
if has "python_${EBUILD_PHASE}" "${FUNCNAME[@]}"; then
eqawarn "QA Notice: distutils-r1_python_${EBUILD_PHASE}_all called"
eqawarn "from python_${EBUILD_PHASE}. Did you mean to use"
eqawarn "python_${EBUILD_PHASE}_all()?"
[[ ${EAPI} != [67] ]] &&
die "distutils-r1_python_${EBUILD_PHASE}_all called from python_${EBUILD_PHASE}."
fi
}
# @FUNCTION: distutils-r1_python_prepare_all # @FUNCTION: distutils-r1_python_prepare_all
# @DESCRIPTION: # @DESCRIPTION:
# The default python_prepare_all(). It applies the patches from PATCHES # The default python_prepare_all(). It applies the patches from PATCHES
@ -655,14 +647,10 @@ _distutils-r1_handle_pyproject_toml() {
# distutils patches and/or quirks. # distutils patches and/or quirks.
distutils-r1_python_prepare_all() { distutils-r1_python_prepare_all() {
debug-print-function ${FUNCNAME} "${@}" debug-print-function ${FUNCNAME} "${@}"
_distutils-r1_check_all_phase_mismatch
if [[ ! ${DISTUTILS_OPTIONAL} ]]; then if [[ ! ${DISTUTILS_OPTIONAL} ]]; then
if [[ ${EAPI} != [45] ]]; then default
default
else
[[ ${PATCHES} ]] && epatch "${PATCHES[@]}"
epatch_user
fi
fi fi
# by default, use in-source build if python_prepare() is used # by default, use in-source build if python_prepare() is used
@ -684,24 +672,6 @@ distutils-r1_python_prepare_all() {
_DISTUTILS_DEFAULT_CALLED=1 _DISTUTILS_DEFAULT_CALLED=1
} }
# @FUNCTION: distutils-r1_python_prepare
# @DESCRIPTION:
# The default python_prepare(). A no-op.
distutils-r1_python_prepare() {
debug-print-function ${FUNCNAME} "${@}"
[[ ${EAPI} == [45] ]] || die "${FUNCNAME} is banned in EAPI 6 (it was a no-op)"
}
# @FUNCTION: distutils-r1_python_configure
# @DESCRIPTION:
# The default python_configure(). A no-op.
distutils-r1_python_configure() {
debug-print-function ${FUNCNAME} "${@}"
[[ ${EAPI} == [45] ]] || die "${FUNCNAME} is banned in EAPI 6 (it was a no-op)"
}
# @FUNCTION: _distutils-r1_create_setup_cfg # @FUNCTION: _distutils-r1_create_setup_cfg
# @INTERNAL # @INTERNAL
# @DESCRIPTION: # @DESCRIPTION:
@ -710,7 +680,7 @@ distutils-r1_python_configure() {
_distutils-r1_create_setup_cfg() { _distutils-r1_create_setup_cfg() {
cat > "${HOME}"/.pydistutils.cfg <<-_EOF_ || die cat > "${HOME}"/.pydistutils.cfg <<-_EOF_ || die
[build] [build]
build-base = ${BUILD_DIR} build_base = ${BUILD_DIR}
# using a single directory for them helps us export # using a single directory for them helps us export
# ${PYTHONPATH} and ebuilds find the sources independently # ${PYTHONPATH} and ebuilds find the sources independently
@ -719,16 +689,20 @@ _distutils-r1_create_setup_cfg() {
# note: due to some packages (wxpython) relying on separate # note: due to some packages (wxpython) relying on separate
# platlib & purelib dirs, we do not set --build-lib (which # platlib & purelib dirs, we do not set --build-lib (which
# can not be overridden with --build-*lib) # can not be overridden with --build-*lib)
build-platlib = %(build-base)s/lib build_platlib = %(build_base)s/lib
build-purelib = %(build-base)s/lib build_purelib = %(build_base)s/lib
# make the ebuild writer lives easier # make the ebuild writer lives easier
build-scripts = %(build-base)s/scripts build_scripts = %(build_base)s/scripts
# this is needed by distutils_install_for_testing since # this is needed by distutils_install_for_testing since
# setuptools like to create .egg files for install --home. # setuptools like to create .egg files for install --home.
[bdist_egg] [bdist_egg]
dist-dir = ${BUILD_DIR}/dist dist_dir = ${BUILD_DIR}/dist
# avoid packing up eggs in a zip as it often breaks test suites
[options]
zip_safe = False
_EOF_ _EOF_
# we can't refer to ${D} before src_install() # we can't refer to ${D} before src_install()
@ -745,7 +719,7 @@ _distutils-r1_create_setup_cfg() {
if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
cat >> "${HOME}"/.pydistutils.cfg <<-_EOF_ || die cat >> "${HOME}"/.pydistutils.cfg <<-_EOF_ || die
install-scripts = $(python_get_scriptdir) install_scripts = $(python_get_scriptdir)
_EOF_ _EOF_
fi fi
fi fi
@ -775,46 +749,38 @@ _distutils-r1_copy_egg_info() {
distutils-r1_python_compile() { distutils-r1_python_compile() {
debug-print-function ${FUNCNAME} "${@}" debug-print-function ${FUNCNAME} "${@}"
_python_check_EPYTHON
_distutils-r1_copy_egg_info _distutils-r1_copy_egg_info
local build_args=()
# distutils is parallel-capable since py3.5 # distutils is parallel-capable since py3.5
# to avoid breaking stable ebuilds, enable it only if either: local jobs=$(makeopts_jobs "${MAKEOPTS}" INF)
# a. we're dealing with EAPI 7 if [[ ${jobs} == INF ]]; then
# b. we're dealing with Python 3.7 or PyPy3 local nproc=$(get_nproc)
if python_is_python3 && [[ ${EPYTHON} != python3.4 ]]; then jobs=$(( nproc + 1 ))
if [[ ${EAPI} != [56] || ${EPYTHON} != python3.[56] ]]; then
local jobs=$(makeopts_jobs "${MAKEOPTS}" INF)
if [[ ${jobs} == INF ]]; then
local nproc=$(get_nproc)
jobs=$(( nproc + 1 ))
fi
build_args+=( -j "${jobs}" )
fi
fi fi
esetup.py build "${build_args[@]}" "${@}" esetup.py build -j "${jobs}" "${@}"
} }
# @FUNCTION: _distutils-r1_wrap_scripts # @FUNCTION: _distutils-r1_wrap_scripts
# @USAGE: <path> <bindir> # @USAGE: <bindir>
# @INTERNAL # @INTERNAL
# @DESCRIPTION: # @DESCRIPTION:
# Moves and wraps all installed scripts/executables as necessary. # Moves and wraps all installed scripts/executables as necessary.
_distutils-r1_wrap_scripts() { _distutils-r1_wrap_scripts() {
debug-print-function ${FUNCNAME} "${@}" debug-print-function ${FUNCNAME} "${@}"
[[ ${#} -eq 2 ]] || die "usage: ${FUNCNAME} <path> <bindir>" [[ ${#} -eq 1 ]] || die "usage: ${FUNCNAME} <bindir>"
local path=${1} local bindir=${1}
local bindir=${2}
local scriptdir=$(python_get_scriptdir) local scriptdir=$(python_get_scriptdir)
local f python_files=() non_python_files=() local f python_files=() non_python_files=()
if [[ -d ${path}${scriptdir} ]]; then if [[ -d ${D%/}${scriptdir} ]]; then
for f in "${path}${scriptdir}"/*; do for f in "${D%/}${scriptdir}"/*; do
[[ -d ${f} ]] && die "Unexpected directory: ${f}" [[ -d ${f} ]] && die "Unexpected directory: ${f}"
debug-print "${FUNCNAME}: found executable at ${f#${path}/}" debug-print "${FUNCNAME}: found executable at ${f#${D%/}/}"
local shebang local shebang
read -r shebang < "${f}" read -r shebang < "${f}"
@ -826,26 +792,72 @@ _distutils-r1_wrap_scripts() {
non_python_files+=( "${f}" ) non_python_files+=( "${f}" )
fi fi
mkdir -p "${path}${bindir}" || die mkdir -p "${D%/}${bindir}" || die
done done
for f in "${python_files[@]}"; do for f in "${python_files[@]}"; do
local basename=${f##*/} local basename=${f##*/}
debug-print "${FUNCNAME}: installing wrapper at ${bindir}/${basename}" debug-print "${FUNCNAME}: installing wrapper at ${bindir}/${basename}"
_python_ln_rel "${path}${EPREFIX}"/usr/lib/python-exec/python-exec2 \ local dosym=dosym
"${path}${bindir}/${basename}" || die [[ ${EAPI} == [67] ]] && dosym=dosym8
"${dosym}" -r /usr/lib/python-exec/python-exec2 \
"${bindir#${EPREFIX}}/${basename}"
done done
for f in "${non_python_files[@]}"; do for f in "${non_python_files[@]}"; do
local basename=${f##*/} local basename=${f##*/}
debug-print "${FUNCNAME}: moving ${f#${path}/} to ${bindir}/${basename}" debug-print "${FUNCNAME}: moving ${f#${D%/}/} to ${bindir}/${basename}"
mv "${f}" "${path}${bindir}/${basename}" || die mv "${f}" "${D%/}${bindir}/${basename}" || die
done done
fi fi
} }
# @FUNCTION: distutils-r1_python_test
# @USAGE: [additional-args...]
# @DESCRIPTION:
# The python_test() implementation used by distutils_enable_tests.
# Runs tests using the specified test runner, possibly installing them
# first.
#
# This function is used only if distutils_enable_tests is called.
distutils-r1_python_test() {
debug-print-function ${FUNCNAME} "${@}"
if [[ -z ${_DISTUTILS_TEST_RUNNER} ]]; then
die "${FUNCNAME} can be only used after calling distutils_enable_tests"
fi
_python_check_EPYTHON
if [[ ${_DISTUTILS_TEST_INSTALL} ]]; then
distutils_install_for_testing
fi
case ${_DISTUTILS_TEST_RUNNER} in
nose)
nosetests -v "${@}"
;;
pytest)
epytest
;;
setup.py)
nonfatal esetup.py test --verbose
;;
unittest)
eunittest
;;
*)
die "Mis-synced test runner between ${FUNCNAME} and distutils_enable_testing"
;;
esac
if [[ ${?} -ne 0 ]]; then
die "Tests failed with ${EPYTHON}"
fi
}
# @FUNCTION: distutils-r1_python_install # @FUNCTION: distutils-r1_python_install
# @USAGE: [additional-args...] # @USAGE: [additional-args...]
# @DESCRIPTION: # @DESCRIPTION:
@ -858,7 +870,21 @@ _distutils-r1_wrap_scripts() {
distutils-r1_python_install() { distutils-r1_python_install() {
debug-print-function ${FUNCNAME} "${@}" debug-print-function ${FUNCNAME} "${@}"
local args=( "${@}" ) _python_check_EPYTHON
local root=${D%/}/_${EPYTHON}
[[ ${DISTUTILS_SINGLE_IMPL} ]] && root=${D%/}
# inline DISTUTILS_ARGS logic from esetup.py in order to make
# argv overwriting easier
local args=(
"${DISTUTILS_ARGS[@]}"
"${mydistutilsargs[@]}"
install --skip-build --root="${root}" "${args[@]}"
"${@}"
)
local DISTUTILS_ARGS=()
local mydistutilsargs=()
# enable compilation for the install phase. # enable compilation for the install phase.
local -x PYTHONDONTWRITEBYTECODE= local -x PYTHONDONTWRITEBYTECODE=
@ -866,53 +892,43 @@ distutils-r1_python_install() {
# python likes to compile any module it sees, which triggers sandbox # python likes to compile any module it sees, which triggers sandbox
# failures if some packages haven't compiled their modules yet. # failures if some packages haven't compiled their modules yet.
addpredict "${EPREFIX}/usr/lib/${EPYTHON}" addpredict "${EPREFIX}/usr/lib/${EPYTHON}"
addpredict "${EPREFIX}/usr/$(get_libdir)/${EPYTHON}" addpredict /usr/lib/pypy3.8
addpredict /usr/lib/pypy2.7
addpredict /usr/lib/pypy3.6
addpredict /usr/lib/portage/pym addpredict /usr/lib/portage/pym
addpredict /usr/local # bug 498232 addpredict /usr/local # bug 498232
if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
# user may override --install-scripts # user may override --install-scripts
# note: this is poor but distutils argv parsing is dumb # note: this is poor but distutils argv parsing is dumb
local mydistutilsargs=( "${mydistutilsargs[@]}" )
local scriptdir=${EPREFIX}/usr/bin local scriptdir=${EPREFIX}/usr/bin
# construct a list of mydistutilsargs[0] args[0] args[1]... # rewrite all the arguments
local arg arg_vars set -- "${args[@]}"
[[ ${mydistutilsargs[@]} ]] && eval arg_vars+=( args=()
'mydistutilsargs['{0..$(( ${#mydistutilsargs[@]} - 1 ))}']'
)
[[ ${args[@]} ]] && eval arg_vars+=(
'args['{0..$(( ${#args[@]} - 1 ))}']'
)
set -- "${arg_vars[@]}"
while [[ ${@} ]]; do while [[ ${@} ]]; do
local arg_var=${1} local a=${1}
shift shift
local a=${!arg_var}
case "${a}" in case ${a} in
--install-scripts=*) --install-scripts=*)
scriptdir=${a#--install-scripts=} scriptdir=${a#--install-scripts=}
unset "${arg_var}"
;; ;;
--install-scripts) --install-scripts)
scriptdir=${!1} scriptdir=${1}
unset "${arg_var}" "${1}"
shift shift
;; ;;
*)
args+=( "${a}" )
;;
esac esac
done done
fi fi
local root=${D%/}/_${EPYTHON} esetup.py "${args[@]}"
[[ ${DISTUTILS_SINGLE_IMPL} ]] && root=${D%/}
esetup.py install --skip-build --root="${root}" "${args[@]}" local forbidden_package_names=(
examples test tests
local forbidden_package_names=( examples test tests .pytest_cache ) .pytest_cache .hypothesis
)
local p local p
for p in "${forbidden_package_names[@]}"; do for p in "${forbidden_package_names[@]}"; do
if [[ -d ${root}$(python_get_sitedir)/${p} ]]; then if [[ -d ${root}$(python_get_sitedir)/${p} ]]; then
@ -933,8 +949,8 @@ distutils-r1_python_install() {
fi fi
if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
_distutils-r1_wrap_scripts "${root}" "${scriptdir}"
multibuild_merge_root "${root}" "${D%/}" multibuild_merge_root "${root}" "${D%/}"
_distutils-r1_wrap_scripts "${scriptdir}"
fi fi
} }
@ -943,18 +959,9 @@ distutils-r1_python_install() {
# The default python_install_all(). It installs the documentation. # The default python_install_all(). It installs the documentation.
distutils-r1_python_install_all() { distutils-r1_python_install_all() {
debug-print-function ${FUNCNAME} "${@}" debug-print-function ${FUNCNAME} "${@}"
_distutils-r1_check_all_phase_mismatch
einstalldocs einstalldocs
if declare -p EXAMPLES &>/dev/null; then
[[ ${EAPI} != [45] ]] && die "EXAMPLES are banned in EAPI ${EAPI}"
(
docinto examples
dodoc -r "${EXAMPLES[@]}"
)
docompress -x "/usr/share/doc/${PF}/examples"
fi
} }
# @FUNCTION: distutils-r1_run_phase # @FUNCTION: distutils-r1_run_phase
@ -1085,10 +1092,7 @@ distutils-r1_src_prepare() {
fi fi
if [[ ! ${_DISTUTILS_DEFAULT_CALLED} ]]; then if [[ ! ${_DISTUTILS_DEFAULT_CALLED} ]]; then
local cmd=die die "QA: python_prepare_all() didn't call distutils-r1_python_prepare_all"
[[ ${EAPI} == [45] ]] && cmd=eqawarn
"${cmd}" "QA: python_prepare_all() didn't call distutils-r1_python_prepare_all"
fi fi
if declare -f python_prepare >/dev/null; then if declare -f python_prepare >/dev/null; then
@ -1098,7 +1102,7 @@ distutils-r1_src_prepare() {
distutils-r1_src_configure() { distutils-r1_src_configure() {
python_export_utf8_locale python_export_utf8_locale
[[ ${EAPI} == [56] ]] && xdg_environment_reset # Bug 577704 [[ ${EAPI} == 6 ]] && xdg_environment_reset # Bug 577704
if declare -f python_configure >/dev/null; then if declare -f python_configure >/dev/null; then
_distutils-r1_run_foreach_impl python_configure _distutils-r1_run_foreach_impl python_configure
@ -1191,39 +1195,5 @@ distutils-r1_src_install() {
_distutils-r1_check_namespace_pth _distutils-r1_check_namespace_pth
} }
# -- distutils.eclass functions --
distutils_get_intermediate_installation_image() {
die "${FUNCNAME}() is invalid for distutils-r1"
}
distutils_src_unpack() {
die "${FUNCNAME}() is invalid for distutils-r1, and you don't want it in EAPI ${EAPI} anyway"
}
distutils_src_prepare() {
die "${FUNCNAME}() is invalid for distutils-r1, you probably want: ${FUNCNAME/_/-r1_}"
}
distutils_src_compile() {
die "${FUNCNAME}() is invalid for distutils-r1, you probably want: ${FUNCNAME/_/-r1_}"
}
distutils_src_test() {
die "${FUNCNAME}() is invalid for distutils-r1, you probably want: ${FUNCNAME/_/-r1_}"
}
distutils_src_install() {
die "${FUNCNAME}() is invalid for distutils-r1, you probably want: ${FUNCNAME/_/-r1_}"
}
distutils_pkg_postinst() {
die "${FUNCNAME}() is invalid for distutils-r1, and pkg_postinst is unnecessary"
}
distutils_pkg_postrm() {
die "${FUNCNAME}() is invalid for distutils-r1, and pkg_postrm is unnecessary"
}
_DISTUTILS_R1=1 _DISTUTILS_R1=1
fi fi