full step execution support (selective or continous), profile support, addConf, seq template from own file

WIP helpApi, small refactoring of globals
This commit is contained in:
2022-05-28 23:54:07 +02:00
parent 373cc8e8b6
commit 51e3d774bd
2 changed files with 604 additions and 69 deletions

View File

@@ -2,35 +2,31 @@
readonly toolName=mytool
# Get script working directory
# (when called from a different directory and even when called via symlink)
readonly sq_dir="$(cd "$(dirname -- "$(realpath ${BASH_SOURCE[0]})")" >>/dev/null 2>&1 && pwd)"
readonly sq_scriptFile=$(basename -- $0)
readonly sq_scriptName=${sq_scriptFile%%.*}
readonly sq_configFileName="${sq_scriptName}.cfg"
readonly sq_configFileTemplate="$sq_dir/${sq_configFileName}.example"
# Already defined by sequencer.sh, but may be overwritten
#readonly seq_configName="${sq_scriptName}.cfg"
#readonly seq_configTemplate="${seq_origin}/${sq_configName}.example"
sq_aptOpt=
sq_config=0
step_config() {
seq_config() {
## Called once before executing steps.
## e.g. to source a config file manually:
#. "$sq_config_FILE"
#. "${seq_origin}/${seq_configName}"
## or to use sequencer api with profile config file support:
#initSeqConfig -p "$sq_scriptName" "$sq_configFileTemplate"
#if initSeqConfig -p "${seq_fileName}" "${seq_configTemplate}" ; then
## or to use sequencer api with global config file:
#initSeqConfig "$sq_configFileName" "$sq_configFileTemplate"
#if [ $? -eq 0 ] ; then
#if initSeqConfig "${seq_configName}" "${seq_configTemplate}" ; then
# sq_config=1
#else
# # End if no configuration file exists
# [ $DRY -eq 0 ] && return -1
# dry || return -1
#fi
## Apt cmdline option to suppress user interaction
[ $QUIET -ne 0 ] && sq_aptOpt="-y"
interactive || sq_aptOpt="-y"
## Return of non zero value will abort the sequence
return 0
@@ -39,13 +35,13 @@ step_config() {
step_1_info() { echoinfoArgs "[OPTIONS]"; echo "My custom step"; }
step_1_alias() { echo "begin"; }
step_1() {
echo "Doing something for step $1 ..."
echo "Command line arguments starting with argument 2: $@"
info "Doing something for step $1 ..."
warning "Command line arguments starting with argument 2: $*"
# Use exe for regular command
# Use exep "command" for commands containing pipes or redirects
exe ls
exep "dmesg | head"
}
VERSION_SEQREV=16
readonly sqr_minVersion=16
. /usr/local/bin/sequencer.sh

View File

@@ -15,10 +15,10 @@ set -o pipefail
## Globals
{
readonly _sqr_version=16
readonly _sqr_versionMajor=0
readonly _sqr_versionMinor=0
readonly _sqr_versionString="${_sqr_version}.${_sqr_versionMajor}.${_sqr_versionMinor}"
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##*/}}"
@@ -28,14 +28,17 @@ set -o pipefail
readonly seq_fileName=${seq_file%%.*}
# shellcheck disable=SC2015 # && || is not if else
readonly seq_invocation="$(printf '%q' "${0}")$( (($#)) && printf ' %q' "$@" || true)"
readonly seq_template="seqTemplate.sh"
seq_args=
seq_configFile= # Filled by initSeqConfig
seq_profileName=
_seq_profileList=
_seq_stepReturn=255
# May be overwritten by seq
seq_configName="${seq_fileName}.cfg"
seq_configTemplate="${0%.*}.cfg.example"
seq_profileName=
_seq_profileList=
## Sequencer
readonly sqr_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
@@ -44,6 +47,7 @@ set -o pipefail
readonly sqr_origin="$(cd -- "$(dirname -- \
"$(readlink -f -- "${BASH_SOURCE[0]}")")" && pwd)"
sqr_args=
sqr_missingConf=missingConf.log
_sqr_configEdit=0
readonly _sqr_configDirName=".seqs"
@@ -55,6 +59,7 @@ set -o pipefail
_sqr_editor=
_sqr_errno=0
_sqr_interactive=1
_sqr_single=0
readonly _sqr_stepMax=512
_sqr_verbose=0
@@ -102,7 +107,7 @@ Usage: ${seq_name} [OPTIONS] [STEP NUMBER(s) or ALIAS] [STEP ARGUMENTS]
-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
--silent, -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)
@@ -124,9 +129,238 @@ Usage: ${seq_name} [OPTIONS] [STEP NUMBER(s) or ALIAS] [STEP ARGUMENTS]
USAGE_EOF
}
helpApi(){
cat <<USAGE_API
sequencer.sh API
The sequencer.sh build-in functions are available in all sequence functions:
- step_config
If optional step_config is defined in the sequence, it will be called once before execution of steps.
- step_[1-${_sqr_stepMax}]_info
- step_[1-${_sqr_stepMax}]_alias
- step_[1-${_sqr_stepMax}]
sequencer.sh global variables:
\$SEQUENCER_ARGS
String of all given options
\$SEQ_CONFIG_HOME
Path to user specific seq configuration directory
\$SEQ_CONFIG_FILE
Path to user specific seq configuration file
Will be empty if unused
\$SEQ_PROFILE_NAME
Profile string selected with -p argument
sequencer.sh build-in functions:
USAGE_API
echo -e "${col_green} root${col_off}"
cat <<USAGE_API
USAGE_API
echo -e "${col_green} running${col_off}"
cat <<USAGE_API
USAGE_API
echo -e "${col_green} exists [OPTIONS] [ELEMENT]${col_off}"
cat <<USAGE_API
[ELEMENT]
: either a variable- or a funtion name (-f)
[OPTIONS]
-f : a function
-- : end of options
USAGE_API
echo -e "${col_green} quiet${col_off}"
cat <<USAGE_API
USAGE_API
echo -e "${col_green} silent${col_off}"
cat <<USAGE_API
USAGE_API
echo -e "${col_green} dry${col_off}"
cat <<USAGE_API
USAGE_API
echo -e "${col_green} verbose${col_off}"
cat <<USAGE_API
USAGE_API
echo -e "${col_green} contextHelp${col_off}"
cat <<USAGE_API
USAGE_API
echo -e "${col_green} contextExe${col_off}"
cat <<USAGE_API
USAGE_API
echo -e "${col_green} confirm [OPTIONS] [QUESTION]${col_off}"
cat <<USAGE_API
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
USAGE_API
echo -e "${col_green} ask [OPTION] [QUESTION] [DEFAULT]${col_off}"
cat <<USAGE_API
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
USAGE_API
echo -e "${col_green} exe [COMMANDLINE]${col_off}"
cat <<USAGE_API
Execute command line without pipes or redirects (>,<,|).
Supporting: dry-run (-d): only print command without execution
verbose (-v): print command before execution
USAGE_API
echo -e "${col_green} exep \"[COMMAND STRING(s)]\"${col_off}"
cat <<USAGE_API
See exe, but support for pipes or redirects.
e.g.: exep echo hello world \\> \\'out put.log\\'
exep echo hello world \\> out\\\\ put.log
exep "echo hello world > 'out put.log'"
exep "echo hello world > out\\ put.log"
Important:
- Shell commands cd, read, ... won't work because [COMMAND STRING(s)] is started in a new shell.
- All apostrophes need to be esacped since the command line is given as string.
USAGE_API
echo -e "${col_green} escpath <PATH>${col_off}"
cat <<USAGE_API
Escaping non-printable characters with the proposed POSIX $'' syntax
e.g. \$(escpath /my own/ho me/path) = $(escpath /my own/ho me/path)
USAGE_API
echo -e "${col_green} initSeqConfig [OPTION] <NAME> [TEMPLATE]${col_off}"
cat <<USAGE_API
Create a configuration file in ${_sqr_configRoot}/ and source it if already existent.
[OPTION]
-p : Use profiles
-t : Source config also if created from template
-e : Create empty configuration if no template is found
Returns
0 : sourced configuration or
(-t) : created and sourced configuration from template
1 : created configuration from template but not sourced
2 : created empty configuration
3 : No configuration created
USAGE_API
echo -e "${col_green} addConf <OPTIONS> [SOURCE TYPE] <SOURCE> <DESTINATION FILE>${col_off}"
cat <<USAGE_API
Trying to write or append text or a file (<SOURCE>) to a destination file.
If the CONFIGFILE exists, a backup (name_%Y%m%d-%H%M%S.bck) is saved at the same location.
If -s fails or -m, "$(realpath "${sqr_missingConf}")" is created with the conflicts
to be resolved by the user.
<OPTIONS>
-c : create a new file
-a : append to existing file
-s : skip if CONFIGFILE exists (no backup and entry in missing conf)
-m : only add content to missing conf and warn user
[SOURCE TYPE]
-f : <SOURCE> is a file
<SOURCE>
Text or file (-f) to create or added to <DESTINATION FILE>
<DESTINATION FILE>
Target file to be created or modified.
USAGE_API
echo -e "${col_green} step <STEP NUMBER OR ALIAS>${col_off}"
cat <<USAGE_API
Executes a single step also by alias. Useful if step numbers get reorganized.
dry-run is not applied in this function! The executed step is responsible.
USAGE_API
echo -e "${col_green} outColor [FOREGROUND COLOR] [BACKGROUND COLOR]${col_off}"
cat <<USAGE_API
Set output color permanently until reset.
No argument or unknown foreground color restores shell default (reset).
Color reset happens after every step and step_info function call.
[COLOR]: black, red, green, yellow, blue, magenta, cyan, white
USAGE_API
echo -e "${col_green} echoerr [...]${col_off}"
cat <<USAGE_API
echo to stderr
[...] : all parameter are forwarded to echo
USAGE_API
echo -e "${col_green} echoseq [...]${col_off}"
cat <<USAGE_API
echo to stdout if sequencer output is not suppressed
[...] : all parameter are forwarded to echo
USAGE_API
echo -e "${col_green} echoinfo [...]${col_off}"
cat <<USAGE_API
echo additional correctly indented line to step info
[...] : all parameter are forwared to echo
USAGE_API
echo -e "${col_green} echoinfoArgs [...]${col_off}"
cat <<USAGE_API
echo argument description after step number or alias.
This must be called first in the step info function.
Does not add a newline at the end.
[...] : no parameter are forwared to echo
USAGE_API
echo -e "${col_green} endCheckEmpty <VARIABLENAME> [DESCRIPTION]${col_off}"
cat <<USAGE_API
exit 666 if variable is empty
<VARIABLENAME> : Name without \$
[DESCRIPTION] : Additional text for error output
USAGE_API
echo -e "${col_green} saveReturn [ERRORCODE]${col_off}"
cat <<USAGE_API
Save ERRORCODE if it is != 0 for later use with endReturn
USAGE_API
echo -e "${col_green} getReturn${col_off}"
cat <<USAGE_API
Return last saved error code
USAGE_API
echo -e "${col_green} endReturn [OPTIONS] [MESSAGE]${col_off}"
cat <<USAGE_API
Notifys user that there was an error (previously saved by saveReturn,
or -o [ERRORCODE]) and asks to continue or end the sequence.
Always exits with evaluated error code.
[OPTIONS]
-f : force exit without user input, if error code is not 0
-o ERRORCODE : override stored error code and check ERRORCODE
[MESSAGE]
String which is displayed in the error output
USAGE_API
echo -e "${col_green} exitIfRunning${col_off}"
cat <<USAGE_API
End sequence if an instance of it is still running
USAGE_API
}
## Logging
{
LOG_LEVEL="${LOG_LEVEL:-3}" # 4 = debug -> 0 = fatal (stop)
readonly log_fatal=0
readonly log_error=1
readonly log_warning=2
readonly log_info=3
readonly log_debug=4
LOG_LEVEL="${LOG_LEVEL:-"${log_info}"}" # 4 = debug -> 0 = fatal (stop)
LOG_TIME="${LOG_TIME:-}" # 1 = show time stamps
# sqr::log [LOG LEVEL] [LOG_COLOR] [OPTIONS] [LOG MESSAGE]
@@ -190,16 +424,16 @@ USAGE_EOF
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; }
fatal () { sqr::log "stop" "${col_red}" "${@}"; exit 1; }
error () { [[ "${LOG_LEVEL:-0}" -ge ${log_error} ]] && sqr::log "e" "${col_red}" "${@}"; true; }
warning () { [[ "${LOG_LEVEL:-0}" -ge ${log_warning} ]] && sqr::log "w" "${col_orange}" "${@}"; true; }
info () { [[ "${LOG_LEVEL:-0}" -ge ${log_info} ]] && sqr::log "i" "" "${@}"; true; }
debug () { [[ "${LOG_LEVEL:-0}" -ge ${log_debug} ]] && 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::printf () { [[ "${LOG_LEVEL:-0}" -ge ${log_error} ]] && printf "$@"; true; }
sqr::echo () { [[ "${LOG_LEVEL:-0}" -ge ${log_error} ]] && echo "$@"; true; }
sqr::debugPause() {
if (( _sqr_debug )) ; then set +o xtrace; else true; fi
@@ -283,6 +517,8 @@ USAGE_EOF
## Traps
{
sqr::trap_exit () {
# Only print if not silent
[[ "${LOG_LEVEL:-0}" -ge ${log_info} ]] && printf '\n%s\n' "$seq_name finished"
exists -f seq_trapExit && seq_trapExit
debug "Sequencer exit"
}
@@ -326,26 +562,21 @@ exists() {
if [[ -n "${func}" ]] ; then
declare -F "${func}" &>>/dev/null
else
[[ -n "${!1:-}" ]]
[[ "${1:-}" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] && [[ -n "${!1:-}" ]]
fi
}
# editor [FILE(s)..]
# Starts the detected system text editor
editor() {
"${_sqr_editor}" "$@"
}
# interactive
# Started with -q to use defaults for confirmations
# Started without -q to have user interactions
interactive() {
(( _sqr_interactive ))
}
# quiet
# Log level smaller 3 (info) are treated as quiet request
# Started with -q to use defaults for confirmations
quiet() {
[[ $LOG_LEVEL -lt 3 ]]
(( ! _sqr_interactive ))
}
# silent
# Log level equals 0 (stop)
# Log level equals 0 (fatal)
silent() {
[[ $LOG_LEVEL -eq 0 ]]
}
@@ -366,6 +597,12 @@ contextExe() {
(( _sqr_contextExe ))
}
# editor [FILE(s)..]
# Starts the detected system text editor
editor() {
"${_sqr_editor}" "$@"
}
### interactive
# confirm [OPTIONS] [--] [QUESTION]
# Default (empty character) = no
@@ -458,10 +695,12 @@ ask() {
[[ -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() {
@@ -549,20 +788,129 @@ endReturn() {
# endIfEmpty <VariableName> [DESCRIPTION]
# DESCRIPTION : Optional text for error
endIfEmpty() {
eval 'local ref=$'"${1:-}"
local ref=
exists "${1:-}" && ref="${!1:-}"
if [ -z "${ref:-}" ] ; then
if [ -z "${ref}" ] ; then
if [ -n "${2:-}" ] ; then
error -- "$2"
error -a "Sequence stopped."
else
error -- "\${$1} must not be empty."
error -- "\${${1:-"-"}} must not be empty."
error -a "Sequence stopped."
fi
exit 6
fi
}
# addConf <CONF_MODE> [FILE_MODE] <SOURCE> <DESTINATION_FILE>
# trying to write a file
# if exists, one attempt is made to create bck file of it
# if all fails, a log file is created with the conflicts to be resolved by the user
addConf() {
local addConfBackup=
local arg
local confMode=""
local transferCmd="echo"
for arg in "$@" ; do
case "${1:-}" in
-c) # create a new file
confMode="-c"
shift ;;
-a) # append to existing file
confMode="-a"
shift ;;
-s) # skip if CONFIGFILE exists
confMode="-s"
shift ;;
-m) # only add content to missing conf and warn user
confMode="-m"
shift ;;
-f) # choose if source is a file or text
transferCmd="cat"
shift ;;
*) # default
if [ "$confMode" == "" ] ; then
error "Parameter 1 (-a|-c|-m|-s) missing for addConf()"
exit 0
fi ;;
esac
done
local source="${1:?}"
local dest="${2:?}"
if [ "${transferCmd}" == "cat" ] && [ ! -f "${source}" ] ; then
error "Source: \"${source}\" does not exist"
return 1
fi
if dry ; then
info "Writing ${dest} ...dry-run"
return 0
fi
if [ -z "${dest}" ] ; then
error "Destination empty"
return 1
fi
sqr::echo -n " [i] Writing ${dest} ..."
if [[ ${confMode} != "-m" ]] ; then
# try writing config directly if it doesn't exist
if [ ! -f "$dest" ] ; then
"${transferCmd}" "${source}" > "${dest}"
sqr::echo "ok"
return 0
fi
if [[ ${confMode} == "-s" ]] ; then
# if skip is selected, don't try to backup but add confilict entry
sqr::echo "skipping (exists)"
else
# try backup existing config
addConfBackup="${dest}_$(date +%Y%m%d-%H%M%S).bck"
if [ ! -f "${addConfBackup}" ] ; then
cp -ar "${dest}" "${addConfBackup}"
if [[ ${confMode} == "-c" ]] ; then
"${transferCmd}" "${source}" > "${dest}"
else
"${transferCmd}" "${source}" >> "${dest}"
fi
sqr::echo -e "ok \n [i] Existing config saved to ${addConfBackup}"
return 0
else
sqr::echo "nok"
warnign -e "backup exists"
fi
fi
else
sqr::echo -e "ok \n [i] no change requested"
fi
# add configuration to missingConf file
if [[ "${missingDate:-}" = "" ]] ; then
missingDate="set"
echo -n "### " >> "${sqr_missingConf}"
date >> "${sqr_missingConf}"
fi
local helpText="needs to be added manually"
if [[ "$confMode" == "-s" ]] ; then
helpText="not overwritten"
fi
{
printf '#--- "%s" %s (Option: %s) ---' "${dest}" "${helpText}" "${confMode}"
"${transferCmd}" "${source}"
echo
} >> "${sqr_missingConf}"
warning -e "Check $(realpath "${sqr_missingConf}") for configuration conflicts (${dest})"
return 1
}
# checkStep <Step Number or Alias>
# return 0 - for invalid step
# return Step Number
@@ -571,20 +919,27 @@ endIfEmpty() {
checkStep() {
local checkStep_rex='^[0-9]+$'
local checkStep_ref=""
local testRef=
# 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 exists "_sqr_alias_${1:-}" ; then
testRef="_sqr_alias_${1:-}"
checkStep_ref="${!testRef}"
else
checkStep_ref=0
fi
# Catch special character after evaluation
if ! [[ "${checkStep_ref}" =~ ${checkStep_rex} ]] ; then
checkStep_ref=0
fi
else
checkStep_ref="$1"
checkStep_ref="${1:-}"
fi
if (( checkStep_ref < 1 || checkStep_ref > _sqr_stepMax )) ; then
error "Invalid step: ${1:-}"
error -e "Invalid step: ${1:-}"
printf '0'
return 1
else
@@ -593,7 +948,7 @@ checkStep() {
return 0
else
# step doesn't exist
error "Invalid step: ${1:-}"
error -e "Invalid step: ${1:-}"
printf '0'
return 1
fi
@@ -625,11 +980,18 @@ parseAlias() {
exists -f "step_${i}_alias" || continue
# Function returns step alias
eval '_sqr_alias_'"$("step_${i}_alias")"'='"$i"
declare -g "_sqr_alias_$("step_${i}_alias")=$i"
done
sqr::debugContinue
}
# Creating a minimal seq (step definition) template
createTemplate() {
[ -f "${seq_template}" ] && return 1
exe cp "${sqr_origin}/${seq_template}" "${seq_template}"
}
# displayHelp [NO TEMPLATE] [STEP NUMBER OR ALIAS]
# [NO TEMPLATE]
# 0 (default) : Ask for template creation
@@ -683,12 +1045,11 @@ displayHelp() {
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."
if confirm " Create a template now?" ; then
if createTemplate ; then
printf '\n %s\n' "${seq_template} created."
else
printf '\n %s\n' "$TEMPLATE_NAME exists...Nothing to do!"
printf '\n %s\n' "${seq_template} exists...Nothing to do!"
fi
else
printf '\n Nothing to do!\n'
@@ -793,8 +1154,8 @@ listProfiles() {
# showVersion
showVersion() {
printf 'Sequencer %s\n' "${_sqr_versionString}"
printf 'Seq Revision %s\n' "${VERSION_SEQREV:-"-"}"
printf 'Sequencer: %s\n' "${sqr_versionString}"
printf 'Seq needs: %s\n' "${sqr_minVersion:-"-"}"
}
# initSeqConfig [OPTION] <NAME> [TEMPLATE]
@@ -929,6 +1290,125 @@ initSeqConfig() {
return $retVal
}
# execute [-q] <Step Number>
# -q: don't stop and don't report step functions which cannot be found
# execute given step_<Step Number> function
execute() {
local answer=
local notFound=0
local noReport=0
local stepAlias=
if [[ "${1:-}" == "-q" ]] ; then
noReport=1
shift
fi
# check if step function exists
#declare -F "step_${1:?}" &>>/dev/null || notFound=1
exists -f "step_${1:?}" || notFound=1
if [ ${notFound} -eq 1 ] && [ ${noReport} -ne 1 ] ; then
error "Step ${1:-"-"} not found"
exit 1
fi
# don't execute step functions which are not available
if (( notFound )) ; then
return 1
fi
if ! quiet ; then
exists -f "step_${1}_alias" && stepAlias=$("step_${1}_alias")
printf "\n [%3d] " "${1}"
if [ -n "${stepAlias}" ]; then
echo -en "${col_orange}${stepAlias}${col_off}${_sqr_savePosAlias}"
# Only add newline if step info() available
exists -f "step_${1}_info" && printf "\n%s" "${_sqr_indentExe}"
else
echo -en "${_sqr_savePosExe}"
fi
if exists -f "step_${1}_info" ; then
_sqr_contextExe=1
"step_${1}_info" "$1" "${seq_args[@]}"
_sqr_contextExe=0
color none
else
# Add newline if no info is given
echo
fi
fi
if interactive ; then
answer="$(ask "Start: (y)es/[n]o/(s)kip?" "n")"
case "${answer}" in
[yY])
"step_$1" "$1" "${seq_args[@]}"
_seq_stepReturn="$?" ;;
[sS]) # skip step
_seq_stepReturn=0
return 0 ;;
*)
stepAlias="${1}"
# Display alias if exists
exists -f "step_${1}_alias" && stepAlias="$("step_${1}_alias")"
sqr::echo " [i] Stopping sequence at step: $stepAlias"
exit 1 ;;
esac
else
"step_$1" "$1" "${seq_args[@]}"
_seq_stepReturn="$?"
fi
color none
}
# continous <Starting Step Number>
# (max $_sqr_stepMax)
# execute sequence continously from given starting step
continous() {
local continous_all=0
local continous_i
local continous_step=0
if [ "${1:-}" == "-a" ]; then
continous_all=1
shift
fi
continous_step="$(checkStep "$1")" || return 1
info "Starting sequence ${seq_name} ..."
for ((continous_i=continous_step; continous_i<=_sqr_stepMax; continous_i++)); do
if ! execute -q "${continous_i}" ; then
[ ${continous_all} -eq 0 ] && break
fi
[ ${_seq_stepReturn} -ne 0 ] && break
done
return ${_seq_stepReturn}
}
# selection <STEP ARRAY>
# execute given step list
# e.g.: selection -q (1, 4, 12)
selection() {
local selection_i
local selection_step=0
local selection_array=("$@")
[ ${#selection_array[@]} -eq 0 ] && return 1
info "Starting sequence ${seq_name} ..."
for selection_i in "${selection_array[@]}" ; do
selection_step="$(checkStep "${selection_i}")" || return 1
execute "${selection_step}"
done
return ${_seq_stepReturn}
}
# exe <COMMAND>
# Handle dry run and verbose output for commands without pipe and/or redirects
exe() {
@@ -956,6 +1436,26 @@ exep() {
fi
}
# Check if sequence is compatible
sqr::compatible() {
if [ -z "${sqr_minVersion:-}" ] ; then
warning "No sequence revision found. Trying anyway..."
else
if [ -n "${sqr_minVersion}" ] && [[ ${sqr_minVersion} -gt ${sqr_version} ]] ; then
error "Unsupported sequence revision"
showVersion
return 1
fi
# exclude older versions if needed
if [ -n "${sqr_minVersion}" ] && [[ ${sqr_minVersion} -lt 3 ]] ; then
error "Unsupported sequence revision (addConf)"
showVersion
return 1
fi
fi
return 0
}
# Used as editor if no system editor could be found
sqr::noEditor() {
error "No editor found (\$EDITOR,\"/etc/alternatives\",nano,vi)"
@@ -965,15 +1465,25 @@ sqr::noEditor() {
sqr::main() {
local emptyCall=1
local quickStartOne=0
local toStart=( "0" )
local startAll=
# options check
for arg in "$@" ; do
case "${1:-}" in
++) # end parameter and quickstart step 1 with -qq
quickStartOne=1
_sqr_interactive=0
LOG_LEVEL=0
shift && break ;;
--) # end parameter
shift && break;;
shift && break ;;
--all|-a) # execute all steps; regardless continouity
startAll="-a"
shift ;;
--config|-c) # open sequence configuration file
_sqr_configEdit=1
shift;;
shift ;;
--debug)
_sqr_debug="1"
shift ;;
@@ -983,9 +1493,13 @@ sqr::main() {
--help|-h) # show only help
displayHelp 1 "${2:-}"
exit 0 ;;
--helpapi|-ha) #show build-in functions
helpApi
exit 0;;
--liststeps|-ls)
shift
listSteps "${1:-}"
LOG_LEVEL=0 # suppress finish message
exit 0 ;;
--profile|-p) # seq profile name
sqr_args+=" $1 ${2:-}"
@@ -1011,6 +1525,10 @@ sqr::main() {
_sqr_interactive=0
LOG_LEVEL=0
shift ;;
--single|-s) # execute only one step and stop
sqr_args+=" $1"
_sqr_single=1
shift ;;
--verbose|-v)
sqr_args+=" $1"
_sqr_verbose=1
@@ -1028,7 +1546,7 @@ sqr::main() {
# Enable error backtracing
trap 'sqr::error_report "${FUNCNAME:-.}" ${LINENO}' ERR
fi
# Don't show help if only configuration should be edited
[ ${_sqr_configEdit} -ne 0 ] && [ -z "${1:-}" ] && LOG_LEVEL=1
@@ -1038,18 +1556,32 @@ sqr::main() {
displayHelp
fi
# Assume starting at one for interactive mode
START=1
toStart=( "1" )
elif [ $quickStartOne -ne 0 ] ; then
emptyCall=0
START=1
toStart=( "1" )
seq_args=( "$@" )
else
emptyCall=0
read -r -a START <<< "$1"
read -r -a toStart <<< "$1"
shift
seq_args=( "$@" )
fi
# compatibility check of sequence
sqr::compatible || exit 1
# dry run warning
if dry && ! quiet ; then
color yellow
echo
echo " [w] Dry run active."
echo " - Printed commands may not be accurate (e.g. quotation incorrect)"
echo " - Sequence may ignore dry run"
color none
confirm -f -n -y "Press enter to continue or Ctrl + C to abort"
fi
# Determine system default editor
# Change with update-alternatives --config editor
_sqr_editor="$(realpath -eq "/etc/alternatives/editor")"
@@ -1080,7 +1612,7 @@ sqr::main() {
[ ${emptyCall} -ne 0 ] && exit 0
fi
if checkStep "${START[0]}" >/dev/null ; then
if checkStep "${toStart[0]}" >/dev/null ; then
if ! seq_config "${seq_args[@]}" ; then
error "Configuring sequence failed"
exit 1
@@ -1095,14 +1627,21 @@ sqr::main() {
# Check for profile support
if [ -n "${_seq_profileList}" ]; then
listProfiles "${_seq_profileList}"; exit $?
LOG_LEVEL=1 # suppress finish message
listProfiles "${_seq_profileList}"
exit $?
elif [ -n "${seq_profileName}" ]; then
listProfiles -q || exit 1
fi
sqr::printf 'Running...\n'
step 1 "$@"
# check if more than one step is given and select execution mode
if [ ${_sqr_single} -ne 0 ] ; then
selection "${toStart[0]}"
elif [ "${#toStart[@]}" -gt "1" ]; then
selection "${toStart[@]}"
else
continous ${startAll} "${toStart[0]}"
fi
}
sqr::main "$@"