| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- #!/usr/bin/env bash
- set -euo pipefail
- PROJECT_PATH="."
- OUTPUT_FILE="COMMANDS.md"
- declare -A VISITED
- TREE_TEMP=$(mktemp)
- BODY_TEMP=$(mktemp)
- trap 'rm -f "$TREE_TEMP" "$BODY_TEMP"' EXIT
- # ----------------------------
- # Helpers
- # ----------------------------
- strip_colors() {
- sed -E "s/\x1B\[[0-9;]*[mK]//g"
- }
- run_help() {
- local project="./RackPeek"
- local config="Release"
- local publish_dir="$project/publish"
- local exe="$publish_dir/RackPeek"
- if [[ ! -x "$exe" ]]; then
- echo "Publishing RackPeek ($config)..." >&2
- dotnet publish "$project" -c "$config" -o "$publish_dir" --self-contained false -p:PublishSingleFile=true >&2
- fi
- local output
- output=$("$exe" "$@" 2>&1 | strip_colors)
- echo "$output"
- }
- # UPDATED: Handles descriptions that start on the next line
- get_description() {
- local help_output="$1"
- echo "$help_output" | awk '
- # If we find the header...
- /^DESCRIPTION:/ {
- in_desc = 1
- # Remove the header itself
- sub(/^DESCRIPTION:[[:space:]]*/, "")
-
- # If there is text on this same line, print it and quit
- if (length($0) > 0) {
- print $0
- exit
- }
- next
- }
- # If we are inside the description block...
- in_desc {
- # Stop if we hit an empty line or the next Section (UPPERCASE:)
- if (/^[[:space:]]*$/) exit
- if (/^[A-Z]+:/) exit
- # Trim leading/trailing whitespace
- gsub(/^[[:space:]]+|[[:space:]]+$/, "")
-
- # Print the line (we only take the first non-empty line for the index)
- print $0
- exit
- }
- '
- }
- # UPDATED: Handles "add <name>" correctly by taking only the first column ($1)
- get_child_commands() {
- local help_output="$1"
-
- echo "$help_output" | awk '
- BEGIN { in_commands = 0 }
- /^COMMANDS:/ { in_commands = 1; next }
-
- in_commands {
- # Stop if we hit an empty line or a new section
- if ($0 ~ /^[[:space:]]*$/) exit;
- if ($0 ~ /^[A-Z]+:/) exit;
- # Match lines that look like commands (indented)
- if ($0 ~ /^[[:space:]]+[a-zA-Z0-9-]+/) {
- # Print only the first word (the command name)
- print $1
- }
- }
- '
- }
- # ----------------------------
- # Recursion
- # ----------------------------
- generate_help_recursive() {
- local path_string="$1"
-
- # Convert string to array for the run_help command
- local current_cmd_array=()
- if [[ -n "$path_string" ]]; then
- IFS=' ' read -r -a current_cmd_array <<< "$path_string"
- fi
- local map_key="${path_string:-root}"
-
- if [[ -n "${VISITED["$map_key"]:-}" ]]; then return; fi
- VISITED["$map_key"]=1
- # 1. Run Help
- local help_output
- if ! help_output=$(run_help "${current_cmd_array[@]}" --help); then
- echo "Skipping: $map_key (help failed)" >&2
- return
- fi
- if is_invalid_help "$help_output"; then
- echo "Skipping: $map_key (invalid command)" >&2
- return
- fi
- # 2. Extract Description
- local description
- description=$(get_description "$help_output")
-
- # 3. Build Tree Entry
- local depth=${#current_cmd_array[@]}
- local indent=""
- [[ $depth -gt 0 ]] && printf -v indent "%*s" $((depth * 2)) ""
-
- local tree_label
- [[ $depth -eq 0 ]] && tree_label="rpk" || tree_label="${current_cmd_array[-1]}"
- local anchor_text="rpk $path_string"
- anchor_text="${anchor_text% }"
- local anchor_link=$(echo "$anchor_text" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
- # Format: - [label](link) - Description
- local tree_entry="${indent}- [${tree_label}](docs/Commands.md#${anchor_link})"
- if [[ -n "$description" ]]; then
- tree_entry="${tree_entry} - ${description}"
- fi
-
- echo "$tree_entry" >> "$TREE_TEMP"
- # 4. Write Body
- local display_header
- [[ -z "$path_string" ]] && display_header="rpk" || display_header="rpk $path_string"
- {
- echo "## \`${display_header}\`"
- echo '```'
- echo "$help_output"
- echo '```'
- echo ""
- } >> "$BODY_TEMP"
- # 5. Recurse
- local child_cmds
- mapfile -t child_cmds < <(get_child_commands "$help_output")
- for child in "${child_cmds[@]}"; do
- echo "Recursing into: ${display_header} ${child}" >&2
- local next_path
- if [[ -z "$path_string" ]]; then
- next_path="$child"
- else
- next_path="$path_string $child"
- fi
- generate_help_recursive "$next_path"
- done
- }
- is_invalid_help() {
- local output="$1"
- # Detect common failure patterns
- if echo "$output" | grep -qiE \
- "Unknown command|CommandParseException|Unexpected error occurred"; then
- return 0
- fi
- return 1
- }
- # ----------------------------
- # Main
- # ----------------------------
- echo "Generating documentation..."
- generate_help_recursive ""
- {
- echo ""
- cat "$TREE_TEMP"
- } > "Shared.Rcl/wwwroot/raw_docs/CommandIndex.md"
- {
- echo "# CLI Commands"
- echo ""
- cat "$BODY_TEMP"
- } > "Shared.Rcl/wwwroot/raw_docs/Commands.md"
- echo "Generated Successfully."
|