mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
186 lines
5.4 KiB
Bash
Executable File
186 lines
5.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# Extract validation structure from Rust source files
|
|
# Usage: ./extract-validation-structure.sh <version>
|
|
# Example: ./extract-validation-structure.sh v1.15.0
|
|
|
|
set -e
|
|
|
|
VERSION=${1:-"main"}
|
|
GOOSE_REPO=${GOOSE_REPO:-"$HOME/Development/goose"}
|
|
|
|
if [ ! -d "$GOOSE_REPO" ]; then
|
|
echo "Error: GOOSE_REPO directory not found: $GOOSE_REPO" >&2
|
|
exit 1
|
|
fi
|
|
|
|
cd "$GOOSE_REPO"
|
|
|
|
# Verify version exists (for non-main versions)
|
|
if [ "$VERSION" != "main" ]; then
|
|
if ! git rev-parse "$VERSION" >/dev/null 2>&1; then
|
|
echo "Error: Version $VERSION not found in git history" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Start JSON output
|
|
# Use ISO 8601 format that works on both macOS and Linux
|
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u -Iseconds 2>/dev/null || date -u)
|
|
cat << EOF
|
|
{
|
|
"version": "$VERSION",
|
|
"extracted_at": "$TIMESTAMP",
|
|
"struct_fields": [
|
|
EOF
|
|
|
|
# Extract fields from multiple structs
|
|
FIRST_FIELD=true
|
|
|
|
# Get file content from git history or working directory
|
|
if [ "$VERSION" = "main" ]; then
|
|
MOD_RS_CONTENT=$(cat crates/goose/src/recipe/mod.rs)
|
|
else
|
|
MOD_RS_CONTENT=$(git show "$VERSION:crates/goose/src/recipe/mod.rs" 2>/dev/null || {
|
|
echo "Error: Failed to read mod.rs from version $VERSION" >&2
|
|
exit 1
|
|
})
|
|
fi
|
|
|
|
# List of structs to extract (in order of appearance in file)
|
|
STRUCTS="Recipe Author Settings Response SubRecipe RecipeParameter"
|
|
|
|
# Create a temporary file to collect all fields
|
|
TEMP_FIELDS=$(mktemp)
|
|
|
|
for STRUCT_NAME in $STRUCTS; do
|
|
# Extract just this struct's definition (from "pub struct Name" to the closing "}")
|
|
echo "$MOD_RS_CONTENT" | awk "
|
|
/^pub struct $STRUCT_NAME/ { in_struct=1; next }
|
|
in_struct && /^}/ { exit }
|
|
in_struct && /^[[:space:]]+pub [a-z_]+:/ { print }
|
|
" | while IFS= read -r line; do
|
|
# Extract field name (word after 'pub ')
|
|
field_name=$(echo "$line" | sed -E 's/.*pub ([a-z_]+):.*/\1/')
|
|
|
|
# Extract type (between : and , or // or end of line)
|
|
field_type=$(echo "$line" | sed -E 's/.*:\s*([^,\/]+).*/\1/' | sed 's/[[:space:]]*$//')
|
|
|
|
# Extract inline comment (after //)
|
|
inline_comment=""
|
|
if echo "$line" | grep -q "//"; then
|
|
inline_comment=$(echo "$line" | sed -E 's/.*\/\/\s*(.*)$/\1/' | sed 's/[[:space:]]*$//' | sed 's/"/\\"/g')
|
|
fi
|
|
|
|
# Check if optional
|
|
is_optional="false"
|
|
if echo "$field_type" | grep -q "Option<"; then
|
|
is_optional="true"
|
|
fi
|
|
|
|
# Output to temp file
|
|
cat << FIELD_JSON >> "$TEMP_FIELDS"
|
|
{
|
|
"struct": "$STRUCT_NAME",
|
|
"field": "$field_name",
|
|
"type": "$field_type",
|
|
"optional": $is_optional,
|
|
"inline_comment": "$inline_comment"
|
|
}
|
|
FIELD_JSON
|
|
done
|
|
done
|
|
|
|
# Output fields with proper comma separation
|
|
if [ -s "$TEMP_FIELDS" ]; then
|
|
# Read all JSON objects into an array and format with commas
|
|
jq -s '.' "$TEMP_FIELDS" | jq -r 'to_entries | .[] | (if .key > 0 then "," else "" end) + " " + (.value | tostring)'
|
|
fi
|
|
|
|
rm -f "$TEMP_FIELDS"
|
|
|
|
# Close struct_fields array, start validation_functions
|
|
cat << EOF
|
|
|
|
],
|
|
"validation_functions": [
|
|
EOF
|
|
|
|
# Extract validation functions with error messages and code snippets
|
|
FIRST_FUNC=true
|
|
|
|
# Get validation file content from git history or working directory
|
|
# Note: validate_recipe.rs may not exist in older versions
|
|
if [ "$VERSION" = "main" ]; then
|
|
if [ -f crates/goose/src/recipe/validate_recipe.rs ]; then
|
|
VALIDATE_RS_CONTENT=$(cat crates/goose/src/recipe/validate_recipe.rs)
|
|
else
|
|
VALIDATE_RS_CONTENT=""
|
|
fi
|
|
else
|
|
VALIDATE_RS_CONTENT=$(git show "$VERSION:crates/goose/src/recipe/validate_recipe.rs" 2>/dev/null || echo "")
|
|
fi
|
|
|
|
if [ -n "$VALIDATE_RS_CONTENT" ]; then
|
|
echo "$VALIDATE_RS_CONTENT" | rg "^fn validate_" -A 30 | \
|
|
awk '
|
|
/^fn validate_/ {
|
|
if (func_name != "") {
|
|
# Output previous function
|
|
if (first_func == "true") {
|
|
first_func = "false"
|
|
} else {
|
|
print ","
|
|
}
|
|
printf " {\n"
|
|
printf " \"function\": \"%s\",\n", func_name
|
|
printf " \"signature\": \"%s\",\n", signature
|
|
printf " \"error_messages\": [%s],\n", error_msgs
|
|
printf " \"code_snippet\": %s\n", code_snippet
|
|
printf " }"
|
|
}
|
|
|
|
# Start new function
|
|
func_name = $0
|
|
gsub(/^fn /, "", func_name)
|
|
gsub(/\(.*/, "", func_name)
|
|
signature = $0
|
|
gsub(/"/, "\\\"", signature)
|
|
error_msgs = ""
|
|
code_snippet = "\"...\""
|
|
first_func = (first_func == "") ? "true" : first_func
|
|
}
|
|
|
|
/anyhow::anyhow!\("/ {
|
|
# Extract error message
|
|
msg = $0
|
|
gsub(/.*anyhow::anyhow!\("/, "", msg)
|
|
gsub(/".*/, "", msg)
|
|
gsub(/"/, "\\\"", msg)
|
|
if (error_msgs != "") error_msgs = error_msgs ", "
|
|
error_msgs = error_msgs "\"" msg "\""
|
|
}
|
|
|
|
END {
|
|
# Output last function
|
|
if (func_name != "") {
|
|
if (first_func != "true") {
|
|
print ","
|
|
}
|
|
printf " {\n"
|
|
printf " \"function\": \"%s\",\n", func_name
|
|
printf " \"signature\": \"%s\",\n", signature
|
|
printf " \"error_messages\": [%s],\n", error_msgs
|
|
printf " \"code_snippet\": %s\n", code_snippet
|
|
printf " }"
|
|
}
|
|
}
|
|
'
|
|
fi
|
|
|
|
# Close validation_functions array and JSON
|
|
cat << EOF
|
|
|
|
]
|
|
}
|
|
EOF
|