Regeln, Standards, Kontextstruktur und Werkzeuge übernommen; 2nd-brain- Inhalte (Stacks, Ansible-Inventar, Architektur, Knowledge) entfernt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
105 lines
4.4 KiB
Bash
Executable File
105 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
#-------------------------------------------------------------------------------
|
||
## @file bashdoc.sh
|
||
## @brief Erzeugt Markdown-Doku aus den '##'-Kommentaren von Bash-Scripts
|
||
## (Präambel + Funktionsköpfe, angelehnt an javadoc)
|
||
## @author <AUTOR – aus ai/context/responsible.md>
|
||
## @owner <VERANTWORTLICH – aus ai/context/responsible.md>
|
||
## @assist KI-unterstützt (Claude), geprüft von <AUTOR>
|
||
## @version 1.0.0 (07.10.2026)
|
||
##
|
||
## @usage bashdoc.sh [Optionen] <script.sh> [...]
|
||
## Ausgabe auf stdout oder mit -o in eine Datei
|
||
## @options
|
||
## @OPTIONS@
|
||
## @exit 0 = ok · 1 = Fehler · 2 = Aufruffehler
|
||
#-------------------------------------------------------------------------------
|
||
set -Eeuo pipefail
|
||
|
||
SCRIPT_PATH="$(readlink -f -- "${BASH_SOURCE[0]}")"
|
||
SCRIPT_DIR="${SCRIPT_PATH%/*}"
|
||
SCRIPT_NAME="${SCRIPT_PATH##*/}"
|
||
# shellcheck source=_functions.sh
|
||
source "${SCRIPT_DIR}/_functions.sh" || { echo "FEHLER: ${SCRIPT_DIR}/_functions.sh fehlt" >&2; exit 1; }
|
||
|
||
B_OPTS+=(
|
||
"o|output|value:DATEI||Markdown in DATEI schreiben (relativ = zum Aufrufverzeichnis)"
|
||
"p|private|flag|0|auch interne Funktionen (_name) dokumentieren"
|
||
)
|
||
b_init "$@"
|
||
set -- "${ARGS[@]}"
|
||
|
||
## @brief Wandelt ein Script in Markdown um
|
||
## @param $1 Script-Datei
|
||
## @return 0 ok, 1 Datei nicht lesbar; Markdown auf stdout
|
||
doc_file() {
|
||
local file="$1"
|
||
[[ -r "$file" ]] || { berror "Nicht lesbar: $file"; return 1; }
|
||
awk -v fname="${file##*/}" -v private="$OPTION_PRIVATE" '
|
||
function flush_block(name, i, l, tag) {
|
||
if (!private && name ~ /^_/) { n = 0; return }
|
||
printf "\n### `%s()`\n\n", name
|
||
for (i = 1; i <= n; i++) {
|
||
l = blk[i]
|
||
if (l ~ /^@brief/) { sub(/^@brief[ \t]*/, "", l); print l; last = "brief" }
|
||
else if (l ~ /^@param/) { sub(/^@param[ \t]*/, "", l); print "- **Param** " l; last = "param" }
|
||
else if (l ~ /^@return/) { sub(/^@return[ \t]*/, "", l); print "- **Return** " l; last = "return" }
|
||
else if (l ~ /^@/) { tag = l; sub(/[ \t].*/, "", tag); sub(/^@[a-z]+[ \t]*/, "", l); print "- **" substr(tag, 2) "** " l }
|
||
else if (l != "") { print (last == "brief" ? l : " " l) }
|
||
}
|
||
n = 0
|
||
}
|
||
function print_opts( i, f, left) {
|
||
print " -h -d -q -n -l Standardoptionen (Hilfe, Debug, still, Trockenlauf, Logdatei)"
|
||
for (i = 1; i <= nopt; i++) {
|
||
split(opt[i], f, "|"); sub(/:.*/, "", f[3])
|
||
left = (f[1] != "" ? "-" f[1] " | " : "") "--" f[2]
|
||
if (opt_meta[i] != "") left = left " " opt_meta[i]
|
||
printf " %-26s %s%s\n", left, f[5], (f[3] == "value" && f[4] != "" ? " (Default: " f[4] ")" : "")
|
||
}
|
||
}
|
||
# 1. Durchlauf: Script-Optionen aus B_OPTS+=( "…" ) sammeln
|
||
FNR == NR {
|
||
if ($0 ~ /^[ \t]*B_OPTS\+=\(/) inopts = 1
|
||
if (inopts) {
|
||
l = $0
|
||
while (match(l, /"[^"]*"/)) {
|
||
o = substr(l, RSTART + 1, RLENGTH - 2); l = substr(l, RSTART + RLENGTH)
|
||
opt[++nopt] = o; split(o, f, "|"); opt_meta[nopt] = (f[3] ~ /:/ ? substr(f[3], index(f[3], ":") + 1) : (f[3] == "value" ? "WERT" : ""))
|
||
}
|
||
if ($0 ~ /\)[ \t]*$/) inopts = 0
|
||
}
|
||
next
|
||
}
|
||
# 2. Durchlauf: Präambel + Funktionsköpfe
|
||
/^#-{10,}/ { part++; if (part == 1) printf "## %s\n\n```text\n", fname; if (part == 2) print "```"; next }
|
||
part == 1 && /^##/ { l = $0; sub(/^## ?/, "", l); if (l !~ /@OPTIONS@/) print l; else print_opts(); next }
|
||
part >= 2 && /^[ \t]*##/ { l = $0; sub(/^[ \t]*## ?/, "", l); blk[++n] = l; next }
|
||
part >= 2 && n > 0 && /^[ \t]*(function[ \t]+)?[A-Za-z_][A-Za-z0-9_]*[ \t]*\(\)/ {
|
||
name = $0; sub(/^[ \t]*(function[ \t]+)?/, "", name); sub(/[ \t]*\(.*/, "", name)
|
||
flush_block(name); next
|
||
}
|
||
part >= 2 && n > 0 && !/^[ \t]*#/ { n = 0 }
|
||
' "$file" "$file"
|
||
}
|
||
|
||
## @brief Hauptablauf
|
||
## @param $@ Script-Dateien
|
||
## @return 0 ok, 1 Fehler
|
||
main() {
|
||
(( $# )) || bdie "Mindestens ein Script angeben" 2
|
||
local f out="" rc=0
|
||
[[ -n "$OPTION_OUTPUT" ]] && out="$(b_abspath "$OPTION_OUTPUT" "$B_CALL_DIR")"
|
||
{
|
||
printf '# Script-Doku\n\n> Erzeugt mit `bin/bashdoc.sh` am %(%d.%m.%Y)T – Quelle sind die `##`-Kommentare.\n\n' -1
|
||
for f in "$@"; do
|
||
doc_file "$(b_abspath "$f" "$B_CALL_DIR")" || rc=1
|
||
printf '\n'
|
||
done
|
||
} > "${out:-/dev/stdout}"
|
||
[[ -n "$out" ]] && becho "Doku geschrieben: $out"
|
||
return "$rc"
|
||
}
|
||
|
||
main "$@"
|