From 161484ef7bee1f18733ac02bcee391f35d56a350 Mon Sep 17 00:00:00 2001 From: Chen Peng Date: Tue, 26 Mar 2024 16:12:17 +0800 Subject: [PATCH] bake refractor --- n => bake | 20 +-- bake.bash | 291 +++++++++++++++++++++++++------------------ test/bake2_test.bash | 117 ++++++++--------- 3 files changed, 234 insertions(+), 194 deletions(-) rename n => bake (80%) diff --git a/n b/bake similarity index 80% rename from n rename to bake index a3d3ca93..cf3434a7 100755 --- a/n +++ b/bake @@ -1,9 +1,4 @@ #!/usr/bin/env bash -set -o errtrace # -E trap inherited in sub script -set -o errexit # -e -set -o functrace # -T If set, any trap on DEBUG and RETURN are inherited by shell functions -set -o pipefail # default pipeline status==last command status, If set, status=any command fail -#set -o nounset # -u: don't use it ,it is crazy, 1.bash version is diff Behavior 2.we need like this: ${arr[@]+"${arr[@]}"} # On Mac OS, readlink -f doesn't work, so use._real_path get the real path of the file _real_path() ( @@ -31,7 +26,7 @@ _exec() { local project project=$(basename "$PWD") # [[ "$PWD" == "$SCRIPT_DIR" ]] && project="_root" - _info "${FUNCNAME[1]}() ▶︎【$*】" + echo "${FUNCNAME[1]}() ▶︎【$*】" "$@" return $? } @@ -90,11 +85,6 @@ p.all() { (cd spaces/flutter_note && _exec "$@") } -bake.cmd.set --cmd p.note --summary " run cmd on note project" --usage "./$SCRIPT_FILE note [any command]" -bake.cmd.set --cmd p.flutter_note --summary " run cmd on flutter_note project" --usage "./$SCRIPT_FILE flutter_note [any command]" -bake.cmd.set --cmd p.mate --usage "./$SCRIPT_FILE mate [any command]" -bake.cmd.set --cmd p.mate_flutter --summary " run cmd on mate_flutter project" --usage "./$SCRIPT_FILE mate_flutter [any command]" -bake.cmd.set --cmd p.note_test --summary " run cmd on note_test project" --usage "./$SCRIPT_FILE note_test [any command]" p.note() (cd note && _exec "$@") p.flutter_note() (cd spaces/flutter_note && _exec "$@") p.mate() (cd mate && _exec "$@") @@ -102,13 +92,10 @@ p.mate_flutter() (cd mate_flutter && _exec "$@") p.note_test() (cd note_test && _exec "$@") p.note_tools() (cd note_tools && _exec "$@") -bake.cmd.set --cmd get --usage "./$SCRIPT_FILE get" --summary " ./bake all flutter pub get" get() { _exec all flutter pub get; } -bake.cmd.set --cmd test --usage "./$SCRIPT_FILE test" --summary " run all tests in all projects" -bake.cmd.set --cmd test.bake --usage "./$SCRIPT_FILE test" --summary " run all tests in all projects" -test() (./test/bake2_test.bash test ; _exec all flutter test ;) -test.bake() ( ./test/bake2_test.bash test ; ) +test() { ./test/bake2_test.bash test ; _exec all flutter test ;} +test.bake() { ./test/bake2_test.bash test ; } # get ip only work on macos # shellcheck disable=SC2155 @@ -145,6 +132,7 @@ docker.preview() { _exec docker build --progress plain --build-arg test=off --t docker.debug() { _exec docker run -v $PWD:/home/flutter/note --workdir /home/flutter/note --rm -it fischerscode/flutter:3.10.0-1.3.pre bash ; } docker.push() { docker image push younpc/note:latest ; } + #################################################### # app entry script & _root cmd #################################################### diff --git a/bake.bash b/bake.bash index 2cfa7101..a7ef7fa1 100755 --- a/bake.bash +++ b/bake.bash @@ -99,7 +99,7 @@ set -o pipefail # default pipeline status==last command status, If set, status= # https://pub.dev/documentation/args/latest/args/ArgParser-class.html # https://github.com/spf13/pflag # https://oclif.io/docs/flags - +# # know bash version # ref: https://ftp.gnu.org/gnu/bash/ # 1. ${parameter@operator} : from 2016 bash 4.4 @@ -108,14 +108,7 @@ set -o pipefail # default pipeline status==last command status, If set, status= # ${parameter@A} an assignment statement or declare command # 2. associative array : from 2009 bash 4.0 # declare -A -_on_error() { - echo "trapped an error: ↑ , trace: ↓" >&2 - _stack_frame -} -# Add the error catch first -#https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-trap -trap "_on_error" ERR -# todo trap exit and kill all subprocess + # check bake dependencies if ((BASH_VERSINFO[0] < 4 || (\ @@ -125,8 +118,8 @@ if ((BASH_VERSINFO[0] < 4 || (\ brew install bash # mac" exit 1 fi -# On Mac OS, readlink -f doesn't work, so use._real_path get the real path of the file -_real_path() ( +# On Mac OS, readlink -f doesn't work, so use.bake._real_path get the real path of the file +bake._real_path() ( cd "$(dirname "$1")" file="$PWD/$(basename "$1")" while [[ -L "$file" ]]; do @@ -138,35 +131,93 @@ _real_path() ( ) # bake context -BAKE_PATH="$(_real_path "${BASH_SOURCE[0]}")" +BAKE_PATH="$(bake._real_path "${BASH_SOURCE[0]}")" BAKE_DIR="$(dirname "$BAKE_PATH")" BAKE_FILE="$(basename "$BAKE_PATH")" cd "${BAKE_DIR}" # set workdir +declare debug=false +declare help=false +declare verbose=false -declare -r _LOG_LEVELS=(error info debug) -declare LOG=${LOG:-info} +bake._on_error() { + bake._error "ERROR - trapped an error: ↑ , trace: ↓" + local i=0 + local stackInfo + while true; do + stackInfo=$(caller $i 2>&1 && true) && true + if [[ $? != 0 ]]; then return 0; fi -# replace $HOME with "~" -_current_dir() { echo "${PWD/#$HOME/\~}" ; } + # 一行调用栈 '97 bake.build ./note/bake' + # 解析后 => 行号no=97 , 报错的函数func=bake.build , file=./note/bake + local no func file + IFS=' ' read -r no func file <<<"$stackInfo" -_error() { + # 打印出可读性强的信息: + # => ./note/bake:38 -> bake.build + printf "%s\n" "$(bake._real_path $file):$no -> $func" >&2 + + i=$((i + 1)) + done +} +# Add the error catch first +#https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-trap +trap "bake._on_error" ERR + + +# replace $HOME with "~" +# Usage: bake._pwd +# Examples: 当前目录如果是"/Users/chen/git/note/" +# 转成更简单易读的 => "~/git/note/" +bake._pwd() { echo "${PWD/#$HOME/\~}" ; } + +# 报错后终止程序,类似于其他语言的throw Excpetion +# 因set -o errexit 后,程序将在return 1 时退出, +# 退出前被‘trap bake._on_error ERR’捕获并显示错误堆栈 +# Usage: bake._throw +bake._throw(){ + bake._error "$@" + # set -o errexit 后,程序将退出,退出前被trap bake._on_error Err捕获并显示错误堆栈 + return 1 +} +bake._error() { if [[ "${_LOG_LEVELS[@]:0}" != *"$LOG"* ]]; then return 0; fi - echo -e "ERROR $(date "+%F %T") $(_current_dir)\$ ${FUNCNAME[1]}() : $*" >&2 + bake._log "$@" } -_info() { - if [[ "${_LOG_LEVELS[@]:1}" != *"$LOG"* ]]; then return 0; fi - echo -e "INFO $(date "+%F %T") $(_current_dir)\$ ${FUNCNAME[1]}() : $*" >&2 +bake._info() { + bake._log "$@" } -_debug() { +bake._debug() { + if [[ "${debug}" != true ]]; then return 0; fi + bake._log "$@" +} +# Usage: bake._log DEBUG "错误消息" +bake._log(){ + local level; + level=$1 if [[ "${_LOG_LEVELS[@]:2}" != *"$LOG"* ]]; then return 0; fi - echo -e "DEBUG $(date "+%F %T") $(_current_dir)\$ ${FUNCNAME[1]}() : $*" >&2 + echo -e "$level $(date "+%F %T") $(bake._pwd)\$ ${FUNCNAME[1]}() : $*" >&2 } -_debug "LOG level is $LOG :===${_LOG_LEVELS[@]:0}===" -# list internal var , used to debug bake self -# Usage: _self -_self() ( - echo '# bake _self internal var' +# 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 @@ -179,28 +230,22 @@ _self() ( 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 "verbose= $verbose" + echo -# Usage: _stack_frame -_stack_frame() { - local i=0 - local stackInfo - while true; do - stackInfo=$(caller $i 2>&1 && true) && true - if [[ $? != 0 ]]; then break; fi +cat <<- EOF - # parse - # 97 test_bake.str.split ./test/bake2_test.bash - local no func file - IFS=' ' read -r no func file <<<"$stackInfo" - # clickable stack: - # /Users/c/git/younpc/note/test/bake2_test.bash:38 bake.test.runTest() - printf "%s\n" "$(_real_path $file):$no $func()" >&2 - i=$((i + 1)) - done -} + +EOF +) + ########################################## # bake common script @@ -221,12 +266,12 @@ TYPE_CMD="type:cmd" # bake common function ########################################## -# Usage: bake.str.cutLeft -# bake.path.dirname a/b/c a/b => c -bake.str.cutLeft() { printf "${1#$2}"; } +# Usage: bake._str_cutLeft +# bake._path_dirname a/b/c a/b => c +bake._str_cutLeft() { printf "${1#$2}"; } # Usage: bake.str.split [delimiter:default /] -bake.str.split() { +bake._str_split() { local str=$1 delimiter=${2:-/} # # use <() process-substitution # # don't use <<< "" its add newline @@ -235,49 +280,49 @@ bake.str.split() { printf '%s\n' "${arr[@]}" } -# Usage: bake.str.revertLines <<< "$(echo -e "a\nb\nc")" => "c\nb\na" -bake.str.revertLines() { +# Usage: bake._str_revertLines <<< "$(echo -e "a\nb\nc")" => "c\nb\na" +bake._str_revertLines() { # cat xxx | tail -r; # macos bsd only, not work on linux # so use sed sed '1!G;h;$!d' # sed magic } -# Usage: bake.path.dirname [delimiter:default /] +# Usage: bake._path_dirname [delimiter:default /] # similar command dirname, but # dirname root is ".", only work with "/" -# bake.path.dirname root is "" , can set delimiter -# bake.path.dirname a.b.c . => a.b -bake.path.dirname() { +# bake._path_dirname root is "" , can set delimiter +# bake._path_dirname a.b.c . => a.b +bake._path_dirname() { local pathLikeStr="$1" delimiter="${2:-/}" if [[ "$pathLikeStr" != *"$delimiter"* ]]; then return fi printf '%s' "${pathLikeStr%$delimiter*}" } -# Usage: bake.path.first [delimiter:default /] -# bake.path.first a.b.c . => a -bake.path.first() { +# Usage: bake._path_first [delimiter:default /] +# bake._path_first a.b.c . => a +bake._path_first() { local pathLikeStr="$1" delimiter="${2:-/}" - # if /a/b/c , call :bake.path.first a/b/c / + # if /a/b/c , call :bake._path_first a/b/c / if [[ "$pathLikeStr" == "$delimiter"* ]]; then local removeDelim - removeDelim=$(bake.str.cutLeft "$pathLikeStr" "$delimiter") - printf "$delimiter$(bake.path.first "$removeDelim" "$delimiter")" + removeDelim=$(bake._str_cutLeft "$pathLikeStr" "$delimiter") + printf "$delimiter$(bake._path_first "$removeDelim" "$delimiter")" else # a/b/c printf "${pathLikeStr%%$delimiter*}" fi } # similar command basename -# Usage: bake.path.basename [delimiter:default /] -bake.path.basename() { +# Usage: bake._path_basename [delimiter:default /] +bake._path_basename() { local pathLikeStr="$1" delimiter="${2:-/}" # ${1##*/} => ## left remove until last "/" printf "${pathLikeStr##*$delimiter}" } -# Usage: bake.data.children +# Usage: bake._data_children # return children name -bake.data.children() { +bake._data_children() { local path="$1" # ${!_data[@]}: get all array keys local key @@ -286,22 +331,22 @@ bake.data.children() { if [[ "$key" == "$path"* ]]; then # https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html # remove prefix : key:build/opts/dir/type/x leftPathToBeCut:build/opts => dir/type/x - local child=$(bake.str.cutLeft "$key" "$path/") + local child=$(bake._str_cutLeft "$key" "$path/") # remove suffix: dir/type/x => dir - child=$(bake.path.first "$child" "/") + child=$(bake._path_first "$child" "/") printf '%s\n' "$child" fi done | sort -u } -bake.cmd.childrenNameMaxLength() { +bake._cmd_childrenNameMaxLength() { local cmd="$1" maxLengthOfCmd=0 - for child in $(bake.cmd.children "$cmd"); do + for child in $(bake._cmd_children "$cmd"); do if ((${#child} > maxLengthOfCmd)); then maxLengthOfCmd=${#child}; fi done printf "$maxLengthOfCmd" } -bake.cmd.children() ( +bake._cmd_children() ( path="$1" if [[ "$path" == _root ]]; then path="" @@ -313,37 +358,38 @@ bake.cmd.children() ( if [[ "$key" == "$path"* && "$key" != "$path" && "$key" != "_root" ]]; then # https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html # remove prefix : key:a.b.c leftPathToBeCut:a => b.c - child=$(bake.str.cutLeft "$key" "$path.") + child=$(bake._str_cutLeft "$key" "$path.") # remove suffix: b.c => c - child=$(bake.path.first "$child" ".") + child=$(bake._path_first "$child" ".") printf '%s\n' "$child" fi done | sort -u ) -# Usage: bake.cmd.up_chain -# sample: bake.cmd.up_chain a.b => "a.b", "a", "_root" -bake.cmd.up_chain() { +# Usage: bake._cmd_up_chain +# sample: bake._cmd_up_chain a.b => "a.b", "a", "_root" +bake._cmd_up_chain() { local path="${1:-_root}" local up="$path" while [[ "$up" != "" ]]; do printf '%s\n' "$up" - up=$(bake.path.dirname "$up" ".") + up=$(bake._path_dirname "$up" ".") done if [[ "$path" != "_root" ]]; then printf "_root\n"; fi } -# Usage: bake.cmd.down_chain -# reverse of bake.cmd.up_chain -bake.cmd.down_chain() { - bake.cmd.up_chain "$1" | bake.str.revertLines +# Usage: bake._cmd_down_chain +# reverse of bake._cmd_up_chain +bake._cmd_down_chain() { + bake._cmd_up_chain "$1" | bake._str_revertLines } -# Usage: bake.opt.cmd_chain_opts +# Usage: bake._opt_cmd_chain_opts +# Examples: bake._opt_cmd_chain_opts bake.info # return optionDataPath list -bake.opt.cmd_chain_opts() { +bake._opt_cmd_chain_opts() { local cmd=$1 local upCmds - readarray -t upCmds <<<"$(bake.cmd.up_chain "$cmd")" + readarray -t upCmds <<<"$(bake._cmd_up_chain "$cmd")" local key for key in "${!_data[@]}"; do @@ -359,7 +405,7 @@ bake.opt.cmd_chain_opts() { # only use by bake.opt.set, # because "bake.opt.set" is meta function, use this func to add self -bake.opt._internal_add() { +bake._opt_internal_add() { local cmd="$1" opt="$2" type="$3" required="$4" default="$5" abbr="$6" help="$7" _data["$cmd/opts/$opt"]="type:opt" _data["$cmd/opts/$opt/name"]="$opt" @@ -370,13 +416,13 @@ bake.opt._internal_add() { _data["$cmd/opts/$opt/optHelp"]="$optHelp" } -bake.opt._internal_add bake.opt.set "cmd" "string" "true" "" "" "cmd name" -bake.opt._internal_add bake.opt.set "name" "string" "true" "" "" "option name" -bake.opt._internal_add bake.opt.set "type" "string" "true" "" "" "option type" -bake.opt._internal_add bake.opt.set "required" "bool" "false" "false" "" "option required" -bake.opt._internal_add bake.opt.set "abbr" "string" "false" "" "" "option abbr" -bake.opt._internal_add bake.opt.set "default" "string" "false" "" "" "option abbr" -bake.opt._internal_add bake.opt.set "optHelp" "string" "false" "" "" "option help" +bake._opt_internal_add bake.opt.set "cmd" "string" "true" "" "" "cmd name" +bake._opt_internal_add bake.opt.set "name" "string" "true" "" "" "option name" +bake._opt_internal_add bake.opt.set "type" "string" "true" "" "" "option type" +bake._opt_internal_add bake.opt.set "required" "bool" "false" "false" "" "option required" +bake._opt_internal_add bake.opt.set "abbr" "string" "false" "" "" "option abbr" +bake._opt_internal_add bake.opt.set "default" "string" "false" "" "" "option abbr" +bake._opt_internal_add bake.opt.set "optHelp" "string" "false" "" "" "option help" bake.opt.set() { eval "$(bake.opt.parse ""${FUNCNAME[0]}"" "$@")" if [[ "$name" == "" ]]; then @@ -388,13 +434,7 @@ bake.opt.set() { if [[ "$type" != "bool" && "$type" != "string" && "$type" != "list" ]]; then echo "error: option [--type] must in [bool|string|list] " >&2 && return 1 fi - bake.opt._internal_add "$cmd" "$name" "$type" "${required:-false}" "$default" "$abbr" "$optHelp" -} - -# only use by bake.opt.set, -bake.opt.get() { - local cmd="$1" opt="$2" - printf '%s' "${_data["$cmd/opts/$opt/value"]}" + bake._opt_internal_add "$cmd" "$name" "$type" "${required:-false}" "$default" "$abbr" "$optHelp" } # Usage: bake.opt.parse [arg1] [arg2] ... @@ -406,9 +446,9 @@ bake.opt.parse() { declare -A allOptOnCmdChain # collect opt from command chain : _root>pub>pub.get # root option first , priority low -> priority high: - for optPath in $(bake.opt.cmd_chain_opts "$cmd" | bake.str.revertLines); do + for optPath in $(bake._opt_cmd_chain_opts "$cmd" | bake._str_revertLines); do local opt - opt=$(bake.path.basename "$optPath") + opt=$(bake._path_basename "$optPath") local abbr abbr=${_data["$optPath/abbr"]} allOptOnCmdChain["--$opt"]="${optPath}" @@ -429,7 +469,7 @@ bake.opt.parse() { if [[ "${optPath}" == "" ]]; then break; fi # _opt_value_ prefix : avoid conflicts in the current context - optVars["$optPath"]="_opt_value_$(bake.path.basename "$optPath")" + optVars["$optPath"]="_opt_value_$(bake._path_basename "$optPath")" declare "${optVars["$optPath"]}" # reference to the current dynamic opt variable declare -n currentOptValue=${optVars["$optPath"]} @@ -485,17 +525,18 @@ bake.cmd.set() { _data["$cmd/description"]="$description" } -# Usage: bake.cmd.register +# Usage: bake._cmd_register # ensure all cmd register -bake.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 + 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" @@ -508,11 +549,20 @@ bake.cmd.register() { # declare -F | awk {'print $3'} == compgen -A function # declare -f func1 -> func1 # declare -fx func2 -> func2 - done <<<"$(compgen -A function)" +# done <<<"$(compgen -A function)" + done <<<"$(declare -F | grep "declare -f" | awk {'print $3'})" } -bake.help() ( +# 显示一条命令的帮助 +# 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.opt.parse "${FUNCNAME[0]}" "$@")" @@ -526,7 +576,7 @@ bake.help() ( echo - echo "Currently running: $(_current_dir)/$BAKE_FILE $cmd $@" + echo "Currently running: $(bake._pwd)/$BAKE_FILE $cmd $@" echo @@ -541,9 +591,9 @@ bake.help() ( echo echo "Available Options:" - for optPath in $(bake.opt.cmd_chain_opts "$cmd"); do + for optPath in $(bake._opt_cmd_chain_opts "$cmd"); do local opt - opt=$(bake.path.basename "$optPath") + opt=$(bake._path_basename "$optPath") local name=${_data["$optPath/name"]} local type=${_data["$optPath/type"]} local required=${_data["$optPath/required"]} @@ -566,8 +616,8 @@ bake.help() ( echo " Available Commands:" local maxLengthOfCmd - maxLengthOfCmd="$(bake.cmd.childrenNameMaxLength "$cmd")" - for subcmdName in $(bake.cmd.children "$cmd"); do + maxLengthOfCmd="$(bake._cmd_childrenNameMaxLength "$cmd")" + for subcmdName in $(bake._cmd_children "$cmd"); do # only show public cmd if not verbose if [[ "$verbose" == "" && ("$subcmdName" == _* || @@ -585,12 +635,12 @@ Available Commands:" printf " %-$((maxLengthOfCmd))s ${summary}\n" "${subcmdName}" done -) +} bake.go() { # init register all cmd - bake.cmd.register + bake._cmd_register # parse cmd : # ./bake pub get -v -b @@ -609,7 +659,7 @@ bake.go() { eval "$(bake.opt.parse "$cmd" "$@")" if [[ "$help" == "true" ]]; then - bake.help "$cmd" "$@" + bake._show_cmd_help "$cmd" "$@" return 0 fi if [[ "$log" != "" ]]; then LOG="$log"; fi @@ -617,11 +667,10 @@ bake.go() { # # parse opts if ! declare -f "$cmd" >/dev/null 2>&1; then if [[ "${_cmdTree["$cmd"]}" == "PARENT_CMD_NOT_FUNC" ]]; then - bake.help "$cmd" "$@" + bake._show_cmd_help "$cmd" "$@" return 0 fi - _error "Error: 404 ,cmd '${cmd}' not define, please define cmd function '${cmd}()'" - return 1 + bake._throw "Error: 404 ,cmd '${cmd}' not define, please define cmd function '${cmd}()'" fi $cmd "$@" @@ -630,15 +679,15 @@ bake.go() { # _root is special cmd(you can define it), bake add some common options to this cmd, you can add yourself options bake.opt.set --cmd _root --name "help" --abbr h --type bool --default false --optHelp "print help, show all commands" bake.opt.set --cmd _root --name "verbose" --abbr v --type bool --default false --optHelp "verbose, show more info, more hidden commands" -bake.opt.set --cmd _root --name "log" --type string --default info --optHelp "log level: debug, info, error" +bake.opt.set --cmd _root --name "debug" --abbr d --type bool --default false --optHelp "debug mode, print more internal info" # BASH_SOURCE > 1 , means bake import from other script, it is lib mode # lib mod is not load app function, so we need to stop here if ((${#BASH_SOURCE[@]} > 1)); then - _debug "【${BAKE_FILE}】 call by other script【$(printf " ▶︎ %s" "${BASH_SOURCE[@]}")】, lib mode on, not load below app script" >&2 - return 0 + bake._debug "【${BAKE_FILE}】 call by other script【$(printf " ▶︎ %s" "${BASH_SOURCE[@]}")】, lib mode on, not load below app script" >&2 fi + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # bake common script end line. # The above code is common code that is not related to the specific app, diff --git a/test/bake2_test.bash b/test/bake2_test.bash index 7a4c5731..31e686ab 100755 --- a/test/bake2_test.bash +++ b/test/bake2_test.bash @@ -38,7 +38,10 @@ function bake.test.all() { # TIMEFORMAT: https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html # %R==real %U==user %S==sys %P==(user+sys)/real TIMEFORMAT="real %R user %U sys %S percent %P" - time "$functionName" #2>&1 + ( + # 隔离test在子shell里,防止环境互相影响 + time "$functionName" ; + )# 2>&1 done <<< "$(compgen -A function)" } @@ -321,96 +324,96 @@ test.assert_sample(){ assert $((1+1)) @is 2 } -test.bake.path.dirname(){ - assert "$(bake.path.dirname a/b/c '/')" @is "a/b" - assert "$(bake.path.dirname a '/')" @is "" - assert "$(bake.path.dirname "" '/')" @is "" +test.bake._path_dirname(){ + assert "$(bake._path_dirname a/b/c '/')" @is "a/b" + assert "$(bake._path_dirname a '/')" @is "" + assert "$(bake._path_dirname "" '/')" @is "" # abstract path - assert "$(bake.path.dirname /a/b/c '/')" @is "/a/b" - assert "$(bake.path.dirname /a '/')" @is "" - assert "$(bake.path.dirname / '/')" @is "" + assert "$(bake._path_dirname /a/b/c '/')" @is "/a/b" + assert "$(bake._path_dirname /a '/')" @is "" + assert "$(bake._path_dirname / '/')" @is "" } -test.bake.path.first(){ - assert "$(bake.path.first a/b/c '/')" @is "a" - assert "$(bake.path.first a '/')" @is "a" - assert "$(bake.path.first '' '/')" @is "" +test.bake._path_first(){ + assert "$(bake._path_first a/b/c '/')" @is "a" + assert "$(bake._path_first a '/')" @is "a" + assert "$(bake._path_first '' '/')" @is "" - assert "$(bake.path.first /a/b/c '/')" @is "/a" + assert "$(bake._path_first /a/b/c '/')" @is "/a" } -test.bake.path.basename(){ - assert "$(bake.path.basename a/b/c '/')" @is "c" - assert "$(bake.path.basename a '/')" @is "a" - assert "$(bake.path.basename "" '/')" @is "" +test.bake._path_basename(){ + assert "$(bake._path_basename a/b/c '/')" @is "c" + assert "$(bake._path_basename a '/')" @is "a" + assert "$(bake._path_basename "" '/')" @is "" # abstract path - assert "$(bake.path.basename "/a" '/')" @is "a" - assert "$(bake.path.basename "/" '/')" @is "" + assert "$(bake._path_basename "/a" '/')" @is "a" + assert "$(bake._path_basename "/" '/')" @is "" } -test.bake.str.cutLeft(){ - assert "$(bake.str.cutLeft a/b/c 'a/b/')" @is "c" - assert "$(bake.str.cutLeft a/b/c '')" @is "a/b/c" +test.bake._str_cutLeft(){ + assert "$(bake._str_cutLeft a/b/c 'a/b/')" @is "c" + assert "$(bake._str_cutLeft a/b/c '')" @is "a/b/c" - assert "$(bake.str.cutLeft /a/b/c '/')" @is "a/b/c" + assert "$(bake._str_cutLeft /a/b/c '/')" @is "a/b/c" - assert "$(bake.str.cutLeft a/b/c 'notStart')" @is "a/b/c" - assert "$(bake.str.cutLeft a/b/c '/')" @is "a/b/c" + assert "$(bake._str_cutLeft a/b/c 'notStart')" @is "a/b/c" + assert "$(bake._str_cutLeft a/b/c '/')" @is "a/b/c" } -test.bake.cmd.up_chain(){ - assert "$(bake.cmd.up_chain a.b)" @is_escape "a.b\na\n_root" - assert "$(bake.cmd.up_chain '_root')" @is "_root" - assert "$(bake.cmd.up_chain '')" @is "_root" +test.bake._cmd_up_chain(){ + assert "$(bake._cmd_up_chain a.b)" @is_escape "a.b\na\n_root" + assert "$(bake._cmd_up_chain '_root')" @is "_root" + assert "$(bake._cmd_up_chain '')" @is "_root" } -test.bake.cmd.children(){ - assert "$(bake.cmd.children bake.test)" @is_escape "all" +test.bake._cmd_children(){ + assert "$(bake._cmd_children bake.test)" @is_escape "all" } test.bake.str.split(){ - assert "$(bake.str.split "a/b" '/')" @is_escape "a\nb" - assert "$(bake.str.split "a/b/" '/')" @is_escape "a\nb" + assert "$(bake._str_split "a/b" '/')" @is_escape "a\nb" + assert "$(bake._str_split "a/b/" '/')" @is_escape "a\nb" # abstract path - assert "$(bake.str.split "/a/b" '/')" @is_escape "\na\nb" - assert "$(bake.str.split "/a/b/" '/')" @is_escape "\na\nb" + assert "$(bake._str_split "/a/b" '/')" @is_escape "\na\nb" + assert "$(bake._str_split "/a/b/" '/')" @is_escape "\na\nb" # 包含破坏性特殊字符 - assert "$(bake.str.split $'a\nb' "/" )" @is_escape "a\nb" - assert "$(bake.str.split $'a\n/b' "/" )" @is_escape "a\n\nb" - assert "$(bake.str.split "a + assert "$(bake._str_split $'a\nb' "/" )" @is_escape "a\nb" + assert "$(bake._str_split $'a\n/b' "/" )" @is_escape "a\n\nb" + assert "$(bake._str_split "a /b " )" @is_escape "a\n\nb" # default delimiter - assert "$(bake.str.split "a/b" )" @is_escape "a\nb" + assert "$(bake._str_split "a/b" )" @is_escape "a\nb" # other delimiter - assert "$(bake.str.split "a.b" '.')" @is_escape "a\nb" + assert "$(bake._str_split "a.b" '.')" @is_escape "a\nb" } -test.bake.cmd.register()( - bake.cmd.register - assert "$(_self | grep test.bake.cmd.register)" \ - @contains "test.bake.cmd.register" -) +test.bake._cmd_register(){ + bake._cmd_register + assert "$(bake.info | grep test.bake._cmd_register)" \ + @contains "test.bake._cmd_register" +} test.data.children(){ - assert "$(bake.data.children "bake.opt.set/opts")" @is_escape "abbr\ncmd\ndefault\nname\noptHelp\nrequired\ntype" + assert "$(bake._data_children "bake.opt.set/opts")" @is_escape "abbr\ncmd\ndefault\nname\noptHelp\nrequired\ntype" } -test.bake.opt.cmd_chain_opts(){ - assert "$(bake.opt.cmd_chain_opts "_root")" @is \ -"_root/opts/help -_root/opts/log +test.bake._opt_cmd_chain_opts(){ + assert "$(bake._opt_cmd_chain_opts "_root")" @is \ +"_root/opts/debug +_root/opts/help _root/opts/verbose" # "include parent option" - assert "$(bake.opt.cmd_chain_opts "bake.opt.set")" @is \ -"_root/opts/help -_root/opts/log + assert "$(bake._opt_cmd_chain_opts "bake.opt.set")" @is \ +"_root/opts/debug +_root/opts/help _root/opts/verbose bake.opt.set/opts/abbr bake.opt.set/opts/cmd @@ -442,16 +445,16 @@ declare optShift=4;' assert "$(bake.opt.parse "test.cmd.parse" --no_exists_opt)" @is "declare optShift=0;" } -test.bake.opt.set()( +test.bake.opt.set(){ bake.opt.set --cmd "test.opt.add" --name boolopt --type bool -) +} -test.bake.opt.value.parse_and_get_value()( +test.bake.opt.value.parse_and_get_value(){ bake.opt.set --cmd "test.opt.add" --name xxx --type string echo $(bake.opt.parse "test.opt.add" --xxx chen) eval "$(bake.opt.parse "test.opt.add" --xxx chen)" assert "$xxx" @is "chen" -) +} function test(){