dev-qt/qttest: stable 5.14.2 for ppc, bug #719732
[gentoo.git] / eclass / distutils-r1.eclass
1 # Copyright 1999-2020 Gentoo Authors
2 # Distributed under the terms of the GNU General Public License v2
3
4 # @ECLASS: distutils-r1.eclass
5 # @MAINTAINER:
6 # Python team <python@gentoo.org>
7 # @AUTHOR:
8 # Author: Michał Górny <mgorny@gentoo.org>
9 # Based on the work of: Krzysztof Pawlik <nelchael@gentoo.org>
10 # @SUPPORTED_EAPIS: 5 6 7
11 # @BLURB: A simple eclass to build Python packages using distutils.
12 # @DESCRIPTION:
13 # A simple eclass providing functions to build Python packages using
14 # the distutils build system. It exports phase functions for all
15 # the src_* phases. Each of the phases runs two pseudo-phases:
16 # python_..._all() (e.g. python_prepare_all()) once in ${S}, then
17 # python_...() (e.g. python_prepare()) for each implementation
18 # (see: python_foreach_impl() in python-r1).
19 #
20 # In distutils-r1_src_prepare(), the 'all' function is run before
21 # per-implementation ones (because it creates the implementations),
22 # per-implementation functions are run in a random order.
23 #
24 # In remaining phase functions, the per-implementation functions are run
25 # before the 'all' one, and they are ordered from the least to the most
26 # preferred implementation (so that 'better' files overwrite 'worse'
27 # ones).
28 #
29 # If the ebuild doesn't specify a particular pseudo-phase function,
30 # the default one will be used (distutils-r1_...). Defaults are provided
31 # for all per-implementation pseudo-phases, python_prepare_all()
32 # and python_install_all(); whenever writing your own pseudo-phase
33 # functions, you should consider calling the defaults (and especially
34 # distutils-r1_python_prepare_all).
35 #
36 # Please note that distutils-r1 sets RDEPEND and DEPEND unconditionally
37 # for you.
38 #
39 # Also, please note that distutils-r1 will always inherit python-r1
40 # as well. Thus, all the variables defined and documented there are
41 # relevant to the packages using distutils-r1.
42 #
43 # For more information, please see the Python Guide:
44 # https://dev.gentoo.org/~mgorny/python-guide/
45
46 case "${EAPI:-0}" in
47         0|1|2|3|4)
48                 die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
49                 ;;
50         5|6|7)
51                 ;;
52         *)
53                 die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
54                 ;;
55 esac
56
57 # @ECLASS-VARIABLE: DISTUTILS_OPTIONAL
58 # @DEFAULT_UNSET
59 # @DESCRIPTION:
60 # If set to a non-null value, distutils part in the ebuild will
61 # be considered optional. No dependencies will be added and no phase
62 # functions will be exported.
63 #
64 # If you enable DISTUTILS_OPTIONAL, you have to set proper dependencies
65 # for your package (using ${PYTHON_DEPS}) and to either call
66 # distutils-r1 default phase functions or call the build system
67 # manually.
68
69 # @ECLASS-VARIABLE: DISTUTILS_SINGLE_IMPL
70 # @DEFAULT_UNSET
71 # @DESCRIPTION:
72 # If set to a non-null value, the ebuild will support setting a single
73 # Python implementation only. It will effectively replace the python-r1
74 # eclass inherit with python-single-r1.
75 #
76 # Note that inheriting python-single-r1 will cause pkg_setup()
77 # to be exported. It must be run in order for the eclass functions
78 # to function properly.
79
80 # @ECLASS-VARIABLE: DISTUTILS_USE_SETUPTOOLS
81 # @PRE_INHERIT
82 # @DESCRIPTION:
83 # Controls adding dev-python/setuptools dependency.  The allowed values
84 # are:
85 #
86 # - no -- do not add the dependency (pure distutils package)
87 # - bdepend -- add it to BDEPEND (the default)
88 # - rdepend -- add it to BDEPEND+RDEPEND (when using entry_points)
89 # - pyproject.toml -- use pyproject2setuptools to install a project
90 #                     using pyproject.toml (flit, poetry...)
91 # - manual -- do not add the depedency and suppress the checks
92 #             (assumes you will take care of doing it correctly)
93 #
94 # This variable is effective only if DISTUTILS_OPTIONAL is disabled.
95 # It needs to be set before the inherit line.
96 : ${DISTUTILS_USE_SETUPTOOLS:=bdepend}
97
98 if [[ ! ${_DISTUTILS_R1} ]]; then
99
100 [[ ${EAPI} == [456] ]] && inherit eutils
101 [[ ${EAPI} == [56] ]] && inherit xdg-utils
102 inherit multiprocessing toolchain-funcs
103
104 if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
105         inherit python-r1
106 else
107         inherit python-single-r1
108 fi
109
110 fi
111
112 if [[ ! ${DISTUTILS_OPTIONAL} ]]; then
113         EXPORT_FUNCTIONS src_prepare src_configure src_compile src_test src_install
114 fi
115
116 if [[ ! ${_DISTUTILS_R1} ]]; then
117
118 _distutils_set_globals() {
119         local rdep=${PYTHON_DEPS}
120         local bdep=${rdep}
121
122         if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
123                 local sdep=">=dev-python/setuptools-42.0.2[${PYTHON_USEDEP}]"
124         else
125                 local sdep="$(python_gen_cond_dep '
126                         >=dev-python/setuptools-42.0.2[${PYTHON_MULTI_USEDEP}]
127                 ')"
128         fi
129
130         case ${DISTUTILS_USE_SETUPTOOLS} in
131                 no|manual)
132                         ;;
133                 bdepend)
134                         bdep+=" ${sdep}"
135                         ;;
136                 rdepend)
137                         bdep+=" ${sdep}"
138                         rdep+=" ${sdep}"
139                         ;;
140                 pyproject.toml)
141                         bdep+=" dev-python/pyproject2setuppy[${PYTHON_USEDEP}]"
142                         ;;
143                 *)
144                         die "Invalid DISTUTILS_USE_SETUPTOOLS=${DISTUTILS_USE_SETUPTOOLS}"
145                         ;;
146         esac
147
148         RDEPEND=${rdep}
149         if [[ ${EAPI} != [56] ]]; then
150                 BDEPEND=${bdep}
151         else
152                 DEPEND=${bdep}
153         fi
154         REQUIRED_USE=${PYTHON_REQUIRED_USE}
155 }
156 [[ ! ${DISTUTILS_OPTIONAL} ]] && _distutils_set_globals
157 unset -f _distutils_set_globals
158
159 # @ECLASS-VARIABLE: PATCHES
160 # @DEFAULT_UNSET
161 # @DESCRIPTION:
162 # An array containing patches to be applied to the sources before
163 # copying them.
164 #
165 # If unset, no custom patches will be applied.
166 #
167 # Please note, however, that at some point the eclass may apply
168 # additional distutils patches/quirks independently of this variable.
169 #
170 # Example:
171 # @CODE
172 # PATCHES=( "${FILESDIR}"/${P}-make-gentoo-happy.patch )
173 # @CODE
174
175 # @ECLASS-VARIABLE: DOCS
176 # @DEFAULT_UNSET
177 # @DESCRIPTION:
178 # An array containing documents installed using dodoc. The files listed
179 # there must exist in the directory from which
180 # distutils-r1_python_install_all() is run (${S} by default).
181 #
182 # If unset, the function will instead look up files matching default
183 # filename pattern list (from the Package Manager Specification),
184 # and install those found.
185 #
186 # Example:
187 # @CODE
188 # DOCS=( NEWS README )
189 # @CODE
190
191 # @ECLASS-VARIABLE: HTML_DOCS
192 # @DEFAULT_UNSET
193 # @DESCRIPTION:
194 # An array containing documents installed using dohtml. The files
195 # and directories listed there must exist in the directory from which
196 # distutils-r1_python_install_all() is run (${S} by default).
197 #
198 # If unset, no HTML docs will be installed.
199 #
200 # Example:
201 # @CODE
202 # HTML_DOCS=( doc/html/. )
203 # @CODE
204
205 # @ECLASS-VARIABLE: EXAMPLES
206 # @DEFAULT_UNSET
207 # @DESCRIPTION:
208 # OBSOLETE: this variable is deprecated and banned in EAPI 6
209 #
210 # An array containing examples installed into 'examples' doc
211 # subdirectory. The files and directories listed there must exist
212 # in the directory from which distutils-r1_python_install_all() is run
213 # (${S} by default).
214 #
215 # The 'examples' subdirectory will be marked not to be compressed
216 # automatically.
217 #
218 # If unset, no examples will be installed.
219 #
220 # Example:
221 # @CODE
222 # EXAMPLES=( examples/. demos/. )
223 # @CODE
224
225 # @ECLASS-VARIABLE: DISTUTILS_IN_SOURCE_BUILD
226 # @DEFAULT_UNSET
227 # @DESCRIPTION:
228 # If set to a non-null value, in-source builds will be enabled.
229 # If unset, the default is to use in-source builds when python_prepare()
230 # is declared, and out-of-source builds otherwise.
231 #
232 # If in-source builds are used, the eclass will create a copy of package
233 # sources for each Python implementation in python_prepare_all(),
234 # and work on that copy afterwards.
235 #
236 # If out-of-source builds are used, the eclass will instead work
237 # on the sources directly, prepending setup.py arguments with
238 # 'build --build-base ${BUILD_DIR}' to enforce keeping & using built
239 # files in the specific root.
240
241 # @ECLASS-VARIABLE: DISTUTILS_ALL_SUBPHASE_IMPLS
242 # @DEFAULT_UNSET
243 # @DESCRIPTION:
244 # An array of patterns specifying which implementations can be used
245 # for *_all() sub-phase functions. If undefined, defaults to '*'
246 # (allowing any implementation). If multiple values are specified,
247 # implementations matching any of the patterns will be accepted.
248 #
249 # The patterns can be either fnmatch-style patterns (matched via bash
250 # == operator against PYTHON_COMPAT values) or '-2' / '-3' to indicate
251 # appropriately all enabled Python 2/3 implementations (alike
252 # python_is_python3). Remember to escape or quote the fnmatch patterns
253 # to prevent accidental shell filename expansion.
254 #
255 # If the restriction needs to apply conditionally to a USE flag,
256 # the variable should be set conditionally as well (e.g. in an early
257 # phase function or other convenient location).
258 #
259 # Please remember to add a matching || block to REQUIRED_USE,
260 # to ensure that at least one implementation matching the patterns will
261 # be enabled.
262 #
263 # Example:
264 # @CODE
265 # REQUIRED_USE="doc? ( || ( $(python_gen_useflags 'python2*') ) )"
266 #
267 # pkg_setup() {
268 #     use doc && DISTUTILS_ALL_SUBPHASE_IMPLS=( 'python2*' )
269 # }
270 # @CODE
271
272 # @ECLASS-VARIABLE: mydistutilsargs
273 # @DEFAULT_UNSET
274 # @DESCRIPTION:
275 # An array containing options to be passed to setup.py.
276 #
277 # Example:
278 # @CODE
279 # python_configure_all() {
280 #       mydistutilsargs=( --enable-my-hidden-option )
281 # }
282 # @CODE
283
284 # @FUNCTION: distutils_enable_sphinx
285 # @USAGE: <subdir> [--no-autodoc | <plugin-pkgs>...]
286 # @DESCRIPTION:
287 # Set up IUSE, BDEPEND, python_check_deps() and python_compile_all() for
288 # building HTML docs via dev-python/sphinx.  python_compile_all() will
289 # append to HTML_DOCS if docs are enabled.
290 #
291 # This helper is meant for the most common case, that is a single Sphinx
292 # subdirectory with standard layout, building and installing HTML docs
293 # behind USE=doc.  It assumes it's the only consumer of the three
294 # aforementioned functions.  If you need to use a custom implemention,
295 # you can't use it.
296 #
297 # If your package uses additional Sphinx plugins, they should be passed
298 # (without PYTHON_USEDEP) as <plugin-pkgs>.  The function will take care
299 # of setting appropriate any-of dep and python_check_deps().
300 #
301 # If no plugin packages are specified, the eclass will still utilize
302 # any-r1 API to support autodoc (documenting source code).
303 # If the package uses neither autodoc nor additional plugins, you should
304 # pass --no-autodoc to disable this API and simplify the resulting code.
305 #
306 # This function must be called in global scope.  Take care not to
307 # overwrite the variables set by it.  If you need to extend
308 # python_compile_all(), you can call the original implementation
309 # as sphinx_compile_all.
310 distutils_enable_sphinx() {
311         debug-print-function ${FUNCNAME} "${@}"
312         [[ ${#} -ge 1 ]] || die "${FUNCNAME} takes at least one arg: <subdir>"
313
314         _DISTUTILS_SPHINX_SUBDIR=${1}
315         shift
316         _DISTUTILS_SPHINX_PLUGINS=( "${@}" )
317
318         local deps autodoc=1 d
319         for d; do
320                 if [[ ${d} == --no-autodoc ]]; then
321                         autodoc=
322                 else
323                         deps+="
324                                 ${d}[\${PYTHON_USEDEP}]"
325                 fi
326         done
327
328         if [[ ! ${autodoc} && -n ${deps} ]]; then
329                 die "${FUNCNAME}: do not pass --no-autodoc if external plugins are used"
330         fi
331         if [[ ${autodoc} ]]; then
332                 deps="$(python_gen_any_dep "
333                         dev-python/sphinx[\${PYTHON_USEDEP}]
334                         ${deps}")"
335
336                 python_check_deps() {
337                         use doc || return 0
338                         local p
339                         for p in dev-python/sphinx "${_DISTUTILS_SPHINX_PLUGINS[@]}"; do
340                                 has_version "${p}[${PYTHON_USEDEP}]" || return 1
341                         done
342                 }
343         else
344                 deps="dev-python/sphinx"
345         fi
346
347         sphinx_compile_all() {
348                 use doc || return
349
350                 local confpy=${_DISTUTILS_SPHINX_SUBDIR}/conf.py
351                 [[ -f ${confpy} ]] ||
352                         die "${confpy} not found, distutils_enable_sphinx call wrong"
353
354                 if [[ ${_DISTUTILS_SPHINX_PLUGINS[0]} == --no-autodoc ]]; then
355                         if grep -F -q 'sphinx.ext.autodoc' "${confpy}"; then
356                                 die "distutils_enable_sphinx: --no-autodoc passed but sphinx.ext.autodoc found in ${confpy}"
357                         fi
358                 elif [[ -z ${_DISTUTILS_SPHINX_PLUGINS[@]} ]]; then
359                         if ! grep -F -q 'sphinx.ext.autodoc' "${confpy}"; then
360                                 die "distutils_enable_sphinx: sphinx.ext.autodoc not found in ${confpy}, pass --no-autodoc"
361                         fi
362                 fi
363
364                 build_sphinx "${_DISTUTILS_SPHINX_SUBDIR}"
365         }
366         python_compile_all() { sphinx_compile_all; }
367
368         IUSE+=" doc"
369         if [[ ${EAPI} == [56] ]]; then
370                 DEPEND+=" doc? ( ${deps} )"
371         else
372                 BDEPEND+=" doc? ( ${deps} )"
373         fi
374
375         # we need to ensure successful return in case we're called last,
376         # otherwise Portage may wrongly assume sourcing failed
377         return 0
378 }
379
380 # @FUNCTION: distutils_enable_tests
381 # @USAGE: <test-runner>
382 # @DESCRIPTION:
383 # Set up IUSE, RESTRICT, BDEPEND and python_test() for running tests
384 # with the specified test runner.  Also copies the current value
385 # of RDEPEND to test?-BDEPEND.  The test-runner argument must be one of:
386 #
387 # - nose: nosetests (dev-python/nose)
388 # - pytest: dev-python/pytest
389 # - setup.py: setup.py test (no deps included)
390 # - unittest: for built-in Python unittest module
391 #
392 # This function is meant as a helper for common use cases, and it only
393 # takes care of basic setup.  You still need to list additional test
394 # dependencies manually.  If you have uncommon use case, you should
395 # not use it and instead enable tests manually.
396 #
397 # This function must be called in global scope, after RDEPEND has been
398 # declared.  Take care not to overwrite the variables set by it.
399 distutils_enable_tests() {
400         debug-print-function ${FUNCNAME} "${@}"
401         [[ ${#} -eq 1 ]] || die "${FUNCNAME} takes exactly one argument: test-runner"
402
403         local test_pkg
404         case ${1} in
405                 nose)
406                         test_pkg="dev-python/nose"
407                         python_test() {
408                                 nosetests -v || die "Tests fail with ${EPYTHON}"
409                         }
410                         ;;
411                 pytest)
412                         test_pkg="dev-python/pytest"
413                         python_test() {
414                                 pytest -vv || die "Tests fail with ${EPYTHON}"
415                         }
416                         ;;
417                 setup.py)
418                         python_test() {
419                                 nonfatal esetup.py test --verbose ||
420                                         die "Tests fail with ${EPYTHON}"
421                         }
422                         ;;
423                 unittest)
424                         python_test() {
425                                 "${EPYTHON}" -m unittest discover -v ||
426                                         die "Tests fail with ${EPYTHON}"
427                         }
428                         ;;
429                 *)
430                         die "${FUNCNAME}: unsupported argument: ${1}"
431         esac
432
433         local test_deps=${RDEPEND}
434         if [[ -n ${test_pkg} ]]; then
435                 if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
436                         test_deps+=" ${test_pkg}[${PYTHON_USEDEP}]"
437                 else
438                         test_deps+=" $(python_gen_cond_dep "
439                                 ${test_pkg}[\${PYTHON_MULTI_USEDEP}]
440                         ")"
441                 fi
442         fi
443         if [[ -n ${test_deps} ]]; then
444                 IUSE+=" test"
445                 RESTRICT+=" !test? ( test )"
446                 if [[ ${EAPI} == [56] ]]; then
447                         DEPEND+=" test? ( ${test_deps} )"
448                 else
449                         BDEPEND+=" test? ( ${test_deps} )"
450                 fi
451         fi
452
453         # we need to ensure successful return in case we're called last,
454         # otherwise Portage may wrongly assume sourcing failed
455         return 0
456 }
457
458 # @FUNCTION: _distutils-r1_verify_use_setuptools
459 # @INTERNAL
460 # @DESCRIPTION:
461 # Check setup.py for signs that DISTUTILS_USE_SETUPTOOLS have been set
462 # incorrectly.
463 _distutils_verify_use_setuptools() {
464         [[ ${DISTUTILS_OPTIONAL} ]] && return
465         [[ ${DISTUTILS_USE_SETUPTOOLS} == manual ]] && return
466         [[ ${DISTUTILS_USE_SETUPTOOLS} == pyproject.toml ]] && return
467
468         # ok, those are cheap greps.  we can try toimprove them if we hit
469         # false positives.
470         local expected=no
471         if [[ ${CATEGORY}/${PN} == dev-python/setuptools ]]; then
472                 # as a special case, setuptools provides itself ;-)
473                 :
474         elif grep -E -q -s '(from|import)\s+setuptools' setup.py; then
475                 if grep -E -q -s 'entry_points\s*=' setup.py; then
476                         expected=rdepend
477                 elif grep -F -q -s '[options.entry_points]' setup.cfg; then
478                         expected=rdepend
479                 else
480                         expected=bdepend
481                 fi
482         fi
483
484         if [[ ${DISTUTILS_USE_SETUPTOOLS} != ${expected} ]]; then
485                 if [[ ! ${_DISTUTILS_SETUPTOOLS_WARNED} ]]; then
486                         _DISTUTILS_SETUPTOOLS_WARNED=1
487                         local def=
488                         [[ ${DISTUTILS_USE_SETUPTOOLS} == bdepend ]] && def=' (default?)'
489
490                         eqawarn "DISTUTILS_USE_SETUPTOOLS value is probably incorrect"
491                         eqawarn "  value:    DISTUTILS_USE_SETUPTOOLS=${DISTUTILS_USE_SETUPTOOLS}${def}"
492                         eqawarn "  expected: DISTUTILS_USE_SETUPTOOLS=${expected}"
493                 fi
494         fi
495 }
496
497 # @FUNCTION: esetup.py
498 # @USAGE: [<args>...]
499 # @DESCRIPTION:
500 # Run setup.py using currently selected Python interpreter
501 # (if ${EPYTHON} is set; fallback 'python' otherwise).
502 #
503 # setup.py will be passed the following, in order:
504 # 1. ${mydistutilsargs[@]}
505 # 2. additional arguments passed to the esetup.py function.
506 #
507 # Please note that setup.py will respect defaults (unless overridden
508 # via command-line options) from setup.cfg that is created
509 # in distutils-r1_python_compile and in distutils-r1_python_install.
510 #
511 # This command dies on failure.
512 esetup.py() {
513         debug-print-function ${FUNCNAME} "${@}"
514
515         local die_args=()
516         [[ ${EAPI} != [45] ]] && die_args+=( -n )
517
518         [[ ${BUILD_DIR} ]] && _distutils-r1_create_setup_cfg
519         _distutils_verify_use_setuptools
520
521         set -- "${EPYTHON:-python}" setup.py "${mydistutilsargs[@]}" "${@}"
522
523         echo "${@}" >&2
524         "${@}" || die "${die_args[@]}"
525         local ret=${?}
526
527         if [[ ${BUILD_DIR} ]]; then
528                 rm "${HOME}"/.pydistutils.cfg || die "${die_args[@]}"
529         fi
530
531         return ${ret}
532 }
533
534 # @FUNCTION: distutils_install_for_testing
535 # @USAGE: [<args>...]
536 # @DESCRIPTION:
537 # Install the package into a temporary location for running tests.
538 # Update PYTHONPATH appropriately and set TEST_DIR to the test
539 # installation root. The Python packages will be installed in 'lib'
540 # subdir, and scripts in 'scripts' subdir (like in BUILD_DIR).
541 #
542 # Please note that this function should be only used if package uses
543 # namespaces (and therefore proper install needs to be done to enforce
544 # PYTHONPATH) or tests rely on the results of install command.
545 # For most of the packages, tests built in BUILD_DIR are good enough.
546 distutils_install_for_testing() {
547         debug-print-function ${FUNCNAME} "${@}"
548
549         # A few notes:
550         # 1) because of namespaces, we can't use 'install --root',
551         # 2) 'install --home' is terribly broken on pypy, so we need
552         #    to override --install-lib and --install-scripts,
553         # 3) non-root 'install' complains about PYTHONPATH and missing dirs,
554         #    so we need to set it properly and mkdir them,
555         # 4) it runs a bunch of commands which write random files to cwd,
556         #    in order to avoid that, we add the necessary path overrides
557         #    in _distutils-r1_create_setup_cfg.
558
559         TEST_DIR=${BUILD_DIR}/test
560         local bindir=${TEST_DIR}/scripts
561         local libdir=${TEST_DIR}/lib
562         PYTHONPATH=${libdir}:${PYTHONPATH}
563
564         local add_args=(
565                 install
566                         --home="${TEST_DIR}"
567                         --install-lib="${libdir}"
568                         --install-scripts="${bindir}"
569         )
570
571         mkdir -p "${libdir}" || die
572         esetup.py "${add_args[@]}" "${@}"
573 }
574
575 # @FUNCTION: _distutils-r1_disable_ez_setup
576 # @INTERNAL
577 # @DESCRIPTION:
578 # Stub out ez_setup.py and distribute_setup.py to prevent packages
579 # from trying to download a local copy of setuptools.
580 _distutils-r1_disable_ez_setup() {
581         local stub="def use_setuptools(*args, **kwargs): pass"
582         if [[ -f ez_setup.py ]]; then
583                 echo "${stub}" > ez_setup.py || die
584         fi
585         if [[ -f distribute_setup.py ]]; then
586                 echo "${stub}" > distribute_setup.py || die
587         fi
588 }
589
590 # @FUNCTION: _distutils-r1_handle_pyproject_toml
591 # @INTERNAL
592 # @DESCRIPTION:
593 # Generate setup.py for pyproject.toml if requested.
594 _distutils-r1_handle_pyproject_toml() {
595         if [[ ! -f setup.py && -f pyproject.toml ]]; then
596                 if [[ ${DISTUTILS_USE_SETUPTOOLS} == pyproject.toml ]]; then
597                         cat > setup.py <<-EOF || die
598                                 #!/usr/bin/env python
599                                 from pyproject2setuppy.main import main
600                                 main()
601                         EOF
602                         chmod +x setup.py || die
603                 else
604                         eerror "No setup.py found but pyproject.toml is present.  In order to enable"
605                         eerror "pyproject.toml support in distutils-r1, set:"
606                         eerror "  DISTUTILS_USE_SETUPTOOLS=pyproject.toml"
607                         die "No setup.py found and DISTUTILS_USE_SETUPTOOLS!=pyproject.toml"
608                 fi
609         fi
610 }
611
612 # @FUNCTION: distutils-r1_python_prepare_all
613 # @DESCRIPTION:
614 # The default python_prepare_all(). It applies the patches from PATCHES
615 # array, then user patches and finally calls python_copy_sources to
616 # create copies of resulting sources for each Python implementation.
617 #
618 # At some point in the future, it may also apply eclass-specific
619 # distutils patches and/or quirks.
620 distutils-r1_python_prepare_all() {
621         debug-print-function ${FUNCNAME} "${@}"
622
623         if [[ ! ${DISTUTILS_OPTIONAL} ]]; then
624                 if [[ ${EAPI} != [45] ]]; then
625                         default
626                 else
627                         [[ ${PATCHES} ]] && epatch "${PATCHES[@]}"
628                         epatch_user
629                 fi
630         fi
631
632         # by default, use in-source build if python_prepare() is used
633         if [[ ! ${DISTUTILS_IN_SOURCE_BUILD+1} ]]; then
634                 if declare -f python_prepare >/dev/null; then
635                         DISTUTILS_IN_SOURCE_BUILD=1
636                 fi
637         fi
638
639         _distutils-r1_disable_ez_setup
640         _distutils-r1_handle_pyproject_toml
641
642         if [[ ${DISTUTILS_IN_SOURCE_BUILD} && ! ${DISTUTILS_SINGLE_IMPL} ]]
643         then
644                 # create source copies for each implementation
645                 python_copy_sources
646         fi
647
648         _DISTUTILS_DEFAULT_CALLED=1
649 }
650
651 # @FUNCTION: distutils-r1_python_prepare
652 # @DESCRIPTION:
653 # The default python_prepare(). A no-op.
654 distutils-r1_python_prepare() {
655         debug-print-function ${FUNCNAME} "${@}"
656
657         [[ ${EAPI} == [45] ]] || die "${FUNCNAME} is banned in EAPI 6 (it was a no-op)"
658 }
659
660 # @FUNCTION: distutils-r1_python_configure
661 # @DESCRIPTION:
662 # The default python_configure(). A no-op.
663 distutils-r1_python_configure() {
664         debug-print-function ${FUNCNAME} "${@}"
665
666         [[ ${EAPI} == [45] ]] || die "${FUNCNAME} is banned in EAPI 6 (it was a no-op)"
667 }
668
669 # @FUNCTION: _distutils-r1_create_setup_cfg
670 # @INTERNAL
671 # @DESCRIPTION:
672 # Create implementation-specific configuration file for distutils,
673 # setting proper build-dir (and install-dir) paths.
674 _distutils-r1_create_setup_cfg() {
675         cat > "${HOME}"/.pydistutils.cfg <<-_EOF_ || die
676                 [build]
677                 build-base = ${BUILD_DIR}
678
679                 # using a single directory for them helps us export
680                 # ${PYTHONPATH} and ebuilds find the sources independently
681                 # of whether the package installs extensions or not
682                 #
683                 # note: due to some packages (wxpython) relying on separate
684                 # platlib & purelib dirs, we do not set --build-lib (which
685                 # can not be overridden with --build-*lib)
686                 build-platlib = %(build-base)s/lib
687                 build-purelib = %(build-base)s/lib
688
689                 # make the ebuild writer lives easier
690                 build-scripts = %(build-base)s/scripts
691
692                 # this is needed by distutils_install_for_testing since
693                 # setuptools like to create .egg files for install --home.
694                 [bdist_egg]
695                 dist-dir = ${BUILD_DIR}/dist
696         _EOF_
697
698         # we can't refer to ${D} before src_install()
699         if [[ ${EBUILD_PHASE} == install ]]; then
700                 cat >> "${HOME}"/.pydistutils.cfg <<-_EOF_ || die
701
702                         # installation paths -- allow calling extra install targets
703                         # without the default 'install'
704                         [install]
705                         compile = True
706                         optimize = 2
707                         root = ${D%/}
708                 _EOF_
709
710                 if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
711                         cat >> "${HOME}"/.pydistutils.cfg <<-_EOF_ || die
712                                 install-scripts = $(python_get_scriptdir)
713                         _EOF_
714                 fi
715         fi
716 }
717
718 # @FUNCTION: _distutils-r1_copy_egg_info
719 # @INTERNAL
720 # @DESCRIPTION:
721 # Copy egg-info files to the ${BUILD_DIR} (that's going to become
722 # egg-base in esetup.py). This way, we respect whatever's in upstream
723 # egg-info.
724 _distutils-r1_copy_egg_info() {
725         mkdir -p "${BUILD_DIR}" || die
726         # stupid freebsd can't do 'cp -t ${BUILD_DIR} {} +'
727         find -name '*.egg-info' -type d -exec cp -R -p {} "${BUILD_DIR}"/ ';' || die
728 }
729
730 # @FUNCTION: distutils-r1_python_compile
731 # @USAGE: [additional-args...]
732 # @DESCRIPTION:
733 # The default python_compile(). Runs 'esetup.py build'. Any parameters
734 # passed to this function will be appended to setup.py invocation,
735 # i.e. passed as options to the 'build' command.
736 #
737 # This phase also sets up initial setup.cfg with build directories
738 # and copies upstream egg-info files if supplied.
739 distutils-r1_python_compile() {
740         debug-print-function ${FUNCNAME} "${@}"
741
742         _distutils-r1_copy_egg_info
743
744         local build_args=()
745         # distutils is parallel-capable since py3.5
746         # to avoid breaking stable ebuilds, enable it only if either:
747         # a. we're dealing with EAPI 7
748         # b. we're dealing with Python 3.7 or PyPy3
749         if python_is_python3 && [[ ${EPYTHON} != python3.4 ]]; then
750                 if [[ ${EAPI} != [56] || ${EPYTHON} != python3.[56] ]]; then
751                         local jobs=$(makeopts_jobs "${MAKEOPTS}" INF)
752                         if [[ ${jobs} == INF ]]; then
753                                 local nproc=$(get_nproc)
754                                 jobs=$(( nproc + 1 ))
755                         fi
756                         build_args+=( -j "${jobs}" )
757                 fi
758         fi
759
760         esetup.py build "${build_args[@]}" "${@}"
761 }
762
763 # @FUNCTION: _distutils-r1_wrap_scripts
764 # @USAGE: <path> <bindir>
765 # @INTERNAL
766 # @DESCRIPTION:
767 # Moves and wraps all installed scripts/executables as necessary.
768 _distutils-r1_wrap_scripts() {
769         debug-print-function ${FUNCNAME} "${@}"
770
771         [[ ${#} -eq 2 ]] || die "usage: ${FUNCNAME} <path> <bindir>"
772         local path=${1}
773         local bindir=${2}
774
775         local scriptdir=$(python_get_scriptdir)
776         local f python_files=() non_python_files=()
777
778         if [[ -d ${path}${scriptdir} ]]; then
779                 for f in "${path}${scriptdir}"/*; do
780                         [[ -d ${f} ]] && die "Unexpected directory: ${f}"
781                         debug-print "${FUNCNAME}: found executable at ${f#${path}/}"
782
783                         local shebang
784                         read -r shebang < "${f}"
785                         if [[ ${shebang} == '#!'*${EPYTHON}* ]]; then
786                                 debug-print "${FUNCNAME}: matching shebang: ${shebang}"
787                                 python_files+=( "${f}" )
788                         else
789                                 debug-print "${FUNCNAME}: non-matching shebang: ${shebang}"
790                                 non_python_files+=( "${f}" )
791                         fi
792
793                         mkdir -p "${path}${bindir}" || die
794                 done
795
796                 for f in "${python_files[@]}"; do
797                         local basename=${f##*/}
798
799                         debug-print "${FUNCNAME}: installing wrapper at ${bindir}/${basename}"
800                         _python_ln_rel "${path}${EPREFIX}"/usr/lib/python-exec/python-exec2 \
801                                 "${path}${bindir}/${basename}" || die
802                 done
803
804                 for f in "${non_python_files[@]}"; do
805                         local basename=${f##*/}
806
807                         debug-print "${FUNCNAME}: moving ${f#${path}/} to ${bindir}/${basename}"
808                         mv "${f}" "${path}${bindir}/${basename}" || die
809                 done
810         fi
811 }
812
813 # @FUNCTION: distutils-r1_python_install
814 # @USAGE: [additional-args...]
815 # @DESCRIPTION:
816 # The default python_install(). Runs 'esetup.py install', doing
817 # intermediate root install and handling script wrapping afterwards.
818 # Any parameters passed to this function will be appended
819 # to the setup.py invocation (i.e. as options to the 'install' command).
820 #
821 # This phase updates the setup.cfg file with install directories.
822 distutils-r1_python_install() {
823         debug-print-function ${FUNCNAME} "${@}"
824
825         local args=( "${@}" )
826
827         # enable compilation for the install phase.
828         local -x PYTHONDONTWRITEBYTECODE=
829
830         # python likes to compile any module it sees, which triggers sandbox
831         # failures if some packages haven't compiled their modules yet.
832         addpredict "${EPREFIX}/usr/lib/${EPYTHON}"
833         addpredict "${EPREFIX}/usr/$(get_libdir)/${EPYTHON}"
834         addpredict /usr/lib/pypy2.7
835         addpredict /usr/lib/pypy3.6
836         addpredict /usr/lib/portage/pym
837         addpredict /usr/local # bug 498232
838
839         if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
840                 # user may override --install-scripts
841                 # note: this is poor but distutils argv parsing is dumb
842                 local mydistutilsargs=( "${mydistutilsargs[@]}" )
843                 local scriptdir=${EPREFIX}/usr/bin
844
845                 # construct a list of mydistutilsargs[0] args[0] args[1]...
846                 local arg arg_vars
847                 [[ ${mydistutilsargs[@]} ]] && eval arg_vars+=(
848                         'mydistutilsargs['{0..$(( ${#mydistutilsargs[@]} - 1 ))}']'
849                 )
850                 [[ ${args[@]} ]] && eval arg_vars+=(
851                         'args['{0..$(( ${#args[@]} - 1 ))}']'
852                 )
853
854                 set -- "${arg_vars[@]}"
855                 while [[ ${@} ]]; do
856                         local arg_var=${1}
857                         shift
858                         local a=${!arg_var}
859
860                         case "${a}" in
861                                 --install-scripts=*)
862                                         scriptdir=${a#--install-scripts=}
863                                         unset "${arg_var}"
864                                         ;;
865                                 --install-scripts)
866                                         scriptdir=${!1}
867                                         unset "${arg_var}" "${1}"
868                                         shift
869                                         ;;
870                         esac
871                 done
872         fi
873
874         local root=${D%/}/_${EPYTHON}
875         [[ ${DISTUTILS_SINGLE_IMPL} ]] && root=${D%/}
876
877         esetup.py install --skip-build --root="${root}" "${args[@]}"
878
879         local forbidden_package_names=( examples test tests .pytest_cache )
880         local p
881         for p in "${forbidden_package_names[@]}"; do
882                 if [[ -d ${root}$(python_get_sitedir)/${p} ]]; then
883                         die "Package installs '${p}' package which is forbidden and likely a bug in the build system."
884                 fi
885         done
886
887         local shopt_save=$(shopt -p nullglob)
888         shopt -s nullglob
889         local pypy_dirs=(
890                 "${root}/usr/$(get_libdir)"/pypy*/share
891                 "${root}/usr/lib"/pypy*/share
892         )
893         ${shopt_save}
894
895         if [[ -n ${pypy_dirs} ]]; then
896                 die "Package installs 'share' in PyPy prefix, see bug #465546."
897         fi
898
899         if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
900                 _distutils-r1_wrap_scripts "${root}" "${scriptdir}"
901                 multibuild_merge_root "${root}" "${D%/}"
902         fi
903 }
904
905 # @FUNCTION: distutils-r1_python_install_all
906 # @DESCRIPTION:
907 # The default python_install_all(). It installs the documentation.
908 distutils-r1_python_install_all() {
909         debug-print-function ${FUNCNAME} "${@}"
910
911         einstalldocs
912
913         if declare -p EXAMPLES &>/dev/null; then
914                 [[ ${EAPI} != [45] ]] && die "EXAMPLES are banned in EAPI ${EAPI}"
915
916                 (
917                         docinto examples
918                         dodoc -r "${EXAMPLES[@]}"
919                 )
920                 docompress -x "/usr/share/doc/${PF}/examples"
921         fi
922 }
923
924 # @FUNCTION: distutils-r1_run_phase
925 # @USAGE: [<argv>...]
926 # @INTERNAL
927 # @DESCRIPTION:
928 # Run the given command.
929 #
930 # If out-of-source builds are used, the phase function is run in source
931 # directory, with BUILD_DIR pointing at the build directory
932 # and PYTHONPATH having an entry for the module build directory.
933 #
934 # If in-source builds are used, the command is executed in the directory
935 # holding the per-implementation copy of sources. BUILD_DIR points
936 # to the 'build' subdirectory.
937 distutils-r1_run_phase() {
938         debug-print-function ${FUNCNAME} "${@}"
939
940         if [[ ${DISTUTILS_IN_SOURCE_BUILD} ]]; then
941                 # only force BUILD_DIR if implementation is explicitly enabled
942                 # for building; any-r1 API may select one that is not
943                 # https://bugs.gentoo.org/701506
944                 if [[ ! ${DISTUTILS_SINGLE_IMPL} ]] &&
945                                 has "${EPYTHON/./_}" ${PYTHON_TARGETS}; then
946                         cd "${BUILD_DIR}" || die
947                 fi
948                 local BUILD_DIR=${BUILD_DIR}/build
949         fi
950         local -x PYTHONPATH="${BUILD_DIR}/lib:${PYTHONPATH}"
951
952         # Bug 559644
953         # using PYTHONPATH when the ${BUILD_DIR}/lib is not created yet might lead to
954         # problems in setup.py scripts that try to import modules/packages from that path
955         # during the build process (Python at startup evaluates PYTHONPATH, if the dir is
956         # not valid then associates a NullImporter object to ${BUILD_DIR}/lib storing it
957         # in the sys.path_importer_cache)
958         mkdir -p "${BUILD_DIR}/lib" || die
959
960         # Set up build environment, bug #513664.
961         local -x AR=${AR} CC=${CC} CPP=${CPP} CXX=${CXX}
962         tc-export AR CC CPP CXX
963
964         # How to build Python modules in different worlds...
965         local ldopts
966         case "${CHOST}" in
967                 # provided by haubi, 2014-07-08
968                 *-aix*) ldopts='-shared -Wl,-berok';; # good enough
969                 # provided by grobian, 2014-06-22, bug #513664 c7
970                 *-darwin*) ldopts='-bundle -undefined dynamic_lookup';;
971                 *) ldopts='-shared';;
972         esac
973
974         local -x LDSHARED="${CC} ${ldopts}" LDCXXSHARED="${CXX} ${ldopts}"
975
976         "${@}"
977
978         cd "${_DISTUTILS_INITIAL_CWD}" || die
979 }
980
981 # @FUNCTION: _distutils-r1_run_common_phase
982 # @USAGE: [<argv>...]
983 # @INTERNAL
984 # @DESCRIPTION:
985 # Run the given command, restoring the state for a most preferred Python
986 # implementation matching DISTUTILS_ALL_SUBPHASE_IMPLS.
987 #
988 # If in-source build is used, the command will be run in the copy
989 # of sources made for the selected Python interpreter.
990 _distutils-r1_run_common_phase() {
991         local DISTUTILS_ORIG_BUILD_DIR=${BUILD_DIR}
992
993         if [[ ${DISTUTILS_SINGLE_IMPL} ]]; then
994                 # reuse the dedicated code branch
995                 _distutils-r1_run_foreach_impl "${@}"
996         else
997                 local -x EPYTHON PYTHON
998                 local -x PATH=${PATH} PKG_CONFIG_PATH=${PKG_CONFIG_PATH}
999                 python_setup "${DISTUTILS_ALL_SUBPHASE_IMPLS[@]}"
1000
1001                 local MULTIBUILD_VARIANTS=( "${EPYTHON/./_}" )
1002                 # store for restoring after distutils-r1_run_phase.
1003                 local _DISTUTILS_INITIAL_CWD=${PWD}
1004                 multibuild_foreach_variant \
1005                         distutils-r1_run_phase "${@}"
1006         fi
1007 }
1008
1009 # @FUNCTION: _distutils-r1_run_foreach_impl
1010 # @INTERNAL
1011 # @DESCRIPTION:
1012 # Run the given phase for each implementation if multiple implementations
1013 # are enabled, once otherwise.
1014 _distutils-r1_run_foreach_impl() {
1015         debug-print-function ${FUNCNAME} "${@}"
1016
1017         # store for restoring after distutils-r1_run_phase.
1018         local _DISTUTILS_INITIAL_CWD=${PWD}
1019         set -- distutils-r1_run_phase "${@}"
1020
1021         if [[ ! ${DISTUTILS_SINGLE_IMPL} ]]; then
1022                 python_foreach_impl "${@}"
1023         else
1024                 if [[ ! ${EPYTHON} ]]; then
1025                         die "EPYTHON unset, python-single-r1_pkg_setup not called?!"
1026                 fi
1027                 local BUILD_DIR=${BUILD_DIR:-${S}}
1028                 BUILD_DIR=${BUILD_DIR%%/}_${EPYTHON}
1029
1030                 "${@}"
1031         fi
1032 }
1033
1034 distutils-r1_src_prepare() {
1035         debug-print-function ${FUNCNAME} "${@}"
1036
1037         local _DISTUTILS_DEFAULT_CALLED
1038
1039         # common preparations
1040         if declare -f python_prepare_all >/dev/null; then
1041                 python_prepare_all
1042         else
1043                 distutils-r1_python_prepare_all
1044         fi
1045
1046         if [[ ! ${_DISTUTILS_DEFAULT_CALLED} ]]; then
1047                 local cmd=die
1048                 [[ ${EAPI} == [45] ]] && cmd=eqawarn
1049
1050                 "${cmd}" "QA: python_prepare_all() didn't call distutils-r1_python_prepare_all"
1051         fi
1052
1053         if declare -f python_prepare >/dev/null; then
1054                 _distutils-r1_run_foreach_impl python_prepare
1055         fi
1056 }
1057
1058 distutils-r1_src_configure() {
1059         python_export_utf8_locale
1060         [[ ${EAPI} == [56] ]] && xdg_environment_reset # Bug 577704
1061
1062         if declare -f python_configure >/dev/null; then
1063                 _distutils-r1_run_foreach_impl python_configure
1064         fi
1065
1066         if declare -f python_configure_all >/dev/null; then
1067                 _distutils-r1_run_common_phase python_configure_all
1068         fi
1069 }
1070
1071 distutils-r1_src_compile() {
1072         debug-print-function ${FUNCNAME} "${@}"
1073
1074         if declare -f python_compile >/dev/null; then
1075                 _distutils-r1_run_foreach_impl python_compile
1076         else
1077                 _distutils-r1_run_foreach_impl distutils-r1_python_compile
1078         fi
1079
1080         if declare -f python_compile_all >/dev/null; then
1081                 _distutils-r1_run_common_phase python_compile_all
1082         fi
1083 }
1084
1085 # @FUNCTION: _distutils-r1_clean_egg_info
1086 # @INTERNAL
1087 # @DESCRIPTION:
1088 # Clean up potential stray egg-info files left by setuptools test phase.
1089 # Those files ended up being unversioned, and caused issues:
1090 # https://bugs.gentoo.org/534058
1091 _distutils-r1_clean_egg_info() {
1092         rm -rf "${BUILD_DIR}"/lib/*.egg-info || die
1093 }
1094
1095 distutils-r1_src_test() {
1096         debug-print-function ${FUNCNAME} "${@}"
1097
1098         if declare -f python_test >/dev/null; then
1099                 _distutils-r1_run_foreach_impl python_test
1100                 _distutils-r1_run_foreach_impl _distutils-r1_clean_egg_info
1101         fi
1102
1103         if declare -f python_test_all >/dev/null; then
1104                 _distutils-r1_run_common_phase python_test_all
1105         fi
1106 }
1107
1108 # @FUNCTION: _distutils-r1_check_namespace_pth
1109 # @INTERNAL
1110 # @DESCRIPTION:
1111 # Check if any *-nspkg.pth files were installed (by setuptools)
1112 # and warn about the policy non-conformance if they were.
1113 _distutils-r1_check_namespace_pth() {
1114         local f pth=()
1115
1116         while IFS= read -r -d '' f; do
1117                 pth+=( "${f}" )
1118         done < <(find "${ED%/}" -name '*-nspkg.pth' -print0)
1119
1120         if [[ ${pth[@]} ]]; then
1121                 ewarn "The following *-nspkg.pth files were found installed:"
1122                 ewarn
1123                 for f in "${pth[@]}"; do
1124                         ewarn "  ${f#${ED%/}}"
1125                 done
1126                 ewarn
1127                 ewarn "The presence of those files may break namespaces in Python 3.5+. Please"
1128                 ewarn "read our documentation on reliable handling of namespaces and update"
1129                 ewarn "the ebuild accordingly:"
1130                 ewarn
1131                 ewarn "  https://wiki.gentoo.org/wiki/Project:Python/Namespace_packages"
1132         fi
1133 }
1134
1135 distutils-r1_src_install() {
1136         debug-print-function ${FUNCNAME} "${@}"
1137
1138         if declare -f python_install >/dev/null; then
1139                 _distutils-r1_run_foreach_impl python_install
1140         else
1141                 _distutils-r1_run_foreach_impl distutils-r1_python_install
1142         fi
1143
1144         if declare -f python_install_all >/dev/null; then
1145                 _distutils-r1_run_common_phase python_install_all
1146         else
1147                 _distutils-r1_run_common_phase distutils-r1_python_install_all
1148         fi
1149
1150         _distutils-r1_check_namespace_pth
1151 }
1152
1153 # -- distutils.eclass functions --
1154
1155 distutils_get_intermediate_installation_image() {
1156         die "${FUNCNAME}() is invalid for distutils-r1"
1157 }
1158
1159 distutils_src_unpack() {
1160         die "${FUNCNAME}() is invalid for distutils-r1, and you don't want it in EAPI ${EAPI} anyway"
1161 }
1162
1163 distutils_src_prepare() {
1164         die "${FUNCNAME}() is invalid for distutils-r1, you probably want: ${FUNCNAME/_/-r1_}"
1165 }
1166
1167 distutils_src_compile() {
1168         die "${FUNCNAME}() is invalid for distutils-r1, you probably want: ${FUNCNAME/_/-r1_}"
1169 }
1170
1171 distutils_src_test() {
1172         die "${FUNCNAME}() is invalid for distutils-r1, you probably want: ${FUNCNAME/_/-r1_}"
1173 }
1174
1175 distutils_src_install() {
1176         die "${FUNCNAME}() is invalid for distutils-r1, you probably want: ${FUNCNAME/_/-r1_}"
1177 }
1178
1179 distutils_pkg_postinst() {
1180         die "${FUNCNAME}() is invalid for distutils-r1, and pkg_postinst is unnecessary"
1181 }
1182
1183 distutils_pkg_postrm() {
1184         die "${FUNCNAME}() is invalid for distutils-r1, and pkg_postrm is unnecessary"
1185 }
1186
1187 _DISTUTILS_R1=1
1188 fi