summaryrefslogtreecommitdiff
path: root/eclass
diff options
context:
space:
mode:
Diffstat (limited to 'eclass')
-rw-r--r--eclass/python.eclass418
1 files changed, 339 insertions, 79 deletions
diff --git a/eclass/python.eclass b/eclass/python.eclass
index 56ad1d680f3e..282750320d5a 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.105 2010/10/29 19:09:08 arfrever Exp $
+# $Header: /var/cvsroot/gentoo-x86/eclass/python.eclass,v 1.106 2010/12/24 15:01:09 arfrever Exp $
# @ECLASS: python.eclass
# @MAINTAINER:
@@ -15,15 +15,35 @@ if ! has "${EAPI:-0}" 0 1 2 3; then
die "API of python.eclass in EAPI=\"${EAPI}\" not established"
fi
-_CPYTHON2_SUPPORTED_ABIS=(2.4 2.5 2.6 2.7)
-_CPYTHON3_SUPPORTED_ABIS=(3.0 3.1 3.2)
-_JYTHON_SUPPORTED_ABIS=(2.5-jython)
-_PYTHON_SUPPORTED_ABIS=(${_CPYTHON2_SUPPORTED_ABIS[@]} ${_CPYTHON3_SUPPORTED_ABIS[@]} ${_JYTHON_SUPPORTED_ABIS[@]})
+_CPYTHON2_GLOBALLY_SUPPORTED_ABIS=(2.4 2.5 2.6 2.7)
+_CPYTHON3_GLOBALLY_SUPPORTED_ABIS=(3.0 3.1 3.2)
+_JYTHON_GLOBALLY_SUPPORTED_ABIS=(2.5-jython)
+_PYTHON_GLOBALLY_SUPPORTED_ABIS=(${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]} ${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]} ${_JYTHON_GLOBALLY_SUPPORTED_ABIS[@]})
# ================================================================================================
# ===================================== HANDLING OF METADATA =====================================
# ================================================================================================
+_python_check_python_abi_matching() {
+ if [[ "$#" -ne 2 ]]; then
+ die "${FUNCNAME}() requires 2 arguments"
+ fi
+
+ if [[ "$2" == *"-cpython" ]]; then
+ [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ && "$1" == ${2%-cpython} ]]
+ elif [[ "$2" == *"-jython" ]]; then
+ [[ "$1" == $2 ]]
+ else
+ if [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ ]]; then
+ [[ "$1" == $2 ]]
+ elif [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+-jython$ ]]; then
+ [[ "${1%-jython}" == $2 ]]
+ else
+ die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+ fi
+ fi
+}
+
# @ECLASS-VARIABLE: PYTHON_DEPEND
# @DESCRIPTION:
# Specification of dependency on dev-lang/python.
@@ -67,17 +87,17 @@ _python_parse_PYTHON_DEPEND() {
if [[ "${major_version}" == "2" ]]; then
python2="1"
- python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}")
+ python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}")
python2_minimal_version="${minimal_version}"
python2_maximal_version="${maximal_version}"
elif [[ "${major_version}" == "3" ]]; then
python3="1"
- python_versions=("${_CPYTHON3_SUPPORTED_ABIS[@]}")
+ python_versions=("${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
python3_minimal_version="${minimal_version}"
python3_maximal_version="${maximal_version}"
else
python_all="1"
- python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}")
+ python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
python_minimal_version="${minimal_version}"
python_maximal_version="${maximal_version}"
fi
@@ -115,7 +135,7 @@ _python_parse_PYTHON_DEPEND() {
if [[ -z "${python_minimal_version}" && -z "${python_maximal_version}" ]]; then
_PYTHON_ATOMS+=("dev-lang/python")
else
- python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}")
+ python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
python_minimal_version="${python_minimal_version:-${python_versions[0]}}"
python_maximal_version="${python_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
_append_accepted_versions_range
@@ -125,7 +145,7 @@ _python_parse_PYTHON_DEPEND() {
if [[ -z "${python3_minimal_version}" && -z "${python3_maximal_version}" ]]; then
_PYTHON_ATOMS+=("=dev-lang/python-3*")
else
- python_versions=("${_CPYTHON3_SUPPORTED_ABIS[@]}")
+ python_versions=("${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}")
python_minimal_version="${python3_minimal_version:-${python_versions[0]}}"
python_maximal_version="${python3_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
_append_accepted_versions_range
@@ -135,7 +155,7 @@ _python_parse_PYTHON_DEPEND() {
if [[ -z "${python2_minimal_version}" && -z "${python2_maximal_version}" ]]; then
_PYTHON_ATOMS+=("=dev-lang/python-2*")
else
- python_versions=("${_CPYTHON2_SUPPORTED_ABIS[@]}")
+ python_versions=("${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}")
python_minimal_version="${python2_minimal_version:-${python_versions[0]}}"
python_maximal_version="${python2_maximal_version:-${python_versions[${#python_versions[@]}-1]}}"
_append_accepted_versions_range
@@ -350,6 +370,9 @@ python_pkg_setup() {
die "${FUNCNAME}() does not accept arguments"
fi
+ export JYTHON_SYSTEM_CACHEDIR="1"
+ addwrite "${EPREFIX}/var/cache/jython"
+
if _python_package_supporting_installation_for_multiple_python_abis; then
_python_calculate_PYTHON_ABIS
export EPYTHON="$(PYTHON -f)"
@@ -405,14 +428,16 @@ if ! has "${EAPI:-0}" 0 1 2 3 || { has "${EAPI:-0}" 2 3 && [[ -n "${PYTHON_USE_W
EXPORT_FUNCTIONS pkg_setup
fi
+_PYTHON_SHEBANG_BASE_PART_REGEX='^#![[:space:]]*([^[:space:]]*/usr/bin/env[[:space:]]+)?([^[:space:]]*/)?(jython|python)'
+
# @FUNCTION: python_convert_shebangs
-# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_version> <file|directory> [files|directories]
+# @USAGE: [-q|--quiet] [-r|--recursive] [-x|--only-executables] [--] <Python_ABI|Python_version> <file|directory> [files|directories]
# @DESCRIPTION:
# Convert shebangs in specified files. Directories can be specified only with --recursive option.
python_convert_shebangs() {
_python_check_python_pkg_setup_execution
- local argument file files=() only_executables="0" python_version quiet="0" recursive="0"
+ local argument file files=() only_executables="0" python_interpreter quiet="0" recursive="0"
while (($#)); do
case "$1" in
@@ -445,7 +470,11 @@ python_convert_shebangs() {
die "${FUNCNAME}(): Missing files or directories"
fi
- python_version="$1"
+ if [[ -n "$(_python_get_implementation --ignore-invalid "$1")" ]]; then
+ python_interpreter="$(PYTHON "$1")"
+ else
+ python_interpreter="python$1"
+ fi
shift
for argument in "$@"; do
@@ -470,17 +499,14 @@ python_convert_shebangs() {
file="${file#./}"
[[ "${only_executables}" == "1" && ! -x "${file}" ]] && continue
- if [[ "$(head -n1 "${file}")" =~ ^'#!'.*python ]]; then
+ if [[ "$(head -n1 "${file}")" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX} ]]; 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"
+ sed -e "1s:^#![[:space:]]*\([^[:space:]]*/usr/bin/env[[:space:]]\)\?[[:space:]]*\([^[:space:]]*/\)\?\(jython\|python\)\([[:digit:]]\+\(\.[[:digit:]]\+\)\?\)\?\(\$\|[[:space:]].*\):#!\1\2${python_interpreter}\6:" -i "${file}" || die "Conversion of shebang in '${file}' failed"
fi
done
}
@@ -618,17 +644,17 @@ _python_calculate_PYTHON_ABIS() {
fi
for PYTHON_ABI in ${USE_PYTHON}; do
- if ! has "${PYTHON_ABI}" ${_PYTHON_SUPPORTED_ABIS[@]}; then
+ if ! has "${PYTHON_ABI}" "${_PYTHON_GLOBALLY_SUPPORTED_ABIS[@]}"; then
die "USE_PYTHON variable contains invalid value '${PYTHON_ABI}'"
fi
- if has "${PYTHON_ABI}" "${_CPYTHON2_SUPPORTED_ABIS[@]}" "${_CPYTHON3_SUPPORTED_ABIS[@]}"; then
+ if has "${PYTHON_ABI}" "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}" "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; then
cpython_enabled="1"
fi
support_ABI="1"
while read restricted_ABI; do
- if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+ if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
support_ABI="0"
break
fi
@@ -659,10 +685,10 @@ _python_calculate_PYTHON_ABIS() {
python2_version="$("${EPREFIX}/usr/bin/python2" -c 'from sys import version_info; print(".".join(str(x) for x in version_info[:2]))')"
- for PYTHON_ABI in "${_CPYTHON2_SUPPORTED_ABIS[@]}"; do
+ for PYTHON_ABI in "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}"; do
support_python_major_version="1"
while read restricted_ABI; do
- if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+ if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
support_python_major_version="0"
fi
done <<< "${restricted_ABIs}"
@@ -670,8 +696,8 @@ _python_calculate_PYTHON_ABIS() {
done
if [[ "${support_python_major_version}" == "1" ]]; then
while read restricted_ABI; do
- if [[ "${python2_version}" == ${restricted_ABI} ]]; then
- die "Active version of Python 2 is not supported by ${CATEGORY}/${PF}"
+ if _python_check_python_abi_matching "${python2_version}" "${restricted_ABI}"; then
+ die "Active version of CPython 2 is not supported by ${CATEGORY}/${PF}"
fi
done <<< "${restricted_ABIs}"
else
@@ -686,10 +712,10 @@ _python_calculate_PYTHON_ABIS() {
python3_version="$("${EPREFIX}/usr/bin/python3" -c 'from sys import version_info; print(".".join(str(x) for x in version_info[:2]))')"
- for PYTHON_ABI in "${_CPYTHON3_SUPPORTED_ABIS[@]}"; do
+ for PYTHON_ABI in "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; do
support_python_major_version="1"
while read restricted_ABI; do
- if [[ "${PYTHON_ABI}" == ${restricted_ABI} ]]; then
+ if _python_check_python_abi_matching "${PYTHON_ABI}" "${restricted_ABI}"; then
support_python_major_version="0"
fi
done <<< "${restricted_ABIs}"
@@ -697,8 +723,8 @@ _python_calculate_PYTHON_ABIS() {
done
if [[ "${support_python_major_version}" == "1" ]]; then
while read restricted_ABI; do
- if [[ "${python3_version}" == ${restricted_ABI} ]]; then
- die "Active version of Python 3 is not supported by ${CATEGORY}/${PF}"
+ if _python_check_python_abi_matching "${python3_version}" "${restricted_ABI}"; then
+ die "Active version of CPython 3 is not supported by ${CATEGORY}/${PF}"
fi
done <<< "${restricted_ABIs}"
else
@@ -740,7 +766,7 @@ _python_prepare_flags() {
element="${element#* }"
operator="${element%% *}"
flags="${element#* }"
- if [[ "${PYTHON_ABI}" == ${pattern} ]]; then
+ if _python_check_python_abi_matching "${PYTHON_ABI}" "${pattern}"; then
if [[ "${operator}" == "+" ]]; then
eval "export ${variable}+=\"\${variable:+ }${flags}\""
elif [[ "${operator}" == "-" ]]; then
@@ -1057,7 +1083,7 @@ python_generate_wrapper_scripts() {
_python_initialize_prefix_variables
- local eselect_python_option file force="0" quiet="0" PYTHON_ABI python2_enabled="0" python3_enabled="0" respect_EPYTHON="0"
+ local eselect_python_option file force="0" quiet="0" PYTHON_ABI PYTHON_ABIS_list python2_enabled="0" python3_enabled="0" respect_EPYTHON="0"
while (($#)); do
case "$1" in
@@ -1089,12 +1115,12 @@ python_generate_wrapper_scripts() {
fi
_python_calculate_PYTHON_ABIS
- for PYTHON_ABI in "${_CPYTHON2_SUPPORTED_ABIS[@]}"; do
+ for PYTHON_ABI in "${_CPYTHON2_GLOBALLY_SUPPORTED_ABIS[@]}"; do
if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then
python2_enabled="1"
fi
done
- for PYTHON_ABI in "${_CPYTHON3_SUPPORTED_ABIS[@]}"; do
+ for PYTHON_ABI in "${_CPYTHON3_GLOBALLY_SUPPORTED_ABIS[@]}"; do
if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then
python3_enabled="1"
fi
@@ -1110,9 +1136,11 @@ python_generate_wrapper_scripts() {
die "${FUNCNAME}(): Unsupported environment"
fi
+ PYTHON_ABIS_list="$("$(PYTHON -f)" -c "print(', '.join('\"%s\"' % x for x in reversed('${PYTHON_ABIS}'.split())))")"
+
for file in "$@"; do
if [[ -f "${file}" && "${force}" == "0" ]]; then
- die "${FUNCNAME}(): '$1' already exists"
+ die "${FUNCNAME}(): '${file}' already exists"
fi
if [[ "${quiet}" == "0" ]]; then
@@ -1128,10 +1156,22 @@ import re
import subprocess
import sys
-EPYTHON_re = re.compile(r"^python(\d+\.\d+)$")
+cpython_re = re.compile(r"^python(\d+\.\d+)$")
+jython_re = re.compile(r"^jython(\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$")
+def get_PYTHON_ABI(EPYTHON):
+ cpython_matched = cpython_re.match(EPYTHON)
+ jython_matched = jython_re.match(EPYTHON)
+ if cpython_matched is not None:
+ PYTHON_ABI = cpython_matched.group(1)
+ elif jython_matched is not None:
+ PYTHON_ABI = jython_matched.group(1) + "-jython"
+ else:
+ PYTHON_ABI = None
+ return PYTHON_ABI
+
EOF
if [[ "$?" != "0" ]]; then
die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1140,10 +1180,8 @@ EOF
cat << EOF >> "${file}"
EPYTHON = os.environ.get("EPYTHON")
if EPYTHON:
- EPYTHON_matched = EPYTHON_re.match(EPYTHON)
- if EPYTHON_matched:
- PYTHON_ABI = EPYTHON_matched.group(1)
- else:
+ PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+ if PYTHON_ABI is None:
sys.stderr.write("EPYTHON variable has unrecognized value '%s'\n" % EPYTHON)
sys.exit(1)
else:
@@ -1161,12 +1199,16 @@ else:
EPYTHON = EPYTHON.decode()
EPYTHON = EPYTHON.rstrip("\n")
- EPYTHON_matched = EPYTHON_re.match(EPYTHON)
- if EPYTHON_matched:
- PYTHON_ABI = EPYTHON_matched.group(1)
- else:
+ PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+ if PYTHON_ABI is None:
sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s'\n" % EPYTHON)
sys.exit(1)
+
+wrapper_script_path = os.path.realpath(sys.argv[0])
+target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
+if not os.path.exists(target_executable_path):
+ sys.stderr.write("'%s' does not exist\n" % target_executable_path)
+ sys.exit(1)
EOF
if [[ "$?" != "0" ]]; then
die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1187,12 +1229,19 @@ if not isinstance(EPYTHON, str):
EPYTHON = EPYTHON.decode()
EPYTHON = EPYTHON.rstrip("\n")
-EPYTHON_matched = EPYTHON_re.match(EPYTHON)
-if EPYTHON_matched:
- PYTHON_ABI = EPYTHON_matched.group(1)
-else:
+PYTHON_ABI = get_PYTHON_ABI(EPYTHON)
+if PYTHON_ABI is None:
sys.stderr.write("'eselect python show${eselect_python_option:+ }${eselect_python_option}' printed unrecognized value '%s'\n" % EPYTHON)
sys.exit(1)
+
+wrapper_script_path = os.path.realpath(sys.argv[0])
+for PYTHON_ABI in [PYTHON_ABI, ${PYTHON_ABIS_list}]:
+ target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
+ if os.path.exists(target_executable_path):
+ break
+else:
+ sys.stderr.write("No target script exists for '%s'\n" % wrapper_script_path)
+ sys.exit(1)
EOF
if [[ "$?" != "0" ]]; then
die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1200,15 +1249,6 @@ EOF
fi
cat << EOF >> "${file}"
-wrapper_script_path = os.path.realpath(sys.argv[0])
-target_executable_path = "%s-%s" % (wrapper_script_path, PYTHON_ABI)
-os.environ["GENTOO_PYTHON_PROCESS_NAME"] = os.path.basename(sys.argv[0])
-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)
-
target_executable = open(target_executable_path, "rb")
target_executable_first_line = target_executable.readline()
if not isinstance(target_executable_first_line, str):
@@ -1218,7 +1258,7 @@ if not isinstance(target_executable_first_line, str):
python_shebang_matched = python_shebang_re.match(target_executable_first_line)
target_executable.close()
-if python_shebang_matched:
+if python_shebang_matched is not None:
try:
python_interpreter_path = "${EPREFIX}/usr/bin/%s" % EPYTHON
os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"] = "1"
@@ -1235,13 +1275,27 @@ if python_shebang_matched:
if not python_verification_output_re.match(python_verification_output):
raise ValueError
- os.execv(python_interpreter_path, [python_interpreter_path] + sys.argv)
+ if cpython_re.match(EPYTHON) is not None:
+ os.environ["GENTOO_PYTHON_PROCESS_NAME"] = os.path.basename(sys.argv[0])
+ os.environ["GENTOO_PYTHON_WRAPPER_SCRIPT_PATH"] = sys.argv[0]
+ os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH"] = target_executable_path
+
+ if hasattr(os, "execv"):
+ os.execv(python_interpreter_path, [python_interpreter_path] + sys.argv)
+ else:
+ sys.exit(subprocess.Popen([python_interpreter_path] + sys.argv).wait())
+ except (KeyboardInterrupt, SystemExit):
+ raise
except:
pass
- if "GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION" in os.environ:
- del os.environ["GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"]
+ for variable in ("GENTOO_PYTHON_PROCESS_NAME", "GENTOO_PYTHON_WRAPPER_SCRIPT_PATH", "GENTOO_PYTHON_TARGET_SCRIPT_PATH", "GENTOO_PYTHON_TARGET_SCRIPT_PATH_VERIFICATION"):
+ if variable in os.environ:
+ del os.environ[variable]
-os.execv(target_executable_path, sys.argv)
+if hasattr(os, "execv"):
+ os.execv(target_executable_path, sys.argv)
+else:
+ sys.exit(subprocess.Popen([target_executable_path] + sys.argv[1:]).wait())
EOF
if [[ "$?" != "0" ]]; then
die "${FUNCNAME}(): Generation of '$1' failed"
@@ -1250,6 +1304,184 @@ EOF
done
}
+# @ECLASS-VARIABLE: PYTHON_VERSIONED_SCRIPTS
+# @DESCRIPTION:
+# Array of regular expressions of paths to versioned Python scripts.
+# Python scripts in /usr/bin and /usr/sbin are versioned by default.
+
+# @ECLASS-VARIABLE: PYTHON_VERSIONED_EXECUTABLES
+# @DESCRIPTION:
+# Array of regular expressions of paths to versioned executables (including Python scripts).
+
+# @ECLASS-VARIABLE: PYTHON_NONVERSIONED_EXECUTABLES
+# @DESCRIPTION:
+# Array of regular expressions of paths to nonversioned executables (including Python scripts).
+
+# @FUNCTION: python_merge_intermediate_installation_images
+# @USAGE: [-q|--quiet] [--] <intermediate_installation_images_directory>
+# @DESCRIPTION:
+# Merge intermediate installation images into installation image.
+python_merge_intermediate_installation_images() {
+ _python_check_python_pkg_setup_execution
+ _python_initialize_prefix_variables
+
+ local b file files=() intermediate_installation_images_directory PYTHON_ABI quiet="0" regex shebang version_executable wrapper_scripts=() wrapper_scripts_set=()
+
+ # 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"
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ die "${FUNCNAME}(): Unrecognized option '$1'"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
+ if [[ "$#" -ne 1 ]]; then
+ die "${FUNCNAME}() requires 1 argument"
+ fi
+
+ intermediate_installation_images_directory="$1"
+
+ if [[ ! -d "${intermediate_installation_images_directory}" ]]; then
+ die "${FUNCNAME}(): Intermediate installation images directory '${intermediate_installation_images_directory}' does not exist"
+ fi
+
+ _python_calculate_PYTHON_ABIS
+ if [[ "$(PYTHON -f --ABI)" == 3.* ]]; then
+ b="b"
+ fi
+
+ while read -d $'\0' -r file; do
+ files+=("${file}")
+ done < <("$(PYTHON -f)" -c \
+"import os
+import sys
+
+if hasattr(sys.stdout, 'buffer'):
+ # Python 3
+ stdout = sys.stdout.buffer
+else:
+ # Python 2
+ stdout = sys.stdout
+
+files_set = set()
+
+os.chdir(${b}'${intermediate_installation_images_directory}')
+
+for PYTHON_ABI in ${b}'${PYTHON_ABIS}'.split():
+ for root, dirs, files in os.walk(PYTHON_ABI + ${b}'${EPREFIX}'):
+ root = root[len(PYTHON_ABI + ${b}'${EPREFIX}')+1:]
+ files_set.update(root + ${b}'/' + file for file in files)
+
+for file in sorted(files_set):
+ stdout.write(file)
+ stdout.write(${b}'\x00')" || die "${FUNCNAME}(): Failure of extraction of files in intermediate installation images")
+
+ for PYTHON_ABI in ${PYTHON_ABIS}; do
+ if [[ ! -d "${intermediate_installation_images_directory}/${PYTHON_ABI}" ]]; then
+ die "${FUNCNAME}(): Intermediate installation image for Python ABI '${PYTHON_ABI}' does not exist"
+ fi
+
+ pushd "${intermediate_installation_images_directory}/${PYTHON_ABI}${EPREFIX}" > /dev/null || die "pushd failed"
+
+ for file in "${files[@]}"; do
+ version_executable="0"
+ for regex in "/usr/bin/.*" "/usr/sbin/.*" "${PYTHON_VERSIONED_SCRIPTS[@]}"; do
+ if [[ "/${file}" =~ ^${regex}$ ]]; then
+ version_executable="1"
+ break
+ fi
+ done
+ for regex in "${PYTHON_VERSIONED_EXECUTABLES[@]}"; do
+ if [[ "/${file}" =~ ^${regex}$ ]]; then
+ version_executable="2"
+ break
+ fi
+ done
+ if [[ "${version_executable}" != "0" ]]; then
+ for regex in "${PYTHON_NONVERSIONED_EXECUTABLES[@]}"; do
+ if [[ "/${file}" =~ ^${regex}$ ]]; then
+ version_executable="0"
+ break
+ fi
+ done
+ fi
+
+ [[ "${version_executable}" == "0" || ! -x "${file}" ]] && continue
+
+ shebang="$(head -n1 "${file}")" || die "Extraction of shebang from '${file}' failed"
+
+ if [[ "${version_executable}" == "2" ]]; then
+ wrapper_scripts+=("${ED}${file}")
+ elif [[ "${version_executable}" == "1" ]]; then
+ if [[ "${shebang}" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX}([[:digit:]]+(\.[[:digit:]]+)?)?($|[[:space:]]+) ]]; then
+ wrapper_scripts+=("${ED}${file}")
+ else
+ version_executable="0"
+ fi
+ fi
+
+ [[ "${version_executable}" == "0" ]] && continue
+
+ if [[ -e "${file}-${PYTHON_ABI}" ]]; then
+ die "${FUNCNAME}(): '${EPREFIX}/${file}-${PYTHON_ABI}' already exists"
+ fi
+
+ mv "${file}" "${file}-${PYTHON_ABI}" || die "Renaming of '${file}' failed"
+
+ if [[ "${shebang}" =~ ${_PYTHON_SHEBANG_BASE_PART_REGEX}[[:digit:]]*($|[[:space:]]+) ]]; then
+ python_convert_shebangs $([[ "${quiet}" == "1" ]] && echo --quiet) "${PYTHON_ABI}" "${file}-${PYTHON_ABI}"
+ fi
+ done
+
+ popd > /dev/null || die "popd failed"
+
+ cp -fr --preserve=all "${intermediate_installation_images_directory}/${PYTHON_ABI}/"* "${ED}" || die "Merging of intermediate installation image for Python ABI '${PYTHON_ABI} into installation image failed"
+ done
+
+ if [[ "${#wrapper_scripts[@]}" -ge 1 ]]; then
+ rm -f "${T}/python_wrapper_scripts"
+
+ for file in "${wrapper_scripts[@]}"; do
+ echo -n "${file}" >> "${T}/python_wrapper_scripts"
+ echo -en "\x00" >> "${T}/python_wrapper_scripts"
+ done
+
+ while read -d $'\0' -r file; do
+ wrapper_scripts_set+=("${file}")
+ done < <("$(PYTHON -f)" -c \
+"import sys
+
+if hasattr(sys.stdout, 'buffer'):
+ # Python 3
+ stdout = sys.stdout.buffer
+else:
+ # Python 2
+ stdout = sys.stdout
+
+files = set(open('${T}/python_wrapper_scripts', 'rb').read().rstrip(${b}'\x00').split(${b}'\x00'))
+
+for file in sorted(files):
+ stdout.write(file)
+ stdout.write(${b}'\x00')" || die "${FUNCNAME}(): Failure of extraction of set of wrapper scripts")
+
+ python_generate_wrapper_scripts $([[ "${quiet}" == "1" ]] && echo --quiet) "${wrapper_scripts_set[@]}"
+ fi
+}
+
# ================================================================================================
# ========= FUNCTIONS FOR PACKAGES NOT SUPPORTING INSTALLATION FOR MULTIPLE PYTHON ABIS ==========
# ================================================================================================
@@ -1257,9 +1489,12 @@ EOF
unset EPYTHON PYTHON_ABI
# @FUNCTION: python_set_active_version
-# @USAGE: <CPython_ABI|2|3>
+# @USAGE: <Python_ABI|2|3>
# @DESCRIPTION:
-# Set specified version of CPython as active version of Python.
+# Set locally active version of Python.
+# If Python_ABI argument is specified, then version of Python corresponding to Python_ABI is used.
+# If 2 argument is specified, then active version of CPython 2 is used.
+# If 3 argument is specified, then active version of CPython 3 is used.
#
# This function can be used only in pkg_setup() phase.
python_set_active_version() {
@@ -1277,9 +1512,12 @@ python_set_active_version() {
_python_initial_sanity_checks
if [[ -z "${PYTHON_ABI}" ]]; then
- if [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+$ ]]; then
- if ! _python_implementation && ! has_version "dev-lang/python:$1"; then
- die "${FUNCNAME}(): 'dev-lang/python:$1' is not installed"
+ if [[ -n "$(_python_get_implementation --ignore-invalid "$1")" ]]; then
+ # PYTHON_ABI variable is intended to be used only in ebuilds/eclasses,
+ # so it does not need to be exported to subprocesses.
+ PYTHON_ABI="$1"
+ if ! _python_implementation && ! has_version "$(python_get_implementational_package)"; then
+ die "${FUNCNAME}(): '$(python_get_implementational_package)' is not installed"
fi
export EPYTHON="$(PYTHON "$1")"
elif [[ "$1" == "2" ]]; then
@@ -1287,19 +1525,18 @@ python_set_active_version() {
die "${FUNCNAME}(): '=dev-lang/python-2*' is not installed"
fi
export EPYTHON="$(PYTHON -2)"
+ PYTHON_ABI="${EPYTHON#python}"
+ PYTHON_ABI="${PYTHON_ABI%%-*}"
elif [[ "$1" == "3" ]]; then
if ! _python_implementation && ! has_version "=dev-lang/python-3*"; then
die "${FUNCNAME}(): '=dev-lang/python-3*' is not installed"
fi
export EPYTHON="$(PYTHON -3)"
+ PYTHON_ABI="${EPYTHON#python}"
+ PYTHON_ABI="${PYTHON_ABI%%-*}"
else
die "${FUNCNAME}(): Unrecognized argument '$1'"
fi
-
- # PYTHON_ABI variable is intended to be used only in ebuilds/eclasses,
- # so it does not need to be exported to subprocesses.
- PYTHON_ABI="${EPYTHON#python}"
- PYTHON_ABI="${PYTHON_ABI%%-*}"
fi
_python_final_sanity_checks
@@ -1336,6 +1573,27 @@ if platform.system()[:4] == "Java":
sys.stdout.write("-jython")'
_python_get_implementation() {
+ local ignore_invalid="0"
+
+ while (($#)); do
+ case "$1" in
+ --ignore-invalid)
+ ignore_invalid="1"
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -*)
+ die "${FUNCNAME}(): Unrecognized option '$1'"
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+ done
+
if [[ "$#" -ne 1 ]]; then
die "${FUNCNAME}() requires 1 argument"
fi
@@ -1345,7 +1603,9 @@ _python_get_implementation() {
elif [[ "$1" =~ ^[[:digit:]]+\.[[:digit:]]+-jython$ ]]; then
echo "Jython"
else
- die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+ if [[ "${ignore_invalid}" == "0" ]]; then
+ die "${FUNCNAME}(): Unrecognized Python ABI '$1'"
+ fi
fi
}
@@ -1354,8 +1614,8 @@ _python_get_implementation() {
# @DESCRIPTION:
# Print filename of Python interpreter for specified Python ABI. If Python_ABI argument
# is ommitted, then PYTHON_ABI environment variable must be set and is used.
-# If -2 option is specified, then active version of Python 2 is used.
-# If -3 option is specified, then active version of Python 3 is used.
+# If -2 option is specified, then active version of CPython 2 is used.
+# If -3 option is specified, then active version of CPython 3 is used.
# If --final-ABI option is specified, then final ABI from the list of enabled ABIs is used.
# -2, -3 and --final-ABI options and Python_ABI argument cannot be specified simultaneously.
# If --ABI option is specified, then only specified Python ABI is printed instead of
@@ -1416,14 +1676,14 @@ PYTHON() {
elif [[ "${python2}" == "1" ]]; then
PYTHON_ABI="$(eselect python show --python2 --ABI)"
if [[ -z "${PYTHON_ABI}" ]]; then
- die "${FUNCNAME}(): Active version of Python 2 not set"
+ die "${FUNCNAME}(): Active version of CPython 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 version of Python 3 not set"
+ die "${FUNCNAME}(): Active version of CPython 3 not set"
elif [[ "${PYTHON_ABI}" != "3."* ]]; then
die "${FUNCNAME}(): Internal error in \`eselect python show --python3\`"
fi
@@ -1459,7 +1719,7 @@ PYTHON() {
if [[ "$(_python_get_implementation "${PYTHON_ABI}")" == "CPython" ]]; then
python_interpreter="python${PYTHON_ABI}"
elif [[ "$(_python_get_implementation "${PYTHON_ABI}")" == "Jython" ]]; then
- python_interpreter="jython-${PYTHON_ABI%-jython}"
+ python_interpreter="jython${PYTHON_ABI%-jython}"
fi
if [[ "${absolute_path_output}" == "1" ]]; then
@@ -2176,7 +2436,7 @@ _python_clean_compiled_modules() {
base_module_name="${base_module_name%\$py.class}"
py_file="${compiled_file%__pycache__/*}${base_module_name}.py"
else
- py_file="${compiled_file%\$py.class}"
+ py_file="${compiled_file%\$py.class}.py"
fi
if [[ "${EBUILD_PHASE}" == "postinst" ]]; then
[[ -f "${py_file}" && "${compiled_file}" -nt "${py_file}" ]] && continue