#!/bin/bash # Build and run Gaze application # Usage: ./run [build|test|run|lsp] [-v|--verbose] [-c|--coverage] [-p|--performance] [-o|--output ] [--no-lsp] # Note: Default action (./run with no args) runs the app with verbose logging enabled set -o pipefail # Configuration readonly PROJECT="Gaze.xcodeproj" readonly SCHEME="Gaze" readonly CONFIGURATION="Debug" readonly APP_SUBSYSTEM="com.mikefreno.Gaze" VERBOSE=false OUTPUT_FILE="" SKIP_LSP=false PERFORMANCE=false COVERAGE=false # Constructs xcodebuild command with common parameters build_xcodebuild_command() { local action="$1" local cmd="xcodebuild -project $PROJECT -scheme $SCHEME -configuration $CONFIGURATION $action" # Add performance profiling if requested if [ "$PERFORMANCE" = true ]; then cmd="$cmd -enablePerformanceTestsDiagnostics YES" fi # Add coverage analysis if requested if [ "$COVERAGE" = true ]; then cmd="$cmd -enableCodeCoverage YES" fi echo "$cmd" } # Kills any existing Gaze processes kill_existing_gaze_processes() { echo "🔍 Checking for existing Gaze processes..." local pids pids=$(pgrep -f "Gaze.app") if [ -n "$pids" ]; then echo "🛑 Killing existing Gaze processes (PID(s): $pids)..." kill $pids 2>/dev/null sleep 1 else echo "✅ No existing Gaze processes found" fi } # Updates LSP configuration for editor support update_lsp_config() { echo "🔧 Updating LSP configuration..." if command -v xcode-build-server &> /dev/null; then xcode-build-server config -project "$PROJECT" -scheme "$SCHEME" > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "✅ LSP configuration updated (buildServer.json created)" else echo "⚠️ Could not update LSP configuration" fi else echo "⚠️ xcode-build-server not found. Install with: brew install xcode-build-server" echo " This helps Neovim's LSP recognize your Swift modules" fi } # Gets the build output directory from xcodebuild get_build_directory() { xcodebuild -project "$PROJECT" -scheme "$SCHEME" -configuration "$CONFIGURATION" \ -showBuildSettings 2>/dev/null | \ grep -m 1 "BUILT_PRODUCTS_DIR" | \ sed 's/.*= //' } # Handles post-build success actions handle_build_success() { echo "✅ Build succeeded!" if [ "$SKIP_LSP" != true ]; then update_lsp_config fi } # Pretty prints build/test errors from output print_errors() { local output="$1" local action_type="$2" # "Build" or "Test" echo "" echo "📝 ${action_type} Errors:" echo "================================================================================" # Extract error lines and format them local errors errors=$(echo "$output" | grep -E "error:|Error |failed|FAIL" | sed 's/^/ /') if [ -n "$errors" ]; then echo "$errors" else echo " No specific error messages found. See full output above." fi echo "================================================================================" } # Launches the built application launch_app() { local build_dir build_dir=$(get_build_directory) local app_path="${build_dir}/Gaze.app" if [ -d "$app_path" ]; then echo "🚀 Launching: $app_path" echo "📝 Capturing application logs (Ctrl+C to stop - won't kill app)..." open "$app_path" & sleep 2 echo "================================================================" /usr/bin/log stream --predicate "subsystem contains \"$APP_SUBSYSTEM\"" \ --style compact 2>/dev/null else echo "⚠️ App not found at expected location, trying fallback..." open "$HOME/Library/Developer/Xcode/DerivedData/Gaze-*/Build/Products/Debug/Gaze.app" fi } # Runs command with configurable output handling # Always captures output for error reporting run_with_output() { local cmd="$1" local exit_code if [ "$VERBOSE" = true ] && [ -n "$OUTPUT_FILE" ]; then # Capture to variable and tee to file COMMAND_OUTPUT=$(eval "$cmd" 2>&1 | tee "$OUTPUT_FILE") exit_code=${PIPESTATUS[0]} elif [ "$VERBOSE" = true ]; then # Show output live and capture it if [ -t 1 ]; then # Interactive terminal - use tee to show output COMMAND_OUTPUT=$(eval "$cmd" 2>&1 | tee /dev/tty) exit_code=${PIPESTATUS[0]} else # Non-interactive - just capture and echo COMMAND_OUTPUT=$(eval "$cmd" 2>&1) exit_code=$? echo "$COMMAND_OUTPUT" fi elif [ -n "$OUTPUT_FILE" ]; then # Write to file and capture COMMAND_OUTPUT=$(eval "$cmd" 2>&1 | tee "$OUTPUT_FILE") exit_code=${PIPESTATUS[0]} else # Silent mode - capture for error display if needed COMMAND_OUTPUT=$(eval "$cmd" 2>&1) exit_code=$? fi return $exit_code } # Displays usage information show_usage() { echo "Usage: $0 [build|test|run|lsp] [-v|--verbose] [-o|--output ] [--no-lsp] [-p|--performance] [-c|--coverage]" echo "" echo "Commands:" echo " build - Build the application" echo " test - Run unit tests" echo " run - Build and run the application with full logging (default)" echo " lsp - Update LSP configuration only (buildServer.json)" echo "" echo "Options:" echo " -v, --verbose - Show output in stdout" echo " -o, --output - Write output to log file" echo " --no-lsp - Skip LSP configuration update" echo " -p, --performance - Run tests with performance profiling" echo " -c, --coverage - Run tests with code coverage analysis" echo "" echo "Note: Running './run' with no arguments defaults to 'run' action with verbose logging." echo " Press Ctrl+C to stop log capture and keep the app running." } # Parse command line arguments ACTION="" while [[ $# -gt 0 ]]; do case $1 in -v|--verbose) VERBOSE=true shift ;; -o|--output) OUTPUT_FILE="$2" VERBOSE=true shift 2 ;; --no-lsp) SKIP_LSP=true shift ;; -p|--performance) PERFORMANCE=true shift ;; -c|--coverage) COVERAGE=true shift ;; *) if [ -z "$ACTION" ]; then ACTION="$1" fi shift ;; esac done # Default to run if no action specified if [ -z "$ACTION" ]; then ACTION="run" fi # Main execution echo "=== Gaze Application Script ===" case "$ACTION" in build) echo "Building Gaze project..." run_with_output "$(build_xcodebuild_command build)" if [ $? -eq 0 ]; then handle_build_success echo "💡 The app is located at: build/Debug/Gaze.app" else echo "❌ Build failed!" print_errors "$COMMAND_OUTPUT" "Build" exit 1 fi ;; test) echo "Running unit tests..." run_with_output "$(build_xcodebuild_command test)" if [ $? -eq 0 ]; then echo "✅ Tests passed!" else echo "❌ Tests failed!" print_errors "$COMMAND_OUTPUT" "Test" exit 1 fi ;; run) echo "Building and running Gaze application..." kill_existing_gaze_processes run_with_output "$(build_xcodebuild_command build)" if [ $? -eq 0 ]; then handle_build_success launch_app else echo "❌ Build failed!" print_errors "$COMMAND_OUTPUT" "Build" exit 1 fi ;; lsp) echo "Updating LSP configuration only..." update_lsp_config ;; *) show_usage exit 1 ;; esac