#!/usr/bin/env bash # shellcheck disable=SC2034 # variable not used # shellcheck disable=SC1090 # follow non constant source # Exit on error. Append "|| true" if you expect an error. set -o errexit # Exit on error inside any functions or subshells. set -o errtrace # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR set -o nounset # Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip` set -o pipefail # Turn on traces, useful while debugging but commented out by default # set -o xtrace ## Globals { 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##*/}}" readonly seq_dir="$(cd -- "$(dirname -- "${0}")" && pwd)" readonly seq_origin="$(cd -- "$(dirname -- "$(readlink -f -- "${0}")")" && pwd)" readonly seq_file=$(basename -- "${0}") readonly seq_fileName=${seq_file%%.*} # shellcheck disable=SC2015 # && || is not if else readonly seq_invocation="$(printf '%q' "${0}")$( (($#)) && printf ' %q' "$@" || true)" seq_args= seq_configFile= # Filled by initSeqConfig # 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)" readonly sqr_file="$(basename -- "${BASH_SOURCE[0]}")" readonly sqr_name="${sqr_file%%.*}" readonly sqr_origin="$(cd -- "$(dirname -- \ "$(readlink -f -- "${BASH_SOURCE[0]}")")" && pwd)" sqr_args= _sqr_configEdit=0 readonly _sqr_configDirName=".seqs" _sqr_configRoot="${HOME}/${_sqr_configDirName}" _sqr_contextHelp=0 _sqr_contextExe=0 _sqr_debug=0 _sqr_dry=0 _sqr_editor= _sqr_errno=0 _sqr_interactive=1 readonly _sqr_stepMax=512 _sqr_verbose=0 ## 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' ## 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' col_lightred= ; [ -t 1 ] && col_lightred='\033[1;31m' col_green= ; [ -t 1 ] && col_green='\033[0;32m' col_lightgreen= ; [ -t 1 ] && col_lightgreen='\033[1;32m' col_orange= ; [ -t 1 ] && col_orange='\033[0;33m' col_yellow= ; [ -t 1 ] && col_yellow='\033[1;33m' col_blue= ; [ -t 1 ] && col_blue='\033[0;34m' col_lightblue= ; [ -t 1 ] && col_lightblue='\033[1;34m' col_purple= ; [ -t 1 ] && col_purple='\033[0;35m' col_lightpurple= ; [ -t 1 ] && col_lightpurple='\033[1;35m' col_cyan= ; [ -t 1 ] && col_cyan='\033[0;36m' col_lightcyan= ; [ -t 1 ] && col_lightcyan='\033[1;36m' col_lightgray= ; [ -t 1 ] && col_lightgray='\033[0;37m' col_white= ; [ -t 1 ] && col_white='\033[1;37m' col_off= ;[ -t 1 ] && col_off='\033[0m' # No Color } helpSequencer() { cat < 0 = fatal (stop) LOG_TIME="${LOG_TIME:-}" # 1 = show time stamps # sqr::log [LOG LEVEL] [LOG_COLOR] [OPTIONS] [LOG MESSAGE] # Construct log messages # # [OPTIONS] # -a : append text (no info and timestamp) # Uses color from last sqr::log call without -a # -e : Output to stderr # -- : End of options # sqr::log () { sqr::debugPause local appendText= local arg= local col_end="${col_off}" local outp='/dev/stdout' local log_level="${1:-}" shift local log_color="${1:-}" shift for arg in "${@}" ; do case "${1:-}" in --) shift && break ;; -a) appendText=1 shift ;; -e) outp='/dev/stderr' shift ;; esac done [[ -z "${log_color}" ]] && col_end="" # all remaining arguments are to be printed local log_line="" while IFS=$'\n' read -r log_line ; do printf '%b' "${log_color}" >${outp} if [[ -n "${LOG_TIME}" ]] ; then if (( appendText )) ; then printf '%24s' "" >${outp} else printf '%s ' "$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >${outp} fi fi if (( ! appendText )) ; then printf " %3s " "[${log_level}]" >${outp} printf "%s" "${log_line}" >${outp} else # +3 : "[] " printf "%$((${#log_level} + 4))s%s" "" "${log_line}" >${outp} fi printf '%b\n' "${col_end}" >${outp} done <<< "${@:-}" 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; } # 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::debugPause() { if (( _sqr_debug )) ; then set +o xtrace; else true; fi } sqr::debugContinue() { if (( _sqr_debug )) ; then set -o xtrace; else true; fi } # color [BACKGROUND COLOR] color() { [ ! -t 1 ] && return 0 [ -z "${1:-}" ] && tput sgr0 && return 0 case "${1:-}" in black) tput setaf 0 ;; red) tput setaf 1 ;; green) tput setaf 2 ;; yellow) tput setaf 3 ;; blue) tput setaf 4 ;; magenta) tput setaf 5 ;; cyan) tput setaf 6 ;; white) tput setaf 7 ;; none) tput sgr0 return 0 ;; *) tput setaf "${1:-}" ;; esac case "${2:-}" in black) tput setab 0 ;; red) tput setab 1 ;; green) tput setab 2 ;; yellow) tput setab 3 ;; blue) tput setab 4 ;; magenta) tput setab 5 ;; cyan) tput setab 6 ;; white) 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 { sqr::trap_exit () { exists -f seq_trapExit && seq_trapExit debug "Sequencer exit" } trap sqr::trap_exit EXIT # requires `set -o errtrace` sqr::error_report() { local error_code=${?} error "Error in ${sqr_file} in function ${1} on line ${2}" exit ${error_code} } # Uncomment the following line for always providing an error backtrace # trap 'sqr::error_report "${FUNCNAME:-.}" ${LINENO}' ERR } # check if run as root root() { [[ $(id -u) -eq 0 ]] } # check if there is another PID other than this one running() { pidof -o %PPID -x "${0##*/}">>/dev/null } # exists [-f] [--] [ELEMENT] # [ELEMENT] # : either a variable name or # -f : a function exists() { local func= local arg= for arg in "$@" ; do case "${1:-}" in --) shift && break ;; -f) func="${2:-}" esac done if [[ -n "${func}" ]] ; then declare -F "${func}" &>>/dev/null else [[ -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() { (( _sqr_interactive )) } # quiet # Log level smaller 3 (info) are treated as quiet request quiet() { [[ $LOG_LEVEL -lt 3 ]] } # silent # Log level equals 0 (stop) silent() { [[ $LOG_LEVEL -eq 0 ]] } # dry-run # Started with --dry-run dry() { (( _sqr_dry )) } # verbose # Started with --verbose 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 # -n : no input help # -y : default = yes # -- : end of options confirm() { sqr::debugPause local arg= local rexReply='^[Yy]+$' # default no local inputHelp='[y/N] ' # default no local noHelp=0 local force=0 for arg in "${@}" ; do case "${1:-}" in --) shift && break ;; -f) force=1 shift ;; -n) noHelp=1 shift ;; -y) rexReply='^[^Nn]*$' # default yes inputHelp='[Y/n] ' # default yes shift ;; esac done (( noHelp )) && inputHelp= if interactive || (( force )) ; then read -r -p "${1:-} ${inputHelp}" -n 1 # Needed when read stops after one character (-n 1) # Add a newline only if input is not empty (just enter is pressed) [[ -z "$REPLY" ]] || sqr::echo "" else REPLY='' fi sqr::debugContinue [[ $REPLY =~ ${rexReply} ]] } # ask [OPTION] [QUESTION] [DEFAULT] # 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 ask() { sqr::debugPause local hidden= local empty=0 local arg= for arg in "$@" ; do case "${1}" in --) shift && break ;; -e) empty=1 shift ;; -s) hidden="-s" shift ;; esac done local answer= if [[ -n "${2:-}" ]] ; then ! interactive && printf '%s\n' "${2}" && sqr::debugContinue && return 0 read ${hidden?} -r -p "${1:-"User input"} ($2) " answer else read ${hidden?} -r -p "${1:-"User input"} " answer fi if [[ -z "$answer" ]] ; then answer="${2:-}" fi printf '%s\n' "${answer}" # return if answer is empty sqr::debugContinue if (( ! empty )) ; then [[ -n "${answer}" ]] fi } # Escaping non-printable characters with the proposed POSIX $'' syntax escpath() { printf "%q" "$*" } # saveReturn # Function returns with in case step wants additional evaluation saveReturn() { if [[ "${1:-"0"}" -ne 0 ]] ; then _sqr_errno=${1} fi return "${_sqr_errno}" } # getReturn # Returns latest saved $_sqr_errno getReturn() { return "${_sqr_errno}" } # endReturn [-f] [-o ERRORCODE] [MESSAGE] # -f : force exit with $_sqr_errno without user input # -o : override and check given [ERRORCODE] # [MESSAGE] : Custom error message # endReturn() { local arg local forceExit=0 local errorCode=${_sqr_errno} 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 warning "Ignoring invalid error code: $1" fi shift ;; "") break ;; *) endMessage="$*" break ;; esac done if ( [[ ${errorCode} -ne 0 ]] && ! interactive ) \ || [[ ${errorCode} -ne 0 && $forceExit -ne 0 ]] ; then sqr::echo if [[ -n "${endMessage}" ]] ; then error -e "${endMessage}" error -e -a "Sequence stopped" else error -e "Return value ${errorCode} detected." error -e -a "Sequence stopped" fi exit "${errorCode}" fi if [[ "${errorCode}" -ne 0 ]] ; then sqr::echo if [ "${endMessage}" != "" ]; then error -e "${endMessage}" else error -e "Return value ${errorCode} detected." fi if confirm -y "End sequence" ; then error -e "Sequence stopped" exit "${errorCode}" else # reset saved error code if user chooses to continue _sqr_errno=0 sqr::echo warning "Continuing sequence..." fi fi } # endIfEmpty [DESCRIPTION] # DESCRIPTION : Optional text for error endIfEmpty() { eval 'local ref=$'"${1:-}" if [ -z "${ref:-}" ] ; then if [ -n "${2:-}" ] ; then error -- "$2" error -a "Sequence stopped." else error -- "\${$1} must not be empty." error -a "Sequence stopped." fi exit 6 fi } # checkStep # 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 # 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() { sqr::debugPause 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 sqr::debugContinue } # 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] listSteps() { local locAlias= local aList=() local aSearch="${1:-}" for ((i=1; i<=_sqr_stepMax; i++)); do # Display step reference in help if step function exists exists -f "step_${i}" || continue # Display alias if exists if exists -f "step_${i}_alias" ; then locAlias="$("step_${i}_alias")" else locAlias="$i" fi if [ -z "$aSearch" ]; then aList+=("$locAlias") elif [[ "$locAlias" =~ ^$aSearch ]]; then aList+=("$locAlias") fi done [ ${#aList[@]} -ne 0 ] && printf '%s\n' "${aList[*]}" } # listProfiles [OPTION] [SEARCH] # List all available profiles for current user # [OPTION] # -q : only check for profile support listProfiles() { local file= local profiles=() if [[ ${_sqr_configDirName} == $(basename "${_sqr_configRoot}") ]] ; then error "${seq_name} does not have configuration profiles" return 1 fi [[ "${1:-}" == "-q" ]] && return 0 #for file in $(ls "${_sqr_configRoot}" 2>/dev/null); do for file in "${_sqr_configRoot}"/* ; do file="$(basename -- "${file}")" [[ ${file%.*} =~ ^${1:-".*"} ]] && profiles+=("${file%.*}") done printf '%s\n' "${profiles[*]}" } # showVersion showVersion() { printf 'Sequencer %s\n' "${_sqr_versionString}" printf 'Seq Revision %s\n' "${VERSION_SEQREV:-"-"}" } # initSeqConfig [OPTION] [TEMPLATE] # Create a configuration file in the users' home. # Source it if already existent # [OPTION] # -p : is subfolder used for profiles # -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 arg local answer=n local retVal=255 local sourceAlways=0 local createEmpty=0 local seqProfiles=0 local configExists= local configDir= for arg in "$@" ; do case "$1" in -e) createEmpty=1 shift ;; -p) seqProfiles=1 shift ;; -t) sourceAlways=1 shift ;; esac done local configLoc="$_sqr_configRoot/$1" if [[ $seqProfiles -ne 0 ]] ; then [ -z "$seq_profileName" ] && seq_profileName=default configLoc="$_sqr_configRoot/$1/${seq_profileName}.cfg" fi configDir="$(dirname -- "$configLoc")" local configTemplate="$2" # Don't create anything if only profiles should be listed if [ -n "${_seq_profileList}" ] ; then _sqr_configRoot="$configDir" return 0 fi _sqr_configRoot="$configDir" if [ -s "$configLoc" ] ; then info "Using configuration file: $configLoc" seq_configFile="$configLoc" . "$configLoc" return 0 fi # Ask for config creation if not existent if ! quiet && ! dry ; then sqr::echo " [i] Configuration $configLoc missing" confirm "Create it now?" || return 3 fi # Create config subdir in users home if [ ! -e "$configDir/" ] ; then sqr::echo -n "Creating $(realpath -- "$configDir")..." # shellcheck disable=SC2015 # && || is not if else exe install -m 700 -d "$configDir" && sqr::echo "Ok" || sqr::echo "Nok" fi # Config does not exist, check for template if [ -s "$configTemplate" ] ; then # Check first if there is an existing configuration at the templates position configExists="$(dirname -- "$configTemplate")/$1" if [ -s "$configExists" ] ; then exe mv "$configExists" "$configLoc" endReturn -o $? "Unable to use existing configuration: $configExists" sqr::echo " [i] Using existing configuration: $configExists" sqr::echo " (Moved to $configDir)" . "$configLoc" retVal=0 else # Install new template to the final location exe install -m 600 -T "$configTemplate" "$configLoc" endReturn -o $? "Failed to create configuration" if [ $sourceAlways -eq 0 ] ; then if [ $_sqr_configEdit -eq 0 ] ; then warning "Seq configuration created from template but not used" warning -a "Please modify \"$configLoc\" first" fi retVal=1 else warning "Using seq configuration from template $configTemplate" warning -a " (Copied to $configDir)" . "$configTemplate" retVal=0 fi fi seq_configFile="$configLoc" else warning "Seq configuration template not found" fi if [ $createEmpty -ne 0 ] ; then # Create empty config file warning "Created empty configuration file $configLoc" exe touch "$configLoc" exe chmod 600 "$configLoc" seq_configFile="$configLoc" retVal=2 fi # Give the user a chance to edit the create config file if [ $retVal -eq 255 ]; then error "No seq configuration created" retVal=3 elif ! quiet && ! dry ; then if confirm "Edit configuration file now?" ; then exe editor "$configLoc" . "$configLoc" retVal=0 fi fi return $retVal } # exe # Handle dry run and verbose output for commands without pipe and/or redirects exe() { dry && printf -- '--' if dry || verbose ; then (set -x; : "$@") fi if ! dry ; then "$@" fi } # exep # Handle dry run and verbose output for commands containing pipe and/or redirects exep() { if dry ; then printf -- '--++ : %s\n' "$*" elif verbose ; then printf '++ : %s\n' "$*" fi if ! dry ; then bash -c "$*" fi } # Used as editor if no system editor could be found sqr::noEditor() { error "No editor found (\$EDITOR,\"/etc/alternatives\",nano,vi)" error -a "Cannot open: $*" } sqr::main() { local emptyCall=1 local quickStartOne=0 # options check for arg in "$@" ; do case "${1:-}" in --) # end parameter shift && break;; --config|-c) # open sequence configuration file _sqr_configEdit=1 shift;; --debug) _sqr_debug="1" shift ;; --dry-run|-d) _sqr_dry=1 shift ;; --help|-h) # show only help displayHelp 1 "${2:-}" exit 0 ;; --liststeps|-ls) shift listSteps "${1:-}" exit 0 ;; --profile|-p) # seq profile name sqr_args+=" $1 ${2:-}" shift # Cover the case when only -p is given without profile name if [ -z "${1:-}" ] ; then seq_profileName=default else seq_profileName="$1" && shift fi ;; -pl) # List available profiles with search shift [[ ${LOG_LEVEL} -gt 1 ]] && LOG_LEVEL=1 # "only show errors" _seq_profileList="${1:-".*"}" [ -n "${1:-}" ] && shift ;; --quiet|-q) sqr_args+=" $1" _sqr_interactive=0 shift ;; --silent|-qq) sqr_args+=" $1" _sqr_interactive=0 LOG_LEVEL=0 shift ;; --verbose|-v) sqr_args+=" $1" _sqr_verbose=1 shift ;; --version) # version request showVersion exit 0 ;; esac done # debug mode if [[ "${_sqr_debug:-}" = "1" ]]; then set -o xtrace PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' # Enable error backtracing trap 'sqr::error_report "${FUNCNAME:-.}" ${LINENO}' ERR fi # Don't show help if only configuration should be edited [ ${_sqr_configEdit} -ne 0 ] && [ -z "${1:-}" ] && LOG_LEVEL=1 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 seq_args=( "$@" ) else emptyCall=0 read -r -a START <<< "$1" shift seq_args=( "$@" ) fi # Determine system default editor # Change with update-alternatives --config 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)" ## Fall back to error message [ -z "${_sqr_editor}" ] && _sqr_editor="sqr::noEditor" parseAlias # run configuration for sequence only if available and if first step is valid if exists -f seq_config ; then # Create/edit configuration file if [ $_sqr_configEdit -ne 0 ] ; then # Suppress seq_config output for editing quietSave=${LOG_LEVEL} LOG_LEVEL=0 seq_config "${seq_args[@]}" LOG_LEVEL=${quietSave} if [ -w "$seq_configFile" ]; then exe editor "$seq_configFile" else error "No configuration file available" fi [ ${emptyCall} -ne 0 ] && exit 0 fi if checkStep "${START[0]}" >/dev/null ; then if ! seq_config "${seq_args[@]}" ; then error "Configuring sequence failed" exit 1 fi else return 1 fi elif [ ${_sqr_configEdit} -ne 0 ] ; then error "Sequence does not have a configuration file" return 1 fi # Check for profile support if [ -n "${_seq_profileList}" ]; then listProfiles "${_seq_profileList}"; exit $? elif [ -n "${seq_profileName}" ]; then listProfiles -q || exit 1 fi sqr::printf 'Running...\n' step 1 "$@" } sqr::main "$@"