#!/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 seqTemplate.sh) ## Version information VERSION_REV=2 VERSION_MAJOR=0 VERSION_MINOR=0 ## Start of generic script part QUIET=0 ERNO=0 MAX_STEP=255 ALIAS= TEMPLATE_NAME=seqTemplateExample.sh MISSING_CONF=missingConf.h VERSION_STRING="${VERSION_REV}.${VERSION_MAJOR}.${VERSION_MINOR}" helpSequencer() { echo "Usage: ${0##*/} [OPTIONS] [STEP NUMBER(s) or ALIAS]" echo echo " [OPTIONS]" echo " --help, -h : Display help" echo " --quiet, -q : Don't ask for permission to execute steps" echo " If called without starting step number, only this help is shown" echo " --version,-v : Display version of sequencer and revision of sequence" echo echo " [STEP NUMBER(s) 1-${MAX_STEP} or ALIAS]" echo " Single STEP or ALIAS : starting point of process" echo " Multiple STEPS or ALIAS : execute only given steps" echo " execute only one step with using special step 0" echo " ( e.g. only execute step 4: $0 4 0 )" } # endCheckEmpty [VariableName] [DESCRIPTION] # DESCRIPTION : Optional text for error endCheckEmpty() { local errorText=$1 eval 'local ref=$'$1 if [ ! -z "$2" ] ; then errorText=$2 fi if [ -z $ref ] ; then echo -e "[Error] $errorText must not be empty.\nAborting installation." exit 666 fi } existsFunction() { local NOTFOUND=0 declare -F $1 &>>/dev/null || NOTFOUND=1 return $NOTFOUND } saveReturn() { if [ $1 -ne 0 ] ; then ERNO=$1 fi } # endReturn [-f] # -f : force exit with $ERNO without user input endReturn() { if [[ ( $ERNO -ne 0 && $QUIET -ne 0 ) || ( $ERNO -ne 0 && ! -z $1 && $1 == "-f" ) ]] ; then echo echo -e "[Error] Return value $ERNO detected.\nAborting installation." exit $ERNO fi if [ $ERNO -ne 0 ] ; then echo echo "[Error] Return value $ERNO detected." read -p "End installation: y(default)/n? " answer case $answer in [nN]) echo echo Continuing installation... ;; *) echo echo Installation aborted exit $ERNO; ;; esac fi } # addConf # 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() { echo -n "Writing $2 ... " # try writing config directly if [ ! -f "$2" ] ; then echo "$1" > "$2" echo "ok" return 0 fi # try backup existing config if [ ! -f "$2".bck ] ; then cp -ar "$2" "$2".bck echo "$1" > "$2" echo "[WARN] Existing config saved to ${2}.bck" return 0 fi # add configuration to missingConf file if [ "$missingDate" = "" ] ; then missingDate=set echo -n "### " >> "$MISSING_CONF" date >> "$MISSING_CONF" fi echo "#--- $2 ---" >> "$MISSING_CONF" echo "$1" >> "$MISSING_CONF" echo >> "$MISSING_CONF" echo "[WARN] Check $(realpath "$missingConf") for configuration conflicts ($2)" return 1 } # execute [-q] # -q: don't stop and don't report step functions which cannot be found # execute given step_ 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 echo "Step $1 not found" exit 1; fi # don't execute step functions which are not available if [ $NOTFOUND -eq 1 ] ; then return $NOTFOUND fi echo -en "\n[STEP $1] " existsFunction step_${1}_info if [ $? -eq 0 ] ; then step_${1}_info $1 fi if [ $QUIET -ne 1 ] ; then read -p "Start: y/n(default)? " answer case $answer in [yY]) step_$1 $1 ;; *) echo Aborting installation at step $1 exit 1; ;; esac else step_$1 $1 fi } # checkStep # return 0 - for invalid step # Check sanitiy of step number or # Check if alias exists checkStep() { if (( $1 < 1 || $1 > $MAX_STEP )) ; then eval 'local ref=$alias_'$1 if [ -z $ref ] || [ "$ref" == "$1" ] ; then return 0 else return $ref fi else return $1 fi } # continous # (max $MAX_STEP) # execute installation continously from given starting step continous() { local step=0 checkStep $1 step=$? if [[ $step == 0 ]] ; then return 1 fi for ((i=$step; i<=${MAX_STEP}; i++)); do execute -q $i local res=$? if [ $res -ne 0 ] ; then break; fi done } # selection # execute given step list # e.g.: selection -q 1 4 12 selection() { local step=0 for i in $@ ; do checkStep $i step=$? # stop on step 0 if [ $step -eq 0 ] ; then break else execute $step fi done } # Creating a minimal step definition template createTemplate() { if [ -f $TEMPLATE_NAME ] ; then return 1 fi echo "#!/bin/bash" > $TEMPLATE_NAME echo >> $TEMPLATE_NAME echo "# Step 1 is mandatory" >> $TEMPLATE_NAME echo "step_1_info() { echo \"My custom step \$1\"; }" >> $TEMPLATE_NAME echo "step_1_alias() { ALIAS=\"begin\"; }" >> $TEMPLATE_NAME echo "step_1() {" >> $TEMPLATE_NAME echo " echo \"Doing something...\"" >> $TEMPLATE_NAME echo "}" >> $TEMPLATE_NAME echo >> $TEMPLATE_NAME echo "VERSION_SEQREV=2" >> $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 } # Always display sequencer help and, if available, sequence help displayHelp() { helpSequencer # check if step definition exists by looking for step_1() existsFunction step_1 if [ $? -ne 0 ] ; then echo -e "\n It seems ${0##*/} was called directly." echo -e " Please create a sequence script first.\n" read -p " Create a template now? y/n(default)? " 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 exit 1; else echo " 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 ' : ' 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 fi } # showVersion showVersion() { echo "Sequencer ${VERSION_STRING}" echo -n "Seq Revision " if [ ! -z "${VERSION_SEQREV}" ] ; then echo "${VERSION_SEQREV}" else echo "-" fi } main() { local START=0 # option check case "$1" in --help|-h) # show only help displayHelp exit 0; ;; --quiet|-q) # detect if option quiet is available QUIET=1 shift ;; --version|-v) # version request showVersion exit 0; ;; "") # Empty -> show help displayHelp # Assume starting at one for interactive mode START=1 ;; esac # compatibility check of sequence if [ ! -z $VERSION_SEQREV ] && [ $VERSION_SEQREV -gt $VERSION_REV ] ; then echo "[ERROR] Unsupported sequence revision" showVersion exit 1 fi # TODO exclude older versions if needed if [ -z $VERSION_SEQREV ] ; then echo -e "[WARNING] No sequence revision found. Trying anyway...\n"; fi # check for starting step if [ ! -z "$1" ] ; then START=$1 else # End here on quiet mode and no step was given if [ $QUIET -eq 1 ] ; then exit 1; fi fi parseAlias # check if more than one step is given and select execution mode if [ ! -z $2 ] ; then selection $@ else continous $START fi echo echo "${0##*/} finished" } main "$@" exit 0;