Introduce tod - Template Open Deploy
diff --git a/util/option.sh b/util/option.sh
new file mode 100644
index 0000000..5f13a4c
--- /dev/null
+++ b/util/option.sh
@@ -0,0 +1,218 @@
+#!/bin/bash
+#
+# shared.sh - multiple utils
+#
+# Copyright 2019 Luigi Santivetti <luigi.santivetti@gmail.com>
+
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+function __call_module
+{
+	local -r this_module="$1"
+
+	[ -n "$this_module" ] || { lets -l -e "module not defined"; return $s_err; }
+
+	if is_opt "upins" "upall"; then
+		[ ! -d "$instance_d" ] && {
+			lets -l -e "trying to update an invalid instance"
+			return $s_err
+		}
+	fi
+
+	if is_opt "check" "watch" "upins" "upall" "doins" "doall"; then
+		local __envtable; local -i ret
+
+		__envtable="$(get_module_dependencies "envtable" $this_module)"; ret=$?
+		case "$ret" in
+			$s_ok )
+				[ -n "$__envtable" ] && {
+
+					# Export what's inside __envtable and check the actual table is
+					# imported as a variable.
+					eval "$__envtable" && declare -p -- "envtable" >/dev/null || {
+							lets -l -e "failed to export enviroment table"
+							return $s_err
+						}
+
+					# envtable is successfully on the stack, throw away its
+					# textual representation.
+					unset __envtable
+				} || {
+					lets -l -e "failed to get environment table"
+					return $s_err
+				} ;;
+			* ) return $s_err ;;
+		esac
+	fi
+
+	if is_opt "check"; then
+		(
+			# Export external variables found
+			set -eu; eval "${envtable[$this_module]}"; set +eu
+
+			case "${#deps[@]}" in
+				0 ) lets -l -i "$this_module doesn't have dependencies"
+					return $s_ok ;;
+				* ) lets -l -i "$this_module depends on: ${deps[@]}"
+					are_in_modules ${deps[@]} || {
+						lets -l -w "${deps[@]} not in MODULES"
+					} ;;
+			esac
+
+			# Check if this module correctly defines its own
+			# depmod. Return with an error if it doesn't since
+			# other options rely on this module depmod.
+
+			source "$module_d/$this_module/$module_sh"
+			if ! declare -p -- "depmod" &>/dev/null; then
+				lets -l -e "$this_module must define 'depmod'"
+				return $s_err
+			fi
+
+			for dep in ${deps[@]}; do
+				__is_in_array $dep ${depmod[@]} || {
+					lets -l -e "$dep not in $this_module depmod: ${depmod[@]}"
+					lets -l -e "add $dep to $this_module depmod"
+					return $s_err
+				}
+			done
+		)
+		return $?
+	fi
+
+	(
+		local -a files=( )
+		local callback
+
+		files+=( "$module_d/$this_module/$module_sh" )
+		files+=( "$module_d/$this_module/$holder_sh" )
+		files+=( "$module_d/$this_module/$scheme_sh" )
+
+		if is_opt "doins" "upins" "upall" "doall" "watch"; then
+
+			# Export external references
+			if test_source <(echo "${envtable[$this_module]}"); then
+				eval "${envtable[$this_module]}" || return $s_err2
+			else
+				return $s_err2
+			fi
+		fi
+
+		# Source needed files
+		if test_source "${files[@]}"; then
+			for f in ${files[@]}; do source "$f" || return $s_err3; done
+		else
+			return $s_err3
+		fi
+
+		callback="$(declare -F -- "tod_$2" 2>/dev/null)" || return $s_err6
+
+		if is_opt "doins" "doall"; then
+			create_instance_d $instance_d || return $s_err4
+		fi
+
+		# -- Here be dragons
+		eval "$callback \"${@:2}\"" || return $s_err5
+	)
+	case "$?" in
+		$s_err2 ) lets -l -e "$this_module: failed to export environment" ;;
+		$s_err3 ) lets -l -e "$this_module: failed to source $f"          ;;
+		$s_err4 ) lets -l -e "$this_module: failed to create instance_d"  ;;
+		$s_err5 ) lets -l -e "$this_module: $callback failed"             ;;
+		$s_err6 ) lets -l -w "$this_module: $callback not available"
+				  return $s_ok ;;
+		$s_ok   ) return $s_ok ;;
+	esac
+
+	return $s_err
+}
+
+function __option_call
+{
+	local option="$1"; shift
+	local -a mods=( "${@}" )
+	local modname
+
+	is_valid_module "${mods[@]}"
+	case "$?" in
+		$s_err | $s_off_broken ) return $s_err ;;
+		$s_ok  | $s_off_usable ) ;;
+	esac
+
+	# Actually call into module code
+	for modname in ${OPTARG[@]}; do
+		__call_module $modname $option
+		[ $? -eq $s_ok ] || return $s_err
+	done
+}
+
+function option_call
+{
+	local -a mods
+
+	mods=( $(get_modules_optarg "${@:2}") ) || return $s_err
+	# Filtered out list of requested modules
+	OPTARG=( "${mods[@]}" )
+
+	__option_call "$1" "${mods[@]}" >/dev/null
+}
+
+# @desc   : process command line options only two options allowed per invocation
+#         : at the moment. Keep it simple, keep it robust. For options details
+#         : see help.sh.
+#         :
+#         : credits to https://stackoverflow.com/a/28466267
+function __option_process
+{
+	local opt; OPTIND=1
+
+	# Be quiet and disallow any single char option
+	local -r options=":-:"
+	local -a args
+
+	if getopts "$options" opt; then
+		if [ "$opt" = "-" ]; then
+			opt="${OPTARG%%=*}"      # Get option name
+			OPTARG="${OPTARG#$opt}"  # Get option argument(s)
+			OPTARG="${OPTARG#=}"     # Drop `=` if any
+			OPTARG="${OPTARG//,/ }"  # Drop `,` if any
+
+			# Early return for help
+			[ "$opt" = "help" ] && __help && return $s_ok
+
+			is_in_options "$opt" || return $s_err2
+		fi
+	fi
+
+	OPTIONS[$opt]=1; option_call $opt "${OPTARG[@]}"
+	case "$?" in
+		$s_err ) lets -l -e "$opt failed"; return $s_err        ;;
+		$s_ok  ) lets -l -i --phew "$opt success"; return $s_ok ;;
+	esac
+}
+
+function option_process
+{
+	__option_process ${@}
+	case "$?" in
+		$s_err2 ) lets -l -e "invalid option, --help" ;;
+		$s_err  ) return $s_err                       ;;
+		$s_ok   ) return $s_ok                        ;;
+	esac
+}