blob: 0734dd544bd469b50c3145488fe75e825531df32 [file] [log] [blame]
#!/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" )
if is_opt "doins" "upins" "upall" "doall" "watch"; then
# Only upmod doesn't need scheme
files+=( "$module_d/$this_module/$scheme_sh" )
# 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
}