summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichał Górny <mgorny@gentoo.org>2014-06-19 08:08:10 +0000
committerMichał Górny <mgorny@gentoo.org>2014-06-19 08:08:10 +0000
commit55350ac56cf2f9c9318584f53522be1a027c3dc8 (patch)
tree1a613eeec43c73928d34b76103108b66059fd550
parentFixed dependency to javacc wrt bug #513562 (diff)
downloadgentoo-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/ChangeLog7
-rw-r--r--eclass/python-r1.eclass6
-rw-r--r--eclass/python-utils-r1.eclass156
-rwxr-xr-xeclass/tests/python-utils-r1.sh71
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