blind mgmt setup

This commit is contained in:
Robert Perce 2026-01-29 23:39:06 -06:00
parent 87f5dfcdf8
commit 074131bb54
5 changed files with 201 additions and 0 deletions

View file

@ -0,0 +1,76 @@
#!/usr/bin/env bash
declare -gA ARGP
declare -gA SHORT
__reset_argparse() {
declare -gA ARGP
declare -gA SHORT
}
die() { echo "Error: $*"; exit 1; }
def_arg() {
test "$3" = bool -o "$3" = value || die "def_arg: type (\$3) must be 'bool' or 'value', received '$3'"
ARGP["$1,type"]="$3"
if [ "$3" = bool ]; then
test -z "$4" || die "def_arg: bool args cannot specify required/default"
declare -g "$1=0"
else
test "$4" = required -o "$4" = default || die "def_arg: \$4 must be 'required' or 'default', received '$4'"
if [ "$4" = required ]; then
ARGP["$1,required"]=1
else
value="$5"
declare -g "$1=$value"
fi
fi
if [ -n "$2" ]; then
SHORT["$2"]="$1"
fi
}
parse_args() {
positional=()
while (( $# > 0 )); do
next="$1"; shift
if [[ "$next" == --* ]]; then
arg=${next#--}
test -n "${ARGP["$arg,type"]}" || die "unknown arg --$arg"
if [ "${ARGP["$arg,type"]}" = bool ]; then
value=1
elif [ $# -eq 0 ]; then
die "Missing value for --$arg"
else
value="$1"; shift
fi
declare -g "$arg=$value"
elif [[ "$next" == -* ]]; then
for ((i = 1 ; i < ${#next} ; i++ )); do
short=${next:$i:1}
arg=${SHORT["$short"]}
test -n "$arg" || die "unknown short arg -$short"
if [ "${ARGP["$arg,type"]}" = bool ]; then
declare -g "$arg=1"
else
value=${next:$(( i+1 ))}
if [ -z "$value" ]; then
value="$1"; shift
fi
test -n "$value" || die "missing value for -$short"
declare -g "$arg=$value"
break
fi
done
else
positional+=("$next")
fi
done
# check for missing required
for arg in "${!ARGP[@]}"; do
arg="${arg%%,*}"
[ "${ARGP["$arg,required"]}" != 1 ] || [ -n "${!arg}" ] || die "missing argument --$arg"
done
}

90
private_bin/private_mgmt Executable file
View file

@ -0,0 +1,90 @@
#!/usr/bin/env bash
set -e
source argparse.bash
functions=; def_arg functions f value default "${XDG_CONFIG_HOME:-"$HOME/.config"}/mgmt/functions"
modules=; def_arg modules m value default "${XDG_CONFIG_HOME:-"$HOME/.config"}/mgmt/modules"
positional=(); parse_args "$@"
while IFS= read -rd '' fnfile; do
source "$fnfile"
done < <(find "$functions" -type f -print0)
PREFIX=""
grey() { printf "\33[37;2m%s\33[0;m" "$*"; }
red() { printf "\33[31;1m%s\33[0;m" "$*"; }
diag() {
>&2 printf "\33[2K\r%s" "$(grey "$PREFIX")"
>&2 echo "$@"
}
join_by() { local IFS="$1"; shift; echo "$*"; }
filter_by_args() { grep -E "$(join_by '|' "${positional[@]}")"; }
#####
# Gather dependencies of (filtered) modules
#####
declare -a found_modules
mapfile -t filtered_mods < <(find "$modules" -type f | filter_by_args)
set -- "${filtered_mods[@]}"
while [ $# -gt 0 ]; do
unset deps; declare -a deps
for mod; do
if echo "${found_modules[@]}" | grep -q "$mod"; then
continue
fi
found_modules+=( "$mod" )
unset DEPENDS
source "$mod"
for dep in "${DEPENDS[@]}"; do
if echo "${found_modules[@]}" | grep -qv "$dep"; then
if echo "${deps[@]}" | grep -qv "$dep"; then
deps+=( "$dep" )
fi
fi
done
done
set -- "${deps[@]}"
done
#####
# Resolve dependency ordering
#####
declare -a ordered_modules
set -- "${found_modules[@]}"
while [ $# -gt 0 ]; do
unset remaining; declare -a remaining
for mod; do
unset DEPENDS
source "$mod"
if [[ -n "$(comm -23 <(printf -- '%s\n' "${DEPENDS[@]}" | sort) <(printf -- '%s\n' "${ordered_modules[@]}" | sort))" ]]; then
remaining+=( "$mod" )
else
ordered_modules+=( "$mod" )
fi
done
if [ $# -eq ${#remaining[@]} ]; then
diag "$(red "Error: dependency loop involving ${remaining[*]}")"
exit 1
fi
set -- "${remaining[@]}"
done
#####
# Apply modules
#####
sudo -v
set -- "${ordered_modules[@]}"
for mod; do
diag -e "\nApplying $mod"
PREFIX="[$mod] "
unset check_setup setup check_apply apply
source "$modules/$mod"
test "$(declare -F check_setup)" || { check_setup() { false ; } }
test "$(declare -F check_apply)" || { check_apply() { false ; } }
test "$(declare -F setup)" || { setup() { true; } }
test "$(declare -F apply)" || { apply() { true; } }
check_setup || setup
check_apply || apply
PREFIX=""
done