Gentoo Archives: gentoo-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-dev@l.g.o
Subject: Re: [gentoo-dev] [PATCH v3] estack.eclass: Split estack* logic from eutils
Date: Sat, 18 Mar 2017 07:37:35
Message-Id: 1489822512.1289.5.camel@gentoo.org
In Reply to: [gentoo-dev] [PATCH v3] estack.eclass: Split estack* logic from eutils by "Michał Górny"
1 On nie, 2017-03-12 at 11:13 +0100, Michał Górny wrote:
2 > Split the estack_* and related functions from eutils into a dedicated
3 > estack.eclass. Those functions have significant complexity and are not
4 > used frequently, therefore they benefit from having a separate file
5 > and an explicit dedicated maintainer.
6 >
7 > The new eclass is implicitly inherited by eutils to preserve
8 > compatibility. However, the inherit will be removed in EAPI 7,
9 > and the ebuilds should switch to using estack directly.
10 >
11 > Thanks to Ulrich Müller for doing the research on this.
12 >
13 > // v3: also rename&update tests
14 > ---
15 > eclass/estack.eclass | 217 +++++++++++++++++++++
16 > eclass/eutils.eclass | 210 +-------------------
17 > .../tests/{eutils_eshopts.sh => estack_eshopts.sh} | 4 +-
18 > .../tests/{eutils_estack.sh => estack_estack.sh} | 4 +-
19 > eclass/tests/{eutils_evar.sh => estack_evar.sh} | 4 +-
20 > 5 files changed, 230 insertions(+), 209 deletions(-)
21 > create mode 100644 eclass/estack.eclass
22 > rename eclass/tests/{eutils_eshopts.sh => estack_eshopts.sh} (93%)
23 > rename eclass/tests/{eutils_estack.sh => estack_estack.sh} (93%)
24 > rename eclass/tests/{eutils_evar.sh => estack_evar.sh} (96%)
25 >
26 > diff --git a/eclass/estack.eclass b/eclass/estack.eclass
27 > new file mode 100644
28 > index 000000000000..19c388f3d8d2
29 > --- /dev/null
30 > +++ b/eclass/estack.eclass
31 > @@ -0,0 +1,217 @@
32 > +# Copyright 1999-2017 Gentoo Foundation
33 > +# Distributed under the terms of the GNU General Public License v2
34 > +
35 > +# @ECLASS: estack.eclass
36 > +# @MAINTAINER:
37 > +# base-system@g.o
38 > +# @BLURB: stack-like value storage support
39 > +# @DESCRIPTION:
40 > +# Support for storing values on stack-like variables.
41 > +
42 > +if [[ -z ${_ESTACK_ECLASS} ]]; then
43 > +
44 > +# @FUNCTION: estack_push
45 > +# @USAGE: <stack> [items to push]
46 > +# @DESCRIPTION:
47 > +# Push any number of items onto the specified stack. Pick a name that
48 > +# is a valid variable (i.e. stick to alphanumerics), and push as many
49 > +# items as you like onto the stack at once.
50 > +#
51 > +# The following code snippet will echo 5, then 4, then 3, then ...
52 > +# @CODE
53 > +# estack_push mystack 1 2 3 4 5
54 > +# while estack_pop mystack i ; do
55 > +# echo "${i}"
56 > +# done
57 > +# @CODE
58 > +estack_push() {
59 > + [[ $# -eq 0 ]] && die "estack_push: incorrect # of arguments"
60 > + local stack_name="_ESTACK_$1_" ; shift
61 > + eval ${stack_name}+=\( \"\$@\" \)
62 > +}
63 > +
64 > +# @FUNCTION: estack_pop
65 > +# @USAGE: <stack> [variable]
66 > +# @DESCRIPTION:
67 > +# Pop a single item off the specified stack. If a variable is specified,
68 > +# the popped item is stored there. If no more items are available, return
69 > +# 1, else return 0. See estack_push for more info.
70 > +estack_pop() {
71 > + [[ $# -eq 0 || $# -gt 2 ]] && die "estack_pop: incorrect # of arguments"
72 > +
73 > + # We use the fugly _estack_xxx var names to avoid collision with
74 > + # passing back the return value. If we used "local i" and the
75 > + # caller ran `estack_pop ... i`, we'd end up setting the local
76 > + # copy of "i" rather than the caller's copy. The _estack_xxx
77 > + # garbage is preferable to using $1/$2 everywhere as that is a
78 > + # bit harder to read.
79 > + local _estack_name="_ESTACK_$1_" ; shift
80 > + local _estack_retvar=$1 ; shift
81 > + eval local _estack_i=\${#${_estack_name}\[@\]}
82 > + # Don't warn -- let the caller interpret this as a failure
83 > + # or as normal behavior (akin to `shift`)
84 > + [[ $(( --_estack_i )) -eq -1 ]] && return 1
85 > +
86 > + if [[ -n ${_estack_retvar} ]] ; then
87 > + eval ${_estack_retvar}=\"\${${_estack_name}\[${_estack_i}\]}\"
88 > + fi
89 > + eval unset \"${_estack_name}\[${_estack_i}\]\"
90 > +}
91 > +
92 > +# @FUNCTION: evar_push
93 > +# @USAGE: <variable to save> [more vars to save]
94 > +# @DESCRIPTION:
95 > +# This let's you temporarily modify a variable and then restore it (including
96 > +# set vs unset semantics). Arrays are not supported at this time.
97 > +#
98 > +# This is meant for variables where using `local` does not work (such as
99 > +# exported variables, or only temporarily changing things in a func).
100 > +#
101 > +# For example:
102 > +# @CODE
103 > +# evar_push LC_ALL
104 > +# export LC_ALL=C
105 > +# ... do some stuff that needs LC_ALL=C set ...
106 > +# evar_pop
107 > +#
108 > +# # You can also save/restore more than one var at a time
109 > +# evar_push BUTTERFLY IN THE SKY
110 > +# ... do stuff with the vars ...
111 > +# evar_pop # This restores just one var, SKY
112 > +# ... do more stuff ...
113 > +# evar_pop 3 # This pops the remaining 3 vars
114 > +# @CODE
115 > +evar_push() {
116 > + local var val
117 > + for var ; do
118 > + [[ ${!var+set} == "set" ]] \
119 > + && val=${!var} \
120 > + || val="unset_76fc3c462065bb4ca959f939e6793f94"
121 > + estack_push evar "${var}" "${val}"
122 > + done
123 > +}
124 > +
125 > +# @FUNCTION: evar_push_set
126 > +# @USAGE: <variable to save> [new value to store]
127 > +# @DESCRIPTION:
128 > +# This is a handy shortcut to save and temporarily set a variable. If a value
129 > +# is not specified, the var will be unset.
130 > +evar_push_set() {
131 > + local var=$1
132 > + evar_push ${var}
133 > + case $# in
134 > + 1) unset ${var} ;;
135 > + 2) printf -v "${var}" '%s' "$2" ;;
136 > + *) die "${FUNCNAME}: incorrect # of args: $*" ;;
137 > + esac
138 > +}
139 > +
140 > +# @FUNCTION: evar_pop
141 > +# @USAGE: [number of vars to restore]
142 > +# @DESCRIPTION:
143 > +# Restore the variables to the state saved with the corresponding
144 > +# evar_push call. See that function for more details.
145 > +evar_pop() {
146 > + local cnt=${1:-bad}
147 > + case $# in
148 > + 0) cnt=1 ;;
149 > + 1) isdigit "${cnt}" || die "${FUNCNAME}: first arg must be a number: $*" ;;
150 > + *) die "${FUNCNAME}: only accepts one arg: $*" ;;
151 > + esac
152 > +
153 > + local var val
154 > + while (( cnt-- )) ; do
155 > + estack_pop evar val || die "${FUNCNAME}: unbalanced push"
156 > + estack_pop evar var || die "${FUNCNAME}: unbalanced push"
157 > + [[ ${val} == "unset_76fc3c462065bb4ca959f939e6793f94" ]] \
158 > + && unset ${var} \
159 > + || printf -v "${var}" '%s' "${val}"
160 > + done
161 > +}
162 > +
163 > +# @FUNCTION: eshopts_push
164 > +# @USAGE: [options to `set` or `shopt`]
165 > +# @DESCRIPTION:
166 > +# Often times code will want to enable a shell option to change code behavior.
167 > +# Since changing shell options can easily break other pieces of code (which
168 > +# assume the default state), eshopts_push is used to (1) push the current shell
169 > +# options onto a stack and (2) pass the specified arguments to set.
170 > +#
171 > +# If the first argument is '-s' or '-u', we assume you want to call `shopt`
172 > +# rather than `set` as there are some options only available via that.
173 > +#
174 > +# A common example is to disable shell globbing so that special meaning/care
175 > +# may be used with variables/arguments to custom functions. That would be:
176 > +# @CODE
177 > +# eshopts_push -o noglob
178 > +# for x in ${foo} ; do
179 > +# if ...some check... ; then
180 > +# eshopts_pop
181 > +# return 0
182 > +# fi
183 > +# done
184 > +# eshopts_pop
185 > +# @CODE
186 > +eshopts_push() {
187 > + if [[ $1 == -[su] ]] ; then
188 > + estack_push eshopts "$(shopt -p)"
189 > + [[ $# -eq 0 ]] && return 0
190 > + shopt "$@" || die "${FUNCNAME}: bad options to shopt: $*"
191 > + else
192 > + estack_push eshopts $-
193 > + [[ $# -eq 0 ]] && return 0
194 > + set "$@" || die "${FUNCNAME}: bad options to set: $*"
195 > + fi
196 > +}
197 > +
198 > +# @FUNCTION: eshopts_pop
199 > +# @USAGE:
200 > +# @DESCRIPTION:
201 > +# Restore the shell options to the state saved with the corresponding
202 > +# eshopts_push call. See that function for more details.
203 > +eshopts_pop() {
204 > + local s
205 > + estack_pop eshopts s || die "${FUNCNAME}: unbalanced push"
206 > + if [[ ${s} == "shopt -"* ]] ; then
207 > + eval "${s}" || die "${FUNCNAME}: sanity: invalid shopt options: ${s}"
208 > + else
209 > + set +$- || die "${FUNCNAME}: sanity: invalid shell settings: $-"
210 > + set -${s} || die "${FUNCNAME}: sanity: unable to restore saved shell settings: ${s}"
211 > + fi
212 > +}
213 > +
214 > +# @FUNCTION: eumask_push
215 > +# @USAGE: <new umask>
216 > +# @DESCRIPTION:
217 > +# Set the umask to the new value specified while saving the previous
218 > +# value onto a stack. Useful for temporarily changing the umask.
219 > +eumask_push() {
220 > + estack_push eumask "$(umask)"
221 > + umask "$@" || die "${FUNCNAME}: bad options to umask: $*"
222 > +}
223 > +
224 > +# @FUNCTION: eumask_pop
225 > +# @USAGE:
226 > +# @DESCRIPTION:
227 > +# Restore the previous umask state.
228 > +eumask_pop() {
229 > + [[ $# -eq 0 ]] || die "${FUNCNAME}: we take no options"
230 > + local s
231 > + estack_pop eumask s || die "${FUNCNAME}: unbalanced push"
232 > + umask ${s} || die "${FUNCNAME}: sanity: could not restore umask: ${s}"
233 > +}
234 > +
235 > +# @FUNCTION: isdigit
236 > +# @USAGE: <number> [more numbers]
237 > +# @DESCRIPTION:
238 > +# Return true if all arguments are numbers.
239 > +isdigit() {
240 > + local d
241 > + for d ; do
242 > + [[ ${d:-bad} == *[!0-9]* ]] && return 1
243 > + done
244 > + return 0
245 > +}
246 > +
247 > +_ESTACK_ECLASS=1
248 > +fi #_ESTACK_ECLASS
249 > diff --git a/eclass/eutils.eclass b/eclass/eutils.eclass
250 > index ac6a4854d17b..79ec00042a3f 100644
251 > --- a/eclass/eutils.eclass
252 > +++ b/eclass/eutils.eclass
253 > @@ -19,6 +19,13 @@ _EUTILS_ECLASS=1
254 >
255 > inherit multilib toolchain-funcs
256 >
257 > +# implicitly inherited (now split) eclasses
258 > +case ${EAPI:-0} in
259 > +0|1|2|3|4|5|6)
260 > + inherit estack
261 > + ;;
262 > +esac
263 > +
264 > # @FUNCTION: eqawarn
265 > # @USAGE: [message]
266 > # @DESCRIPTION:
267 > @@ -63,209 +70,6 @@ egit_clean() {
268 > find "$@" -type d -name '.git*' -prune -print0 | xargs -0 rm -rf
269 > }
270 >
271 > -# @FUNCTION: estack_push
272 > -# @USAGE: <stack> [items to push]
273 > -# @DESCRIPTION:
274 > -# Push any number of items onto the specified stack. Pick a name that
275 > -# is a valid variable (i.e. stick to alphanumerics), and push as many
276 > -# items as you like onto the stack at once.
277 > -#
278 > -# The following code snippet will echo 5, then 4, then 3, then ...
279 > -# @CODE
280 > -# estack_push mystack 1 2 3 4 5
281 > -# while estack_pop mystack i ; do
282 > -# echo "${i}"
283 > -# done
284 > -# @CODE
285 > -estack_push() {
286 > - [[ $# -eq 0 ]] && die "estack_push: incorrect # of arguments"
287 > - local stack_name="_ESTACK_$1_" ; shift
288 > - eval ${stack_name}+=\( \"\$@\" \)
289 > -}
290 > -
291 > -# @FUNCTION: estack_pop
292 > -# @USAGE: <stack> [variable]
293 > -# @DESCRIPTION:
294 > -# Pop a single item off the specified stack. If a variable is specified,
295 > -# the popped item is stored there. If no more items are available, return
296 > -# 1, else return 0. See estack_push for more info.
297 > -estack_pop() {
298 > - [[ $# -eq 0 || $# -gt 2 ]] && die "estack_pop: incorrect # of arguments"
299 > -
300 > - # We use the fugly _estack_xxx var names to avoid collision with
301 > - # passing back the return value. If we used "local i" and the
302 > - # caller ran `estack_pop ... i`, we'd end up setting the local
303 > - # copy of "i" rather than the caller's copy. The _estack_xxx
304 > - # garbage is preferable to using $1/$2 everywhere as that is a
305 > - # bit harder to read.
306 > - local _estack_name="_ESTACK_$1_" ; shift
307 > - local _estack_retvar=$1 ; shift
308 > - eval local _estack_i=\${#${_estack_name}\[@\]}
309 > - # Don't warn -- let the caller interpret this as a failure
310 > - # or as normal behavior (akin to `shift`)
311 > - [[ $(( --_estack_i )) -eq -1 ]] && return 1
312 > -
313 > - if [[ -n ${_estack_retvar} ]] ; then
314 > - eval ${_estack_retvar}=\"\${${_estack_name}\[${_estack_i}\]}\"
315 > - fi
316 > - eval unset \"${_estack_name}\[${_estack_i}\]\"
317 > -}
318 > -
319 > -# @FUNCTION: evar_push
320 > -# @USAGE: <variable to save> [more vars to save]
321 > -# @DESCRIPTION:
322 > -# This let's you temporarily modify a variable and then restore it (including
323 > -# set vs unset semantics). Arrays are not supported at this time.
324 > -#
325 > -# This is meant for variables where using `local` does not work (such as
326 > -# exported variables, or only temporarily changing things in a func).
327 > -#
328 > -# For example:
329 > -# @CODE
330 > -# evar_push LC_ALL
331 > -# export LC_ALL=C
332 > -# ... do some stuff that needs LC_ALL=C set ...
333 > -# evar_pop
334 > -#
335 > -# # You can also save/restore more than one var at a time
336 > -# evar_push BUTTERFLY IN THE SKY
337 > -# ... do stuff with the vars ...
338 > -# evar_pop # This restores just one var, SKY
339 > -# ... do more stuff ...
340 > -# evar_pop 3 # This pops the remaining 3 vars
341 > -# @CODE
342 > -evar_push() {
343 > - local var val
344 > - for var ; do
345 > - [[ ${!var+set} == "set" ]] \
346 > - && val=${!var} \
347 > - || val="unset_76fc3c462065bb4ca959f939e6793f94"
348 > - estack_push evar "${var}" "${val}"
349 > - done
350 > -}
351 > -
352 > -# @FUNCTION: evar_push_set
353 > -# @USAGE: <variable to save> [new value to store]
354 > -# @DESCRIPTION:
355 > -# This is a handy shortcut to save and temporarily set a variable. If a value
356 > -# is not specified, the var will be unset.
357 > -evar_push_set() {
358 > - local var=$1
359 > - evar_push ${var}
360 > - case $# in
361 > - 1) unset ${var} ;;
362 > - 2) printf -v "${var}" '%s' "$2" ;;
363 > - *) die "${FUNCNAME}: incorrect # of args: $*" ;;
364 > - esac
365 > -}
366 > -
367 > -# @FUNCTION: evar_pop
368 > -# @USAGE: [number of vars to restore]
369 > -# @DESCRIPTION:
370 > -# Restore the variables to the state saved with the corresponding
371 > -# evar_push call. See that function for more details.
372 > -evar_pop() {
373 > - local cnt=${1:-bad}
374 > - case $# in
375 > - 0) cnt=1 ;;
376 > - 1) isdigit "${cnt}" || die "${FUNCNAME}: first arg must be a number: $*" ;;
377 > - *) die "${FUNCNAME}: only accepts one arg: $*" ;;
378 > - esac
379 > -
380 > - local var val
381 > - while (( cnt-- )) ; do
382 > - estack_pop evar val || die "${FUNCNAME}: unbalanced push"
383 > - estack_pop evar var || die "${FUNCNAME}: unbalanced push"
384 > - [[ ${val} == "unset_76fc3c462065bb4ca959f939e6793f94" ]] \
385 > - && unset ${var} \
386 > - || printf -v "${var}" '%s' "${val}"
387 > - done
388 > -}
389 > -
390 > -# @FUNCTION: eshopts_push
391 > -# @USAGE: [options to `set` or `shopt`]
392 > -# @DESCRIPTION:
393 > -# Often times code will want to enable a shell option to change code behavior.
394 > -# Since changing shell options can easily break other pieces of code (which
395 > -# assume the default state), eshopts_push is used to (1) push the current shell
396 > -# options onto a stack and (2) pass the specified arguments to set.
397 > -#
398 > -# If the first argument is '-s' or '-u', we assume you want to call `shopt`
399 > -# rather than `set` as there are some options only available via that.
400 > -#
401 > -# A common example is to disable shell globbing so that special meaning/care
402 > -# may be used with variables/arguments to custom functions. That would be:
403 > -# @CODE
404 > -# eshopts_push -o noglob
405 > -# for x in ${foo} ; do
406 > -# if ...some check... ; then
407 > -# eshopts_pop
408 > -# return 0
409 > -# fi
410 > -# done
411 > -# eshopts_pop
412 > -# @CODE
413 > -eshopts_push() {
414 > - if [[ $1 == -[su] ]] ; then
415 > - estack_push eshopts "$(shopt -p)"
416 > - [[ $# -eq 0 ]] && return 0
417 > - shopt "$@" || die "${FUNCNAME}: bad options to shopt: $*"
418 > - else
419 > - estack_push eshopts $-
420 > - [[ $# -eq 0 ]] && return 0
421 > - set "$@" || die "${FUNCNAME}: bad options to set: $*"
422 > - fi
423 > -}
424 > -
425 > -# @FUNCTION: eshopts_pop
426 > -# @USAGE:
427 > -# @DESCRIPTION:
428 > -# Restore the shell options to the state saved with the corresponding
429 > -# eshopts_push call. See that function for more details.
430 > -eshopts_pop() {
431 > - local s
432 > - estack_pop eshopts s || die "${FUNCNAME}: unbalanced push"
433 > - if [[ ${s} == "shopt -"* ]] ; then
434 > - eval "${s}" || die "${FUNCNAME}: sanity: invalid shopt options: ${s}"
435 > - else
436 > - set +$- || die "${FUNCNAME}: sanity: invalid shell settings: $-"
437 > - set -${s} || die "${FUNCNAME}: sanity: unable to restore saved shell settings: ${s}"
438 > - fi
439 > -}
440 > -
441 > -# @FUNCTION: eumask_push
442 > -# @USAGE: <new umask>
443 > -# @DESCRIPTION:
444 > -# Set the umask to the new value specified while saving the previous
445 > -# value onto a stack. Useful for temporarily changing the umask.
446 > -eumask_push() {
447 > - estack_push eumask "$(umask)"
448 > - umask "$@" || die "${FUNCNAME}: bad options to umask: $*"
449 > -}
450 > -
451 > -# @FUNCTION: eumask_pop
452 > -# @USAGE:
453 > -# @DESCRIPTION:
454 > -# Restore the previous umask state.
455 > -eumask_pop() {
456 > - [[ $# -eq 0 ]] || die "${FUNCNAME}: we take no options"
457 > - local s
458 > - estack_pop eumask s || die "${FUNCNAME}: unbalanced push"
459 > - umask ${s} || die "${FUNCNAME}: sanity: could not restore umask: ${s}"
460 > -}
461 > -
462 > -# @FUNCTION: isdigit
463 > -# @USAGE: <number> [more numbers]
464 > -# @DESCRIPTION:
465 > -# Return true if all arguments are numbers.
466 > -isdigit() {
467 > - local d
468 > - for d ; do
469 > - [[ ${d:-bad} == *[!0-9]* ]] && return 1
470 > - done
471 > - return 0
472 > -}
473 > -
474 > # @VARIABLE: EPATCH_SOURCE
475 > # @DESCRIPTION:
476 > # Default directory to search for patches.
477 > diff --git a/eclass/tests/eutils_eshopts.sh b/eclass/tests/estack_eshopts.sh
478 > similarity index 93%
479 > rename from eclass/tests/eutils_eshopts.sh
480 > rename to eclass/tests/estack_eshopts.sh
481 > index 2e9bbb6d4612..606a17cfb053 100755
482 > --- a/eclass/tests/eutils_eshopts.sh
483 > +++ b/eclass/tests/estack_eshopts.sh
484 > @@ -1,10 +1,10 @@
485 > #!/bin/bash
486 > -# Copyright 1999-2015 Gentoo Foundation
487 > +# Copyright 1999-2017 Gentoo Foundation
488 > # Distributed under the terms of the GNU General Public License v2
489 >
490 > source tests-common.sh
491 >
492 > -inherit eutils
493 > +inherit estack
494 >
495 > test-it() {
496 > local s0 s1 s2
497 > diff --git a/eclass/tests/eutils_estack.sh b/eclass/tests/estack_estack.sh
498 > similarity index 93%
499 > rename from eclass/tests/eutils_estack.sh
500 > rename to eclass/tests/estack_estack.sh
501 > index c1fecf323133..4845243d3ae4 100755
502 > --- a/eclass/tests/eutils_estack.sh
503 > +++ b/eclass/tests/estack_estack.sh
504 > @@ -1,10 +1,10 @@
505 > #!/bin/bash
506 > -# Copyright 1999-2015 Gentoo Foundation
507 > +# Copyright 1999-2017 Gentoo Foundation
508 > # Distributed under the terms of the GNU General Public License v2
509 >
510 > source tests-common.sh
511 >
512 > -inherit eutils
513 > +inherit estack
514 >
515 > tbegin "initial stack state"
516 > estack_pop teststack
517 > diff --git a/eclass/tests/eutils_evar.sh b/eclass/tests/estack_evar.sh
518 > similarity index 96%
519 > rename from eclass/tests/eutils_evar.sh
520 > rename to eclass/tests/estack_evar.sh
521 > index f8db340f723d..29badba0079e 100755
522 > --- a/eclass/tests/eutils_evar.sh
523 > +++ b/eclass/tests/estack_evar.sh
524 > @@ -1,10 +1,10 @@
525 > #!/bin/bash
526 > -# Copyright 1999-2015 Gentoo Foundation
527 > +# Copyright 1999-2017 Gentoo Foundation
528 > # Distributed under the terms of the GNU General Public License v2
529 >
530 > source tests-common.sh
531 >
532 > -inherit eutils
533 > +inherit estack
534 >
535 > tbegin "simple push/pop"
536 > VAR=1
537
538 Merged.
539
540 --
541 Best regards,
542 Michał Górny

Attachments

File name MIME type
signature.asc application/pgp-signature