1 |
It serves both as public shebang fixing function and replacement of |
2 |
_python_rewrite_shebang internal function. For the sake of having common |
3 |
code and consistent behavior. |
4 |
|
5 |
Notes on the 'new' function: |
6 |
|
7 |
1. takes a list of files and/or directories to fix. Directories are |
8 |
processed recursively, |
9 |
|
10 |
2. files, depending on the shebang: |
11 |
|
12 |
a) with shebang matching $EPYTHON (e.g. already having pythonX.Y) are |
13 |
skipped silently (but see 3), |
14 |
|
15 |
b) with shebang 'compatible' with $EPYTHON (e.g. python3 -> python3.2, |
16 |
but not python2 -> python3.2) are mangled verbosely, |
17 |
|
18 |
c) with shebang 'incompatible' with $EPYTHON (e.g. python3 -> python2.7, |
19 |
python3.2 -> python3.3) raise a fatal error, |
20 |
|
21 |
d) with shebang not looking like Python at all are skipped when |
22 |
processing directory recursively and raise a fatal error when are |
23 |
specified directly. |
24 |
|
25 |
3. there are two new QA warnings: |
26 |
|
27 |
a) when specified file (or all files in the directory) has proper |
28 |
shebang already -- likely attempting double mangling, |
29 |
|
30 |
b) when specified directory contains no Python files. |
31 |
--- |
32 |
eclass/python-r1.eclass | 6 +- |
33 |
eclass/python-single-r1.eclass | 44 ----------- |
34 |
eclass/python-utils-r1.eclass | 170 +++++++++++++++++++++++------------------ |
35 |
3 files changed, 100 insertions(+), 120 deletions(-) |
36 |
|
37 |
diff --git a/eclass/python-r1.eclass b/eclass/python-r1.eclass |
38 |
index 0fb188d..876ce7e 100644 |
39 |
--- a/eclass/python-r1.eclass |
40 |
+++ b/eclass/python-r1.eclass |
41 |
@@ -783,6 +783,8 @@ python_replicate_script() { |
42 |
debug-print-function ${FUNCNAME} "${@}" |
43 |
|
44 |
_python_replicate_script() { |
45 |
+ local _PYTHON_FIX_SHEBANG_QUIET=1 |
46 |
+ |
47 |
if _python_want_python_exec2; then |
48 |
local PYTHON_SCRIPTDIR |
49 |
python_export PYTHON_SCRIPTDIR |
50 |
@@ -792,7 +794,7 @@ python_replicate_script() { |
51 |
doexe "${files[@]}" |
52 |
) |
53 |
|
54 |
- _python_rewrite_shebang "${EPYTHON}" \ |
55 |
+ python_fix_shebang \ |
56 |
"${files[@]/*\//${D%/}/${PYTHON_SCRIPTDIR}/}" |
57 |
else |
58 |
local f |
59 |
@@ -800,7 +802,7 @@ python_replicate_script() { |
60 |
cp -p "${f}" "${f}-${EPYTHON}" || die |
61 |
done |
62 |
|
63 |
- _python_rewrite_shebang "${EPYTHON}" \ |
64 |
+ python_fix_shebang \ |
65 |
"${files[@]/%/-${EPYTHON}}" |
66 |
fi |
67 |
} |
68 |
diff --git a/eclass/python-single-r1.eclass b/eclass/python-single-r1.eclass |
69 |
index 7ce57c6..2a3a3fc 100644 |
70 |
--- a/eclass/python-single-r1.eclass |
71 |
+++ b/eclass/python-single-r1.eclass |
72 |
@@ -261,49 +261,5 @@ python-single-r1_pkg_setup() { |
73 |
python_setup |
74 |
} |
75 |
|
76 |
-# @FUNCTION: python_fix_shebang |
77 |
-# @USAGE: <path>... |
78 |
-# @DESCRIPTION: |
79 |
-# Replace the shebang in Python scripts with the current Python |
80 |
-# implementation (EPYTHON). If a directory is passed, works recursively |
81 |
-# on all Python scripts. |
82 |
-# |
83 |
-# Only files having a 'python' shebang will be modified; other files |
84 |
-# will be skipped. If a script has a complete shebang matching |
85 |
-# the chosen interpreter version, it is left unmodified. If a script has |
86 |
-# a complete shebang matching other version, the command dies. |
87 |
-python_fix_shebang() { |
88 |
- debug-print-function ${FUNCNAME} "${@}" |
89 |
- |
90 |
- [[ ${1} ]] || die "${FUNCNAME}: no paths given" |
91 |
- [[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)" |
92 |
- |
93 |
- local path f |
94 |
- for path; do |
95 |
- while IFS= read -r -d '' f; do |
96 |
- local shebang=$(head -n 1 "${f}") |
97 |
- |
98 |
- case "${shebang}" in |
99 |
- '#!'*${EPYTHON}*) |
100 |
- debug-print "${FUNCNAME}: in file ${f#${D}}" |
101 |
- debug-print "${FUNCNAME}: shebang matches EPYTHON: ${shebang}" |
102 |
- ;; |
103 |
- '#!'*python[23].[0123456789]*|'#!'*pypy-c*|'#!'*jython*) |
104 |
- debug-print "${FUNCNAME}: in file ${f#${D}}" |
105 |
- debug-print "${FUNCNAME}: incorrect specific shebang: ${shebang}" |
106 |
- |
107 |
- die "${f#${D}} has a specific Python shebang not matching EPYTHON" |
108 |
- ;; |
109 |
- '#!'*python*) |
110 |
- debug-print "${FUNCNAME}: in file ${f#${D}}" |
111 |
- debug-print "${FUNCNAME}: rewriting shebang: ${shebang}" |
112 |
- |
113 |
- einfo "Fixing shebang in ${f#${D}}" |
114 |
- _python_rewrite_shebang "${f}" |
115 |
- esac |
116 |
- done < <(find "${path}" -type f -print0) |
117 |
- done |
118 |
-} |
119 |
- |
120 |
_PYTHON_SINGLE_R1=1 |
121 |
fi |
122 |
diff --git a/eclass/python-utils-r1.eclass b/eclass/python-utils-r1.eclass |
123 |
index 81d6691..e292760 100644 |
124 |
--- a/eclass/python-utils-r1.eclass |
125 |
+++ b/eclass/python-utils-r1.eclass |
126 |
@@ -478,79 +478,6 @@ python_get_scriptdir() { |
127 |
echo "${PYTHON_SCRIPTDIR}" |
128 |
} |
129 |
|
130 |
-# @FUNCTION: _python_rewrite_shebang |
131 |
-# @USAGE: [<EPYTHON>] <path>... |
132 |
-# @INTERNAL |
133 |
-# @DESCRIPTION: |
134 |
-# Replaces 'python' executable in the shebang with the executable name |
135 |
-# of the specified interpreter. If no EPYTHON value (implementation) is |
136 |
-# used, the current ${EPYTHON} will be used. |
137 |
-# |
138 |
-# All specified files must start with a 'python' shebang. A file not |
139 |
-# having a matching shebang will be refused. The exact shebang style |
140 |
-# will be preserved in order not to break anything. |
141 |
-# |
142 |
-# Example conversions: |
143 |
-# @CODE |
144 |
-# From: #!/usr/bin/python -R |
145 |
-# To: #!/usr/bin/python2.7 -R |
146 |
-# |
147 |
-# From: #!/usr/bin/env FOO=bar python |
148 |
-# To: #!/usr/bin/env FOO=bar python2.7 |
149 |
-# @CODE |
150 |
-_python_rewrite_shebang() { |
151 |
- debug-print-function ${FUNCNAME} "${@}" |
152 |
- |
153 |
- local impl |
154 |
- case "${1}" in |
155 |
- python*|jython*|pypy*) |
156 |
- impl=${1} |
157 |
- shift |
158 |
- ;; |
159 |
- *) |
160 |
- impl=${EPYTHON} |
161 |
- [[ ${impl} ]] || die "${FUNCNAME}: no impl nor EPYTHON" |
162 |
- ;; |
163 |
- esac |
164 |
- debug-print "${FUNCNAME}: implementation: ${impl}" |
165 |
- |
166 |
- local f |
167 |
- for f; do |
168 |
- local from shebang |
169 |
- read -r shebang < "${f}" |
170 |
- shebang=${shebang%$'\r'} |
171 |
- debug-print "${FUNCNAME}: path = ${f}" |
172 |
- debug-print "${FUNCNAME}: shebang = ${shebang}" |
173 |
- |
174 |
- if [[ "${shebang} " == *"${impl} "* ]]; then |
175 |
- # skip files with correct impl |
176 |
- continue |
177 |
- elif [[ "${shebang} " == *'python '* ]]; then |
178 |
- from=python |
179 |
- elif [[ "${shebang} " == *'python2 '* ]]; then |
180 |
- from=python2 |
181 |
- elif [[ "${shebang} " == *'python3 '* ]]; then |
182 |
- from=python3 |
183 |
- else |
184 |
- eerror "A file does not seem to have a supported shebang:" |
185 |
- eerror " file: ${f}" |
186 |
- eerror " shebang: ${shebang}" |
187 |
- die "${FUNCNAME}: ${f} does not seem to have a valid shebang" |
188 |
- fi |
189 |
- |
190 |
- if { [[ ${from} == python2 ]] && python_is_python3 "${impl}"; } \ |
191 |
- || { [[ ${from} == python3 ]] && ! python_is_python3 "${impl}"; } then |
192 |
- eerror "A file does have shebang not supporting requested impl:" |
193 |
- eerror " file: ${f}" |
194 |
- eerror " shebang: ${shebang}" |
195 |
- eerror " impl: ${impl}" |
196 |
- die "${FUNCNAME}: ${f} does have shebang not supporting ${EPYTHON}" |
197 |
- fi |
198 |
- |
199 |
- sed -i -e "1s:${from}:${impl}:" "${f}" || die |
200 |
- done |
201 |
-} |
202 |
- |
203 |
# @FUNCTION: _python_ln_rel |
204 |
# @USAGE: <from> <to> |
205 |
# @INTERNAL |
206 |
@@ -743,7 +670,8 @@ python_newexe() { |
207 |
|
208 |
# don't use this at home, just call python_doscript() instead |
209 |
if [[ ${_PYTHON_REWRITE_SHEBANG} ]]; then |
210 |
- _python_rewrite_shebang "${ED%/}/${d}/${newfn}" |
211 |
+ local _PYTHON_FIX_SHEBANG_QUIET=1 |
212 |
+ python_fix_shebang "${ED%/}/${d}/${newfn}" |
213 |
fi |
214 |
} |
215 |
|
216 |
@@ -1006,6 +934,100 @@ python_is_python3() { |
217 |
[[ ${impl} == python3* ]] |
218 |
} |
219 |
|
220 |
+# @FUNCTION: python_fix_shebang |
221 |
+# @USAGE: <path>... |
222 |
+# @DESCRIPTION: |
223 |
+# Replace the shebang in Python scripts with the current Python |
224 |
+# implementation (EPYTHON). If a directory is passed, works recursively |
225 |
+# on all Python scripts. |
226 |
+# |
227 |
+# Only files having a 'python*' shebang will be modified. Files with |
228 |
+# other shebang will either be skipped when working recursively |
229 |
+# on a directory or treated as error when specified explicitly. |
230 |
+# |
231 |
+# Shebangs matching explicitly current Python version will be left |
232 |
+# unmodified. Shebangs requesting another Python version will be treated |
233 |
+# as fatal error. |
234 |
+python_fix_shebang() { |
235 |
+ debug-print-function ${FUNCNAME} "${@}" |
236 |
+ |
237 |
+ [[ ${1} ]] || die "${FUNCNAME}: no paths given" |
238 |
+ [[ ${EPYTHON} ]] || die "${FUNCNAME}: EPYTHON unset (pkg_setup not called?)" |
239 |
+ |
240 |
+ local path f |
241 |
+ for path; do |
242 |
+ local any_correct any_fixed is_recursive |
243 |
+ |
244 |
+ [[ -d ${path} ]] && is_recursive=1 |
245 |
+ |
246 |
+ while IFS= read -r -d '' f; do |
247 |
+ local shebang=$(head -n 1 "${f}") |
248 |
+ local error |
249 |
+ |
250 |
+ case "${shebang} " in |
251 |
+ '#!'*"${EPYTHON} "*) |
252 |
+ debug-print "${FUNCNAME}: in file ${f#${D}}" |
253 |
+ debug-print "${FUNCNAME}: shebang matches EPYTHON: ${shebang}" |
254 |
+ |
255 |
+ # Nothing to do, move along. |
256 |
+ any_correct=1 |
257 |
+ ;; |
258 |
+ '#!'*python" "*|'#!'*python[23]" "*) |
259 |
+ debug-print "${FUNCNAME}: in file ${f#${D}}" |
260 |
+ debug-print "${FUNCNAME}: rewriting shebang: ${shebang}" |
261 |
+ |
262 |
+ # Note: for internal use. |
263 |
+ if [[ ! ${_PYTHON_FIX_SHEBANG_QUIET} ]]; then |
264 |
+ einfo "Fixing shebang in ${f#${D}}." |
265 |
+ fi |
266 |
+ |
267 |
+ local from |
268 |
+ if [[ "${shebang} " == *'python2 '* ]]; then |
269 |
+ from=python2 |
270 |
+ python_is_python3 "${EPYTHON}" && error=1 |
271 |
+ elif [[ "${shebang} " == *'python3 '* ]]; then |
272 |
+ from=python3 |
273 |
+ python_is_python3 "${EPYTHON}" || error=1 |
274 |
+ else |
275 |
+ from=python |
276 |
+ fi |
277 |
+ |
278 |
+ if [[ ! ${error} ]]; then |
279 |
+ sed -i -e "1s:${from}:${EPYTHON}:" "${f}" || die |
280 |
+ any_fixed=1 |
281 |
+ fi |
282 |
+ ;; |
283 |
+ '#!'*python[23].[0123456789]" "*|'#!'*pypy" "*|'#!'*jython[23].[0123456789]" "*) |
284 |
+ # Explicit mismatch. |
285 |
+ error=1 |
286 |
+ ;; |
287 |
+ *) |
288 |
+ # Non-Python shebang. Allowed in recursive mode, |
289 |
+ # disallowed when specifying file explicitly. |
290 |
+ [[ ${is_recursive} ]] || error=1 |
291 |
+ ;; |
292 |
+ esac |
293 |
+ |
294 |
+ if [[ ${error} ]]; then |
295 |
+ eerror "The file has incompatible shebang:" |
296 |
+ eerror " file: ${f#${D}}" |
297 |
+ eerror " current shebang: ${shebang}" |
298 |
+ eerror " requested impl: ${EPYTHON}" |
299 |
+ die "${FUNCNAME}: conversion of incompatible shebang requested" |
300 |
+ fi |
301 |
+ done < <(find "${path}" -type f -print0) |
302 |
+ |
303 |
+ if [[ ! ${any_fixed} ]]; then |
304 |
+ eqawarn "QA warning: ${FUNCNAME}, ${path#${D}} did not match any fixable files." |
305 |
+ if [[ ${any_correct} ]]; then |
306 |
+ eqawarn "All files have ${EPYTHON} shebang already." |
307 |
+ else |
308 |
+ eqawarn "There are no Python files in specified directory." |
309 |
+ fi |
310 |
+ fi |
311 |
+ done |
312 |
+} |
313 |
+ |
314 |
# @FUNCTION: _python_want_python_exec2 |
315 |
# @INTERNAL |
316 |
# @DESCRIPTION: |
317 |
-- |
318 |
1.9.3 |