Luigi Santivetti | 0fdd470 | 2020-06-22 19:00:32 +0100 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # |
| 3 | # shared.sh - multiple utils |
| 4 | # |
| 5 | # Copyright 2019 Luigi Santivetti <luigi.santivetti@gmail.com> |
| 6 | |
| 7 | # Permission is hereby granted, free of charge, to any person obtaining a |
| 8 | # copy of this software and associated documentation files (the "Software"), |
| 9 | # to deal in the Software without restriction, including without limitation |
| 10 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 11 | # and/or sell copies of the Software, and to permit persons to whom the |
| 12 | # Software is furnished to do so, subject to the following conditions: |
| 13 | |
| 14 | # The above copyright notice and this permission notice (including the next |
| 15 | # paragraph) shall be included in all copies or substantial portions of the |
| 16 | # Software. |
| 17 | |
| 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 21 | # ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| 22 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 23 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 24 | |
| 25 | function __call_module |
| 26 | { |
| 27 | local -r this_module="$1" |
| 28 | |
| 29 | [ -n "$this_module" ] || { lets -l -e "module not defined"; return $s_err; } |
| 30 | |
| 31 | if is_opt "upins" "upall"; then |
| 32 | [ ! -d "$instance_d" ] && { |
| 33 | lets -l -e "trying to update an invalid instance" |
| 34 | return $s_err |
| 35 | } |
| 36 | fi |
| 37 | |
| 38 | if is_opt "check" "watch" "upins" "upall" "doins" "doall"; then |
| 39 | local __envtable; local -i ret |
| 40 | |
| 41 | __envtable="$(get_module_dependencies "envtable" $this_module)"; ret=$? |
| 42 | case "$ret" in |
| 43 | $s_ok ) |
| 44 | [ -n "$__envtable" ] && { |
| 45 | |
| 46 | # Export what's inside __envtable and check the actual table is |
| 47 | # imported as a variable. |
| 48 | eval "$__envtable" && declare -p -- "envtable" >/dev/null || { |
| 49 | lets -l -e "failed to export enviroment table" |
| 50 | return $s_err |
| 51 | } |
| 52 | |
| 53 | # envtable is successfully on the stack, throw away its |
| 54 | # textual representation. |
| 55 | unset __envtable |
| 56 | } || { |
| 57 | lets -l -e "failed to get environment table" |
| 58 | return $s_err |
| 59 | } ;; |
| 60 | * ) return $s_err ;; |
| 61 | esac |
| 62 | fi |
| 63 | |
| 64 | if is_opt "check"; then |
| 65 | ( |
| 66 | # Export external variables found |
| 67 | set -eu; eval "${envtable[$this_module]}"; set +eu |
| 68 | |
| 69 | case "${#deps[@]}" in |
| 70 | 0 ) lets -l -i "$this_module doesn't have dependencies" |
| 71 | return $s_ok ;; |
| 72 | * ) lets -l -i "$this_module depends on: ${deps[@]}" |
| 73 | are_in_modules ${deps[@]} || { |
| 74 | lets -l -w "${deps[@]} not in MODULES" |
| 75 | } ;; |
| 76 | esac |
| 77 | |
| 78 | # Check if this module correctly defines its own |
| 79 | # depmod. Return with an error if it doesn't since |
| 80 | # other options rely on this module depmod. |
| 81 | |
| 82 | source "$module_d/$this_module/$module_sh" |
| 83 | if ! declare -p -- "depmod" &>/dev/null; then |
| 84 | lets -l -e "$this_module must define 'depmod'" |
| 85 | return $s_err |
| 86 | fi |
| 87 | |
| 88 | for dep in ${deps[@]}; do |
| 89 | __is_in_array $dep ${depmod[@]} || { |
| 90 | lets -l -e "$dep not in $this_module depmod: ${depmod[@]}" |
| 91 | lets -l -e "add $dep to $this_module depmod" |
| 92 | return $s_err |
| 93 | } |
| 94 | done |
| 95 | ) |
| 96 | return $? |
| 97 | fi |
| 98 | |
| 99 | ( |
| 100 | local -a files=( ) |
| 101 | local callback |
| 102 | |
| 103 | files+=( "$module_d/$this_module/$module_sh" ) |
| 104 | files+=( "$module_d/$this_module/$holder_sh" ) |
Luigi Santivetti | 0fdd470 | 2020-06-22 19:00:32 +0100 | [diff] [blame] | 105 | |
| 106 | if is_opt "doins" "upins" "upall" "doall" "watch"; then |
| 107 | |
Luigi Santivetti | 0b2f48a | 2020-10-25 21:23:27 +0000 | [diff] [blame] | 108 | # Only upmod doesn't need scheme |
| 109 | files+=( "$module_d/$this_module/$scheme_sh" ) |
| 110 | |
Luigi Santivetti | 0fdd470 | 2020-06-22 19:00:32 +0100 | [diff] [blame] | 111 | # Export external references |
| 112 | if test_source <(echo "${envtable[$this_module]}"); then |
| 113 | eval "${envtable[$this_module]}" || return $s_err2 |
| 114 | else |
| 115 | return $s_err2 |
| 116 | fi |
| 117 | fi |
| 118 | |
| 119 | # Source needed files |
| 120 | if test_source "${files[@]}"; then |
| 121 | for f in ${files[@]}; do source "$f" || return $s_err3; done |
| 122 | else |
| 123 | return $s_err3 |
| 124 | fi |
| 125 | |
| 126 | callback="$(declare -F -- "tod_$2" 2>/dev/null)" || return $s_err6 |
| 127 | |
| 128 | if is_opt "doins" "doall"; then |
| 129 | create_instance_d $instance_d || return $s_err4 |
| 130 | fi |
| 131 | |
| 132 | # -- Here be dragons |
| 133 | eval "$callback \"${@:2}\"" || return $s_err5 |
| 134 | ) |
| 135 | case "$?" in |
| 136 | $s_err2 ) lets -l -e "$this_module: failed to export environment" ;; |
| 137 | $s_err3 ) lets -l -e "$this_module: failed to source $f" ;; |
| 138 | $s_err4 ) lets -l -e "$this_module: failed to create instance_d" ;; |
| 139 | $s_err5 ) lets -l -e "$this_module: $callback failed" ;; |
| 140 | $s_err6 ) lets -l -w "$this_module: $callback not available" |
| 141 | return $s_ok ;; |
| 142 | $s_ok ) return $s_ok ;; |
| 143 | esac |
| 144 | |
| 145 | return $s_err |
| 146 | } |
| 147 | |
| 148 | function __option_call |
| 149 | { |
| 150 | local option="$1"; shift |
| 151 | local -a mods=( "${@}" ) |
| 152 | local modname |
| 153 | |
| 154 | is_valid_module "${mods[@]}" |
| 155 | case "$?" in |
| 156 | $s_err | $s_off_broken ) return $s_err ;; |
| 157 | $s_ok | $s_off_usable ) ;; |
| 158 | esac |
| 159 | |
| 160 | # Actually call into module code |
| 161 | for modname in ${OPTARG[@]}; do |
| 162 | __call_module $modname $option |
| 163 | [ $? -eq $s_ok ] || return $s_err |
| 164 | done |
| 165 | } |
| 166 | |
| 167 | function option_call |
| 168 | { |
| 169 | local -a mods |
| 170 | |
| 171 | mods=( $(get_modules_optarg "${@:2}") ) || return $s_err |
| 172 | # Filtered out list of requested modules |
| 173 | OPTARG=( "${mods[@]}" ) |
| 174 | |
| 175 | __option_call "$1" "${mods[@]}" >/dev/null |
| 176 | } |
| 177 | |
| 178 | # @desc : process command line options only two options allowed per invocation |
| 179 | # : at the moment. Keep it simple, keep it robust. For options details |
| 180 | # : see help.sh. |
| 181 | # : |
| 182 | # : credits to https://stackoverflow.com/a/28466267 |
| 183 | function __option_process |
| 184 | { |
| 185 | local opt; OPTIND=1 |
| 186 | |
| 187 | # Be quiet and disallow any single char option |
| 188 | local -r options=":-:" |
| 189 | local -a args |
| 190 | |
| 191 | if getopts "$options" opt; then |
| 192 | if [ "$opt" = "-" ]; then |
| 193 | opt="${OPTARG%%=*}" # Get option name |
| 194 | OPTARG="${OPTARG#$opt}" # Get option argument(s) |
| 195 | OPTARG="${OPTARG#=}" # Drop `=` if any |
| 196 | OPTARG="${OPTARG//,/ }" # Drop `,` if any |
| 197 | |
| 198 | # Early return for help |
| 199 | [ "$opt" = "help" ] && __help && return $s_ok |
| 200 | |
| 201 | is_in_options "$opt" || return $s_err2 |
| 202 | fi |
| 203 | fi |
| 204 | |
| 205 | OPTIONS[$opt]=1; option_call $opt "${OPTARG[@]}" |
| 206 | case "$?" in |
| 207 | $s_err ) lets -l -e "$opt failed"; return $s_err ;; |
| 208 | $s_ok ) lets -l -i --phew "$opt success"; return $s_ok ;; |
| 209 | esac |
| 210 | } |
| 211 | |
| 212 | function option_process |
| 213 | { |
| 214 | __option_process ${@} |
| 215 | case "$?" in |
| 216 | $s_err2 ) lets -l -e "invalid option, --help" ;; |
| 217 | $s_err ) return $s_err ;; |
| 218 | $s_ok ) return $s_ok ;; |
| 219 | esac |
| 220 | } |