Rustelo/scripts/setup/install.ps1

622 lines
19 KiB
PowerShell
Raw Normal View History

2025-07-07 23:53:50 +01:00
# 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 <name> Project name [default: my-rustelo-app]"
Write-Host " -Environment <env> Environment (dev, prod) [default: dev]"
Write-Host " -InstallDir <path> Installation directory [default: .\<project-name>]"
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
}