WIP added help and related functions
Some refactoring and shellcheck; TODO: template
This commit is contained in:
315
sequencer.sh
315
sequencer.sh
@@ -45,10 +45,17 @@ set -o pipefail
|
|||||||
_sqr_dry=0
|
_sqr_dry=0
|
||||||
_sqr_verbose=0
|
_sqr_verbose=0
|
||||||
_sqr_errno=0
|
_sqr_errno=0
|
||||||
|
_sqr_contextHelp=0
|
||||||
|
_sqr_contextExe=0
|
||||||
|
_sqr_editor=
|
||||||
|
|
||||||
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'
|
||||||
|
|
||||||
# Colors
|
## Terminal colors
|
||||||
col_black= ; [ -t 1 ] && col_black='\033[0;30m'
|
col_black= ; [ -t 1 ] && col_black='\033[0;30m'
|
||||||
col_darkgrey= ; [ -t 1 ] && col_darkgrey='\033[1;30m'
|
col_darkgrey= ; [ -t 1 ] && col_darkgrey='\033[1;30m'
|
||||||
col_red= ; [ -t 1 ] && col_red='\033[0;31m'
|
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
|
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
|
## Logging
|
||||||
{
|
{
|
||||||
LOG_LEVEL="${LOG_LEVEL:-3}" # 4 = debug -> 0 = fatal (stop)
|
LOG_LEVEL="${LOG_LEVEL:-3}" # 4 = debug -> 0 = fatal (stop)
|
||||||
@@ -199,6 +246,29 @@ set -o pipefail
|
|||||||
tput setab 7 ;;
|
tput setab 7 ;;
|
||||||
esac
|
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
|
## Traps
|
||||||
@@ -252,6 +322,11 @@ exists() {
|
|||||||
[[ -n "${!1:-}" ]]
|
[[ -n "${!1:-}" ]]
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
# editor [FILE(s)..]
|
||||||
|
# Starts the detected system text editor
|
||||||
|
editor() {
|
||||||
|
"${_sqr_editor}" "$@"
|
||||||
|
}
|
||||||
# interactive
|
# interactive
|
||||||
# Started with -q to use defaults for confirmations
|
# Started with -q to use defaults for confirmations
|
||||||
interactive() {
|
interactive() {
|
||||||
@@ -277,10 +352,17 @@ dry() {
|
|||||||
verbose() {
|
verbose() {
|
||||||
(( _sqr_verbose ))
|
(( _sqr_verbose ))
|
||||||
}
|
}
|
||||||
|
contextHelp() {
|
||||||
|
(( _sqr_contextHelp ))
|
||||||
|
}
|
||||||
|
contextExe() {
|
||||||
|
(( _sqr_contextExe ))
|
||||||
|
}
|
||||||
|
|
||||||
### interactive
|
### interactive
|
||||||
# confirm [OPTIONS] [--] [QUESTION]
|
# confirm [OPTIONS] [--] [QUESTION]
|
||||||
# Default (empty character) = no
|
# Default (empty character) = no
|
||||||
|
# Invalid character trigger the default
|
||||||
#
|
#
|
||||||
# [OPTIONS]
|
# [OPTIONS]
|
||||||
# -f : interactive even if quiet
|
# -f : interactive even if quiet
|
||||||
@@ -290,7 +372,7 @@ verbose() {
|
|||||||
confirm() {
|
confirm() {
|
||||||
sqr::debugPause
|
sqr::debugPause
|
||||||
local arg=
|
local arg=
|
||||||
local rexReply='^[Yy]$' # default no
|
local rexReply='^[Yy]+$' # default no
|
||||||
local inputHelp='[y/N] ' # default no
|
local inputHelp='[y/N] ' # default no
|
||||||
local noHelp=0
|
local noHelp=0
|
||||||
local force=0
|
local force=0
|
||||||
@@ -306,7 +388,7 @@ confirm() {
|
|||||||
noHelp=1
|
noHelp=1
|
||||||
shift ;;
|
shift ;;
|
||||||
-y)
|
-y)
|
||||||
rexReply='^[Yy]*$' # default yes
|
rexReply='^[^Nn]*$' # default yes
|
||||||
inputHelp='[Y/n] ' # default yes
|
inputHelp='[Y/n] ' # default yes
|
||||||
shift ;;
|
shift ;;
|
||||||
esac
|
esac
|
||||||
@@ -389,9 +471,9 @@ getReturn() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# endReturn [-f] [-o ERRORCODE] [MESSAGE]
|
# endReturn [-f] [-o ERRORCODE] [MESSAGE]
|
||||||
# -f : force exit with $_sqr_errno without user input
|
# -f : force exit with $_sqr_errno without user input
|
||||||
# -o : override and check given error code
|
# -o : override and check given [ERRORCODE]
|
||||||
# MESSAGE : Custom error message
|
# [MESSAGE] : Custom error message
|
||||||
#
|
#
|
||||||
endReturn() {
|
endReturn() {
|
||||||
local arg
|
local arg
|
||||||
@@ -445,9 +527,9 @@ endReturn() {
|
|||||||
else
|
else
|
||||||
error -e "Return value ${errorCode} detected."
|
error -e "Return value ${errorCode} detected."
|
||||||
fi
|
fi
|
||||||
if confirm -y "End sequence"; then
|
if confirm -y "End sequence" ; then
|
||||||
error -e "Sequence stopped"
|
error -e "Sequence stopped"
|
||||||
exit "${errorCode}";
|
exit "${errorCode}"
|
||||||
else
|
else
|
||||||
# reset saved error code if user chooses to continue
|
# reset saved error code if user chooses to continue
|
||||||
_sqr_errno=0
|
_sqr_errno=0
|
||||||
@@ -457,6 +539,183 @@ endReturn() {
|
|||||||
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]
|
# listSteps [FILTER STRING]
|
||||||
# [FILTER STRING]
|
# [FILTER STRING]
|
||||||
# show only steps and aliases starting with [FILTER STRING]
|
# show only steps and aliases starting with [FILTER STRING]
|
||||||
@@ -526,6 +785,8 @@ sqr::noEditor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sqr::main() {
|
sqr::main() {
|
||||||
|
local quickStartOne=0
|
||||||
|
|
||||||
# options check
|
# options check
|
||||||
for arg in "$@" ; do
|
for arg in "$@" ; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@@ -535,6 +796,9 @@ sqr::main() {
|
|||||||
--dry-run|-d)
|
--dry-run|-d)
|
||||||
_sqr_dry=1
|
_sqr_dry=1
|
||||||
shift ;;
|
shift ;;
|
||||||
|
--help|-h) # show only help
|
||||||
|
displayHelp 1 "${2:-}"
|
||||||
|
exit 0;;
|
||||||
--liststeps|-ls)
|
--liststeps|-ls)
|
||||||
shift
|
shift
|
||||||
listSteps "${1:-}"
|
listSteps "${1:-}"
|
||||||
@@ -563,19 +827,40 @@ sqr::main() {
|
|||||||
trap 'sqr::error_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
trap 'sqr::error_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||||
fi
|
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
|
# Determine system default editor
|
||||||
# Change with update-alternatives --config editor
|
# Change with update-alternatives --config editor
|
||||||
sqr_editor="$(realpath -eq "/etc/alternatives/editor")"
|
_sqr_editor="$(realpath -eq "/etc/alternatives/editor")"
|
||||||
## Various fallbacks
|
## Various fallbacks
|
||||||
[ -z "${sqr_editor}" ] && sqr_editor="$EDITOR"
|
[ -z "${_sqr_editor}" ] && _sqr_editor="$EDITOR"
|
||||||
[ -z "${sqr_editor}" ] && sqr_editor="$(command -v nano)"
|
[ -z "${_sqr_editor}" ] && _sqr_editor="$(command -v nano)"
|
||||||
[ -z "${sqr_editor}" ] && sqr_editor="$(command -v vi)"
|
[ -z "${_sqr_editor}" ] && _sqr_editor="$(command -v vi)"
|
||||||
## Fall back to error message
|
## Fall back to error message
|
||||||
[ -z "${sqr_editor}" ] && sqr_editor="sqr::noEditor"
|
[ -z "${_sqr_editor}" ] && _sqr_editor="sqr::noEditor"
|
||||||
|
|
||||||
sqr::printf 'Running...\n'
|
sqr::printf 'Running...\n'
|
||||||
seq_config 2>/dev/null || true
|
seq_config 2>/dev/null || true
|
||||||
step_1 "$@"
|
step 1 "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
sqr::main "$@"
|
sqr::main "$@"
|
||||||
|
Reference in New Issue
Block a user