4 Commits

  1. 48
      bin/miaou-bash
  2. 59
      lib/ansi.bash
  3. 3
      test/miaou-bash.test.bash
  4. 18
      test/stub/scenario.bash

48
bin/miaou-bash

@ -8,15 +8,15 @@ readonly MIAOU_BASH_ERROR MIAOU_BASH_DEBUG
# FUNCTIONS
function on_return {
# regex does not work here unfortunately!
if [[ "${BASH_COMMAND}" == 'return '* ]]; then
code=$(echo "${BASH_COMMAND}" | cut -d' ' -f2)
if [[ -n "$code" ]] && [[ "$code" -ne 0 ]]; then
trap - DEBUG
>&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: return $code from ${FUNCNAME[1]}"
fi
fi
function is_true {
[[ "${1,,}" =~ ^(true|yes|1)$ ]]
}
# overridden function which permits backtracing of original `return` statement
function false {
>&2 echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]} false"
debug "overridden false"
builtin false
}
# overridden function which permits backtracing of original `exit` statement
@ -28,6 +28,17 @@ function exit {
builtin exit "$code"
}
function on_return {
# regex does not work here unfortunately!
if [[ "${BASH_COMMAND}" == 'return '* ]]; then
code=$(echo "${BASH_COMMAND}" | cut -d' ' -f2)
if [[ -n "$code" ]] && [[ "$code" -ne 0 ]]; then
trap - DEBUG
>&2 echo "${BASH_SOURCE[2]}: line ${BASH_LINENO[0]}: return $code from ${FUNCNAME[1]}"
fi
fi
}
function on_exit {
code=${1:-0}
@ -48,8 +59,8 @@ function on_exit {
unset 'stack_sources[0]'
unset 'stack_sources[-1]'
if [[ "${#stack_functions[@]}" -gt 1 && "${stack_functions[1]}" == exit && "${stack_sources[1]}" == "${BASH_SOURCE[0]}" ]]; then
# the exit case scenario
if [[ "${#stack_functions[@]}" -gt 1 && "${stack_functions[1]}" =~ exit|false && "${stack_sources[1]}" == "${BASH_SOURCE[0]}" ]]; then
# the exit or false case scenario
unset 'stack_functions[1]'
unset 'stack_sources[1]'
unset 'stack_lines[0]'
@ -70,6 +81,7 @@ function on_exit {
last_source=${last_source//./"\."} # replace '.' with '\.'
regex1="^$last_source: line ([0-9]+): (.*)\$"
regex2="^$last_source:([0-9]+) (.*)\$"
# debug "last_error=[$last_error] <=> ${last_source}"
if [[ "$last_error" =~ $regex1 || "$last_error" =~ $regex2 ]]; then
line=${BASH_REMATCH[1]}
message=${BASH_REMATCH[2]}
@ -80,7 +92,9 @@ function on_exit {
failure_payload="${BASH_REMATCH[1]}"
stack_lines[0]=$line
else
if [[ "$message" == 'false' ]]; then
failure_type='FALSE'
else
regex="^return ([0-9]*) from (.*)\$"
if [[ "$message" =~ $regex ]]; then
# return_code="${BASH_REMATCH[1]}"
@ -132,6 +146,7 @@ function on_exit {
fi
fi
fi
fi
else
failure_type='UNDEFINED'
debug "last error=${last_error}"
@ -167,8 +182,7 @@ function on_exit {
}
function debug {
$MIAOU_BASH_DEBUG && >/dev/tty echo "*********** DEBUG: $*"
true
is_true "${MIAOU_BASH_DEBUG}" && >/dev/tty echo "*********** DEBUG: $*" || true
}
function dump_failure {
@ -195,9 +209,9 @@ function dump_failure {
function dump_stderr {
last_trim=${1:-false}
mapfile -t tmp_error <"$MIAOU_BASH_ERROR"
$last_trim && unset 'tmp_error[-1]' && tmp_error=("${tmp_error[@]}")
is_true "$last_trim" && unset 'tmp_error[-1]' && tmp_error=("${tmp_error[@]}")
if [[ "${#tmp_error[@]}" -gt 0 ]]; then
$MIAOU_BASH_DEBUG && >/dev/tty echo '---stderr---'
debug '---stderr---'
for i in "${tmp_error[@]}"; do
>&4 echo -e "$i"
done
@ -227,7 +241,7 @@ BASH_ARGV0="$1" && shift # to pretend script runs by itself
# magic FD + delayed tee => /dev/fd/3 means delayed stderr, /dev/fd/4 remains original stderr
exec 3> >(tee "$MIAOU_BASH_ERROR" >/dev/null) 4>/dev/stderr
$MIAOU_BASH_DEBUG && >/dev/tty echo '---stdout---'
debug '---stdout---'
# shellcheck source=/dev/null
source "$BASH_ARGV0" 2>&3
dump_success

59
lib/ansi.bash

@ -3,14 +3,30 @@
# MARGIN=0
PADDING=0
ANSI_RESET='\e[0m'
declare -A FG_COLORS
FG_COLORS["BLACK"]='\e[30m'
FG_COLORS["RED"]='\e[31m'
FG_COLORS["GREEN"]='\e[32m'
FG_COLORS["YELLOW"]='\e[93m'
FG_COLORS["YELLOW"]='\e[33m'
FG_COLORS["BLUE"]='\e[34m'
FG_COLORS["PURPLE"]='\e[35m'
FG_COLORS["CYAN"]='\e[36m'
FG_COLORS["MAGENTA"]='\e[95m'
FG_COLORS["WHITE"]='\e[37m'
FG_COLORS["GRAY"]='\e[90m'
FG_COLORS["MAGENTA"]='\e[95m'
declare -A BG_COLORS
BG_COLORS["BLACK"]='\e[40m'
BG_COLORS["RED"]='\e[41m'
BG_COLORS["GREEN"]='\e[42m'
BG_COLORS["YELLOW"]='\e[43m'
BG_COLORS["BLUE"]='\e[44m'
BG_COLORS["PURPLE"]='\e[45m'
BG_COLORS["CYAN"]='\e[46m'
BG_COLORS["WHITE"]='\e[47m'
# BG_COLORS["GRAY"]='\e[90m'
# BG_COLORS["MAGENTA"]='\e[95m'
# FUNCTIONS
@ -21,40 +37,63 @@ function ansi_length {
}
function style_padding {
local left right
local padding_left=${PADDING_LEFT:-$PADDING}
local padding_right=${PADDING_RIGHT:-$PADDING}
for _ in $(seq 1 "${padding_left}"); do builtin echo -n ' '; done
left=$(for _ in $(seq 1 "${padding_left}"); do builtin echo -n ' '; done)
style_ansi "$left"
builtin echo -n "$1"
for _ in $(seq 1 "${padding_right}"); do builtin echo -n ' '; done
right=$(for _ in $(seq 1 "${padding_right}"); do builtin echo -n ' '; done)
style_ansi "$right"
}
function _style_fg {
[[ -n $1 ]] && echo "${FG_COLORS[$1]}" || true
}
function _style_bg {
if [[ -n "$1" ]]; then
[[ -v BG_COLORS[$1] ]] && echo "${BG_COLORS[$1]}" && return
>&2 echo "unknown BG value: $1"
false
fi
}
function style_ansi {
local fg
local fg bg
fg=$(_style_fg "${FG:-}")
# local bg=${BG:-}
bg=$(_style_bg "${BG:-}")
[[ -n $fg ]] && builtin echo -en "$fg"
[[ -n $bg ]] && builtin echo -en "$bg"
builtin echo -en "$1"
[[ -n $fg ]] && builtin echo -en "$ANSI_RESET"
[[ -n $fg || -n $bg ]] && builtin echo -en "$ANSI_RESET"
true
}
function style_block {
local content length
local content length top bottom
content=$(style_padding "$1")
length=$(ansi_length "$content")
length=$((length + 2))
top=$(
builtin echo -n "╔"
for _ in $(seq 1 "${length}"); do builtin echo -n '═'; done
builtin echo "╗"
)
style_ansi "${top}" && echo
builtin echo "$content"
style_ansi "║"
style_ansi "${content}"
style_ansi "║" && echo
bottom=$(
builtin echo -n "╚"
for _ in $(seq 1 "${length}"); do builtin echo -n '═'; done
builtin echo "╝"
)
style_ansi "${bottom}" && echo
}

3
test/miaou-bash.test.bash

@ -1,3 +1,6 @@
#!/usr/bin/env bash
# do not use miaou-bash as the shebang
./test/stub/scenario.bash success >/dev/null
[[ $(./test/stub/scenario.bash unbound_variable 2>&1 1>/dev/null) =~ 'TYPE: UNBOUND VARIABLE' ]]
[[ $(./test/stub/scenario.bash false 2>&1 1>/dev/null) =~ 'TYPE: FALSE' ]]

18
test/stub/scenario.bash

@ -7,6 +7,19 @@ readonly BASEDIR
# SCENARII
function do_pipe_error {
declare -A associative
associative['A']='Abc'
[[ -v associative['A'] ]] && echo "${associative['A']}"
true
}
function do_false {
echo before false
false
echo after false
}
function do_success {
echo -n 'SUCCESS args=['
(
@ -16,8 +29,9 @@ function do_success {
echo ']'
source "${MIAOU_BASH_DIR}/lib/ansi.bash"
local content
content=$(FG=MAGENTA style_ansi "this is success")
FG=GRAY PADDING=8 style_block "$content"
content=$(PADDING_LEFT=2 PADDING_RIGHT=6 style_padding 'this is success')
content=$(FG=YELLOW BG=BLUE style_ansi "$content")
FG=BLACK BG=RED PADDING=8 style_block "$content"
}
function do_unbound_variable {

Loading…
Cancel
Save