967 lines
28 KiB
Bash
967 lines
28 KiB
Bash
![]() |
#!/bin/bash
|
||
|
|
||
|
# Rustelo Unified Installer
|
||
|
# Single installation script for all environments and modes
|
||
|
# Supports development, production, and custom installations
|
||
|
|
||
|
set -e
|
||
|
|
||
|
# 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'
|
||
|
WHITE='\033[1;37m'
|
||
|
NC='\033[0m' # No Color
|
||
|
|
||
|
# Default configuration (can be overridden by environment variables or arguments)
|
||
|
INSTALL_MODE="${INSTALL_MODE:-dev}" # dev, prod, or custom
|
||
|
PROJECT_NAME="${PROJECT_NAME:-my-rustelo-app}"
|
||
|
ENVIRONMENT="${ENVIRONMENT:-dev}" # dev or prod
|
||
|
ENABLE_TLS="${ENABLE_TLS:-false}"
|
||
|
ENABLE_AUTH="${ENABLE_AUTH:-true}"
|
||
|
ENABLE_CONTENT_DB="${ENABLE_CONTENT_DB:-true}"
|
||
|
ENABLE_OAUTH="${ENABLE_OAUTH:-false}"
|
||
|
SKIP_DEPS="${SKIP_DEPS:-false}"
|
||
|
FORCE_REINSTALL="${FORCE_REINSTALL:-false}"
|
||
|
QUIET="${QUIET:-false}"
|
||
|
INSTALL_DIR="${INSTALL_DIR:-}"
|
||
|
|
||
|
# Script configuration
|
||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
PROJECT_ROOT="$SCRIPT_DIR"
|
||
|
TEMPLATE_DIR="$PROJECT_ROOT/template"
|
||
|
INSTALL_LOG="$PROJECT_ROOT/install.log"
|
||
|
TEMP_DIR=$(mktemp -d)
|
||
|
|
||
|
# Dependency versions
|
||
|
RUST_MIN_VERSION="1.75.0"
|
||
|
NODE_MIN_VERSION="18.0.0"
|
||
|
|
||
|
# Trap to cleanup on exit
|
||
|
trap cleanup EXIT
|
||
|
|
||
|
cleanup() {
|
||
|
if [ -d "$TEMP_DIR" ]; then
|
||
|
rm -rf "$TEMP_DIR"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Logging functions
|
||
|
log() {
|
||
|
echo -e "${GREEN}[INFO]${NC} $1" | tee -a "$INSTALL_LOG"
|
||
|
}
|
||
|
|
||
|
log_warn() {
|
||
|
echo -e "${YELLOW}[WARN]${NC} $1" | tee -a "$INSTALL_LOG"
|
||
|
}
|
||
|
|
||
|
log_error() {
|
||
|
echo -e "${RED}[ERROR]${NC} $1" | tee -a "$INSTALL_LOG"
|
||
|
}
|
||
|
|
||
|
log_debug() {
|
||
|
if [ "$QUIET" != "true" ]; then
|
||
|
echo -e "${CYAN}[DEBUG]${NC} $1" | tee -a "$INSTALL_LOG"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
print_header() {
|
||
|
echo -e "${BLUE}$1${NC}"
|
||
|
}
|
||
|
|
||
|
print_step() {
|
||
|
echo -e "${PURPLE}➤${NC} $1"
|
||
|
}
|
||
|
|
||
|
print_success() {
|
||
|
echo -e "${GREEN}✓${NC} $1"
|
||
|
}
|
||
|
|
||
|
print_banner() {
|
||
|
echo -e "${WHITE}"
|
||
|
echo "╭─────────────────────────────────────────────────────────────╮"
|
||
|
echo "│ RUSTELO INSTALLER │"
|
||
|
echo "│ │"
|
||
|
echo "│ A modern Rust web application framework built with Leptos │"
|
||
|
echo "│ │"
|
||
|
echo "╰─────────────────────────────────────────────────────────────╯"
|
||
|
echo -e "${NC}"
|
||
|
}
|
||
|
|
||
|
# Version comparison function
|
||
|
version_compare() {
|
||
|
local version1="$1"
|
||
|
local version2="$2"
|
||
|
|
||
|
# Convert versions to comparable format
|
||
|
local IFS=.
|
||
|
local ver1=($version1)
|
||
|
local ver2=($version2)
|
||
|
|
||
|
# Compare major version
|
||
|
if [ ${ver1[0]} -gt ${ver2[0]} ]; then
|
||
|
return 0
|
||
|
elif [ ${ver1[0]} -lt ${ver2[0]} ]; then
|
||
|
return 1
|
||
|
fi
|
||
|
|
||
|
# Compare minor version
|
||
|
if [ ${ver1[1]} -gt ${ver2[1]} ]; then
|
||
|
return 0
|
||
|
elif [ ${ver1[1]} -lt ${ver2[1]} ]; then
|
||
|
return 1
|
||
|
fi
|
||
|
|
||
|
# Compare patch version
|
||
|
if [ ${ver1[2]} -ge ${ver2[2]} ]; then
|
||
|
return 0
|
||
|
else
|
||
|
return 1
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Function to check if a command exists
|
||
|
command_exists() {
|
||
|
command -v "$1" >/dev/null 2>&1
|
||
|
}
|
||
|
|
||
|
# Function to get system information
|
||
|
get_system_info() {
|
||
|
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||
|
echo "linux"
|
||
|
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||
|
echo "macos"
|
||
|
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
|
||
|
echo "windows"
|
||
|
else
|
||
|
echo "unknown"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Function to check system requirements
|
||
|
check_system_requirements() {
|
||
|
print_step "Checking system requirements..."
|
||
|
|
||
|
local system=$(get_system_info)
|
||
|
log_debug "Detected system: $system"
|
||
|
|
||
|
# Check for required tools
|
||
|
local missing_tools=()
|
||
|
|
||
|
if ! command_exists "curl" && ! command_exists "wget"; then
|
||
|
missing_tools+=("curl or wget")
|
||
|
fi
|
||
|
|
||
|
if ! command_exists "git"; then
|
||
|
missing_tools+=("git")
|
||
|
fi
|
||
|
|
||
|
if ! command_exists "openssl"; then
|
||
|
missing_tools+=("openssl")
|
||
|
fi
|
||
|
|
||
|
if [ ${#missing_tools[@]} -gt 0 ]; then
|
||
|
log_error "Missing required system tools: ${missing_tools[*]}"
|
||
|
echo "Please install these tools before continuing."
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
print_success "System requirements check passed"
|
||
|
}
|
||
|
|
||
|
# Function to install Rust
|
||
|
install_rust() {
|
||
|
print_step "Checking Rust installation..."
|
||
|
|
||
|
if command_exists "rustc" && command_exists "cargo"; then
|
||
|
local rust_version=$(rustc --version | cut -d' ' -f2)
|
||
|
log_debug "Found Rust version: $rust_version"
|
||
|
|
||
|
if version_compare "$rust_version" "$RUST_MIN_VERSION"; then
|
||
|
print_success "Rust $rust_version is already installed"
|
||
|
return 0
|
||
|
else
|
||
|
log_warn "Rust version $rust_version is too old (minimum: $RUST_MIN_VERSION)"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
if [ "$SKIP_DEPS" = "true" ]; then
|
||
|
log_warn "Skipping Rust installation due to --skip-deps flag"
|
||
|
return 0
|
||
|
fi
|
||
|
|
||
|
log "Installing Rust..."
|
||
|
|
||
|
# Download and install Rust
|
||
|
if command_exists "curl"; then
|
||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||
|
elif command_exists "wget"; then
|
||
|
wget -qO- https://sh.rustup.rs | sh -s -- -y
|
||
|
else
|
||
|
log_error "Neither curl nor wget found for Rust installation"
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
# Source the cargo environment
|
||
|
source "$HOME/.cargo/env"
|
||
|
|
||
|
# Verify installation
|
||
|
if command_exists "rustc" && command_exists "cargo"; then
|
||
|
local rust_version=$(rustc --version | cut -d' ' -f2)
|
||
|
print_success "Rust $rust_version installed successfully"
|
||
|
else
|
||
|
log_error "Rust installation failed"
|
||
|
exit 1
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Function to install Node.js
|
||
|
install_nodejs() {
|
||
|
print_step "Checking Node.js installation..."
|
||
|
|
||
|
if command_exists "node" && command_exists "npm"; then
|
||
|
local node_version=$(node --version | sed 's/v//')
|
||
|
log_debug "Found Node.js version: $node_version"
|
||
|
|
||
|
if version_compare "$node_version" "$NODE_MIN_VERSION"; then
|
||
|
print_success "Node.js $node_version is already installed"
|
||
|
return 0
|
||
|
else
|
||
|
log_warn "Node.js version $node_version is too old (minimum: $NODE_MIN_VERSION)"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
if [ "$SKIP_DEPS" = "true" ]; then
|
||
|
log_warn "Skipping Node.js installation due to --skip-deps flag"
|
||
|
return 0
|
||
|
fi
|
||
|
|
||
|
log "Installing Node.js..."
|
||
|
|
||
|
local system=$(get_system_info)
|
||
|
|
||
|
case $system in
|
||
|
"linux")
|
||
|
# Install Node.js via NodeSource repository
|
||
|
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
|
||
|
sudo apt-get install -y nodejs
|
||
|
;;
|
||
|
"macos")
|
||
|
# Install Node.js via Homebrew if available, otherwise download
|
||
|
if command_exists "brew"; then
|
||
|
brew install node
|
||
|
else
|
||
|
log_warn "Homebrew not found. Please install Node.js manually from https://nodejs.org/"
|
||
|
exit 1
|
||
|
fi
|
||
|
;;
|
||
|
"windows")
|
||
|
log_warn "Please install Node.js manually from https://nodejs.org/"
|
||
|
exit 1
|
||
|
;;
|
||
|
*)
|
||
|
log_warn "Unknown system. Please install Node.js manually from https://nodejs.org/"
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
|
||
|
# Verify installation
|
||
|
if command_exists "node" && command_exists "npm"; then
|
||
|
local node_version=$(node --version | sed 's/v//')
|
||
|
print_success "Node.js $node_version installed successfully"
|
||
|
else
|
||
|
log_error "Node.js installation failed"
|
||
|
exit 1
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Function to install Rust tools
|
||
|
install_rust_tools() {
|
||
|
print_step "Installing Rust tools..."
|
||
|
|
||
|
# Install cargo-leptos
|
||
|
if command_exists "cargo-leptos"; then
|
||
|
print_success "cargo-leptos is already installed"
|
||
|
else
|
||
|
log "Installing cargo-leptos..."
|
||
|
cargo install cargo-leptos
|
||
|
print_success "cargo-leptos installed"
|
||
|
fi
|
||
|
|
||
|
# Install mdBook (required for documentation)
|
||
|
if command_exists "mdbook"; then
|
||
|
print_success "mdbook is already installed"
|
||
|
else
|
||
|
log "Installing mdbook..."
|
||
|
cargo install mdbook
|
||
|
print_success "mdbook installed"
|
||
|
fi
|
||
|
|
||
|
# Install Just (task runner)
|
||
|
if command_exists "just"; then
|
||
|
print_success "just is already installed"
|
||
|
else
|
||
|
log "Installing just..."
|
||
|
cargo install just
|
||
|
print_success "just installed"
|
||
|
fi
|
||
|
|
||
|
# Install mdBook plugins for enhanced documentation
|
||
|
log "Installing mdBook plugins..."
|
||
|
local mdbook_plugins=("mdbook-linkcheck" "mdbook-toc" "mdbook-mermaid")
|
||
|
for plugin in "${mdbook_plugins[@]}"; do
|
||
|
if command_exists "$plugin"; then
|
||
|
log_debug "$plugin is already installed"
|
||
|
else
|
||
|
log "Installing $plugin..."
|
||
|
cargo install "$plugin" || log_warn "Failed to install $plugin (optional)"
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
# Install other useful tools (only in dev mode or if explicitly requested)
|
||
|
if [ "$INSTALL_MODE" = "dev" ] || [ "$ENVIRONMENT" = "dev" ]; then
|
||
|
local tools=("cargo-watch" "cargo-audit" "cargo-outdated")
|
||
|
|
||
|
for tool in "${tools[@]}"; do
|
||
|
if command_exists "$tool"; then
|
||
|
log_debug "$tool is already installed"
|
||
|
else
|
||
|
log "Installing $tool..."
|
||
|
cargo install "$tool" || log_warn "Failed to install $tool"
|
||
|
fi
|
||
|
done
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Function to create project directory
|
||
|
create_project() {
|
||
|
print_step "Setting up project: $PROJECT_NAME"
|
||
|
|
||
|
# Determine installation directory
|
||
|
if [ -z "$INSTALL_DIR" ]; then
|
||
|
INSTALL_DIR="$PWD/$PROJECT_NAME"
|
||
|
fi
|
||
|
|
||
|
# Create project directory
|
||
|
if [ -d "$INSTALL_DIR" ]; then
|
||
|
if [ "$FORCE_REINSTALL" = "true" ]; then
|
||
|
log_warn "Removing existing project directory: $INSTALL_DIR"
|
||
|
rm -rf "$INSTALL_DIR"
|
||
|
else
|
||
|
log_error "Project directory already exists: $INSTALL_DIR"
|
||
|
echo "Use --force to overwrite or choose a different name/location"
|
||
|
exit 1
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
log "Creating project directory: $INSTALL_DIR"
|
||
|
mkdir -p "$INSTALL_DIR"
|
||
|
|
||
|
# Copy template files
|
||
|
log "Copying template files..."
|
||
|
cp -r "$TEMPLATE_DIR"/* "$INSTALL_DIR"/ || {
|
||
|
log_error "Failed to copy template files"
|
||
|
exit 1
|
||
|
}
|
||
|
|
||
|
# Copy additional files
|
||
|
if [ -f "$PROJECT_ROOT/README.md" ]; then
|
||
|
cp "$PROJECT_ROOT/README.md" "$INSTALL_DIR/"
|
||
|
fi
|
||
|
|
||
|
print_success "Project files copied to $INSTALL_DIR"
|
||
|
}
|
||
|
|
||
|
# Function to configure project
|
||
|
configure_project() {
|
||
|
print_step "Configuring project..."
|
||
|
|
||
|
cd "$INSTALL_DIR"
|
||
|
|
||
|
# Create .env file
|
||
|
if [ ! -f ".env" ]; then
|
||
|
log "Creating .env file..."
|
||
|
cat > ".env" << EOF
|
||
|
# Environment Configuration
|
||
|
ENVIRONMENT=$ENVIRONMENT
|
||
|
|
||
|
# Server Configuration
|
||
|
SERVER_HOST=$([ "$ENVIRONMENT" = "dev" ] && echo "127.0.0.1" || echo "0.0.0.0")
|
||
|
SERVER_PORT=$([ "$ENVIRONMENT" = "dev" ] && echo "3030" || echo "443")
|
||
|
SERVER_PROTOCOL=$([ "$ENABLE_TLS" = "true" ] && echo "https" || echo "http")
|
||
|
|
||
|
# Database Configuration
|
||
|
DATABASE_URL=postgresql://$([ "$ENVIRONMENT" = "dev" ] && echo "dev:dev@localhost:5432/${PROJECT_NAME}_dev" || echo "prod:\${DATABASE_PASSWORD}@db.example.com:5432/${PROJECT_NAME}_prod")
|
||
|
|
||
|
# Session Configuration
|
||
|
SESSION_SECRET=$([ "$ENVIRONMENT" = "dev" ] && echo "dev-secret-not-for-production" || echo "$(openssl rand -base64 32)")
|
||
|
|
||
|
# Features
|
||
|
ENABLE_AUTH=$ENABLE_AUTH
|
||
|
ENABLE_CONTENT_DB=$ENABLE_CONTENT_DB
|
||
|
ENABLE_TLS=$ENABLE_TLS
|
||
|
ENABLE_OAUTH=$ENABLE_OAUTH
|
||
|
|
||
|
# OAuth Configuration (if enabled)
|
||
|
$([ "$ENABLE_OAUTH" = "true" ] && echo "GOOGLE_CLIENT_ID=" || echo "# GOOGLE_CLIENT_ID=")
|
||
|
$([ "$ENABLE_OAUTH" = "true" ] && echo "GOOGLE_CLIENT_SECRET=" || echo "# GOOGLE_CLIENT_SECRET=")
|
||
|
$([ "$ENABLE_OAUTH" = "true" ] && echo "GITHUB_CLIENT_ID=" || echo "# GITHUB_CLIENT_ID=")
|
||
|
$([ "$ENABLE_OAUTH" = "true" ] && echo "GITHUB_CLIENT_SECRET=" || echo "# GITHUB_CLIENT_SECRET=")
|
||
|
|
||
|
# Email Configuration
|
||
|
# SMTP_HOST=
|
||
|
# SMTP_PORT=587
|
||
|
# SMTP_USERNAME=
|
||
|
# SMTP_PASSWORD=
|
||
|
# FROM_EMAIL=
|
||
|
# FROM_NAME=
|
||
|
|
||
|
# Logging
|
||
|
LOG_LEVEL=$([ "$ENVIRONMENT" = "dev" ] && echo "debug" || echo "info")
|
||
|
RUST_LOG=$([ "$ENVIRONMENT" = "dev" ] && echo "debug" || echo "info")
|
||
|
EOF
|
||
|
print_success ".env file created"
|
||
|
else
|
||
|
log_warn ".env file already exists, skipping creation"
|
||
|
fi
|
||
|
|
||
|
# Update Cargo.toml with project name
|
||
|
if [ -f "Cargo.toml" ]; then
|
||
|
sed -i.bak "s/name = \"rustelo\"/name = \"$PROJECT_NAME\"/" Cargo.toml
|
||
|
rm -f Cargo.toml.bak
|
||
|
log_debug "Updated project name in Cargo.toml"
|
||
|
fi
|
||
|
|
||
|
# Create necessary directories
|
||
|
mkdir -p public uploads logs cache config data
|
||
|
|
||
|
# Create additional directories for production
|
||
|
if [ "$ENVIRONMENT" = "prod" ]; then
|
||
|
mkdir -p backups
|
||
|
fi
|
||
|
|
||
|
if [ "$ENABLE_TLS" = "true" ]; then
|
||
|
mkdir -p certs
|
||
|
log_debug "Created certs directory for TLS"
|
||
|
fi
|
||
|
|
||
|
print_success "Project configured"
|
||
|
}
|
||
|
|
||
|
# Function to install dependencies
|
||
|
install_dependencies() {
|
||
|
print_step "Installing project dependencies..."
|
||
|
|
||
|
cd "$INSTALL_DIR"
|
||
|
|
||
|
# Install Rust dependencies
|
||
|
log "Installing Rust dependencies..."
|
||
|
cargo fetch || {
|
||
|
log_error "Failed to fetch Rust dependencies"
|
||
|
exit 1
|
||
|
}
|
||
|
|
||
|
# Install Node.js dependencies
|
||
|
if [ -f "package.json" ]; then
|
||
|
log "Installing Node.js dependencies..."
|
||
|
|
||
|
# Prefer pnpm, then npm
|
||
|
if command_exists "pnpm"; then
|
||
|
pnpm install || {
|
||
|
log_error "Failed to install Node.js dependencies with pnpm"
|
||
|
exit 1
|
||
|
}
|
||
|
elif command_exists "npm"; then
|
||
|
npm install || {
|
||
|
log_error "Failed to install Node.js dependencies with npm"
|
||
|
exit 1
|
||
|
}
|
||
|
else
|
||
|
log_error "Neither pnpm nor npm found"
|
||
|
exit 1
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
print_success "Dependencies installed"
|
||
|
}
|
||
|
|
||
|
# Function to build the project
|
||
|
build_project() {
|
||
|
print_step "Building project..."
|
||
|
|
||
|
cd "$INSTALL_DIR"
|
||
|
|
||
|
# Build CSS
|
||
|
log "Building CSS..."
|
||
|
if command_exists "pnpm"; then
|
||
|
pnpm run build:css || log_warn "Failed to build CSS"
|
||
|
elif command_exists "npm"; then
|
||
|
npm run build:css || log_warn "Failed to build CSS"
|
||
|
fi
|
||
|
|
||
|
# Build Rust project
|
||
|
log "Building Rust project..."
|
||
|
if [ "$ENVIRONMENT" = "prod" ]; then
|
||
|
cargo build --release || {
|
||
|
log_error "Failed to build Rust project"
|
||
|
exit 1
|
||
|
}
|
||
|
else
|
||
|
cargo build || {
|
||
|
log_error "Failed to build Rust project"
|
||
|
exit 1
|
||
|
}
|
||
|
fi
|
||
|
|
||
|
print_success "Project built successfully"
|
||
|
}
|
||
|
|
||
|
# Function to generate TLS certificates
|
||
|
generate_tls_certs() {
|
||
|
if [ "$ENABLE_TLS" != "true" ]; then
|
||
|
return 0
|
||
|
fi
|
||
|
|
||
|
print_step "Generating TLS certificates..."
|
||
|
|
||
|
cd "$INSTALL_DIR"
|
||
|
|
||
|
if [ -f "certs/server.crt" ] && [ -f "certs/server.key" ]; then
|
||
|
log_warn "TLS certificates already exist, skipping generation"
|
||
|
return 0
|
||
|
fi
|
||
|
|
||
|
if [ -f "scripts/generate_certs.sh" ]; then
|
||
|
log "Running certificate generation script..."
|
||
|
cd scripts
|
||
|
./generate_certs.sh
|
||
|
cd ..
|
||
|
print_success "TLS certificates generated"
|
||
|
else
|
||
|
log "Generating self-signed certificates..."
|
||
|
openssl req -x509 -newkey rsa:4096 -keyout certs/server.key -out certs/server.crt -days 365 -nodes -subj "/CN=localhost"
|
||
|
print_success "Self-signed TLS certificates generated"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Function to create startup scripts
|
||
|
create_startup_scripts() {
|
||
|
print_step "Creating startup scripts..."
|
||
|
|
||
|
cd "$INSTALL_DIR"
|
||
|
|
||
|
# Create development start script
|
||
|
cat > "start.sh" << EOF
|
||
|
#!/bin/bash
|
||
|
cd "\$(dirname "\$0")"
|
||
|
cargo leptos watch
|
||
|
EOF
|
||
|
chmod +x "start.sh"
|
||
|
|
||
|
# Create production start script
|
||
|
cat > "start-prod.sh" << EOF
|
||
|
#!/bin/bash
|
||
|
cd "\$(dirname "\$0")"
|
||
|
cargo leptos build --release
|
||
|
./target/release/server
|
||
|
EOF
|
||
|
chmod +x "start-prod.sh"
|
||
|
|
||
|
# Create build script
|
||
|
cat > "build.sh" << EOF
|
||
|
#!/bin/bash
|
||
|
cd "\$(dirname "\$0")"
|
||
|
cargo leptos build --release
|
||
|
EOF
|
||
|
chmod +x "build.sh"
|
||
|
|
||
|
print_success "Startup scripts created"
|
||
|
}
|
||
|
|
||
|
# Function to run setup scripts
|
||
|
run_setup_scripts() {
|
||
|
print_step "Running setup scripts..."
|
||
|
|
||
|
cd "$INSTALL_DIR"
|
||
|
|
||
|
# Run configuration setup
|
||
|
if [ -f "scripts/setup-config.sh" ]; then
|
||
|
log "Running configuration setup..."
|
||
|
bash scripts/setup-config.sh -e "$ENVIRONMENT" -f || log_warn "Configuration setup failed"
|
||
|
fi
|
||
|
|
||
|
# Run feature configuration
|
||
|
if [ -f "scripts/configure-features.sh" ]; then
|
||
|
log "Configuring features..."
|
||
|
bash scripts/configure-features.sh || log_warn "Feature configuration failed"
|
||
|
fi
|
||
|
|
||
|
print_success "Setup scripts completed"
|
||
|
}
|
||
|
|
||
|
# Function to display final instructions
|
||
|
display_instructions() {
|
||
|
echo
|
||
|
print_header "╭─────────────────────────────────────────────────────────────╮"
|
||
|
print_header "│ INSTALLATION COMPLETE │"
|
||
|
print_header "╰─────────────────────────────────────────────────────────────╯"
|
||
|
echo
|
||
|
|
||
|
print_success "Project '$PROJECT_NAME' has been successfully installed!"
|
||
|
echo
|
||
|
echo -e "${WHITE}Installation Details:${NC}"
|
||
|
echo " Mode: $INSTALL_MODE"
|
||
|
echo " Environment: $ENVIRONMENT"
|
||
|
echo " Location: $INSTALL_DIR"
|
||
|
echo " Features:"
|
||
|
echo " - Authentication: $ENABLE_AUTH"
|
||
|
echo " - Content Database: $ENABLE_CONTENT_DB"
|
||
|
echo " - TLS/HTTPS: $ENABLE_TLS"
|
||
|
echo " - OAuth: $ENABLE_OAUTH"
|
||
|
echo
|
||
|
echo -e "${WHITE}Quick Start:${NC}"
|
||
|
echo "1. cd $INSTALL_DIR"
|
||
|
echo "2. ./start.sh"
|
||
|
echo "3. Open $([ "$ENABLE_TLS" = "true" ] && echo "https" || echo "http")://127.0.0.1:3030"
|
||
|
echo
|
||
|
echo -e "${WHITE}Available Commands:${NC}"
|
||
|
echo " ./start.sh - Start development server"
|
||
|
echo " ./start-prod.sh - Start production server"
|
||
|
echo " ./build.sh - Build for production"
|
||
|
echo " cargo leptos watch - Development with hot reload"
|
||
|
echo " cargo leptos build - Build project"
|
||
|
echo " cargo build - Build Rust code only"
|
||
|
echo " npm run dev - Watch CSS changes"
|
||
|
echo ""
|
||
|
echo -e "${WHITE}Documentation Commands:${NC}"
|
||
|
echo " just docs-dev - Start documentation server"
|
||
|
echo " just docs-build - Build documentation"
|
||
|
echo " just docs-deploy-github - Deploy to GitHub Pages"
|
||
|
echo " just help-docs - Show all documentation commands"
|
||
|
echo ""
|
||
|
echo -e "${WHITE}Task Runner Commands:${NC}"
|
||
|
echo " just dev - Start development server"
|
||
|
echo " just build - Build project"
|
||
|
echo " just test - Run tests"
|
||
|
echo " just verify-setup - Verify installation"
|
||
|
echo " just help - Show all available commands"
|
||
|
echo
|
||
|
echo -e "${WHITE}Configuration Files:${NC}"
|
||
|
echo " .env - Environment variables"
|
||
|
echo " Cargo.toml - Rust dependencies"
|
||
|
echo " package.json - Node.js dependencies"
|
||
|
echo
|
||
|
if [ "$ENABLE_TLS" = "true" ]; then
|
||
|
echo -e "${YELLOW}Note:${NC} Self-signed certificates were generated for HTTPS."
|
||
|
echo "Your browser will show a security warning for development."
|
||
|
echo
|
||
|
fi
|
||
|
|
||
|
if [ "$ENVIRONMENT" = "prod" ]; then
|
||
|
echo -e "${YELLOW}Production Checklist:${NC}"
|
||
|
echo "□ Update SESSION_SECRET in .env"
|
||
|
echo "□ Configure database connection"
|
||
|
echo "□ Set up proper TLS certificates"
|
||
|
echo "□ Review security settings"
|
||
|
echo "□ Configure OAuth providers (if enabled)"
|
||
|
echo
|
||
|
fi
|
||
|
|
||
|
echo -e "${WHITE}Verification:${NC}"
|
||
|
echo "Run 'just verify-setup' to verify your installation."
|
||
|
echo ""
|
||
|
echo -e "${WHITE}Setup Report:${NC}"
|
||
|
echo "Check 'SETUP_COMPLETE.md' for a detailed setup summary."
|
||
|
echo ""
|
||
|
print_success "Happy coding with Rustelo! 🚀"
|
||
|
}
|
||
|
|
||
|
# Function to show usage information
|
||
|
show_usage() {
|
||
|
echo "Rustelo Unified Installer"
|
||
|
echo
|
||
|
echo "Usage: $0 [OPTIONS]"
|
||
|
echo
|
||
|
echo "Options:"
|
||
|
echo " -h, --help Show this help message"
|
||
|
echo " -m, --mode MODE Installation mode (dev, prod, custom) [default: dev]"
|
||
|
echo " -n, --name NAME Project name [default: my-rustelo-app]"
|
||
|
echo " -e, --env ENV Environment (dev, prod) [default: dev]"
|
||
|
echo " -d, --dir DIR Installation directory [default: ./<project-name>]"
|
||
|
echo " --enable-tls Enable TLS/HTTPS support"
|
||
|
echo " --enable-oauth Enable OAuth authentication"
|
||
|
echo " --disable-auth Disable authentication features"
|
||
|
echo " --disable-content-db Disable content database features"
|
||
|
echo " --skip-deps Skip dependency installation"
|
||
|
echo " --force Force reinstallation (overwrite existing)"
|
||
|
echo " --quiet Suppress debug output"
|
||
|
echo
|
||
|
echo "Installation Modes:"
|
||
|
echo " dev - Development setup with debugging enabled"
|
||
|
echo " prod - Production setup with optimizations"
|
||
|
echo " custom - Interactive configuration selection"
|
||
|
echo
|
||
|
echo "Environment Variables:"
|
||
|
echo " INSTALL_MODE Installation mode (dev/prod/custom)"
|
||
|
echo " PROJECT_NAME Project name"
|
||
|
echo " ENVIRONMENT Environment (dev/prod)"
|
||
|
echo " ENABLE_TLS Enable TLS (true/false)"
|
||
|
echo " ENABLE_AUTH Enable authentication (true/false)"
|
||
|
echo " ENABLE_CONTENT_DB Enable content database (true/false)"
|
||
|
echo " ENABLE_OAUTH Enable OAuth (true/false)"
|
||
|
echo " SKIP_DEPS Skip dependencies (true/false)"
|
||
|
echo " FORCE_REINSTALL Force reinstall (true/false)"
|
||
|
echo " QUIET Quiet mode (true/false)"
|
||
|
echo
|
||
|
echo "Examples:"
|
||
|
echo " $0 # Quick dev setup"
|
||
|
echo " $0 -m prod -n my-app --enable-tls # Production with HTTPS"
|
||
|
echo " $0 -m custom # Interactive setup"
|
||
|
echo " INSTALL_MODE=prod $0 # Using environment variable"
|
||
|
echo " $0 --force -n existing-project # Force reinstall"
|
||
|
}
|
||
|
|
||
|
# Function for custom installation
|
||
|
custom_install() {
|
||
|
print_header "Custom Installation Configuration"
|
||
|
echo
|
||
|
|
||
|
# Project name
|
||
|
echo -n "Project name [$PROJECT_NAME]: "
|
||
|
read -r input
|
||
|
if [ -n "$input" ]; then
|
||
|
PROJECT_NAME="$input"
|
||
|
fi
|
||
|
|
||
|
# Environment
|
||
|
echo -n "Environment (dev/prod) [$ENVIRONMENT]: "
|
||
|
read -r input
|
||
|
if [ -n "$input" ]; then
|
||
|
ENVIRONMENT="$input"
|
||
|
fi
|
||
|
|
||
|
# Features
|
||
|
echo -n "Enable authentication? (Y/n): "
|
||
|
read -r input
|
||
|
if [[ "$input" =~ ^[Nn]$ ]]; then
|
||
|
ENABLE_AUTH="false"
|
||
|
else
|
||
|
ENABLE_AUTH="true"
|
||
|
fi
|
||
|
|
||
|
echo -n "Enable content database? (Y/n): "
|
||
|
read -r input
|
||
|
if [[ "$input" =~ ^[Nn]$ ]]; then
|
||
|
ENABLE_CONTENT_DB="false"
|
||
|
else
|
||
|
ENABLE_CONTENT_DB="true"
|
||
|
fi
|
||
|
|
||
|
echo -n "Enable TLS/HTTPS? (y/N): "
|
||
|
read -r input
|
||
|
if [[ "$input" =~ ^[Yy]$ ]]; then
|
||
|
ENABLE_TLS="true"
|
||
|
else
|
||
|
ENABLE_TLS="false"
|
||
|
fi
|
||
|
|
||
|
if [ "$ENABLE_AUTH" = "true" ]; then
|
||
|
echo -n "Enable OAuth authentication? (y/N): "
|
||
|
read -r input
|
||
|
if [[ "$input" =~ ^[Yy]$ ]]; then
|
||
|
ENABLE_OAUTH="true"
|
||
|
else
|
||
|
ENABLE_OAUTH="false"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
echo -n "Skip dependency installation? (y/N): "
|
||
|
read -r input
|
||
|
if [[ "$input" =~ ^[Yy]$ ]]; then
|
||
|
SKIP_DEPS="true"
|
||
|
else
|
||
|
SKIP_DEPS="false"
|
||
|
fi
|
||
|
|
||
|
echo
|
||
|
echo "Configuration Summary:"
|
||
|
echo " Project Name: $PROJECT_NAME"
|
||
|
echo " Environment: $ENVIRONMENT"
|
||
|
echo " Authentication: $ENABLE_AUTH"
|
||
|
echo " Content Database: $ENABLE_CONTENT_DB"
|
||
|
echo " TLS/HTTPS: $ENABLE_TLS"
|
||
|
echo " OAuth: $ENABLE_OAUTH"
|
||
|
echo " Skip Dependencies: $SKIP_DEPS"
|
||
|
echo
|
||
|
echo -n "Proceed with installation? (Y/n): "
|
||
|
read -r input
|
||
|
if [[ "$input" =~ ^[Nn]$ ]]; then
|
||
|
echo "Installation cancelled."
|
||
|
exit 0
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# Parse command line arguments
|
||
|
while [[ $# -gt 0 ]]; do
|
||
|
case $1 in
|
||
|
-h|--help)
|
||
|
show_usage
|
||
|
exit 0
|
||
|
;;
|
||
|
-m|--mode)
|
||
|
INSTALL_MODE="$2"
|
||
|
shift 2
|
||
|
;;
|
||
|
-n|--name)
|
||
|
PROJECT_NAME="$2"
|
||
|
shift 2
|
||
|
;;
|
||
|
-e|--env)
|
||
|
ENVIRONMENT="$2"
|
||
|
shift 2
|
||
|
;;
|
||
|
-d|--dir)
|
||
|
INSTALL_DIR="$2"
|
||
|
shift 2
|
||
|
;;
|
||
|
--enable-tls)
|
||
|
ENABLE_TLS="true"
|
||
|
shift
|
||
|
;;
|
||
|
--enable-oauth)
|
||
|
ENABLE_OAUTH="true"
|
||
|
shift
|
||
|
;;
|
||
|
--disable-auth)
|
||
|
ENABLE_AUTH="false"
|
||
|
shift
|
||
|
;;
|
||
|
--disable-content-db)
|
||
|
ENABLE_CONTENT_DB="false"
|
||
|
shift
|
||
|
;;
|
||
|
--skip-deps)
|
||
|
SKIP_DEPS="true"
|
||
|
shift
|
||
|
;;
|
||
|
--force)
|
||
|
FORCE_REINSTALL="true"
|
||
|
shift
|
||
|
;;
|
||
|
--quiet)
|
||
|
QUIET="true"
|
||
|
shift
|
||
|
;;
|
||
|
*)
|
||
|
log_error "Unknown option: $1"
|
||
|
show_usage
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
# Validate arguments
|
||
|
case "$INSTALL_MODE" in
|
||
|
"dev"|"prod"|"custom")
|
||
|
;;
|
||
|
*)
|
||
|
log_error "Invalid installation mode: $INSTALL_MODE"
|
||
|
echo "Valid modes: dev, prod, custom"
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
|
||
|
case "$ENVIRONMENT" in
|
||
|
"dev"|"prod")
|
||
|
;;
|
||
|
*)
|
||
|
log_error "Invalid environment: $ENVIRONMENT"
|
||
|
echo "Valid environments: dev, prod"
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
|
||
|
# Configure based on mode
|
||
|
case "$INSTALL_MODE" in
|
||
|
"dev")
|
||
|
ENVIRONMENT="dev"
|
||
|
ENABLE_TLS="${ENABLE_TLS:-false}"
|
||
|
ENABLE_OAUTH="${ENABLE_OAUTH:-false}"
|
||
|
;;
|
||
|
"prod")
|
||
|
ENVIRONMENT="prod"
|
||
|
ENABLE_TLS="${ENABLE_TLS:-true}"
|
||
|
;;
|
||
|
"custom")
|
||
|
custom_install
|
||
|
;;
|
||
|
esac
|
||
|
|
||
|
# Main installation process
|
||
|
main() {
|
||
|
print_banner
|
||
|
|
||
|
# Initialize log
|
||
|
echo "Installation started at $(date)" > "$INSTALL_LOG"
|
||
|
echo "Mode: $INSTALL_MODE, Environment: $ENVIRONMENT" >> "$INSTALL_LOG"
|
||
|
|
||
|
# Check if we're in the right directory
|
||
|
if [ ! -d "$TEMPLATE_DIR" ]; then
|
||
|
log_error "Template directory not found: $TEMPLATE_DIR"
|
||
|
log_error "Please run this script from the Rustelo project root"
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
# Run installation steps
|
||
|
check_system_requirements
|
||
|
|
||
|
if [ "$SKIP_DEPS" != "true" ]; then
|
||
|
install_rust
|
||
|
install_nodejs
|
||
|
install_rust_tools
|
||
|
fi
|
||
|
|
||
|
create_project
|
||
|
configure_project
|
||
|
install_dependencies
|
||
|
build_project
|
||
|
generate_tls_certs
|
||
|
create_startup_scripts
|
||
|
run_setup_scripts
|
||
|
|
||
|
# Run post-setup hook (includes verification and report generation)
|
||
|
echo
|
||
|
print_step "Running post-setup finalization..."
|
||
|
if [ -f "$INSTALL_DIR/scripts/post-setup-hook.sh" ]; then
|
||
|
cd "$INSTALL_DIR"
|
||
|
# Set environment variables for the hook
|
||
|
export PROJECT_NAME="$PROJECT_NAME"
|
||
|
export SETUP_MODE="$INSTALL_MODE"
|
||
|
export ENVIRONMENT="$ENVIRONMENT"
|
||
|
export INSTALL_DATE="$(date '+%Y-%m-%d %H:%M:%S')"
|
||
|
|
||
|
if ./scripts/post-setup-hook.sh "installation"; then
|
||
|
print_success "Post-setup finalization completed"
|
||
|
else
|
||
|
log_warn "Some post-setup tasks had issues, but installation should work"
|
||
|
fi
|
||
|
else
|
||
|
log_warn "Post-setup hook not found - running basic verification"
|
||
|
# Fallback to basic verification
|
||
|
if [ -f "$INSTALL_DIR/scripts/verify-setup.sh" ]; then
|
||
|
./scripts/verify-setup.sh || log_warn "Verification had issues"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Display final instructions
|
||
|
display_instructions
|
||
|
|
||
|
log "Installation completed successfully at $(date)"
|
||
|
}
|
||
|
|
||
|
# Run main function
|
||
|
main "$@"
|