i needed to temporarily modify the umask in some vcs eclasses.  rather than
open coding the umask saving/restoring, i decided to re-use the
eshopts_{push,pop} logic so the umask can be pushed/popped easily.

the resulting code was mostly copy & paste the same, and the stack maintenance
ends up drowning out the meat of the stuff i care about -- screwing with the
umask.  so to that end, i added a set of generic stack helpers:
estack_{push,pop}.  then i rewrote eshopts_{push,pop} and based
eumask_{push,pop} on top of that.

what do people think ?  good stuff, or am i trying too hard ?
-mike

--- eutils.eclass       14 Dec 2011 17:36:18 -0000      1.372
+++ eutils.eclass       14 Dec 2011 22:23:02 -0000
@@ -100,6 +100,51 @@ esvn_clean() {
        find "$@" -type d -name '.svn' -prune -print0 | xargs -0 rm -rf
 }
 
+# @FUNCTION: estack_push
+# @USAGE: <stack> [items to push]
+# @DESCRIPTION:
+# Push any number of items onto the specified stack.  Pick a name that
+# is a valid variable (i.e. stick to alphanumerics), and push as many
+# items as you like onto the stack at once.
+#
+# The following code snippet will echo 5, then 4, then 3, then ...
+# @CODE
+#              estask_push mystack 1 2 3 4 5
+#              while i=$(estack_pop mystack) ; do
+#                      echo ${i}
+#              done
+# @CODE
+estack_push() {
+       [[ $# -eq 0 ]] && die "estack_push: incorrect # of arguments"
+       local stack_name="__ESTACK_$1__" ; shift
+       eval ${stack_name}+=\( \"\$@\" \)
+}
+
+# @FUNCTION: estack_pop
+# @USAGE: <stack>
+# @DESCRIPTION:
+# Pop a single item off the specified stack and return 0.  If no more
+# items are available, return 1.  See estack_push for more info.
+estack_pop() {
+       if [[ $# -ne 1 ]] ; then
+               # Would like to call `die` here, but people will usually
+               # be calling this in a subshell; e.g.
+               # val=$(estack_pop foo)
+               eerror "estack_pop: incorrect # of arguments"
+               return 1
+       fi
+
+       local stack_name="__ESTACK_$1__" ; shift
+       eval local i=\${#${stack_name}[@]}
+       # Don't warn -- let the caller interpret this as a failure
+       # or as normal behavior (akin to `shift`)
+       [[ $(( --i )) -eq -1 ]] && return 1
+
+       eval local s=\"\${${stack_name}[${i}]}\"
+       eval unset ${stack_name}[${i}]
+       echo "${s}"
+}
+
 # @FUNCTION: eshopts_push
 # @USAGE: [options to `set` or `shopt`]
 # @DESCRIPTION:
@@ -126,15 +171,14 @@ esvn_clean() {
 eshopts_push() {
        # have to assume __ESHOPTS_SAVE__ isn't screwed with
        # as a `declare -a` here will reset its value
-       local i=${#__ESHOPTS_SAVE__[@]}
        if [[ $1 == -[su] ]] ; then
-               __ESHOPTS_SAVE__[$i]=$(shopt -p)
+               estack_push eshopts "$(shopt -p)"
                [[ $# -eq 0 ]] && return 0
                shopt "$@" || die "eshopts_push: bad options to shopt: $*"
        else
-               __ESHOPTS_SAVE__[$i]=$-
+               estack_push eshopts $-
                [[ $# -eq 0 ]] && return 0
                set "$@" || die "eshopts_push: bad options to set: $*"
        fi
@@ -144,19 +188,36 @@ eshopts_push() {
 # Restore the shell options to the state saved with the corresponding
 # eshopts_push call.  See that function for more details.
 eshopts_pop() {
-       [[ $# -ne 0 ]] && die "eshopts_pop takes no arguments"
-       local i=$(( ${#__ESHOPTS_SAVE__[@]} - 1 ))
-       [[ ${i} -eq -1 ]] && die "eshopts_{push,pop}: unbalanced pair"
-       local s=${__ESHOPTS_SAVE__[$i]}
-       unset __ESHOPTS_SAVE__[$i]
+       local s
+       s=$(estack_pop eshopts) || die # do not merge with `local` above
        if [[ ${s} == "shopt -"* ]] ; then
                eval "${s}" || die "eshopts_pop: sanity: invalid shopt options: 
${s}"
        else
                set +$-     || die "eshopts_pop: sanity: invalid shell 
settings: $-"
                set -${s}   || die "eshopts_pop: sanity: unable to restore 
saved shell settings: ${s}"
        fi
 }
 
+# @FUNCTION: eumask_push
+# @USAGE: <new umask>
+# @DESCRIPTION:
+# Set the umask to the new value specified while saving the previous
+# value onto a stack.  Useful for temporarily changing the umask.
+eumask_push() {
+       estack_push eumask "$(umask)"
+       umask "$@" || die "${FUNCNAME}: bad options to umask: $*"
+}
+
+# @FUNCTION: eumask_pop
+# @USAGE:
+# @DESCRIPTION:
+# Restore the previous umask state.
+eumask_pop() {
+       local s
+       s=$(estack_pop eumask) || die # do not merge with `local` above
+       umask ${s} || die "${FUNCNAME}: sanity: could not restore umask: ${s}"
+}
+
 # @VARIABLE: EPATCH_SOURCE
 # @DESCRIPTION:
 # Default directory to search for patches.

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to