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:
@@ -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
|
||||
|
637
sequencer.sh
637
sequencer.sh
@@ -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,12 +1465,22 @@ 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 ;;
|
||||
--all|-a) # execute all steps; regardless continouity
|
||||
startAll="-a"
|
||||
shift ;;
|
||||
--config|-c) # open sequence configuration file
|
||||
_sqr_configEdit=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
|
||||
@@ -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 "$@"
|
||||
|
Reference in New Issue
Block a user