Skip to content

Commit

Permalink
Fixing for Bushel v2 (#13)
Browse files Browse the repository at this point in the history
* Adding Extension (#9)

* Adding URLImage (#10)

* adding InitializablePackageOptions (#12)

* adding scripts for documentation
  • Loading branch information
leogdion authored Nov 23, 2024
1 parent 2cd2240 commit b9ba532
Show file tree
Hide file tree
Showing 7 changed files with 601 additions and 13 deletions.
206 changes: 206 additions & 0 deletions Scripts/swift-doc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#!/bin/bash

# Check if ANTHROPIC_API_KEY is set
if [ -z "$ANTHROPIC_API_KEY" ]; then
echo "Error: ANTHROPIC_API_KEY environment variable is not set"
echo "Please set it with: export ANTHROPIC_API_KEY='your-key-here'"
exit 1
fi

# Check if jq is installed
if ! command -v jq &> /dev/null; then
echo "Error: jq is required but not installed."
echo "Please install it:"
echo " - On macOS: brew install jq"
echo " - On Ubuntu/Debian: sudo apt-get install jq"
echo " - On CentOS/RHEL: sudo yum install jq"
exit 1
fi

# Check if an argument was provided
if [ $# -eq 0 ]; then
echo "Usage: $0 <swift-file-or-directory> [--skip-backup]"
exit 1
fi

TARGET=$1
SKIP_BACKUP=0

# Check for optional flags
if [ "$2" = "--skip-backup" ]; then
SKIP_BACKUP=1
fi

# Function to extract header (comments, imports, etc.)
extract_header() {
local file="$1"
local header
# Capture file header (comments, imports, conditional compilation blocks)
header=$(awk '
BEGIN { in_comment=0; in_imports=1; printed=0 }
/^\/\// { print; next }
/^\/\*/ { in_comment=1; print; next }
in_comment==1 { print; if ($0 ~ /\*\//) in_comment=0; next }
/^import/ { if (in_imports) print; next }
/^#if/ { print; next }
/^#else/ { print; next }
/^#endif/ { print; next }
/^$/ { if (!printed) print; next }
{ if (in_imports) in_imports=0; if (!printed) printed=1; exit }
' "$file")
echo "$header"
}

# Function to extract main code (excluding header)
extract_main_code() {
local file="$1"
local main_code
main_code=$(awk '
BEGIN { in_header=1; in_comment=0; buffer="" }
in_header && /^\/\// { next }
in_header && /^\/\*/ { in_comment=1; next }
in_header && in_comment { if ($0 ~ /\*\//) in_comment=0; next }
in_header && /^import/ { next }
in_header && /^#if/ { next }
in_header && /^#else/ { next }
in_header && /^#endif/ { next }
in_header && /^$/ { next }
{ in_header=0; print }
' "$file")
echo "$main_code"
}

# Function to clean markdown code blocks
clean_markdown() {
local content="$1"
# Remove ```swift from the start and ``` from the end, if present
content=$(echo "$content" | sed -E '1s/^```swift[[:space:]]*//')
content=$(echo "$content" | sed -E '$s/```[[:space:]]*$//')
echo "$content"
}

# Function to process a single Swift file
process_swift_file() {
local SWIFT_FILE=$1
echo "Processing: $SWIFT_FILE"

# Create backup unless skipped
if [ $SKIP_BACKUP -eq 0 ]; then
cp "$SWIFT_FILE" "${SWIFT_FILE}.backup"
echo "Created backup: ${SWIFT_FILE}.backup"
fi

# Extract header and main code separately
local header
header=$(extract_header "$SWIFT_FILE")

local main_code
main_code=$(extract_main_code "$SWIFT_FILE")

# Read and escape the main code for JSON
local SWIFT_CODE
SWIFT_CODE=$(echo "$main_code" | jq -Rs .)

# Create the JSON payload
local JSON_PAYLOAD
JSON_PAYLOAD=$(jq -n \
--arg code "$SWIFT_CODE" \
'{
model: "claude-3-haiku-20240307",
max_tokens: 2000,
messages: [{
role: "user",
content: "Please add Swift documentation comments to the following code. Use /// style comments. Include parameter descriptions and return value documentation where applicable. Return only the documented code without any markdown formatting or explanation:\n\n\($code)"
}]
}')

# Make the API call to Claude
local response
response=$(curl -s https://api.anthropic.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d "$JSON_PAYLOAD")

# Check if the API call was successful
if [ $? -ne 0 ]; then
echo "Error: API call failed for $SWIFT_FILE"
return 1
fi

# Extract the content from the response using jq
local documented_code
documented_code=$(echo "$response" | jq -r '.content[0].text // empty')

# Check if we got valid content back
if [ -z "$documented_code" ]; then
echo "Error: No valid response received for $SWIFT_FILE"
echo "API Response: $response"
return 1
fi

# Clean the markdown formatting from the response
documented_code=$(clean_markdown "$documented_code")

# Combine header and documented code
{
echo "$header"
[ ! -z "$header" ] && echo "" # Add blank line if header exists
echo "$documented_code"
} > "$SWIFT_FILE"

# Show diff if available and backup exists
if [ $SKIP_BACKUP -eq 0 ] && command -v diff &> /dev/null; then
echo -e "\nChanges made to $SWIFT_FILE:"
diff "${SWIFT_FILE}.backup" "$SWIFT_FILE"
fi

echo "✓ Documentation added to $SWIFT_FILE"
echo "----------------------------------------"
}

# Function to process directory
process_directory() {
local DIR=$1
local SWIFT_FILES=0
local PROCESSED=0
local FAILED=0

# Count total Swift files
SWIFT_FILES=$(find "$DIR" -name "*.swift" | wc -l)
echo "Found $SWIFT_FILES Swift files in $DIR"
echo "----------------------------------------"

# Process each Swift file
while IFS= read -r file; do
if process_swift_file "$file"; then
((PROCESSED++))
else
((FAILED++))
fi
# Add a small delay to avoid API rate limits
sleep 1
done < <(find "$DIR" -name "*.swift")

echo "Summary:"
echo "- Total Swift files found: $SWIFT_FILES"
echo "- Successfully processed: $PROCESSED"
echo "- Failed: $FAILED"
}

# Main logic
if [ -f "$TARGET" ]; then
# Single file processing
if [[ "$TARGET" == *.swift ]]; then
process_swift_file "$TARGET"
else
echo "Error: File must have .swift extension"
exit 1
fi
elif [ -d "$TARGET" ]; then
# Directory processing
process_directory "$TARGET"
else
echo "Error: $TARGET is neither a valid file nor directory"
exit 1
fi
174 changes: 174 additions & 0 deletions Scripts/watch-docc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/bin/bash

# Help message
show_usage() {
echo "Usage: $0 <watch_directory>"
echo "Watches the specified directory for changes in Swift and Markdown files"
echo "and automatically rebuilds DocC documentation to ./public directory"
exit 1
}

# Check if directory argument is provided
if [ $# -ne 1 ]; then
show_usage
fi

# Configuration
WATCH_DIR="$1" # Use the provided directory
TEMP_DIR=$(mktemp -d)
OUTPUT_DIR="./public"
BUILD_CMD="xcodebuild docbuild -scheme DataThespian -derivedDataPath $TEMP_DIR"
PORT=8000

# Global variables for process management
SERVER_PID=""
FSWATCH_PID=""

# Cleanup function for all processes and temporary directory
cleanup() {
echo -e "\nCleaning up..."

# Kill the Python server
if [ ! -z "$SERVER_PID" ]; then
echo "Stopping web server (PID: $SERVER_PID)..."
kill -9 "$SERVER_PID" 2>/dev/null
wait "$SERVER_PID" 2>/dev/null
fi

# Kill fswatch
if [ ! -z "$FSWATCH_PID" ]; then
echo "Stopping file watcher (PID: $FSWATCH_PID)..."
kill -9 "$FSWATCH_PID" 2>/dev/null
wait "$FSWATCH_PID" 2>/dev/null
fi

# Kill any remaining Python servers on our port (belt and suspenders)
local remaining_servers=$(lsof -ti:$PORT)
if [ ! -z "$remaining_servers" ]; then
echo "Cleaning up remaining processes on port $PORT..."
kill -9 $remaining_servers 2>/dev/null
fi

echo "Removing temporary directory..."
rm -rf "$TEMP_DIR"

echo "Cleanup complete"
exit 0
}

# Register cleanup function for multiple signals
trap cleanup EXIT INT TERM

# Validate watch directory
if [ ! -d "$WATCH_DIR" ]; then
echo "Error: Directory '$WATCH_DIR' does not exist"
exit 1
fi

# Create output directory if it doesn't exist
mkdir -p "$OUTPUT_DIR"

# Check for required tools
if ! command -v fswatch >/dev/null 2>&1; then
echo "Error: This script requires fswatch on macOS."
echo "Install it using: brew install fswatch"
exit 1
fi

if ! command -v python3 >/dev/null 2>&1; then
echo "Error: This script requires python3 for the web server."
exit 1
fi

# Function to find the .doccarchive file
find_doccarchive() {
local archive_path=$(find "$TEMP_DIR" -name "*.doccarchive" -type d | head -n 1)
if [ -z "$archive_path" ]; then
echo "Error: Could not find .doccarchive file"
return 1
fi
echo "$archive_path"
}

# Function to start the web server
start_server() {
# Check if something is already running on the port
if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null ; then
echo "Port $PORT is already in use. Attempting to clean up..."
kill -9 $(lsof -ti:$PORT) 2>/dev/null
sleep 1
fi

echo "Starting web server on http://localhost:$PORT ..."
cd "$OUTPUT_DIR" && python3 -m http.server $PORT &
SERVER_PID=$!
cd - > /dev/null

# Wait a moment to ensure server starts
sleep 1

# Verify server started successfully
if ! lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null ; then
echo "Failed to start web server"
exit 1
fi

echo "Documentation is now available at: http://localhost:$PORT"
}

# Function to rebuild documentation
rebuild_docs() {
echo "Changes detected in: $1"
echo "Rebuilding documentation..."

# Clean temporary directory contents while preserving the directory
rm -rf "$TEMP_DIR"/*

# Build documentation
eval "$BUILD_CMD"
if [ $? -ne 0 ]; then
echo "Error building documentation"
return 1
fi

# Find the .doccarchive file
local archive_path=$(find_doccarchive)
if [ $? -ne 0 ]; then
return 1
fi

# Process the archive for static hosting
echo "Processing documentation for static hosting..."
$(xcrun --find docc) process-archive \
transform-for-static-hosting "$archive_path" \
--output-path "$OUTPUT_DIR" \
--hosting-base-path "/"

if [ $? -eq 0 ]; then
echo "Documentation rebuilt successfully at $(date '+%H:%M:%S')"
echo "Documentation available at: http://localhost:$PORT"
else
echo "Error processing documentation archive"
fi
}

# Initial build
echo "Performing initial documentation build..."
echo "Watching directory: $WATCH_DIR"
echo "Output directory: $OUTPUT_DIR"
rebuild_docs "initial build"

# Start the web server after initial build
start_server

# Watch for changes
echo "Watching for changes in Swift and Markdown files..."
fswatch -r "$WATCH_DIR" | while read -r file; do
if [[ "$file" =~ \.(swift|md)$ ]] || [[ "$file" =~ \.docc/ ]]; then
rebuild_docs "$file"
fi
done &
FSWATCH_PID=$!

# Wait for fswatch to exit (which should only happen if there's an error)
wait $FSWATCH_PID
Loading

0 comments on commit b9ba532

Please sign in to comment.