Gentoo Archives: gentoo-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-dev@l.g.o
Cc: "Michał Górny" <mgorny@g.o>
Subject: [gentoo-dev] [PATCH 1/5] python*-r1.eclass: Commonize PYTHON_COMPAT processing, cache the result
Date: Thu, 17 Dec 2015 22:04:17
Message-Id: 1450389778-10144-2-git-send-email-mgorny@gentoo.org
In Reply to: [gentoo-dev] [PATCH 0/5] python*-r1: commonize PYTHON_COMPAT handling by "Michał Górny"
1 Introduce a common _python_set_impls function in python-utils-r1.eclass
2 that validates and processes PYTHON_COMPAT, then stores the result in
3 _PYTHON_SUPPORTED_IMPLS and _PYTHON_UNSUPPORTED_IMPLS variables. Reuse
4 those variables in all python-r1 suite eclasses, effectively reducing
5 code duplication and providing cache for repeated implementation support
6 checks.
7 ---
8 eclass/python-any-r1.eclass | 28 +++++--------------
9 eclass/python-r1.eclass | 47 ++++++++------------------------
10 eclass/python-single-r1.eclass | 61 ++++++++++++------------------------------
11 eclass/python-utils-r1.eclass | 49 +++++++++++++++++++++++++++++++++
12 4 files changed, 83 insertions(+), 102 deletions(-)
13
14 diff --git a/eclass/python-any-r1.eclass b/eclass/python-any-r1.eclass
15 index 721ba45..dbfeded 100644
16 --- a/eclass/python-any-r1.eclass
17 +++ b/eclass/python-any-r1.eclass
18 @@ -71,12 +71,6 @@ if [[ ! ${_PYTHON_ANY_R1} ]]; then
19 # @CODE
20 # PYTHON_COMPAT=( python{2_5,2_6,2_7} )
21 # @CODE
22 -if ! declare -p PYTHON_COMPAT &>/dev/null; then
23 - die 'PYTHON_COMPAT not declared.'
24 -fi
25 -if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then
26 - die 'PYTHON_COMPAT must be an array.'
27 -fi
28
29 # @ECLASS-VARIABLE: PYTHON_REQ_USE
30 # @DEFAULT_UNSET
31 @@ -119,16 +113,10 @@ _python_any_set_globals() {
32 local usestr i PYTHON_PKG_DEP
33 [[ ${PYTHON_REQ_USE} ]] && usestr="[${PYTHON_REQ_USE}]"
34
35 - # check for invalid PYTHON_COMPAT
36 - for i in "${PYTHON_COMPAT[@]}"; do
37 - # the function simply dies on invalid impl
38 - _python_impl_supported "${i}"
39 - done
40 + _python_set_impls
41
42 PYTHON_DEPS=
43 - for i in "${_PYTHON_ALL_IMPLS[@]}"; do
44 - has "${i}" "${PYTHON_COMPAT[@]}" || continue
45 -
46 + for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
47 python_export "${i}" PYTHON_PKG_DEP
48
49 PYTHON_DEPS="${PYTHON_PKG_DEP} ${PYTHON_DEPS}"
50 @@ -209,9 +197,7 @@ python_gen_any_dep() {
51 [[ ${depstr} ]] || die "No dependency string provided"
52
53 local PYTHON_PKG_DEP out=
54 - for i in "${_PYTHON_ALL_IMPLS[@]}"; do
55 - has "${i}" "${PYTHON_COMPAT[@]}" || continue
56 -
57 + for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
58 local PYTHON_USEDEP="python_targets_${i}(-),python_single_target_${i}(+)"
59 python_export "${i}" PYTHON_PKG_DEP
60
61 @@ -242,7 +228,7 @@ _python_EPYTHON_supported() {
62 ;;
63 esac
64
65 - if has "${i}" "${PYTHON_COMPAT[@]}"; then
66 + if has "${i}" "${_PYTHON_SUPPORTED_IMPLS[@]}"; then
67 if python_is_installed "${i}"; then
68 if declare -f python_check_deps >/dev/null; then
69 local PYTHON_USEDEP="python_targets_${i}(-),python_single_target_${i}(+)"
70 @@ -293,10 +279,8 @@ python_setup() {
71
72 # fallback to best installed impl.
73 local rev_impls=()
74 - for i in "${_PYTHON_ALL_IMPLS[@]}"; do
75 - if has "${i}" "${PYTHON_COMPAT[@]}"; then
76 - rev_impls=( "${i}" "${rev_impls[@]}" )
77 - fi
78 + for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
79 + rev_impls=( "${i}" "${rev_impls[@]}" )
80 done
81
82 for i in "${rev_impls[@]}"; do
83 diff --git a/eclass/python-r1.eclass b/eclass/python-r1.eclass
84 index fbc39dc..f7a8541 100644
85 --- a/eclass/python-r1.eclass
86 +++ b/eclass/python-r1.eclass
87 @@ -82,12 +82,6 @@ inherit multibuild python-utils-r1
88 # @CODE
89 # PYTHON_COMPAT=( python2_7 python3_{3,4} )
90 # @CODE
91 -if ! declare -p PYTHON_COMPAT &>/dev/null; then
92 - die 'PYTHON_COMPAT not declared.'
93 -fi
94 -if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then
95 - die 'PYTHON_COMPAT must be an array.'
96 -fi
97
98 # @ECLASS-VARIABLE: PYTHON_COMPAT_OVERRIDE
99 # @INTERNAL
100 @@ -186,24 +180,17 @@ fi
101 # @CODE
102
103 _python_set_globals() {
104 - local impls=()
105 -
106 PYTHON_DEPS=
107 local i PYTHON_PKG_DEP
108 - for i in "${PYTHON_COMPAT[@]}"; do
109 - _python_impl_supported "${i}" || continue
110
111 + _python_set_impls
112 +
113 + for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
114 python_export "${i}" PYTHON_PKG_DEP
115 PYTHON_DEPS+="python_targets_${i}? ( ${PYTHON_PKG_DEP} ) "
116 -
117 - impls+=( "${i}" )
118 done
119
120 - if [[ ${#impls[@]} -eq 0 ]]; then
121 - die "No supported implementation in PYTHON_COMPAT."
122 - fi
123 -
124 - local flags=( "${impls[@]/#/python_targets_}" )
125 + local flags=( "${_PYTHON_SUPPORTED_IMPLS[@]/#/python_targets_}" )
126 local optflags=${flags[@]/%/(-)?}
127
128 # A nice QA trick here. Since a python-single-r1 package has to have
129 @@ -212,7 +199,7 @@ _python_set_globals() {
130 # it should prevent developers from mistakenly depending on packages
131 # not supporting multiple Python implementations.
132
133 - local flags_st=( "${impls[@]/#/-python_single_target_}" )
134 + local flags_st=( "${_PYTHON_SUPPORTED_IMPLS[@]/#/-python_single_target_}" )
135 optflags+=,${flags_st[@]/%/(-)}
136
137 IUSE=${flags[*]}
138 @@ -246,9 +233,7 @@ _python_validate_useflags() {
139
140 local i
141
142 - for i in "${PYTHON_COMPAT[@]}"; do
143 - _python_impl_supported "${i}" || continue
144 -
145 + for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
146 use "python_targets_${i}" && return 0
147 done
148
149 @@ -290,9 +275,7 @@ python_gen_usedep() {
150 local impl pattern
151 local matches=()
152
153 - for impl in "${PYTHON_COMPAT[@]}"; do
154 - _python_impl_supported "${impl}" || continue
155 -
156 + for impl in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
157 for pattern; do
158 if [[ ${impl} == ${pattern} ]]; then
159 matches+=(
160 @@ -333,9 +316,7 @@ python_gen_useflags() {
161 local impl pattern
162 local matches=()
163
164 - for impl in "${PYTHON_COMPAT[@]}"; do
165 - _python_impl_supported "${impl}" || continue
166 -
167 + for impl in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
168 for pattern; do
169 if [[ ${impl} == ${pattern} ]]; then
170 matches+=( "python_targets_${impl}" )
171 @@ -382,9 +363,7 @@ python_gen_cond_dep() {
172 local dep=${1}
173 shift
174
175 - for impl in "${PYTHON_COMPAT[@]}"; do
176 - _python_impl_supported "${impl}" || continue
177 -
178 + for impl in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
179 for pattern; do
180 if [[ ${impl} == ${pattern} ]]; then
181 # substitute ${PYTHON_USEDEP} if used
182 @@ -460,12 +439,8 @@ _python_obtain_impls() {
183
184 MULTIBUILD_VARIANTS=()
185
186 - for impl in "${_PYTHON_ALL_IMPLS[@]}"; do
187 - if has "${impl}" "${PYTHON_COMPAT[@]}" \
188 - && use "python_targets_${impl}"
189 - then
190 - MULTIBUILD_VARIANTS+=( "${impl}" )
191 - fi
192 + for impl in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
193 + use "python_targets_${impl}" && MULTIBUILD_VARIANTS+=( "${impl}" )
194 done
195 }
196
197 diff --git a/eclass/python-single-r1.eclass b/eclass/python-single-r1.eclass
198 index b8684f0..8ef3846 100644
199 --- a/eclass/python-single-r1.eclass
200 +++ b/eclass/python-single-r1.eclass
201 @@ -95,12 +95,6 @@ if [[ ! ${_PYTHON_SINGLE_R1} ]]; then
202 # @CODE
203 # PYTHON_COMPAT=( python2_7 python3_{3,4} )
204 # @CODE
205 -if ! declare -p PYTHON_COMPAT &>/dev/null; then
206 - die 'PYTHON_COMPAT not declared.'
207 -fi
208 -if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then
209 - die 'PYTHON_COMPAT must be an array.'
210 -fi
211
212 # @ECLASS-VARIABLE: PYTHON_REQ_USE
213 # @DEFAULT_UNSET
214 @@ -186,34 +180,24 @@ fi
215 # @CODE
216
217 _python_single_set_globals() {
218 - local impls=()
219 - local unimpls=()
220 + _python_set_impls
221
222 PYTHON_DEPS=
223 local i PYTHON_PKG_DEP
224 - for i in "${_PYTHON_ALL_IMPLS[@]}"; do
225 - has "${i}" "${PYTHON_COMPAT[@]}" \
226 - && impls+=( "${i}" ) \
227 - || unimpls+=( "${i}" )
228 - done
229 -
230 - if [[ ${#impls[@]} -eq 0 ]]; then
231 - die "No supported implementation in PYTHON_COMPAT."
232 - fi
233
234 - local flags_mt=( "${impls[@]/#/python_targets_}" )
235 - local flags=( "${impls[@]/#/python_single_target_}" )
236 - local unflags=( "${unimpls[@]/#/-python_single_target_}" )
237 + local flags_mt=( "${_PYTHON_SUPPORTED_IMPLS[@]/#/python_targets_}" )
238 + local flags=( "${_PYTHON_SUPPORTED_IMPLS[@]/#/python_single_target_}" )
239 + local unflags=( "${_PYTHON_UNSUPPORTED_IMPLS[@]/#/-python_single_target_}" )
240
241 local optflags=${flags_mt[@]/%/(-)?},${unflags[@]/%/(-)}
242
243 IUSE="${flags_mt[*]}"
244
245 - if [[ ${#impls[@]} -eq 1 ]]; then
246 + if [[ ${#_PYTHON_SUPPORTED_IMPLS[@]} -eq 1 ]]; then
247 # There is only one supported implementation; set IUSE and other
248 # variables without PYTHON_SINGLE_TARGET.
249 PYTHON_REQUIRED_USE="${flags_mt[*]}"
250 - python_export "${impls[0]}" PYTHON_PKG_DEP
251 + python_export "${_PYTHON_SUPPORTED_IMPLS[0]}" PYTHON_PKG_DEP
252 PYTHON_DEPS="${PYTHON_PKG_DEP} "
253 # Force on the python_single_target_* flag for this impl, so
254 # that any dependencies that inherit python-single-r1 and
255 @@ -228,7 +212,7 @@ _python_single_set_globals() {
256 # on this package.
257 optflags+=,${flags[@]/%/(+)?}
258
259 - for i in "${impls[@]}"; do
260 + for i in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
261 # The chosen targets need to be in PYTHON_TARGETS as well.
262 # This is in order to enforce correct dependencies on packages
263 # supporting multiple implementations.
264 @@ -288,9 +272,7 @@ python_gen_usedep() {
265 local impl pattern
266 local matches=()
267
268 - for impl in "${PYTHON_COMPAT[@]}"; do
269 - _python_impl_supported "${impl}" || continue
270 -
271 + for impl in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
272 for pattern; do
273 if [[ ${impl} == ${pattern} ]]; then
274 matches+=(
275 @@ -331,9 +313,7 @@ python_gen_useflags() {
276 local impl pattern
277 local matches=()
278
279 - for impl in "${PYTHON_COMPAT[@]}"; do
280 - _python_impl_supported "${impl}" || continue
281 -
282 + for impl in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
283 for pattern; do
284 if [[ ${impl} == ${pattern} ]]; then
285 matches+=( "python_single_target_${impl}" )
286 @@ -380,9 +360,7 @@ python_gen_cond_dep() {
287 local dep=${1}
288 shift
289
290 - for impl in "${PYTHON_COMPAT[@]}"; do
291 - _python_impl_supported "${impl}" || continue
292 -
293 + for impl in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
294 for pattern; do
295 if [[ ${impl} == ${pattern} ]]; then
296 # substitute ${PYTHON_USEDEP} if used
297 @@ -411,20 +389,15 @@ python_setup() {
298
299 unset EPYTHON
300
301 - local impl impls=()
302 - for impl in "${PYTHON_COMPAT[@]}"; do
303 - _python_impl_supported "${impl}" || continue
304 - impls+=( "${impl}" )
305 - done
306 -
307 - if [[ ${#impls[@]} -eq 1 ]]; then
308 - if use "python_targets_${impls[0]}"; then
309 + if [[ ${#_PYTHON_SUPPORTED_IMPLS[@]} -eq 1 ]]; then
310 + if use "python_targets_${_PYTHON_SUPPORTED_IMPLS[0]}"; then
311 # Only one supported implementation, enable it explicitly
312 - python_export "${impls[0]}" EPYTHON PYTHON
313 + python_export "${_PYTHON_SUPPORTED_IMPLS[0]}" EPYTHON PYTHON
314 python_wrapper_setup
315 fi
316 else
317 - for impl in "${impls[@]}"; do
318 + local impl
319 + for impl in "${_PYTHON_SUPPORTED_IMPLS[@]}"; do
320 if use "python_single_target_${impl}"; then
321 if [[ ${EPYTHON} ]]; then
322 eerror "Your PYTHON_SINGLE_TARGET setting lists more than a single Python"
323 @@ -452,14 +425,14 @@ python_setup() {
324
325 if [[ ! ${EPYTHON} ]]; then
326 eerror "No Python implementation selected for the build. Please set"
327 - if [[ ${#impls[@]} -eq 1 ]]; then
328 + if [[ ${#_PYTHON_SUPPORTED_IMPLS[@]} -eq 1 ]]; then
329 eerror "the PYTHON_TARGETS variable in your make.conf to include one"
330 else
331 eerror "the PYTHON_SINGLE_TARGET variable in your make.conf to one"
332 fi
333 eerror "of the following values:"
334 eerror
335 - eerror "${impls[@]}"
336 + eerror "${_PYTHON_SUPPORTED_IMPLS[@]}"
337 echo
338 die "No supported Python implementation in PYTHON_SINGLE_TARGET/PYTHON_TARGETS."
339 fi
340 diff --git a/eclass/python-utils-r1.eclass b/eclass/python-utils-r1.eclass
341 index 7830323..89a7cbf 100644
342 --- a/eclass/python-utils-r1.eclass
343 +++ b/eclass/python-utils-r1.eclass
344 @@ -84,6 +84,55 @@ _python_impl_supported() {
345 esac
346 }
347
348 +# @FUNCTION: _python_set_impls
349 +# @INTERNAL
350 +# @DESCRIPTION:
351 +# Check PYTHON_COMPAT for well-formedness and validity, then set
352 +# two global variables:
353 +#
354 +# - _PYTHON_SUPPORTED_IMPLS containing valid implementations supported
355 +# by the ebuild (PYTHON_COMPAT - dead implementations),
356 +#
357 +# - and _PYTHON_UNSUPPORTED_IMPLS containing valid implementations that
358 +# are not supported by the ebuild.
359 +#
360 +# Implementations in both variables are ordered using the pre-defined
361 +# eclass implementation ordering.
362 +#
363 +# This function must be called once in global scope by an eclass
364 +# utilizing PYTHON_COMPAT.
365 +_python_set_impls() {
366 + local i
367 +
368 + if ! declare -p PYTHON_COMPAT &>/dev/null; then
369 + die 'PYTHON_COMPAT not declared.'
370 + fi
371 + if [[ $(declare -p PYTHON_COMPAT) != "declare -a"* ]]; then
372 + die 'PYTHON_COMPAT must be an array.'
373 + fi
374 + for i in "${PYTHON_COMPAT[@]}"; do
375 + # trigger validity checks
376 + _python_impl_supported "${i}"
377 + done
378 +
379 + _PYTHON_SUPPORTED_IMPLS=()
380 + _PYTHON_UNSUPPORTED_IMPLS=()
381 +
382 + for i in "${_PYTHON_ALL_IMPLS[@]}"; do
383 + if has "${i}" "${PYTHON_COMPAT[@]}"; then
384 + _PYTHON_SUPPORTED_IMPLS+=( "${i}" )
385 + else
386 + _PYTHON_UNSUPPORTED_IMPLS+=( "${i}" )
387 + fi
388 + done
389 +
390 + if [[ ${#_PYTHON_SUPPORTED_IMPLS[@]} -eq 0 ]]; then
391 + die "No supported implementation in PYTHON_COMPAT."
392 + fi
393 +
394 + readonly _PYTHON_SUPPORTED_IMPLS _PYTHON_UNSUPPORTED_IMPLS
395 +}
396 +
397 # @ECLASS-VARIABLE: PYTHON
398 # @DEFAULT_UNSET
399 # @DESCRIPTION:
400 --
401 2.6.4