#!/bin/bash
#
# source BaseEnvHelper.sh or source ArgsHelper.sh to use
# used to help other scripts to make their args organized
# invoke 'SetRequestedArg' / 'SetDescription' / 'SetExample' first
# then invoke 'VerifyAllArgs "$@"'
set -e
source ${HOME}/env-setup/env-helper/ColorStyleHelper.sh
# create empty arrays to store arguments with corresponding names
# shortNameArray to store shortName and so on
shortNameArray=()
fullNameArray=()
exampleNameArray=() # used to store [$shortName $fullName] together to output when argUsage() called
ifOptionalArray=()
argDescriptionArray=()
ifAcceptValueArray=()
validValueArray=()
ifMultipleArray=()
# it's VERY likely to create an array with non-continuous indices when VerfiyAllArgs() is called
# one or more indices may be 'jumped' over when one or more optional args are NOT passed-in
# so ONLY passed-in args and values are verified and then put into validPassedInValueArray
validPassedInArgArray=()
validPassedInValueArray=()
# call anywhere inside worker script after VerifyAllArgs() was called
# example and description are skipped
PukeMeOut() {
local size=${#shortNameArray[*]}
declare -i i=1 # skip [--help HELP_ARG]
ifAll=$1
while [ "$size" -gt "$i" ]; do
if [ "$ifAll" == true ]; then # puke all build-in arrays and items
if [ -z "${validPassedInValueArray[$i]}" ]; then
validPassedInArgArray[$i]='None'
validPassedInValueArray[$i]='None'
fi
# exampleName and exampleNameArray are skipped cause they already have styles
echo -e "${_COLOR_D}\
shortName: [${shortNameArray[$i]}] \
| fullName: [${fullNameArray[$i]}] \
| ifOptional: [${ifOptionalArray[$i]}] \
| argDescription: [${argDescriptionArray[$i]}] \
| ifAcceptValue: [${ifAcceptValueArray[$i]}] \
| validValue: [${validValueArray[$i]}] \
| ifMultiple: [${ifMultipleArray[$i]}] \
| validPassedInArg: [${validPassedInArgArray[$i]}] \
| validPassedInValue: [${validPassedInValueArray[$i]}]\
${_END}"
else # puke only arrays and itmes related to passed-in args
if [ -z "${validPassedInValueArray[$i]}" ]; then
i=$i+1
continue
fi
echo -e "${_COLOR_D}\
validPassedInArg: [${validPassedInArgArray[$i]}] \
| fullName: [${fullNameArray[$i]}] \
| ifOptional: [${ifOptionalArray[$i]}] \
| ifAcceptValue: [${ifAcceptValueArray[$i]}] \
| validValue: [${validValueArray[$i]}] \
| ifMultiple: [${ifMultipleArray[$i]}] \
| validPassedInValue: [${validPassedInValueArray[$i]}]\
${_END}"
fi
i=$i+1
done
}
description= # not an array
exampleArray=()
exampleDescArray=()
# invoke SetRequestedArg() multiple times to setup a list of required args
SetRequestedArg() {
# 0 at the 1st time, increases by 1 on each invocation
# so value can be set at correct index of target array
argNum=${#shortNameArray[*]}
# two examples:
# 1. SetRequestedArg "-c" "true" "COMPRESS_FILE" "if compress the output file" "true" "zip tar.gz"
# valid: '-c zip' or not passed-in, invalid: '-c bzip2'
#
# 2. SetRequestedArg "-os" "false" "OS_NAME" "name of operating system" "true" "win7 win10 win2008r2 win2012r2" "true"
# valid: '-os "win7 win2k8r2"', invalid: '-os "win8 win10"' or not passed-in
shortName=$1 # arg short name, used when call from command line, like '-c' or '-os'
ifOptional=$2 # if optional or mendatory, 'true' or 'false'
fullName=$3 # arg full name, used in script which sources ArgsHelper, like 'COMPRESS_FILE' or 'OS_NAME'
argDescription=$4 # arg description, describe what is the arg used for
ifAcceptValue=$5 # if accepta passing value from command line, 'true' or 'false' (false means the arg is like a switch, can be turned on or off)
validValue=$6 # a list of valid values, used to validate passed-in values, like 'zip tar.gz' or 'win7 win10 win2008r2 win2012r2'
ifMultiple=$7 # if arg can be passed-in multi-values, multi-values needs double quotes, see examples above
# 'accepts value' means 'mendatory', so only 'optoinal' arg can accept no value
if [ "$ifOptional" == "false" -a "$ifAcceptValue" == "false" ]; then
echo -e "\n${_ERROR}ERROR: only optional arg can be set not to accept value${_END}"
echo -e "${_ERROR}please re-define arg [$shortName $fullName] and try again${_END}"
exit 100
fi
if [ "$shortName" == "--help" ]; then
exampleName="${_B}${_COLOR_A}[$shortName]${_END}"
else
exampleName="${_B}${_COLOR_A}$shortName${_END} ${_UL}${_COLOR_A}$fullName${_END}"
[ "$ifOptional" == "true" ] && exampleName="${_COLOR_A}[${_END}${exampleName} ${_COLOR_A}(optional)]${_END}"
[ "$ifAcceptValue" == "false" ] && exampleName="${exampleName} ${_COLOR_A}(not accepts value)${_END}"
fi
shortNameArray[$argNum]=$shortName
fullNameArray[$argNum]=$fullName
ifOptionalArray[$argNum]=$ifOptional
argDescriptionArray[$argNum]=$argDescription
ifAcceptValueArray[$argNum]=$ifAcceptValue
exampleNameArray[$argNum]=$exampleName
validValueArray[$argNum]=$validValue
ifMultipleArray[$argNum]=$ifMultiple
}
SetDescription() {
description=$1
}
# example and its description
# if need to use customized format, like
# example:
# info1
# info2
# info3
# just set 'exampleArray' but leave 'exampleDescArray' empty, like
# SetExample "example:\n info1\n info2\n info3" ""
SetExample() {
argNum=${#exampleArray[*]}
exampleArray[$argNum]="$1"
exampleDescArray[$argNum]="$2"
}
# will be invoked on each ERROR in 'shortMode', and '--help' with every details
argUsage() {
argNum=${#shortNameArray[*]}
exampleNum=${#exampleArray[*]}
# create a brief argUsage with script name and arg list
declare -i i=0
while [ "$argNum" -gt "$i" ]; do
argList="$argList ${exampleNameArray[$i]}"
i=$i+1
done
if [ "$1" == "short" ]; then
echo -e "\n${_COLOR_A}argUsage${_END}:$argList"
echo -e "${_COLOR_A}run '$villain --help' for more details${_END}"
else # display every details if not 'shortMode'
if [ -n "$preLogs" ]; then
echo -e "${_COLOR_D}----------------------------------------------------------------------------${_END}"
echo -e "${_COLOR_D} Functions called before ${FUNCNAME}:${_END}"
for preLog in $preLogs; do
echo -e "${_COLOR_D} ${preLog}${_END}"
done
echo -e "${_COLOR_D}----------------------------------------------------------------------------${_END}"
fi
echo -e "\n${_4S}${_COLOR_A}argUsage:${_END}$argList"
echo -e "${_4S}${_COLOR_D}$description${_END}\n"
declare -i i=0
while [ "$argNum" -gt "$i" ]; do
echo -e "${_4S}${exampleNameArray[$i]}" # '[-c COMPRESS_FILE]'
echo -e "${_4S}${_4S}${_COLOR_B}${argDescriptionArray[$i]}${_END}" # '(optional) if compress the output file'
if [ "${ifAcceptValueArray[$i]}" == "true" ]; then
if [ ! -z "${validValueArray[$i]}" ]; then
if [ "${ifMultipleArray[$i]}" == "true" ]; then # 'Valid values: [win7 win10 win2008r2 win2012r2]'
echo -e "${_4S}${_4S}${_COLOR_B}valid values: [${validValueArray[$i]}]\
\n${_4S}${_4S}single('') or double(\"\") quotes required if multi-values passed-in${_END}"
else
echo -e "${_4S}${_4S}${_COLOR_B}valid value: [${validValueArray[$i]}]${_END}" # 'Valid value: [zip tar.gz]'
fi
else
echo -e "${_4S}${_4S}${_COLOR_B}accepts any value (validation needs be done in worker script)${_END}" # 'Valid value: [zip tar.gz]'
fi
fi
i=$i+1
done
if [ "$exampleNum" -gt 0 ]; then
echo -e "\n${_4S}${_COLOR_C}Examples:${_END}"
declare -i i=0
while [ "$exampleNum" -gt "$i" ]; do
echo -e "${_4S}${_4S}${_COLOR_D}${exampleArray[$i]}${_END}"
echo -e "${_2S}${_4S}${_4S}${_COLOR_D}${exampleDescArray[$i]}${_END}\n"
i=$i+1
done
fi
fi
}
# exceptions=(noArgs), for now only one type of exception
# make an exception when some scripts need NO args to run
MakeException() {
exception=$1
}
# used to check if required arg(s) are passed-in
# call "CheckArgBinds '-c XYZ' '-a -b'" inside the beginning of a function
# or code block before doing real work
CheckArgBinds() {
local action=$1
local binds=$2
for bind in $binds; do # check each required arg is passed-in
local shortName=${bind%:*}
if [[ ! "${validPassedInArgArray[@]}" =~ "$shortName" ]]; then
echo -e "${_ERROR}ERROR: Arguments Binds validation falied. [$action] requires [${bind/:/ }] to pass-in${_END}"
exit 11
fi
done
}
# useful if want to output log for functions called before argUsage() or VerifyAllArgs()
# cause some values of args need to be generated before worker scripts actually run
preRunningLog=''
SetPreRunningLogs() {
preRunningLog="${preRunningLog} ${1}"
}
# verify all args passed in, invoked by: 'VerifyAllArgs "$@"'
VerifyAllArgs() {
if [ "$#" -eq 0 ] && [ "$exception" != 'noArgs' ]; then
echo -e "\n${_ERROR}ERROR: no arguments passed-in${_END}"
argUsage short
exit 11
fi
if [ "$1" == "--help" ]; then
argUsage # display every details if the 1st arg is '--help'
exit 0
fi
echo -e "\n${_COLOR_D}----------------------------------------------------------------------------${_END}"
if [ -n "$preRunningLog" ]; then
echo -e "${_COLOR_D} Functions called before ${FUNCNAME}:${_END}"
for preLog in $preRunningLog; do
echo -e "${_COLOR_D} ${preLog}${_END}"
done
echo ""
fi
# print info of which worker script runs on which host with what arguments
# will be useful if called by other script from remote
echo -e "${_COLOR_D} On Host [`hostname`] run full invocation as:${_END}"
echo -e "${_COLOR_D} $villain $@${_END}"
echo -e "${_COLOR_D}----------------------------------------------------------------------------${_END}\n"
ifPassedArray=() # create an array for checking every required arg is passed-in
argNum=${#shortNameArray[*]}
declare -i i=0
while [ "$argNum" -gt "$i" ]; do
ifPassedArray[$i]="false"
i=$i+1
done
while [ "$#" -gt 0 ]; do
found="false"
declare -i i=0
for short in ${shortNameArray[@]}; do # check if passed-in shortName is valid
if [ "$short" == "$1" ]; then
found="true"
break
fi
i=$i+1
done
if [ "$found" == "true" ]; then # if shortName is valid
validPassedInArgArray[$i]="$1"
ifPassedArray[$i]="true"
if [ "${ifAcceptValueArray[$i]}" == "true" ]; then # check if accepts values
validValues="${validValueArray[$i]}"
if [ -z "$2" ]; then
echo -e "\n${_ERROR}ERROR: the arg [$1] accepts value but passed-in none${_END}"
argUsage 'short'
exit 11
else # check if passed-in value is valid
if [ ! -z "${validValues}" ]; then # if accepts value and has a list of valid value
# iterate all passed-in values, exit on each invalid value
if [ "${ifMultipleArray[$i]}" == "true" ]; then # if can pass-in multi-values
for value_i in $2; do # iterate passed-in values
valid="false"
for value_j in $validValues; do # iterate the list of valid value
if [ "$value_i" == "$value_j" ]; then
valid="true"
break
fi
done
if [ "$valid" == "false" ]; then # passed-in value is invalid
echo -e "\n${_ERROR}ERROR: arg [$1] does not accept value [$value_i]${_END}"
echo -e "${_ERROR}please choose one or more among [${validValues}]${_END}"
echo -e "${_ERROR}multiple values need single or double quotes${_END}"
argUsage 'short'
exit 11
fi
done
else
# iterate all passed-in values, exit on each invalid value
valid="false"
for value in $validValues; do # iterate valid value list
if [ "$value" == "$2" ]; then
valid="true"
break
fi
done
if [ "$valid" == "false" ]; then # passed-in value is invalid
echo -e "\n${_ERROR}ERROR: arg [$1] does not accept value [$2]${_END}"
echo -e "${_ERROR}please choose one among [${validValues}]${_END}"
argUsage 'short'
exit 11
fi
fi
fi
# the condition of [ -z "${validValueArray[$i]}" ] needes no validation
# so all passed-in value(s) should be valid till here, export them by 'eval'
export_cmd="export ${fullNameArray[$i]}=\"$2\"" # make arg can accept values with space, like -x "AA BB"
validPassedInValueArray[$i]="$2"
eval "$export_cmd" # export arg and value to parent script
shift; shift # shift arg and value
fi
else
# simply set the arg to true if not accepts value, only applied to optional arg
export_cmd="export ${fullNameArray[$i]}=true"
validPassedInValueArray[$i]=true
eval "$export_cmd"
shift; # shift only arg
fi
else # if shortName is invalid
echo -e "\n${_ERROR}ERROR: unknown arg [$1]${_END}"
argUsage 'short'
exit 11
fi
done
declare -i i=0
while [ "$argNum" -gt "$i" ]; do
# if not optional but without passing value
if [ "${ifOptionalArray[$i]}" == "false" -a "${ifPassedArray[$i]}" == "false" ]; then
echo -e "\n${_ERROR}ERROR: missing required arg [${shortNameArray[$i]} ${fullNameArray[$i]}]${_END}"
argUsage 'short'
exit 11
fi
i=$i+1
done
}
# add the 1st arg
SetRequestedArg "--help" "true" "HELP_ARG" "displays extended argUsage" "false"
网友评论