Improve phase functions.
authorArfrever Frehtes Taifersar Arahesis <arfrever@gentoo.org>
Sat, 13 Mar 2010 13:46:20 +0000 (13:46 +0000)
committerArfrever Frehtes Taifersar Arahesis <arfrever@gentoo.org>
Sat, 13 Mar 2010 13:46:20 +0000 (13:46 +0000)
Simplify and improve validate_PYTHON_ABIS().
Fix handling of ${S} ending in '/' in python_copy_sources() (bug #307943).
Improve python_generate_wrapper_scripts().
Improve python_convert_shebangs().
Add python_clean_sitedirs().
Simplify python_mod_cleanup().
Improve deprecation warnings in python_version(), python_mod_exists() and python_tkinter_exists().

eclass/python.eclass

index a88c297311f21223f63991fcd6bdd96431d1a57f..bdfcbb549886b87e7e839e2d955a203f405113c2 100644 (file)
@@ -1,6 +1,6 @@
 # Copyright 1999-2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.93 2010/03/12 18:27:01 betelgeuse Exp $
+# $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.94 2010/03/13 13:46:20 arfrever Exp $
 
 # @ECLASS: python.eclass
 # @MAINTAINER:
@@ -273,13 +273,15 @@ unset _PYTHON_ATOMS
 # @DESCRIPTION:
 # Set this to export phase functions for the following ebuild phases:
 # src_prepare, src_configure, src_compile, src_test, src_install.
-if ! has "${EAPI:-0}" 0 1 && [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then
+if ! has "${EAPI:-0}" 0 1; then
        python_src_prepare() {
                python_copy_sources
        }
 
        for python_default_function in src_configure src_compile src_test src_install; do
-               eval "python_${python_default_function}() { python_execute_function -d -s; }"
+               eval "python_${python_default_function}() {
+                       python_execute_function -d -s \"\$@\"
+               }"
        done
        unset python_default_function
 
@@ -308,7 +310,7 @@ validate_PYTHON_ABIS() {
                PYTHON_ABI_SUPPORTED_VALUES="${_CPYTHON2_SUPPORTED_ABIS[@]} ${_CPYTHON3_SUPPORTED_ABIS[@]} ${_JYTHON_SUPPORTED_ABIS[@]}"
 
                if [[ "$(declare -p USE_PYTHON 2> /dev/null)" == "declare -x USE_PYTHON="* ]]; then
-                       local python2_enabled="0" python3_enabled="0"
+                       local cpython_enabled="0"
 
                        if [[ -z "${USE_PYTHON}" ]]; then
                                die "USE_PYTHON variable is empty"
@@ -319,11 +321,8 @@ validate_PYTHON_ABIS() {
                                        die "USE_PYTHON variable contains invalid value '${PYTHON_ABI}'"
                                fi
 
-                               if has "${PYTHON_ABI}" "${_CPYTHON2_SUPPORTED_ABIS[@]}"; then
-                                       python2_enabled="1"
-                               fi
-                               if has "${PYTHON_ABI}" "${_CPYTHON3_SUPPORTED_ABIS[@]}"; then
-                                       python3_enabled="1"
+                               if has "${PYTHON_ABI}" "${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}"; then
+                                       cpython_enabled="1"
                                fi
 
                                support_ABI="1"
@@ -340,13 +339,7 @@ validate_PYTHON_ABIS() {
                                die "USE_PYTHON variable does not enable any version of Python supported by ${CATEGORY}/${PF}"
                        fi
 
-                       if [[ "${python2_enabled}" == "0" ]]; then
-                               ewarn "USE_PYTHON variable does not enable any version of Python 2. This configuration is unsupported."
-                       fi
-                       if [[ "${python3_enabled}" == "0" ]]; then
-                               ewarn "USE_PYTHON variable does not enable any version of Python 3. This configuration is unsupported."
-                       fi
-                       if [[ "${python2_enabled}" == "0" && "${python3_enabled}" == "0" ]]; then
+                       if [[ "${cpython_enabled}" == "0" ]]; then
                                die "USE_PYTHON variable does not enable any version of CPython"
                        fi
                else
@@ -496,9 +489,6 @@ python_execute_function() {
                        die "${FUNCNAME}(): '${function}' function is not defined"
                fi
        else
-               if [[ "$#" -ne 0 ]]; then
-                       die "${FUNCNAME}(): '--default-function' option and function name cannot be specified simultaneously"
-               fi
                if has "${EAPI:-0}" 0 1; then
                        die "${FUNCNAME}(): '--default-function' option cannot be used in this EAPI"
                fi
@@ -506,28 +496,28 @@ python_execute_function() {
                if [[ "${EBUILD_PHASE}" == "configure" ]]; then
                        if has "${EAPI}" 2 3; then
                                python_default_function() {
-                                       econf
+                                       econf "$@"
                                }
                        else
                                python_default_function() {
-                                       nonfatal econf
+                                       nonfatal econf "$@"
                                }
                        fi
                elif [[ "${EBUILD_PHASE}" == "compile" ]]; then
                        python_default_function() {
-                               emake
+                               emake "$@"
                        }
                elif [[ "${EBUILD_PHASE}" == "test" ]]; then
                        python_default_function() {
                                if emake -j1 -n check &> /dev/null; then
-                                       emake -j1 check
+                                       emake -j1 check "$@"
                                elif emake -j1 -n test &> /dev/null; then
-                                       emake -j1 test
+                                       emake -j1 test "$@"
                                fi
                        }
                elif [[ "${EBUILD_PHASE}" == "install" ]]; then
                        python_default_function() {
-                               emake DESTDIR="${D}" install
+                               emake DESTDIR="${D}" install "$@"
                        }
                else
                        die "${FUNCNAME}(): '--default-function' option cannot be used in this ebuild phase"
@@ -665,7 +655,7 @@ python_copy_sources() {
                if [[ "${WORKDIR}" == "${S}" ]]; then
                        die "${FUNCNAME}() cannot be used"
                fi
-               dirs=("${S}")
+               dirs=("${S%/}")
        else
                dirs=("$@")
        fi
@@ -761,12 +751,12 @@ python_generate_wrapper_scripts() {
                fi
 
                if [[ "${quiet}" == "0" ]]; then
-                       einfo "Generating '${file#${D%/}}' wrapper script"
+                       einfo "Generating '${file#${ED%/}}' wrapper script"
                fi
 
                cat << EOF > "${file}"
 #!/usr/bin/env python
-# Gentoo '${file##*/}' wrapper script
+# Gentoo '${file##*/}' wrapper script generated by python_generate_wrapper_scripts()
 
 import os
 import re
@@ -774,6 +764,8 @@ import subprocess
 import sys
 
 EPYTHON_re = re.compile(r"^python(\d+\.\d+)$")
+python_shebang_re = re.compile(r"^#! *(${EPREFIX}/usr/bin/python|(${EPREFIX})?/usr/bin/env +(${EPREFIX}/usr/bin/)?python)")
+python_verification_output_re = re.compile("^GENTOO_PYTHON_TARGET_SCRIPT_PATH supported\n$")
 
 EOF
                if [[ "$?" != "0" ]]; then
@@ -798,16 +790,16 @@ else:
                sys.stderr.write("Execution of 'eselect python show${eselect_python_option:+ }${eselect_python_option}' failed\n")
                sys.exit(1)
 
-       eselect_output = eselect_process.stdout.read()
-       if not isinstance(eselect_output, str):
+       EPYTHON = eselect_process.stdout.read().rstrip("\n")
+       if not isinstance(EPYTHON, str):
                # Python 3
-               eselect_output = eselect_output.decode()
+               EPYTHON = EPYTHON.decode()
 
-       EPYTHON_matched = EPYTHON_re.match(eselect_output)
+       EPYTHON_matched = EPYTHON_re.match(EPYTHON)
        if EPYTHON_matched:
                PYTHON_ABI = EPYTHON_matched.group(1)
        else:
-               sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s" % eselect_output)
+               sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s" % EPYTHON)
                sys.exit(1)
 EOF
                        if [[ "$?" != "0" ]]; then
@@ -823,16 +815,16 @@ except (OSError, ValueError):
        sys.stderr.write("Execution of 'eselect python show${eselect_python_option:+ }${eselect_python_option}' failed\n")
        sys.exit(1)
 
-eselect_output = eselect_process.stdout.read()
-if not isinstance(eselect_output, str):
+EPYTHON = eselect_process.stdout.read().rstrip("\n")
+if not isinstance(EPYTHON, str):
        # Python 3
-       eselect_output = eselect_output.decode()
+       EPYTHON = EPYTHON.decode()
 
-EPYTHON_matched = EPYTHON_re.match(eselect_output)
+EPYTHON_matched = EPYTHON_re.match(EPYTHON)
 if EPYTHON_matched:
        PYTHON_ABI = EPYTHON_matched.group(1)
 else:
-       sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s" % eselect_output)
+       sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s" % EPYTHON)
        sys.exit(1)
 EOF
                        if [[ "$?" != "0" ]]; then
@@ -841,13 +833,47 @@ EOF
                fi
                cat << EOF >> "${file}"
 
-os.environ["PYTHON_SCRIPT_NAME"] = sys.argv[0]
-target_executable = "%s-%s" % (os.path.realpath(sys.argv[0]), PYTHON_ABI)
-if not os.path.exists(target_executable):
-       sys.stderr.write("'%s' does not exist\n" % target_executable)
+wrapper_script_path = os.path.realpath(sys.argv[0])
+target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
+os.environ["GENTOO_PYTHON_WRAPPER_SCRIPT_PATH"] = sys.argv[0]
+os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH"] = target_executable_path
+if not os.path.exists(target_executable_path):
+       sys.stderr.write("'%s' does not exist\n" % target_executable_path)
        sys.exit(1)
 
-os.execv(target_executable, sys.argv)
+target_executable = open(target_executable_path, "rb")
+target_executable_first_line = target_executable.readline()
+if not isinstance(target_executable_first_line, str):
+       # Python 3
+       target_executable_first_line = target_executable_first_line.decode("utf_8", "replace")
+
+python_shebang_matched = python_shebang_re.match(target_executable_first_line)
+target_executable.close()
+
+if python_shebang_matched:
+       try:
+               python_interpreter_path = "${EPREFIX}/usr/bin/%s" % EPYTHON
+               os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"] = "1"
+               python_verification_process = subprocess.Popen([python_interpreter_path, "-c", "pass"], stdout=subprocess.PIPE)
+               del os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"]
+               if python_verification_process.wait() != 0:
+                       raise ValueError
+
+               python_verification_output = python_verification_process.stdout.read()
+               if not isinstance(python_verification_output, str):
+                       # Python 3
+                       python_verification_output = python_verification_output.decode()
+
+               if not python_verification_output_re.match(python_verification_output):
+                       raise ValueError
+
+               os.execv(python_interpreter_path, [python_interpreter_path] + sys.argv)
+       except:
+               pass
+       if "GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION" in os.environ:
+               del os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"]
+
+os.execv(target_executable_path, sys.argv)
 EOF
                if [[ "$?" != "0" ]]; then
                        die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1019,7 +1045,7 @@ PYTHON() {
                elif [[ -z "${SUPPORT_PYTHON_ABIS}" ]]; then
                        PYTHON_ABI="$("${EPREFIX}/usr/bin/python" -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")"
                elif [[ -z "${PYTHON_ABI}" ]]; then
-                       die "${FUNCNAME}(): Invalid usage: Python ABI not specified"
+                       die "${FUNCNAME}(): Invalid usage: ${FUNCNAME}() should be used in ABI-specific local scope"
                fi
        elif [[ "$#" -eq 1 ]]; then
                if [[ "${final_ABI}" == "1" ]]; then
@@ -1487,9 +1513,12 @@ python_convert_shebangs() {
                [[ "${only_executables}" == "1" && ! -x "${file}" ]] && continue
 
                if [[ "$(head -n1 "${file}")" =~ ^'#!'.*python ]]; then
+                       [[ "$(sed -ne "2p" "${file}")" =~ ^"# Gentoo '".*"' wrapper script generated by python_generate_wrapper_scripts()"$ ]] && continue
+
                        if [[ "${quiet}" == "0" ]]; then
                                einfo "Converting shebang in '${file}'"
                        fi
+
                        sed -e "1s/python\([[:digit:]]\+\(\.[[:digit:]]\+\)\?\)\?/python${python_version}/" -i "${file}" || die "Conversion of shebang in '${file}' failed"
 
                        # Delete potential whitespace after "#!".
@@ -1498,6 +1527,15 @@ python_convert_shebangs() {
        done
 }
 
+# @FUNCTION: python_clean_sitedirs
+# @DESCRIPTION:
+# Delete needless files in site-packages directories in ${ED}.
+python_clean_sitedirs() {
+       _python_initialize_prefix_variables
+
+       find "${ED}"usr/$(get_libdir)/python*/site-packages "(" -name "*.c" -o -name "*.h" -o -name "*.la" ")" -type f -print0 | xargs -0 rm -f
+}
+
 # ================================================================================================
 # ================================ FUNCTIONS FOR RUNNING OF TESTS ================================
 # ================================================================================================
@@ -1984,27 +2022,27 @@ python_mod_cleanup() {
                                if [[ "${REPLY}" == *[co] ]]; then
                                        py_file="${REPLY%[co]}"
                                        [[ -f "${py_file}" || (! -f "${py_file}c" && ! -f "${py_file}o") ]] && continue
-                                       einfo "${_BLUE}<<< ${py_file}[co]${_NORMAL}"
+                                       echo "${_BLUE}<<< ${py_file}[co]${_NORMAL}"
                                        rm -f "${py_file}"[co]
                                elif [[ "${REPLY}" == *\$py.class ]]; then
                                        py_file="${REPLY%\$py.class}.py"
                                        [[ -f "${py_file}" || ! -f "${py_file%.py}\$py.class" ]] && continue
-                                       einfo "${_BLUE}<<< ${py_file%.py}\$py.class${_NORMAL}"
+                                       echo "${_BLUE}<<< ${py_file%.py}\$py.class${_NORMAL}"
                                        rm -f "${py_file%.py}\$py.class"
                                fi
                        done
 
                        # Attempt to delete directories, which may be empty.
                        find "${path}" -type d | sort -r | while read -r dir; do
-                               rmdir "${dir}" 2>/dev/null && einfo "${_CYAN}<<< ${dir}${_NORMAL}"
+                               rmdir "${dir}" 2>/dev/null && echo "${_CYAN}<<< ${dir}${_NORMAL}"
                        done
                elif [[ "${path}" == *.py && ! -f "${path}" ]]; then
                        if [[ (-f "${path}c" || -f "${path}o") ]]; then
-                               einfo "${_BLUE}<<< ${path}[co]${_NORMAL}"
+                               echo "${_BLUE}<<< ${path}[co]${_NORMAL}"
                                rm -f "${path}"[co]
                        fi
                        if [[ -f "${path%.py}\$py.class" ]]; then
-                               einfo "${_BLUE}<<< ${path%.py}\$py.class${_NORMAL}"
+                               echo "${_BLUE}<<< ${path%.py}\$py.class${_NORMAL}"
                                rm -f "${path%.py}\$py.class"
                        fi
                fi
@@ -2029,6 +2067,7 @@ python_version() {
                einfo
                einfo "Deprecation Warning: ${FUNCNAME}() is deprecated and will be banned on 2010-07-01."
                einfo "Use PYTHON() instead of python variable. Use python_get_*() instead of PYVER* variables."
+               einfo "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
                einfo
        fi
 
@@ -2066,6 +2105,7 @@ python_mod_exists() {
        einfo
        einfo "Deprecation Warning: ${FUNCNAME}() is deprecated and will be banned on 2010-07-01."
        einfo "Use USE dependencies and/or has_version() instead of ${FUNCNAME}()."
+       einfo "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
        einfo
 
        if [[ "$#" -ne 1 ]]; then
@@ -2088,6 +2128,7 @@ python_tkinter_exists() {
                einfo
                einfo "Deprecation Warning: ${FUNCNAME}() is deprecated and will be banned on 2010-07-01."
                einfo "Use PYTHON_USE_WITH=\"xml\" and python_pkg_setup() instead of ${FUNCNAME}()."
+               einfo "The ebuild needs to be fixed. Please report a bug, if it has not been already reported."
                einfo
        fi