mirror of
https://github.com/kvz/bash3boilerplate.git
synced 2024-12-19 22:57:51 +00:00
Merge pull request #73 from mstreuhofer/usage-validation
Added automatic usage validation for required args Thanks again for another wonderful contribution, @mstreuhofer!
This commit is contained in:
commit
02cb82c9e6
50
main.sh
50
main.sh
@ -159,28 +159,34 @@ while read -r __b3bp_tmp_line; do
|
|||||||
__b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
|
__b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# map long name back to short name
|
# map opt long name to+from opt short name
|
||||||
printf -v "__b3bp_tmp_short_opt_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}"
|
printf -v "__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}"
|
||||||
|
printf -v "__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt}" '%s' "${__b3bp_tmp_long_opt//-/_}"
|
||||||
|
|
||||||
# check if option takes an argument
|
# check if option takes an argument
|
||||||
if [[ ! "${__b3bp_tmp_line}" =~ \[.*\] ]]; then
|
if [[ "${__b3bp_tmp_line}" =~ \[.*\] ]]; then
|
||||||
__b3bp_tmp_init="0" # it's a flag. init with 0
|
|
||||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0"
|
|
||||||
else
|
|
||||||
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
||||||
__b3bp_tmp_init="" # it has an arg. init with ""
|
__b3bp_tmp_init="" # it has an arg. init with ""
|
||||||
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1"
|
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1"
|
||||||
|
elif [[ "${__b3bp_tmp_line}" =~ \{.*\} ]]; then
|
||||||
|
__b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
|
||||||
|
__b3bp_tmp_init="" # it has an arg. init with ""
|
||||||
|
# remember that this option requires an argument
|
||||||
|
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||||
|
else
|
||||||
|
__b3bp_tmp_init="0" # it's a flag. init with 0
|
||||||
|
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0"
|
||||||
fi
|
fi
|
||||||
__b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}"
|
__b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -z "${__b3bp_tmp_opt:-}" ] && continue
|
[ -z "${__b3bp_tmp_opt:-}" ] && continue
|
||||||
|
|
||||||
if [[ "${__b3bp_tmp_line}" =~ \.\ Default ]]; then
|
if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Default= ]]; then
|
||||||
# ignore default value if option does not have an argument
|
# ignore default value if option does not have an argument
|
||||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}"
|
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}"
|
||||||
|
|
||||||
if [ "${!__b3bp_tmp_varname}" = "1" ]; then
|
if [ "${!__b3bp_tmp_varname}" != "0" ]; then
|
||||||
__b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
|
__b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
|
||||||
__b3bp_tmp_re='^"(.*)"$'
|
__b3bp_tmp_re='^"(.*)"$'
|
||||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||||
@ -194,6 +200,11 @@ while read -r __b3bp_tmp_line; do
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Required\. ]]; then
|
||||||
|
# remember that this option requires an argument
|
||||||
|
printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
|
||||||
|
fi
|
||||||
|
|
||||||
printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}"
|
printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}"
|
||||||
done <<< "${__usage:-}"
|
done <<< "${__usage:-}"
|
||||||
|
|
||||||
@ -218,13 +229,13 @@ if [ -n "${__b3bp_tmp_opts:-}" ]; then
|
|||||||
# --key=value format
|
# --key=value format
|
||||||
__b3bp_tmp_long_opt=${OPTARG/=*/}
|
__b3bp_tmp_long_opt=${OPTARG/=*/}
|
||||||
# Set opt to the short option corresponding to the long option
|
# Set opt to the short option corresponding to the long option
|
||||||
__b3bp_tmp_varname="__b3bp_tmp_short_opt_${__b3bp_tmp_long_opt//-/_}"
|
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
|
||||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||||
OPTARG=${OPTARG#*=}
|
OPTARG=${OPTARG#*=}
|
||||||
else
|
else
|
||||||
# --key value format
|
# --key value format
|
||||||
# Map long name to short version of option
|
# Map long name to short version of option
|
||||||
__b3bp_tmp_varname="__b3bp_tmp_short_opt_${OPTARG//-/_}"
|
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
|
||||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||||
# Only assign OPTARG if option takes an argument
|
# Only assign OPTARG if option takes an argument
|
||||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
|
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
|
||||||
@ -253,6 +264,25 @@ if [ -n "${__b3bp_tmp_opts:-}" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
### Automatic validation of required option arguments
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do
|
||||||
|
# validate only options which required an argument
|
||||||
|
[ "${!__b3bp_tmp_varname}" = "2" ] || continue
|
||||||
|
|
||||||
|
__b3bp_tmp_opt_short="${__b3bp_tmp_varname##*_}"
|
||||||
|
__b3bp_tmp_varname="arg_${__b3bp_tmp_opt_short}"
|
||||||
|
[ -n "${!__b3bp_tmp_varname}" ] && continue
|
||||||
|
|
||||||
|
__b3bp_tmp_varname="__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt_short}"
|
||||||
|
printf -v "__b3bp_tmp_opt_long" '%s' "${!__b3bp_tmp_varname}"
|
||||||
|
[ -n "${__b3bp_tmp_opt_long:-}" ] && __b3bp_tmp_opt_long=" (--${__b3bp_tmp_opt_long//_/-})"
|
||||||
|
|
||||||
|
help "Option -${__b3bp_tmp_opt_short}${__b3bp_tmp_opt_long:-} requires an argument"
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
### Cleanup Environment variables
|
### Cleanup Environment variables
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
1
test/fixture/main-usage-validation.exitcode
Normal file
1
test/fixture/main-usage-validation.exitcode
Normal file
@ -0,0 +1 @@
|
|||||||
|
0
|
155
test/fixture/main-usage-validation.stdio
Normal file
155
test/fixture/main-usage-validation.stdio
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
ACCPTST:STDIO_REPLACE_DATETIMES
|
||||||
|
# complain about -3
|
||||||
|
|
||||||
|
Option -3 (--three) requires an argument
|
||||||
|
|
||||||
|
-0 --zero Do nothing.
|
||||||
|
-1 --one Do one thing. Required.
|
||||||
|
More description.
|
||||||
|
-2 --two Do two things.
|
||||||
|
More. Required. Description.
|
||||||
|
-3 --three [arg] Do three things.
|
||||||
|
Required.
|
||||||
|
-4 --four {arg} Do four things.
|
||||||
|
-5 --five {arg} Do five things. Required. Maybe.
|
||||||
|
-6 --six [arg] Do six things. Not Required.
|
||||||
|
Required, it is not.
|
||||||
|
-7 --seven [arg] Required. Or bust.
|
||||||
|
-8 --eight [arg] Do eight things.
|
||||||
|
More.Required.Description.
|
||||||
|
-a [arg] Do A. Required.
|
||||||
|
Default="do-a"
|
||||||
|
-b {arg} Do B.Default="do-b"
|
||||||
|
-c [arg] Required. Default="do-c"
|
||||||
|
-d {arg} Default="do-d"
|
||||||
|
|
||||||
|
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||||
|
program or elaborate more on command-line arguments. This section is not
|
||||||
|
parsed and will be added as-is to the help.
|
||||||
|
|
||||||
|
# complain about -4
|
||||||
|
|
||||||
|
Option -4 (--four) requires an argument
|
||||||
|
|
||||||
|
-0 --zero Do nothing.
|
||||||
|
-1 --one Do one thing. Required.
|
||||||
|
More description.
|
||||||
|
-2 --two Do two things.
|
||||||
|
More. Required. Description.
|
||||||
|
-3 --three [arg] Do three things.
|
||||||
|
Required.
|
||||||
|
-4 --four {arg} Do four things.
|
||||||
|
-5 --five {arg} Do five things. Required. Maybe.
|
||||||
|
-6 --six [arg] Do six things. Not Required.
|
||||||
|
Required, it is not.
|
||||||
|
-7 --seven [arg] Required. Or bust.
|
||||||
|
-8 --eight [arg] Do eight things.
|
||||||
|
More.Required.Description.
|
||||||
|
-a [arg] Do A. Required.
|
||||||
|
Default="do-a"
|
||||||
|
-b {arg} Do B.Default="do-b"
|
||||||
|
-c [arg] Required. Default="do-c"
|
||||||
|
-d {arg} Default="do-d"
|
||||||
|
|
||||||
|
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||||
|
program or elaborate more on command-line arguments. This section is not
|
||||||
|
parsed and will be added as-is to the help.
|
||||||
|
|
||||||
|
# complain about -5
|
||||||
|
|
||||||
|
Option -5 (--five) requires an argument
|
||||||
|
|
||||||
|
-0 --zero Do nothing.
|
||||||
|
-1 --one Do one thing. Required.
|
||||||
|
More description.
|
||||||
|
-2 --two Do two things.
|
||||||
|
More. Required. Description.
|
||||||
|
-3 --three [arg] Do three things.
|
||||||
|
Required.
|
||||||
|
-4 --four {arg} Do four things.
|
||||||
|
-5 --five {arg} Do five things. Required. Maybe.
|
||||||
|
-6 --six [arg] Do six things. Not Required.
|
||||||
|
Required, it is not.
|
||||||
|
-7 --seven [arg] Required. Or bust.
|
||||||
|
-8 --eight [arg] Do eight things.
|
||||||
|
More.Required.Description.
|
||||||
|
-a [arg] Do A. Required.
|
||||||
|
Default="do-a"
|
||||||
|
-b {arg} Do B.Default="do-b"
|
||||||
|
-c [arg] Required. Default="do-c"
|
||||||
|
-d {arg} Default="do-d"
|
||||||
|
|
||||||
|
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||||
|
program or elaborate more on command-line arguments. This section is not
|
||||||
|
parsed and will be added as-is to the help.
|
||||||
|
|
||||||
|
# complain about -8 (because -7 syntax is not supported)
|
||||||
|
|
||||||
|
Option -8 (--eight) requires an argument
|
||||||
|
|
||||||
|
-0 --zero Do nothing.
|
||||||
|
-1 --one Do one thing. Required.
|
||||||
|
More description.
|
||||||
|
-2 --two Do two things.
|
||||||
|
More. Required. Description.
|
||||||
|
-3 --three [arg] Do three things.
|
||||||
|
Required.
|
||||||
|
-4 --four {arg} Do four things.
|
||||||
|
-5 --five {arg} Do five things. Required. Maybe.
|
||||||
|
-6 --six [arg] Do six things. Not Required.
|
||||||
|
Required, it is not.
|
||||||
|
-7 --seven [arg] Required. Or bust.
|
||||||
|
-8 --eight [arg] Do eight things.
|
||||||
|
More.Required.Description.
|
||||||
|
-a [arg] Do A. Required.
|
||||||
|
Default="do-a"
|
||||||
|
-b {arg} Do B.Default="do-b"
|
||||||
|
-c [arg] Required. Default="do-c"
|
||||||
|
-d {arg} Default="do-d"
|
||||||
|
|
||||||
|
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||||
|
program or elaborate more on command-line arguments. This section is not
|
||||||
|
parsed and will be added as-is to the help.
|
||||||
|
|
||||||
|
# complain about -d (because -d syntax is not supported)
|
||||||
|
|
||||||
|
Option -d requires an argument
|
||||||
|
|
||||||
|
-0 --zero Do nothing.
|
||||||
|
-1 --one Do one thing. Required.
|
||||||
|
More description.
|
||||||
|
-2 --two Do two things.
|
||||||
|
More. Required. Description.
|
||||||
|
-3 --three [arg] Do three things.
|
||||||
|
Required.
|
||||||
|
-4 --four {arg} Do four things.
|
||||||
|
-5 --five {arg} Do five things. Required. Maybe.
|
||||||
|
-6 --six [arg] Do six things. Not Required.
|
||||||
|
Required, it is not.
|
||||||
|
-7 --seven [arg] Required. Or bust.
|
||||||
|
-8 --eight [arg] Do eight things.
|
||||||
|
More.Required.Description.
|
||||||
|
-a [arg] Do A. Required.
|
||||||
|
Default="do-a"
|
||||||
|
-b {arg} Do B.Default="do-b"
|
||||||
|
-c [arg] Required. Default="do-c"
|
||||||
|
-d {arg} Default="do-d"
|
||||||
|
|
||||||
|
This is Bash3 Boilerplate's help text. Feel free to add any description of your
|
||||||
|
program or elaborate more on command-line arguments. This section is not
|
||||||
|
parsed and will be added as-is to the help.
|
||||||
|
|
||||||
|
# complain about nothing
|
||||||
|
{datetime} UTC [ info] arg_0: 0
|
||||||
|
{datetime} UTC [ info] arg_1: 0
|
||||||
|
{datetime} UTC [ info] arg_2: 0
|
||||||
|
{datetime} UTC [ info] arg_3: arg3
|
||||||
|
{datetime} UTC [ info] arg_4: arg4
|
||||||
|
{datetime} UTC [ info] arg_5: arg5
|
||||||
|
{datetime} UTC [ info] arg_6:
|
||||||
|
{datetime} UTC [ info] arg_7:
|
||||||
|
{datetime} UTC [ info] arg_8: arg8
|
||||||
|
{datetime} UTC [ info] arg_a: do-a
|
||||||
|
{datetime} UTC [ info] arg_b: do-b
|
||||||
|
{datetime} UTC [ info] arg_c: do-c
|
||||||
|
{datetime} UTC [ info] arg_d: argd
|
@ -12,4 +12,4 @@ __root="$(cd "$(dirname $(dirname $(dirname "${__dir}")))" && pwd)"
|
|||||||
|
|
||||||
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||||
|
|
||||||
bash "${__root}/main.sh" -h
|
bash "${__root}/main.sh" -f /tmp/x -h
|
||||||
|
60
test/scenario/main-usage-validation/run.sh
Executable file
60
test/scenario/main-usage-validation/run.sh
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -o pipefail
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
# set -o xtrace
|
||||||
|
|
||||||
|
# Set magic variables for current FILE & DIR
|
||||||
|
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||||
|
__base="$(basename ${__file} .sh)"
|
||||||
|
__root="$(cd "$(dirname $(dirname $(dirname "${__dir}")))" && pwd)"
|
||||||
|
|
||||||
|
# Set __usage and source main.sh
|
||||||
|
read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
|
||||||
|
-0 --zero Do nothing.
|
||||||
|
-1 --one Do one thing. Required.
|
||||||
|
More description.
|
||||||
|
-2 --two Do two things.
|
||||||
|
More. Required. Description.
|
||||||
|
-3 --three [arg] Do three things.
|
||||||
|
Required.
|
||||||
|
-4 --four {arg} Do four things.
|
||||||
|
-5 --five {arg} Do five things. Required. Maybe.
|
||||||
|
-6 --six [arg] Do six things. Not Required.
|
||||||
|
Required, it is not.
|
||||||
|
-7 --seven [arg] Required. Or bust.
|
||||||
|
-8 --eight [arg] Do eight things.
|
||||||
|
More.Required.Description.
|
||||||
|
-a [arg] Do A. Required.
|
||||||
|
Default="do-a"
|
||||||
|
-b {arg} Do B.Default="do-b"
|
||||||
|
-c [arg] Required. Default="do-c"
|
||||||
|
-d {arg} Default="do-d"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
export __usage
|
||||||
|
export NO_COLOR="true"
|
||||||
|
|
||||||
|
echo "ACCPTST:STDIO_REPLACE_DATETIMES"
|
||||||
|
|
||||||
|
echo "# complain about -3"
|
||||||
|
(source "${__root}/main.sh") || true
|
||||||
|
|
||||||
|
echo "# complain about -4"
|
||||||
|
(source "${__root}/main.sh" -3 arg3) || true
|
||||||
|
|
||||||
|
echo "# complain about -5"
|
||||||
|
(source "${__root}/main.sh" -3 arg3 -4 arg4) || true
|
||||||
|
|
||||||
|
echo "# complain about -8 (because -7 syntax is not supported)"
|
||||||
|
(source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5) || true
|
||||||
|
|
||||||
|
echo "# complain about -d (because -d syntax is not supported)"
|
||||||
|
(source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5 -8 arg8) || true
|
||||||
|
|
||||||
|
echo "# complain about nothing"
|
||||||
|
(
|
||||||
|
source "${__root}/main.sh" -3 arg3 -4 arg4 -5 arg5 -8 arg8 -d argd
|
||||||
|
for argument in ${!arg_*}; do info "${argument}: ${!argument}"; done
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user