#!/bin/bash
#   app - application support library

set -e


######
# Start/Exit Functions

# app_start() - Called by ``app_run()`` to perform all necessary startup
# actions.  This includes loading configuration files, initializing settings,
# and finally calling the application callback: ``${script_name}_init``.
app_start() {
	info "Running '$script_name${*:+ }$*'"
	info "  in '$PWD'..."
	cleanup_init

	app_timer_start

	config_init
	#; override lib_load to perform late initialization
	func_chain config lib_load

	config_load

	config_check

	settings_check
	settings_final

	#; override lib_load to perform late init/check
	func_chain app lib_load

	script_cmd_exec init

	! $dumpenv || set >"$script_name.env"
}

# app_exit() - Called by ``app_run()`` to perform graceful exit actions.
app_exit() {
	if [ "$1" ]; then
		error "$@"
		[ "$exit_code" ] || exit_code=1
	else
		info "... done"
	fi

	exit $exit_code
}


######
# Application Timer

# app_timer_start() - Starts the application timer to track execution time.
# This registers a cleanup function (``app_timer_cleanup()``).
app_timer_start() {
	timer_start app_timer_runtime
	cleanup_add app_timer_cleanup
}

# app_timer_cleanup() - Stops the application timer and reports the elapsed
# time (if ``$verbose = true``).  Called automatically when the script exits.
app_timer_cleanup() {
	timer_stop app_timer_runtime
	local elapsed
	elapsed=$(timer_elapsed app_timer_runtime)
	info "Running time: $elapsed"
}


######
# Application Commands

# app_version() - Prints the package/tool version.
app_version() {
	local name version desc
	if [ $script_name = $package_name ]; then
		name=$package_name
		version=$package_version
	else
		name="$package_name $script_name"
		version=$script_version
	fi
	desc=$(local -a script=( $script_name ) && cmd_exec desc)
	echo "$name v$version ($package_build_date)${desc:+  }$desc"
}

# app_license() - Handles application license commands, displaying
# a summary, warranty information, or full license.
app_license() {
	app_version
	lib_load 'core/license'

	case "$1" in
	(''|short|blurb)		license_blurb ;;
	(warranty)			license_warranty ;;
	(full)				license_full ;;
	(*)
		warn "$1: unknown license command"
		;;
	esac
}

# app_help() - Prints the top-level help text for the application.
app_help() {
	app_version
	cmd_help
}

# app_check() - Executes the check command if it exists, otherwise issues
# a warning.  The normal disptch would give an error and usage message.
app_check() {
	if cmd_exists check; then
		app_echo "$script check${*+ }$*: started..."
		cmd_dispatch check "$@"
		app_echo "$script check${*+ }$*: ...finished"
	else
		# Obviously, this is NOT an error, just an embarassment.
		warn "TODO: 'check' is not implemented"
	fi
}

# app_check_lib() - Executes the ``lib_check`` callback for each named
# library (``$@``).  With no arguments, checks all libraries that have a
# ``lib_check`` callback.
app_check_lib() {
	lib_load 'sys/check'
	if [ "$@" ]; then
		for_each lib_load "$@"
		for_each lib_check "$@"
	else
		lib_check_all
	fi
}

# app_usage() - Top-level application usage function.  These commands are
# automatically available in all scripts and displayed after the top-level
# script command usage function has been called.
app_usage() {
	cat <<USAGE

Tool Commands:
	--version			Prints tool version and exits
	--license [<kind>]		Prints tool license details and exits
	app ...				Application management commands
	check [...]			Runs tool self-test/demo
	check-lib <lib>+		Runs library self-test/demo
	shell [<file> [<arg>+]]		Runs tool command shell
USAGE
}


######
# Application Command Dispatch

# app_main() - Top-level application command dispatch function.
app_main() {
	debug "processing command line arguments..."
	local cmd=$1
	[ "$cmd" ] || error_usage "command required"
	shift

	case "$cmd" in
	-V|--version)
		app_version
		;;
	--license)
		app_license "$@"
		;;
	check)
		app_check "$@"
		;;
	check-lib)
		app_check_lib "$@"
		;;
	shell)
		lib_load 'sys/shell'
		shell_run "$@"
		;;
	app)
		lib_cmd_dispatch app_cmd_builtin "$@"
		;;
	*)
		app_cmd_dispatch "$cmd" "$@"
		;;
	esac
}

# app_cmd_dispatch - Top-level command dispatch handler.  It allows scripts to
# provide their own ``${script_name}_dispatch`` function to add dynamic
# top-level commands.  This mechanism should not be needed by most tools, as
# normal command dispatching methods suffice for a static command language.
app_cmd_dispatch() {
	if cmd_exists dispatch; then
		cmd_exec dispatch "$@"
	else
		cmd_dispatch "$@"
	fi
}


######
# Application Commands

# app_cmd_builtin_usage() -
app_cmd_builtin_usage() {
	cat <<USAGE
...
Application Commands:
	client ...			Client commands
	server ...			Server commands
	backup ...			Backup commands
	restore ...			Restore commands
USAGE
}

# app_cmd_builtin_config() - Dispatches application configuration commands.
app_cmd_builtin_config() { lib_cmd_dispatch 'config' "$@"; }

# app_cmd_builtin_backup() - Dispatches application backup commands.
app_cmd_builtin_backup() {
	lib_load 'sys/backup'
	backup_dispatch 'backup' "$@"
}

# app_cmd_builtin_restore() - Dispatches application restore commands.
app_cmd_builtin_restore() {
	lib_load 'sys/backup'
	backup_dispatch 'restore' "$@"
}

# app_cmd_builtin_client() - Dispatches application client commands.
app_cmd_builtin_client() {
	lib_load 'sys/client'
	lib_cmd_dispatch 'client' "$@"
}

# app_cmd_builtin_server() - Dispatches application server commands.
app_cmd_builtin_server() {
	lib_load 'sys/server'
	lib_cmd_dispatch 'server' "$@"
}


######
# Public Interface

# app_run() - Called at the end of every tool script, after defining all
# callbacks, commands, and other data and functions.  It calls ``app_start()``,
# ``app_main()``, and ``app_exit()`` in that order.
app_run() {
	app_start "$@"
	app_main "$@"
	app_exit
}


######
# Late Library Loading Function Chains

# config_lib_load() - Chain function to initialize libraries loaded "late".
config_lib_load() {
	local name=$1
	! is_lib_loaded "$name" || return 0
	config_lib_load_next "$name"
	config_init_lib "$name"
	config_load_lib "$name"
}

# app_lib_load() - Chain function to initialize libraries loaded "late".
app_lib_load() {
	local name=$1
	! is_lib_loaded "$name" || return 0
	app_lib_load_next "$name"
	config_check_lib "$name"
	! $settings_dump || settings_dump_lib "$name"
	settings_check_lib "$name"
	settings_final_lib "$name"
}

View the Developer Guide Index

View the Reference Manual Index


Generated on Fri Jul 28 14:34:49 PDT 2017 by mcsh d14 v0.23.0.