868 lines
22 KiB
Bash
Executable File
868 lines
22 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# shellcheck disable=SC2034 # variable not used
|
|
|
|
# Exit on error. Append "|| true" if you expect an error.
|
|
set -o errexit
|
|
# Exit on error inside any functions or subshells.
|
|
set -o errtrace
|
|
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
|
|
set -o nounset
|
|
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
|
|
set -o pipefail
|
|
# Turn on traces, useful while debugging but commented out by default
|
|
# set -o xtrace
|
|
|
|
## Globals
|
|
{
|
|
readonly _sqr_version=16
|
|
readonly _sqr_versionMajor=0
|
|
readonly _sqr_versionMinor=0
|
|
readonly _sqr_versionString="${_sqr_version}.${_sqr_versionMajor}.${_sqr_versionMinor}"
|
|
|
|
## Seq
|
|
readonly seq_name="${_sqn_alias:-${0##*/}}"
|
|
readonly seq_dir="$(cd -- "$(dirname -- "${0}")" && pwd)"
|
|
readonly seq_origin="$(cd -- "$(dirname -- "$(readlink -f -- "${0}")")" && pwd)"
|
|
readonly seq_file=$(basename -- "${0}")
|
|
readonly seq_fileName=${seq_file%%.*}
|
|
# shellcheck disable=SC2015 # && || is not if else
|
|
readonly seq_invocation="$(printf '%q' "${0}")$( (($#)) && printf ' %q' "$@" || true)"
|
|
|
|
# May be overwritten by seq
|
|
seq_configFile="${seq_fileName}.cfg"
|
|
seq_configTemplate="${0%.*}.cfg.example"
|
|
|
|
## Sequencer
|
|
readonly sqr_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
readonly sqr_file="$(basename -- "${BASH_SOURCE[0]}")"
|
|
readonly sqr_name="${sqr_file%%.*}"
|
|
readonly sqr_origin="$(cd -- "$(dirname -- \
|
|
"$(readlink -f -- "${BASH_SOURCE[0]}")")" && pwd)"
|
|
|
|
_sqr_stepMax=512
|
|
_sqr_interactive=1
|
|
_sqr_debug=0
|
|
_sqr_dry=0
|
|
_sqr_verbose=0
|
|
_sqr_errno=0
|
|
_sqr_contextHelp=0
|
|
_sqr_contextExe=0
|
|
_sqr_editor=
|
|
|
|
## Terminal position
|
|
_sqr_savePosAlias= ;[ -t 1 ] && _sqr_savePosAlias='\033[1A\033[1C\033[s\033[1B\033[1C'
|
|
_sqr_savePosExe= ;[ -t 1 ] && _sqr_savePosExe='\033[s'
|
|
_sqr_savePos= ;[ -t 1 ] && _sqr_savePos='\033[3D\033[s\033[3C'
|
|
_sqr_restorePos= ;[ -t 1 ] && _sqr_restorePos='\033[u'
|
|
|
|
## Terminal colors
|
|
col_black= ; [ -t 1 ] && col_black='\033[0;30m'
|
|
col_darkgrey= ; [ -t 1 ] && col_darkgrey='\033[1;30m'
|
|
col_red= ; [ -t 1 ] && col_red='\033[0;31m'
|
|
col_lightred= ; [ -t 1 ] && col_lightred='\033[1;31m'
|
|
col_green= ; [ -t 1 ] && col_green='\033[0;32m'
|
|
col_lightgreen= ; [ -t 1 ] && col_lightgreen='\033[1;32m'
|
|
col_orange= ; [ -t 1 ] && col_orange='\033[0;33m'
|
|
col_yellow= ; [ -t 1 ] && col_yellow='\033[1;33m'
|
|
col_blue= ; [ -t 1 ] && col_blue='\033[0;34m'
|
|
col_lightblue= ; [ -t 1 ] && col_lightblue='\033[1;34m'
|
|
col_purple= ; [ -t 1 ] && col_purple='\033[0;35m'
|
|
col_lightpurple= ; [ -t 1 ] && col_lightpurple='\033[1;35m'
|
|
col_cyan= ; [ -t 1 ] && col_cyan='\033[0;36m'
|
|
col_lightcyan= ; [ -t 1 ] && col_lightcyan='\033[1;36m'
|
|
col_lightgray= ; [ -t 1 ] && col_lightgray='\033[0;37m'
|
|
col_white= ; [ -t 1 ] && col_white='\033[1;37m'
|
|
col_off= ;[ -t 1 ] && col_off='\033[0m' # No Color
|
|
}
|
|
|
|
helpSequencer() {
|
|
cat <<USAGE_EOF
|
|
Usage: ${seq_name} [OPTIONS] [STEP NUMBER(s) or ALIAS] [STEP ARGUMENTS]
|
|
|
|
[OPTIONS]
|
|
--all, -a : Run all steps regardless of continuity
|
|
--config, -c : Open sequence configuration file (also sets -qq)
|
|
--dry-run, -d : Only print to console what would be done
|
|
! Attention - Sequence must support this
|
|
--help, -h : Display help
|
|
--helpapi, -ha : Display help about build-in supporting functions
|
|
(e.g. exe,addconf,echerr,...)
|
|
--liststeps, -ls : List all step numbers and alias
|
|
--profile, -p : Sequence configuration profile name (default: "default")
|
|
(if supported by sequence)
|
|
-pl : List available profiles
|
|
--quiet, -q : Don't ask for permission to execute steps
|
|
If called without starting step number, only this help is shown
|
|
-qq : Same as --quiet but suppresses regular sequencer.sh output
|
|
--single, -s : Execute only one step
|
|
If more than one step is requested, only the first will be executed
|
|
--verbose, -v : Verbose output (use exe() function to call shell commands in seqs)
|
|
( e.g.: exe apt update )
|
|
--version : Display version of sequencer and revision of sequence
|
|
-- : End options marker
|
|
++ : Quick start step 1 (-qq) and skipping [STEP NUMBER(s) or ALIAS]
|
|
|
|
[STEP NUMBER"(s)" 1-${_sqr_stepMax} or ALIAS]
|
|
No STEP or ALIAS : assume 1 as starting point
|
|
Single STEP or ALIAS : starting point of sequential process
|
|
Multiple STEPS or ALIAS : execute only given steps
|
|
(e.g. $0 "2 4 12")
|
|
multiple steps need to be given as string
|
|
[STEP ARGUMENTS]
|
|
* : Arguments will be passed to selected steps and step infos as:
|
|
\$2 ...
|
|
\$1 is always the step number
|
|
USAGE_EOF
|
|
}
|
|
|
|
## Logging
|
|
{
|
|
LOG_LEVEL="${LOG_LEVEL:-3}" # 4 = debug -> 0 = fatal (stop)
|
|
LOG_TIME="${LOG_TIME:-}" # 1 = show time stamps
|
|
|
|
# sqr::log [LOG LEVEL] [LOG_COLOR] [OPTIONS] [LOG MESSAGE]
|
|
# Construct log messages
|
|
#
|
|
# [OPTIONS]
|
|
# -a : append text (no info and timestamp)
|
|
# Uses color from last sqr::log call without -a
|
|
# -e : Output to stderr
|
|
# -- : End of options
|
|
#
|
|
sqr::log () {
|
|
sqr::debugPause
|
|
local appendText=
|
|
local arg=
|
|
local col_end="${col_off}"
|
|
local outp='/dev/stdout'
|
|
|
|
local log_level="${1:-}"
|
|
shift
|
|
local log_color="${1:-}"
|
|
shift
|
|
for arg in "${@}" ; do
|
|
case "${1:-}" in
|
|
--)
|
|
shift && break ;;
|
|
-a)
|
|
appendText=1
|
|
shift ;;
|
|
-e)
|
|
outp='/dev/stderr'
|
|
shift ;;
|
|
esac
|
|
done
|
|
|
|
[[ -z "${log_color}" ]] && col_end=""
|
|
|
|
# all remaining arguments are to be printed
|
|
local log_line=""
|
|
|
|
while IFS=$'\n' read -r log_line ; do
|
|
printf '%b' "${log_color}" >${outp}
|
|
if [[ -n "${LOG_TIME}" ]] ; then
|
|
if (( appendText )) ; then
|
|
printf '%24s' "" >${outp}
|
|
else
|
|
printf '%s ' "$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >${outp}
|
|
fi
|
|
fi
|
|
|
|
if (( ! appendText )) ; then
|
|
printf " %3s " "[${log_level}]" >${outp}
|
|
printf "%s" "${log_line}" >${outp}
|
|
else
|
|
# +3 : "[] "
|
|
printf "%$((${#log_level} + 4))s%s" "" "${log_line}" >${outp}
|
|
fi
|
|
|
|
printf '%b\n' "${col_end}" >${outp}
|
|
done <<< "${@:-}"
|
|
sqr::debugContinue
|
|
}
|
|
|
|
stop () { sqr::log "stop" "${col_red}" "${@}"; exit 1; }
|
|
error () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && sqr::log "e" "${col_red}" "${@}"; true; }
|
|
warning () { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && sqr::log "w" "${col_orange}" "${@}"; true; }
|
|
info () { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && sqr::log "i" "" "${@}"; true; }
|
|
debug () { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && sqr::log "dbug" "${col_lightpurple}" "${@}"; true; }
|
|
|
|
# internal print(s) same loglevel as error
|
|
# shellcheck disable=SC2059 # don't use variables in format
|
|
sqr::printf () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && printf "$@"; true; }
|
|
sqr::echo () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && echo "$@"; true; }
|
|
|
|
sqr::debugPause() {
|
|
if (( _sqr_debug )) ; then set +o xtrace; else true; fi
|
|
}
|
|
sqr::debugContinue() {
|
|
if (( _sqr_debug )) ; then set -o xtrace; else true; fi
|
|
}
|
|
|
|
# color <FOREGROUND COLOR> [BACKGROUND COLOR]
|
|
color() {
|
|
[ ! -t 1 ] && return 0
|
|
[ -z "${1:-}" ] && tput sgr0 && return 0
|
|
case "${1:-}" in
|
|
black)
|
|
tput setaf 0 ;;
|
|
red)
|
|
tput setaf 1 ;;
|
|
green)
|
|
tput setaf 2 ;;
|
|
yellow)
|
|
tput setaf 3 ;;
|
|
blue)
|
|
tput setaf 4 ;;
|
|
magenta)
|
|
tput setaf 5 ;;
|
|
cyan)
|
|
tput setaf 6 ;;
|
|
white)
|
|
tput setaf 7 ;;
|
|
none)
|
|
tput sgr0
|
|
return 0 ;;
|
|
*)
|
|
tput setaf "${1:-}" ;;
|
|
esac
|
|
|
|
case "${2:-}" in
|
|
black)
|
|
tput setab 0 ;;
|
|
red)
|
|
tput setab 1 ;;
|
|
green)
|
|
tput setab 2 ;;
|
|
yellow)
|
|
tput setab 3 ;;
|
|
blue)
|
|
tput setab 4 ;;
|
|
magenta)
|
|
tput setab 5 ;;
|
|
cyan)
|
|
tput setab 6 ;;
|
|
white)
|
|
tput setab 7 ;;
|
|
esac
|
|
}
|
|
|
|
# Echo additional line to info correctly indented
|
|
readonly _sqr_indentHelp=' : '
|
|
readonly _sqr_indentExe=' '
|
|
readonly _sqr_indentAppendHelp=' '
|
|
echoinfo() {
|
|
if [ $_sqr_contextHelp -ne 0 ] ; then
|
|
printf '%s' "$_sqr_indentAppendHelp"; echo "$@"
|
|
else
|
|
printf '%s' "$_sqr_indentExe"; echo "$@"
|
|
fi
|
|
}
|
|
|
|
# Echo info about step arguments
|
|
# Needs to be called first in _info() function
|
|
echoinfoArgs() {
|
|
echo -e "${_sqr_restorePos}$*"
|
|
if [ $_sqr_contextExe -ne 0 ]; then
|
|
printf '%s' "$_sqr_indentExe"
|
|
else
|
|
printf '%s' "$_sqr_indentHelp"
|
|
fi
|
|
}
|
|
}
|
|
|
|
## Traps
|
|
{
|
|
sqr::trap_exit () {
|
|
exists -f seq_trapExit && seq_trapExit
|
|
debug "Sequencer exit"
|
|
}
|
|
trap sqr::trap_exit EXIT
|
|
|
|
# requires `set -o errtrace`
|
|
sqr::error_report() {
|
|
local error_code=${?}
|
|
error "Error in ${sqr_file} in function ${1} on line ${2}"
|
|
exit ${error_code}
|
|
}
|
|
|
|
# Uncomment the following line for always providing an error backtrace
|
|
# trap 'sqr::error_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
|
}
|
|
|
|
# check if run as root
|
|
root() {
|
|
[[ $(id -u) -eq 0 ]]
|
|
}
|
|
# check if there is another PID other than this one
|
|
running() {
|
|
pidof -o %PPID -x "${0##*/}">>/dev/null
|
|
}
|
|
# exists [-f] [--] [ELEMENT]
|
|
# [ELEMENT]
|
|
# : either a variable name or
|
|
# -f : a function
|
|
exists() {
|
|
sqr::debugPause
|
|
local func=
|
|
local arg=
|
|
|
|
for arg in "$@" ; do
|
|
case "${1:-}" in
|
|
--)
|
|
shift && break ;;
|
|
-f)
|
|
func="${2:-}"
|
|
esac
|
|
done
|
|
sqr::debugContinue
|
|
if [[ -n "${func}" ]] ; then
|
|
declare -F "${func}" &>>/dev/null
|
|
else
|
|
[[ -n "${!1:-}" ]]
|
|
fi
|
|
}
|
|
# editor [FILE(s)..]
|
|
# Starts the detected system text editor
|
|
editor() {
|
|
"${_sqr_editor}" "$@"
|
|
}
|
|
# interactive
|
|
# Started with -q to use defaults for confirmations
|
|
interactive() {
|
|
(( _sqr_interactive ))
|
|
}
|
|
# quiet
|
|
# Log level smaller 3 (info) are treated as quiet request
|
|
quiet() {
|
|
[[ $LOG_LEVEL -lt 3 ]]
|
|
}
|
|
# silent
|
|
# Log level equals 0 (stop)
|
|
silent() {
|
|
[[ $LOG_LEVEL -eq 0 ]]
|
|
}
|
|
# dry-run
|
|
# Started with --dry-run
|
|
dry() {
|
|
(( _sqr_dry ))
|
|
}
|
|
# verbose
|
|
# Started with --verbose
|
|
verbose() {
|
|
(( _sqr_verbose ))
|
|
}
|
|
contextHelp() {
|
|
(( _sqr_contextHelp ))
|
|
}
|
|
contextExe() {
|
|
(( _sqr_contextExe ))
|
|
}
|
|
|
|
### interactive
|
|
# confirm [OPTIONS] [--] [QUESTION]
|
|
# Default (empty character) = no
|
|
# Invalid character trigger the default
|
|
#
|
|
# [OPTIONS]
|
|
# -f : interactive even if quiet
|
|
# -n : no input help
|
|
# -y : default = yes
|
|
# -- : end of options
|
|
confirm() {
|
|
sqr::debugPause
|
|
local arg=
|
|
local rexReply='^[Yy]+$' # default no
|
|
local inputHelp='[y/N] ' # default no
|
|
local noHelp=0
|
|
local force=0
|
|
|
|
for arg in "${@}" ; do
|
|
case "${1:-}" in
|
|
--)
|
|
shift && break ;;
|
|
-f)
|
|
force=1
|
|
shift ;;
|
|
-n)
|
|
noHelp=1
|
|
shift ;;
|
|
-y)
|
|
rexReply='^[^Nn]*$' # default yes
|
|
inputHelp='[Y/n] ' # default yes
|
|
shift ;;
|
|
esac
|
|
done
|
|
(( noHelp )) && inputHelp=
|
|
if interactive || (( force )) ; then
|
|
read -r -p "${1:-} ${inputHelp}" -n 1
|
|
# Needed when read stops after one character (-n 1)
|
|
# Add a newline only if input is not empty (just enter is pressed)
|
|
[[ -z "$REPLY" ]] || sqr::echo ""
|
|
else
|
|
REPLY=''
|
|
fi
|
|
sqr::debugContinue
|
|
[[ $REPLY =~ ${rexReply} ]]
|
|
}
|
|
|
|
# ask [OPTION] [QUESTION] [DEFAULT]
|
|
# Will ask for input even if quiet, when [DEFAULT] is empty
|
|
#
|
|
# [OPTION]
|
|
# -e : allow empty input
|
|
# Ignored if [DEFAULT] is available
|
|
# -s : ask for secret (don't print input)
|
|
# Does not add a newline. Usage:
|
|
# pass=$(ask -s "Password"); echo
|
|
# -- : End of options
|
|
ask() {
|
|
sqr::debugPause
|
|
local hidden=
|
|
local empty=0
|
|
local arg=
|
|
for arg in "$@" ; do
|
|
case "${1}" in
|
|
--)
|
|
shift && break ;;
|
|
-e)
|
|
empty=1
|
|
shift ;;
|
|
-s)
|
|
hidden="-s"
|
|
shift ;;
|
|
esac
|
|
done
|
|
local answer=
|
|
if [[ -n "${2:-}" ]] ; then
|
|
! interactive && printf '%s\n' "${2}" && sqr::debugContinue && return 0
|
|
read ${hidden?} -r -p "${1:-"User input"} ($2) " answer
|
|
else
|
|
read ${hidden?} -r -p "${1:-"User input"} " answer
|
|
fi
|
|
if [[ -z "$answer" ]] ; then
|
|
answer="${2:-}"
|
|
fi
|
|
printf '%s\n' "${answer}"
|
|
|
|
# return if answer is empty
|
|
sqr::debugContinue
|
|
if (( ! empty )) ; then
|
|
[[ -n "${answer}" ]]
|
|
fi
|
|
}
|
|
# Escaping non-printable characters with the proposed POSIX $'' syntax
|
|
escpath() {
|
|
printf "%q" "$*"
|
|
}
|
|
# saveReturn <ERRNO>
|
|
# Function returns with <ERRNO> in case step wants additional evaluation
|
|
saveReturn() {
|
|
if [[ "${1:-"0"}" -ne 0 ]] ; then
|
|
_sqr_errno=${1}
|
|
fi
|
|
return "${_sqr_errno}"
|
|
}
|
|
|
|
# getReturn
|
|
# Returns latest saved $_sqr_errno
|
|
getReturn() {
|
|
return "${_sqr_errno}"
|
|
}
|
|
|
|
# endReturn [-f] [-o ERRORCODE] [MESSAGE]
|
|
# -f : force exit with $_sqr_errno without user input
|
|
# -o : override and check given [ERRORCODE]
|
|
# [MESSAGE] : Custom error message
|
|
#
|
|
endReturn() {
|
|
local arg
|
|
local forceExit=0
|
|
local errorCode=${_sqr_errno}
|
|
local endMessage=""
|
|
|
|
for arg in "$@" ; do
|
|
case "$1" in
|
|
-f)
|
|
forceExit=1
|
|
shift
|
|
;;
|
|
-o)
|
|
shift
|
|
local rex='^[-]*[0-9]+$'
|
|
# Check if string is a number or alias
|
|
if [[ "${1:?}" =~ ${rex} ]] ; then
|
|
errorCode="${1:?}"
|
|
else
|
|
warning " [W] Ignoring invalid error code: $1"
|
|
fi
|
|
shift
|
|
;;
|
|
"")
|
|
break
|
|
;;
|
|
*)
|
|
endMessage="$*"
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if ( [[ ${errorCode} -ne 0 ]] && ! interactive ) \
|
|
|| [[ ${errorCode} -ne 0 && $forceExit -ne 0 ]] ; then
|
|
sqr::echo
|
|
if [[ -n "${endMessage}" ]] ; then
|
|
error -e "${endMessage}"
|
|
error -e -a "Sequence stopped"
|
|
else
|
|
error -e "Return value ${errorCode} detected."
|
|
error -e -a "Sequence stopped"
|
|
fi
|
|
exit "${errorCode}"
|
|
fi
|
|
if [[ "${errorCode}" -ne 0 ]] ; then
|
|
sqr::echo
|
|
if [ "${endMessage}" != "" ]; then
|
|
error -e "${endMessage}"
|
|
else
|
|
error -e "Return value ${errorCode} detected."
|
|
fi
|
|
if confirm -y "End sequence" ; then
|
|
error -e "Sequence stopped"
|
|
exit "${errorCode}"
|
|
else
|
|
# reset saved error code if user chooses to continue
|
|
_sqr_errno=0
|
|
sqr::echo
|
|
warning "Continuing sequence..."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# checkStep <Step Number or Alias>
|
|
# return 0 - for invalid step
|
|
# return Step Number
|
|
# Check sanitiy of step number or
|
|
# Check if alias exists
|
|
checkStep() {
|
|
local checkStep_rex='^[0-9]+$'
|
|
local checkStep_ref=""
|
|
|
|
# Check if string is a number or alias
|
|
if ! [[ "${1:-}" =~ ${checkStep_rex} ]] ; then
|
|
eval 'checkStep_ref=${_sqr_alias_'"${1:-}"'}'
|
|
# Catch special character after eval
|
|
if ! [[ "${checkStep_ref}" =~ ${checkStep_rex} ]] ; then
|
|
checkStep_ref=0
|
|
fi
|
|
else
|
|
checkStep_ref="$1"
|
|
fi
|
|
|
|
if (( checkStep_ref < 1 || checkStep_ref > _sqr_stepMax )) ; then
|
|
error "Invalid step: ${1:-}"
|
|
printf '0'
|
|
return 1
|
|
else
|
|
if exists -f "step_$checkStep_ref" ; then
|
|
printf '%s' "${checkStep_ref}"
|
|
return 0
|
|
else
|
|
# step doesn't exist
|
|
error "Invalid step: ${1:-}"
|
|
printf '0'
|
|
return 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# step <Step Number of Alias>
|
|
# execute given step
|
|
step() {
|
|
local stepNo=0
|
|
local stepArgs=("$@")
|
|
|
|
if ! stepNo="$(checkStep "${1:-}")" ; then
|
|
return 1
|
|
else
|
|
"step_$stepNo" "${stepArgs[@]}"
|
|
fi
|
|
color
|
|
}
|
|
|
|
# Parse alias functions "step_[STEP NUBER]_alias" to create
|
|
# back reference variable of schema:
|
|
# alias_[ALIAS]=[STEP NUMBER]
|
|
parseAlias() {
|
|
local i
|
|
for ((i=1; i<=_sqr_stepMax; i++)); do
|
|
# Check for alias definition
|
|
exists -f "step_${i}_alias" || continue
|
|
|
|
# Function returns step alias
|
|
eval '_sqr_alias_'"$("step_${i}_alias")"'='"$i"
|
|
done
|
|
}
|
|
|
|
# displayHelp [NO TEMPLATE] [STEP NUMBER OR ALIAS]
|
|
# [NO TEMPLATE]
|
|
# 0 (default) : Ask for template creation
|
|
# 1 : Do not ask for template creation
|
|
# [STEP NUMBER OR ALIAS]
|
|
# [NO TEMPLATE] must be set
|
|
# Display step info function only for given step
|
|
#
|
|
# - Display sequencer help and, if available, sequence help
|
|
# - Cluster continous (more than 1) steps visually together
|
|
displayHelp() {
|
|
sqr::debugPause
|
|
local i
|
|
local answer
|
|
local clusterSize=0
|
|
local lastClusterSize=0
|
|
local createTemplate=1
|
|
local stepFound=0
|
|
local loopStart=0
|
|
local loopEnd="${_sqr_stepMax}"
|
|
_sqr_contextHelp=1
|
|
|
|
# check if help is requested for a single step
|
|
if [ -n "${2:-}" ]; then
|
|
parseAlias
|
|
loopStart="$(checkStep "$2")"
|
|
fi
|
|
|
|
if [[ "$loopStart" == "0" ]] ; then
|
|
helpSequencer
|
|
loopStart=1
|
|
else
|
|
# Output loop only for one step
|
|
loopEnd=$loopStart
|
|
fi
|
|
|
|
if [ -n "${1:-}" ] && [[ ${1:-} -eq 1 ]] ; then
|
|
createTemplate=0
|
|
fi
|
|
|
|
# check if step definition exists by looking for a step_*() function
|
|
for ((i=1; i<=_sqr_stepMax; i++)); do
|
|
if ! exists -f "step_${i}" ; then
|
|
continue
|
|
fi
|
|
stepFound=$i
|
|
break
|
|
done
|
|
|
|
if [[ "$stepFound" -eq 0 ]] ; then
|
|
printf '\n %s\n' "It seems ${0##*/} was called directly."
|
|
printf ' %s\n\n' "Please create a sequence script first."
|
|
if [ $createTemplate -ne 0 ] ; then
|
|
if confirm -- " Create a template now?" ; then
|
|
sqr::echo "TODO: createTemplate"
|
|
if [ $? -eq 0 ] ; then
|
|
printf '\n %s\n' "$TEMPLATE_NAME created."
|
|
else
|
|
printf '\n %s\n' "$TEMPLATE_NAME exists...Nothing to do!"
|
|
fi
|
|
else
|
|
printf '\n Nothing to do!\n'
|
|
fi
|
|
fi
|
|
exit 1
|
|
else
|
|
printf '\n %s\n' "Step (= alias) [STEP ARGS] : documentation"
|
|
for ((i=loopStart; i<=loopEnd; i++)); do
|
|
|
|
# Display step reference in help if step function exists
|
|
if ! exists -f "step_${i}" ; then
|
|
if [ $clusterSize -ne 0 ] ; then
|
|
# Mark the end of a cluster
|
|
lastClusterSize=$clusterSize
|
|
clusterSize=0
|
|
fi
|
|
continue
|
|
fi
|
|
((clusterSize+=1))
|
|
if [ $lastClusterSize -gt 1 ] ; then
|
|
# Add separation at the end of a cluster
|
|
lastClusterSize=0
|
|
echo
|
|
elif [[ $clusterSize -eq 1 ]]; then
|
|
# Add separation before the start of a cluster if it is not the first
|
|
exists -f "step_$((i+1))" && [[ $i -ne $stepFound ]] && echo
|
|
fi
|
|
printf ' %3s ' "$i"
|
|
|
|
# Display alias if exists
|
|
if exists -f "step_${i}_alias" ; then
|
|
echo -en " = ${col_orange}$("step_${i}_alias")${col_off}${_sqr_savePosAlias}"
|
|
# Newline only if step info() exists
|
|
exists -f "step_${i}_info" && printf '\n%s' "$_sqr_indentHelp"
|
|
else
|
|
echo -en " : ${_sqr_savePos}"
|
|
fi
|
|
|
|
# Display step help only if info function exists
|
|
if exists -f "step_${i}_info" ; then
|
|
"step_${i}_info" "$i"
|
|
else
|
|
echo
|
|
fi
|
|
color ""
|
|
done
|
|
echo
|
|
fi
|
|
_sqr_contextHelp=0
|
|
sqr::debugContinue
|
|
}
|
|
|
|
# listSteps [FILTER STRING]
|
|
# [FILTER STRING]
|
|
# show only steps and aliases starting with [FILTER STRING]
|
|
listSteps() {
|
|
local locAlias=
|
|
local aList=()
|
|
local aSearch="${1:-}"
|
|
|
|
for ((i=1; i<=_sqr_stepMax; i++)); do
|
|
# Display step reference in help if step function exists
|
|
exists -f "step_${i}" || continue
|
|
|
|
# Display alias if exists
|
|
if exists -f "step_${i}_alias" ; then
|
|
locAlias="$("step_${i}_alias")"
|
|
else
|
|
locAlias="$i"
|
|
fi
|
|
|
|
if [ -z "$aSearch" ]; then
|
|
aList+=("$locAlias")
|
|
elif [[ "$locAlias" =~ ^$aSearch ]]; then
|
|
aList+=("$locAlias")
|
|
fi
|
|
done
|
|
|
|
[ ${#aList[@]} -ne 0 ] && printf '%s\n' "${aList[*]}"
|
|
}
|
|
|
|
# showVersion
|
|
showVersion() {
|
|
printf 'Sequencer %s\n' "${_sqr_versionString}"
|
|
printf 'Seq Revision %s\n' "${VERSION_SEQREV:-"-"}"
|
|
}
|
|
|
|
# exe <COMMAND>
|
|
# Handle dry run and verbose output for commands without pipe and/or redirects
|
|
exe() {
|
|
dry && printf -- '--'
|
|
if dry || verbose ; then
|
|
(set -x; : "$@")
|
|
fi
|
|
|
|
if ! dry ; then
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
# exep <COMMAND AS STRING(S)>
|
|
# Handle dry run and verbose output for commands containing pipe and/or redirects
|
|
exep() {
|
|
if dry ; then
|
|
printf -- '--++ : %s\n' "$*"
|
|
elif verbose ; then
|
|
printf '++ : %s\n' "$*"
|
|
fi
|
|
|
|
if ! dry ; then
|
|
bash -c "$*"
|
|
fi
|
|
}
|
|
|
|
# Used as editor if no system editor could be found
|
|
sqr::noEditor() {
|
|
error "No editor found (\$EDITOR,\"/etc/alternatives\",nano,vi)"
|
|
error -a "Cannot open: $*"
|
|
}
|
|
|
|
sqr::main() {
|
|
local quickStartOne=0
|
|
|
|
# options check
|
|
for arg in "$@" ; do
|
|
case "$1" in
|
|
--debug)
|
|
_sqr_debug="1"
|
|
shift ;;
|
|
--dry-run|-d)
|
|
_sqr_dry=1
|
|
shift ;;
|
|
--help|-h) # show only help
|
|
displayHelp 1 "${2:-}"
|
|
exit 0;;
|
|
--liststeps|-ls)
|
|
shift
|
|
listSteps "${1:-}"
|
|
exit 0;;
|
|
--quiet|-q)
|
|
_sqr_interactive=0
|
|
shift ;;
|
|
--silent|-qq)
|
|
_sqr_interactive=0
|
|
LOG_LEVEL=0
|
|
shift ;;
|
|
--verbose|-v)
|
|
_sqr_verbose=1
|
|
shift ;;
|
|
--version) # version request
|
|
showVersion
|
|
exit 0;;
|
|
esac
|
|
done
|
|
|
|
# debug mode
|
|
if [[ "${_sqr_debug:-}" = "1" ]]; then
|
|
set -o xtrace
|
|
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
|
# Enable error backtracing
|
|
trap 'sqr::error_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
|
fi
|
|
|
|
# Don't show help if only configuration should be edited
|
|
# TODO [ $SEQ_CONFIG_EDIT -ne 0 ] && [ -z "$1" ] && QUIET=2
|
|
|
|
if [ -z "${1:-}" ] && [ $quickStartOne -eq 0 ] ; then
|
|
if ! quiet ; then
|
|
# Empty -> show help
|
|
displayHelp
|
|
fi
|
|
# Assume starting at one for interactive mode
|
|
START=1
|
|
elif [ $quickStartOne -ne 0 ] ; then
|
|
EMPTYCALL=0
|
|
START=1
|
|
STEP_ARGS=( "$@" )
|
|
else
|
|
EMPTYCALL=0
|
|
read -r -a START <<< "$1"
|
|
shift
|
|
STEP_ARGS=( "$@" )
|
|
fi
|
|
|
|
# Determine system default editor
|
|
# Change with update-alternatives --config editor
|
|
_sqr_editor="$(realpath -eq "/etc/alternatives/editor")"
|
|
## Various fallbacks
|
|
[ -z "${_sqr_editor}" ] && _sqr_editor="$EDITOR"
|
|
[ -z "${_sqr_editor}" ] && _sqr_editor="$(command -v nano)"
|
|
[ -z "${_sqr_editor}" ] && _sqr_editor="$(command -v vi)"
|
|
## Fall back to error message
|
|
[ -z "${_sqr_editor}" ] && _sqr_editor="sqr::noEditor"
|
|
|
|
sqr::printf 'Running...\n'
|
|
seq_config 2>/dev/null || true
|
|
step 1 "$@"
|
|
}
|
|
|
|
sqr::main "$@"
|
|
|