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:
Corwin Brust 2026-05-02 08:06:57 +05:30
parent 69a54a8e9f
commit 961a3ecec2

713
ghostwheel.fn.sh Executable file
View 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][foo [UP] 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
####