From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from pigeon.gentoo.org ([208.92.234.80] helo=lists.gentoo.org) by finch.gentoo.org with esmtp (Exim 4.60) (envelope-from ) id 1NM192-00062T-4O for garchives@archives.gentoo.org; Sat, 19 Dec 2009 15:23:00 +0000 Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 4D05EE0592; Sat, 19 Dec 2009 15:22:21 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) by pigeon.gentoo.org (Postfix) with ESMTP id F0BEBE0592 for ; Sat, 19 Dec 2009 15:22:20 +0000 (UTC) Received: from afta-gentoo.localnet (ip-85-198-235-97.broker.com.pl [85.198.235.97]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTP id B1CA0641BD for ; Sat, 19 Dec 2009 15:22:19 +0000 (UTC) From: Arfrever Frehtes Taifersar Arahesis To: Gentoo Development Subject: [gentoo-dev] Versioning of Python scripts Date: Sat, 19 Dec 2009 16:24:49 +0100 User-Agent: KMail/1.12.4 (Linux/2.6.32-tuxonice-AFTA; KDE/4.3.4; x86_64; ; ) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-dev@lists.gentoo.org Reply-to: gentoo-dev@lists.gentoo.org MIME-Version: 1.0 Content-Type: multipart/signed; boundary="nextPart5762234.gMKvNcgVUZ"; protocol="application/pgp-signature"; micalg=pgp-sha1 Content-Transfer-Encoding: 7bit Message-Id: <200912191624.55244.Arfrever@gentoo.org> X-Archives-Salt: 879caba9-3db5-4669-9a4c-f70e5cb50891 X-Archives-Hash: 0eb0a982108b8c108980c4c7eb6facbf --nextPart5762234.gMKvNcgVUZ Content-Type: multipart/mixed; boundary="Boundary-01=_BBPLLtZgIFKkp+P" Content-Transfer-Encoding: 7bit --Boundary-01=_BBPLLtZgIFKkp+P Content-Type: Text/Plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Distutils/Setuptools/Distribute modify shebangs of installed Python scripts= , so that they contain path of Python interpreter with version included (e.g. "#!/usr/bin/= python3.2"). This behavior has both advantage and disadvantages: - Scripts of packages supporting only e.g. Python 2 can be executed (with= out necessity of using of e.g. "python2 /usr/bin/${script}") after activating of e.g.= Python 3. - Scripts of packages supporting multiple Python versions ignore active P= ython version. - Scripts of packages supporting multiple Python versions cannot be easil= y (without necessity of using of e.g. "python3.1 /usr/bin/${script}") executed wit= h a Python version different than active Python version. The best solution, which removes these 2 disadvantages and preserves the ad= vantage, seems to be to rename Python scripts to include Python version [1] in filenames, = and create wrapper scripts, which call appropriate target scripts [2]. Some files sometimes tr= y to execute e.g. "/usr/bin/python /usr/bin/${script}", so wrapper scripts must be imple= mented in Python. Wrapper scripts try to execute "${wrapper_script}-${PYTHON_ABI}" files (e.g= =2E "py.test" will execute "py.test-3.1", when Python 3.1 is set as active Python version). distutils.eclass will automatically rename some scripts [3] in "${D}usr/bin= " and call the function, which generates wrapper scripts. In case somebody is interest= ed in reading of source code of python_generate_wrapper_scripts() function and potential sug= gesting of improvements, I'm attaching this function and 2 example wrapper scripts. I'= m planning to commit addition of this function in next week. [1] Actually Python ABI. [2] Wrapper scripts can also be created for ELF target files (e.g. "mpipyth= on"). [3] Only scripts of packages supporting installation for multiple Python ve= rsions will be renamed. Scripts, whose filenames end in [[:digit:]]+\.[[:digit:]]+, wo= n't be renamed. =2D-=20 Arfrever Frehtes Taifersar Arahesis --Boundary-01=_BBPLLtZgIFKkp+P Content-Type: text/plain; charset="UTF-8"; name="python_generate_wrapper_scripts.function" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="python_generate_wrapper_scripts.function" # @FUNCTION: python_generate_wrapper_scripts # @USAGE: [-E|--respect-EPYTHON] [-f|--force] [-q|--quiet] [--] [files] # @DESCRIPTION: # Generate wrapper scripts. Existing files are overwritten only with --force option. # If --respect-EPYTHON option is specified, then generated wrapper scripts will # respect EPYTHON variable at run time. python_generate_wrapper_scripts() { local eselect_python_option file force="0" quiet="0" PYTHON_ABI python2_enabled="0" python2_supported_versions python3_enabled="0" python3_supported_versions respect_EPYTHON="0" python2_supported_versions="2.4 2.5 2.6 2.7" python3_supported_versions="3.0 3.1 3.2" while (($#)); do case "$1" in -E|--respect-EPYTHON) respect_EPYTHON="1" ;; -f|--force) force="1" ;; -q|--quiet) quiet="1" ;; --) break ;; -*) die "${FUNCNAME}(): Unrecognized option '$1'" ;; *) break ;; esac shift done validate_PYTHON_ABIS for PYTHON_ABI in ${python2_supported_versions}; do if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then python2_enabled="1" fi done for PYTHON_ABI in ${python3_supported_versions}; do if has "${PYTHON_ABI}" ${PYTHON_ABIS}; then python3_enabled="1" fi done if [[ "${python2_enabled}" == "1" && "${python3_enabled}" == "1" ]]; then eselect_python_option= elif [[ "${python2_enabled}" == "1" && "${python3_enabled}" == "0" ]]; then eselect_python_option="--python2" elif [[ "${python2_enabled}" == "0" && "${python3_enabled}" == "1" ]]; then eselect_python_option="--python3" else die "${FUNCNAME}(): Unsupported environment" fi for file in "$@"; do if [[ -f "${file}" && "${force}" == "0" ]]; then die "${FUNCNAME}(): '$1' already exists" fi if [[ "${quiet}" == "0" ]]; then einfo "Generating '${file#${D%/}}' wrapper script" fi cat << EOF > "${file}" #!/usr/bin/env python # Gentoo '${file##*/}' wrapper script import os import re import subprocess import sys EPYTHON_re = re.compile(r"^python(\d+\.\d+)$") EOF if [[ "$?" != "0" ]]; then die "${FUNCNAME}(): Generation of '$1' failed" fi if [[ "${respect_EPYTHON}" == "1" ]]; then 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: sys.stderr.write("EPYTHON variable has unrecognized value '%s'\n" % EPYTHON) sys.exit(1) else: try: eselect_process = subprocess.Popen(["/usr/bin/eselect", "python", "show"${eselect_python_option:+, $(echo "\"")}${eselect_python_option}${eselect_python_option:+$(echo "\"")}], stdout=subprocess.PIPE) if eselect_process.wait() != 0: raise ValueError 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): # Python 3 eselect_output = eselect_output.decode() EPYTHON_matched = EPYTHON_re.match(eselect_output) 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.exit(1) EOF if [[ "$?" != "0" ]]; then die "${FUNCNAME}(): Generation of '$1' failed" fi else cat << EOF >> "${file}" try: eselect_process = subprocess.Popen(["/usr/bin/eselect", "python", "show"${eselect_python_option:+, $(echo "\"")}${eselect_python_option}${eselect_python_option:+$(echo "\"")}], stdout=subprocess.PIPE) if eselect_process.wait() != 0: raise ValueError 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): # Python 3 eselect_output = eselect_output.decode() EPYTHON_matched = EPYTHON_re.match(eselect_output) 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.exit(1) EOF if [[ "$?" != "0" ]]; then die "${FUNCNAME}(): Generation of '$1' failed" fi fi cat << EOF >> "${file}" target_executable = "%s-%s" % (sys.argv[0], PYTHON_ABI) if not os.path.exists(target_executable): sys.stderr.write("'%s' does not exist\n" % target_executable) sys.exit(1) os.execv(target_executable, sys.argv) EOF if [[ "$?" != "0" ]]; then die "${FUNCNAME}(): Generation of '$1' failed" fi fperms +x "${file#${D%/}}" || die "fperms '${file}' failed" done } --Boundary-01=_BBPLLtZgIFKkp+P Content-Type: text/x-python; charset="UTF-8"; name="sphinx-build" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="sphinx-build" #!/usr/bin/env python # Gentoo 'sphinx-build' wrapper script import os import re import subprocess import sys EPYTHON_re = re.compile(r"^python(\d+\.\d+)$") try: eselect_process = subprocess.Popen(["/usr/bin/eselect", "python", "show", "--python2"], stdout=subprocess.PIPE) if eselect_process.wait() != 0: raise ValueError except (OSError, ValueError): sys.stderr.write("Execution of 'eselect python show --python2' failed\n") sys.exit(1) eselect_output = eselect_process.stdout.read() if not isinstance(eselect_output, str): # Python 3 eselect_output = eselect_output.decode() EPYTHON_matched = EPYTHON_re.match(eselect_output) if EPYTHON_matched: PYTHON_ABI = EPYTHON_matched.group(1) else: sys.stderr.write("'eselect python show --python2' printed unrecognized value '%s" % eselect_output) sys.exit(1) target_executable = "%s-%s" % (sys.argv[0], PYTHON_ABI) if not os.path.exists(target_executable): sys.stderr.write("'%s' does not exist\n" % target_executable) sys.exit(1) os.execv(target_executable, sys.argv) --Boundary-01=_BBPLLtZgIFKkp+P Content-Type: text/x-python; charset="UTF-8"; name="py.test" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="py.test" #!/usr/bin/env python # Gentoo 'py.test' wrapper script import os import re import subprocess import sys EPYTHON_re = re.compile(r"^python(\d+\.\d+)$") EPYTHON = os.environ.get("EPYTHON") if EPYTHON: EPYTHON_matched = EPYTHON_re.match(EPYTHON) if EPYTHON_matched: PYTHON_ABI = EPYTHON_matched.group(1) else: sys.stderr.write("EPYTHON variable has unrecognized value '%s'\n" % EPYTHON) sys.exit(1) else: try: eselect_process = subprocess.Popen(["/usr/bin/eselect", "python", "show"], stdout=subprocess.PIPE) if eselect_process.wait() != 0: raise ValueError except (OSError, ValueError): sys.stderr.write("Execution of 'eselect python show' failed\n") sys.exit(1) eselect_output = eselect_process.stdout.read() if not isinstance(eselect_output, str): # Python 3 eselect_output = eselect_output.decode() EPYTHON_matched = EPYTHON_re.match(eselect_output) if EPYTHON_matched: PYTHON_ABI = EPYTHON_matched.group(1) else: sys.stderr.write("'eselect python show' printed unrecognized value '%s" % eselect_output) sys.exit(1) target_executable = "%s-%s" % (sys.argv[0], PYTHON_ABI) if not os.path.exists(target_executable): sys.stderr.write("'%s' does not exist\n" % target_executable) sys.exit(1) os.execv(target_executable, sys.argv) --Boundary-01=_BBPLLtZgIFKkp+P-- --nextPart5762234.gMKvNcgVUZ Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.13 (GNU/Linux) iQIcBAABAgAGBQJLLPBHAAoJEFtpjAED8H0YwdUP/jnTbE1UxQG/WSbW+jXuLNyb Q3Ipn5H2XJrMywQPAdn4WbyOGTx8x9Q7oHYSocM3l1wGfcSEbpRW2f5CO24c7hdw xIv3ax3J4Hdr0c4YMuO2MBUA+maJVMTz2UxdPKeQYNxgoo0EtNYLw66dXxQjEGSe 0xy6PyaUJfKb6xdhhBNeAB5eR0Uc9F/sxWzv64UMDZMYcOUDeLl/YFZDYpUIMk+w S/NubSw6fKaQI4899VqYBry10TvZj2ag2uEtR3d601fKrSjW5Cydqkia3jzbIDW4 pTAjRATmvMG4Jyn0dVHdsfsLodCiYkhXCY/nJq1odG7peoXYyEczQdCWjY+2+996 HYZa/ILr41LRMiXNKu2OeWnT6jmVILtF8ZqidxVZzFvhaBVJaYV9rnqgMwquOUiQ +KWaWdO6cDLiVG9lgecRRYoUfHvFhZ1oSGb9Eg+QLvjhLbtEZ/KNRMoL3JTEV3Cs UNKhrBCuLMu262uKwOWxb6yyPd+KajhaPTXI+FrWowD2Oz1YSFVnnYMJQ06TgSn8 noUeXBwQJa80inZ4Re6xPNqkzV8sNyvlr9G2V9lo6FzmS9KRz4T/TdKXnU3JbYh7 G27n6PsCleQRQWlAiPp3Xn9J2+sItZm/ZWlMbVATtb8PHpKK8EmfyNCuxWqACoR4 3yRvOtFLb0umOV+XBZNm =eO7b -----END PGP SIGNATURE----- --nextPart5762234.gMKvNcgVUZ--