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

Replies