945 lines
25 KiB
Bash
Executable File
945 lines
25 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
## Sequencer script is doing nothing on its own. It is included by a squence script
|
|
## which uses the sequencer.sh to provide sequencial operations with or without
|
|
## user interaction (see generated template which can be generated by calling this
|
|
## script directly)
|
|
|
|
## Version information
|
|
|
|
VERSION_REV=11
|
|
VERSION_MAJOR=0
|
|
VERSION_MINOR=2
|
|
|
|
## Start of generic script part
|
|
|
|
QUIET=0
|
|
DRY=0
|
|
VERBOSE=0
|
|
SINGLE=0
|
|
ERNO=0
|
|
STEP_ARGS=
|
|
STEP_RETURN=255
|
|
MAX_STEP=512
|
|
ALIAS=
|
|
SEQ_CONFIG_NAME=".seqs"
|
|
SEQ_CONFIG_HOME="$HOME/$SEQ_CONFIG_NAME"
|
|
SEQ_CONFIG_FILE=
|
|
TEMPLATE_NAME=seqTemplateExample.sh
|
|
MISSING_CONF=missingConf.log
|
|
VERSION_STRING="${VERSION_REV}.${VERSION_MAJOR}.${VERSION_MINOR}"
|
|
|
|
helpSequencer() {
|
|
echo "Usage: ${0##*/} [OPTIONS] [STEP NUMBER(s) or ALIAS] [STEP ARGUMENTS]"
|
|
echo
|
|
echo " [OPTIONS]"
|
|
echo " --dry-run, -d : Only print to console what would be done"
|
|
echo " ! Attention - Sequence must support this"
|
|
echo " --help, -h : Display help"
|
|
echo " --helpapi, -ha : Display help about build-in supporting functions"
|
|
echo " (e.g. exe,addconf,echerr,...)"
|
|
echo " --quiet, -q : Don't ask for permission to execute steps"
|
|
echo " If called without starting step number, only this help is shown"
|
|
echo " -qq : Same as --quiet but suppresses regular sequencer.sh output"
|
|
echo " --single, -s : Execute only one step"
|
|
echo " If more than one step is requested, only the first will be executed"
|
|
echo " --verbose, -v : Verbose output (use exe() function to call shell commands in seqs)"
|
|
echo " ( e.g.: exe apt update )"
|
|
echo " --version : Display version of sequencer and revision of sequence"
|
|
echo
|
|
echo " [STEP NUMBER\"(s)\" 1-${MAX_STEP} or ALIAS]"
|
|
echo " No STEP or ALIAS : assume 1 as starting point"
|
|
echo " Single STEP or ALIAS : starting point of sequential process"
|
|
echo " Multiple STEPS or ALIAS : execute only given steps"
|
|
echo " (e.g. $0 \"2 4 12\")"
|
|
echo " multiple steps need to be given as string"
|
|
echo " [STEP ARGUMENTS]"
|
|
echo " * : Arguments will be passed to selected steps and step infos as:"
|
|
echo " \$2 ..."
|
|
echo " \$1 is always the step number"
|
|
}
|
|
|
|
helpApi() {
|
|
echo "sequencer.sh API"
|
|
echo
|
|
echo "The sequencer.sh build-in functions are available in all sequence functions:"
|
|
echo "- step_config"
|
|
echo " If optional step_config is defined in the sequence, it will be called once before any step."
|
|
echo "- step_[1-${MAX_STEP}]_info"
|
|
echo "- step_[1-${MAX_STEP}]_alias"
|
|
echo "- step_[1-${MAX_STEP}]"
|
|
echo
|
|
echo "sequencer.sh global variables:"
|
|
echo
|
|
echo " \$QUIET"
|
|
echo " 0 : default"
|
|
echo " 1 (-q) : No user interaction (e.g. question to start a step)"
|
|
echo " 2 (-qq) : 1 and no regular output of sequencer.sh"
|
|
echo " \$DRY"
|
|
echo " 0 : default"
|
|
echo " 1 (-d) : Commands shall only be printed but not executed"
|
|
echo " \$SEQ_CONFIG_HOME"
|
|
echo " Path to user specific seq configuration directory"
|
|
echo " \$SEQ_CONFIG_FILE"
|
|
echo " Path to user specific seq configuration file"
|
|
echo " Will be empty if unused"
|
|
echo
|
|
echo "sequencer.sh build-in functions:"
|
|
echo
|
|
echo " exe [COMMANDLINE]"
|
|
echo " Execute command line without pipes or redirects (>,<,|)."
|
|
echo " Supporting: dry-run (-d): only print command without execution"
|
|
echo " verbose (-v): print command before execution"
|
|
echo
|
|
echo " exep \"[COMMANDLINE]\""
|
|
echo " See exe, but support for pipes or redirects."
|
|
echo " Important:"
|
|
echo " - Shell commands cd, read, ... won't work because COMMANDLINE is started in a new shell."
|
|
echo " - All apostrophes need to be esacped since the command line is given as string."
|
|
echo
|
|
echo " initSeqConfig [OPTION] <NAME> [TEMPLATE]"
|
|
echo " Create a configuration file in $SEQ_CONFIG_HOME/ and source it if already existent."
|
|
echo " [OPTION]"
|
|
echo " -t : Source config also if created from template"
|
|
echo " -e : Create empty configuration if no template is found"
|
|
echo " Returns"
|
|
echo " 0 : sourced configuration or"
|
|
echo " (-t) : created and sourced configuration from template"
|
|
echo " 1 : created configuration from template but not sourced"
|
|
echo " 2 : created empty configuration"
|
|
echo " 3 : No configuration created"
|
|
echo
|
|
echo " addConf <OPTIONS> [SOURCE TYPE] <SOURCE> <DESTINATION FILE>"
|
|
echo " Trying to write or append text or a file (<SOURCE>) to a destination file."
|
|
echo " If the CONFIGFILE exists, a backup (name_%Y%m%d-%H%M%S.bck) is saved at the same location."
|
|
echo " If -s fails or -m, \"$(realpath "$MISSING_CONF")\" is created with the conflicts"
|
|
echo " to be resolved by the user."
|
|
echo " <OPTIONS>"
|
|
echo " -c : create a new file"
|
|
echo " -a : append to existing file"
|
|
echo " -s : skip if CONFIGFILE exists (no backup and entry in missing conf)"
|
|
echo " -m : only add content to missing conf and warn user"
|
|
echo " [SOURCE TYPE]"
|
|
echo " -f : <SOURCE> is a file"
|
|
echo " <SOURCE>"
|
|
echo " Text or file (-f) to create or added to <DESTINATION FILE>"
|
|
echo " <DESTINATION FILE>"
|
|
echo " Target file to be created or modified."
|
|
echo
|
|
echo " step <STEP NUMBER OR ALIAS>"
|
|
echo " Executes a single step also by alias. Useful if step numbers get reorganized."
|
|
echo " dry-run is not applied in this function! The executed step is responsible."
|
|
echo
|
|
echo " echoerr [...]"
|
|
echo " echo to stderr"
|
|
echo " [...] : all parameter are forwarded to echo"
|
|
echo
|
|
echo " echoinfo [...]"
|
|
echo " echo additional correctly indented line to step info"
|
|
echo " [...] : all parrameter are forwared to echo"
|
|
echo
|
|
echo " endCheckEmpty <VARIABLENAME> [DESCRIPTION]"
|
|
echo " exit 666 if variable is empty"
|
|
echo " <VARIABLENAME> : Name used within eval"
|
|
echo " [DESCRIPTION] : Additional text for error output"
|
|
echo
|
|
echo " saveReturn [ERRORCODE]"
|
|
echo " Save ERRORCODE if it is != 0 for later use with endReturn"
|
|
echo
|
|
echo " getReturn"
|
|
echo " Return last saved error code"
|
|
echo
|
|
echo " endReturn [OPTIONS] [MESSAGE]"
|
|
echo " Notifys user that there was an error (previously saved by saveReturn,"
|
|
echo " or -o [ERRORCODE]) and asks to continue or end the sequence."
|
|
echo " Always exits with evaluated error code."
|
|
echo " [OPTIONS]"
|
|
echo " -f : force exit without user input, if error code is not 0"
|
|
echo " -o ERRORCODE : override stored error code and check ERRORCODE"
|
|
echo " [MESSAGE]"
|
|
echo " String which is displayed in the error output"
|
|
echo
|
|
}
|
|
|
|
# Echo to stderr
|
|
echoerr() { >&2 echo "$@"; }
|
|
|
|
# Echo additional line to info correctly indented
|
|
CONTEXT_HELP=0
|
|
INDENT_HELP=' : '
|
|
INDENTAPPEND_HELP=' '
|
|
INDENTAPPEND_INFO=' '
|
|
echoinfo() {
|
|
if [ $CONTEXT_HELP -ne 0 ] ; then
|
|
printf '%s' "$INDENTAPPEND_HELP"; echo "$@"
|
|
else
|
|
printf '%s' "$INDENTAPPEND_INFO"; echo "$@"
|
|
fi
|
|
}
|
|
|
|
# endCheckEmpty <VariableName> [DESCRIPTION]
|
|
# DESCRIPTION : Optional text for error
|
|
endCheckEmpty() {
|
|
eval 'local ref=$'$1
|
|
|
|
if [ -z $ref ] ; then
|
|
if [ ! -z "$2" ] ; then
|
|
echoerr -e " [E] $2\n Sequence stopped."
|
|
else
|
|
echoerr -e " [E] $1 must not be empty.\n Sequence stopped."
|
|
fi
|
|
exit 666
|
|
fi
|
|
}
|
|
|
|
existsFunction() {
|
|
local NOTFOUND=0
|
|
declare -F $1 &>>/dev/null || NOTFOUND=1
|
|
return $NOTFOUND
|
|
}
|
|
|
|
# saveReturn <ERRNO>
|
|
# Function returns with <ERRNO> in case step wants additional evaluation
|
|
saveReturn() {
|
|
if [ $1 -ne 0 ] ; then
|
|
ERNO=$1
|
|
fi
|
|
return $ERNO
|
|
}
|
|
|
|
# getReturn
|
|
# Returns latest saved $ERNO
|
|
getReturn() {
|
|
return $ERNO
|
|
}
|
|
|
|
# endReturn [-f] [-o ERRORCODE] [MESSAGE]
|
|
# -f : force exit with $ERNO without user input
|
|
# -o : override and check given error code
|
|
# MESSAGE : Custom error message
|
|
#
|
|
endReturn() {
|
|
local forceExit=0
|
|
local errorCode=$ERNO
|
|
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
|
|
echoerr " [W] Ignoring invalid error code: $1"
|
|
fi
|
|
shift
|
|
;;
|
|
"")
|
|
break
|
|
;;
|
|
*)
|
|
endMessage="$@"
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ ( $errorCode -ne 0 && $QUIET -ne 0 ) || ( $errorCode -ne 0 && $forceExit -ne 0 ) ]] ; then
|
|
echo
|
|
if [ "$endMessage" != "" ]; then
|
|
echoerr -e " [E] $endMessage\n Sequence stopped"
|
|
else
|
|
echoerr -e " [E] Return value $errorCode detected.\n Sequence stopped"
|
|
fi
|
|
exit $errorCode
|
|
fi
|
|
if [ $errorCode -ne 0 ] ; then
|
|
echo
|
|
if [ "$endMessage" != "" ]; then
|
|
echoerr -e " [W] $endMessage"
|
|
else
|
|
echoerr " [W] Return value $errorCode detected."
|
|
fi
|
|
read -p "End sequence: [y]/n? " answer
|
|
case $answer in
|
|
[nN])
|
|
# reset saved error code if user chooses to continue
|
|
ERNO=0
|
|
echo
|
|
echo " [I] Continuing sequence..."
|
|
;;
|
|
*)
|
|
echo
|
|
echoerr " [E] Sequence stopped"
|
|
exit $errorCode;
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
# initSeqConfig [OPTION] <NAME> [TEMPLATE]
|
|
# Create a configuration file in the users' home.
|
|
# Source it if already existent
|
|
# [OPTION]
|
|
# -t : Source config also if created from template
|
|
# -e : Create empty configuration if no template is found
|
|
# Return
|
|
# 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
|
|
initSeqConfig() {
|
|
local sourceAlways=0
|
|
local createEmpty=0
|
|
for arg in "$@" ; do
|
|
case "$1" in
|
|
-t)
|
|
sourceAlways=1
|
|
shift
|
|
;;
|
|
-e)
|
|
createEmpty=1
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
local configLoc="$SEQ_CONFIG_HOME/$1"
|
|
local configTemplate="$2"
|
|
|
|
# Create config subdir in users home
|
|
if [ ! -e "$SEQ_CONFIG_HOME/" ] ; then
|
|
echo -n " [I] Creating $(realpath $SEQ_CONFIG_HOME)..."
|
|
exe mkdir -p "$SEQ_CONFIG_HOME" && echo "Ok" || echo "Nok"
|
|
fi
|
|
|
|
if [ -s "$configLoc" ] ; then
|
|
echo " [I] Using configuration file: $configLoc"
|
|
SEQ_CONFIG_FILE="$configLoc"
|
|
. "$configLoc"
|
|
return 0
|
|
fi
|
|
|
|
# Config does not exist, check for template
|
|
if [ -s "$configTemplate" ] ; then
|
|
|
|
# Check first if there is an existing configuration at the templates position
|
|
local configExists="$(dirname $configTemplate)/$1"
|
|
if [ -s "$configExists" ] ; then
|
|
exe mv "$configExists" "$configLoc"
|
|
endReturn -o $? "Unable to use existing configuration: $configExists"
|
|
|
|
echoerr " [I] Using existing configuration: $configExists"
|
|
echoerr " (Moved to $SEQ_CONFIG_HOME)"
|
|
. "$configLoc"
|
|
return 0
|
|
fi
|
|
|
|
exe cp -ar "$configTemplate" "$configLoc"
|
|
endReturn -o $? "Failed to create configuration"
|
|
|
|
if [ $sourceAlways -eq 0 ] ; then
|
|
echoerr " [W] Seq configuration created from template but not used"
|
|
echoerr " Please modify "$configLoc" first and restart sequence"
|
|
return 1
|
|
else
|
|
echo " [W] Using seq configuration from template $configTemplate"
|
|
echo " (Copied to $SEQ_CONFIG_HOME)"
|
|
SEQ_CONFIG_FILE="$configLoc"
|
|
. "$configLoc"
|
|
return 0
|
|
fi
|
|
else
|
|
echo " [W] Seq configuration template not found"
|
|
fi
|
|
|
|
if [ $createEmpty -ne 0 ] ; then
|
|
# Create empty config file
|
|
echo " [W] Created empty configuration file $configLoc"
|
|
exe touch "$configLoc"
|
|
return 2
|
|
fi
|
|
|
|
echoerr " [E] No seq configuration created"
|
|
return 3
|
|
}
|
|
|
|
# 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 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
|
|
echoerr " [E] 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
|
|
echoerr " [E] Source: \"$source\" does not exist"
|
|
return 1;
|
|
fi
|
|
if [ "$dest" == "" ] ; then
|
|
echoerr " [E] Destination empty"
|
|
return 1;
|
|
fi
|
|
|
|
if [ "$DRY" -ne 0 ] ; then
|
|
echo " [I] Writing $dest ...dry-run"
|
|
return 0;
|
|
fi
|
|
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"
|
|
echo "ok"
|
|
return 0
|
|
fi
|
|
|
|
if [ $confMode == "-s" ] ; then
|
|
# if skip is selected, don't try to backup but add confilict entry
|
|
echo "skipping (exists)"
|
|
else
|
|
# try backup existing config
|
|
local 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
|
|
echo -e "ok \n [I] Existing config saved to ${addConfBackup}"
|
|
return 0
|
|
else
|
|
echo "nok"
|
|
echoerr " [W] backup exists"
|
|
fi
|
|
fi
|
|
else
|
|
echo -e "ok \n [I] no change requested"
|
|
fi
|
|
|
|
# add configuration to missingConf file
|
|
if [ "$missingDate" = "" ] ; then
|
|
missingDate=set
|
|
echo -n "### " >> "$MISSING_CONF"
|
|
date >> "$MISSING_CONF"
|
|
fi
|
|
|
|
local helpText="needs to be added manually"
|
|
if [ "$confMode" == "-s" ] ; then
|
|
helpText="not overwritten"
|
|
fi
|
|
|
|
echo "#--- \"$dest\" $helpText (Option: $confMode) ---" >> "$MISSING_CONF"
|
|
$transferCmd "$source" >> "$MISSING_CONF"
|
|
echo >> "$MISSING_CONF"
|
|
|
|
echoerr " [W] Check $(realpath "$MISSING_CONF") for configuration conflicts ($dest)"
|
|
return 1
|
|
}
|
|
|
|
# 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 NOTFOUND=0
|
|
local NOREPORT=0
|
|
|
|
if [ $1 == "-q" ] ; then
|
|
NOREPORT=1
|
|
shift
|
|
fi
|
|
|
|
# check if step function exists
|
|
declare -F step_$1 &>>/dev/null || NOTFOUND=1
|
|
if [ $NOTFOUND -eq 1 ] && [ $NOREPORT -ne 1 ] ; then
|
|
echoerr " [E] Step $1 not found"
|
|
exit 1;
|
|
fi
|
|
|
|
# don't execute step functions which are not available
|
|
if [ $NOTFOUND -ne 0 ] ; then
|
|
return $NOTFOUND
|
|
fi
|
|
|
|
if [ $QUIET -ne 2 ] ; then
|
|
echo -en "\n [STEP $1] "
|
|
existsFunction step_${1}_info
|
|
if [ $? -eq 0 ] ; then
|
|
step_${1}_info $1 "${STEP_ARGS[@]}"
|
|
else
|
|
# Add newline if no info is given
|
|
echo
|
|
fi
|
|
fi
|
|
|
|
if [ $QUIET -eq 0 ] ; then
|
|
read -p "Start: (y)es/[n]o/(s)kip? " answer
|
|
case $answer in
|
|
[yY])
|
|
step_$1 $1 "${STEP_ARGS[@]}"
|
|
STEP_RETURN=$?
|
|
;;
|
|
[sS]) # skip step
|
|
STEP_RETURN=0
|
|
return 0
|
|
;;
|
|
*)
|
|
local stepId="$1"
|
|
# Display alias if exists
|
|
existsFunction step_${1}_alias
|
|
if [ $? -eq 0 ] ; then
|
|
step_${i}_alias
|
|
stepId="$ALIAS"
|
|
fi
|
|
echoerr " [I] Stopping sequence at step: $stepId"
|
|
exit 1;
|
|
;;
|
|
esac
|
|
else
|
|
step_$1 $1 "${STEP_ARGS[@]}"
|
|
STEP_RETURN=$?
|
|
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 rex='^[0-9]+$'
|
|
local ref=""
|
|
|
|
# Check if string is a number or alias
|
|
if ! [[ "$1" =~ $rex ]] ; then
|
|
eval 'ref=$alias_'"$1"
|
|
# Catch special character after eval
|
|
if ! [[ "$ref" =~ $rex ]] ; then
|
|
ref=0
|
|
fi
|
|
else
|
|
ref=$1
|
|
fi
|
|
|
|
if (( $ref < 1 || $ref > $MAX_STEP )) ; then
|
|
echoerr " [E] Invalid step: $ref"
|
|
return 0
|
|
else
|
|
existsFunction step_$ref
|
|
if [ $? -eq 0 ] ; then
|
|
return $ref
|
|
else
|
|
# step doesn't exist
|
|
echoerr " [E] Invalid step: $ref"
|
|
return 0
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# step <Step Number of Alias>
|
|
# execute given step
|
|
step() {
|
|
local stepNo=0
|
|
local stepArgs=("$@")
|
|
|
|
checkStep "$1"
|
|
stepNo=$?
|
|
if [ "$stepNo" == "0" ] ; then
|
|
return 1
|
|
else
|
|
step_$stepNo "${stepArgs[@]}"
|
|
fi
|
|
}
|
|
|
|
# continous <Starting Step Number>
|
|
# (max $MAX_STEP)
|
|
# execute sequence continously from given starting step
|
|
continous() {
|
|
local step=0
|
|
|
|
checkStep "$1"
|
|
step=$?
|
|
if [[ $step == 0 ]] ; then
|
|
return 1
|
|
fi
|
|
|
|
if [ $QUIET -ne 2 ]; then echo " [I] Starting sequence $(realpath $0) ..."; fi
|
|
|
|
for ((i=$step; i<=${MAX_STEP}; i++)); do
|
|
execute -q $i
|
|
local res=$?
|
|
if [ $res -ne 0 ] ; then
|
|
break
|
|
fi
|
|
if [ $STEP_RETURN -ne 0 ] ; then
|
|
break
|
|
fi
|
|
done
|
|
return $STEP_RETURN
|
|
}
|
|
|
|
# selection <STEP ARRAY>
|
|
# execute given step list
|
|
# e.g.: selection -q (1, 4, 12)
|
|
selection() {
|
|
local step=0
|
|
local array=("$@")
|
|
|
|
if [ ${#array[@]} -eq 0 ] ; then
|
|
return 1
|
|
fi
|
|
|
|
if [ $QUIET -ne 2 ]; then echo " [I] Starting sequence $(realpath $0) ..."; fi
|
|
|
|
for i in ${array[@]} ; do
|
|
checkStep "$i"
|
|
step=$?
|
|
if [ $step -eq 0 ] ; then
|
|
return 1
|
|
else
|
|
execute $step
|
|
fi
|
|
done
|
|
return $STEP_RETURN
|
|
}
|
|
|
|
# Creating a minimal seq (step definition) template
|
|
createTemplate() {
|
|
if [ -f $TEMPLATE_NAME ] ; then
|
|
return 1
|
|
fi
|
|
echo "#!/bin/bash" > $TEMPLATE_NAME
|
|
echo >> $TEMPLATE_NAME
|
|
echo "toolName=mytool" >> $TEMPLATE_NAME
|
|
echo >> $TEMPLATE_NAME
|
|
echo "# Get script working directory" >> $TEMPLATE_NAME
|
|
echo "# (when called from a different directory)" >> $TEMPLATE_NAME
|
|
echo "WDIR=\"\$( cd \"\$( dirname \"\${BASH_SOURCE[0]}\" )\" >>/dev/null 2>&1 && pwd )\"" >> $TEMPLATE_NAME
|
|
echo "CONFIG=0" >> $TEMPLATE_NAME
|
|
echo "CONFIG_FILE_NAME=\"\${toolName}.cfg\"" >> $TEMPLATE_NAME
|
|
echo "CONFIG_FILE_TEMPLATE=\"\$WDIR/\${CONFIG_FILE_NAME}.example\"" >> $TEMPLATE_NAME
|
|
echo >> $TEMPLATE_NAME
|
|
echo "step_config() {" >> $TEMPLATE_NAME
|
|
echo " echo \"Called once before executing steps.\"" >> $TEMPLATE_NAME
|
|
echo " ## e.g. to source a config file manually:" >> $TEMPLATE_NAME
|
|
echo " #. \"\$CONFIG_FILE\"" >> $TEMPLATE_NAME
|
|
echo " ## or to use sequencer api:" >> $TEMPLATE_NAME
|
|
echo " #initSeqConfig \"\$CONFIG_FILE_NAME\" \"\$CONFIG_FILE_TEMPLATE\"" >> $TEMPLATE_NAME
|
|
echo " #if [ \$? -eq 0 ] ; then" >> $TEMPLATE_NAME
|
|
echo " # CONFIG=1" >> $TEMPLATE_NAME
|
|
echo " #fi" >> $TEMPLATE_NAME
|
|
echo "}" >> $TEMPLATE_NAME
|
|
echo >> $TEMPLATE_NAME
|
|
echo "step_1_info() { echo \"My custom step\"; }" >> $TEMPLATE_NAME
|
|
echo "step_1_alias() { ALIAS=\"begin\"; }" >> $TEMPLATE_NAME
|
|
echo "step_1() {" >> $TEMPLATE_NAME
|
|
echo " echo \"Doing something for step \$1 ...\"" >> $TEMPLATE_NAME
|
|
echo " echo \"Command line arguments starting with argument 2: \$@\"" >> $TEMPLATE_NAME
|
|
echo " # Use exe for regular command" >> $TEMPLATE_NAME
|
|
echo " # Use exep \"command\" for commands containing pipes or redirects" >> $TEMPLATE_NAME
|
|
echo " exe ls" >> $TEMPLATE_NAME
|
|
echo " exep \"dmesg | grep usb\"" >> $TEMPLATE_NAME
|
|
echo "}" >> $TEMPLATE_NAME
|
|
echo >> $TEMPLATE_NAME
|
|
echo "VERSION_SEQREV=${VERSION_REV}" >> $TEMPLATE_NAME
|
|
echo ". $0" >> $TEMPLATE_NAME
|
|
|
|
chmod +x $TEMPLATE_NAME
|
|
return 0
|
|
}
|
|
|
|
# Parse alias functions "step_[STEP NUBER]_alias" to create
|
|
# back reference variable of schema:
|
|
# alias_[ALIAS]=[STEP NUMBER]
|
|
parseAlias() {
|
|
for ((i=1; i<=${MAX_STEP}; i++)); do
|
|
# Check for alias definition
|
|
existsFunction step_${i}_alias
|
|
if [ $? -ne 0 ] ; then
|
|
continue
|
|
fi
|
|
|
|
# Function writes global ALIAS variable
|
|
step_${i}_alias
|
|
|
|
eval 'alias_'$ALIAS'='$i
|
|
done
|
|
}
|
|
|
|
# displayHelp [NO TEMPLATE]
|
|
# [NO TEMPLATE]
|
|
# 0 (default) : Ask for template creation
|
|
# 1 : Do not ask for template creation
|
|
# Always display sequencer help and, if available, sequence help
|
|
displayHelp() {
|
|
local createTemplate=1
|
|
local stepsFound=0
|
|
CONTEXT_HELP=1
|
|
helpSequencer
|
|
|
|
if [ ! -z $1 ] && [ $1 -eq 1 ] ; then
|
|
createTemplate=0
|
|
fi
|
|
|
|
# check if step definition exists by looking for a step_*() function
|
|
for ((i=1; i<=${MAX_STEP}; i++)); do
|
|
existsFunction step_${i}
|
|
if [ $? -ne 0 ] ; then
|
|
continue
|
|
fi
|
|
stepsFound=1
|
|
done
|
|
|
|
if [ $stepsFound -eq 0 ] ; then
|
|
echo -e "\n It seems ${0##*/} was called directly."
|
|
echo -e " Please create a sequence script first.\n"
|
|
if [ $createTemplate -ne 0 ] ; then
|
|
read -p " Create a template now? y/[n]? " answer
|
|
case $answer in
|
|
[yY])
|
|
createTemplate
|
|
if [ $? -eq 0 ] ; then
|
|
echo -e "\n $TEMPLATE_NAME created."
|
|
else
|
|
echo -e "\n $TEMPLATE_NAME exists...Nothing to do!"
|
|
fi
|
|
;;
|
|
*)
|
|
echo -e "\n Nothing to do!"
|
|
;;
|
|
esac
|
|
fi
|
|
exit 1;
|
|
else
|
|
echo -e "\n Step (= alias) documentation:"
|
|
for ((i=1; i<=${MAX_STEP}; i++)); do
|
|
|
|
# Display step reference in help if step function exists
|
|
existsFunction step_${i}
|
|
if [ $? -ne 0 ] ; then
|
|
continue
|
|
fi
|
|
printf ' Step %3s ' $i
|
|
|
|
# Display alias if exists
|
|
existsFunction step_${i}_alias
|
|
if [ $? -eq 0 ] ; then
|
|
step_${i}_alias
|
|
echo " = $ALIAS"
|
|
printf '%s' "$INDENT_HELP"
|
|
else
|
|
echo -n " : "
|
|
fi
|
|
|
|
# Display step help only if info function exists
|
|
existsFunction step_${i}_info
|
|
if [ $? -eq 0 ] ; then
|
|
step_${i}_info $i
|
|
else
|
|
echo " - step_${i}_info() missing"
|
|
fi
|
|
done
|
|
echo
|
|
fi
|
|
CONTEXT_HELP=0
|
|
}
|
|
|
|
# showVersion
|
|
showVersion() {
|
|
echo "Sequencer ${VERSION_STRING}"
|
|
echo -n "Seq Revision "
|
|
if [ ! -z "${VERSION_SEQREV}" ] ; then
|
|
echo "${VERSION_SEQREV}"
|
|
else
|
|
echo "-"
|
|
fi
|
|
}
|
|
|
|
exe() {
|
|
local arr=("$@")
|
|
if [ $DRY -ne 0 ] ; then
|
|
echo -n "--"
|
|
fi
|
|
if [ $DRY -ne 0 ] || [ $VERBOSE -eq 1 ] ; then
|
|
(set -x; : "${arr[@]}")
|
|
fi
|
|
|
|
if [ $DRY -eq 0 ] ; then
|
|
"${arr[@]}"
|
|
fi
|
|
}
|
|
|
|
# Handle dry run and verbose output for commands containing pipe and/or redirects
|
|
# exep <COMMAND TO RUN AS STRING>
|
|
exep() {
|
|
if [ $DRY -ne 0 ] ; then
|
|
echo "--++ : $1"
|
|
elif [ $VERBOSE -eq 1 ] ; then
|
|
echo "++ : $1"
|
|
fi
|
|
|
|
if [ $DRY -eq 0 ] ; then
|
|
bash -c "$1"
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
local START=0
|
|
local EMPTYCALL=1
|
|
|
|
# options check
|
|
for arg in "$@" ; do
|
|
case "$1" in
|
|
--dry-run|-d) # shows what would be done
|
|
DRY=1
|
|
shift
|
|
;;
|
|
--help|-h) # show only help
|
|
displayHelp 1
|
|
exit 0;
|
|
;;
|
|
--helpapi|-ha) #show build-in functions
|
|
helpApi
|
|
exit 0;
|
|
;;
|
|
--quiet|-q|-qq) # detect if option quiet is available
|
|
if [ "$1" == "-qq" ] ; then
|
|
QUIET=2
|
|
else
|
|
QUIET=1
|
|
fi
|
|
shift
|
|
;;
|
|
--single|-s) # execute only one step and stop
|
|
SINGLE=1
|
|
shift
|
|
;;
|
|
--verbose|-v) # set verbose flag
|
|
VERBOSE=1
|
|
shift
|
|
;;
|
|
--version) # version request
|
|
showVersion
|
|
exit 0;
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "$1" ] || [ "$1" == "" ] ; then
|
|
# Empty -> show help
|
|
displayHelp
|
|
# Assume starting at one for interactive mode
|
|
START=1
|
|
else
|
|
EMPTYCALL=0
|
|
read -r -a START <<< "$1"
|
|
shift
|
|
STEP_ARGS=( "$@" )
|
|
fi
|
|
|
|
# compatibility check of sequence
|
|
if [ ! -z $VERSION_SEQREV ] && [ $VERSION_SEQREV -gt $VERSION_REV ] ; then
|
|
echoerr " [E] Unsupported sequence revision"
|
|
showVersion
|
|
exit 1
|
|
fi
|
|
# exclude older versions if needed
|
|
if [ ! -z $VERSION_SEQREV ] && [ $VERSION_SEQREV -lt 3 ] ; then
|
|
echoerr " [E] Unsupported sequence revision (addConf)"
|
|
showVersion
|
|
exit 1
|
|
fi
|
|
if [ -z $VERSION_SEQREV ] ; then
|
|
echoerr -e " [W] No sequence revision found. Trying anyway...\n";
|
|
fi
|
|
|
|
# End here on quiet mode and no step was given
|
|
if [ $EMPTYCALL -ne 0 ] && [ $QUIET -ne 0 ] ; then
|
|
exit 1;
|
|
fi
|
|
|
|
if [ $DRY -ne 0 ] && [ $QUIET -eq 0 ] ; then
|
|
echo
|
|
echo " [W] Dry run active."
|
|
echo " - Printed commands may not be accurate (e.g. quotation incorrect)"
|
|
echo " - Sequence may ignore dry run"
|
|
read -p "Press enter to continue or Ctrl + C to abort"
|
|
fi
|
|
|
|
parseAlias
|
|
|
|
# run configuration for seq only if available and if first step is valid
|
|
existsFunction step_config
|
|
if [ $? -eq 0 ] ; then
|
|
checkStep "${START[0]}"
|
|
if [ $? -ne 0 ] ; then
|
|
echo " [I] Configuring sequence (step_config) ..."
|
|
step_config
|
|
else
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# check if more than one step is given and select execution mode
|
|
if [ $SINGLE -ne 0 ] ; then
|
|
selection "${START[0]}"
|
|
elif [ "${#START[@]}" -gt "1" ]; then
|
|
selection "${START[@]}"
|
|
else
|
|
continous $START
|
|
fi
|
|
}
|
|
|
|
main "$@"
|
|
MAINRETURN=$?
|
|
|
|
if [ $QUIET -ne 2 ] ; then
|
|
echo
|
|
echo "${0##*/} finished"
|
|
fi
|
|
|
|
exit $MAINRETURN;
|