#!/bin/bash
# dev/gen/bash - MCSH bash script source generation
set -e
######
# Library Configuration
dev_gen_bash_config_init() {
	# $gen_bash_namespace - If set, specifies the namespace to use
	# when generating library script functions.  If not set, the
	# basename of the generated library will be used automatically.
	lib_setting_vars --null gen_bash_namespace
	# $gen_bash_here_pipe[] - Specifies the pipeline of commands
	# that should be used to encode/decode the content in a here
	# document function.  The commands should be specified in the
	# order required for encoding.
	#
	# For decoding, the command pipeline is built in reverse order,
	# and each command gets passed one additional option: ``-d``.
	lib_setting_arrays gen_bash_here_pipe
	[ ${#gen_bash_here_pipe[*]} -gt 0 ] \
		|| gen_bash_here_pipe=( 'gzip -c' 'base64' )
}
######
# MCSH Bash Script CLI
# gen_bash_dispatch() - Dispatches a Bash script generation command ($@)
gen_bash_dispatch() { lib_cmd_dispatch gen_bash "$@"; }
# gen_bash_usage() - Prints usage for Bash script generation commands
gen_bash_usage() {
	cat <<USAGE
<cmd> ...
Source Generation Commands:
	tool <name> <desc> [<lib>+]	Generates a new tool
	lib <name> <desc> [<lib>+]	Generates a new library
	license <blurb> <wrnty> <lic>	Generates the 'license' library
Low-Level Source Generation Commands:
	header <name> <desc>		Prints standard library header code
	func <name>			Generates a function
	here doc <tag>			Generates here document
	here func <tag>			Generates here document function
USAGE
}
# gen_bash_source() - Generates Bash source file(s) for the given kind ($1),
# name ($2), description ($3), and (optional) dependencies ($@).
gen_bash_source() {
	min_args 2 "$@"
	local kind=$1
	local name=$2
	local desc=$3
	local gen_edit=true
	local gen_error_fail=true
	local conf dir
	case "$kind" in
	(tool)
		gen_bash_source "conf" "$name.conf" "$desc configuration"
		conf="conf/$name.conf.in"
		dir=src
		;;
	(conf)
		gen_edit=false
		gen_error_fail=false
		dir=conf
		;;
	(library)
		dir=libs
		;;
	esac
	local file="$dir/$name.in"
	[ ! -f "$file" ] || error "$file: exists"
	gen_bash_source_file "$@" >"$file"
	local -a files=( "$file" )
	[ -z "$conf" ] || files+=( "$conf" )
	! $gen_edit || run_editor "${files[@]}"
	if [ ! -s "$file" ]; then
		warn "$file: $kind empty... aborting"
		run rm -f "${files[@]}"
	fi
}
#; internal helper
gen_bash_source_file() {
	min_args 3 "$@"
	local kind=$1
	local name=$2
	local desc=$3
	shift 3
	gen_bash_header "$name" "$desc"
	if [ "$kind" = tool ]; then
		echo
		echo "source '__""runtime""__'"
	fi
	if [ "$*" ]; then
		echo
		for_each gen_bash_lib_load "$@"
	fi
	gen_bash_source_$kind "$name" "$desc"
}
######
# MCSH Functions
# gen_bash_lib_load() - Generates a command to load a named library script ($1)
gen_bash_lib_load() { echo "lib_load '$1'"; }
######
# MCSH Tool Scripts
# gen_bash_tool() - Generates template source code for a new tool ($1)
# given its description ($2) and (optional) dependencies ($@).
gen_bash_tool() { gen_bash_source tool "$@"; }
# gen_bash_source_tool() - Generates the body of a new tool script ($1).
gen_bash_source_tool() {
	local path=$1
	local desc=$2
	local name=${path##*/}
	local sym=$(lib_symbol "$name")
#---
	cat <<TOOL
######
# Native Dependencies
${sym}_client_packages=( )
${sym}_server_packages=( )
######
# Script Initialization
# ${sym}_init() - Performs script-specific initialization.
${sym}_init() {
	: debug "${sym}_init called"
}
######
# Script Configuration
# ${sym}_config_init() - Defines, documents, and initializes script settings.
${sym}_config_init() {
	# ${sym}_var - Documents this setting variable
	lib_setting_vars ${sym}_var
}
# ${sym}_config_check() - Initializes remaining script settings and
# validates their values.
${sym}_config_check() {
	${sym}_var=\${${sym}_var:-true}
}
######
# CLI
# ${sym}_func() - Does not do what this documentation says it does
${sym}_func() {
	warn "$name has not been implemented"  # if true, what is this?!
}
######
# Check
# ${sym}_check() - Performs a self-check of all script functionality
${sym}_check() {
	${sym}_func
}
######
# Main
# ${sym}_desc() - Prints a short description of the $name script
${sym}_desc() { echo "$desc"; }
# ${sym}_usage() - Prints the top-level command usage for the $name script
${sym}_usage() {
	cat <<USAGE
...
$sym Commands:
	func				Tests the $name tool
USAGE
}
# ${sym}_help() - Prints the top-level command help for this script
${sym}_help() {
	cat <<HELP
$name is a $desc tool.  It is part of the $package_name package.
HELP
}
app_run "\$@"
TOOL
#+++
}
######
# MCSH Tool Configuration Scripts
# gen_bash_source_conf() - Generates a tool configuration file.
gen_bash_source_conf() {
	:
}
######
# MCSH Library Scripts
# gen_bash_lib() - Generates template source code for a new library ($1)
# given its description ($2) and (optional) dependencies ($@).
gen_bash_lib() { gen_bash_source library "$@"; }
# gen_bash_source_library() - Generates the body of a new library script ($1)
# with the given description ($2).
gen_bash_source_library() {
	local name=$1
	local desc=$2
	local sym=$(lib_symbol "$name")
	local ns=${gen_bash_namespace:-$(lib_symbol "${name##*/}")}
#---
	cat <<LIB
######
# Native Dependencies
${sym}_client_packages=( )
${sym}_server_packages=( )
######
# Library Initialization
# ${sym}_lib_init() - Performs global library initialization.
${sym}_lib_init() {
	: debug "${sym}_lib_init called"
}
######
# Library Configuration
# ${sym}_config_init() - Defines, documents, and initializes library settings.
${sym}_config_init() {
	: debug "${sym}_config_init called"
}
# ${sym}_config_check() - Initializes remaining library settings and
# validates their values.
${sym}_config_check() {
	: debug "${sym}_config_check called"
}
######
# $name CLI
# ${ns}_dispatch() - Initializes remaining library settings and
${ns}_dispatch() { lib_cmd_dispatch ${ns} "\$@"; }
# ${ns}_usage() - Prints the top-level command usage for the $name script
${ns}_usage() {
	cat <<USAGE
...
Commands:
	func				Tests $ns command dispatch
USAGE
}
######
# Public Interface
# ${ns}_func() - Does not do what this documentation says it does
${ns}_func() {
	warn "$name library has not been implemented"  # if true, what is this?!
}
LIB
#+++
}
######
# License Library
# gen_bash_license() - Generates the license library from the named files.
# $1 - Name of the package (e.g. $(PKG))
# $2 - Name of file containing license blurb (e.g. LICENSE)
# $3 - Name of file containing warranty information (e.g. WARRANTY)
# $4 - Name of file containing full license (e.g. COPYING)
gen_bash_license() {
	has_args 4 "$@"
	gen_bash_header "license-parts" "$1 licence details"
	gen_bash_license_func blurb "summary" <"$2"
	gen_bash_license_func warranty "warrany information "<"$3"
	gen_bash_license_func full <"$4"
}
# gen_bash_license_func() - Generates a single here document function
# using the given function ($1) with the given description ($2).
# $1 - Name of generated license function
# $2 - Description of license function (optional)
gen_bash_license_func() {
	min_max_args 1 2 "$@"
	echo
	local func="license_${1}_print"
	gen_bash_here_func "$func" "Prints the package license${2:+ }$2."
}
######
# Source File Headers
# gen_bash_header() - Generates a header for a Bash script.
gen_bash_header() {
	has_args 2 "$@"
	local name=$1
	local desc=$2
#---
	cat <<EOF
#!/bin/bash
# $name - $desc
EOF
#+++
	$gen_error_fail || return 0
	echo
	echo "set -e"
}
######
# Here Document Functions
# gen_bash_here_func() - Generates a function ($1) containing a single
# here document ($2).
#
# By default, the here document content gets compressed and encoded to
# reduce the space of the final distributable.  This can be disabled
# by adding the following line in your configuration:
#
#   ``gen_bash_here_pipe=( cat )``
#
# To extract the original content, the generated function will pipe the
# encoded document through the same decoding and decompression
# programs when called.  Consequently, those native dependencies must be
# installed on the system.
#
# $1 - Name of function.
# $2 - Function documentation string.
# $3 - Name of file (optional); otherwise, document will be read from `stdin`.
gen_bash_here_func() {
	min_max_args 2 3 "$@"
	local name=$1
	local docs=$2
	local file=${3:--}
	local -a decode_pipe=( $(gen_bash_here_decode_pipe) )
	local -u tag="${name}_data"
	cat "$file" \
		| eval "$(gen_bash_here_encode_pipe)" \
		| gen_bash_here_doc "$tag" - ${decode_pipe[*]} \
		| gen_bash_func "$name" "$docs"
}
# gen_bash_here_encode_pipe() - Prints the command pipeline for encoding
# the content of a here document.  See ``$gen_bash_here_pipe[]``.
gen_bash_here_encode_pipe() {
	gen_bash_here_pipe "${gen_bash_here_pipe[@]}"
}
# gen_bash_here_decode_pipe() - Prints the command pipeline for decoding an
# encoded here document.  See ``$gen_bash_here_pipe[]``.
gen_bash_here_decode_pipe() {
	local -a cmds=( "${gen_bash_here_pipe[@]}" )
	list_reverse cmds
	list_map gen_bash_here_decode_cmd cmds
	echo '|'
	gen_bash_here_pipe "${cmds[@]}"
}
# gen_bash_here_decode_cmd() - Appends decode option to each pipeline command.
gen_bash_here_decode_cmd() { echo "$* -d"; }
# gen_bash_here_pipe() - Prints a command pipline, constructed from
# the given commands ($@), that can be ``eval``-uated by the shell.
gen_bash_here_pipe() {
	local i result=""
	for i in "$@"; do
		result="$result${result:+ | }$i"
	done
	echo "$result"
}
######
# Functions
# gen_bash_func() - Generates a function ($1) from the given file ($2).
#
# $1 - Name of function.
# $2 - Function documentation.  If `null`, no documentation will be
# generated for the new function.
# $3 - Name of file containing the function body (optional).  If not
# given, the function body will be read from `stdin`.
gen_bash_func() {
	min_max_args 2 3 "$@"
	local name=$1
	local docs=$2
	local file=${3:--}
	[ -z "$docs" ] || echo "# $name() - $docs"
	echo "$name() {"
	cat "$file"
	echo "}"
}
######
# Here Documents
# gen_bash_here_doc() - Generates a here document with the given tag
# ($1) from the given file ($2).
# $1 - Tag to use as delimiter.
# $2 - Name of file containing here document content.  Use ``-`` to use `stdin`.
# $@ - Command pipeline to use for decoding content.
gen_bash_here_doc() {
	min_args 2 "$@"
	local tag=$1
	local file=$2
	shift 2
	echo "cat <<$tag" "$@"
	cat "$file"
	echo "$tag"
}
 
Generated on Tue Jul  4 17:00:32 PDT 2017 by mcsh d14 v0.21.0.