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