From ab7a4e9131e1ae0f7c35d1a10666b8ef8169e0c9 Mon Sep 17 00:00:00 2001 From: rtorres Date: Wed, 28 Nov 2012 11:00:38 -0500 Subject: [PATCH 1/4] Adding support to automatic ui type. First it will try to use dialog, then will fallback to cli mode in case dialog utility is not available --- libui.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) mode change 100644 => 100755 libui.sh diff --git a/libui.sh b/libui.sh old mode 100644 new mode 100755 index 84a9f48..6940b17 --- a/libui.sh +++ b/libui.sh @@ -8,7 +8,7 @@ # you can call this function to change settings, before calling other libui functions or afterwards # it must always be called at least once to set the right variables, but it gets automatically called once at the end of this file # Don't set the variable or leave it empty to set the default value -# $1 ui type (dia or cli). default: cli +# $1 ui type (dia, cli or auto). default: cli # $2 directory for tmp files. default: /tmp # $3 logfile (or string of logfiles, separated by whitespace). default: no logging # $4 categories (separated by whitespace) you will use in debug calls. @@ -17,10 +17,13 @@ # $5 show stacktrace on die_error: 1 or 0 (default) libui_sh_init () { - LIBUI_UI=${1:-cli} - local allowed_uis=('cli' 'dia') - check_is_in "$LIBUI_UI" "${allowed_uis[@]}" || die_error "libui_sh_init \$1 must be one of 'cli', 'dia' or '' (for cli)" - [ "$LIBUI_UI" == 'dialog' ] && ! which dialog &>/dev/null && die_error "Required dependency dialog not found" + LIBUI_UI=${1:-auto} + allowed_uis=('cli' 'dia' 'auto') + check_is_in "$LIBUI_UI" "${allowed_uis[@]}" || die_error "libui_sh_init \$1 must be one of 'cli', 'dia', 'auto' or '' (for cli)" + [ "$LIBUI_UI" == 'dia' ] && ! which dialog &>/dev/null && die_error "Required dependency dialog not found" + if [ "$LIBUI_UI" == 'auto' ]; then + ! which dialog &>/dev/null && LIBUI_UI='cli' || LIBUI_UI='dia' + fi LIBUI_TMP_DIR=/tmp if [ -n "$2" ]; then LIBUI_TMP_DIR=$2 From 499b75cae00ca49ac8c5b0193e4f046d83ed5431 Mon Sep 17 00:00:00 2001 From: rtorres Date: Wed, 28 Nov 2012 11:31:07 -0500 Subject: [PATCH 2/4] Addapting to Bash 3; local var does not work fine with bash 3 and += operator is not supported by bash 3 --- libui.sh | 172 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 88 insertions(+), 84 deletions(-) diff --git a/libui.sh b/libui.sh index 6940b17..7472537 100755 --- a/libui.sh +++ b/libui.sh @@ -38,7 +38,7 @@ libui_sh_init () if [ -n "$4" ]; then LIBUI_DEBUG=1 LIBUI_DEBUG_CATEGORIES=($4) - check_is_in 'UI' "${LIBUI_DEBUG_CATEGORIES[@]}" || LIBUI_DEBUG_CATEGORIES+=('UI') + check_is_in 'UI' "${LIBUI_DEBUG_CATEGORIES[@]}" || LIBUI_DEBUG_CATEGORIES=("${LIBUI_DEBUG_CATEGORIES[@]}" 'UI') fi LIBUI_STACKTRACE=${5:-0} check_is_in $LIBUI_STACKTRACE 0 1 || die_error "libui_sh_init \$5 must be 0 or 1 to denote printing stacktrace in die_error ('' = default = 0)" @@ -69,18 +69,18 @@ check_is_in () # the list of choices is automatically adapted based on locally available editors # if $EDITOR is non-empty and found, we return right away, unless $1 is 'force' seteditor() { - local default=nano + default=nano if [ -n "$EDITOR" ] && which "$EDITOR" >/dev/null then [ "$1" != 'force' ] && return 0 default=$EDITOR fi - local editor - local opts=() + editor= + opts=() declare -A LIBUI_EDITORS=(["nano"]="nano (easy)" ["pico"]="pico (easy)" ["joe"]="joe (bit more powerful)" ["vi"]="vi (advanced)" ["vim"]="vim (advanced)") for editor in ${!LIBUI_EDITORS[@]} do - which $editor &>/dev/null && opts+=($editor "${LIBUI_EDITORS[$editor]}") + which $editor &>/dev/null && opts=("${opts[@]}" $editor "${LIBUI_EDITORS[$editor]}") done ask_option $default "Text editor selection" "Select a Text Editor to Use" required "${opts[@]}" || return 1 check_is_in "$ANSWER_OPTION" "${!LIBUI_EDITORS[@]}" && EDITOR=$ANSWER_OPTION || EDITOR=$default @@ -129,7 +129,7 @@ show_warning () [ -z "$1" ] && die_error "show_warning needs a title" [ -z "$2" ] && die_error "show_warning needs an item to show" [ -n "$3" -a "$3" != msg -a "$3" != text ] && die_error "show_warning \$3 must be text or msg" - local type=msg + type=msg [ -n "$3" ] && type=$3 debug 'UI' "show_warning '$1': $2 ($type)" [ `type -t _${LIBUI_UI}_show_warning` == function ] || die_error "_${LIBUI_UI}_show_warning is not a function" @@ -154,8 +154,8 @@ notify () # $3 0/1 this is the last one of the group of several things (eg clear buffer). default 0. (optional) inform () #TODO: when using successive things, the screen can become full and you only see the old stuff, not the new { - local successive=${2:-0} - local succ_last=${3:-0} + successive=${2:-0} + succ_last=${3:-0} debug 'UI' "inform: $1" [ `type -t _${LIBUI_UI}_inform` == function ] || die_error "_${LIBUI_UI}_inform is not a function" _${LIBUI_UI}_inform "$1" $successive $succ_last @@ -164,13 +164,13 @@ inform () #TODO: when using successive things, the screen can become full and yo # logging of stuff log () { - local file + file= [ "$LIBUI_LOG" = 1 ] || return 0 for file in $LIBUI_LOG_FILE; do [ -z "$file" ] && continue; - local dir=$(dirname $file) + dir=$(dirname $file) mkdir -p $dir || die_error "Cannot create log directory $dir" - local str="[LOG] `date +"%Y-%m-%d %H:%M:%S"` $@" + str="[LOG] `date +"%Y-%m-%d %H:%M:%S"` $@" echo -e "$str" >> $file || die_error "Cannot log $str to $file" done } @@ -182,8 +182,8 @@ log () # always make sure this function never calls die_error, not even indirectly through other functions we call here, to avoid loops debug () { - local cat - local file + cat= + file= [ "$LIBUI_DEBUG" = "1" ] || return 0 [ -n "$1" ] || die error_raw "you must specify at least one (non-empty) debug category" [ -n "$2" ] || die_error_raw "debug \$2 cannot be empty" @@ -193,9 +193,9 @@ debug () done for file in $LIBUI_LOG_FILE; do [ -z "$file" ] && continue; - local dir=$(dirname $file) + dir=$(dirname $file) mkdir -p $dir || die_error_raw "Cannot create log directory $dir" - local str="[DEBUG $1 ] $2" + str="[DEBUG $1 ] $2" echo -e "$str" >> $file || die_error_raw "Cannot debug $str to $file" done } @@ -207,8 +207,8 @@ debug () # we also make it clearer you can select UTC. there are some other timezones as well (GMT+2 and whatever) but we assume user doesn't want those. ask_timezone () { - local REGIONS="UTC -" # not really a region, but the easiest to incorporate UTC in the flow. - local region + REGIONS="UTC -" # not really a region, but the easiest to incorporate UTC in the flow. + region for region in $(grep '^[A-Z]' /usr/share/zoneinfo/zone.tab | cut -f 3 | sed -e 's#/.*##g'| sort -u); do REGIONS="$REGIONS $region -" done @@ -219,8 +219,8 @@ ask_timezone () return 0 fi region=$ANSWER_OPTION - local ZONES= - local zone + ZONES= + zone= for zone in $(grep '^[A-Z]' /usr/share/zoneinfo/zone.tab | grep $region/ | cut -f 3 | sed -e "s#$region/##g"| sort -u); do ZONES="$ZONES $zone -" done @@ -391,7 +391,7 @@ _dia_notify () _dia_inform () { - local str="$1" + str="$1" if [ "$2" != 0 ] then echo "$1" >> $LIBUI_DIA_SUCCESSIVE_ITEMS-$2 @@ -404,17 +404,17 @@ _dia_inform () _dia_ask_checklist () { - local str=$1 - local elaborate=$2 + str=$1 + elaborate=$2 shift 2 - local list=() + list=() while [ -n "$1" ] do [ -z "$2" ] && die_error "no item given for element $1" [ -z "$3" ] && die_error "no ON/OFF switch given for element $1 (item $2)" [ "$3" = ON -o "$3" = OFF ] || die_error "element $1 (item $2) has status $3 instead of ON/OFF!" - list+=("$1" "$2" $3) - [ $elaborate -gt 0 ] && list+=("$4") # this can be an empty string, that's ok. + list=("${list[@]}" "$1" "$2" $3) + [ $elaborate -gt 0 ] && list=("${list[@]}" "$4") # this can be an empty string, that's ok. shift 3 [ $elaborate -gt 0 ] && shift done @@ -422,15 +422,16 @@ _dia_ask_checklist () # but it doesn't. there really is no good way to separate items currently # let's assume there are no newlines in the item tags ANSWER_CHECKLIST=() - local elab='' + elab= [ $elaborate -gt 0 ] && elab='--item-help' - local line + line= while read -r line do - ANSWER_CHECKLIST+=("$line") + ANSWER_CHECKLIST=("${ANSWER_CHECKLIST[@]}" "$line") done < <(_dia_dialog --separate-output $elab --checklist "$str" 0 0 0 "${list[@]}") - local ret=$? + ret=$? debug 'UI' "_dia_ask_checklist: user checked ON: ${ANSWER_CHECKLIST[@]}" + #[ "${#ANSWER_CHECKLIST[@]}" = 0 ] && return 1 return $ret } @@ -438,7 +439,7 @@ _dia_ask_checklist () _dia_ask_datetime () { # display and ask to set date/time - local _date _time + _date _time _date=$(_dia_dialog --calendar "Set the date.\nUse to navigate and arrow keys to change values." 0 0 0 0 0) || return 1 # form like: 07/12/2008 _time=$(_dia_dialog --timebox "Set the time.\nUse to navigate and up/down to change values." 0 0) || return 1 # form like: 15:26:46 debug 'UI' "Date as specified by user $_date time: $_time" @@ -455,13 +456,13 @@ _dia_ask_number () #TODO: i'm not entirely sure this works perfectly. what if user doesnt give anything or wants to abort? while true do - local str="$1" - local str2 + str="$1" + str2= [ -n $2 ] && str2="min $2" [ -n $3 -a $3 != '0' ] && str2="$str2 max $3" [ -n "$str2" ] && str="$str ( $str2 )" ANSWER_NUMBER=$(_dia_dialog --inputbox "$str" 0 0 $4) - local ret=$? + ret=$? if [[ $ANSWER_NUMBER = *[^0-9]* ]] #TODO: handle exit state then show_warning 'Invalid number input' "$ANSWER_NUMBER is not a number! try again." @@ -485,16 +486,16 @@ _dia_ask_number () _dia_ask_option () { - local DEFAULT="" + DEFAULT= [ "$1" != 'no' ] && DEFAULT="--default-item $1" - local DIA_MENU_TITLE=$2 - local EXTRA_INFO=$3 - local TYPE=${4:-required} + DIA_MENU_TITLE=$2 + EXTRA_INFO=$3 + TYPE=${4:-required} shift 4 - local CANCEL_LABEL=Cancel + CANCEL_LABEL=Cancel [ $TYPE == optional ] && CANCEL_LABEL='Skip' ANSWER_OPTION=$(_dia_dialog $DEFAULT --cancel-label $CANCEL_LABEL --colors --title " $DIA_MENU_TITLE " --menu "$LIBUI_DIA_MENU_TEXT $EXTRA_INFO" 0 0 0 "$@") - local ret=$? + ret=$? debug 'UI' "dia_ask_option: ANSWER_OPTION: $ANSWER_OPTION, returncode (skip/cancel): $ret ($DIA_MENU_TITLE)" [ $TYPE == required ] && return $ret return 0 # TODO: check if dialog returned >0 because of an other reason then the user hitting 'cancel/skip' @@ -503,18 +504,18 @@ _dia_ask_option () _dia_ask_password () { - local type_l= - local type_u= + type_l= + type_u= if [ -n "$1" ] then type_l=`tr '[:upper:]' '[:lower:]' <<< $1` type_u=`tr '[:lower:]' '[:upper:]' <<< $1` fi - local ANSWER=$(_dia_dialog --passwordbox "Enter your $type_l password" 8 65 "$2") - local ret=$? - local ${type_u}_PASSWORD - local PASSWORD + ANSWER=$(_dia_dialog --passwordbox "Enter your $type_l password" 8 65 "$2") + ret=$? + ${type_u}_PASSWORD= + PASSWORD= [ -n "$type_u" ] && read ${type_u}_PASSWORD <<< $ANSWER [ -z "$type_u" ] && PASSWORD=$ANSWER echo $ANSWER @@ -525,9 +526,9 @@ _dia_ask_password () _dia_ask_string () { - local exitcode=${3:-1} + exitcode=${3:-1} ANSWER_STRING=$(_dia_dialog --inputbox "$1" 0 0 "$2") - local ret=$? + ret=$? debug 'UI' "_dia_ask_string: user entered $ANSWER_STRING" [ -z "$ANSWER_STRING" ] && return $exitcode return $ret @@ -536,20 +537,20 @@ _dia_ask_string () _dia_ask_string_multiple () { - local MAXRESPONSE=0 - local formtitle="$1" - local exitcode="${2:-1}" + MAXRESPONSE=0 + formtitle="$1" + exitcode="${2:-1}" shift 2 - local items=() - local line=1 - unset m; local i=0 + items=() + line=1 + unset m; i=0 while [ -n "$1" ] do [ -z "$2" ] && die_error "No default value for $1" # format: Label Y X Value Y X display-size value-size - items+=("$1" $line 1 "$2" $line 20 20 $MAXRESPONSE) + items=("${items[@]}" "$1" $line 1 "$2" $line 20 20 $MAXRESPONSE) let line++ shift 2 done @@ -557,20 +558,23 @@ _dia_ask_string_multiple () ANSWER_VALUES=() while read -r line do - ANSWER_VALUES+=("$line") + ANSWER_VALUES=("${ANSWER_VALUES[@]}" "$line") done < <(_dia_dialog --form "$formtitle" 15 50 0 "${items[@]}") + ret=$? + debug 'UI' "_dia_ask_string_multiple: user entered ${ANSWER_VALUES[@]}" + return $ret } _dia_ask_yesno () { - local default + default= str=$1 # If $2 contains an explicit 'no' we set defaultno for yesno dialog [ "$2" == "no" ] && default="--defaultno" dialog $default --yesno "$str" 0 0 # returns 0 for yes, 1 for no - local ret=$? + ret=$? [ $ret -eq 0 ] && debug 'UI' "dia_ask_yesno: User picked YES" [ $ret -gt 0 ] && debug 'UI' "dia_ask_yesno: User picked NO" return $ret @@ -579,8 +583,8 @@ _dia_ask_yesno () # sets FOLLOW_PID to the pid of dialog, so you can kill dialog when you no longer want to "tail" _dia_follow_progress () { - local title=$1 - local logfile=$2 + title=$1 + logfile=$2 _dia_dialog --title "$1" --no-kill --tailboxbg "$2" 0 0 >$LIBUI_FOLLOW_PID FOLLOW_PID=`cat $LIBUI_FOLLOW_PID` @@ -623,11 +627,11 @@ _cli_inform () _cli_ask_checklist () { - local str=$1 - local elaborate=$2 + str=$1 + elaborate=$2 shift 2 ANSWER_CHECKLIST=() - local adv=0 + adv=0 if [ -n "$9" ] then # if we have more then 2 elements, switch to advanced mode where we create a tmp file, and put all elements on a separate line @@ -635,12 +639,12 @@ _cli_ask_checklist () # to check for a 3rd element we use field 9. remember elaborate_expl field is optional, and when given can be zero-length. so input could be one of: # t1 i1 ON|OFF '' t2 i2 ON|OFF '' t3 i3 ON|OFF '' # t1 i1 ON|OFF t2 i2 ON|OFF t3 i3 ON|OFF - local adv=1 && seteditor || return 1 - local tmpfile=$(mktemp --tmpdir=$LIBUI_TMP_DIR _cli_ask_checklist-data.XXXX) || return 1 + adv=1 && seteditor || return 1 + tmpfile=$(mktemp --tmpdir=$LIBUI_TMP_DIR _cli_ask_checklist-data.XXXX) || return 1 echo "Comment sign in front of a line indicates OFF-setting." >> $tmpfile echo "Edit this file, when done, just exit the editor" >> $tmpfile echo >> $tmpfile - local allowed_tags=() + allowed_tags=() fi declare -A defaults defaults['ON']=yes @@ -650,16 +654,16 @@ _cli_ask_checklist () [ -z "$2" ] && die_error "no item given for element $1" [ -z "$3" ] && die_error "no ON/OFF switch given for element $1 (item $2)" [ "$3" != ON -a "$3" != OFF ] && die_error "element $1 (item $2) has status $3 instead of ON/OFF!" - local item=$1 - local elab= + item=$1 + elab= [ $elaborate -gt 0 ] && elab=$4 [ "$2" != '-' -a "$2" != '^' ] && item="$1 ($2)" if [ $adv -eq 0 ] then [ -n "$elab" ] && elab="\n$elab" - ask_yesno "Enable $1 ?$elab" ${defaults[$3]} && ANSWER_CHECKLIST+=("$1") + ask_yesno "Enable $1 ?$elab" ${defaults[$3]} && ANSWER_CHECKLIST=("${ANSWER_CHECKLIST[@]}" "$1") else - local allowed_tags+=($1) + allowed_tags=("${allowed_tags[@]}" "$1") [ "$3" = OFF ] && echo -n '#' >> $tmpfile echo "$item $elab" >> $tmpfile fi @@ -671,7 +675,7 @@ _cli_ask_checklist () $EDITOR $tmpfile || return 1 for i in $(grep -v ^# $tmpfile | cut -d' ' -f1) do - check_is_in "$i" "${allowed_tags[@]}" && ANSWER_CHECKLIST+=("$i") + check_is_in "$i" "${allowed_tags[@]}" && ANSWER_CHECKLIST=("${ANSWER_CHECKLIST[@]}" "$i") done fi return 0 @@ -723,12 +727,12 @@ _cli_ask_option () { #TODO: strip out color codes #TODO: if user entered incorrect choice, ask him again - local DEFAULT= + DEFAULT= [ "$1" != 'no' ] && DEFAULT=$1 - local MENU_TITLE=$2 - local EXTRA_INFO=$3 - local TYPE=${4:-required} + MENU_TITLE=$2 + EXTRA_INFO=$3 + TYPE=${4:-required} shift 4 echo "$MENU_TITLE" @@ -739,13 +743,13 @@ _cli_ask_option () echo "$1 ] $2" shift 2 done - local CANCEL_LABEL=CANCEL + CANCEL_LABEL=CANCEL [ $TYPE == optional ] && CANCEL_LABEL=SKIP echo "$CANCEL_LABEL ] $CANCEL_LABEL" [ -n "$DEFAULT" ] && echo -n " > [ $DEFAULT ] " [ -z "$DEFAULT" ] && echo -n " > " read ANSWER_OPTION - local ret=0 + ret=0 [ -z "$ANSWER_OPTION" -a -n "$DEFAULT" ] && ANSWER_OPTION="$DEFAULT" [ "$ANSWER_OPTION" == CANCEL ] && ret=1 && ANSWER_OPTION= [ "$ANSWER_OPTION" == SKIP ] && ret=0 && ANSWER_OPTION= @@ -758,8 +762,8 @@ _cli_ask_option () _cli_ask_password () { - local type_l= - local type_u= + type_l= + type_u= if [ -n "$1" ] then type_l=`tr '[:upper:]' '[:lower:]' <<< $1` @@ -778,7 +782,7 @@ _cli_ask_password () # $3 -z string behavior: always take default if applicable, but if no default then $3 is the returncode (1 is default) _cli_ask_string () { - local exitcode=${3:-1} + exitcode=${3:-1} echo "$1: " [ -n "$2" ] && echo "(Press enter for default. Default: $2)" echo -n ">" @@ -799,11 +803,11 @@ _cli_ask_string () _cli_ask_string_multiple () { echo "$1" - local exitcode=${2:-1} + exitcode=${2:-1} shift 2 ANSWER_VALUES=() - local i=0 + i=0 while [ $# -gt 0 ]; do _cli_ask_string "$1" "$2" $exitcode ANSWER_VALUES[$i]="$ANSWER_STRING" @@ -818,7 +822,7 @@ _cli_ask_yesno () [ "$2" = yes ] && echo -ne "$1 (Y/n): " [ "$2" = no ] && echo -ne "$1 (y/N): " - local answer + answer= read answer answer=`tr '[:upper:]' '[:lower:]' <<< $answer` if [ "$answer" = y -o "$answer" = yes ] || [ -z "$answer" -a "$2" = yes ] @@ -834,8 +838,8 @@ _cli_ask_yesno () _cli_follow_progress () { - local title=$1 - local logfile=$2 + title=$1 + logfile=$2 echo "Title: $1" [ -n "$3" ] && tail -f $2 --pid=$3 [ -z "$3" ] && tail -f $2 From d39f73e2837d80cd29b86a43c698a6ad10f2a70e Mon Sep 17 00:00:00 2001 From: rtorres Date: Wed, 28 Nov 2012 11:32:02 -0500 Subject: [PATCH 3/4] minor bug fix --- libui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libui.sh b/libui.sh index 7472537..8e54fc1 100755 --- a/libui.sh +++ b/libui.sh @@ -208,7 +208,7 @@ debug () ask_timezone () { REGIONS="UTC -" # not really a region, but the easiest to incorporate UTC in the flow. - region + region= for region in $(grep '^[A-Z]' /usr/share/zoneinfo/zone.tab | cut -f 3 | sed -e 's#/.*##g'| sort -u); do REGIONS="$REGIONS $region -" done From 744fe8cc21d21a81184a45d30d4c9e39e197d189 Mon Sep 17 00:00:00 2001 From: rtorres Date: Tue, 22 Jan 2013 00:38:56 -0500 Subject: [PATCH 4/4] implementing progress-box support --- libui.sh | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libui.sh b/libui.sh index 8e54fc1..7332972 100755 --- a/libui.sh +++ b/libui.sh @@ -358,6 +358,15 @@ follow_progress () _${LIBUI_UI}_follow_progress "$@" } +# follow the progress of something by showing it's log, updating real-time. It does not need a physcal file to follow +# $1 title +follow_progress_inline () +{ + [ -z "$1" ] && die_error "follow_progress_inline needs a title!" + debug 'UI' "follow_progress_inline: $@" + [ `type -t _${LIBUI_UI}_follow_progress_inline` == function ] || die_error "_${LIBUI_UI}_follow_progress_inline is not a function" + _${LIBUI_UI}_follow_progress_inline "$@" +} @@ -603,7 +612,11 @@ _dia_follow_progress () } - +_dia_follow_progress_inline () +{ + title=$1 + _dia_dialog --progressbox "$1" 0 0 +} _cli_show_warning () { @@ -845,6 +858,12 @@ _cli_follow_progress () [ -z "$3" ] && tail -f $2 } +_cli_follow_progress_inline () +{ + title=$1 + echo "Title: $1" + cat +} libui_sh_init