barg-parser/arg_parser.sh
2025-10-26 17:04:49 +02:00

162 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# ===== SPEC =====
SPEC=(
"command;build;Build a dev container"
"argument;name;type:positional;required;help:Name of the container"
"argument;image,i;type:option;required;map:image_name;help:Base image"
"argument;include,I;type:option;repeatable;map:include_paths;help:Include paths"
"argument;verbose,v;type:flag;repeatable;default:0;help:Increase verbosity (-v, -vv, ...)"
"argument;quiet,q;type:flag;default:false;help:Suppress all output"
"argument;cmd;type:rest;map:cmd_rest;help:Command and args to run inside the container"
"command;stop;Stop a dev container"
"argument;name;type:positional;required;help:Name of the container"
"argument;kill,k;type:flag;default:false;help:Force kill the container"
)
# ===== CONSTANTS =====
ENTRY_COMMAND="command"
ENTRY_ARGUMENT="argument"
ATTR_REQUIRED="required"
ATTR_HELP="help"
ATTR_DEFAULT="default"
ATTR_MAP="map"
ATTR_TYPE="type"
ATTR_REPEATABLE="repeatable"
ATTR_TYPE_POSITIONAL="positional"
ATTR_TYPE_OPTION="option"
ATTR_TYPE_FLAG="flag"
# ===== STORAGE =====
declare -A SPEC_DATA
declare -A SPEC_ALIASES
# ===== GENERATE IDS =====
cmd_id=0
arg_id=0
get_cmd_id() { echo $((cmd_id++)); }
get_arg_id() { echo $((arg_id++)); }
# ===== PARSE SPEC ENTRY =====
parse_spec_entry() {
local raw_entry="$1"
IFS=';' read -r type alias_str rest <<<"$raw_entry"
IFS=',' read -r -a aliases <<<"$alias_str"
declare -A attr
if [[ "$type" == "$ENTRY_COMMAND" ]]; then
attr["$ATTR_HELP"]="$rest"
else
attr["$ATTR_REQUIRED"]=false
attr["$ATTR_REPEATABLE"]=false
attr["$ATTR_TYPE"]="$ATTR_TYPE_POSITIONAL"
attr["$ATTR_MAP"]=""
attr["$ATTR_DEFAULT"]=""
attr["$ATTR_HELP"]=""
# Re-split rest on ';'
IFS=';' read -r -a elements <<<"$rest"
for element in "${elements[@]}"; do
[[ -z "$element" ]] && continue
IFS=':' read -r attribute value <<<"$element"
case "$attribute" in
"$ATTR_REQUIRED") attr["$ATTR_REQUIRED"]=true ;;
"$ATTR_REPEATABLE") attr["$ATTR_REPEATABLE"]=true ;;
"$ATTR_TYPE") attr["$ATTR_TYPE"]="$value" ;;
"$ATTR_MAP") attr["$ATTR_MAP"]="$value" ;;
"$ATTR_DEFAULT") attr["$ATTR_DEFAULT"]="$value" ;;
"$ATTR_HELP") attr["$ATTR_HELP"]="$value" ;;
esac
done
fi
# Serialize attributes to string
local attr_str=""
for k in "${!attr[@]}"; do
attr_str+="$k=${attr[$k]}|"
done
attr_str="${attr_str%|}"
echo "$type;$alias_str;$attr_str"
}
# ===== PARSE SPEC =====
parse_spec() {
local command_filter="${1:-}"
local skip_cmd=false
local exit_on_next_cmd=false
local current_cmd_id=""
for raw_entry in "${SPEC[@]}"; do
local entry
entry="$(parse_spec_entry "$raw_entry")"
IFS=';' read -r type alias_str attr_str <<<"$entry"
IFS=',' read -r -a aliases <<<"$alias_str"
if [[ "$type" == "$ENTRY_COMMAND" ]]; then
if [[ "$exit_on_next_cmd" == true ]]; then
break
fi
if [[ -n "$command_filter" ]]; then
local found=false
for a in "${aliases[@]}"; do
[[ "$a" == "$command_filter" ]] && found=true && break
done
if [[ "$found" == false ]]; then
skip_cmd=true
continue
fi
skip_cmd=false
exit_on_next_cmd=true
fi
current_cmd_id="$(get_cmd_id)"
SPEC_DATA["$current_cmd_id.type"]="$type"
SPEC_DATA["$current_cmd_id.aliases"]="$alias_str"
SPEC_DATA["$current_cmd_id.attr"]="$attr_str"
SPEC_DATA["$current_cmd_id.id"]="$current_cmd_id"
for a in "${aliases[@]}"; do
SPEC_ALIASES["$a"]="$current_cmd_id"
done
elif [[ "$type" == "$ENTRY_ARGUMENT" ]]; then
if [[ "$skip_cmd" == true ]]; then
continue
fi
local this_arg_id
this_arg_id="$(get_arg_id)"
SPEC_DATA["$current_cmd_id.$this_arg_id.type"]="$type"
SPEC_DATA["$current_cmd_id.$this_arg_id.aliases"]="$alias_str"
SPEC_DATA["$current_cmd_id.$this_arg_id.attr"]="$attr_str"
SPEC_DATA["$current_cmd_id.$this_arg_id.id"]="$this_arg_id"
for a in "${aliases[@]}"; do
SPEC_ALIASES["$current_cmd_id.$a"]="$this_arg_id"
done
fi
done
}
# ===== MAIN =====
parse_spec
# Print results as JSON-like structure
echo "{"
echo " \"spec_data\": {"
for k in "${!SPEC_DATA[@]}"; do
printf ' "%s": "%s",\n' "$k" "${SPEC_DATA[$k]}"
done
echo " },"
echo " \"spec_aliases\": {"
for k in "${!SPEC_ALIASES[@]}"; do
printf ' "%s": "%s",\n' "$k" "${SPEC_ALIASES[$k]}"
done
echo " }"
echo "}"