diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5ff61fb29235d067024df3ab54e8aa00530820dd..b492393940ddf3f74963766cf93a1f977537c320 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,14 @@ stages: - test -tests: - image: ubuntu:16.04 +tests-bash-4.3: + image: bash:4.3 + script: + - ./test.sh + stage: test + +tests-bash-4.4: + image: bash:4.4 script: - ./test.sh stage: test diff --git a/bashopts.sh b/bashopts.sh index 7ea6187959b71294dbfb9aeee276bc832ff070e5..b05b1f378ee96eb0bfa25991ba1c1e1e38a4986c 100644 --- a/bashopts.sh +++ b/bashopts.sh @@ -75,19 +75,27 @@ if [ ! "${BASH_VERSINFO[0]}" -ge 4 ]; then bashopts_log C "bashopts require BASH version 4 or greater" fi -# extract the value part of a declaration ("the value") -bashopts_get_def() { - declare | grep "^$1=" | sed -E 's/^[^=]+=//g' - # NOTE: alternative but not working in some case...: - # declare -p $1 | sed -E "s/^declare\\s[^=]*=//g" -} - -# extract the full declaration (name="the value") -bashopts_get_def_full() { - declare | grep "^$1=" - # NOTE: alternative but not working in some case...: - # declare -p $1 | sed -E "s/^declare\\s[^=]*=/$1=/g" -} +if [ $((${BASH_VERSINFO[0]}*1000 + ${BASH_VERSINFO[1]})) -gt 4004 ]; then + # extract the value part of a declaration ("the value") + bashopts_get_def() { + declare -p $1 | sed --regexp-extended "s/^declare\\s[^=]*=//g" + } + + # extract the full declaration (name="the value") + bashopts_get_def_full() { + declare -p $1 | sed --regexp-extended "s/^declare\\s[^=]*=/$1=/g" + } +else + # extract the value part of a declaration ("the value") + bashopts_get_def() { + declare | grep "^$1=" | sed --regexp-extended 's/^[^=]+=//g' + } + + # extract the full declaration (name="the value") + bashopts_get_def_full() { + declare | grep "^$1=" + } +fi # check and format an option name value bashopts_check_opt_name() { @@ -108,7 +116,7 @@ bashopts_check_number() { echo $1 return 0 fi - bashopts_log E "Option $op: '$1' is not a valid number" + bashopts_log E "Option $property_name: '$1' is not a valid number" return 1 } @@ -124,7 +132,7 @@ bashopts_check_boolean() { return 0 ;; *) - bashopts_log E "Option $op: '$1' is not a valid boolean value" + bashopts_log E "Option $property_name: '$1' is not a valid boolean value" return 1 ;; esac @@ -146,8 +154,8 @@ bashopts_check_enumeration() { return 0 fi values+=("'${line##*|}'") - done <<< "${2:-${bashopts_optprop_enum_values[$op]}}" - bashopts_log E "Option $op: Invalid value '$1' (accepted values are: ${values[*]})" + done <<< "${2:-${bashopts_optprop_enum_values[$property_name]}}" + bashopts_log E "Option $property_name: Invalid value '$1' (accepted values are: ${values[*]})" return 1 } @@ -176,15 +184,14 @@ bashopts_tool_name=$0 # STEP 1: setup bashopts_setup() { local arg arglist no_default_opts non_interactive disable_interactive - if ! arglist=$(getopt -o "n:d:u:s:yxp" -n "$0 " -- "$@"); then + if ! arglist=$(getopt -o "n:d:u:s:yx" -n "$0 " -- "$@"); then bashopts_log C "Usage bashopts_setup:" \ " -n Tool name" \ " -d Tool description" \ " -u Tool usage description" \ " -s setting file path" \ " -y Set non interactive mode as the default mode" \ - " -x Disable entirely interactive mode" \ - " -p Force value storage even if the value is equal to the default one" + " -x Disable entirely interactive mode" fi eval set -- "$arglist"; # Store the global bashopts properties @@ -198,7 +205,6 @@ bashopts_setup() { -s) bashopts_tool_settings_path=$1; shift;; -y) non_interactive="true";; -x) disable_interactive="true";; - -p) bashopts_tool_settings_force_write="true";; --) break;; *) bashopts_log C "Fatal error";; esac @@ -277,8 +283,8 @@ bashopts_declare() { ;; e|enum|enumeration) options[type]="enumeration" - if [ ${#options_enum_values[@]} -lt 2 ]; then - bashopts_log C "bashopts_declare: ${options[name]} enumeration need at least two elements (two '-e ' calls at least)" + if [ ${#options_enum_values[@]} -lt 1 ]; then + bashopts_log C "bashopts_declare: ${options[name]} enumeration need at least one element (one '-e ' calls at least)" fi options[enum_values]="$(printf "%s\n" "${options_enum_values[@]}")" ;; @@ -354,23 +360,23 @@ bashopts_declare() { } bashopts_get_valid_value_list() { - local op + local property_name case "$1" in -*) - op=${bashopts_arg2op[$1]} + property_name=${bashopts_arg2op[$1]} ;; *) - op=$1 + property_name=$1 ;; esac - case "${bashopts_optprop_type[$op]}" in + case "${bashopts_optprop_type[$property_name]}" in boolean) echo -e "true\nfalse" ;; enumeration) while read -r line; do echo "\"${line##*|}\"" - done <<< "${bashopts_optprop_enum_values[$op]}" + done <<< "${bashopts_optprop_enum_values[$property_name]}" ;; esac } @@ -397,27 +403,27 @@ bashopts_join_by() { # dump an option value by its name bashopts_dump_value() { - local op=$1 + local property_name=$1 shift || bashopts_log C "Usage: bashopts_dump_value op_name" - [[ -v "$op" ]] || return 0 - if [ "${bashopts_optprop_method[$op]}" == "set" ]; then - if [ "${bashopts_optprop_type[$op]}" == "string" ]; then - echo -n "\"${!op//\"/\\\"}\"" + [[ -v "$property_name" ]] || return 0 + if [ "${bashopts_optprop_method[$property_name]}" == "set" ]; then + if [ "${bashopts_optprop_type[$property_name]}" == "string" ]; then + echo -n "\"${!property_name//\"/\\\"}\"" else - echo -n "${!op}" + echo -n "${!property_name}" fi return 0 fi - eval set -- \"\${${op}[@]}\" + eval set -- \"\${${property_name}[@]}\" echo -n "[" - if [ "${bashopts_optprop_type[$op]}" == "string" ]; then + if [ "${bashopts_optprop_type[$property_name]}" == "string" ]; then echo -n "\"${1//\"/\\\"}\"" else echo -n "${1}" fi shift while [ -n "$1" ]; do - if [ "${bashopts_optprop_type[$op]}" == "string" ]; then + if [ "${bashopts_optprop_type[$property_name]}" == "string" ]; then echo -n ", \"${1//\"/\\\"}\"" else echo -n ", ${1}" @@ -438,16 +444,20 @@ bashopts_display_help() { fi local value_max_len=$(( $ncol / 4 )) # compute the good arguments column size - for op in "${bashopts_optlist[@]}"; do + for property_name in "${bashopts_optlist[@]}"; do elts=() unset val - if ! [[ $op =~ ^__.*__$ ]] && [[ -v $op ]]; then - val=" $(bashopts_dump_value $op | tr -d '\n')" + if ! [[ $property_name =~ ^__.*__$ ]] && [[ -v $property_name ]]; then + val=" $(bashopts_dump_value $property_name | tr -d '\n')" fi - if [[ -v bashopts_optprop_short_opt[$op] ]]; then elts+=("-${bashopts_optprop_short_opt[$op]}"); fi - if [[ -v bashopts_optprop_long_opt[$op] ]]; then elts+=("--${bashopts_optprop_long_opt[$op]}"); fi - optargs[$op]="$(bashopts_join_by , ${elts[@]})${val:0:${value_max_len}}" - optargs_max_len=$(bashopts_math_max $optargs_max_len ${#optargs[$op]}) + if [[ -v bashopts_optprop_short_opt[$property_name] ]]; then + elts+=("-${bashopts_optprop_short_opt[$property_name]}"); + fi + if [[ -v bashopts_optprop_long_opt[$property_name] ]]; then + elts+=("--${bashopts_optprop_long_opt[$property_name]}"); + fi + optargs[$property_name]="$(bashopts_join_by , ${elts[@]})${val:0:${value_max_len}}" + optargs_max_len=$(bashopts_math_max $optargs_max_len ${#optargs[$property_name]}) done optargs_max_len=$(bashopts_math_min $optargs_max_len $(( $ncol / 3 )) ) # display global info @@ -459,29 +469,32 @@ bashopts_display_help() { echo -e " $bashopts_tool_usage" echo echo "OPTIONS:" - for op in "${bashopts_optlist[@]}"; do + for property_name in "${bashopts_optlist[@]}"; do # display arguments, value if available, description, and additional info if available - printf " %-${optargs_max_len}s ${bashopts_optprop_description[$op]}" "${optargs[$op]}" - if ! [[ $op =~ ^__.*__$ ]]; then + printf " %-${optargs_max_len}s ${bashopts_optprop_description[$property_name]}" "${optargs[$property_name]}" + if ! [[ $property_name =~ ^__.*__$ ]]; then # display additional information the each properties # discarding special options like --help - echo -n " - [\$$op] (type:${bashopts_optprop_type[$op]}" - if [[ -v bashopts_optprop_expression[$op] ]]; then - printf ", default: \"%.${value_max_len}s\"" "$(tr -d '\n' <<< "${bashopts_optprop_expression[$op]//\"/\\\"}")" - elif [[ -v bashopts_optprop_default[$op] ]]; then - if [[ "${bashopts_optprop_type[$op]}" =~ ^(string|enumeration)$ ]]; then - printf ", default: \"%.${value_max_len}s\"" "$(tr -d '\n' <<< "${bashopts_optprop_default[$op]//\"/\\\"}")" + echo -n " - [\$$property_name] (type:${bashopts_optprop_type[$property_name]}" + if [[ -v bashopts_optprop_expression[$property_name] ]]; then + printf ", default: \"%.${value_max_len}s\"" "$(tr -d '\n' \ + <<< "${bashopts_optprop_expression[$property_name]//\"/\\\"}")" + elif [[ -v bashopts_optprop_default[$property_name] ]]; then + if [[ "${bashopts_optprop_type[$property_name]}" =~ ^(string|enumeration)$ ]]; then + printf ", default: \"%.${value_max_len}s\"" "$(tr -d '\n' \ + <<< "${bashopts_optprop_default[$property_name]//\"/\\\"}")" else - printf ", default: %.${value_max_len}s" "$(tr -d '\n' <<< "${bashopts_optprop_default[$op]}")" + printf ", default: %.${value_max_len}s" "$(tr -d '\n' \ + <<< "${bashopts_optprop_default[$property_name]}")" fi else elts=")" fi - if [ "${bashopts_optprop_type[$op]}" == "enumeration" ]; then + if [ "${bashopts_optprop_type[$property_name]}" == "enumeration" ]; then echo -n ", accepted values:$( while read -r line; do echo -n " '${line##*|}'" - done <<< "${bashopts_optprop_enum_values[$op]}" + done <<< "${bashopts_optprop_enum_values[$property_name]}" )" fi echo ")" @@ -499,7 +512,7 @@ bashopts_display_help_delayed() { # display all otions values and properties bashopts_display_summary() { - local elts desc_max_len=0 val dval ncol + local elts desc_max_len=0 val default_value ncol if tput cols &> /dev/null; then ncol=$(tput cols) else @@ -507,19 +520,19 @@ bashopts_display_summary() { fi local value_max_len=$(( $ncol / 4 )) declare -A optargs - for op in "${bashopts_optlist[@]}"; do - desc_max_len=$(bashopts_math_max $desc_max_len ${#bashopts_optprop_description[$op]}) + for property_name in "${bashopts_optlist[@]}"; do + desc_max_len=$(bashopts_math_max $desc_max_len ${#bashopts_optprop_description[$property_name]}) done - for op in "${bashopts_optlist[@]}"; do - if ! [[ $op =~ ^__.*__$ ]]; then - printf "* %-${desc_max_len}.${value_max_len}s : $(bashopts_dump_value $op | tr -d '\n')\n" "${bashopts_optprop_description[$op]}" + for property_name in "${bashopts_optlist[@]}"; do + if ! [[ $property_name =~ ^__.*__$ ]]; then + printf "* %-${desc_max_len}.${value_max_len}s : $(bashopts_dump_value $property_name | tr -d '\n')\n" "${bashopts_optprop_description[$property_name]}" fi done } # STEP 3: parse arg bashopts_parse_args() { - local op arg val args is_arg short_opts long_opts + local property_name arg val args is_arg short_opts long_opts # split argument into two arrays: normal and extra arguments is_arg=1 @@ -536,12 +549,12 @@ bashopts_parse_args() { # build the long and short getopt option list from the options short_opts="" long_opts=() - for op in "${bashopts_optlist[@]}"; do - if [[ -v bashopts_optprop_short_opt[$op] ]]; then - short_opts="${short_opts}${bashopts_optprop_short_opt[$op]}:$(test "${bashopts_optprop_type[$op]}" != "boolean" || echo ":")" + for property_name in "${bashopts_optlist[@]}"; do + if [[ -v bashopts_optprop_short_opt[$property_name] ]]; then + short_opts="${short_opts}${bashopts_optprop_short_opt[$property_name]}:$(test "${bashopts_optprop_type[$property_name]}" != "boolean" || echo ":")" fi - if [[ -v bashopts_optprop_long_opt[$op] ]]; then - long_opts+=("${bashopts_optprop_long_opt[$op]}:$(test "${bashopts_optprop_type[$op]}" != "boolean" || echo ":")") + if [[ -v bashopts_optprop_long_opt[$property_name] ]]; then + long_opts+=("${bashopts_optprop_long_opt[$property_name]}:$(test "${bashopts_optprop_type[$property_name]}" != "boolean" || echo ":")") fi done long_opts=$(bashopts_join_by , ${long_opts[@]}) @@ -565,26 +578,26 @@ bashopts_parse_args() { -*) val="$1" shift - op=${bashopts_arg2op[$arg]} + property_name=${bashopts_arg2op[$arg]} if [ -z "$val" ]; then - if [ "${bashopts_optprop_type[$op]}" == "boolean" ]; then + if [ "${bashopts_optprop_type[$property_name]}" == "boolean" ]; then # boolean argument with no value is considered as true val="true" else # empty value tell to unset the value or clear the array - unset $op + unset $property_name continue fi fi - val="$(${bashopts_optprop_check[$op]} "$val")" || exit 1 - case "${bashopts_optprop_method[$op]}" in + val="$(${bashopts_optprop_check[$property_name]} "$val")" || exit 1 + case "${bashopts_optprop_method[$property_name]}" in set) # normal case: override the value - eval "$op=$(declare -p val | sed -E 's/^declare\s[^=]*=//g')" + eval "$property_name=$(declare -p val | sed --regexp-extended 's/^declare\s[^=]*=//g')" ;; add) # array case: add the value - eval "$op+=($(declare -p val | sed -E 's/^declare\s[^=]*=//g'))" + eval "$property_name+=($(declare -p val | sed --regexp-extended 's/^declare\s[^=]*=//g'))" ;; esac ;; @@ -631,12 +644,13 @@ bashopts_read_json_array() { # Process a specified option bashopts_process_option() { - local dval tval ival op arg arglist check val_req edit_req - if ! arglist=$(getopt -o "n:k:r" -n "bashopts_process_option " -- "$@"); then + local default_value staging_value input_value property_name arg arglist check val_req edit_req + if ! arglist=$(getopt -o "n:k:ri" -n "bashopts_process_option " -- "$@"); then bashopts_log C "Usage bashopts_process_opt" \ " -n property name" \ " -k override value check function" \ - " -r At least one value required" + " -r At least one value required" \ + " -i Enable interactive mode" fi eval set -- "$arglist"; # parse all the parameters @@ -644,48 +658,53 @@ bashopts_process_option() { arg=$1 shift case "$arg" in - -n) op=$1; shift;; + -n) property_name=$1; shift;; -k) check=$1; shift;; -r) val_req="true";; + -i) edit_req="true";; --) break;; - *) bashopts_log C "Fatal error";; + *) bashopts_log C "Option $property_name: Fatal error";; esac done - test -n "$op" || \ - bashopts_log C "bashopts_process_option: missing -n option" + test -n "$property_name" || \ + bashopts_log C "Option $property_name: bashopts_process_option: missing -n option" + [[ -v bashopts_optprop_type[$property_name] ]] || \ + bashopts_log C "Invanid option: $property_name" + # Init edit_req + : ${edit_req:=${bashopts_optprop_interactive[$property_name]}} if [ -z "$check" ]; then - check="${bashopts_optprop_check[$op]}" + check="${bashopts_optprop_check[$property_name]}" fi - if [ "${bashopts_optprop_req_value[$op]}" == "true" ]; then + if [ "${bashopts_optprop_req_value[$property_name]}" == "true" ]; then val_req="true" fi # eval or get default value - if [[ -v bashopts_optprop_expression[$op] ]]; then - eval "dval=${bashopts_optprop_expression[$op]}" - elif [ "${bashopts_optprop_method[$op]}" == "add" ]; then - dval=() + if [[ -v bashopts_optprop_expression[$property_name] ]]; then + eval "default_value=${bashopts_optprop_expression[$property_name]}" + elif [ "${bashopts_optprop_method[$property_name]}" == "add" ]; then + default_value=() else - dval="${bashopts_optprop_default[$op]}" + default_value="${bashopts_optprop_default[$property_name]}" fi - # Init edit_req - edit_req=${bashopts_optprop_interactive[$op]} - if [[ -v $op ]]; then + if [[ -v $property_name ]]; then # Extract value from option name - eval "tval=$(bashopts_get_def $op)" - # Edition no more really required if already defined - edit_req="false" - elif [ "${bashopts_optprop_setting[$op]}" == "true" ] \ - && [ -f "$(readlink -m "$bashopts_tool_settings_path")" ] \ - && grep -E -q "^$op=" $bashopts_tool_settings_path; then - eval "tval=$(grep -E "^${op}=" $bashopts_tool_settings_path | sed -E "s/^[^=]+=//g")" + eval "staging_value=$(bashopts_get_def $property_name)" + elif [ "${bashopts_optprop_setting[$property_name]}" == "true" ]; then + if [ -z "$bashopts_settings_hook_get" ] \ + || ! $bashopts_settings_hook_get "$property_name"; then + test ! -r "$bashopts_tool_settings_path" \ + || eval "$(sed --regexp-extended \ + 's/^'"$property_name"'=(.*)|.*$/\1/g; /^$/d; s/^(.*)$/staging_value=\1/g' \ + "$bashopts_tool_settings_path")" + fi fi - if [[ -v tval ]]; then + if [[ -v staging_value ]]; then # Check current value(s) - for (( i=0; i<${#tval[@]}; i++)); do - if ! $check "${tval[$i]}" > /dev/null; then + for (( i=0; i<${#staging_value[@]}; i++)); do + if ! $check "${staging_value[$i]}" > /dev/null; then if [ "$BASHOPTS_INTERACTIVE" != "true" ]; then - bashopts_log C "Non interactive mode: Exit due to one or more error" + bashopts_log C "Option $property_name: Non interactive mode: Exit due to one or more error" fi # (re)enable edition edit_req="true" @@ -693,86 +712,86 @@ bashopts_process_option() { fi done elif [ "$val_req" == "true" ] && [ "$__BASHOPTS_DISPLAY_HELP__" != "true" ]; then - bashopts_log E "At least one value required" + bashopts_log E "Option $property_name: At least one value required" if [ "$BASHOPTS_INTERACTIVE" != "true" ]; then - bashopts_log C "Non interactive mode: Exit due to one or more error" + bashopts_log C "Option $property_name: Non interactive mode: Exit due to one or more error" fi # (re)enable edition edit_req="true" fi - if ! [[ -v tval ]] || [ "$edit_req" == "true" ]; then - if [[ ! -v tval ]] && [ -n "$dval" ]; then + if ! [[ -v staging_value ]] || [ "$edit_req" == "true" ]; then + if [[ ! -v staging_value ]] && [ -n "$default_value" ]; then # set default value - eval "tval=$(bashopts_get_def dval)" + eval "staging_value=$(bashopts_get_def default_value)" fi if [ "$edit_req" == "true" ]; then if [ "$BASHOPTS_INTERACTIVE" == "true" ]; then # interactive edition while true; do # Display the property description - echo "* ${bashopts_optprop_description[$op]}$( + echo "* ${bashopts_optprop_description[$property_name]}$( # Add possible value list for enumeration type - if [ "${bashopts_optprop_type[$op]}" == "enumeration" ]; then + if [ "${bashopts_optprop_type[$property_name]}" == "enumeration" ]; then echo -n " (accepted values:$( while read -r line; do echo -n " '${line##*|}'" - done <<< "${bashopts_optprop_enum_values[$op]}" + done <<< "${bashopts_optprop_enum_values[$property_name]}" )" echo -n ")" fi )" # Add info for array properties - if [ "${bashopts_optprop_method[$op]}" == "add" ]; then + if [ "${bashopts_optprop_method[$property_name]}" == "add" ]; then echo " -> List property format: 'single val.' or BASH array '(v1 v2 v3)' or JSON array '[v1, v2, v3]'" fi - echo -n " $(bashopts_dump_array {bashopts_optprop_type[$op]} "${tval[@]}"): " - read ival || bashopts_log C "Unexpected error, aborting..." - if [ -n "$ival" ]; then - if [ "${bashopts_optprop_method[$op]}" == "add" ]; then + echo -n " $(bashopts_dump_array {bashopts_optprop_type[$property_name]} "${staging_value[@]}"): " + read input_value || bashopts_log C "Option $property_name: Unexpected error, aborting..." + if [ -n "$input_value" ]; then + if [ "${bashopts_optprop_method[$property_name]}" == "add" ]; then # array value - tval=() - case "${ival:0:1}" in + staging_value=() + case "${input_value:0:1}" in '[') - bashopts_read_json_array tval "$ival" || continue + bashopts_read_json_array staging_value "$input_value" || continue ;; '(') - if ! eval "tval=$ival" 2>/dev/null; then - bashopts_log E "Invalid BASH array" + if ! eval "staging_value=$input_value" 2>/dev/null; then + bashopts_log E "Option $property_name: Invalid BASH array" continue fi ;; *) - tval+=("$ival") + staging_value+=("$input_value") ;; esac else # non array/normal value - tval=$ival + staging_value=$input_value fi - elif [ "${bashopts_optprop_method[$op]}" == "add" ] && ! [[ -v tval ]]; then - tval=() + elif [ "${bashopts_optprop_method[$property_name]}" == "add" ] && ! [[ -v staging_value ]]; then + staging_value=() fi # check format - if [ "${#tval[@]}" -eq 0 ] && [ "$val_req" == "true" ]; then - bashopts_log E "At least one value required" - unset tval + if [ "${#staging_value[@]}" -eq 0 ] && [ "$val_req" == "true" ]; then + bashopts_log E "Option $property_name: At least one value required" + unset staging_value continue fi - if [ "${bashopts_optprop_method[$op]}" == "add" ]; then + if [ "${bashopts_optprop_method[$property_name]}" == "add" ]; then # array value - for (( i=0; i<${#tval[@]}; i++)); do - if ! tval[$i]="$($check "${tval[$i]}")"; then - unset tval + for (( i=0; i<${#staging_value[@]}; i++)); do + if ! staging_value[$i]="$($check "${staging_value[$i]}")"; then + unset staging_value break fi done else # non array/normal value - if ! tval="$($check "$tval")"; then - unset tval + if ! staging_value="$($check "$staging_value")"; then + unset staging_value fi fi - if declare -p tval > /dev/null 2>&1; then + if [[ -v staging_value ]]; then # edit OK, break break fi @@ -781,31 +800,26 @@ bashopts_process_option() { fi fi fi - if [[ -v tval ]]; then - eval "$op=$(bashopts_get_def tval)" - fi - if [ "${bashopts_optprop_setting[$op]}" == "true" ]; then - if [ -n "$bashopts_tool_settings_path" ]; then - # vrite the value to the setting file - ( - test -d "$(dirname $bashopts_tool_settings_path)" || \ - mkdir -p "$(dirname $bashopts_tool_settings_path)" - if [ -f "$bashopts_tool_settings_path" ]; then - # remove old value - sed -i "/^$op=/d" $bashopts_tool_settings_path - fi - if [ "$bashopts_tool_settings_force_write" == "true" ] \ - || [ "$(bashopts_get_def $op)" != "$(bashopts_get_def dval)" ]; then - # append the new value to the file if the value is not the default or - # force_write is true - echo "$(bashopts_get_def_full $op)" >> $bashopts_tool_settings_path + if [[ -v staging_value ]]; then + local op_full_def + op_full_def="$property_name=$(bashopts_get_def staging_value)" + eval "$op_full_def" + if [ "${bashopts_optprop_setting[$property_name]}" == "true" ]; then + if [ -z "$bashopts_settings_hook_set" ] || ! $bashopts_settings_hook_set "$property_name"; then + if [ -n "$bashopts_tool_settings_path" ]; then + if [ -r "$bashopts_tool_settings_path" ]; then + sed -i --regexp-extended '/^'"$property_name"'=.*/d' "$bashopts_tool_settings_path" + fi + mkdir -p "$(dirname "$bashopts_tool_settings_path")" \ + && echo "$op_full_def" >> "$bashopts_tool_settings_path" \ + || bashopts_log W "Option $property_name: Please check the settings file" + else + bashopts_log W "Option $property_name: No settings file specified" fi - ) || bashopts_log W "Please check the settings file" - else - bashopts_log W "No settings file specified" + fi fi fi - if [ "$op" == "BASHOPTS_NON_INTERACTIVE" ] && ! [[ -v BASHOPTS_INTERACTIVE ]]; then + if [ "$property_name" == "BASHOPTS_NON_INTERACTIVE" ] && ! [[ -v BASHOPTS_INTERACTIVE ]]; then if [ "$BASHOPTS_NON_INTERACTIVE" == "true" ]; then BASHOPTS_INTERACTIVE="false" else @@ -816,12 +830,12 @@ bashopts_process_option() { # STEP 4: process arg bashopts_process_opts() { - local op + local property_name if [ "$__BASHOPTS_DISPLAY_HELP__" == "true" ]; then BASHOPTS_INTERACTIVE="false" fi - for op in "${bashopts_optlist[@]}"; do - bashopts_process_option -n $op + for property_name in "${bashopts_optlist[@]}"; do + bashopts_process_option -n $property_name done if [ "$__BASHOPTS_DISPLAY_HELP__" == "true" ]; then bashopts_display_help @@ -831,9 +845,9 @@ bashopts_process_opts() { # Export all option variables bashopts_export_opts() { - for op in "${bashopts_optlist[@]}"; do - if [[ -v $op ]]; then - export $op + for property_name in "${bashopts_optlist[@]}"; do + if [[ -v $property_name ]]; then + export $property_name fi done } diff --git a/test.sh b/test.sh index c8d609a15d376e4c30deec3ee77af5523d592916..a55815e2990aeba7fec05c9f994e9b08a6d90013 100755 --- a/test.sh +++ b/test.sh @@ -1,4 +1,4 @@ -#!/bin/bash -e +#!/usr/bin/env bash # Copyright 2017-2018 Emeric Verschuur # # Licensed to the Apache Software Foundation (ASF) under one @@ -18,6 +18,8 @@ # specific language governing permissions and limitations # under the License. +set -e + . bashopts.sh trap 'bashopts_exit_handle' ERR @@ -47,14 +49,14 @@ _test_case_2() { bashopts_setup -n "$0" -d "Test case $0" -s /tmp/bashopts_testrc - bashopts_declare -n base_path -l base -o b -d "Base path" -t string -v "/opt/test" -i -s + bashopts_declare -n base_path -l base -o b -d "Base path" -t string -v "/opt/test" -i bashopts_declare -n config_path -l config -o c -d "Configuration path" -t string -x "\$base_path/myconf.cfg" -s bashopts_parse_args --base /tmp -n bashopts_process_opts req_test_eq "$config_path" "/tmp/myconf.cfg" - req_test_eq "$(cat /tmp/bashopts_testrc)" "base_path=/tmp" + req_test_eq "$(cat /tmp/bashopts_testrc)" "config_path=/tmp/myconf.cfg" } _test_case_3() { @@ -155,7 +157,7 @@ _test_case_10() { bashopts_declare -n simple_val -s -l value -d "Simple value" -t string -v 'val' bashopts_parse_args --value=test - req_test_eq "$(bashopts_process_opts 2>&1)" "[WARN] No settings file specified" + req_test_eq "$(bashopts_process_opts 2>&1)" "[WARN] Option simple_val: No settings file specified" } _test_case_11() { @@ -164,7 +166,7 @@ _test_case_11() { bashopts_declare -n simple_val -s -l value -d "Simple value" -t string -v 'val' bashopts_parse_args --value=test - req_test_eq "$(bashopts_process_opts 2>&1 | grep 'WARN')" "[WARN] Please check the settings file" + req_test_eq "$(bashopts_process_opts 2>&1 | grep 'WARN')" "[WARN] Option simple_val: Please check the settings file" } _test_case_12() { @@ -235,37 +237,6 @@ _test_case_15() { req_test_eq "$(cat /tmp/bashopts_testrc)" 'array_value=([0]="value 1" [1]="value 3")' } -_test_case_16() { - rm -f /tmp/bashopts_testrc - bashopts_setup -n "$0" -d "Test case $0" -s /tmp/bashopts_testrc - - bashopts_declare -n array_value -l value -m add -d "Array value" -s -i -t string -x '("value 1" "value 2")' - - bashopts_parse_args --value "" - bashopts_process_opts > /dev/null <<< '( "value 1" "value 2" )' - - req_test_eq "${#array_value[@]}" "2" - req_test_eq "${array_value[0]}" "value 1" - req_test_eq "${array_value[1]}" "value 2" - if [ -f /tmp/bashopts_testrc ]; then - echo "file /tmp/bashopts_testrc should not be present" - exit 1 - fi -} - -_test_case_17() { - rm -f /tmp/bashopts_testrc - bashopts_setup -n "$0" -d "Test case $0" -s /tmp/bashopts_testrc -p - - bashopts_declare -n a_value -l value -d "A value" -s -i -t string -v "default value" - - bashopts_parse_args - bashopts_process_opts > /dev/null <<< "" - - req_test_eq "$a_value" "default value" - req_test_eq "$(cat /tmp/bashopts_testrc)" "a_value='default value'" -} - _test_case_18() { bashopts_setup -n "$0" -d "Test case $0" @@ -310,7 +281,7 @@ _test_case_20() { req_test_eq "$(echo "$(bashopts_process_option -n value -k is_eq_to_null -r 2>&1 > /dev/null <<< "na")" \ | grep '^\[ERR' | tail -n 1 || true)" '[ERRO] Not equal to NULL' req_test_eq "$(echo "$(bashopts_process_option -n value -k is_eq_to_null -r 2>&1 > /dev/null <<< "()")" \ - | grep '^\[ERR' | tail -n 1 || true)" '[ERRO] At least one value required' + | grep '^\[ERR' | tail -n 1 || true)" '[ERRO] Option value: At least one value required' bashopts_process_option -n value -k is_eq_to_null -r > /dev/null 2>&1 <<< "NULL" } @@ -322,7 +293,7 @@ _test_case_21() { bashopts_parse_args -n bashopts_process_opts req_test_eq "$(echo "$(bashopts_process_option -n value -k is_not_empty -r 2>&1 > /dev/null)" \ - | grep '^\[ERR' | head -n 1)" '[ERRO] At least one value required' + | grep '^\[ERR' | head -n 1)" '[ERRO] Option value: At least one value required' } _test_case_22() { @@ -351,9 +322,10 @@ _test_case_24() { bashopts_parse_args bashopts_process_opts + # NOTE: Fix answer again after a is_eq_to_null check failure req_test_eq "$( (bashopts_process_option -n value -k is_eq_to_null -r 2>&1 <<< "NUL" \ - || true) | grep -E '^* A str value$' | wc -l )" "2" + || true) | grep '^* A str value$' | wc -l )" "2" } _test_case_25() { @@ -362,7 +334,7 @@ _test_case_25() { bashopts_declare -n value -l value -d "A str value" -t string -r req_test_eq "$( (bashopts_process_opts 2>&1 <<< "" \ - || true) | grep -E '^* A str value$' | wc -l )" "2" + || true) | grep '^* A str value$' | wc -l )" "2" } _test_case_26() {