diff options
author | Michał Górny <mgorny@gentoo.org> | 2014-06-19 08:08:10 +0000 |
---|---|---|
committer | Michał Górny <mgorny@gentoo.org> | 2014-06-19 08:08:10 +0000 |
commit | 55350ac56cf2f9c9318584f53522be1a027c3dc8 (patch) | |
tree | 1a613eeec43c73928d34b76103108b66059fd550 | |
parent | Fixed dependency to javacc wrt bug #513562 (diff) | |
download | gentoo-2-55350ac56cf2f9c9318584f53522be1a027c3dc8.tar.gz gentoo-2-55350ac56cf2f9c9318584f53522be1a027c3dc8.tar.bz2 gentoo-2-55350ac56cf2f9c9318584f53522be1a027c3dc8.zip |
Improve handling of corner cases in python_fix_shebang. Support --force and --quiet options, bug #505354. Add tests.
-rw-r--r-- | eclass/ChangeLog | 7 | ||||
-rw-r--r-- | eclass/python-r1.eclass | 6 | ||||
-rw-r--r-- | eclass/python-utils-r1.eclass | 156 | ||||
-rwxr-xr-x | eclass/tests/python-utils-r1.sh | 71 |
4 files changed, 182 insertions, 58 deletions
diff --git a/eclass/ChangeLog b/eclass/ChangeLog index 42d865c80ca2..3b662b0e4ed1 100644 --- a/eclass/ChangeLog +++ b/eclass/ChangeLog @@ -1,6 +1,11 @@ # ChangeLog for eclass directory # Copyright 1999-2014 Gentoo Foundation; Distributed under the GPL v2 -# $Header: /var/cvsroot/gentoo-x86/eclass/ChangeLog,v 1.1290 2014/06/14 18:33:59 kensington Exp $ +# $Header: /var/cvsroot/gentoo-x86/eclass/ChangeLog,v 1.1291 2014/06/19 08:08:10 mgorny Exp $ + + 19 Jun 2014; Michał Górny <mgorny@gentoo.org> python-r1.eclass, + python-utils-r1.eclass, tests/python-utils-r1.sh: + Improve handling of corner cases in python_fix_shebang. Support --force and + --quiet options, bug #505354. Add tests. 14 Jun 2014; Michael Palimaka <kensington@gentoo.org> kde4-base.eclass, kde4-functions.eclass: Sync with KDE overlay. Adapt to live ebuild versioning change. Remove diff --git a/eclass/python-r1.eclass b/eclass/python-r1.eclass index 8670ab6d4073..395c1a60322b 100644 --- a/eclass/python-r1.eclass +++ b/eclass/python-r1.eclass @@ -1,6 +1,6 @@ # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-x86/eclass/python-r1.eclass,v 1.73 2014/05/26 16:13:35 mgorny Exp $ +# $Header: /var/cvsroot/gentoo-x86/eclass/python-r1.eclass,v 1.74 2014/06/19 08:08:10 mgorny Exp $ # @ECLASS: python-r1 # @MAINTAINER: @@ -794,7 +794,7 @@ python_replicate_script() { doexe "${files[@]}" ) - python_fix_shebang \ + python_fix_shebang -q \ "${files[@]/*\//${D%/}/${PYTHON_SCRIPTDIR}/}" else local f @@ -802,7 +802,7 @@ python_replicate_script() { cp -p "${f}" "${f}-${EPYTHON}" || die done - python_fix_shebang \ + python_fix_shebang -q \ "${files[@]/%/-${EPYTHON}}" fi } diff --git a/eclass/python-utils-r1.eclass b/eclass/python-utils-r1.eclass index 6f7f8aea677b..89d6ed21ec52 100644 --- a/eclass/python-utils-r1.eclass +++ b/eclass/python-utils-r1.eclass @@ -1,6 +1,6 @@ # Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-x86/eclass/python-utils-r1.eclass,v 1.56 2014/05/26 16:13:35 mgorny Exp $ +# $Header: /var/cvsroot/gentoo-x86/eclass/python-utils-r1.eclass,v 1.57 2014/06/19 08:08:10 mgorny Exp $ # @ECLASS: python-utils-r1 # @MAINTAINER: @@ -670,8 +670,7 @@ python_newexe() { # don't use this at home, just call python_doscript() instead if [[ ${_PYTHON_REWRITE_SHEBANG} ]]; then - local _PYTHON_FIX_SHEBANG_QUIET=1 - python_fix_shebang "${ED%/}/${d}/${newfn}" + python_fix_shebang -q "${ED%/}/${d}/${newfn}" fi } @@ -935,7 +934,7 @@ python_is_python3() { } # @FUNCTION: python_fix_shebang -# @USAGE: <path>... +# @USAGE: [-f|--force] [-q|--quiet] <path>... # @DESCRIPTION: # Replace the shebang in Python scripts with the current Python # implementation (EPYTHON). If a directory is passed, works recursively @@ -947,13 +946,28 @@ python_is_python3() { # # Shebangs matching explicitly current Python version will be left # unmodified. Shebangs requesting another Python version will be treated -# as fatal error. +# as fatal error, unless --force is given. +# +# --force causes the function to replace even shebangs that require +# incompatible Python version. --quiet causes the function not to list +# modified files verbosely. python_fix_shebang() { debug-print-function ${FUNCNAME} "${@}" - [[ ${1} ]] || die "${FUNCNAME}: no paths given" [[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)" + local force quiet + while [[ ${@} ]]; do + case "${1}" in + -f|--force) force=1; shift;; + -q|--quiet) quiet=1; shift;; + --) shift; break;; + *) break;; + esac + done + + [[ ${1} ]] || die "${FUNCNAME}: no paths given" + local path f for path; do local any_correct any_fixed is_recursive @@ -961,54 +975,88 @@ python_fix_shebang() { [[ -d ${path} ]] && is_recursive=1 while IFS= read -r -d '' f; do - local shebang=$(head -n 1 "${f}") - local error - - case "${shebang} " in - '#!'*"${EPYTHON} "*) - debug-print "${FUNCNAME}: in file ${f#${D}}" - debug-print "${FUNCNAME}: shebang matches EPYTHON: ${shebang}" - - # Nothing to do, move along. - any_correct=1 - ;; - '#!'*python" "*|'#!'*python[23]" "*) - debug-print "${FUNCNAME}: in file ${f#${D}}" - debug-print "${FUNCNAME}: rewriting shebang: ${shebang}" - - # Note: for internal use. - if [[ ! ${_PYTHON_FIX_SHEBANG_QUIET} ]]; then - einfo "Fixing shebang in ${f#${D}}." - fi - - local from - if [[ "${shebang} " == *'python2 '* ]]; then - from=python2 - python_is_python3 "${EPYTHON}" && error=1 - elif [[ "${shebang} " == *'python3 '* ]]; then - from=python3 - python_is_python3 "${EPYTHON}" || error=1 - else - from=python - fi - - if [[ ! ${error} ]]; then - sed -i -e "1s:${from}:${EPYTHON}:" "${f}" || die - any_fixed=1 - fi - ;; - '#!'*python[23].[0123456789]" "*|'#!'*pypy" "*|'#!'*jython[23].[0123456789]" "*) - # Explicit mismatch. - error=1 - ;; - *) - # Non-Python shebang. Allowed in recursive mode, - # disallowed when specifying file explicitly. - [[ ${is_recursive} ]] || error=1 - ;; - esac - - if [[ ${error} ]]; then + local shebang i + local error from + + read shebang <"${f}" + + # First, check if it's shebang at all... + if [[ ${shebang} == '#!'* ]]; then + # Match left-to-right in a loop, to avoid matching random + # repetitions like 'python2.7 python2'. + for i in ${shebang}; do + case "${i}" in + *"${EPYTHON}") + debug-print "${FUNCNAME}: in file ${f#${D}}" + debug-print "${FUNCNAME}: shebang matches EPYTHON: ${shebang}" + + # Nothing to do, move along. + any_correct=1 + from=${EPYTHON} + break + ;; + *python|*python[23]) + debug-print "${FUNCNAME}: in file ${f#${D}}" + debug-print "${FUNCNAME}: rewriting shebang: ${shebang}" + + if [[ ${i} == *python2 ]]; then + from=python2 + if [[ ! ${force} ]]; then + python_is_python3 "${EPYTHON}" && error=1 + fi + elif [[ ${i} == *python3 ]]; then + from=python3 + if [[ ! ${force} ]]; then + python_is_python3 "${EPYTHON}" || error=1 + fi + else + from=python + fi + break + ;; + *python[23].[0123456789]|*pypy|*jython[23].[0123456789]) + # Explicit mismatch. + if [[ ! ${force} ]]; then + error=1 + else + case "${i}" in + *python[23].[0123456789]) + from="python[23].[0123456789]";; + *pypy) + from="pypy";; + *jython[23].[0123456789]) + from="jython[23].[0123456789]";; + *) + die "${FUNCNAME}: internal error in 2nd pattern match";; + esac + fi + break + ;; + esac + done + fi + + if [[ ! ${error} && ! ${from} ]]; then + # Non-Python shebang. Allowed in recursive mode, + # disallowed when specifying file explicitly. + [[ ${is_recursive} ]] && continue + error=1 + fi + + if [[ ! ${quiet} ]]; then + einfo "Fixing shebang in ${f#${D}}." + fi + + if [[ ! ${error} ]]; then + # We either want to match ${from} followed by space + # or at end-of-string. + if [[ ${shebang} == *${from}" "* ]]; then + sed -i -e "1s:${from} :${EPYTHON} :" "${f}" || die + else + sed -i -e "1s:${from}$:${EPYTHON}:" "${f}" || die + fi + any_fixed=1 + else eerror "The file has incompatible shebang:" eerror " file: ${f#${D}}" eerror " current shebang: ${shebang}" diff --git a/eclass/tests/python-utils-r1.sh b/eclass/tests/python-utils-r1.sh index ff98d83f2984..29a6e1f94911 100755 --- a/eclass/tests/python-utils-r1.sh +++ b/eclass/tests/python-utils-r1.sh @@ -30,6 +30,33 @@ test_is() { tend ${?} } +test_fix_shebang() { + local from=${1} + local to=${2} + local expect=${3} + local args=( "${@:4}" ) + + tbegin "python_fix_shebang${args[@]+ ${args[*]}} from ${from} to ${to} (exp: ${expect})" + + echo "${from}" > "${tmpfile}" + output=$( EPYTHON=${to} python_fix_shebang "${args[@]}" -q "${tmpfile}" 2>&1 ) + + if [[ ${?} != 0 ]]; then + if [[ ${expect} != FAIL ]]; then + echo "${output}" + tend 1 + else + tend 0 + fi + else + [[ $(<"${tmpfile}") == ${expect} ]] \ + || eerror "${from} -> ${to}: $(<"${tmpfile}") != ${expect}" + tend ${?} + fi +} + +tmpfile=$(mktemp) + inherit python-utils-r1 test_var EPYTHON python2_7 python2.7 @@ -66,4 +93,48 @@ test_is python_is_python3 python3.2 0 test_is python_is_python3 jython2.7 1 test_is python_is_python3 pypy 1 +# generic shebangs +test_fix_shebang '#!/usr/bin/python' python2.7 '#!/usr/bin/python2.7' +test_fix_shebang '#!/usr/bin/python' python3.4 '#!/usr/bin/python3.4' +test_fix_shebang '#!/usr/bin/python' pypy '#!/usr/bin/pypy' +test_fix_shebang '#!/usr/bin/python' jython2.7 '#!/usr/bin/jython2.7' + +# python2/python3 matching +test_fix_shebang '#!/usr/bin/python2' python2.7 '#!/usr/bin/python2.7' +test_fix_shebang '#!/usr/bin/python3' python2.7 FAIL +test_fix_shebang '#!/usr/bin/python3' python2.7 '#!/usr/bin/python2.7' --force +test_fix_shebang '#!/usr/bin/python3' python3.4 '#!/usr/bin/python3.4' +test_fix_shebang '#!/usr/bin/python2' python3.4 FAIL +test_fix_shebang '#!/usr/bin/python2' python3.4 '#!/usr/bin/python3.4' --force + +# pythonX.Y matching (those mostly test the patterns) +test_fix_shebang '#!/usr/bin/python2.7' python2.7 '#!/usr/bin/python2.7' +test_fix_shebang '#!/usr/bin/python2.7' python3.2 FAIL +test_fix_shebang '#!/usr/bin/python2.7' python3.2 '#!/usr/bin/python3.2' --force +test_fix_shebang '#!/usr/bin/python3.2' python3.2 '#!/usr/bin/python3.2' +test_fix_shebang '#!/usr/bin/python3.2' python2.7 FAIL +test_fix_shebang '#!/usr/bin/python3.2' python2.7 '#!/usr/bin/python2.7' --force +test_fix_shebang '#!/usr/bin/pypy' pypy '#!/usr/bin/pypy' +test_fix_shebang '#!/usr/bin/pypy' python2.7 FAIL +test_fix_shebang '#!/usr/bin/pypy' python2.7 '#!/usr/bin/python2.7' --force +test_fix_shebang '#!/usr/bin/jython2.7' jython2.7 '#!/usr/bin/jython2.7' +test_fix_shebang '#!/usr/bin/jython2.7' jython3.2 FAIL +test_fix_shebang '#!/usr/bin/jython2.7' jython3.2 '#!/usr/bin/jython3.2' --force + +# fancy path handling +test_fix_shebang '#!/mnt/python2/usr/bin/python' python3.4 \ + '#!/mnt/python2/usr/bin/python3.4' +test_fix_shebang '#!/mnt/python2/usr/bin/python2' python2.7 \ + '#!/mnt/python2/usr/bin/python2.7' +test_fix_shebang '#!/mnt/python2/usr/bin/env python' python2.7 \ + '#!/mnt/python2/usr/bin/env python2.7' +test_fix_shebang '#!/mnt/python2/usr/bin/python2 python2' python2.7 \ + '#!/mnt/python2/usr/bin/python2.7 python2' +test_fix_shebang '#!/mnt/python2/usr/bin/python3 python2' python2.7 FAIL +test_fix_shebang '#!/mnt/python2/usr/bin/python3 python2' python2.7 \ + '#!/mnt/python2/usr/bin/python2.7 python2' --force +test_fix_shebang '#!/usr/bin/foo' python2.7 FAIL + +rm "${tmpfile}" + texit |