Skip to content

Instantly share code, notes, and snippets.

@brlin-tw
Created May 29, 2017 11:10
Show Gist options
  • Save brlin-tw/6370743dae4b4e7e20c2be47d6e93ba7 to your computer and use it in GitHub Desktop.
Save brlin-tw/6370743dae4b4e7e20c2be47d6e93ba7 to your computer and use it in GitHub Desktop.
bashbeautify #10 reproducing scipt
#!/usr/bin/env bash
# shellcheck disable=SC2034
## ############ META_PROGRAM_*: Metadata about This Program ###################
## Fill in metadata about this program for reusing in the script and documenting purposes
## You may safely remove this entire section if you don't need it
### Program's name, by default it is determined in runtime according to the filename, set this variable to override the autodetection, default: ${RUNTIME_EXECUTABLE_NAME}(optional)
declare META_PROGRAM_NAME_OVERRIDE=""
### Program's identifier, program's name with character limitation exposed by platform(optional)
declare META_PROGRAM_IDENTIFIER=""
### Program's description, default(optional)
declare META_PROGRAM_DESCRIPTION=""
### Intellectual property license applied to this program(optional)
declare META_PROGRAM_LICENSE=""
### Years since any fraction of copyright material is activated, indicates the year when copyright protection will be outdated(optional)
declare META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE=""
### Whether program should pause and expect user pressing enter when program ended, which is useful when launching scripts in GUI, which may undesirebly close the terminal emulator window when the script is exited and leaving user no chance to check execution result
### 0: Don't pause(default)
### 1: Pause
### This parameter is overridable, in case of command-line options like --interactive and --no-interactive
declare -i META_PROGRAM_PAUSE_BEFORE_EXIT="0"
## ######################## End of META_PROGRAM_* #############################
## META_APPLICATION_*: Metadata about the application this program belongs to
## https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#meta_application_
## You may safely remove this entire section if you don't need it
### Human-readable name of application(optional)
declare META_APPLICATION_NAME=""
### Application's identifier, application's name with limitation posed by other software, default(not implemented): unnamed-application
declare META_APPLICATION_IDENTIFIER=""
### Developers' name of application(optional)
declare META_APPLICATION_DEVELOPER_NAME=""
### Application's official site URL(optional)
declare META_APPLICATION_SITE_URL=""
### Application's issue tracker, if there's any(optional)
declare META_APPLICATION_ISSUE_TRACKER_URL=""
### An action to let user get help from developer or other sources when error occurred
declare META_APPLICATION_SEEKING_HELP_OPTION="contact developer"
### The Software Directory Configuration this application uses, refer below section for more info
declare META_APPLICATION_INSTALL_STYLE="STANDALONE"
## ####################### End of META_APPLICATION_* ##########################
## META_RUNTIME_*: Runtime dependencies information for dependency checking
## You may safely remove this entire section if you don't need it
### Human-friendly runtime dependency name definition
declare -r META_RUNTIME_DEPENDENCIES_DESCRIPTION_GNU_COREUTILS="GNU Coreutils"
### These are the dependencies that the script foundation needs, and needs to be checked IMMEDIATELY
### BASHDOC: Bash Features - Arrays(associative array)
declare -Ar META_RUNTIME_DEPENDENCIES_CRITICAL=(
["basename"]="${META_RUNTIME_DEPENDENCIES_DESCRIPTION_GNU_COREUTILS}"
["realpath"]="${META_RUNTIME_DEPENDENCIES_DESCRIPTION_GNU_COREUTILS}"
)
### These are the dependencies that are used later and also checked later
declare -Ar META_RUNTIME_DEPENDENCIES=()
## ######################### End of META_RUNTIME_* ############################
## init function, the main program's entry point
## This function is called from the "main" content near the end of this file,
## with the command-line parameters as it's arguments
init() {
if ! meta_processCommandlineArguments; then
meta_printHelpMessage
exit 1
fi
exit 0
}; declare -fr init
## ##################### Start of GBSST Support Code ##########################
## The following section are GNU Bash Shell Script's support code, you may
## remove the entire section if you want, just leave the last init call
declare -r GBSS_NAME="GNU Bash Shell Script Template"
### Common constant definitions
declare -ir COMMON_RESULT_SUCCESS=0
declare -ir COMMON_RESULT_FAILURE=1
declare -ir COMMON_BOOLEAN_TRUE=0
declare -ir COMMON_BOOLEAN_FALSE=1
### NOTE: realpath's commandline option, `--strip` will be replaced in favor of `--no-symlinks` after April 2019(Ubuntu 14.04's Support EOL)
### Makes debuggers' life easier - Unofficial Bash Strict Mode
### http://redsymbol.net/articles/unofficial-bash-strict-mode/
### BASHDOC: Shell Builtin Commands - Modifying Shell Behavior - The Set Builtin
#### Prematurely terminates the script on any command returning non-zero, append " || true"(BASHDOC: Basic Shell Features » Shell Commands » Lists of Commands) if the non-zero return value is rather intended to happen. A trap on `ERR', if set, is executed before the shell exits.
set -o errexit
#### If set, any trap on `ERR' is also inherited by shell functions, command substitutions, and commands executed in a subshell environment.
set -o errtrace
#### If set, the return value of a pipeline(BASHDOC: Basic Shell Features » Shell Commands » Pipelines) is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully.
set -o pipefail
#### Treat unset variables and parameters other than the special parameters `@' or `*' as an error when performing parameter expansion. An error message will be written to the standard error, and a non-interactive shell will exit.
#### NOTE: errexit will NOT be triggered by this condition as this is not a command error
#### bash - Correct behavior of EXIT and ERR traps when using `set -eu` - Unix & Linux Stack Exchange
#### https://unix.stackexchange.com/questions/208112/correct-behavior-of-exit-and-err-traps-when-using-set-eu
set -o nounset
### Traps
### Functions that will be triggered if certain condition met
### BASHDOC: Shell Builtin Commands » Bourne Shell Builtins(trap)
#### Collect all information useful for debugging
meta_trap_err_print_debugging_info(){
if [ ${#} -ne 3 ]; then
printf "ERROR: %s: Wrong function argument quantity!\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
local -ir line_error_location=${1}; shift # The line number that triggers the error
local -r failing_command="${1}"; shift # The failing command
local -ir failing_command_return_status=${1} # The failing command's return value
# Don't print trace for printf commands
set +o xtrace
printf \
"ERROR: %s has encountered an error and is ending prematurely, %s for support.\n"\
"${META_PROGRAM_NAME_OVERRIDE:-${RUNTIME_EXECUTABLE_NAME:-This program}}"\
"${META_APPLICATION_SEEKING_HELP_OPTION:-contact developer}"\
1>&2
printf "\n" # Separate paragraphs
printf "Technical information:\n"
printf "\n" # Separate list title and items
printf "* The failing command is \"%s\"\n" "${failing_command}"
printf "* Failing command's return status is %s\n" "${failing_command_return_status}"
printf "* Intepreter info: GNU Bash v%s on %s platform\n" "${BASH_VERSION}" "${MACHTYPE}"
printf "* Stacktrace:\n"
declare -i level=0; while [ "${level}" -lt "${#FUNCNAME[@]}" ]; do
if [ "${level}" -eq 0 ]; then
printf " %u. %s(%s:%u)\n"\
"${level}"\
"${FUNCNAME[${level}]}"\
"${BASH_SOURCE[${level}]}"\
"${line_error_location}"
else
printf " %u. %s(%s:%u)\n"\
"${level}"\
"${FUNCNAME[${level}]}"\
"${BASH_SOURCE[${level}]}"\
"${BASH_LINENO[((${level} - 1))]}"
fi
((level = level + 1))
done; unset level
printf "\n" # Separate list and further content
return "${COMMON_RESULT_SUCCESS}"
}; declare -rf meta_trap_err_print_debugging_info
meta_trap_err(){
if [ ${#} -ne 3 ]; then
printf "ERROR: %s: Wrong function argument quantity!\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
local -ir line_error_location=${1}; shift # The line number that triggers the error
local -r failing_command="${1}"; shift # The failing command
local -ir failing_command_return_status=${1} # The failing command's return value
meta_trap_err_print_debugging_info "${line_error_location}" "${failing_command}" "${failing_command_return_status}"
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_trap_err
# Variable is expanded when trap triggered, not now
#shellcheck disable=SC2016
declare -r TRAP_ERREXIT_ARG='meta_trap_err ${LINENO} "${BASH_COMMAND}" ${?}'
# We separate the arguments to TRAP_ERREXIT_ARG, so it should be expand here
#shellcheck disable=SC2064
trap "${TRAP_ERREXIT_ARG}" ERR
# NOTE: Associative arrays are NOT supported by this function
meta_util_is_array_set_and_not_null(){
if [ "${#}" -ne 1 ]; then
printf "%s: Error: argument quantity illegal\n" "${FUNCNAME[0]}" 1>&2
exit "${COMMON_RESULT_FAILURE}"
fi
declare -n array_nameref="${1}"
if [ "${#array_nameref[@]}" -eq 0 ]; then
return "${COMMON_BOOLEAN_FALSE}"
fi
return "${COMMON_BOOLEAN_TRUE}"
}; declare -fr meta_util_is_array_set_and_not_null
# NOTE: Array and nameref are NOT supported by this function
meta_util_is_parameter_set_and_not_null(){
if [ "${#}" -ne 1 ]; then
printf "%s: Error: argument quantity illegal\n" "${FUNCNAME[0]}" 1>&2
exit "${COMMON_RESULT_FAILURE}"
fi
declare -n name_reference
name_reference="${1}"
if [ ! -v name_reference ]; then
return "${COMMON_BOOLEAN_FALSE}"
else
if [ -z "${name_reference}" ]; then
return "${COMMON_BOOLEAN_FALSE}"
else
return "${COMMON_BOOLEAN_TRUE}"
fi
fi
}; declare -fr meta_util_is_parameter_set_and_not_null
meta_util_make_parameter_readonly_if_not_null_otherwise_unset(){
if [ "${#}" -eq 0 ]; then
printf "%s: Error: argument quantity illegal\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
for parameter_name in "${@}"; do
declare -n parameter_reference="${parameter_name}"
if [ -v "${parameter_name}" ]; then
if [ -z "${parameter_reference}" ]; then
unset "${parameter_name}"
else
declare -r "${parameter_name}"
fi
fi
unset -n parameter_reference
done; unset parameter_name
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_make_parameter_readonly_if_not_null_otherwise_unset
#### Introduce the program and software at leaving
meta_trap_exit_print_application_information(){
# No need to debug this area, keep output simple
set +o xtrace
# Only print the line if:
#
# * There's info to be print
# * Pausing program is desired(META_PROGRAM_PAUSE_BEFORE_EXIT=1)
#
# ...cause it's kinda stupid for a trailing line at end-of-program-output
if meta_util_is_parameter_set_and_not_null META_APPLICATION_NAME\
|| meta_util_is_parameter_set_and_not_null META_APPLICATION_DEVELOPER_NAME\
|| meta_util_is_parameter_set_and_not_null META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE\
|| meta_util_is_parameter_set_and_not_null META_PROGRAM_LICENSE\
|| meta_util_is_parameter_set_and_not_null META_APPLICATION_LICENSE\
|| meta_util_is_parameter_set_and_not_null META_APPLICATION_SITE_URL\
|| meta_util_is_parameter_set_and_not_null META_APPLICATION_ISSUE_TRACKER_URL\
|| (\
meta_util_is_parameter_set_and_not_null META_PROGRAM_PAUSE_BEFORE_EXIT\
&& [ "${META_PROGRAM_PAUSE_BEFORE_EXIT}" -eq 1 ] \
); then
printf -- "------------------------------------\n"
fi
if meta_util_is_parameter_set_and_not_null META_APPLICATION_NAME; then
printf "%s\n" "${META_APPLICATION_NAME}"
fi
if meta_util_is_parameter_set_and_not_null META_APPLICATION_DEVELOPER_NAME; then
printf "%s et. al." "${META_APPLICATION_DEVELOPER_NAME}"
if meta_util_is_parameter_set_and_not_null META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE; then
printf " " # Separator with ${META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE}
else
printf "\n"
fi
fi
if meta_util_is_parameter_set_and_not_null META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE; then
printf "© %s\n" "${META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE}"
fi
if meta_util_is_parameter_set_and_not_null META_PROGRAM_LICENSE; then
printf "Intellectual Property License: %s\n" "${META_PROGRAM_LICENSE}"
elif meta_util_is_parameter_set_and_not_null META_APPLICATION_LICENSE; then
printf "Intellectual Property License: %s\n" "${META_APPLICATION_LICENSE}"
fi
if meta_util_is_parameter_set_and_not_null META_APPLICATION_SITE_URL; then
printf "Official Website: %s\n" "${META_APPLICATION_SITE_URL}"
fi
if meta_util_is_parameter_set_and_not_null META_APPLICATION_ISSUE_TRACKER_URL; then
printf "Issue Tracker: %s\n" "${META_APPLICATION_ISSUE_TRACKER_URL}"
fi
if meta_util_is_parameter_set_and_not_null META_PROGRAM_PAUSE_BEFORE_EXIT\
&& [ "${META_PROGRAM_PAUSE_BEFORE_EXIT}" -eq 1 ]; then
local enter_holder
printf "Press ENTER to quit the program.\n"
read -r enter_holder
fi
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_trap_exit_print_application_information
meta_trap_exit(){
meta_trap_exit_print_application_information
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_trap_exit
trap 'meta_trap_exit' EXIT
### Unset all null META_PROGRAM_* parameters and readonly all others
### META_APPLICATION_IDENTIFIER also as it can't be determined in runtime
meta_util_make_parameter_readonly_if_not_null_otherwise_unset\
META_PROGRAM_NAME_OVERRIDE\
META_PROGRAM_IDENTIFIER\
META_PROGRAM_DESCRIPTION\
META_PROGRAM_LICENSE\
META_PROGRAM_PAUSE_BEFORE_EXIT\
META_PROGRAM_COPYRIGHT_ACTIVATED_SINCE\
META_APPLICATION_IDENTIFIER
### Workarounds
#### Temporarily disable errexit
meta_workaround_errexit_setup() {
if [ ${#} -ne 1 ]; then
printf "ERROR: %s: Wrong function argument quantity!\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
local option=${1} # on: enable errexit; off: disable errexit
if [ "${option}" == "on" ]; then
set -o errexit
# We separate the arguments to TRAP_ERREXIT_ARG, so it should be expand here
#shellcheck disable=SC2064
trap "${TRAP_ERREXIT_ARG}" ERR
elif [ "${option}" == "off" ]; then
set +o errexit
trap - ERR
else
printf "ERROR: %s: Wrong function argument format!\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_workaround_errexit_setup
meta_util_declare_global_parameters(){
if [ "${#}" -eq 0 ]; then
printf "%s: Error: Function parameter quantity illegal\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
for parameter_name in "${@}"; do
declare -g "${parameter_name}"
done; unset parameter_name
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_declare_global_parameters
meta_util_unset_global_parameters_if_null(){
if [ "${#}" -eq 0 ]; then
printf "%s: Error: Function parameter quantity illegal\n" "${FUNCNAME[0]}" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
for parameter_name in "${@}"; do
if [ -z "${parameter_name}" ]; then
unset "${parameter_name}"
fi
done; unset parameter_name
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_unset_global_parameters_if_null
### Runtime Dependencies Checking
### shell - Check if a program exists from a Bash script - Stack Overflow
### http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script
meta_checkRuntimeDependencies() {
local -n array_ref="${1}"
if [ "${#array_ref[@]}" -eq 0 ]; then
return "${COMMON_RESULT_SUCCESS}"
else
declare -i exit_status; for a_command in "${!array_ref[@]}"; do
meta_workaround_errexit_setup off
command -v "${a_command}" >/dev/null 2>&1
exit_status="${?}"
meta_workaround_errexit_setup on
if [ ${exit_status} -ne 0 ]; then
printf "ERROR: Command \"%s\" not found, program cannot continue like this.\n" "${a_command}" 1>&2
printf "ERROR: Please make sure %s is installed and it's executable path is in your operating system's executable search path.\n" "${array_ref["${a_command}"]}" >&2
printf "Goodbye.\n"
exit "${COMMON_RESULT_FAILURE}"
fi
done; unset a_command exit_status
return "${COMMON_RESULT_SUCCESS}"
fi
}; declare -fr meta_checkRuntimeDependencies
### RUNTIME_*: Info acquired from runtime environment
### https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#runtime-determined-settings
### The following variables defines the environment aspects that can only be detected in runtime, we use RUNTIME_ namespace for these variables.
### These variables will not be set if technically not available(e.g. the program is provided to intepreter/etc. via stdin), or just not implemented yet
meta_fsis_setup_runtime_parameters(){
meta_util_declare_global_parameters\
RUNTIME_EXECUTABLE_FILENAME\
RUNTIME_EXECUTABLE_NAME\
RUNTIME_EXECUTABLE_DIRECTORY\
RUNTIME_EXECUTABLE_PATH_ABSOLUTE\
RUNTIME_EXECUTABLE_PATH_RELATIVE\
RUNTIME_COMMAND_BASE
# Runtime environment's executable search path priority array
declare -a RUNTIME_PATH_DIRECTORIES
IFS=':'\
read -r -a RUNTIME_PATH_DIRECTORIES <<< "${PATH}"\
|| true # Without this `read` will return 1
declare -r RUNTIME_PATH_DIRECTORIES
if [ ! -v BASH_SOURCE ]; then
if meta_util_is_parameter_set_and_not_null META_APPLICATION_INSTALL_STYLE\
&& [ "${META_APPLICATION_INSTALL_STYLE}" == "SHC" ]; then
printf "GNU Bash Shell Script Template: Error: META_APPLICATION_INSTALL_STYLE set to SHC, but is not possible due to unknown script location, make sure the program is not run as intepreter's standard input stream.\n" 1>&2
exit "${COMMON_RESULT_FAILURE}"
fi
else
# BashFAQ/How do I determine the location of my script? I want to read some config files from the same place. - Greg's Wiki
# http://mywiki.wooledge.org/BashFAQ/028
RUNTIME_EXECUTABLE_FILENAME="$(basename "${BASH_SOURCE[0]}")"
RUNTIME_EXECUTABLE_NAME="${META_PROGRAM_NAME_OVERRIDE:-${RUNTIME_EXECUTABLE_FILENAME%.*}}"
RUNTIME_EXECUTABLE_DIRECTORY="$(dirname "$(realpath --strip "${0}")")"
RUNTIME_EXECUTABLE_PATH_ABSOLUTE="${RUNTIME_EXECUTABLE_DIRECTORY}/${RUNTIME_EXECUTABLE_FILENAME}"
RUNTIME_EXECUTABLE_PATH_RELATIVE="${0}"
for pathdir in "${RUNTIME_PATH_DIRECTORIES[@]}"; do
# It is possible that the pathdir is invalid (e.g. wrong configuration or misuse ":" as path content which is not allowed in PATH), simply ignore it
if [ ! -d "${pathdir}" ]; then
continue
fi
# If executable is in shell's executable search path, consider the command is the executable's filename
# Also do so if the resolved path matches(symbolic linked)
resolved_pathdir="$(realpath "${pathdir}")"
if [ "${RUNTIME_EXECUTABLE_DIRECTORY}" == "${pathdir}" ]\
|| [ "${RUNTIME_EXECUTABLE_DIRECTORY}" == "${resolved_pathdir}" ]; then
RUNTIME_COMMAND_BASE="${RUNTIME_EXECUTABLE_FILENAME}"
break
fi
done; unset pathdir resolved_pathdir
declare -r RUNTIME_COMMAND_BASE="${RUNTIME_COMMAND_BASE:-${0}}"
fi
meta_util_make_parameter_readonly_if_not_null_otherwise_unset\
RUNTIME_EXECUTABLE_FILENAME\
RUNTIME_EXECUTABLE_NAME\
RUNTIME_EXECUTABLE_DIRECTORY\
RUNTIME_EXECUTABLE_PATH_ABSOLUTE\
RUNTIME_EXECUTABLE_PATH_RELATIVE\
RUNTIME_COMMAND_BASE
# Collect command-line parameters
declare -igr RUNTIME_COMMANDLINE_ARGUMENT_QUANTITY="${#}"
if [ "${RUNTIME_COMMANDLINE_ARGUMENT_QUANTITY}" -ne 0 ]; then
declare -ag RUNTIME_COMMANDLINE_ARGUMENT_LIST
RUNTIME_COMMANDLINE_ARGUMENT_LIST=("${@:1}")
declare -agr RUNTIME_COMMANDLINE_ARGUMENT_LIST
fi
# Set run guard
declare -gr meta_fsis_setup_runtime_parameters_called="yes"
}; declare -fr meta_fsis_setup_runtime_parameters
### Flexible Software Installation Specification - Software Directories Configuration(S.D.C.)
### This function defines and determines the directories used by the software
### https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#software-directories-configurationsdc
meta_fsis_setup_software_directories_configuration(){
# Run guard
if [ ! -v meta_fsis_setup_runtime_parameters_called ]; then
printf "%s: %s: %u: Error: This function cannot be called before meta_fsis_setup_runtime_parameters, please contact developer.\n"\
"${GBSS_NAME}"\
"${FUNCNAME[0]}"\
"${LINENO}"\
1>&2
exit "${COMMON_RESULT_FAILURE}"
fi
meta_util_declare_global_parameters\
SDC_EXECUTABLES_DIR\
SDC_LIBRARIES_DIR\
SDC_SHARED_RES_DIR\
SDC_I18N_DATA_DIR\
SDC_SETTINGS_DIR\
SDC_TEMP_DIR
if meta_util_is_parameter_set_and_not_null META_APPLICATION_INSTALL_STYLE; then
case "${META_APPLICATION_INSTALL_STYLE}" in
FHS)
# Filesystem Hierarchy Standard(F.H.S.) configuration paths
# http://refspecs.linuxfoundation.org/FHS_3.0/fhs
## Software installation directory prefix, should be overridable by configure/install script
meta_util_declare_global_parameters FHS_PREFIX_DIR
declare -r FHS_PREFIX_DIR="/usr/local"
declare -r SDC_EXECUTABLES_DIR="${FHS_PREFIX_DIR}/bin"
declare -r SDC_LIBRARIES_DIR="${FHS_PREFIX_DIR}/lib"
declare -r SDC_I18N_DATA_DIR="${FHS_PREFIX_DIR}/share/locale"
if meta_util_is_parameter_set_and_not_null META_APPLICATION_IDENTIFIER; then
declare -r SDC_SHARED_RES_DIR="${FHS_PREFIX_DIR}/share/${META_APPLICATION_IDENTIFIER}"
declare -r SDC_SETTINGS_DIR="/etc/${META_APPLICATION_IDENTIFIER}"
declare -r SDC_TEMP_DIR="/tmp/${META_APPLICATION_IDENTIFIER}"
else
unset\
SDC_SHARED_RES_DIR\
SDC_SETTINGS_DIR\
SDC_TEMP_DIR
fi
;;
SHC)
# Setup Self-contained Hierarchy Configuration(S.H.C.)
# https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#self-contained-hierarchy-configurationshc
# https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#path_to_software_installation_prefix_directorysourceshc-only
# https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#shc_prefix_dirshc-only
meta_util_declare_global_parameters SHC_PREFIX_DIR
if [ -f "${RUNTIME_EXECUTABLE_DIRECTORY}/APPLICATION_METADATA.source" ]; then
SHC_PREFIX_DIR="${RUNTIME_EXECUTABLE_DIRECTORY}"
else
if [ ! -f "${RUNTIME_EXECUTABLE_DIRECTORY}/PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY.source" ]; then
printf "GNU Bash Script Template: Error: PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY.source not exist, can't setup Self-contained Hierarchy Configuration.\n" 1>&2
exit 1
fi
# Scope of Flexible Software Installation Specification
# shellcheck disable=SC1090,SC1091
source "${RUNTIME_EXECUTABLE_DIRECTORY}/PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY.source"
if ! meta_util_is_parameter_set_and_not_null PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY; then
printf "GNU Bash Script Template: Error: PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY not defined, can't setup Self-contained Hierarchy Configuration.\n" 1>&2
exit 1
fi
SHC_PREFIX_DIR="$(realpath --strip "${RUNTIME_EXECUTABLE_DIRECTORY}/${PATH_TO_SOFTWARE_INSTALLATION_PREFIX_DIRECTORY}")"
fi
declare -gr SHC_PREFIX_DIR
# Read external software directory configuration(S.D.C.)
# https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#software-directories-configurationsdc
# Scope of Flexible Software Installation Specification
# shellcheck disable=SC1090,SC1091
source "${SHC_PREFIX_DIR}/SOFTWARE_DIRECTORY_CONFIGURATION.source" 2>/dev/null || true
meta_util_unset_global_parameters_if_null\
SDC_EXECUTABLES_DIR\
SDC_LIBRARIES_DIR\
SDC_SHARED_RES_DIR\
SDC_I18N_DATA_DIR\
SDC_SETTINGS_DIR\
SDC_TEMP_DIR
;;
STANDALONE)
# Standalone Configuration
# This program don't rely on any directories, make no attempt defining them
unset SDC_EXECUTABLES_DIR SDC_LIBRARIES_DIR SDC_SHARED_RES_DIR SDC_I18N_DATA_DIR SDC_SETTINGS_DIR SDC_TEMP_DIR
;;
*)
printf "Error: Unknown software directories configuration, program can not continue.\n" 1>&2
exit 1
;;
esac
fi
meta_util_make_parameter_readonly_if_not_null_otherwise_unset\
SDC_EXECUTABLES_DIR\
SDC_LIBRARIES_DIR\
SDC_SHARED_RES_DIR\
SDC_I18N_DATA_DIR\
SDC_SETTINGS_DIR\
SDC_TEMP_DIR
# Set run guard
declare -gr meta_fsis_setup_software_directories_configuration_called="yes"
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_fsis_setup_software_directories_configuration
### Flexible Software Installation Specification - Setup application metadata
### This function locates and loads the metadata of the application
### https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification#application_metadatasource
meta_fsis_setup_application_metadata(){
# Run guard
if [ ! -v meta_fsis_setup_software_directories_configuration_called ]; then
printf "%s: %s: %u: Error: This function cannot be called before meta_fsis_setup_software_directories_configuration_called, please contact developer.\n"\
"${GBSS_NAME}"\
"${FUNCNAME[0]}"\
"${LINENO}"\
1>&2
exit "${COMMON_RESULT_FAILURE}"
fi
meta_util_declare_global_parameters\
META_APPLICATION_NAME\
META_APPLICATION_DEVELOPER_NAME\
META_APPLICATION_LICENSE\
META_APPLICATION_SITE_URL\
META_APPLICATION_ISSUE_TRACKER_URL\
META_APPLICATION_SEEKING_HELP_OPTION
if meta_util_is_parameter_set_and_not_null META_APPLICATION_INSTALL_STYLE; then
case "${META_APPLICATION_INSTALL_STYLE}" in
FHS)
if [ -v "${SDC_SHARED_RES_DIR}" ] && [ -n "${SDC_SHARED_RES_DIR}" ]; then
:
else
# Scope of external project
# shellcheck disable=SC1090,SC1091
source "${SDC_SHARED_RES_DIR}/APPLICATION_METADATA.source" 2>/dev/null || true
fi
;;
SHC)
# Scope of external project
# shellcheck disable=SC1090,SC1091
source "${SHC_PREFIX_DIR}/APPLICATION_METADATA.source" 2>/dev/null || true
;;
STANDALONE)
: # metadata can only be set from header
;;
*)
printf "Error: Unknown META_APPLICATION_INSTALL_STYLE, program can not continue.\n" 1>&2
exit 1
;;
esac
fi
# FIXME: META_APPLICATION_LICENSE isn't unset by this call
meta_util_make_parameter_readonly_if_not_null_otherwise_unset\
META_APPLICATION_NAME\
META_APPLICATION_DEVELOPER_NAME\
META_APPLICATION_LICENSE\
META_APPLICATION_SITE_URL\
META_APPLICATION_ISSUE_TRACKER_URL\
META_APPLICATION_SEEKING_HELP_OPTION
}; declare -fr meta_fsis_setup_application_metadata
### Program's Commandline Options Definitions
declare -r COMMANDLINE_OPTION_DISPLAY_HELP_LONG="--help"
declare -r COMMANDLINE_OPTION_DISPLAY_HELP_SHORT="-h"
declare -r COMMANDLINE_OPTION_DISPLAY_HELP_DESCRIPTION="Display help message"
declare -r COMMANDLINE_OPTION_ENABLE_DEBUGGING_LONG="--debug"
declare -r COMMANDLINE_OPTION_ENABLE_DEBUGGING_SHORT="-d"
declare -r COMMANDLINE_OPTION_ENABLE_DEBUGGING_DESCRIPTION="Enable debug mode"
### Drop first element from array and shift remaining elements to replace the first one
### FIXME: command error in this function doesn't not trigger ERR trap for some reason
meta_util_array_shift(){
if [ "${#}" -ne 1 ]; then
printf "%s: Error: argument quantity illegal\n" "${FUNCNAME[0]}" 1>&2
exit "${COMMON_RESULT_FAILURE}"
fi
local -n array_ref="${1}"
if [ "${#array_ref[@]}" -eq 0 ]; then
printf "ERROR: array is empty!\n" 1>&2
return "${COMMON_RESULT_FAILURE}"
fi
# Unset the 1st element
unset "array_ref[0]"
# Repack array if element still available in array
if [ "${#array_ref[@]}" -ne 0 ]; then
array_ref=("${array_ref[@]}")
fi
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_array_shift
### Understand what argument is in the command, and set the global variables accordingly.
meta_processCommandlineArguments() {
if [ "${RUNTIME_COMMANDLINE_ARGUMENT_QUANTITY}" -eq 0 ]; then
return "${COMMON_RESULT_SUCCESS}"
else
# modifyable parameters for parsing by consuming
local -a arguments=("${RUNTIME_COMMANDLINE_ARGUMENT_LIST[@]}")
# Normally we won't want debug traces to appear during parameter parsing, so we add this flag and defer it activation till returning(Y: Do debug)
local enable_debug="N"
while :; do
# BREAK if no arguments left
if [ ! -v arguments ]; then
break
else
case "${arguments[0]}" in
"${COMMANDLINE_OPTION_DISPLAY_HELP_LONG}"\
|"${COMMANDLINE_OPTION_DISPLAY_HELP_SHORT}")
meta_printHelpMessage
exit 0
;;
"${COMMANDLINE_OPTION_ENABLE_DEBUGGING_LONG}"\
|"${COMMANDLINE_OPTION_ENABLE_DEBUGGING_SHORT}")
enable_debug="Y"
;;
*)
printf "ERROR: Unknown command-line argument \"%s\"\n" "${arguments[0]}" >&2
return ${COMMON_RESULT_FAILURE}
;;
esac
meta_util_array_shift arguments
fi
done
fi
if [ "${enable_debug}" = "Y" ]; then
set -o xtrace
fi
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_processCommandlineArguments
### Print single segment of commandline option help
meta_util_printSingleCommandlineOptionHelp(){
if [ "${#}" -ne 3 ] && [ "${#}" -ne 4 ]; then
printf "ERROR: %s: Wrong parameter quantity!\n" "${FUNCNAME[0]}" >&2
return "${COMMON_RESULT_FAILURE}"
fi
local description="${1}"; shift # Option description
local long_option="${1}"; shift # The long version of option
local short_option="${1}"; shift # The short version of option
declare -r description long_option short_option
if [ "${#}" -ne 0 ]; then
local current_value="${1}"; shift # Current value of option, if option has value
declare -r current_value
fi
printf "### %s / %s ###\n" "${long_option}" "${short_option}"
printf "%s\n" "${description}"
if [ -v current_value ]; then
printf "Current value: %s\n" "${current_value}"
fi
printf "\n" # Separate with next option(or next heading)
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_util_printSingleCommandlineOptionHelp
### Print help message whenever:
### * User requests it
### * An command syntax error has detected
meta_printHelpMessage(){
printf "# %s #\n" "${RUNTIME_EXECUTABLE_NAME}"
if meta_util_is_parameter_set_and_not_null META_PROGRAM_DESCRIPTION; then
printf "%s\n" "${META_PROGRAM_DESCRIPTION}"
printf "\n"
fi
printf "## Usage ##\n"
printf "\t%s (command-line options and parameters)\n" "${RUNTIME_COMMAND_BASE}"
printf "\n"
printf "## Command-line Options ##\n"
meta_util_printSingleCommandlineOptionHelp "${COMMANDLINE_OPTION_DISPLAY_HELP_DESCRIPTION}" "${COMMANDLINE_OPTION_DISPLAY_HELP_LONG}" "${COMMANDLINE_OPTION_DISPLAY_HELP_SHORT}"
meta_util_printSingleCommandlineOptionHelp "${COMMANDLINE_OPTION_ENABLE_DEBUGGING_DESCRIPTION}" "${COMMANDLINE_OPTION_ENABLE_DEBUGGING_LONG}" "${COMMANDLINE_OPTION_ENABLE_DEBUGGING_SHORT}"
return "${COMMON_RESULT_SUCCESS}"
}; declare -fr meta_printHelpMessage
if meta_util_is_array_set_and_not_null META_RUNTIME_DEPENDENCIES_CRITICAL; then
meta_checkRuntimeDependencies META_RUNTIME_DEPENDENCIES_CRITICAL
fi
if meta_util_is_array_set_and_not_null META_RUNTIME_DEPENDENCIES; then
meta_checkRuntimeDependencies META_RUNTIME_DEPENDENCIES
fi
meta_fsis_setup_runtime_parameters
meta_fsis_setup_software_directories_configuration
meta_fsis_setup_application_metadata
### This script is based on the GNU Bash Shell Script Template project
### https://github.com/Lin-Buo-Ren/GNU-Bash-Shell-Script-Template
### and is based on the following version:
declare -r META_BASED_ON_GNU_BASH_SHELL_SCRIPT_TEMPLATE_VERSION="v1.26.0-15-g935eb02-dirty"
### You may rebase your script to incorporate new features and fixes from the template
### This script is comforming to Flexible Software Installation Specification
### https://github.com/Lin-Buo-Ren/Flexible-Software-Installation-Specification
### and is based on the following version: v1.5.0
## ###################### End of GBSST Support Code #########################
init "${@}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment