if [ "$0" != "${BASH_SOURCE[0]}" ] && [ "$BAKE_INTERNAL_CAN_SOURCE" != 'yes' ]; then
printf '%s\n' 'Error: This file should not be sourced' >&2
return 1
fi
bake.die() {
if [ -n "$1" ]; then
__bake_error "$1. Exiting"
else
__bake_error 'Exiting'
fi
__bake_print_big '<- ERROR'
__bake_print_stacktrace
exit 1
}
bake.warn() {
if __bake_is_color; then
printf "\033[1;33m%s:\033[0m %s\n" 'Warn' "$1"
else
printf '%s: %s\n' 'Warn' "$1"
fi
} >&2
bake.info() {
if __bake_is_color; then
printf "\033[0;34m%s:\033[0m %s\n" 'Info' "$1"
else
printf '%s: %s\n' 'Info' "$1"
fi
}
bake.assert_nonempty() {
__bake_internal_warn "Function 'bake.assert_nonempty' is deprecated. Please use 'bake.assert_not_empty' instead"
bake.assert_not_empty "$@"
}
bake.assert_not_empty() {
local variable_name=
for variable_name; do
local -n ____variable="$variable_name"
if [ -z "$____variable" ]; then
bake.die "Failed because variable '$variable_name' is empty"
fi
done; unset -v variable_name
}
bake.assert_cmd() {
local cmd=$1
if [ -z "$cmd" ]; then
bake.die "Argument must not be empty"
fi
if ! command -v "$cmd" &>/dev/null; then
bake.die "Failed to find command '$cmd'. Please install it before continuing"
fi
}
bake.cfg() {
local cfg="$1"
local value="$2"
case $cfg in
stacktrace)
case $value in
yes|no) __bake_cfg_stacktrace=$value ;;
*) __bake_internal_die2 "Config property '$cfg' accepts only either 'yes' or 'no'" ;;
esac
;;
pedantic-task-cd)
case $value in
yes) trap '__bake_trap_debug' 'DEBUG' ;;
no) trap - 'DEBUG' ;;
*) __bake_internal_die2 "Config property '$cfg' accepts only either 'yes' or 'no'" ;;
esac
;;
big-print)
case $value in
yes|no) ;;
*) __bake_internal_die2 "Config property '$cfg' accepts only either 'yes' or 'no'" ;;
esac
;;
*)
__bake_internal_die2 "No config property matched '$cfg'"
;;
esac
}
__bake_print_stacktrace() {
if [ "$__bake_cfg_stacktrace" = 'yes' ]; then
if __bake_is_color; then
printf '\033[4m%s\033[0m\n' 'Stacktrace:'
else
printf '%s\n' 'Stacktrace:'
fi
local i=
for ((i=0; i<${#FUNCNAME[@]}-1; ++i)); do
local __bash_source="${BASH_SOURCE[$i]}"; __bash_source=${__bash_source##*/}
printf '%s\n' " in ${FUNCNAME[$i]} ($__bash_source:${BASH_LINENO[$i-1]})"
done; unset -v i __bash_source
fi
} >&2
__bake_trap_err() {
local error_code=$?
__bake_print_big "<- ERROR"
__bake_internal_error "Your Bakefile did not exit successfully (exit code $error_code)"
__bake_print_stacktrace
exit $error_code
} >&2
__global_bake_trap_debug_current_function=
__bake_trap_debug() {
local current_function="${FUNCNAME[1]}"
if [[ $current_function != "$__global_bake_trap_debug_current_function" \
&& $current_function == task.* ]]; then
if ! cd "$BAKE_ROOT"; then
__bake_internal_die "Failed to cd to \$BAKE_ROOT"
fi
fi
__global_bake_trap_debug_current_function=$current_function
} >&2
__bake_is_color() {
if [[ -v NO_COLOR || $TERM == dumb ]]; then
return 1
else
return 0
fi
}
__bake_internal_die() {
__bake_internal_error "$1. Exiting"
exit 1
}
__bake_internal_die2() {
__bake_print_big '<- ERROR'
__bake_internal_error "$1. Exiting"
exit 1
}
__bake_internal_error() {
if __bake_is_color; then
printf "\033[0;31m%s:\033[0m %s\n" "Error (bake)" "$1"
else
printf '%s: %s\n' 'Error (bake)' "$1"
fi
} >&2
__bake_internal_warn() {
if __bake_is_color; then
printf "\033[0;33m%s:\033[0m %s\n" "Warn (bake)" "$1"
else
printf '%s: %s\n' 'Warn (bake)' "$1"
fi
} >&2
__bake_error() {
if __bake_is_color; then
printf "\033[0;31m%s:\033[0m %s\n" 'Error' "$1"
else
printf '%s: %s\n' 'Error' "$1"
fi
} >&2
__bake_print_tasks() {
printf '%s\n' 'Tasks:'
local str=
local regex="^(([[:space:]]*function[[:space:]]*)?task\.(.*?)\(\)).*"
local line=
while IFS= read -r line || [ -n "$line" ]; do
if [[ "$line" =~ $regex ]]; then
str+=" -> ${BASH_REMATCH[3]}"$'\n'
fi
done < "$BAKE_FILE"; unset -v line
if [ -z "$str" ]; then
if __bake_is_color; then
str=$' \033[3mNo tasks\033[0m\n'
else
str=$' No tasks\n'
fi
fi
printf '%s' "$str"
} >&2
__bake_print_big() {
local print_text="$1"
if [ "$__bake_cfg_big_print" = 'no' ]; then
return
fi
local _stty_height= _stty_width=
read -r _stty_height _stty_width < <(
if command -v stty &>/dev/null; then
stty size
else
printf '%s\n' '20 80'
fi
)
local separator_text=
printf -v separator_text '%*s' $((_stty_width - ${#print_text} - 1))
printf -v separator_text '%s' "${separator_text// /=}"
if __bake_is_color; then
printf '\033[1m%s %s\033[0m\n' "$print_text" "$separator_text"
else
printf '%s %s\n' "$print_text" "$separator_text"
fi
} >&2
__bake_parse_args() {
unset REPLY; REPLY=
local -i total_shifts=0
local __bake_arg=
for arg; do case $arg in
-f)
BAKE_FILE=$2
if [ -z "$BAKE_FILE" ]; then
__bake_internal_die "A value was not specified for for flag '-f"
fi
((total_shifts += 2))
if ! shift 2; then
__bake_internal_die 'Failed to shift'
fi
if [ ! -e "$BAKE_FILE" ]; then
__bake_internal_die "Specified file '$BAKE_FILE' does not exist"
fi
if [ ! -f "$BAKE_FILE" ]; then
__bake_internal_die "Specified file '$BAKE_FILE' is not actually a file"
fi
;;
-v)
local bake_version='1.7.0'
printf '%s\n' "Version: $bake_version"
;;
-h)
local flag_help='yes'
if ! shift; then
__bake_internal_die 'Failed to shift'
fi
esac done
if [ -n "$BAKE_FILE" ]; then
BAKE_ROOT=$(
CDPATH= cd -- "${BAKE_FILE%/*}"
printf '%s\n' "$PWD"
)
BAKE_FILE="$BAKE_ROOT/${BAKE_FILE##*/}"
else
if ! BAKE_ROOT=$(
while [ ! -f './Bakefile.sh' ] && [ "$PWD" != / ]; do
if ! cd ..; then
exit 1
fi
done
if [ "$PWD" = / ]; then
exit 1
fi
printf '%s' "$PWD"
); then
__bake_internal_die "Failed to find 'Bakefile.sh'"
fi
BAKE_FILE="$BAKE_ROOT/Bakefile.sh"
fi
if [ "$flag_help" = 'yes' ]; then
cat <<-"EOF"
Usage: bake [-h|-v] [-f <Bakefile>] [var=value ...] <task> [args ...]
EOF
__bake_print_tasks
exit
fi
REPLY=$total_shifts
}
__bake_main() {
__bake_cfg_stacktrace='no'
__bake_cfg_big_print='yes'
set -ETeo pipefail
shopt -s dotglob extglob globasciiranges globstar lastpipe shift_verbose
export LANG='C' LC_CTYPE='C' LC_NUMERIC='C' LC_TIME='C' LC_COLLATE='C' \
LC_MONETARY='C' LC_MESSAGES='C' LC_PAPER='C' LC_NAME='C' LC_ADDRESS='C' \
LC_TELEPHONE='C' LC_MEASUREMENT='C' LC_IDENTIFICATION='C' LC_ALL='C'
trap '__bake_trap_err' 'ERR'
trap ':' 'INT' bake.cfg pedantic-task-cd 'no'
BAKE_ROOT=; BAKE_FILE=
__bake_parse_args "$@"
if ! shift "$REPLY"; then
__bake_internal_die 'Failed to shift'
fi
local __bake_key= __bake_value=
local __bake_arg=
for __bake_arg; do case $__bake_arg in
*=*)
IFS='=' read -r __bake_key __bake_value <<< "$__bake_arg"
declare -g "$__bake_key"
local -n __bake_variable="$__bake_key"
__bake_variable="$__bake_value"
if ! shift; then
__bake_internal_die 'Failed to shift'
fi
;;
*) break
esac done; unset -v __bake_arg
unset -v __bake_key __bake_value
unset -vn __bake_variable
local __bake_task="$1"
if [ -z "$__bake_task" ]; then
__bake_internal_error "No valid task supplied"
__bake_print_tasks
exit 1
fi
if ! shift; then
__bake_internal_die 'Failed to shift'
fi
if ! cd "$BAKE_ROOT"; then
__bake_internal_die "Failed to cd"
fi
__bake_task= source "$BAKE_FILE"
if declare -f task."$__bake_task" >/dev/null 2>&1; then
local line=
local shouldTestNextLine='no'
while IFS= read -r line; do
if [ "$shouldTestNextLine" = 'yes' ]; then
if [[ $line == *'bake.cfg'*big-print*no* ]]; then
__bake_cfg_big_print='no'
fi
shouldTestNextLine='no'
fi
if [[ $line == @(task."$__bake_task"|init)*'('*')'*'{' ]]; then
shouldTestNextLine='yes'
fi
done < "$BAKE_FILE"; unset -v line shouldTestNextLine
__bake_print_big "-> RUNNING TASK '$__bake_task'"
if declare -f init >/dev/null 2>&1; then
init "$__bake_task"
fi
task."$__bake_task" "$@"
__bake_print_big "<- DONE"
else
__bake_internal_error "Task '$__bake_task' not found"
__bake_print_tasks
exit 1
fi
}
__bake_main "$@"