diff --git a/bake.bash b/bake.bash index fde92f6b..54ac2634 100644 --- a/bake.bash +++ b/bake.bash @@ -197,53 +197,6 @@ bake._log(){ echo -e "$level $(date "+%F %T") $(bake._pwd)\$ ${FUNCNAME[1]}() : $*" >&2 } -# list bake internal var , used to debug bake self -# Usage: info -bake.info() ( - -cat <<- EOF - - .----------------. .----------------. .----------------. .----------------. -| .--------------. || .--------------. || .--------------. || .--------------. | -| | ______ | || | __ | || | ___ ____ | || | _________ | | -| | |_ _ \ | || | / \ | || | |_ ||_ _| | || | |_ ___ | | | -| | | |_) | | || | / /\ \ | || | | |_/ / | || | | |_ \_| | | -| | | __'. | || | / ____ \ | || | | __'. | || | | _| _ | | -| | _| |__) | | || | _/ / \ \_ | || | _| | \ \_ | || | _| |___/ | | | -| | |_______/ | || ||____| |____|| || | |____||____| | || | |_________| | | -| | | || | | || | | || | | | -| '--------------' || '--------------' || '--------------' || '--------------' | - '----------------' '----------------' '----------------' '----------------' - -EOF - echo '# bake info & internal var' - echo - echo '## _cmdTree' - echo - for key in "${!_cmdTree[@]}"; do - printf "cmd - %-40s = %q\n" "$key" "${_cmdTree["$key"]:0:100}" - done | sort - echo - echo '## _data' - echo - for key in "${!_data[@]}"; do - printf "data - %-40s = %q\n" "$key" "${_data["$key"]:0:100}" - done | sort - echo - echo '## options' - echo - echo "help = $help" - echo "debug = $debug" - echo - -cat <<- EOF - - - - -EOF -) - ########################################## # bake common script @@ -415,6 +368,122 @@ bake._opt_internal_add() { } +# Usage: bake._cmd_register +# ensure all cmd register +bake._cmd_register() { + local functionName + + while IFS=$'\n' read -r functionName; do + if [[ "$functionName" == */* ]]; then + echo "error: function $functionName() can not contains '/' " >&2 + return 1 + fi + local upCmd + for upCmd in $(bake._cmd_up_chain "$functionName"); do + # if upCmd is a function , set upCmd value to data path + if compgen -A function | grep -q "^$upCmd$"; then + _cmdTree["$upCmd"]="$upCmd" + else + _cmdTree["$upCmd"]="PARENT_CMD_NOT_FUNC" + fi + done + + # list all function name + # declare -F | awk {'print $3'} == compgen -A function + # declare -f func1 -> func1 + # declare -fx func2 -> func2 +# done <<<"$(compgen -A function)" + done <<<"$(declare -F | grep "declare -f" | awk {'print $3'})" +} + +# 显示一条命令的帮助 +# Usage: bake._show_cmd_help +# Examples: bake._show_cmd_help deploy #显示deploy的帮助: +bake._show_cmd_help() { + local cmd="$1" + + if [[ "$cmd" == "" ]]; then + bake._throw "bake._show_cmd_help need a arg: bake._show_cmd_help [cmd]" + fi + + shift + + eval "$(bake.parse "${FUNCNAME[0]}" "$@")" + + local usage + usage="${_data["${cmd}/usage"]}" + if [[ "$usage" != "" ]]; then + echo -e "\nUsage: $usage " + else + echo -e "\nUsage: ./$BAKE_FILE $(bake._str_split "$cmd" "." | tr "\n" " ") [options] [args...]" + fi + + echo + + echo "Currently running: $(bake._pwd)/$BAKE_FILE $cmd $@" + + echo + + if [[ "${_data["${cmd}/description"]}" != "" ]]; then + echo "Description: ${_data["${cmd}/description"]}" + elif [[ "${_data[${cmd} / summary]}" != "" ]]; then + echo "Description: ${_data["${cmd}/summary"]}" + else + echo "no description" + fi + + echo + + echo "Available Options:" + for optPath in $(bake._opt_cmd_chain_opts "$cmd"); do + local opt + opt=$(bake._path_basename "$optPath") + local name=${_data["$optPath/name"]} + local type=${_data["$optPath/type"]} + local required=${_data["$optPath/required"]} + local abbr=${_data["$optPath/abbr"]} + local default=${_data["$optPath/default"]} + local optHelp="${_data["$optPath/optHelp"]}" + + local optArgDesc="" + if [[ "$type" == "string" ]]; then + if [[ "$default" != "" ]]; then + optArgDesc+="<$type:${default}>" + else + optArgDesc="<$type>" + fi + fi + + printf " --%-20s -%-2s %-6s required:[%s] %b\n" "$name $optArgDesc" "$abbr" "$type" "$required" "$optHelp" + done + + echo " +Available Commands:" + local maxLengthOfCmd + maxLengthOfCmd="$(bake._cmd_childrenNameMaxLength "$cmd")" + + for subCmd in $(bake._cmd_children "$cmd"); do + + # only show public cmd if not verbose + # '_'起头的命令和'bake'命令,只有debug模式才打印出来 + if [[ ("$subCmd" == _* || "$subCmd" == bake*) ]]; then + if [[ "$debug" != "true" ]]; then + continue + fi + fi + + local subCmdPath="$cmd/$subCmd" + [[ "$cmd" == "_root" ]] && subCmdPath="$subCmd" + + local summary + summary="${_data["$subCmdPath/summary"]}" + summary="$(echo -e "$summary")" # backslash escapes interpretation + + printf " %-$((maxLengthOfCmd))s ${summary}\n" "${subCmd}" + done +} + + # 为cmd配置参数 # Examples: # bake.opt --cmd "build" --name "is_zip" --type bool --required --abbr z --default true --optHelp "is_zip, build项目时是否压缩" @@ -448,6 +517,7 @@ bake.opt() { bake._opt_internal_add "$cmd" "$name" "$type" "${required:-false}" "$default" "$abbr" "$optHelp" } +# bake.opt (public api) # 像其他高级语言的cli工具一样,用简单变量就可以获取名称化的命令参数: # 支持bool,string,list三种参数,用法如下: # 你的./bake脚本里: @@ -473,7 +543,6 @@ bake.opt() { # # Usage: bake.parse [arg1] [arg2] ... # 参考:[bake.opt] - bake.parse() { local cmd="${1}" if [[ "$cmd" == "" ]]; then @@ -548,6 +617,17 @@ bake.parse() { echo -e "$resultStr" # echo -e : unescapes backslash } + +# bake.cmd (public api) +# 注册一个命令的帮助信息 +# Examples: +# bake.cmd --cmd build --summary "build project" --usage "Usage: ./$SCRIPT_FILE build [options]" +# 尤其是可以配置_root命令以定制根命令的帮助信息,比如: +# bake.cmd --cmd _root \ +# --usage "./$SCRIPT_FILE [cmd] [opts] [args...]" \ +# --summary "flutter-note cli." \ +# --description ".... your root cmd help " +# 这样就可以用'./your_script -h' 查看根帮助了 bake.opt --cmd "bake.cmd" --name "cmd" --type string --optHelp "cmd, function name" bake.opt --cmd "bake.cmd" --name "usage" --type string --optHelp "usage" bake.opt --cmd "bake.cmd" --name "summary" --type string --optHelp "summary help, short, show on cmd list" @@ -566,121 +646,49 @@ bake.cmd() { _data["$cmd/description"]="$description" } -# Usage: bake._cmd_register -# ensure all cmd register -bake._cmd_register() { - local functionName - - while IFS=$'\n' read -r functionName; do - if [[ "$functionName" == */* ]]; then - echo "error: function $functionName() can not contains '/' " >&2 - return 1 - fi - local upCmd - for upCmd in $(bake._cmd_up_chain "$functionName"); do - # if upCmd is a function , set upCmd value to data path - if compgen -A function | grep -q "^$upCmd$"; then - _cmdTree["$upCmd"]="$upCmd" - else - _cmdTree["$upCmd"]="PARENT_CMD_NOT_FUNC" - fi - done - - # list all function name - # declare -F | awk {'print $3'} == compgen -A function - # declare -f func1 -> func1 - # declare -fx func2 -> func2 -# done <<<"$(compgen -A function)" - done <<<"$(declare -F | grep "declare -f" | awk {'print $3'})" -} - -# 显示一条命令的帮助 -# Usage: bake._show_cmd_help -# Examples: bake._show_cmd_help deploy #显示deploy的帮助: -bake._show_cmd_help() { - local cmd="$1" - if [[ "$cmd" == "" ]]; then - bake._throw "bake._show_cmd_help need a arg: bake._show_cmd_help [cmd]" - fi - - shift +# list bake internal var , used to debug bake self +# Usage: info +bake.info() { - eval "$(bake.parse "${FUNCNAME[0]}" "$@")" +cat <<- EOF - local usage - usage="${_data["${cmd}/usage"]}" - if [[ "$usage" != "" ]]; then - echo -e "\nUsage: $usage " - else - echo -e "\nUsage: ./$BAKE_FILE $(bake._str_split "$cmd" "." | tr "\n" " ") [options] [args...]" - fi + .----------------. .----------------. .----------------. .----------------. +| .--------------. || .--------------. || .--------------. || .--------------. | +| | ______ | || | __ | || | ___ ____ | || | _________ | | +| | |_ _ \ | || | / \ | || | |_ ||_ _| | || | |_ ___ | | | +| | | |_) | | || | / /\ \ | || | | |_/ / | || | | |_ \_| | | +| | | __'. | || | / ____ \ | || | | __'. | || | | _| _ | | +| | _| |__) | | || | _/ / \ \_ | || | _| | \ \_ | || | _| |___/ | | | +| | |_______/ | || ||____| |____|| || | |____||____| | || | |_________| | | +| | | || | | || | | || | | | +| '--------------' || '--------------' || '--------------' || '--------------' | + '----------------' '----------------' '----------------' '----------------' +EOF + echo '# bake info & internal var' echo - - echo "Currently running: $(bake._pwd)/$BAKE_FILE $cmd $@" - + echo '## _cmdTree' echo - - if [[ "${_data["${cmd}/description"]}" != "" ]]; then - echo "Description: ${_data["${cmd}/description"]}" - elif [[ "${_data[${cmd} / summary]}" != "" ]]; then - echo "Description: ${_data["${cmd}/summary"]}" - else - echo "no description" - fi - + for key in "${!_cmdTree[@]}"; do + printf "cmd - %-40s = %q\n" "$key" "${_cmdTree["$key"]:0:100}" + done | sort + echo + echo '## _data' + echo + for key in "${!_data[@]}"; do + printf "data - %-40s = %q\n" "$key" "${_data["$key"]:0:100}" + done | sort + echo + echo '## options' + echo + echo "help = $help" + echo "debug = $debug" echo - echo "Available Options:" - for optPath in $(bake._opt_cmd_chain_opts "$cmd"); do - local opt - opt=$(bake._path_basename "$optPath") - local name=${_data["$optPath/name"]} - local type=${_data["$optPath/type"]} - local required=${_data["$optPath/required"]} - local abbr=${_data["$optPath/abbr"]} - local default=${_data["$optPath/default"]} - local optHelp="${_data["$optPath/optHelp"]}" - - local optArgDesc="" - if [[ "$type" == "string" ]]; then - if [[ "$default" != "" ]]; then - optArgDesc+="<$type:${default}>" - else - optArgDesc="<$type>" - fi - fi - - printf " --%-20s -%-2s %-6s required:[%s] %b\n" "$name $optArgDesc" "$abbr" "$type" "$required" "$optHelp" - done - - echo " -Available Commands:" - local maxLengthOfCmd - maxLengthOfCmd="$(bake._cmd_childrenNameMaxLength "$cmd")" - - for subCmd in $(bake._cmd_children "$cmd"); do - - # only show public cmd if not verbose - # '_'起头的命令和'bake'命令,只有debug模式才打印出来 - if [[ ("$subCmd" == _* || "$subCmd" == bake*) ]]; then - if [[ "$debug" != "true" ]]; then - continue - fi - fi - - local subCmdPath="$cmd/$subCmd" - [[ "$cmd" == "_root" ]] && subCmdPath="$subCmd" - - local summary - summary="${_data["$subCmdPath/summary"]}" - summary="$(echo -e "$summary")" # backslash escapes interpretation - - printf " %-$((maxLengthOfCmd))s ${summary}\n" "${subCmd}" - done } + bake.go() { # init register all cmd