WIP added help and related functions
Some refactoring and shellcheck; TODO: template
This commit is contained in:
317
sequencer.sh
317
sequencer.sh
@@ -45,10 +45,17 @@ set -o pipefail
|
||||
_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'
|
||||
|
||||
sqr_editor=
|
||||
|
||||
# Colors
|
||||
## 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'
|
||||
@@ -68,6 +75,46 @@ set -o pipefail
|
||||
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)
|
||||
@@ -199,6 +246,29 @@ set -o pipefail
|
||||
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
|
||||
@@ -252,6 +322,11 @@ exists() {
|
||||
[[ -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() {
|
||||
@@ -277,10 +352,17 @@ dry() {
|
||||
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
|
||||
@@ -290,7 +372,7 @@ verbose() {
|
||||
confirm() {
|
||||
sqr::debugPause
|
||||
local arg=
|
||||
local rexReply='^[Yy]$' # default no
|
||||
local rexReply='^[Yy]+$' # default no
|
||||
local inputHelp='[y/N] ' # default no
|
||||
local noHelp=0
|
||||
local force=0
|
||||
@@ -306,7 +388,7 @@ confirm() {
|
||||
noHelp=1
|
||||
shift ;;
|
||||
-y)
|
||||
rexReply='^[Yy]*$' # default yes
|
||||
rexReply='^[^Nn]*$' # default yes
|
||||
inputHelp='[Y/n] ' # default yes
|
||||
shift ;;
|
||||
esac
|
||||
@@ -389,9 +471,9 @@ getReturn() {
|
||||
}
|
||||
|
||||
# endReturn [-f] [-o ERRORCODE] [MESSAGE]
|
||||
# -f : force exit with $_sqr_errno without user input
|
||||
# -o : override and check given error code
|
||||
# MESSAGE : Custom error message
|
||||
# -f : force exit with $_sqr_errno without user input
|
||||
# -o : override and check given [ERRORCODE]
|
||||
# [MESSAGE] : Custom error message
|
||||
#
|
||||
endReturn() {
|
||||
local arg
|
||||
@@ -445,9 +527,9 @@ endReturn() {
|
||||
else
|
||||
error -e "Return value ${errorCode} detected."
|
||||
fi
|
||||
if confirm -y "End sequence"; then
|
||||
if confirm -y "End sequence" ; then
|
||||
error -e "Sequence stopped"
|
||||
exit "${errorCode}";
|
||||
exit "${errorCode}"
|
||||
else
|
||||
# reset saved error code if user chooses to continue
|
||||
_sqr_errno=0
|
||||
@@ -457,6 +539,183 @@ endReturn() {
|
||||
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]
|
||||
@@ -526,6 +785,8 @@ sqr::noEditor() {
|
||||
}
|
||||
|
||||
sqr::main() {
|
||||
local quickStartOne=0
|
||||
|
||||
# options check
|
||||
for arg in "$@" ; do
|
||||
case "$1" in
|
||||
@@ -535,6 +796,9 @@ sqr::main() {
|
||||
--dry-run|-d)
|
||||
_sqr_dry=1
|
||||
shift ;;
|
||||
--help|-h) # show only help
|
||||
displayHelp 1 "${2:-}"
|
||||
exit 0;;
|
||||
--liststeps|-ls)
|
||||
shift
|
||||
listSteps "${1:-}"
|
||||
@@ -563,19 +827,40 @@ sqr::main() {
|
||||
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")"
|
||||
_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)"
|
||||
[ -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"
|
||||
[ -z "${_sqr_editor}" ] && _sqr_editor="sqr::noEditor"
|
||||
|
||||
sqr::printf 'Running...\n'
|
||||
seq_config 2>/dev/null || true
|
||||
step_1 "$@"
|
||||
step 1 "$@"
|
||||
}
|
||||
|
||||
sqr::main "$@"
|
||||
|
Reference in New Issue
Block a user