#!/bin/bash # Foxhunt Local E2E Compilation Validation Script # This script provides an easy way to run comprehensive validation locally # before committing changes or submitting pull requests set -euo pipefail # Script configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" VALIDATOR_PATH="$PROJECT_ROOT/tools/foxhunt-validator" LOG_DIR="$PROJECT_ROOT/logs" REPORTS_DIR="$PROJECT_ROOT/reports" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' # No Color # Default configuration DEFAULT_MODE="all" DEFAULT_JOBS=$(nproc) DEFAULT_TIMEOUT=300 CONTINUE_ON_ERROR=false SKIP_DOCKER=false VERBOSE=false CLEAN_FIRST=false WATCH_MODE=false # Print functions print_header() { echo -e "${BLUE}╔══════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║ 🦊 Foxhunt Local Validator ║${NC}" echo -e "${BLUE}║ Comprehensive E2E Compilation Suite ║${NC}" echo -e "${BLUE}╚══════════════════════════════════════════════╝${NC}" echo } print_success() { echo -e "${GREEN}✅ $1${NC}" } print_error() { echo -e "${RED}❌ $1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } print_info() { echo -e "${CYAN}ℹ️ $1${NC}" } print_section() { echo echo -e "${PURPLE}📋 $1${NC}" echo -e "${PURPLE}$(echo "$1" | sed 's/./─/g')${NC}" } # Usage information show_usage() { echo "Usage: $0 [OPTIONS] [MODE]" echo echo "Modes:" echo " all Validate everything (default)" echo " libs Validate library crates only" echo " bins Validate binary services only" echo " tests Validate test compilation only" echo " examples Validate example compilation only" echo " docker Validate Docker builds only" echo " analyze Generate workspace analysis report" echo " watch Watch for changes and re-validate" echo " clean Clean all build artifacts and caches" echo echo "Options:" echo " -h, --help Show this help message" echo " -v, --verbose Enable verbose output" echo " -j, --jobs Set maximum parallel jobs (default: $(nproc))" echo " -t, --timeout Set timeout per target in seconds (default: 300)" echo " -c, --continue Continue validation even if some targets fail" echo " --skip-docker Skip Docker validation" echo " --clean-first Clean build artifacts before validation" echo " --format Output format: console, json, html (default: console)" echo " --output Output file path (default: auto-generated for json/html)" echo " --config Use custom configuration file" echo echo "Examples:" echo " $0 # Validate everything with default settings" echo " $0 libs -v # Validate libraries with verbose output" echo " $0 all -j 8 -c # Validate all with 8 parallel jobs, continue on error" echo " $0 --clean-first bins # Clean then validate binaries" echo " $0 watch # Watch mode - re-validate on file changes" } # Parse command line arguments parse_args() { local mode="" local jobs="$DEFAULT_JOBS" local timeout="$DEFAULT_TIMEOUT" local format="console" local output="" local config="" while [[ $# -gt 0 ]]; do case $1 in -h|--help) show_usage exit 0 ;; -v|--verbose) VERBOSE=true shift ;; -j|--jobs) jobs="$2" shift 2 ;; -t|--timeout) timeout="$2" shift 2 ;; -c|--continue) CONTINUE_ON_ERROR=true shift ;; --skip-docker) SKIP_DOCKER=true shift ;; --clean-first) CLEAN_FIRST=true shift ;; --format) format="$2" shift 2 ;; --output) output="$2" shift 2 ;; --config) config="$2" shift 2 ;; all|libs|bins|tests|examples|docker|analyze|watch|clean) mode="$1" shift ;; -*) print_error "Unknown option: $1" show_usage exit 1 ;; *) if [[ -z "$mode" ]]; then mode="$1" else print_error "Multiple modes specified: $mode and $1" exit 1 fi shift ;; esac done # Set defaults MODE="${mode:-$DEFAULT_MODE}" JOBS="$jobs" TIMEOUT="$timeout" FORMAT="$format" OUTPUT="$output" CONFIG="$config" # Validate arguments if [[ ! "$JOBS" =~ ^[0-9]+$ ]] || [[ "$JOBS" -lt 1 ]]; then print_error "Invalid number of jobs: $JOBS" exit 1 fi if [[ ! "$TIMEOUT" =~ ^[0-9]+$ ]] || [[ "$TIMEOUT" -lt 1 ]]; then print_error "Invalid timeout: $TIMEOUT" exit 1 fi if [[ "$FORMAT" != "console" && "$FORMAT" != "json" && "$FORMAT" != "html" ]]; then print_error "Invalid format: $FORMAT. Must be console, json, or html" exit 1 fi } # Setup environment setup_environment() { print_section "Environment Setup" # Ensure we're in the project root cd "$PROJECT_ROOT" print_info "Working directory: $PROJECT_ROOT" # Create necessary directories mkdir -p "$LOG_DIR" "$REPORTS_DIR" # Check if validator exists and build if necessary if [[ ! -f "$VALIDATOR_PATH/target/release/foxhunt-validator" ]]; then print_info "Building foxhunt-validator..." cd "$VALIDATOR_PATH" if [[ "$VERBOSE" == "true" ]]; then cargo build --release else cargo build --release > /dev/null 2>&1 fi if [[ $? -eq 0 ]]; then print_success "Built foxhunt-validator successfully" else print_error "Failed to build foxhunt-validator" exit 1 fi cd "$PROJECT_ROOT" else print_success "Found existing foxhunt-validator" fi # Check Docker availability if not skipping if [[ "$SKIP_DOCKER" == "false" && "$MODE" =~ (all|docker) ]]; then if command -v docker &> /dev/null; then if docker info &> /dev/null; then print_success "Docker is available" else print_warning "Docker daemon is not running - will skip Docker validation" SKIP_DOCKER=true fi else print_warning "Docker not found - will skip Docker validation" SKIP_DOCKER=true fi fi # Display configuration print_info "Configuration:" echo " Mode: $MODE" echo " Jobs: $JOBS" echo " Timeout: ${TIMEOUT}s" echo " Continue on error: $CONTINUE_ON_ERROR" echo " Skip Docker: $SKIP_DOCKER" echo " Verbose: $VERBOSE" echo " Format: $FORMAT" if [[ -n "$OUTPUT" ]]; then echo " Output file: $OUTPUT" fi if [[ -n "$CONFIG" ]]; then echo " Config file: $CONFIG" fi } # Clean build artifacts clean_artifacts() { print_section "Cleaning Build Artifacts" cd "$PROJECT_ROOT" print_info "Running cargo clean..." cargo clean if [[ "$SKIP_DOCKER" == "false" ]]; then print_info "Cleaning Docker build cache..." docker builder prune -f &> /dev/null || true fi print_success "Clean completed" } # Run validation run_validation() { print_section "Running E2E Compilation Validation" cd "$VALIDATOR_PATH" # Prepare command arguments local cmd_args=("$MODE") # Add general arguments cmd_args+=("--workspace" "$PROJECT_ROOT") cmd_args+=("--format" "$FORMAT") cmd_args+=("--jobs" "$JOBS") cmd_args+=("--timeout" "$TIMEOUT") if [[ "$VERBOSE" == "true" ]]; then cmd_args+=("--verbose") fi if [[ "$SKIP_DOCKER" == "true" ]]; then cmd_args+=("--skip-docker") fi if [[ -n "$CONFIG" ]]; then cmd_args+=("--config" "$CONFIG") fi # Add mode-specific arguments if [[ "$MODE" == "all" && "$CONTINUE_ON_ERROR" == "true" ]]; then cmd_args+=("--continue-on-error") fi # Set output file if [[ -n "$OUTPUT" ]]; then cmd_args+=("--output" "$OUTPUT") elif [[ "$FORMAT" != "console" ]]; then local timestamp=$(date +%Y%m%d_%H%M%S) local output_file="$REPORTS_DIR/foxhunt-validation-${timestamp}.${FORMAT}" cmd_args+=("--output" "$output_file") OUTPUT="$output_file" fi print_info "Running: foxhunt-validator ${cmd_args[*]}" echo # Run the validation local start_time=$(date +%s) if cargo run --release -- "${cmd_args[@]}"; then local end_time=$(date +%s) local duration=$((end_time - start_time)) print_success "Validation completed successfully in ${duration}s" if [[ -n "$OUTPUT" && "$FORMAT" != "console" ]]; then print_info "Report saved to: $OUTPUT" fi return 0 else local end_time=$(date +%s) local duration=$((end_time - start_time)) print_error "Validation failed after ${duration}s" if [[ -n "$OUTPUT" && "$FORMAT" != "console" ]]; then print_info "Report saved to: $OUTPUT" fi return 1 fi } # Watch mode implementation run_watch_mode() { print_section "Watch Mode" print_info "Watching for file changes in $PROJECT_ROOT" print_info "Press Ctrl+C to exit" # Check if inotify-tools is available if ! command -v inotifywait &> /dev/null; then print_error "inotifywait not found. Please install inotify-tools:" print_info " Ubuntu/Debian: sudo apt-get install inotify-tools" print_info " RHEL/CentOS: sudo yum install inotify-tools" exit 1 fi local last_run=0 local debounce_time=2 # seconds while true; do # Watch for changes in Rust source files, Cargo.toml, and Dockerfiles inotifywait -r -e modify,create,delete \ --include '\.(rs|toml)$|Dockerfile.*$|\.dockerfile$' \ "$PROJECT_ROOT" &> /dev/null local current_time=$(date +%s) # Debounce rapid changes if [[ $((current_time - last_run)) -gt $debounce_time ]]; then echo print_info "Changes detected, running validation..." if run_validation; then print_success "Validation passed - watching for more changes..." else print_error "Validation failed - fix issues and save to re-run" fi last_run=$current_time echo print_info "Watching for changes... (Press Ctrl+C to exit)" fi done } # Main execution main() { print_header parse_args "$@" setup_environment # Handle special modes case "$MODE" in clean) clean_artifacts exit 0 ;; watch) if [[ "$CLEAN_FIRST" == "true" ]]; then clean_artifacts fi run_watch_mode exit $? ;; *) if [[ "$CLEAN_FIRST" == "true" ]]; then clean_artifacts fi if run_validation; then print_success "All validations completed successfully!" exit 0 else print_error "Some validations failed!" print_info "Check the output above for details" if [[ -n "$OUTPUT" ]]; then print_info "Detailed report available at: $OUTPUT" fi exit 1 fi ;; esac } # Handle script interruption trap 'echo; print_warning "Validation interrupted by user"; exit 130' INT # Ensure we're being run, not sourced if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi