improve module base - use stderr for error messages

helpers: added mkrfilename for making random file names instead of using mktemp
         remote_arg function escapes spaces within an arugment(s) for use passing remotely
master
David Kebler 2024-02-21 11:11:07 -08:00
parent 398ae39a07
commit b7b2d7061a
7 changed files with 145 additions and 80 deletions

View File

@ -64,3 +64,7 @@ interactive non-login shells source /etc/profile via /etc/bash.bashrc otherwise
Thus for non-interactive/non-login shells it is best to symlink a non-module file/directory in modules folder in order to give access to non-interactive shells
TODO
* conditionally create a `which` function` in shell.env if which command is not availble. which being pretty much the same as `command -v cmd`

View File

@ -10,15 +10,14 @@ if [ "$FILE" ]; then
COUNT=$(echo $FILE | xargs -n 1 | wc -l)
fi
if [ $COUNT -gt 1 ]; then
echo two or more modules of same name found, aborting
echo $FILE | xargs -n 1
>&2 echo two or more modules of same name found, aborting
>&2 echo $FILE | xargs -n 1
return 1
fi
[ $COUNT == 1 ] && echo $FILE && return 0
return 1
[[ $COUNT == 1 ]] && echo $FILE
}
module_find() {
[ ! $1 ] && echo "no module specified" && return 1
[ ! $1 ] && >&2 echo "no module specified" && return 1
local MDIRS
local MDIR
local DIRS
@ -36,17 +35,21 @@ for ((i=1;i<=cnt;i++)); do
[ $? -eq 0 ] && echo $RES && return 0
fi
done
>&2 echo no module found anywhere
return 1
}
module_load() {
[ ! $1 ] && echo "no module specified" && return 1
local module;local mpath
[ ! $1 ] && >&2 echo "no module specified" && return 1
local FILE
FILE=$(module_find $1)
[ $? -ne 0 ] && echo no module $1 found && return 1
shift 1
source $FILE "$@"
return 0
for module in "$@"
do
eval "_${module}_ () { echo "$fname test"; }"
mpath=$(module_find $module)
[ $? -ne 0 ] && >&2 echo extreme warning: no module $1 found, so was not loaded
source $mpath "$@"
done
}
shell_run () {
bash -ci ". ${1}"

View File

@ -19,20 +19,18 @@ COUNT=0
if [ "$FILE" ]; then
COUNT=$(echo $FILE | xargs -n 1 | wc -l)
fi
# echo Number: $COUNT
if [ $COUNT -gt 1 ]; then
echo two or more modules of same name found, aborting
echo $FILE | xargs -n 1
>&2 echo two or more modules of same name found, aborting
>&2 echo $FILE | xargs -n 1
return 1
fi
[ $COUNT == 1 ] && echo $FILE && return 0
return 1
[[ $COUNT == 1 ]] && echo $FILE
}
# Returns path to module if succesful
module_find() {
[ ! $1 ] && echo "no module specified" && return 1
[ ! $1 ] && >&2 echo "no module specified" && return 1
local MDIRS
local MDIR
@ -65,22 +63,28 @@ for ((i=1;i<=cnt;i++)); do
[ $? -eq 0 ] && echo $RES && return 0
fi
done
# no module found anywhere
>&2 echo no module found anywhere
return 1
}
module_load() {
[ ! $1 ] && echo "no module specified" && return 1
# (return 0 2>/dev/null) && echo "module_load was sourced" || echo "module_log was executed"
local module;local mpath
[ ! $1 ] && >&2 echo "no module specified" && return 1
local FILE
FILE=$(module_find $1)
[ $? -ne 0 ] && echo no module $1 found && return 1
# source $FILE "$0"
# [[ $BASHPID -eq $$ ]] || echo $FILE
shift 1
source $FILE "$@"
return 0
for module in "$@"
do
# is there way to not reload modules??
# if [[ $(eval "echo \"\$MODULE_$module_LOADED\"") ]]; then
# echo $module already loaded
# else
eval "_${module}_ () { echo "$fname test"; }"
mpath=$(module_find $module)
[ $? -ne 0 ] && >&2 echo extreme warning: no module $1 found, so was not loaded
source $mpath "$@"
# eval "MODULE_$module_LOADED=true"
# fi
done
}
# put here so it's globally available

View File

@ -9,64 +9,69 @@
# source <(echo -e "$scpt")
module_load debug
module_load file
module_load helpers
# TODO keep debug statements if requested, other remove them
bundle () {
local file
local code
local compact
if [[ $1 == "-c" ]]; then
module_load helpers
compact=true
shift 1
fi
# todo add -c for compacting the bundle, change this to options parsing.
if [[ "$1" ]]; then
if [[ -f $1 ]]; then
file=$1
else
if [[ $1 == "-m" ]]; then
file=$(module_find $2)
shift 1
else
if [[ $1 == "-mf" ]]; then
module_load $2
code="$(declare -f $3)"
shift 1
else
code="$1"
shift 1
fi
fi
fi
else
echo "aborting, no file, module or function passed for bundling"
return 1
fi
local file; local xfunc; local compact; local func;
debug $( ( IFS=$','; echo bundle arguments: "$*" ) )
declare OPTION; declare OPTARG; declare OPTIND
while getopts 'cf:x:' OPTION; do
case "$OPTION" in
c)
compact=true
;;
f)
# can pass any arguments along with the function to run. Use " " for any argument with spaces
func="$OPTARG"
;;
x)
# will extract a function from a file or module to be used for bundling
xfunc="$OPTARG"
;;
*)
echo unknown bundle option $OPTION
;;
esac
done
shift $(( OPTIND - 1 ))
tmp_file=$( mktemp -t TEMP_FILE_bundle.XXXXXXXX )
chmod 600 "$tmp_file"
# if [[ $2 == "__recurse__" ]] || [[ $file ]]; then
if [[ $file ]]; then
\cp $file $tmp_file
else
echo "$code" > $tmp_file
fi
if [[ -f $1 ]]; then file=$1; else
if ! file=$(module_find "$1"); then >&2 echo fatal: bundle error, no module of name: $1; file=""; fi; fi
[[ ! $file ]] && >&2 echo "fatal: bundle error aborting, no file, module passed for bundling" && return 1
\cp $file $tmp_file
if [[ $xfunc ]]; then
( source $file; declare -f $xfunc > $tmp_file )
fi
if [[ ! $2 == "__recurse__" ]]; then
_modules=""
output=$2
debug outputing bundle to: $output
[[ $output ]] && debug outputing bundle to: $output || debug outputting bundle to console
debug "bash code to bundle \n $(cat $tmp_file)"
fi
modules=$(sed -n -e 's/^\s*module_load //p' < $tmp_file)
# if [[ ( ! $modules ) && ( ! $2 == "__recurse__" ) ]]; then
# if [[ $output ]]; then
# \cp $tmp_file $output
# else
# echo -e "$(cat $tmp_file)"
# fi
# fi
# remove debug module by default so it doesn't get bundled
if [[ $modules ]]; then
# remove found module_load before continuing
# remove all found module_load before continuing
sed -i '/^\s*module_load/d' $tmp_file
[[ $_modules ]] && debug "already bundled modules: $_modules"
for module in $(printf '%s\n' "${modules[@]}"|tac);
@ -86,14 +91,19 @@ bundle () {
# the recursion is done
if [[ ! $2 == "__recurse__" ]]; then
[[ $compact ]] && compact_file $tmp_file
if [[ $BASH_DEBUG ]]; then
[[ $compact ]] && compact_file $tmp_file
# TODO remove debug statements by default
# remove any default function calls
sed -i '/\s*(\s*return 0 2>\/dev\/null\s*)\s*|| /d' $tmp_file
# add in a function call if requested
[[ $func ]] && echo -e "\n $func \"\$@\"" >> $tmp_file
if [[ $BASH_DEBUG ]]; then
debug "\n ------------code as bundled--------------\n \
$(cat $tmp_file) \
\n ------------------------------------------------------------ \n"
debug "bundled modules were $_modules"
fi
if [[ $2 ]]; then
if [[ $output ]]; then
\cp $tmp_file $output
else
echo -e "$(cat $tmp_file)"
@ -105,3 +115,5 @@ bundle () {
# # if script was executed then call the function
(return 0 2>/dev/null) || bundle $@

View File

@ -1,5 +1,6 @@
#!/bin/bash
# TODO allow debug to have managment flags and levels
# TODO filter debug statements to a particular module
function debug () {
if [[ $BASH_DEBUG ]]; then

View File

@ -61,25 +61,50 @@ parse_option () {
# otherwise just the options value
local opts;local f;local opt; local ret
[[ $1 = "-f" ]] && { f=true;shift 1; }
[[ $1 && $2 ]] || return 1
[[ ! $# -eq 2 ]] && return 1
opts=$1
opt=$2
[[ ! $opts =~ "$opt" ]] && return 1
ret=$(sed -n "/^.*$opt\s\+\(\w\+\).*$/s//\1/p" <<< $opts)
# echo $opts, $opt
[[ ! $opts =~ $opt ]] && return 1
ret=$(sed -n '/^.*'"$opt"'\s\+\(\w\+\).*$/s//\1/p' <<< $opts)
[[ $f ]] && echo "$2 $ret" || echo $ret
}
# TODO: need to pass two arrays and then pass them back, see -r ret in ssh for example
# parse_extra_args () {
# if [[ ! $* =~ "--" ]]; then
# debug $( ( IFS=$','; echo all arguments: "$*" ) )
# for ((d=1; d<$#; ++d)); do
# [[ ${!d} == "--" ]] && break
# done
# if [[ $d -lt $# ]]; then # if there are extra ssh arguments
# debug found -- at $d
# opts=("${@:$d+1:$#}")
# debug $( ( IFS=$','; echo "ssh arguments: ${opts[*]}" ) )
# # [[ ! ${sshargs[0]} ]] && { echo missing remote machine, must provide at least a hostname, -- hostname; return 3; }
# ropts=("${@:1:$d-1}")
# debug $( ( IFS=$','; echo "remaining arguments to parse: ${ropts[*]}" ) )
# fi
# fi
# }
remove_empty_lines () {
if [[ -f $1 ]]; then cat $1; else echo "$1"; fi | sed -n '/^\s*$/!p'
# sed -rz 's/^\n+//; s/\n+$/\n/g'
}
remote_args () {
local rargs
for i; do rargs="$rargs $(sed 's/ /\\ /g' <<< $i)"; done
echo $rargs
}
remove_end_spaces () {
del=${2:-\'}
# echo delimiter: $del
# sed -e "s/[[:space:]]\{1,\}$del/$del/" <<< "$1"
res=$(sed -e "s/^$del[[:space:]]*/$del/" <<< "$1")
sed -e "s/[[:space:]]*${del}$/$del/" <<< "$res"
# sed -e 's/[[:space:]]\{1,\}$del/$del/' <<< "$1"
res=$(sed -e 's/^$del[[:space:]]*/$del/' <<< "$1")
sed -e 's/[[:space:]]*${del}$/$del/' <<< "$res"
}
# pass any sed ' ' string and comments lines will be ignored
@ -102,8 +127,24 @@ compact_file () {
# if [[ -f "$1" ]]; then cat "$1"; else echo -e "$@"; fi | sed 's/\\s*$//g' | sed -r '/^\s*$/d' | grep -v '^\s*#'
}
mkrfilename () {
echo ${2:-/tmp/}${1:-file}.$RANDOM
}
sshtest () {
echo running on machine: $(hostnamectl hostname)
echo as user:home $(whoami):$HOME
echo argument1 $1
echo argument2 $2
echo remaining arguments: "${@:3}"
echo home directory listing
ls -la ~
}
#rows between matched rows
# sed '1,/firstmatch/d;/secondmatch/,$d'
# this will escape ' for all lines having sed
# sed -i '/sed/s/\x27/\\'"'"'/g' $tmp_file

View File

@ -1,6 +1,6 @@
#!/bin/bash
iecho () {
[[ ! -z "$PS1" ]] && echo $1
[[ ! -z "$PS1" ]] && echo "$@"
return 0
}