summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eclass/python.eclass783
1 files changed, 476 insertions, 307 deletions
diff --git a/eclass/python.eclass b/eclass/python.eclass
index a4315519f081..9e5afa762d79 100644
--- a/eclass/python.eclass
+++ b/eclass/python.eclass
@@ -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.96 2010/03/26 15:23:17 arfrever Exp $
+# $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.97 2010/05/17 18:01:59 arfrever Exp $
# @ECLASS: python.eclass
# @MAINTAINER:
@@ -184,20 +184,158 @@ fi
# Set this to a name of a USE flag if you need to make either PYTHON_USE_WITH or
# PYTHON_USE_WITH_OR atoms conditional under a USE flag.
+if ! has "${EAPI:-0}" 0 1 && [[ -n ${PYTHON_USE_WITH} || -n ${PYTHON_USE_WITH_OR} ]]; then
+ _PYTHON_USE_WITH_ATOMS_ARRAY=()
+ if [[ -n "${PYTHON_USE_WITH}" ]]; then
+ for _PYTHON_ATOM in "${_PYTHON_ATOMS[@]}"; do
+ _PYTHON_USE_WITH_ATOMS_ARRAY+=("${_PYTHON_ATOM}[${PYTHON_USE_WITH// /,}]")
+ done
+ elif [[ -n "${PYTHON_USE_WITH_OR}" ]]; then
+ for _USE_flag in ${PYTHON_USE_WITH_OR}; do
+ for _PYTHON_ATOM in "${_PYTHON_ATOMS[@]}"; do
+ _PYTHON_USE_WITH_ATOMS_ARRAY+=("${_PYTHON_ATOM}[${_USE_flag}]")
+ done
+ done
+ unset _USE_flag
+ fi
+ if [[ "${#_PYTHON_USE_WITH_ATOMS_ARRAY[@]}" -gt 1 ]]; then
+ _PYTHON_USE_WITH_ATOMS="|| ( ${_PYTHON_USE_WITH_ATOMS_ARRAY[@]} )"
+ else
+ _PYTHON_USE_WITH_ATOMS="${_PYTHON_USE_WITH_ATOMS_ARRAY[@]}"
+ fi
+ if [[ -n "${PYTHON_USE_WITH_OPT}" ]]; then
+ _PYTHON_USE_WITH_ATOMS="${PYTHON_USE_WITH_OPT}? ( ${_PYTHON_USE_WITH_ATOMS} )"
+ fi
+ DEPEND+=" ${_PYTHON_USE_WITH_ATOMS}"
+ RDEPEND+=" ${_PYTHON_USE_WITH_ATOMS}"
+ unset _PYTHON_ATOM _PYTHON_USE_WITH_ATOMS _PYTHON_USE_WITH_ATOMS_ARRAY
+fi
+
+unset _PYTHON_ATOMS
+
+# ================================================================================================
+# =================================== MISCELLANEOUS FUNCTIONS ====================================
+# ================================================================================================
+
+_python_implementation() {
+ if [[ "${CATEGORY}/${PN}" == "dev-lang/python" ]]; then
+ return 0
+ elif [[ "${CATEGORY}/${PN}" == "dev-java/jython" ]]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+_python_package_supporting_installation_for_multiple_python_abis() {
+ if [[ "${EBUILD_PHASE}" == "depend" ]]; then
+ die "${FUNCNAME}() cannot be used in global scope"
+ fi
+
+ if has "${EAPI:-0}" 0 1 2 3 4; then
+ if [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then
+ return 0
+ else
+ return 1
+ fi
+ else
+ die "${FUNCNAME}(): Support for EAPI=\"${EAPI}\" not implemented"
+ fi
+}
+
+_python_initialize_prefix_variables() {
+ if has "${EAPI:-0}" 0 1 2; then
+ if [[ -n "${ROOT}" && -z "${EROOT}" ]]; then
+ EROOT="${ROOT%/}${EPREFIX}/"
+ fi
+ if [[ -n "${D}" && -z "${ED}" ]]; then
+ ED="${D%/}${EPREFIX}/"
+ fi
+ fi
+}
+
+unset PYTHON_SANITY_CHECKS
+
+_python_initial_sanity_checks() {
+ if [[ "$(declare -p PYTHON_SANITY_CHECKS 2> /dev/null)" != "declare -- PYTHON_SANITY_CHECKS="* ]]; then
+ # Ensure that /usr/bin/python and /usr/bin/python-config are valid.
+ if [[ "$(readlink "${EPREFIX}/usr/bin/python")" != "python-wrapper" ]]; then
+ eerror "'${EPREFIX}/usr/bin/python' is not valid symlink."
+ eerror "Use \`eselect python set \${python_interpreter}\` to fix this problem."
+ die "'${EPREFIX}/usr/bin/python' is not valid symlink"
+ fi
+ if [[ "$(<"${EPREFIX}/usr/bin/python-config")" != *"Gentoo python-config wrapper script"* ]]; then
+ eerror "'${EPREFIX}/usr/bin/python-config' is not valid script"
+ eerror "Use \`eselect python set \${python_interpreter}\` to fix this problem."
+ die "'${EPREFIX}/usr/bin/python-config' is not valid script"
+ fi
+ fi
+}
+
+_python_final_sanity_checks() {
+ if ! _python_implementation && [[ "$(declare -p PYTHON_SANITY_CHECKS 2> /dev/null)" != "declare -- PYTHON_SANITY_CHECKS="* ]]; then
+ local PYTHON_ABI="${PYTHON_ABI}"
+ for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI}}; do
+ # Ensure that appropriate version of Python is installed.
+ if ! has_version "$(python_get_implementational_package)"; then
+ die "$(python_get_implementational_package) is not installed"
+ fi
+
+ # Ensure that EPYTHON variable is respected.
+ if [[ "$(EPYTHON="$(PYTHON)" python -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")" != "${PYTHON_ABI}" ]]; then
+ eerror "Path to 'python': '$(type -p python)'"
+ eerror "ABI: '${ABI}'"
+ eerror "DEFAULT_ABI: '${DEFAULT_ABI}'"
+ eerror "EPYTHON: '$(PYTHON)'"
+ eerror "PYTHON_ABI: '${PYTHON_ABI}'"
+ eerror "Locally active version of Python: '$(EPYTHON="$(PYTHON)" python -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")'"
+ die "'python' does not respect EPYTHON variable"
+ fi
+ done
+ fi
+ PYTHON_SANITY_CHECKS="1"
+}
+
+_python_set_color_variables() {
+ if [[ "${NOCOLOR:-false}" =~ ^(false|no)$ ]]; then
+ _BOLD=$'\e[1m'
+ _RED=$'\e[1;31m'
+ _GREEN=$'\e[1;32m'
+ _BLUE=$'\e[1;34m'
+ _CYAN=$'\e[1;36m'
+ _NORMAL=$'\e[0m'
+ else
+ _BOLD=
+ _RED=
+ _GREEN=
+ _BLUE=
+ _CYAN=
+ _NORMAL=
+ fi
+}
+
+unset PYTHON_PKG_SETUP_EXECUTED
+
# @FUNCTION: python_pkg_setup
# @DESCRIPTION:
-# Makes sure PYTHON_USE_WITH or PYTHON_USE_WITH_OR listed use flags
-# are respected. Only exported if one of those variables is set.
-if ! has "${EAPI:-0}" 0 1 && [[ -n ${PYTHON_USE_WITH} || -n ${PYTHON_USE_WITH_OR} ]]; then
- python_pkg_setup() {
- # Check if phase is pkg_setup().
- [[ "${EBUILD_PHASE}" != "setup" ]] && die "${FUNCNAME}() can be used only in pkg_setup() phase"
+# Perform sanity checks and initialize environment.
+#
+# This function is exported in EAPI 2 and 3 when PYTHON_USE_WITH or PYTHON_USE_WITH_OR variable
+# is set and always in EAPI >=4. Calling of this function is mandatory in EAPI >=4.
+#
+# This function can be used only in pkg_setup() phase.
+python_pkg_setup() {
+ # Check if phase is pkg_setup().
+ [[ "${EBUILD_PHASE}" != "setup" ]] && die "${FUNCNAME}() can be used only in pkg_setup() phase"
- python_pkg_setup_fail() {
- eerror "${1}"
- die "${1}"
- }
+ if _python_package_supporting_installation_for_multiple_python_abis; then
+ validate_PYTHON_ABIS
+ export EPYTHON="$(PYTHON -f)"
+ else
+ PYTHON_ABI="$(PYTHON --ABI)"
+ fi
+ if ! has "${EAPI:-0}" 0 1 && [[ -n "${PYTHON_USE_WITH}" || -n "${PYTHON_USE_WITH_OR}" ]]; then
if [[ "${PYTHON_USE_WITH_OPT}" ]]; then
if [[ "${PYTHON_USE_WITH_OPT}" == !* ]]; then
use ${PYTHON_USE_WITH_OPT#!} && return
@@ -207,23 +345,25 @@ if ! has "${EAPI:-0}" 0 1 && [[ -n ${PYTHON_USE_WITH} || -n ${PYTHON_USE_WITH_OR
fi
python_pkg_setup_check_USE_flags() {
- local pyatom use
- pyatom="$(python_get_implementational_package)"
+ local python_atom USE_flag
+ python_atom="$(python_get_implementational_package)"
- for use in ${PYTHON_USE_WITH}; do
- if ! has_version "${pyatom}[${use}]"; then
- python_pkg_setup_fail "Please rebuild ${pyatom} with the following USE flags enabled: ${PYTHON_USE_WITH}"
+ for USE_flag in ${PYTHON_USE_WITH}; do
+ if ! has_version "${python_atom}[${USE_flag}]"; then
+ eerror "Please rebuild ${python_atom} with the following USE flags enabled: ${PYTHON_USE_WITH}"
+ die "Please rebuild ${python_atom} with the following USE flags enabled: ${PYTHON_USE_WITH}"
fi
done
- for use in ${PYTHON_USE_WITH_OR}; do
- if has_version "${pyatom}[${use}]"; then
+ for USE_flag in ${PYTHON_USE_WITH_OR}; do
+ if has_version "${python_atom}[${USE_flag}]"; then
return
fi
done
if [[ ${PYTHON_USE_WITH_OR} ]]; then
- python_pkg_setup_fail "Please rebuild ${pyatom} with at least one of the following USE flags enabled: ${PYTHON_USE_WITH_OR}"
+ eerror "Please rebuild ${python_atom} with at least one of the following USE flags enabled: ${PYTHON_USE_WITH_OR}"
+ die "Please rebuild ${python_atom} with at least one of the following USE flags enabled: ${PYTHON_USE_WITH_OR}"
fi
}
@@ -233,38 +373,148 @@ if ! has "${EAPI:-0}" 0 1 && [[ -n ${PYTHON_USE_WITH} || -n ${PYTHON_USE_WITH_OR
python_pkg_setup_check_USE_flags
fi
- unset -f python_pkg_setup_check_USE_flags python_pkg_setup_fail
- }
+ unset -f python_pkg_setup_check_USE_flags
+ fi
+
+ PYTHON_PKG_SETUP_EXECUTED="1"
+}
+if ! has "${EAPI:-0}" 0 1 2 3 || has "${EAPI:-0}" 2 3 && [[ -n "${PYTHON_USE_WITH}" || -n "${PYTHON_USE_WITH_OR}" ]]; then
EXPORT_FUNCTIONS pkg_setup
+fi
- _PYTHON_USE_WITH_ATOMS_ARRAY=()
- if [[ -n "${PYTHON_USE_WITH}" ]]; then
- for _PYTHON_ATOM in "${_PYTHON_ATOMS[@]}"; do
- _PYTHON_USE_WITH_ATOMS_ARRAY+=("${_PYTHON_ATOM}[${PYTHON_USE_WITH/ /,}]")
- done
- elif [[ -n "${PYTHON_USE_WITH_OR}" ]]; then
- for _USE_flag in ${PYTHON_USE_WITH_OR}; do
- for _PYTHON_ATOM in "${_PYTHON_ATOMS[@]}"; do
- _PYTHON_USE_WITH_ATOMS_ARRAY+=("${_PYTHON_ATOM}[${_USE_flag}]")
- done
+# @FUNCTION: python_convert_shebangs
+# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_version> <file|directory> [files|directories]
+# @DESCRIPTION:
+# Convert shebangs in specified files. Directories can be specified only with --recursive option.
+python_convert_shebangs() {
+ local argument file files=() only_executables="0" python_version quiet="0" recursive="0"
+
+ while (($#)); do
+ case "$1" in
+ -r|--recursive)
+ recursive="1"
+ ;;
+ -q|--quiet)
+ quiet="1"
+ ;;
+ -x|--only-executables)
+ only_executables="1"
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ die "${FUNCNAME}(): Unrecognized option '$1'"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
+ if [[ "$#" -eq 0 ]]; then
+ die "${FUNCNAME}(): Missing Python version and files or directories"
+ elif [[ "$#" -eq 1 ]]; then
+ die "${FUNCNAME}(): Missing files or directories"
+ fi
+
+ python_version="$1"
+ shift
+
+ for argument in "$@"; do
+ if [[ ! -e "${argument}" ]]; then
+ die "${FUNCNAME}(): '${argument}' does not exist"
+ elif [[ -f "${argument}" ]]; then
+ files+=("${argument}")
+ elif [[ -d "${argument}" ]]; then
+ if [[ "${recursive}" == "1" ]]; then
+ while read -d $'\0' -r file; do
+ files+=("${file}")
+ done < <(find "${argument}" $([[ "${only_executables}" == "1" ]] && echo -perm /111) -type f -print0)
+ else
+ die "${FUNCNAME}(): '${argument}' is not a regular file"
+ fi
+ else
+ die "${FUNCNAME}(): '${argument}' is not a regular file or a directory"
+ fi
+ done
+
+ for file in "${files[@]}"; do
+ file="${file#./}"
+ [[ "${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 "#!".
+ sed -e '1s/\(^#!\)[[:space:]]*/\1/' -i "${file}" || die "sed '${file}' failed"
+ fi
+ done
+}
+
+# @FUNCTION: python_clean_installation_image
+# @USAGE: [-q|--quiet]
+# @DESCRIPTION:
+# Delete needless files in installation image.
+python_clean_installation_image() {
+ _python_initialize_prefix_variables
+
+ local file files=() quiet="0"
+
+ # Check if phase is src_install().
+ [[ "${EBUILD_PHASE}" != "install" ]] && die "${FUNCNAME}() can be used only in src_install() phase"
+
+ while (($#)); do
+ case "$1" in
+ -q|--quiet)
+ quiet="1"
+ ;;
+ -*)
+ die "${FUNCNAME}(): Unrecognized option '$1'"
+ ;;
+ *)
+ die "${FUNCNAME}(): Invalid usage"
+ ;;
+ esac
+ shift
+ done
+
+ while read -d $'\0' -r file; do
+ files+=("${file}")
+ done < <(find "${ED}" "(" -name "*.py[co]" -o -name "*\$py.class" ")" -type f -print0)
+
+ if [[ "${#files[@]}" -gt 0 ]]; then
+ if [[ "${quiet}" == "0" ]]; then
+ ewarn "Deleting byte-compiled Python modules needlessly generated by build system:"
+ fi
+ for file in "${files[@]}"; do
+ if [[ "${quiet}" == "0" ]]; then
+ ewarn " ${file}"
+ fi
+ rm -f "${file}"
done
- unset _USE_flag
fi
- if [[ "${#_PYTHON_USE_WITH_ATOMS_ARRAY[@]}" -gt 1 ]]; then
- _PYTHON_USE_WITH_ATOMS="|| ( ${_PYTHON_USE_WITH_ATOMS_ARRAY[@]} )"
+
+ python_clean_sitedirs() {
+ find "${ED}$(python_get_sitedir)" "(" -name "*.c" -o -name "*.h" -o -name "*.la" ")" -type f -print0 | xargs -0 rm -f
+ }
+ if _python_package_supporting_installation_for_multiple_python_abis; then
+ python_execute_function -q python_clean_sitedirs
else
- _PYTHON_USE_WITH_ATOMS="${_PYTHON_USE_WITH_ATOMS_ARRAY[@]}"
+ python_clean_sitedirs
fi
- if [[ -n "${PYTHON_USE_WITH_OPT}" ]]; then
- _PYTHON_USE_WITH_ATOMS="${PYTHON_USE_WITH_OPT}? ( ${_PYTHON_USE_WITH_ATOMS} )"
- fi
- DEPEND+=" ${_PYTHON_USE_WITH_ATOMS}"
- RDEPEND+=" ${_PYTHON_USE_WITH_ATOMS}"
- unset _PYTHON_ATOM _PYTHON_USE_WITH_ATOMS _PYTHON_USE_WITH_ATOMS_ARRAY
-fi
-unset _PYTHON_ATOMS
+ unset -f python_clean_sitedirs
+}
# ================================================================================================
# =========== FUNCTIONS FOR PACKAGES SUPPORTING INSTALLATION FOR MULTIPLE PYTHON ABIS ============
@@ -294,7 +544,7 @@ if ! has "${EAPI:-0}" 0 1; then
die \"\${FUNCNAME}() cannot be used in ebuilds of packages not supporting installation for multiple Python ABIs\"
fi
- python_execute_function -d -s \"\$@\"
+ python_execute_function -d -s -- \"\$@\"
}"
done
unset python_default_function
@@ -358,6 +608,10 @@ validate_PYTHON_ABIS() {
else
local python_version python2_version= python3_version= support_python_major_version
+ if ! has_version "dev-lang/python"; then
+ die "${FUNCNAME}(): 'dev-lang/python' is not installed"
+ fi
+
python_version="$("${EPREFIX}/usr/bin/python" -c 'from sys import version_info; print(".".join(str(x) for x in version_info[:2]))')"
if has_version "=dev-lang/python-2*"; then
@@ -675,7 +929,7 @@ python_copy_sources() {
if [[ "$#" -eq 0 ]]; then
if [[ "${WORKDIR}" == "${S}" ]]; then
- die "${FUNCNAME}() cannot be used"
+ die "${FUNCNAME}() cannot be used with current value of S variable"
fi
dirs=("${S%/}")
else
@@ -909,6 +1163,10 @@ python_set_active_version() {
die "${FUNCNAME}() cannot be used in ebuilds of packages supporting installation for multiple Python ABIs"
fi
+ if [[ -n "${PYTHON_PKG_SETUP_EXECUTED}" ]]; then
+ die "${FUNCNAME}() should be called before python_pkg_setup()"
+ fi
+
if [[ "$#" -ne 1 ]]; then
die "${FUNCNAME}() requires 1 argument"
fi
@@ -1045,19 +1303,22 @@ PYTHON() {
elif [[ "${python2}" == "1" ]]; then
PYTHON_ABI="$(eselect python show --python2 --ABI)"
if [[ -z "${PYTHON_ABI}" ]]; then
- die "${FUNCNAME}(): Active Python 2 interpreter not set"
+ die "${FUNCNAME}(): Active version of Python 2 not set"
elif [[ "${PYTHON_ABI}" != "2."* ]]; then
die "${FUNCNAME}(): Internal error in \`eselect python show --python2\`"
fi
elif [[ "${python3}" == "1" ]]; then
PYTHON_ABI="$(eselect python show --python3 --ABI)"
if [[ -z "${PYTHON_ABI}" ]]; then
- die "${FUNCNAME}(): Active Python 3 interpreter not set"
+ die "${FUNCNAME}(): Active version of Python 3 not set"
elif [[ "${PYTHON_ABI}" != "3."* ]]; then
die "${FUNCNAME}(): Internal error in \`eselect python show --python3\`"
fi
elif ! _python_package_supporting_installation_for_multiple_python_abis; then
PYTHON_ABI="$("${EPREFIX}/usr/bin/python" -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")"
+ if [[ -z "${PYTHON_ABI}" ]]; then
+ die "${FUNCNAME}(): Main active version of Python not set"
+ fi
elif [[ -z "${PYTHON_ABI}" ]]; then
die "${FUNCNAME}(): Invalid usage: ${FUNCNAME}() should be used in ABI-specific local scope"
fi
@@ -1398,194 +1659,6 @@ python_get_version() {
}
# ================================================================================================
-# =================================== MISCELLANEOUS FUNCTIONS ====================================
-# ================================================================================================
-
-_python_implementation() {
- if [[ "${CATEGORY}/${PN}" == "dev-lang/python" ]]; then
- return 0
- elif [[ "${CATEGORY}/${PN}" == "dev-java/jython" ]]; then
- return 0
- else
- return 1
- fi
-}
-
-_python_package_supporting_installation_for_multiple_python_abis() {
- if [[ "${EBUILD_PHASE}" == "depend" ]]; then
- die "${FUNCNAME}() cannot be used in global scope"
- fi
-
- if has "${EAPI:-0}" 0 1 2 3 4; then
- if [[ -n "${SUPPORT_PYTHON_ABIS}" ]]; then
- return 0
- else
- return 1
- fi
- else
- die "${FUNCNAME}(): Support for EAPI=\"${EAPI}\" not implemented"
- fi
-}
-
-_python_initialize_prefix_variables() {
- if has "${EAPI:-0}" 0 1 2; then
- if [[ -n "${ROOT}" && -z "${EROOT}" ]]; then
- EROOT="${ROOT%/}${EPREFIX}/"
- fi
- if [[ -n "${D}" && -z "${ED}" ]]; then
- ED="${D%/}${EPREFIX}/"
- fi
- fi
-}
-
-unset PYTHON_SANITY_CHECKS
-
-_python_initial_sanity_checks() {
- if [[ "$(declare -p PYTHON_SANITY_CHECKS 2> /dev/null)" != "declare -- PYTHON_SANITY_CHECKS="* ]]; then
- # Ensure that /usr/bin/python and /usr/bin/python-config are valid.
- if [[ "$(readlink "${EPREFIX}/usr/bin/python")" != "python-wrapper" ]]; then
- eerror "'${EPREFIX}/usr/bin/python' is not valid symlink."
- eerror "Use \`eselect python set \${python_interpreter}\` to fix this problem."
- die "'${EPREFIX}/usr/bin/python' is not valid symlink"
- fi
- if [[ "$(<"${EPREFIX}/usr/bin/python-config")" != *"Gentoo python-config wrapper script"* ]]; then
- eerror "'${EPREFIX}/usr/bin/python-config' is not valid script"
- eerror "Use \`eselect python set \${python_interpreter}\` to fix this problem."
- die "'${EPREFIX}/usr/bin/python-config' is not valid script"
- fi
- fi
-}
-
-_python_final_sanity_checks() {
- if ! _python_implementation && [[ "$(declare -p PYTHON_SANITY_CHECKS 2> /dev/null)" != "declare -- PYTHON_SANITY_CHECKS="* ]]; then
- local PYTHON_ABI="${PYTHON_ABI}"
- for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI}}; do
- # Ensure that appropriate version of Python is installed.
- if ! has_version "$(python_get_implementational_package)"; then
- die "$(python_get_implementational_package) is not installed"
- fi
-
- # Ensure that EPYTHON variable is respected.
- if [[ "$(EPYTHON="$(PYTHON)" python -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")" != "${PYTHON_ABI}" ]]; then
- eerror "python: '$(type -p python)'"
- eerror "ABI: '${ABI}'"
- eerror "DEFAULT_ABI: '${DEFAULT_ABI}'"
- eerror "EPYTHON: '$(PYTHON)'"
- eerror "PYTHON_ABI: '${PYTHON_ABI}'"
- eerror "Version of enabled Python: '$(EPYTHON="$(PYTHON)" python -c "${_PYTHON_ABI_EXTRACTION_COMMAND}")'"
- die "'python' does not respect EPYTHON variable"
- fi
- done
- fi
- PYTHON_SANITY_CHECKS="1"
-}
-
-_python_set_color_variables() {
- if [[ "${NOCOLOR:-false}" =~ ^(false|no)$ ]]; then
- _BOLD=$'\e[1m'
- _RED=$'\e[1;31m'
- _GREEN=$'\e[1;32m'
- _BLUE=$'\e[1;34m'
- _CYAN=$'\e[1;36m'
- _NORMAL=$'\e[0m'
- else
- _BOLD=
- _RED=
- _GREEN=
- _BLUE=
- _CYAN=
- _NORMAL=
- fi
-}
-
-# @FUNCTION: python_convert_shebangs
-# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_version> <file|directory> [files|directories]
-# @DESCRIPTION:
-# Convert shebangs in specified files. Directories can be specified only with --recursive option.
-python_convert_shebangs() {
- local argument file files=() only_executables="0" python_version quiet="0" recursive="0"
-
- while (($#)); do
- case "$1" in
- -r|--recursive)
- recursive="1"
- ;;
- -q|--quiet)
- quiet="1"
- ;;
- -x|--only-executables)
- only_executables="1"
- ;;
- --)
- shift
- break
- ;;
- -*)
- die "${FUNCNAME}(): Unrecognized option '$1'"
- ;;
- *)
- break
- ;;
- esac
- shift
- done
-
- if [[ "$#" -eq 0 ]]; then
- die "${FUNCNAME}(): Missing Python version and files or directories"
- elif [[ "$#" -eq 1 ]]; then
- die "${FUNCNAME}(): Missing files or directories"
- fi
-
- python_version="$1"
- shift
-
- for argument in "$@"; do
- if [[ ! -e "${argument}" ]]; then
- die "${FUNCNAME}(): '${argument}' does not exist"
- elif [[ -f "${argument}" ]]; then
- files+=("${argument}")
- elif [[ -d "${argument}" ]]; then
- if [[ "${recursive}" == "1" ]]; then
- while read -d $'\0' -r file; do
- files+=("${file}")
- done < <(find "${argument}" $([[ "${only_executables}" == "1" ]] && echo -perm /111) -type f -print0)
- else
- die "${FUNCNAME}(): '${argument}' is not a regular file"
- fi
- else
- die "${FUNCNAME}(): '${argument}' is not a regular file or a directory"
- fi
- done
-
- for file in "${files[@]}"; do
- file="${file#./}"
- [[ "${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 "#!".
- sed -e '1s/\(^#!\)[[:space:]]*/\1/' -i "${file}" || die "sed '${file}' failed"
- fi
- 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 ================================
# ================================================================================================
@@ -1830,6 +1903,93 @@ python_disable_pyc() {
export PYTHONDONTWRITEBYTECODE="1"
}
+_python_clean_compiled_modules() {
+ _python_initialize_prefix_variables
+ _python_set_color_variables
+
+ [[ "${FUNCNAME[1]}" =~ ^(python_mod_optimize|python_mod_compile|python_mod_cleanup)$ ]] || die "${FUNCNAME}(): Invalid usage"
+
+ local base_module_name compiled_file compiled_files=() dir path py_file root
+
+ # Strip trailing slash from EROOT.
+ root="${EROOT%/}"
+
+ for path in "$@"; do
+ compiled_files=()
+ if [[ -d "${path}" ]]; then
+ while read -d $'\0' -r compiled_file; do
+ compiled_files+=("${compiled_file}")
+ done < <(find "${path}" "(" -name "*.py[co]" -o -name "*\$py.class" ")" -print0)
+
+ if [[ "${EBUILD_PHASE}" == "postrm" ]]; then
+ # Delete empty child directories.
+ find "${path}" -type d | sort -r | while read -r dir; do
+ rmdir "${dir}" 2> /dev/null && echo "${_CYAN}<<< ${dir}${_NORMAL}"
+ done
+ fi
+ elif [[ "${path}" == *.py ]]; then
+ base_module_name="${path##*/}"
+ base_module_name="${base_module_name%.py}"
+ if [[ -d "${path%/*}/__pycache__" ]]; then
+ while read -d $'\0' -r compiled_file; do
+ compiled_files+=("${compiled_file}")
+ done < <(find "${path%/*}/__pycache__" "(" -name "${base_module_name}.*.py[co]" -o -name "${base_module_name}\$py.class" ")" -print0)
+ fi
+ compiled_files+=("${path}c" "${path}o" "${path%.py}\$py.class")
+ fi
+
+ for compiled_file in "${compiled_files[@]}"; do
+ [[ ! -f "${compiled_file}" ]] && continue
+ dir="${compiled_file%/*}"
+ dir="${dir##*/}"
+ if [[ "${compiled_file}" == *.py[co] ]]; then
+ if [[ "${dir}" == "__pycache__" ]]; then
+ base_module_name="${compiled_file##*/}"
+ base_module_name="${base_module_name%%.*py[co]}"
+ py_file="${compiled_file%__pycache__/*}${base_module_name}.py"
+ else
+ py_file="${compiled_file%[co]}"
+ fi
+ if [[ "${EBUILD_PHASE}" == "postinst" ]]; then
+ [[ -f "${py_file}" && "${compiled_file}" -nt "${py_file}" ]] && continue
+ else
+ [[ -f "${py_file}" ]] && continue
+ fi
+ echo "${_BLUE}<<< ${compiled_file%[co]}[co]${_NORMAL}"
+ rm -f "${compiled_file%[co]}"[co]
+ elif [[ "${compiled_file}" == *\$py.class ]]; then
+ if [[ "${dir}" == "__pycache__" ]]; then
+ base_module_name="${compiled_file##*/}"
+ base_module_name="${base_module_name%\$py.class}"
+ py_file="${compiled_file%__pycache__/*}${base_module_name}.py"
+ else
+ py_file="${compiled_file%\$py.class}"
+ fi
+ if [[ "${EBUILD_PHASE}" == "postinst" ]]; then
+ [[ -f "${py_file}" && "${compiled_file}" -nt "${py_file}" ]] && continue
+ else
+ [[ -f "${py_file}" ]] && continue
+ fi
+ echo "${_BLUE}<<< ${compiled_file}${_NORMAL}"
+ rm -f "${compiled_file}"
+ else
+ die "${FUNCNAME}(): Unrecognized file type: '${compiled_file}'"
+ fi
+
+ # Delete empty parent directories.
+ dir="${compiled_file%/*}"
+ while [[ "${dir}" != "${root}" ]]; do
+ if rmdir "${compiled_file%/*}" 2> /dev/null; then
+ echo "${_CYAN}<<< ${compiled_file%/*}${_NORMAL}"
+ else
+ break
+ fi
+ dir="${dir%/*}"
+ done
+ done
+ done
+}
+
# @FUNCTION: python_mod_optimize
# @USAGE: [options] [directory|file]
# @DESCRIPTION:
@@ -1849,12 +2009,22 @@ python_mod_optimize() {
[[ "${EBUILD_PHASE}" != "postinst" ]] && die "${FUNCNAME}() can be used only in pkg_postinst() phase"
if ! has "${EAPI:-0}" 0 1 2 || _python_package_supporting_installation_for_multiple_python_abis; then
- local dir file options=() other_dirs=() other_files=() previous_PYTHON_ABI="${PYTHON_ABI}" PYTHON_ABI="${PYTHON_ABI}" return_code root site_packages_absolute_dirs=() site_packages_dirs=() site_packages_absolute_files=() site_packages_files=()
+ # PYTHON_ABI variable cannot be local in packages not supporting installation for multiple Python ABIs.
+ local dir file iterated_PYTHON_ABIS options=() other_dirs=() other_files=() previous_PYTHON_ABI="${PYTHON_ABI}" return_code root site_packages_absolute_dirs=() site_packages_dirs=() site_packages_absolute_files=() site_packages_files=()
+
+ if _python_package_supporting_installation_for_multiple_python_abis; then
+ if [[ -z "${PYTHON_ABIS}" ]]; then
+ die "${FUNCNAME}(): Environment not initialized"
+ fi
+ iterated_PYTHON_ABIS="${PYTHON_ABIS}"
+ else
+ iterated_PYTHON_ABIS="${PYTHON_ABI:=$(PYTHON --ABI)}"
+ fi
- # Strip trailing slash from ROOT.
+ # Strip trailing slash from EROOT.
root="${EROOT%/}"
- # Respect ROOT and options passed to compileall.py.
+ # Respect EROOT and options passed to compileall.py.
while (($#)); do
case "$1" in
-l|-f|-q)
@@ -1868,20 +2038,23 @@ python_mod_optimize() {
ewarn "${FUNCNAME}(): Ignoring option '$1'"
;;
*)
- if ! _python_implementation && [[ "$1" =~ ^"${EPREFIX}"/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then
- die "${FUNCNAME}() does not support absolute paths of directories/files in site-packages directories"
+ if ! _python_implementation && [[ "$1" =~ ^/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then
+ die "${FUNCNAME}(): Paths of directories / files in site-packages directories must be relative to site-packages directories"
elif [[ "$1" =~ ^/ ]]; then
- if [[ -d "${root}/$1" ]]; then
- other_dirs+=("${root}/$1")
- elif [[ -f "${root}/$1" ]]; then
- other_files+=("${root}/$1")
- elif [[ -e "${root}/$1" ]]; then
- ewarn "'${root}/$1' is not a file or a directory!"
+ if _python_package_supporting_installation_for_multiple_python_abis; then
+ die "${FUNCNAME}(): Absolute paths cannot be used in ebuilds of packages supporting installation for multiple Python ABIs"
+ fi
+ if [[ -d "${root}$1" ]]; then
+ other_dirs+=("${root}$1")
+ elif [[ -f "${root}$1" ]]; then
+ other_files+=("${root}$1")
+ elif [[ -e "${root}$1" ]]; then
+ ewarn "'${root}$1' is not a file or a directory!"
else
- ewarn "'${root}/$1' does not exist!"
+ ewarn "'${root}$1' does not exist!"
fi
else
- for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI:-$(PYTHON --ABI)}}; do
+ for PYTHON_ABI in ${iterated_PYTHON_ABIS}; do
if [[ -d "${root}$(python_get_sitedir)/$1" ]]; then
site_packages_dirs+=("$1")
break
@@ -1903,7 +2076,7 @@ python_mod_optimize() {
# Set additional options.
options+=("-q")
- for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI:-$(PYTHON --ABI)}}; do
+ for PYTHON_ABI in ${iterated_PYTHON_ABIS}; do
if ((${#site_packages_dirs[@]})) || ((${#site_packages_files[@]})); then
return_code="0"
ebegin "Compilation and optimization of Python modules for $(python_get_implementation) $(python_get_version)"
@@ -1915,6 +2088,7 @@ python_mod_optimize() {
if [[ "$(_python_get_implementation "${PYTHON_ABI}")" != "Jython" ]]; then
"$(PYTHON)" -O "${root}$(python_get_libdir)/compileall.py" "${options[@]}" "${site_packages_absolute_dirs[@]}" &> /dev/null || return_code="1"
fi
+ _python_clean_compiled_modules "${site_packages_absolute_dirs[@]}"
fi
if ((${#site_packages_files[@]})); then
for file in "${site_packages_files[@]}"; do
@@ -1924,17 +2098,20 @@ python_mod_optimize() {
if [[ "$(_python_get_implementation "${PYTHON_ABI}")" != "Jython" ]]; then
"$(PYTHON)" -O "${root}$(python_get_libdir)/py_compile.py" "${site_packages_absolute_files[@]}" &> /dev/null || return_code="1"
fi
+ _python_clean_compiled_modules "${site_packages_absolute_files[@]}"
fi
eend "${return_code}"
fi
unset site_packages_absolute_dirs site_packages_absolute_files
done
- # Restore previous value of PYTHON_ABI.
- if [[ -n "${previous_PYTHON_ABI}" ]]; then
- PYTHON_ABI="${previous_PYTHON_ABI}"
- else
- unset PYTHON_ABI
+ if _python_package_supporting_installation_for_multiple_python_abis; then
+ # Restore previous value of PYTHON_ABI.
+ if [[ -n "${previous_PYTHON_ABI}" ]]; then
+ PYTHON_ABI="${previous_PYTHON_ABI}"
+ else
+ unset PYTHON_ABI
+ fi
fi
if ((${#other_dirs[@]})) || ((${#other_files[@]})); then
@@ -1945,12 +2122,14 @@ python_mod_optimize() {
if [[ "$(_python_get_implementation "${PYTHON_ABI-$(PYTHON --ABI)}")" != "Jython" ]]; then
"$(PYTHON ${PYTHON_ABI})" -O "${root}$(python_get_libdir)/compileall.py" "${options[@]}" "${other_dirs[@]}" &> /dev/null || return_code="1"
fi
+ _python_clean_compiled_modules "${other_dirs[@]}"
fi
if ((${#other_files[@]})); then
"$(PYTHON ${PYTHON_ABI})" "${root}$(python_get_libdir)/py_compile.py" "${other_files[@]}" || return_code="1"
if [[ "$(_python_get_implementation "${PYTHON_ABI-$(PYTHON --ABI)}")" != "Jython" ]]; then
"$(PYTHON ${PYTHON_ABI})" -O "${root}$(python_get_libdir)/py_compile.py" "${other_files[@]}" &> /dev/null || return_code="1"
fi
+ _python_clean_compiled_modules "${other_dirs[@]}"
fi
eend "${return_code}"
fi
@@ -1960,7 +2139,7 @@ python_mod_optimize() {
# strip trailing slash
myroot="${EROOT%/}"
- # respect ROOT and options passed to compileall.py
+ # respect EROOT and options passed to compileall.py
while (($#)); do
case "$1" in
-l|-f|-q)
@@ -1974,15 +2153,15 @@ python_mod_optimize() {
ewarn "${FUNCNAME}(): Ignoring option '$1'"
;;
*)
- if [[ -d "${myroot}"/$1 ]]; then
- mydirs+=("${myroot}/$1")
- elif [[ -f "${myroot}"/$1 ]]; then
- # Files are passed to python_mod_compile which is ROOT-aware
+ if [[ -d "${myroot}/${1#/}" ]]; then
+ mydirs+=("${myroot}/${1#/}")
+ elif [[ -f "${myroot}/${1#/}" ]]; then
+ # Files are passed to python_mod_compile which is EROOT-aware
myfiles+=("$1")
- elif [[ -e "${myroot}/$1" ]]; then
- ewarn "${myroot}/$1 is not a file or directory!"
+ elif [[ -e "${myroot}/${1#/}" ]]; then
+ ewarn "${myroot}/${1#/} is not a file or directory!"
else
- ewarn "${myroot}/$1 does not exist!"
+ ewarn "${myroot}/${1#/} does not exist!"
fi
;;
esac
@@ -1992,10 +2171,13 @@ python_mod_optimize() {
# set additional opts
myopts+=(-q)
+ PYTHON_ABI="$(PYTHON --ABI)"
+
ebegin "Compilation and optimization of Python modules for $(python_get_implementation) $(python_get_version)"
if ((${#mydirs[@]})); then
"$(PYTHON ${PYTHON_ABI})" "${myroot}$(python_get_libdir)/compileall.py" "${myopts[@]}" "${mydirs[@]}" || return_code="1"
"$(PYTHON ${PYTHON_ABI})" -O "${myroot}$(python_get_libdir)/compileall.py" "${myopts[@]}" "${mydirs[@]}" &> /dev/null || return_code="1"
+ _python_clean_compiled_modules "${mydirs[@]}"
fi
if ((${#myfiles[@]})); then
@@ -2019,83 +2201,63 @@ python_mod_optimize() {
# This function can be used only in pkg_postrm() phase.
python_mod_cleanup() {
_python_initialize_prefix_variables
- _python_set_color_variables
- local path py_file PYTHON_ABI="${PYTHON_ABI}" SEARCH_PATH=() root
+ local dir iterated_PYTHON_ABIS PYTHON_ABI="${PYTHON_ABI}" root search_paths=() sitedir
# Check if phase is pkg_postrm().
[[ "${EBUILD_PHASE}" != "postrm" ]] && die "${FUNCNAME}() can be used only in pkg_postrm() phase"
- # Strip trailing slash from ROOT.
+ if _python_package_supporting_installation_for_multiple_python_abis; then
+ if [[ -z "${PYTHON_ABIS}" ]]; then
+ die "${FUNCNAME}(): Environment not initialized"
+ fi
+ iterated_PYTHON_ABIS="${PYTHON_ABIS}"
+ else
+ iterated_PYTHON_ABIS="${PYTHON_ABI:-$(PYTHON --ABI)}"
+ fi
+
+ # Strip trailing slash from EROOT.
root="${EROOT%/}"
if (($#)); then
if ! has "${EAPI:-0}" 0 1 2 || _python_package_supporting_installation_for_multiple_python_abis; then
while (($#)); do
- if ! _python_implementation && [[ "$1" =~ ^"${EPREFIX}"/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then
- die "${FUNCNAME}() does not support absolute paths of directories/files in site-packages directories"
+ if ! _python_implementation && [[ "$1" =~ ^/usr/lib(32|64)?/python[[:digit:]]+\.[[:digit:]]+ ]]; then
+ die "${FUNCNAME}(): Paths of directories / files in site-packages directories must be relative to site-packages directories"
elif [[ "$1" =~ ^/ ]]; then
- SEARCH_PATH+=("${root}/${1#/}")
+ if _python_package_supporting_installation_for_multiple_python_abis; then
+ die "${FUNCNAME}(): Absolute paths cannot be used in ebuilds of packages supporting installation for multiple Python ABIs"
+ fi
+ search_paths+=("${root}$1")
else
- for PYTHON_ABI in ${PYTHON_ABIS-${PYTHON_ABI:-$(PYTHON --ABI)}}; do
- SEARCH_PATH+=("${root}$(python_get_sitedir)/$1")
+ for PYTHON_ABI in ${iterated_PYTHON_ABIS}; do
+ search_paths+=("${root}$(python_get_sitedir)/$1")
done
fi
shift
done
else
- SEARCH_PATH=("${@#/}")
- SEARCH_PATH=("${SEARCH_PATH[@]/#/${root}/}")
+ search_paths=("${@#/}")
+ search_paths=("${search_paths[@]/#/${root}/}")
fi
else
- local dir sitedir
for dir in "${root}"/usr/lib*; do
if [[ -d "${dir}" && ! -L "${dir}" ]]; then
for sitedir in "${dir}"/python*/site-packages; do
if [[ -d "${sitedir}" ]]; then
- SEARCH_PATH+=("${sitedir}")
+ search_paths+=("${sitedir}")
fi
done
fi
done
for sitedir in "${root}"/usr/share/jython-*/Lib/site-packages; do
if [[ -d "${sitedir}" ]]; then
- SEARCH_PATH+=("${sitedir}")
+ search_paths+=("${sitedir}")
fi
done
fi
- for path in "${SEARCH_PATH[@]}"; do
- if [[ -d "${path}" ]]; then
- find "${path}" "(" -name "*.py[co]" -o -name "*\$py.class" ")" -print0 | while read -rd ''; do
- if [[ "${REPLY}" == *[co] ]]; then
- py_file="${REPLY%[co]}"
- [[ -f "${py_file}" || (! -f "${py_file}c" && ! -f "${py_file}o") ]] && continue
- 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
- 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 && echo "${_CYAN}<<< ${dir}${_NORMAL}"
- done
- elif [[ "${path}" == *.py && ! -f "${path}" ]]; then
- if [[ (-f "${path}c" || -f "${path}o") ]]; then
- echo "${_BLUE}<<< ${path}[co]${_NORMAL}"
- rm -f "${path}"[co]
- fi
- if [[ -f "${path%.py}\$py.class" ]]; then
- echo "${_BLUE}<<< ${path%.py}\$py.class${_NORMAL}"
- rm -f "${path%.py}\$py.class"
- fi
- fi
- done
+ _python_clean_compiled_modules "${search_paths[@]}"
}
# ================================================================================================
@@ -2159,6 +2321,8 @@ python_mod_exists() {
die "${FUNCNAME}() cannot be used in this EAPI"
fi
+ _python_set_color_variables
+
echo
echo " ${_RED}*${_NORMAL} ${_RED}Deprecation Warning: ${FUNCNAME}() is deprecated and will be banned on 2010-07-01.${_NORMAL}"
echo " ${_RED}*${_NORMAL} ${_RED}Use USE dependencies and/or has_version() instead of ${FUNCNAME}().${_NORMAL}"
@@ -2187,6 +2351,8 @@ python_tkinter_exists() {
die "${FUNCNAME}() cannot be used in this EAPI"
fi
+ _python_set_color_variables
+
if [[ "${FUNCNAME[1]}" != "distutils_python_tkinter" ]]; then
echo
echo " ${_RED}*${_NORMAL} ${_RED}Deprecation Warning: ${FUNCNAME}() is deprecated and will be banned on 2010-07-01.${_NORMAL}"
@@ -2238,14 +2404,17 @@ python_mod_compile() {
# strip trailing slash
myroot="${EROOT%/}"
- # respect ROOT
+ # respect EROOT
for f in "$@"; do
[[ -f "${myroot}/${f}" ]] && myfiles+=("${myroot}/${f}")
done
+ PYTHON_ABI="$(PYTHON --ABI)"
+
if ((${#myfiles[@]})); then
"$(PYTHON ${PYTHON_ABI})" "${myroot}$(python_get_libdir)/py_compile.py" "${myfiles[@]}"
"$(PYTHON ${PYTHON_ABI})" -O "${myroot}$(python_get_libdir)/py_compile.py" "${myfiles[@]}" &> /dev/null
+ _python_clean_compiled_modules "${myfiles[@]}"
else
ewarn "No files to compile!"
fi