add some code..
This whole repository is a place to put this "file" as it breaks up more and more into pieces that might get generated, edited after they are generated, and so on hard-to-manage situation. The repository does not sort out the mess -the software project has this as a feature- the repository is a "backup", and also will proves out functionality related to integrating git as well as other methods of keeping track of versions of things, experimentally already in progress
This commit is contained in:
parent
69a54a8e9f
commit
961a3ecec2
1 changed files with 713 additions and 0 deletions
713
ghostwheel.fn.sh
Executable file
713
ghostwheel.fn.sh
Executable file
|
|
@ -0,0 +1,713 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
# C4 functions for the ghostwheel @@&<_f @@
|
||||||
|
# Copyright (C)2026 Corwin Brust <corwin@brust>
|
||||||
|
# GPLv3+: The program is Free Software
|
||||||
|
#
|
||||||
|
# This is a bootstrapping file, used in RC et. al.
|
||||||
|
# - Do not depend on functions not defined herein
|
||||||
|
# - Obey existing values when settings variables
|
||||||
|
# - Ensure critical variables are initialized
|
||||||
|
# - Emit warnings about problems; no dying
|
||||||
|
#
|
||||||
|
|
||||||
|
####
|
||||||
|
## Tests - forensenices and disaster avoidance
|
||||||
|
## Each test has a name is assicated with a run-level and set
|
||||||
|
## allowing us several ways to conveniently check that required
|
||||||
|
## functionality is without detectated error condition.
|
||||||
|
|
||||||
|
## NOTE:
|
||||||
|
## Test scaffolding must come *before* everything (e.g. utility
|
||||||
|
## functions), reenforsing the need to separately implement tests.
|
||||||
|
|
||||||
|
# (delete variable) unset run level indicates startup hasn't finished
|
||||||
|
declare -p C4_RUN >/dev/null 2>&1 && unset C4_RUN;
|
||||||
|
|
||||||
|
# (overwrite register integer) C4_T - assoicative array TAG => TAGS
|
||||||
|
declare -p C4_T >/dev/null 2>&1 && unset C4_T;
|
||||||
|
declare -A C4_T=([0]= )
|
||||||
|
|
||||||
|
# (overwrite register integer) C4_LASTRUN - prior run-level, if any
|
||||||
|
declare -p CR_LASTRUN >/dev/null 2>&1 && unset C4_LASTRUN;
|
||||||
|
declare -i CR_LASTRUN=${CR_RUN--1};
|
||||||
|
|
||||||
|
# (delayed overwrite register) system runlevel
|
||||||
|
# 0..boostraping
|
||||||
|
# 1..containers
|
||||||
|
# 2..components
|
||||||
|
# 3..configurations
|
||||||
|
# 4..connections
|
||||||
|
# 5..running
|
||||||
|
declare -p C4_RUN >/dev/null 2>&1 && unset C4_RUN;
|
||||||
|
|
||||||
|
# (overwrite register) test register
|
||||||
|
declare C4_TR='T'
|
||||||
|
|
||||||
|
# (overwrite register integer) total count of tests
|
||||||
|
declare -i C4_TN=-1; # test function will be patient zero
|
||||||
|
|
||||||
|
# (required) honor customization of OK/FAIL labels
|
||||||
|
C4_T_OKAY="${C4_T_OKAY-OKAY}"
|
||||||
|
C4_T_FAIL="${C4_T_FAIL-FAIL}"
|
||||||
|
|
||||||
|
####
|
||||||
|
#Lab: this ugly beast merges bash associate arrays
|
||||||
|
# (c=(`unset a b c; \
|
||||||
|
# declare -A a=([b]="bb" [c]="cc"); \
|
||||||
|
# declare -A b=([d]="dd"); declare -p a b | \
|
||||||
|
# perl -e '@a= map { chomp; s/^.*=\(|\)$//g; $_ } <>; print qq(@a)' \
|
||||||
|
# `); declare -p c)
|
||||||
|
# declare -A c=(["[c]=\"cc\" [b]=\"bb\" [d]=\"dd\" "]="" )
|
||||||
|
####
|
||||||
|
|
||||||
|
#### c4.maa -
|
||||||
|
### join valueset assignments of bash assoicative arrays
|
||||||
|
### (unset a b c; \
|
||||||
|
### declare -A a=([b]="bb" [c]="cc"); \
|
||||||
|
### declare -A b=([d]="dd");\
|
||||||
|
### echo $( c4.maa a b ) )
|
||||||
|
function c4.maa {
|
||||||
|
# avoid warning from declare -p when no arguments are given
|
||||||
|
test "$*" && \
|
||||||
|
declare -p $@ \
|
||||||
|
| perl -e ' # combine assignments:
|
||||||
|
$\=q( ); # 1. join ouput on space
|
||||||
|
print map { # 6. output the line
|
||||||
|
chomp; # 3. rm -f newline
|
||||||
|
s/^.*=\(|\)$//g; # 4. extract assignments
|
||||||
|
$_ # 5. use value (not replacment count)
|
||||||
|
} <>' # 2. walk input from declare -p
|
||||||
|
} #### -END c4.maa
|
||||||
|
|
||||||
|
function c4.t.b {
|
||||||
|
C4_TN=$((++C4_TN))
|
||||||
|
|
||||||
|
local -A ta=(
|
||||||
|
[tn]=$C4_TN
|
||||||
|
[okrv]=0 [okay]="$C4_T_OKAY" [fail]="$C4_T_FAIL"
|
||||||
|
[tags]="$1" [runl]="$2" [name]="$3" [desc]="$4"
|
||||||
|
); shift; shift; shift; shift;
|
||||||
|
|
||||||
|
# pick the first non-empty tag as a prefix
|
||||||
|
for t in ${ta[tags]} ; do
|
||||||
|
if test -n "$t" ; then
|
||||||
|
ta[ftag]="$t";
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# make test function name
|
||||||
|
ta[fname]="$( printf 'C4%s_%s_%s' "$C4_TR" "${ta[ftag]^^}" "${ta[name]^^}" )"
|
||||||
|
|
||||||
|
# add test to full and by- run-level lists
|
||||||
|
C4_T["${ta[runl]}"]+="${ta[fname]}"
|
||||||
|
for v in ${ta[tags]} ; do
|
||||||
|
C4_T["$v"]+="${ta[fname]}";
|
||||||
|
done
|
||||||
|
C4_T["${ta[fname]}"]=
|
||||||
|
|
||||||
|
source /dev/stdin <<EOF
|
||||||
|
function ${ta[fname]}()
|
||||||
|
{
|
||||||
|
$( declare -p ta )
|
||||||
|
local debug=\${ta[debug]:-\$C4_DEBUG}
|
||||||
|
|
||||||
|
$@ >/dev/null 2>&1
|
||||||
|
local rv="\$?"
|
||||||
|
C4_T[${ta[fname]}]=\$rv
|
||||||
|
|
||||||
|
if test \${ta[okrv]} -eq "\$rv" ; then
|
||||||
|
if test -n "\$debug" ; then
|
||||||
|
printf '%s%d %03d %-17s .. %s : %s'"\\n" \\
|
||||||
|
"\${ta[ftag]^^}" \${ta[runl]} \${ta[tn]} \\
|
||||||
|
"\${ta[name]}" "\${ta[okay]}" "\${ta[desc]}" >&2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf '%s%d %03d %-17s .. %s : %s'"\\n" \\
|
||||||
|
"\${ta[ftag]^^}" \${ta[runl]} \${ta[tn]} \\
|
||||||
|
"\${ta[name]}" "\${ta[fail]}" "\${ta[desc]}" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
return \$rv;
|
||||||
|
};#$( test ${C4_RUN-0} -ge "${ta[runl]}" && printf "\n%s\n" "${ta[fname]}" )
|
||||||
|
EOF
|
||||||
|
|
||||||
|
}
|
||||||
|
# args and generated, not customizable
|
||||||
|
c4.t.b "t" 0 "tbuild" \
|
||||||
|
"args+gen'ed not custom" \
|
||||||
|
test 0 -eq '"${ta[tn]}"' \
|
||||||
|
-a 0 -eq '"${ta[runl]}"' \
|
||||||
|
-a '"${ta[ftag]}"' == '"t"' \
|
||||||
|
-a '"${ta[name]}"' == '"tbuild"' \
|
||||||
|
-a '"${ta[fname]}"' == '"C4T_T_TBUILD"' \
|
||||||
|
-a '"${ta[desc]}"' == '"args+gen'"'"'ed not custom"'
|
||||||
|
|
||||||
|
#echo "RV:${C4_TN[C4T_T_B]}"
|
||||||
|
#c4.t.b "t" 0 "false" "negitive" export fail=\"'OKAY'\" \; false
|
||||||
|
#C4T_T_FALSE
|
||||||
|
|
||||||
|
## END Tests
|
||||||
|
####
|
||||||
|
|
||||||
|
## settings
|
||||||
|
|
||||||
|
declare C4_DEBUG #=${C4_DEBUG:-1}
|
||||||
|
|
||||||
|
# honor override of system primiary
|
||||||
|
C4_SG=${C4_SG-gw14}
|
||||||
|
|
||||||
|
# honor override of mount name
|
||||||
|
C4_SI=${C4_SI-storage}
|
||||||
|
|
||||||
|
C4_SPOKES=${C4_SPOKES-/spokes}
|
||||||
|
|
||||||
|
C4_SYSID=${Cr_SYSID-c4}
|
||||||
|
|
||||||
|
# honor override of c4 root
|
||||||
|
C4_ROOT=${C4_ROOT-"$C4_SPOKES/$C4_SG/$C4_SI/$C4_SYSID"}
|
||||||
|
|
||||||
|
# honor primary semaphore overrides
|
||||||
|
C4_AS=${C4_AS-$C4_ROOT/a} # asset
|
||||||
|
C4_CS=${C4_CS-$C4_ROOT/c} # command
|
||||||
|
C4_DS=${C4_DS-$C4_ROOT/d} # document
|
||||||
|
C4_ES=${C4_ES-$C4_ROOT/e} # environment
|
||||||
|
C4_FS=${C4_FS-$C4_ROOT/f} # feature
|
||||||
|
C4_GS=${C4_GS-$C4_ROOT/g} # graph
|
||||||
|
C4_HS=${C4_HS-$C4_ROOT/h} # heap
|
||||||
|
C4_IS=${C4_IS-$C4_ROOT/i} # identity
|
||||||
|
C4_JS=${C4_JS-$C4_ROOT/j} # job
|
||||||
|
C4_LS=${C4_LS-$C4_ROOT/l} # link
|
||||||
|
C4_MS=${C4_MS-$C4_ROOT/m} # mapping
|
||||||
|
C4_OS=${C4_OS-$C4_ROOT/o} # object
|
||||||
|
C4_PS=${C4_PS-$C4_ROOT/p} # package
|
||||||
|
C4_RS=${C4_RS-$C4_ROOT/r} # register
|
||||||
|
C4_SS=${C4_SS-$C4_ROOT/s} # subscription
|
||||||
|
C4_TS=${C4_TS-$C4_ROOT/t} # taxonomy
|
||||||
|
C4_WS=${C4_WS-$C4_ROOT/w} # workspace
|
||||||
|
|
||||||
|
# honor override of hostname
|
||||||
|
C4_GW=${C4_GW-$(hostname -s)}
|
||||||
|
|
||||||
|
# honor override of gateway number
|
||||||
|
C4_GN=${C4_GN:-"$(printf '%s' "$C4_GW" | tr -d '[[:alpha:]]')"}
|
||||||
|
|
||||||
|
# honor override of identity domain
|
||||||
|
C4_ID=${C4_ID:-bru.st}
|
||||||
|
|
||||||
|
# hard code a list of vars into the "not empty" test
|
||||||
|
for v in "C4_ID" "C4_ROOT" "C4_AS" "C4_GW"; do
|
||||||
|
c4.t.b "v" 0 "$v" "non-empty" test -n '"$'"$v"'"'
|
||||||
|
done
|
||||||
|
c4.t.b "v" 0 "C4_GN" "positive integer" test 0 -lt '"$C4_GN"'
|
||||||
|
c4.t.b "v" 0 "C4_ID" "DNS suffex non-empty" test -n '"$C4_GN"'
|
||||||
|
|
||||||
|
C4_RUN=0 # only run tests which can indicate startup issues
|
||||||
|
|
||||||
|
## Notes:
|
||||||
|
# More library functions we need:
|
||||||
|
# [ ] TODO logging functions (formatting + update registers)
|
||||||
|
# [ ] TODO option to always print tests output
|
||||||
|
|
||||||
|
####
|
||||||
|
## LIBRARY
|
||||||
|
|
||||||
|
### UTILITY
|
||||||
|
|
||||||
|
## print the first non empty input
|
||||||
|
function c4.s.first {
|
||||||
|
for _s_first_i in "$@" ; do
|
||||||
|
if test -n "$_s_first_i" ; then
|
||||||
|
printf '%s' "$_s_first_i"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
c4.t.b "s" 0 "first" "[ x z] == z" test "x" == '$( c4.s.first "" "$foo" "x" "z" )'
|
||||||
|
|
||||||
|
## Return first non-empty item matching PATTERN from SET
|
||||||
|
## when NEGATE is ! or NOT return first non-empty, non-
|
||||||
|
## matching item.
|
||||||
|
function c4.s.firstmatch {
|
||||||
|
_s_firstmatch_ng=
|
||||||
|
_s_firstmatch_an=
|
||||||
|
if [[ "$1" =~ "!" ]] || [[ "${1^^}" =~ "NOT" ]] ; then
|
||||||
|
_s_firstmatch_ng=1; shift
|
||||||
|
fi
|
||||||
|
if [[ "$1" =~ "^" ]] ; then
|
||||||
|
_s_firstmatch_an="C4C4C4C4"; shift
|
||||||
|
fi
|
||||||
|
_s_firstmatch_re=$1 ; shift;
|
||||||
|
|
||||||
|
for _s_firstmatch_i in "$@" ; do
|
||||||
|
if [[ "$_s_firstmatch_an$_s_firstmatch_i" \
|
||||||
|
=~ "$_s_firstmatch_an$_s_firstmatch_re" ]] ; then
|
||||||
|
if test -z "$_s_firstmatch_ng" -a \
|
||||||
|
-n "$_s_firstmatch_i"; then
|
||||||
|
# non-negatated match!
|
||||||
|
printf '%s' "$_s_firstmatch_i"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
elif test -n "$_s_firstmatch_ng" -a \
|
||||||
|
-n "$_s_firstmatch_i"; then
|
||||||
|
# negigated miss!
|
||||||
|
printf '%s' "$_s_firstmatch_i"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
c4.t.b "s" 0 "firstmatch" "[x o x] == x" test "x" == '"$( c4.s.firstmatch "x" "o" "x" )"'
|
||||||
|
c4.t.b "s" 0 "firstmatch" "[!x o x] == o" test "o" == '"$( c4.s.firstmatch "!" "x" "" "x" "o" )"'
|
||||||
|
|
||||||
|
## give a friendly "did it work?" report
|
||||||
|
## TODO supress ANSI color-codes when STDOUT isn't a TTY
|
||||||
|
_c4_updn_ng=1 # when set, empty $up value is a failure
|
||||||
|
|
||||||
|
_c4_updn_bl="DOWN ERROR FAILED" # bad word list
|
||||||
|
_c4_updn_gl="UP OK" # good word list
|
||||||
|
|
||||||
|
_c4_updn_b="DOWN" # failure output label
|
||||||
|
_c4_updn_g="UP" # success output label
|
||||||
|
|
||||||
|
_c4_updn_nc="36" # name output color
|
||||||
|
_c4_updn_bc="33" # failure output color
|
||||||
|
_c4_updn_gc="32" # success output color
|
||||||
|
|
||||||
|
function c4.updn {
|
||||||
|
local C4_UPDN_NG="${C4_UPDN_NG:-$_c4_updn_ng}"
|
||||||
|
|
||||||
|
local C4_UPDN_BL="${C4_UPDN_BL:-$_c4_updn_bl}"
|
||||||
|
local C4_UPDN_GL="${C4_UPDN_GL:-$_c4_updn_gl}"
|
||||||
|
|
||||||
|
local C4_UPDN_B="${C4_UPDN_B:-$_c4_updn_b}"
|
||||||
|
local C4_UPDN_G="${C4_UPDN_G:-$_c4_updn_g}"
|
||||||
|
|
||||||
|
local C4_UPDN_NC="${C4_UPDN_NC-$_c4_updn_nc}"
|
||||||
|
local C4_UPDN_BC="${C4_UPDN_BC-$_c4_updn_bc}"
|
||||||
|
local C4_UPDN_GC="${C4_UPDN_GC-$_c4_updn_gc}"
|
||||||
|
|
||||||
|
local what=$1
|
||||||
|
local up=$2
|
||||||
|
local msg=$3
|
||||||
|
local _c4_updn_up=
|
||||||
|
local _c4_updn_dw=
|
||||||
|
|
||||||
|
if test -n "$up" ; then
|
||||||
|
for _c4_updn_i in $C4_UPDN_BL ; do
|
||||||
|
if [[ "$up" =~ "$_c4_updn_i" ]] ; then
|
||||||
|
_c4_updn_dw=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -z "$_c4_updn_dw" ; then
|
||||||
|
for _c4_updn_i in $C4_UPDN_GL ; do
|
||||||
|
if [[ "$up" =~ "$_c4_updn_i" ]] ; then
|
||||||
|
_c4_updn_up=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -z "$_c4_updn_up$C4_UPDN_NG" ; then
|
||||||
|
_c4_updn_dw=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif test -n "$_c4_updn_ng" ; then
|
||||||
|
_c4_updn_dw=1
|
||||||
|
fi
|
||||||
|
if test -z "$_c4_updn_dw" ; then
|
||||||
|
up="$C4_UPDN_G"
|
||||||
|
color="$C4_UPDN_GC"
|
||||||
|
else
|
||||||
|
up="$C4_UPDN_B"
|
||||||
|
color="$C4_UPDN_BC"
|
||||||
|
fi
|
||||||
|
if test -n "$msg" ; then
|
||||||
|
msg=" $msg"
|
||||||
|
fi
|
||||||
|
echo -e "Load \e[1;${C4_UPDN_NC}m${what}\e[0m [\e[1;${color}m${up}\e[0m]$msg"
|
||||||
|
}
|
||||||
|
#for n in $( seq 0 64 ) ; do (C4_UPDN_GC="$n";c4.updn "foo" "UP" "$n"); done
|
||||||
|
#echo_updown "foo" "up" "bar" #[[OK][[1;36mfoo[0m [[1;32mUP[0m] bar]]
|
||||||
|
|
||||||
|
### SYSUTIL
|
||||||
|
|
||||||
|
## print hostname if current (or given) file is on a spoke
|
||||||
|
function c4.s.host {
|
||||||
|
_s_host="$1";
|
||||||
|
if test -z "$_s_host" ; then
|
||||||
|
_s_host="$0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_on_spoke=
|
||||||
|
until test -n "$_on_spoke" \
|
||||||
|
-o -z "$_s_host" \
|
||||||
|
-o '.' == "$_s_host" \
|
||||||
|
-o '/' == "$_s_host" ;
|
||||||
|
do
|
||||||
|
if test -d "$_s_host" -a -r "$_s_host/.spoke" ; then
|
||||||
|
_on_spoke=1
|
||||||
|
fi
|
||||||
|
_s_host="$(dirname "$_s_host")"
|
||||||
|
done
|
||||||
|
test -n "$_s_host" && printf '%s' "$(basename "$_s_host")"
|
||||||
|
}
|
||||||
|
c4.t.b "s" 0 \
|
||||||
|
"host" "\$0 == gw14" test \
|
||||||
|
'"$( c4.s.host /spokes/gw14/storage/c4/ghostwheel.fn.sh )"' == '"gw14"'
|
||||||
|
|
||||||
|
## c4.fqn [ GW [ DOMAIN ]]
|
||||||
|
## Output the fully qualfied hostname
|
||||||
|
## Integration Tests:
|
||||||
|
## @@tf: "@@C4_GW@@.@@C4_IS@@" == "$( hostname -f )" @@
|
||||||
|
## @@ta: "@@C4_GW@@.@@C4_IS@@" == "@@].[[C4][GW ID]]@@" @@
|
||||||
|
function c4.fqn {
|
||||||
|
if test -n "$2" || test -n "$C4_ID" ; then
|
||||||
|
if test -n "$1" || test -n "$C4_GW" ; then
|
||||||
|
printf '%s.%s' "${1:-$C4_GW}" "${2:-$C4_ID}"
|
||||||
|
else
|
||||||
|
printf '%s.%s' "$(hostname -s)" "${2:-$C4_ID}"
|
||||||
|
fi
|
||||||
|
elif test -n "$1" || test -n "$C4_GW" ; then
|
||||||
|
printf '%s.%s' "${1:-$C4_GW}"
|
||||||
|
else
|
||||||
|
printf '%s' "$(hostname -f)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
## Unit Tests:
|
||||||
|
c4.t.b "s" 0 "fqn" \
|
||||||
|
"\$0 == gw14" test \
|
||||||
|
'"$( c4.fqn foo bar )"' == 'foo.bar'
|
||||||
|
c4.t.b "s" 0 "fqn_hostname" \
|
||||||
|
"C4.fqn == \`hostname -f\`" test \
|
||||||
|
'"$( c4.fqn )"' == '"$(hostname -f)"'
|
||||||
|
# FIXME: fqn seems badly broken
|
||||||
|
# c4.t.b "s" 0 "fqn_hostname" \
|
||||||
|
# "C4.fqn == \`hostname -f\`" test \
|
||||||
|
# '"$( c4.fqn )"' == '"$(hostname -s)$C4_GW"'
|
||||||
|
#### END c4.fqn
|
||||||
|
|
||||||
|
# return zero if given HOST is the localhost
|
||||||
|
function c4.gw_is_localhost {
|
||||||
|
if test -z "$1" ; then
|
||||||
|
return 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
local _c4_hi=$1; shift;
|
||||||
|
local _c4_hs=
|
||||||
|
|
||||||
|
if echo "$_c4_hi" | grep \. 1>/dev/null ; then
|
||||||
|
# TODO: could be smarter, given e.g. x.gw10.foo and is10 are gw10
|
||||||
|
_c4_hs="$( echo "$_c4_hi" | cut -d '.' -f 1 )"
|
||||||
|
else
|
||||||
|
_c4_hs="$_c4_hin";
|
||||||
|
fi
|
||||||
|
if test "$C4_GW" == "$_c4_hs" ; then
|
||||||
|
return 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
# c4.t.b "s" 0 \
|
||||||
|
# "host" "\$0 == gw14" test \
|
||||||
|
# '' == ''
|
||||||
|
c4.t.b "s" 0 "gw_is_localhost_f" "== hostname -f" test "0" == '"$(c4.gw_is_localhost `hostname -f`; echo "$?")"'
|
||||||
|
c4.t.b "s" 0 "gw_is_localhost" "== hostname -s" test "0" == '"$(c4.gw_is_localhost `hostname -s`; echo "$?")"'
|
||||||
|
c4.t.b "s" 0 "name" "!= moo" test "1" == '"$(c4.gw_is_localhost "moo"; echo "$?")"'
|
||||||
|
|
||||||
|
## check validity/availability of a node
|
||||||
|
_c4_is_gn=
|
||||||
|
function c4.i.is_gn {
|
||||||
|
seq "$(<.min)" "$(<.max)" | grep -v "$( perl -le 'printf q{\(%s\)}, join q{\|}, map {chomp;$_} <>' <.skip )" | grep "$(hostname -s | tr -d '[[:alpha:]]')" >/dev/null 2>&1 && echo OK
|
||||||
|
}
|
||||||
|
|
||||||
|
## Create a shell script by reading STDIN
|
||||||
|
_c4_mksh_infh=/dev/stdin # read from STDIN by default
|
||||||
|
_c4_mksh_otfh=/dev/stdout # write to STDOUT by default
|
||||||
|
_c4_mksh_bash=/usr/bin/bash # script for bash by default
|
||||||
|
function c4.mksh {
|
||||||
|
local C4_MKSH_INFH="$(c4.s.first "$C4_MKSH_INFH" "$_c4_mksh_infh" /dev/stdin)"
|
||||||
|
local C4_MKSH_OTFH="$(c4.s.first "$1" "$C4_MKSH_OTFH" "$_c4_mksh_otfh" /dev/stdout)"
|
||||||
|
local C4_MKSH_BASH="$(c4.s.first "$2" "$C4_MKSH_BASH" "$_c4_mksh_bash" /usr/bin/bash)"
|
||||||
|
|
||||||
|
printf '#!%s'"\n" "$C4_MKSH_BASH" >$C4_MKSH_OTFH
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
echo "$line" >> $C4_MKSH_OTFH
|
||||||
|
done <$C4_MKSH_INFH
|
||||||
|
|
||||||
|
# set the executable bit when making a regular file
|
||||||
|
test -f $C4_MKSH_OTFH && chmod a+x $C4_MKSH_OTFH
|
||||||
|
}
|
||||||
|
|
||||||
|
# run command on rhost via ssh when not on rhost
|
||||||
|
_c4_ssh_debug="$(c4.s.first "$_C4_SSH_DEBUG" "$C4_DEBUG")"
|
||||||
|
_C4_SSH="${_C4_SSH:-ssh}"
|
||||||
|
function c4.ssh {
|
||||||
|
local host="$1"; shift;
|
||||||
|
if c4.gw_is_localhost "$host" ; then # run locally
|
||||||
|
if test -z "$_c4_ssh_debug" ; then
|
||||||
|
$@
|
||||||
|
else
|
||||||
|
echo "$@"
|
||||||
|
fi
|
||||||
|
else # use ssh
|
||||||
|
local sshcmd="$( printf '%s %s' \
|
||||||
|
"$(c4.s.first $C4_SSH $_C4_SSH "ssh")" \
|
||||||
|
"$(c4.fqn "$host" )" \
|
||||||
|
)";
|
||||||
|
if test -z "$_c4_ssh_debug" ; then
|
||||||
|
$sshcmd $@
|
||||||
|
else
|
||||||
|
echo "$sshcmd $@"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
#local rhost="$( c4.gw_is_localhost "$1" && echo $1 )"
|
||||||
|
}
|
||||||
|
|
||||||
|
# run command on rhost via ssh when not on rhost
|
||||||
|
_c4_ssh_debug="$(c4.s.first "$_C4_SSH_DEBUG" "$C4_DEBUG")"
|
||||||
|
_C4_SSH="${_C4_SSH:-ssh}"
|
||||||
|
function c4.ssh2 {
|
||||||
|
if test -z "$1" ; then
|
||||||
|
echo "WF:C4.ssh empty or mssing hostname" 1>&2
|
||||||
|
return 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
_c4_ssh_hi=$1; shift;
|
||||||
|
_c4_ssh_ho=
|
||||||
|
_c4_ssh_hs=
|
||||||
|
_c4_ssh_hc=
|
||||||
|
|
||||||
|
# ensure we have both long and short name
|
||||||
|
if echo "$_c4_ssh_hi" | grep \. 1>/dev/null ; then
|
||||||
|
# TODO: could be smarter, given e.g. x.gw10.foo and is10 are gw10
|
||||||
|
_c4_ssh_hs="$( echo "$_c4_ssh_hi" | cut -d '.' -f 1 )"
|
||||||
|
_c4_ssh_ho="$_c4_ssh_hi";
|
||||||
|
else
|
||||||
|
_c4_hs="$_c4_ssh_hin";
|
||||||
|
_c4_ho="$( c4.fqn $_c4_hs )";
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$C4_GW" != "$_c4_ssh_hs" ; then
|
||||||
|
_c4_ssh_hc="$(printf '%s %s ' "$_C4_SSH" "$_c4_ssh_ho")";
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$_c4_ssh_debug" ; then
|
||||||
|
$_c4_ssh_hc"$@"
|
||||||
|
else
|
||||||
|
#echo "$_c4_ssh_hc"'"'"$@"'"'
|
||||||
|
local pre=
|
||||||
|
local post=
|
||||||
|
if test -n "$_c4_ssh_hc" ; then
|
||||||
|
pre="'"
|
||||||
|
post="'"
|
||||||
|
fi
|
||||||
|
echo "$_c4_ssh_hc$pre$@$post"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## run mkdir locally if the given spoke is up, otherwise use SSH
|
||||||
|
_c4_mkdir_debug="$(c4.s.first "$_C4_MKDIR_DEBUG" "$C4_DEBUG")"
|
||||||
|
function c4.mkdir {
|
||||||
|
_c4_mkdir_islocal="$(
|
||||||
|
c4.s.host "$(
|
||||||
|
c4.s.firstmatch ! - "$@"
|
||||||
|
)"
|
||||||
|
)"
|
||||||
|
if test -n "$_c4_mkdir_islocal" ; then
|
||||||
|
if test -z "$_c4_mkdir_debug" ; then
|
||||||
|
mkdir $@
|
||||||
|
else
|
||||||
|
echo mkdir $@
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
c4.ssh mkdir $@
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
##
|
||||||
|
_c4_rsync_debug="$(c4.s.first "$_C4_RSYNC_DEBUG" "$C4_DEBUG")"
|
||||||
|
function c4.rsync {
|
||||||
|
local m== "$( c4.s.firstmatch ":" "$@" )";
|
||||||
|
if test -n "$m" ; then
|
||||||
|
m="$(echo "$m" | cut -d ':' -f 1)"
|
||||||
|
else
|
||||||
|
m="$(c4.s.host "$( c4.s.firstmatch ! ^ - "$@" )")"
|
||||||
|
fi
|
||||||
|
if test -n "$m" && c4.gw_is_localhost "$m"; then
|
||||||
|
if test -z "$_c4_rsync_debug" ; then
|
||||||
|
echo TROUBLE mkdir $@
|
||||||
|
else
|
||||||
|
echo mkdir $@
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
c4.ssh mkdir $@
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# run command on rhost via ssh when not on rhost
|
||||||
|
_c4_cmd_debug="$(c4.s.first "$_C4_CMD_DEBUG" "$C4_DEBUG")"
|
||||||
|
# function c4.cmd {
|
||||||
|
# _c4_mkdir_islocal="$(
|
||||||
|
# c4.s.host "$(
|
||||||
|
# c4.s.firstmatch ! - "$@"
|
||||||
|
# )"
|
||||||
|
# )"
|
||||||
|
# if test -n "$_c4_mkdir_islocal" ; then
|
||||||
|
# if test -z "$_c4_rsync_debug" ; then
|
||||||
|
# $_c4__cmdpre $@
|
||||||
|
# else
|
||||||
|
# echo $_c4__cmdpre $@
|
||||||
|
# fi
|
||||||
|
#}
|
||||||
|
|
||||||
|
# run rsync on rhost via ssh when not on rhost
|
||||||
|
# function c4.rsync {
|
||||||
|
# if test -z "$_c4_rsync_debug" ; then
|
||||||
|
# $_c4_rsync_ssh $@
|
||||||
|
# else
|
||||||
|
# echo $_c4_rsync_ssh $@
|
||||||
|
# fi
|
||||||
|
# }
|
||||||
|
|
||||||
|
### IDENTITY
|
||||||
|
### - bootstrapping
|
||||||
|
C4_TR='I'
|
||||||
|
#c4.t.b
|
||||||
|
|
||||||
|
#seq $( c4.i.val $(c4.i.of gn min) ) $( c4.i.val $(c4.i.of gn max) )
|
||||||
|
|
||||||
|
C4_I_GN_MIN=
|
||||||
|
function c4.i.gn_min () {
|
||||||
|
if test -n "$1" -o -z "$C4_I_GN_MIN"; then
|
||||||
|
C4_I_GN_MIN=$( c4.i.val $(c4.i.of gn min) )
|
||||||
|
fi
|
||||||
|
printf '%d' $C4_I_GN_MIN
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_I_GN_MAX=
|
||||||
|
function c4.i.gn_max () {
|
||||||
|
if test -n "$1" -o -z "$C4_I_GN_MAX"; then
|
||||||
|
C4_I_GN_MAX=$( c4.i.val $(c4.i.of gn max) )
|
||||||
|
fi
|
||||||
|
printf '%d' $C4_I_GN_MAX
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function c4.i.gn_skip {
|
||||||
|
local gn=$1;
|
||||||
|
|
||||||
|
#if test -z "$gn" -o ! "$gn" -gt "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
## return first identifier from source
|
||||||
|
## where SOURCE is a readable file
|
||||||
|
function c4.i.val {
|
||||||
|
|
||||||
|
local src #="$(case $# in 1) $1 ;; *) $( c4.i.of $@ ) ;; esac) 1)"; shift;
|
||||||
|
case $# in
|
||||||
|
1) src=$1 ;;
|
||||||
|
*) src=$( c4.i.of $@ ) ;;
|
||||||
|
esac
|
||||||
|
if test ! -r "$src" ; then
|
||||||
|
# || test 0 == "$(file "$src" | grep text >2 2>&1; echo $?)"
|
||||||
|
echo "WARN" "C4R${C4_RUN}${C4_TR}_VAL: missing SRC" >&2 # LOG
|
||||||
|
return 1;
|
||||||
|
fi
|
||||||
|
head -1 $src
|
||||||
|
}
|
||||||
|
|
||||||
|
## call COMMAND for each identifier from SOURCE
|
||||||
|
## where SOURCE is a readable file
|
||||||
|
function c4.i.for {
|
||||||
|
local src="$1"; shift;
|
||||||
|
if test ! -r "$src" ; then
|
||||||
|
# || test 0 == "$(file "$src" | grep text >2 2>&1; echo $?)"
|
||||||
|
echo "WARN" "C4R${C4_RUN}${C4_TR}_FOR: missing SRC" >&2 # LOG
|
||||||
|
return 1;
|
||||||
|
fi
|
||||||
|
local line=;
|
||||||
|
while read line ; do
|
||||||
|
$@ "'""$line""'"
|
||||||
|
done <$src
|
||||||
|
}
|
||||||
|
|
||||||
|
## return identity source of [[ <context1> [...]] query
|
||||||
|
## where QUERY (and CONTEXT1, etc, if provided) are words
|
||||||
|
function c4.i.of {
|
||||||
|
local context="$C4_IS";
|
||||||
|
local query=$1; shift;
|
||||||
|
while test -n "$1" ; do
|
||||||
|
# query cannot be empty or contain / or .
|
||||||
|
# starting context must exist
|
||||||
|
if test -z "$query" -o ! -d "$context" \
|
||||||
|
|| [[ "$query" =~ "/" ]] \
|
||||||
|
|| [[ "$query" =~ '.' ]]; then
|
||||||
|
echo "WARN" "C4R${C4_RUN}I_OF: bad QUERY \"$query\" (for context \"$context\")" >&2 # LOG
|
||||||
|
return 1;
|
||||||
|
fi
|
||||||
|
# subsume query into context
|
||||||
|
context="$context/$query"
|
||||||
|
# pop query from input stack
|
||||||
|
query=$1 ; shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# context mus be an existant path and query must be a word not
|
||||||
|
# containing slash or dot
|
||||||
|
if test -z "$query" -o ! -d "$context" \
|
||||||
|
|| [[ "$query" =~ "/" ]] \
|
||||||
|
|| [[ "$query" =~ '.' ]]; then
|
||||||
|
echo "WARN" "C4R${C4_RUN}I_OF: bad QUERY \"$query\" (for context \"$context\")" >&2 # LOG
|
||||||
|
return 1;
|
||||||
|
elif ! [[ "$context" =~ ^$C4_ROOT ]]; then
|
||||||
|
|
||||||
|
echo "WARN" "C4R${C4_RUN}I_OF: context \"$context\" outside C4:$C4_ROOT for QUERY \"$query\")" >&2 # LOG
|
||||||
|
fi
|
||||||
|
|
||||||
|
# return valid seeming identity file
|
||||||
|
printf '%s/.%s' "$context" "$query"
|
||||||
|
}
|
||||||
|
|
||||||
|
# return true when given an existant identity
|
||||||
|
function c4.i.has {
|
||||||
|
local src="$(c4.i.of "$@" )";
|
||||||
|
test -n "$src" -a -r "$src"
|
||||||
|
}
|
||||||
|
# TODO make real tests out of these
|
||||||
|
#(C4_IS=""; c4.i.has ".") && echo ok || echo nope
|
||||||
|
#c4.i.has "gn" "max" && echo ok || echo nope
|
||||||
|
#c4.i.has "users" && echo ok || echo nope
|
||||||
|
|
||||||
|
|
||||||
|
C4_TR='S'; ### SPOKES
|
||||||
|
|
||||||
|
C4_S_IS="${C4_S_IS-spoke}"
|
||||||
|
## return true when given an existant spoke
|
||||||
|
function c4.s.is {
|
||||||
|
( C4_ROOT=$C4_SPOKES;
|
||||||
|
C4_IS=$C4_SPOKES;
|
||||||
|
c4.i.has $@ $C4_S_IS )
|
||||||
|
}
|
||||||
|
|
||||||
|
C4_S_SSHFS_CMD="ssh"
|
||||||
|
C4_S_SSHFS_OPT="-o allow_other"
|
||||||
|
function c4.s.sshfs {
|
||||||
|
if test -z "$1"; then
|
||||||
|
echo "WARN" "C4R${C4_RUN}S_SSHFS: missing FROM" >&2 # LOG
|
||||||
|
return 1;
|
||||||
|
fi
|
||||||
|
if test -z "$2"; then
|
||||||
|
echo "WARN" "C4R${C4_RUN}S_SSHFS: missing TO (FROM \"$1\")" >&2 # LOG
|
||||||
|
return 1;
|
||||||
|
fi
|
||||||
|
if test ! -d "$2"; then
|
||||||
|
echo "WARN" "C4R${C4_RUN}S_SSHFS: missing or non-directory TO \"$2\" (FROM \"$1\")" >&2 # LOG
|
||||||
|
return 1;
|
||||||
|
fi
|
||||||
|
: $C4_S_SSHFS_CMD $C4_S_SSHFS_OPT $@
|
||||||
|
}
|
||||||
|
|
||||||
|
####
|
||||||
|
#### END
|
||||||
|
####
|
||||||
Loading…
Add table
Add a link
Reference in a new issue