# Rustelo Project Installer for Windows # PowerShell script for installing and setting up Rustelo projects param( [string]$ProjectName = "my-rustelo-app", [string]$Environment = "dev", [string]$InstallDir = "", [switch]$EnableTLS, [switch]$EnableOAuth, [switch]$DisableAuth, [switch]$DisableContentDB, [switch]$SkipDeps, [switch]$Force, [switch]$Quiet, [switch]$Help ) # Set error action preference $ErrorActionPreference = "Stop" # Colors for output $Colors = @{ Red = "Red" Green = "Green" Yellow = "Yellow" Blue = "Blue" Purple = "Magenta" Cyan = "Cyan" White = "White" } # Configuration $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $ProjectRoot = $ScriptDir $TemplateDir = Join-Path $ProjectRoot "template" $InstallLog = Join-Path $ProjectRoot "install.log" # Installation options $ENABLE_AUTH = -not $DisableAuth $ENABLE_CONTENT_DB = -not $DisableContentDB $ENABLE_TLS = $EnableTLS $ENABLE_OAUTH = $EnableOAuth # Dependency versions $RUST_MIN_VERSION = "1.75.0" $NODE_MIN_VERSION = "18.0.0" # Logging functions function Write-Log { param([string]$Message, [string]$Level = "INFO") $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logEntry = "[$timestamp] [$Level] $Message" switch ($Level) { "INFO" { Write-Host "[INFO] $Message" -ForegroundColor $Colors.Green } "WARN" { Write-Host "[WARN] $Message" -ForegroundColor $Colors.Yellow } "ERROR" { Write-Host "[ERROR] $Message" -ForegroundColor $Colors.Red } "DEBUG" { if (-not $Quiet) { Write-Host "[DEBUG] $Message" -ForegroundColor $Colors.Cyan } } } Add-Content -Path $InstallLog -Value $logEntry } function Write-Header { param([string]$Message) Write-Host $Message -ForegroundColor $Colors.Blue } function Write-Step { param([string]$Message) Write-Host "➤ $Message" -ForegroundColor $Colors.Purple } function Write-Success { param([string]$Message) Write-Host "✓ $Message" -ForegroundColor $Colors.Green } function Write-Banner { Write-Host "" Write-Host "╭─────────────────────────────────────────────────────────────╮" -ForegroundColor $Colors.White Write-Host "│ RUSTELO INSTALLER │" -ForegroundColor $Colors.White Write-Host "│ │" -ForegroundColor $Colors.White Write-Host "│ A modern Rust web application framework built with Leptos │" -ForegroundColor $Colors.White Write-Host "│ │" -ForegroundColor $Colors.White Write-Host "╰─────────────────────────────────────────────────────────────╯" -ForegroundColor $Colors.White Write-Host "" } # Function to check if a command exists function Test-Command { param([string]$Command) return (Get-Command $Command -ErrorAction SilentlyContinue) -ne $null } # Function to compare versions function Compare-Version { param([string]$Version1, [string]$Version2) $v1 = [version]$Version1 $v2 = [version]$Version2 return $v1 -ge $v2 } # Function to check system requirements function Test-SystemRequirements { Write-Step "Checking system requirements..." $missingTools = @() if (-not (Test-Command "git")) { $missingTools += "git" } if ($missingTools.Count -gt 0) { Write-Log "Missing required system tools: $($missingTools -join ', ')" -Level "ERROR" Write-Host "Please install these tools before continuing." exit 1 } Write-Success "System requirements check passed" } # Function to install Rust function Install-Rust { Write-Step "Checking Rust installation..." if ((Test-Command "rustc") -and (Test-Command "cargo")) { $rustVersion = (rustc --version).Split()[1] Write-Log "Found Rust version: $rustVersion" -Level "DEBUG" if (Compare-Version $rustVersion $RUST_MIN_VERSION) { Write-Success "Rust $rustVersion is already installed" return } else { Write-Log "Rust version $rustVersion is too old (minimum: $RUST_MIN_VERSION)" -Level "WARN" } } if ($SkipDeps) { Write-Log "Skipping Rust installation due to -SkipDeps flag" -Level "WARN" return } Write-Log "Installing Rust..." # Download and install Rust $rustupUrl = "https://win.rustup.rs/x86_64" $rustupPath = Join-Path $env:TEMP "rustup-init.exe" try { Invoke-WebRequest -Uri $rustupUrl -OutFile $rustupPath & $rustupPath -y # Add Cargo to PATH for current session $env:PATH = "$env:USERPROFILE\.cargo\bin;$env:PATH" # Verify installation if ((Test-Command "rustc") -and (Test-Command "cargo")) { $rustVersion = (rustc --version).Split()[1] Write-Success "Rust $rustVersion installed successfully" } else { Write-Log "Rust installation failed" -Level "ERROR" exit 1 } } catch { Write-Log "Failed to install Rust: $_" -Level "ERROR" exit 1 } finally { if (Test-Path $rustupPath) { Remove-Item $rustupPath -Force } } } # Function to install Node.js function Install-NodeJS { Write-Step "Checking Node.js installation..." if ((Test-Command "node") -and (Test-Command "npm")) { $nodeVersion = (node --version).TrimStart('v') Write-Log "Found Node.js version: $nodeVersion" -Level "DEBUG" if (Compare-Version $nodeVersion $NODE_MIN_VERSION) { Write-Success "Node.js $nodeVersion is already installed" return } else { Write-Log "Node.js version $nodeVersion is too old (minimum: $NODE_MIN_VERSION)" -Level "WARN" } } if ($SkipDeps) { Write-Log "Skipping Node.js installation due to -SkipDeps flag" -Level "WARN" return } Write-Log "Node.js installation required" Write-Host "Please install Node.js manually from https://nodejs.org/" Write-Host "Then run this script again." exit 1 } # Function to install Rust tools function Install-RustTools { Write-Step "Installing Rust tools..." if (Test-Command "cargo-leptos") { Write-Success "cargo-leptos is already installed" } else { Write-Log "Installing cargo-leptos..." cargo install cargo-leptos Write-Success "cargo-leptos installed" } # Install other useful tools $tools = @("cargo-watch", "cargo-audit", "cargo-outdated") foreach ($tool in $tools) { if (Test-Command $tool) { Write-Log "$tool is already installed" -Level "DEBUG" } else { Write-Log "Installing $tool..." try { cargo install $tool } catch { Write-Log "Failed to install $tool" -Level "WARN" } } } } # Function to create project function New-Project { Write-Step "Setting up project: $ProjectName" # Determine installation directory if (-not $InstallDir) { $InstallDir = Join-Path (Get-Location) $ProjectName } # Create project directory if (Test-Path $InstallDir) { if ($Force) { Write-Log "Removing existing project directory: $InstallDir" -Level "WARN" Remove-Item $InstallDir -Recurse -Force } else { Write-Log "Project directory already exists: $InstallDir" -Level "ERROR" Write-Host "Use -Force to overwrite or choose a different name/location" exit 1 } } Write-Log "Creating project directory: $InstallDir" New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null # Copy template files Write-Log "Copying template files..." try { Copy-Item -Path "$TemplateDir\*" -Destination $InstallDir -Recurse -Force } catch { Write-Log "Failed to copy template files: $_" -Level "ERROR" exit 1 } # Copy additional files $readmePath = Join-Path $ProjectRoot "README.md" if (Test-Path $readmePath) { Copy-Item -Path $readmePath -Destination $InstallDir -Force } Write-Success "Project files copied to $InstallDir" } # Function to configure project function Set-ProjectConfiguration { Write-Step "Configuring project..." Set-Location $InstallDir # Create .env file $envPath = ".env" if (-not (Test-Path $envPath)) { Write-Log "Creating .env file..." $sessionSecret = -join ((1..32) | ForEach-Object { [char]((65..90) + (97..122) | Get-Random) }) $envContent = @" # Environment Configuration ENVIRONMENT=$Environment # Server Configuration SERVER_HOST=127.0.0.1 SERVER_PORT=3030 SERVER_PROTOCOL=$( if ($ENABLE_TLS) { "https" } else { "http" } ) # Database Configuration DATABASE_URL=postgresql://dev:dev@localhost:5432/${ProjectName}_${Environment} # Session Configuration SESSION_SECRET=$sessionSecret # Features ENABLE_AUTH=$ENABLE_AUTH ENABLE_CONTENT_DB=$ENABLE_CONTENT_DB ENABLE_TLS=$ENABLE_TLS ENABLE_OAUTH=$ENABLE_OAUTH # OAuth Configuration (if enabled) # GOOGLE_CLIENT_ID= # GOOGLE_CLIENT_SECRET= # GITHUB_CLIENT_ID= # GITHUB_CLIENT_SECRET= # Email Configuration # SMTP_HOST= # SMTP_PORT=587 # SMTP_USERNAME= # SMTP_PASSWORD= # FROM_EMAIL= # FROM_NAME= # Logging LOG_LEVEL=info RUST_LOG=info "@ Set-Content -Path $envPath -Value $envContent Write-Success ".env file created" } else { Write-Log ".env file already exists, skipping creation" -Level "WARN" } # Update Cargo.toml with project name $cargoPath = "Cargo.toml" if (Test-Path $cargoPath) { $content = Get-Content $cargoPath $content = $content -replace 'name = "rustelo"', "name = `"$ProjectName`"" Set-Content -Path $cargoPath -Value $content Write-Log "Updated project name in Cargo.toml" -Level "DEBUG" } # Create necessary directories $dirs = @("public", "uploads", "logs", "cache", "config", "data", "backups") foreach ($dir in $dirs) { if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } } if ($ENABLE_TLS) { if (-not (Test-Path "certs")) { New-Item -ItemType Directory -Path "certs" -Force | Out-Null } Write-Log "Created certs directory for TLS" -Level "DEBUG" } Write-Success "Project configured" } # Function to install dependencies function Install-Dependencies { Write-Step "Installing project dependencies..." Set-Location $InstallDir # Install Rust dependencies Write-Log "Installing Rust dependencies..." try { cargo fetch } catch { Write-Log "Failed to fetch Rust dependencies: $_" -Level "ERROR" exit 1 } # Install Node.js dependencies if (Test-Path "package.json") { Write-Log "Installing Node.js dependencies..." try { if (Test-Command "pnpm") { pnpm install } elseif (Test-Command "npm") { npm install } else { Write-Log "Neither pnpm nor npm found" -Level "ERROR" exit 1 } } catch { Write-Log "Failed to install Node.js dependencies: $_" -Level "ERROR" exit 1 } } Write-Success "Dependencies installed" } # Function to build project function Build-Project { Write-Step "Building project..." Set-Location $InstallDir # Build CSS Write-Log "Building CSS..." try { if (Test-Command "pnpm") { pnpm run build:css } elseif (Test-Command "npm") { npm run build:css } } catch { Write-Log "Failed to build CSS" -Level "WARN" } # Build Rust project Write-Log "Building Rust project..." try { cargo build } catch { Write-Log "Failed to build Rust project: $_" -Level "ERROR" exit 1 } Write-Success "Project built successfully" } # Function to create startup scripts function New-StartupScripts { Write-Step "Creating startup scripts..." Set-Location $InstallDir # Create development start script $startScript = @" @echo off cd /d "%~dp0" cargo leptos watch pause "@ Set-Content -Path "start.bat" -Value $startScript # Create production start script $startProdScript = @" @echo off cd /d "%~dp0" cargo leptos build --release .\target\release\server.exe pause "@ Set-Content -Path "start-prod.bat" -Value $startProdScript # Create PowerShell start script $startPsScript = @" # Start development server Set-Location (Split-Path -Parent `$MyInvocation.MyCommand.Path) cargo leptos watch "@ Set-Content -Path "start.ps1" -Value $startPsScript Write-Success "Startup scripts created" } # Function to display final instructions function Show-Instructions { Write-Host "" Write-Header "╭─────────────────────────────────────────────────────────────╮" Write-Header "│ INSTALLATION COMPLETE │" Write-Header "╰─────────────────────────────────────────────────────────────╯" Write-Host "" Write-Success "Project '$ProjectName' has been successfully installed!" Write-Host "" Write-Host "Project Location: " -NoNewline Write-Host $InstallDir -ForegroundColor $Colors.White Write-Host "Environment: " -NoNewline Write-Host $Environment -ForegroundColor $Colors.White Write-Host "Features:" Write-Host " - Authentication: $ENABLE_AUTH" Write-Host " - Content Database: $ENABLE_CONTENT_DB" Write-Host " - TLS/HTTPS: $ENABLE_TLS" Write-Host " - OAuth: $ENABLE_OAUTH" Write-Host "" Write-Host "Next Steps:" -ForegroundColor $Colors.White Write-Host "1. Navigate to your project:" Write-Host " cd $InstallDir" Write-Host "" Write-Host "2. Review and customize your configuration:" Write-Host " - Edit .env file for environment variables" Write-Host " - Review config.toml for detailed settings" Write-Host "" Write-Host "3. Start the development server:" Write-Host " .\start.bat (or .\start.ps1)" Write-Host " # or manually: cargo leptos watch" Write-Host "" Write-Host "4. Open your browser to:" if ($ENABLE_TLS) { Write-Host " https://127.0.0.1:3030" } else { Write-Host " http://127.0.0.1:3030" } Write-Host "" Write-Host "Available Commands:" -ForegroundColor $Colors.White Write-Host " cargo leptos watch - Start development server with hot reload" Write-Host " cargo leptos build - Build for production" Write-Host " cargo build - Build Rust code only" Write-Host " npm run build:css - Build CSS only" Write-Host " npm run dev - Watch CSS changes" Write-Host "" if ($ENABLE_TLS) { Write-Host "Note: " -ForegroundColor $Colors.Yellow -NoNewline Write-Host "Self-signed certificates were generated for HTTPS." Write-Host "Your browser will show a security warning. This is normal for development." Write-Host "" } if ($Environment -eq "prod") { Write-Host "Production Notes:" -ForegroundColor $Colors.Yellow Write-Host "- Update SESSION_SECRET in .env with a secure value" Write-Host "- Configure your database connection string" Write-Host "- Set up proper TLS certificates for production" Write-Host "- Review all security settings in config.toml" Write-Host "" } Write-Host "Documentation:" -ForegroundColor $Colors.White Write-Host "- README.md - General project information" Write-Host "- CONFIG_README.md - Configuration guide" Write-Host "- DAISYUI_INTEGRATION.md - UI components guide" Write-Host "" Write-Host "Support:" -ForegroundColor $Colors.White Write-Host "- Check the logs: $InstallLog" Write-Host "- Run diagnostics: cargo run --bin config_tool -- validate" Write-Host "" Write-Success "Happy coding with Rustelo! 🚀" } # Function to show usage function Show-Usage { Write-Host "Rustelo Project Installer for Windows" Write-Host "" Write-Host "Usage: .\install.ps1 [OPTIONS]" Write-Host "" Write-Host "Options:" Write-Host " -ProjectName Project name [default: my-rustelo-app]" Write-Host " -Environment Environment (dev, prod) [default: dev]" Write-Host " -InstallDir Installation directory [default: .\]" Write-Host " -EnableTLS Enable TLS/HTTPS support" Write-Host " -EnableOAuth Enable OAuth authentication" Write-Host " -DisableAuth Disable authentication features" Write-Host " -DisableContentDB Disable content database features" Write-Host " -SkipDeps Skip dependency installation" Write-Host " -Force Force reinstallation (overwrite existing)" Write-Host " -Quiet Suppress debug output" Write-Host " -Help Show this help message" Write-Host "" Write-Host "Examples:" Write-Host " .\install.ps1 # Default installation" Write-Host " .\install.ps1 -ProjectName my-blog -EnableTLS # Blog with HTTPS" Write-Host " .\install.ps1 -Environment prod # Production setup" } # Main installation function function Start-Installation { Write-Banner # Initialize log "Installation started at $(Get-Date)" | Out-File -FilePath $InstallLog -Encoding UTF8 # Check if we're in the right directory if (-not (Test-Path $TemplateDir)) { Write-Log "Template directory not found: $TemplateDir" -Level "ERROR" Write-Log "Please run this script from the Rustelo project root" -Level "ERROR" exit 1 } # Run installation steps Test-SystemRequirements Install-Rust Install-NodeJS Install-RustTools New-Project Set-ProjectConfiguration Install-Dependencies Build-Project New-StartupScripts # Display final instructions Show-Instructions Write-Log "Installation completed successfully at $(Get-Date)" } # Main execution if ($Help) { Show-Usage exit 0 } # Validate parameters if ($Environment -notin @("dev", "prod")) { Write-Log "Invalid environment: $Environment" -Level "ERROR" exit 1 } # Run main installation try { Start-Installation } catch { Write-Log "Installation failed: $_" -Level "ERROR" exit 1 }