#!/bin/bash
#  commands - heirarchical command support library

set -e

lib_load 'core/script'


######
# Library Configuration

core_commands_config_init() {
	# $cmd_tempdir - Path to temporary directory for this command instance.
	lib_setting_vars cmd_tempdir
	cmd_tempdir="$user_tempdir/run/$script_name/$$"

	run_mkdir "$cmd_tempdir"
	cleanup_add cmd_cleanup_tempdir
}

# $error_usage_hook - Set to ``cmd_error_usage()`` to provide command usage.
error_usage_hook=cmd_error_usage


######
# Library Cleanup

# cmd_cleanup_tempdir() - Removes the command's temporary directory:
# ``$cmd_tempdir``.
cmd_cleanup_tempdir() { rm -rf "$cmd_tempdir"; }


######
# Commands Names

# cmd_tempfile() - Creates a temporary file in ``$cmd_tempdir``, printing
# its name to stdout.  **All of these files will be deleted when the
# script terminates.**  See ``cmd_cleanup_tempdir()`` for more information.
cmd_tempfile() { tempfile -d "$cmd_tempdir"; }

# cmd_name() - Prints a command name, given ``${script[@]}`` and ``$@``.
cmd_name() {
	local -a a=( "${script[@]}" "$@" )
	( export IFS='_'; echo "${a[*]}"; )
}

# cmd_exists() - Returns success if a named command function exists.
# $@ - Command names to pass to ``cmd_name()``.
cmd_exists() { is_function $(cmd_name "$@"); }

######
# Command Execution

# cmd_run() - Executes the current command with the given arguments ($@)
cmd_run() { $(cmd_name) "$@"; }

# cmd_dispatch_builtins() - Attempts to dispatch a built-in command ($1).
# Returns success if the given command was handled.
#
# **TODO**: Extend this mechanism to allow registering new commands
cmd_dispatch_builtins() {
	local cmd=$1
	local handled=true
	case "$cmd" in
	usage|--usage)
		cmd_usage
		;;
	help|--help|-h|-?)
		cmd_help
		;;
	*)
		handled=false
		;;
	esac
	$handled
}

# cmd_dispatch() - Dispatches a command ($1) and moves to that
# command's namespace.  Where used, this function effectively creates
# the script's command language heirarchy.  Recursive calls extend the
# ``${script[@]}`` array, so each successive call operates on a new 
# nested namespace.
# $1 - Command name
# $@ - Command arguments
cmd_dispatch() {
	min_args 1 "$@"
	if cmd_dispatch_builtins "$@"; then
		return
	fi
	local cmd=$1
	if cmd_exists "$cmd"; then
		local script=( "${script[@]}" "$cmd" )
		shift
		cmd_run "$@"
	else
		error_usage "'$cmd' is not a known command"
	fi
}

# cmd_exec() - Executes a command ($1) in the current namespace.
# $1 - Command name
# $@ - Command arguments
cmd_exec() {
	min_args 1 "$@"
	local cmd=$1
	shift
	if cmd_exists "$cmd"; then
		$(cmd_name $cmd) "$@"
	fi
}

# cmd_exec_something() - Executes a command ($1) in the first ancenstor
# namespace that contains it.  The search begins in current command namespace
# and ascends up to the script namespace.  Once a command handler has been
# found, that function will be executed and control returned to the caller.
cmd_exec_something() {
	local cmd=$1
	local -a _script=( "${script[@]}" )
	local -a script=( "${_script[@]}" )
	while [ "${script[*]}" ]; do
		if cmd_exists "$cmd"; then
			cmd_exec "$cmd"
			break
		fi
		list_pop script >/dev/null
	done
}


######
# Command Usage and Help Support

# cmd_usage() - Prints usage information for the current command.  To be
# user-friendly, searchs for usage in anscestor command namespaces.
# This allows commands to defer their usage information to their parent
# commands.
cmd_usage() {
	local usage
	usage=$(cmd_exec_something usage)
	echo "usage: ${script[*]} $usage"

	if [ "${#script[*]}" -eq 1 -a "$script_name" == "$script" ]; then
		app_usage
	fi

	cat <<USAGE

General Commands:
	usage|--usage			Print basic command usage
	help|--help|-h|-?		Print full command help
USAGE
}

# cmd_help() - Prints help text for the current command.  This function
# operates according to the same principles as ``cmd_usage()``.
cmd_help() {
	cmd_usage

	local body
	body=$(cmd_exec_something help)
	if [ "$body" ]; then
		echo
		echo "$body"
	fi

	#; if present, display support contact name/email
	local support_name="${package_support_name:-contacting this address}"
	if [ "$package_support_email" ]; then
		 cat <<EMAIL

Support for this package is provided by $support_name:
	$package_support_email
EMAIL
	elif [ "$package_support_name" ]; then
		 echo "Support for this package is provided by $support_name."
	fi

	#; if present, display package URL
	if [ "$package_url" ]; then
		cat <<URL

For more information, please visit the package webpage:
	$package_url
URL
	fi
}

# cmd_error_usage() - Overrides the stub from ``core/output`` library,
# allowing dynamic command usage lookup.
cmd_error_usage() {
	! error "$1"
	cmd_usage >&2
	false
}

View the Developer Guide Index

View the Reference Manual Index


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