#!/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 Sat Jul 8 19:39:02 PDT 2017 by mcsh d14 v0.22.0.