WIP profile-, seq config and edit config support
This commit is contained in:
276
sequencer.sh
276
sequencer.sh
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# shellcheck disable=SC2034 # variable not used
|
# shellcheck disable=SC2034 # variable not used
|
||||||
|
# shellcheck disable=SC1090 # follow non constant source
|
||||||
|
|
||||||
# Exit on error. Append "|| true" if you expect an error.
|
# Exit on error. Append "|| true" if you expect an error.
|
||||||
set -o errexit
|
set -o errexit
|
||||||
@@ -28,9 +29,13 @@ set -o pipefail
|
|||||||
# shellcheck disable=SC2015 # && || is not if else
|
# shellcheck disable=SC2015 # && || is not if else
|
||||||
readonly seq_invocation="$(printf '%q' "${0}")$( (($#)) && printf ' %q' "$@" || true)"
|
readonly seq_invocation="$(printf '%q' "${0}")$( (($#)) && printf ' %q' "$@" || true)"
|
||||||
|
|
||||||
|
seq_args=
|
||||||
|
seq_configFile= # Filled by initSeqConfig
|
||||||
# May be overwritten by seq
|
# May be overwritten by seq
|
||||||
seq_configFile="${seq_fileName}.cfg"
|
seq_configName="${seq_fileName}.cfg"
|
||||||
seq_configTemplate="${0%.*}.cfg.example"
|
seq_configTemplate="${0%.*}.cfg.example"
|
||||||
|
seq_profileName=
|
||||||
|
_seq_profileList=
|
||||||
|
|
||||||
## Sequencer
|
## Sequencer
|
||||||
readonly sqr_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
readonly sqr_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
@@ -38,16 +43,20 @@ set -o pipefail
|
|||||||
readonly sqr_name="${sqr_file%%.*}"
|
readonly sqr_name="${sqr_file%%.*}"
|
||||||
readonly sqr_origin="$(cd -- "$(dirname -- \
|
readonly sqr_origin="$(cd -- "$(dirname -- \
|
||||||
"$(readlink -f -- "${BASH_SOURCE[0]}")")" && pwd)"
|
"$(readlink -f -- "${BASH_SOURCE[0]}")")" && pwd)"
|
||||||
|
sqr_args=
|
||||||
|
|
||||||
_sqr_stepMax=512
|
_sqr_configEdit=0
|
||||||
_sqr_interactive=1
|
readonly _sqr_configDirName=".seqs"
|
||||||
_sqr_debug=0
|
_sqr_configRoot="${HOME}/${_sqr_configDirName}"
|
||||||
_sqr_dry=0
|
|
||||||
_sqr_verbose=0
|
|
||||||
_sqr_errno=0
|
|
||||||
_sqr_contextHelp=0
|
_sqr_contextHelp=0
|
||||||
_sqr_contextExe=0
|
_sqr_contextExe=0
|
||||||
|
_sqr_debug=0
|
||||||
|
_sqr_dry=0
|
||||||
_sqr_editor=
|
_sqr_editor=
|
||||||
|
_sqr_errno=0
|
||||||
|
_sqr_interactive=1
|
||||||
|
readonly _sqr_stepMax=512
|
||||||
|
_sqr_verbose=0
|
||||||
|
|
||||||
## Terminal position
|
## Terminal position
|
||||||
_sqr_savePosAlias= ;[ -t 1 ] && _sqr_savePosAlias='\033[1A\033[1C\033[s\033[1B\033[1C'
|
_sqr_savePosAlias= ;[ -t 1 ] && _sqr_savePosAlias='\033[1A\033[1C\033[s\033[1B\033[1C'
|
||||||
@@ -303,7 +312,6 @@ running() {
|
|||||||
# : either a variable name or
|
# : either a variable name or
|
||||||
# -f : a function
|
# -f : a function
|
||||||
exists() {
|
exists() {
|
||||||
sqr::debugPause
|
|
||||||
local func=
|
local func=
|
||||||
local arg=
|
local arg=
|
||||||
|
|
||||||
@@ -315,7 +323,6 @@ exists() {
|
|||||||
func="${2:-}"
|
func="${2:-}"
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
sqr::debugContinue
|
|
||||||
if [[ -n "${func}" ]] ; then
|
if [[ -n "${func}" ]] ; then
|
||||||
declare -F "${func}" &>>/dev/null
|
declare -F "${func}" &>>/dev/null
|
||||||
else
|
else
|
||||||
@@ -494,7 +501,7 @@ endReturn() {
|
|||||||
if [[ "${1:?}" =~ ${rex} ]] ; then
|
if [[ "${1:?}" =~ ${rex} ]] ; then
|
||||||
errorCode="${1:?}"
|
errorCode="${1:?}"
|
||||||
else
|
else
|
||||||
warning " [W] Ignoring invalid error code: $1"
|
warning "Ignoring invalid error code: $1"
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
@@ -539,6 +546,23 @@ endReturn() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# endIfEmpty <VariableName> [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 <Step Number or Alias>
|
# checkStep <Step Number or Alias>
|
||||||
# return 0 - for invalid step
|
# return 0 - for invalid step
|
||||||
# return Step Number
|
# return Step Number
|
||||||
@@ -594,6 +618,7 @@ step() {
|
|||||||
# back reference variable of schema:
|
# back reference variable of schema:
|
||||||
# alias_[ALIAS]=[STEP NUMBER]
|
# alias_[ALIAS]=[STEP NUMBER]
|
||||||
parseAlias() {
|
parseAlias() {
|
||||||
|
sqr::debugPause
|
||||||
local i
|
local i
|
||||||
for ((i=1; i<=_sqr_stepMax; i++)); do
|
for ((i=1; i<=_sqr_stepMax; i++)); do
|
||||||
# Check for alias definition
|
# Check for alias definition
|
||||||
@@ -602,6 +627,7 @@ parseAlias() {
|
|||||||
# Function returns step alias
|
# Function returns step alias
|
||||||
eval '_sqr_alias_'"$("step_${i}_alias")"'='"$i"
|
eval '_sqr_alias_'"$("step_${i}_alias")"'='"$i"
|
||||||
done
|
done
|
||||||
|
sqr::debugContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
# displayHelp [NO TEMPLATE] [STEP NUMBER OR ALIAS]
|
# displayHelp [NO TEMPLATE] [STEP NUMBER OR ALIAS]
|
||||||
@@ -745,12 +771,164 @@ listSteps() {
|
|||||||
[ ${#aList[@]} -ne 0 ] && printf '%s\n' "${aList[*]}"
|
[ ${#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
|
||||||
showVersion() {
|
showVersion() {
|
||||||
printf 'Sequencer %s\n' "${_sqr_versionString}"
|
printf 'Sequencer %s\n' "${_sqr_versionString}"
|
||||||
printf 'Seq Revision %s\n' "${VERSION_SEQREV:-"-"}"
|
printf 'Seq Revision %s\n' "${VERSION_SEQREV:-"-"}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# initSeqConfig [OPTION] <NAME> [TEMPLATE]
|
||||||
|
# Create a configuration file in the users' home.
|
||||||
|
# Source it if already existent
|
||||||
|
# [OPTION]
|
||||||
|
# -p : <NAME> 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 <COMMAND>
|
# exe <COMMAND>
|
||||||
# Handle dry run and verbose output for commands without pipe and/or redirects
|
# Handle dry run and verbose output for commands without pipe and/or redirects
|
||||||
exe() {
|
exe() {
|
||||||
@@ -785,11 +963,17 @@ sqr::noEditor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sqr::main() {
|
sqr::main() {
|
||||||
|
local emptyCall=1
|
||||||
local quickStartOne=0
|
local quickStartOne=0
|
||||||
|
|
||||||
# options check
|
# options check
|
||||||
for arg in "$@" ; do
|
for arg in "$@" ; do
|
||||||
case "$1" in
|
case "${1:-}" in
|
||||||
|
--) # end parameter
|
||||||
|
shift && break;;
|
||||||
|
--config|-c) # open sequence configuration file
|
||||||
|
_sqr_configEdit=1
|
||||||
|
shift;;
|
||||||
--debug)
|
--debug)
|
||||||
_sqr_debug="1"
|
_sqr_debug="1"
|
||||||
shift ;;
|
shift ;;
|
||||||
@@ -803,14 +987,32 @@ sqr::main() {
|
|||||||
shift
|
shift
|
||||||
listSteps "${1:-}"
|
listSteps "${1:-}"
|
||||||
exit 0 ;;
|
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)
|
--quiet|-q)
|
||||||
|
sqr_args+=" $1"
|
||||||
_sqr_interactive=0
|
_sqr_interactive=0
|
||||||
shift ;;
|
shift ;;
|
||||||
--silent|-qq)
|
--silent|-qq)
|
||||||
|
sqr_args+=" $1"
|
||||||
_sqr_interactive=0
|
_sqr_interactive=0
|
||||||
LOG_LEVEL=0
|
LOG_LEVEL=0
|
||||||
shift ;;
|
shift ;;
|
||||||
--verbose|-v)
|
--verbose|-v)
|
||||||
|
sqr_args+=" $1"
|
||||||
_sqr_verbose=1
|
_sqr_verbose=1
|
||||||
shift ;;
|
shift ;;
|
||||||
--version) # version request
|
--version) # version request
|
||||||
@@ -828,7 +1030,7 @@ sqr::main() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Don't show help if only configuration should be edited
|
# Don't show help if only configuration should be edited
|
||||||
# TODO [ $SEQ_CONFIG_EDIT -ne 0 ] && [ -z "$1" ] && QUIET=2
|
[ ${_sqr_configEdit} -ne 0 ] && [ -z "${1:-}" ] && LOG_LEVEL=1
|
||||||
|
|
||||||
if [ -z "${1:-}" ] && [ $quickStartOne -eq 0 ] ; then
|
if [ -z "${1:-}" ] && [ $quickStartOne -eq 0 ] ; then
|
||||||
if ! quiet ; then
|
if ! quiet ; then
|
||||||
@@ -838,14 +1040,14 @@ sqr::main() {
|
|||||||
# Assume starting at one for interactive mode
|
# Assume starting at one for interactive mode
|
||||||
START=1
|
START=1
|
||||||
elif [ $quickStartOne -ne 0 ] ; then
|
elif [ $quickStartOne -ne 0 ] ; then
|
||||||
EMPTYCALL=0
|
emptyCall=0
|
||||||
START=1
|
START=1
|
||||||
STEP_ARGS=( "$@" )
|
seq_args=( "$@" )
|
||||||
else
|
else
|
||||||
EMPTYCALL=0
|
emptyCall=0
|
||||||
read -r -a START <<< "$1"
|
read -r -a START <<< "$1"
|
||||||
shift
|
shift
|
||||||
STEP_ARGS=( "$@" )
|
seq_args=( "$@" )
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Determine system default editor
|
# Determine system default editor
|
||||||
@@ -858,8 +1060,48 @@ sqr::main() {
|
|||||||
## Fall back to error message
|
## Fall back to error message
|
||||||
[ -z "${_sqr_editor}" ] && _sqr_editor="sqr::noEditor"
|
[ -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'
|
sqr::printf 'Running...\n'
|
||||||
seq_config 2>/dev/null || true
|
|
||||||
step 1 "$@"
|
step 1 "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user