433 lines
13 KiB
Bash
Executable file
433 lines
13 KiB
Bash
Executable file
#!/bin/bash
|
||
|
||
#############################################
|
||
# Voice to Text - Production Deploy Script
|
||
#############################################
|
||
# Deploys backend (Python API) and frontend (PHP) to production
|
||
# Usage: sudo ./deploy.sh [options]
|
||
|
||
set -e # Exit on error
|
||
|
||
# Color codes for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Configuration
|
||
BACKEND_DIR="/opt/voice2text"
|
||
FRONTEND_DIR="/var/www/html/voice2txt"
|
||
SERVICE_NAME="voice2text-api"
|
||
SERVICE_FILE="voice2text-api.service"
|
||
SERVICE_PATH="/etc/systemd/system/${SERVICE_FILE}"
|
||
|
||
# Parse command line arguments
|
||
DRY_RUN=false
|
||
BACKEND_ONLY=false
|
||
FRONTEND_ONLY=false
|
||
VERBOSE=false
|
||
SKIP_GIT_CHECK=false
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
--dry-run)
|
||
DRY_RUN=true
|
||
shift
|
||
;;
|
||
--backend-only)
|
||
BACKEND_ONLY=true
|
||
shift
|
||
;;
|
||
--frontend-only)
|
||
FRONTEND_ONLY=true
|
||
shift
|
||
;;
|
||
--verbose|-v)
|
||
VERBOSE=true
|
||
shift
|
||
;;
|
||
--skip-git-check)
|
||
SKIP_GIT_CHECK=true
|
||
shift
|
||
;;
|
||
--help|-h)
|
||
echo "Usage: sudo ./deploy.sh [options]"
|
||
echo ""
|
||
echo "Options:"
|
||
echo " --dry-run Show what would be deployed without executing"
|
||
echo " --backend-only Deploy only the Python API backend"
|
||
echo " --frontend-only Deploy only the PHP frontend"
|
||
echo " --verbose, -v Show detailed output"
|
||
echo " --skip-git-check Skip the git status verification prompt"
|
||
echo " --help, -h Show this help message"
|
||
echo ""
|
||
echo "Note: This script does NOT pull code from git."
|
||
echo " Pull the desired code/branch BEFORE running this script."
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo -e "${RED}Unknown option: $1${NC}"
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# Helper functions
|
||
print_header() {
|
||
echo -e "\n${BLUE}═══════════════════════════════════════════════════${NC}"
|
||
echo -e "${BLUE} $1${NC}"
|
||
echo -e "${BLUE}═══════════════════════════════════════════════════${NC}\n"
|
||
}
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}✓${NC} $1"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}✗${NC} $1"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠${NC} $1"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${BLUE}ℹ${NC} $1"
|
||
}
|
||
|
||
run_command() {
|
||
if [ "$VERBOSE" = true ]; then
|
||
echo -e "${BLUE}Running:${NC} $*"
|
||
fi
|
||
|
||
if [ "$DRY_RUN" = true ]; then
|
||
echo -e "${YELLOW}[DRY RUN]${NC} Would execute: $*"
|
||
else
|
||
"$@"
|
||
fi
|
||
}
|
||
|
||
# Pre-flight checks
|
||
print_header "Pre-flight Checks"
|
||
|
||
# Check if running as root
|
||
if [ "$EUID" -ne 0 ]; then
|
||
print_error "This script must be run as root (use sudo)"
|
||
exit 1
|
||
fi
|
||
print_success "Running as root"
|
||
|
||
# Check if backend directory exists
|
||
if [ ! -d "$BACKEND_DIR" ]; then
|
||
print_error "Backend directory not found: $BACKEND_DIR"
|
||
print_info "Create directory and clone repo first: git clone <repo-url> $BACKEND_DIR"
|
||
exit 1
|
||
fi
|
||
print_success "Backend directory exists: $BACKEND_DIR"
|
||
|
||
# Change to backend directory
|
||
cd "$BACKEND_DIR"
|
||
|
||
# Check for required system dependencies
|
||
print_header "Checking Required Dependencies"
|
||
|
||
# Check Python (REQUIRED)
|
||
if ! command -v python3 &> /dev/null; then
|
||
print_error "Python 3 is not installed (REQUIRED)"
|
||
print_info "Install: sudo apt install python3 python3-venv python3-pip"
|
||
exit 1
|
||
fi
|
||
print_success "Python 3 found: $(python3 --version)"
|
||
|
||
# Check Composer (REQUIRED for PHP dependencies)
|
||
if ! command -v composer &> /dev/null; then
|
||
print_error "Composer is not installed (REQUIRED)"
|
||
print_info "Install: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer"
|
||
exit 1
|
||
fi
|
||
print_success "Composer found: $(composer --version | head -n 1)"
|
||
|
||
# Check FFmpeg (REQUIRED for audio processing)
|
||
if ! command -v ffmpeg &> /dev/null; then
|
||
print_error "FFmpeg is not installed (REQUIRED)"
|
||
print_info "Install: sudo apt install ffmpeg"
|
||
exit 1
|
||
fi
|
||
print_success "FFmpeg found: $(ffmpeg -version | head -n 1 | cut -d' ' -f3)"
|
||
|
||
# Detect if this is first deployment
|
||
FIRST_DEPLOY=false
|
||
if [ ! -f "$SERVICE_PATH" ]; then
|
||
FIRST_DEPLOY=true
|
||
print_info "First deployment detected"
|
||
else
|
||
print_info "Updating existing deployment"
|
||
fi
|
||
|
||
# Verify we're ready to deploy
|
||
print_header "Pre-Deployment Verification"
|
||
|
||
print_info "Backend directory: ${GREEN}${BACKEND_DIR}${NC}"
|
||
|
||
# Prompt user to confirm they've pulled the latest code
|
||
if [ "$SKIP_GIT_CHECK" != true ] && [ "$DRY_RUN" != true ]; then
|
||
echo ""
|
||
echo -e "${YELLOW}IMPORTANT:${NC} This script does NOT pull code from git."
|
||
echo -e " Make sure you've pulled the code you want to deploy BEFORE running this script."
|
||
echo ""
|
||
echo "Expected workflow:"
|
||
echo " 1. cd ${BACKEND_DIR}"
|
||
echo " 2. git pull origin main (or checkout desired branch/tag)"
|
||
echo " 3. Review changes"
|
||
echo " 4. Run this deploy script"
|
||
echo ""
|
||
read -p "Are you ready to deploy the current code? (y/n) " -n 1 -r
|
||
echo ""
|
||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||
print_error "Deployment cancelled."
|
||
exit 1
|
||
fi
|
||
print_success "Proceeding with deployment"
|
||
else
|
||
if [ "$SKIP_GIT_CHECK" = true ]; then
|
||
print_info "Skipping deployment confirmation (--skip-git-check)"
|
||
fi
|
||
print_success "Proceeding with deployment"
|
||
fi
|
||
|
||
# Deploy Backend
|
||
if [ "$FRONTEND_ONLY" != true ]; then
|
||
print_header "Deploying Backend (Python API)"
|
||
|
||
cd "$BACKEND_DIR"
|
||
|
||
# Check for Python
|
||
if ! command -v python3 &> /dev/null; then
|
||
print_error "Python 3 is not installed"
|
||
exit 1
|
||
fi
|
||
print_success "Python 3 found: $(python3 --version)"
|
||
|
||
# Create virtual environment if it doesn't exist
|
||
if [ ! -d "venv" ]; then
|
||
print_info "Creating Python virtual environment..."
|
||
run_command python3 -m venv venv
|
||
print_success "Virtual environment created"
|
||
else
|
||
print_success "Virtual environment exists"
|
||
fi
|
||
|
||
# Activate venv and install/update dependencies
|
||
print_info "Installing Python dependencies..."
|
||
run_command venv/bin/pip install --upgrade pip
|
||
run_command venv/bin/pip install -r requirements.txt
|
||
print_success "Python dependencies installed"
|
||
|
||
# Install/update Composer dependencies (REQUIRED)
|
||
print_info "Installing PHP dependencies (Composer)..."
|
||
run_command composer install --no-dev --optimize-autoloader
|
||
|
||
# VERIFY vendor/ directory was created
|
||
if [ ! -d "vendor" ]; then
|
||
print_error "Composer dependencies failed to install - vendor/ directory missing!"
|
||
print_info "Try running: composer install --verbose"
|
||
exit 1
|
||
fi
|
||
|
||
if [ ! -f "vendor/autoload.php" ]; then
|
||
print_error "Composer autoload.php is missing!"
|
||
print_info "This indicates a broken Composer installation"
|
||
exit 1
|
||
fi
|
||
|
||
print_success "Composer dependencies installed and verified"
|
||
|
||
# Create outputs directory if it doesn't exist
|
||
if [ ! -d "outputs" ]; then
|
||
print_info "Creating outputs directory..."
|
||
run_command mkdir -p outputs
|
||
fi
|
||
|
||
# Set proper ownership and permissions
|
||
print_info "Setting permissions..."
|
||
run_command chown -R www-data:www-data "$BACKEND_DIR"
|
||
run_command chmod -R 755 "$BACKEND_DIR"
|
||
run_command chmod 777 "$BACKEND_DIR/outputs"
|
||
print_success "Permissions set"
|
||
|
||
# Handle .env file
|
||
if [ ! -f ".env" ]; then
|
||
print_warning ".env file not found in $BACKEND_DIR"
|
||
if [ -f ".env.example" ]; then
|
||
print_info "Copying .env.example to .env..."
|
||
run_command cp .env.example .env
|
||
print_warning "IMPORTANT: Edit $BACKEND_DIR/.env with production credentials!"
|
||
else
|
||
print_error ".env.example not found - cannot create .env"
|
||
exit 1
|
||
fi
|
||
else
|
||
print_success ".env file exists (not overwriting)"
|
||
fi
|
||
|
||
# Install systemd service
|
||
print_info "Installing systemd service..."
|
||
run_command cp "$BACKEND_DIR/$SERVICE_FILE" "$SERVICE_PATH"
|
||
run_command systemctl daemon-reload
|
||
print_success "Systemd service installed"
|
||
|
||
# Enable and start/restart service
|
||
if [ "$FIRST_DEPLOY" = true ]; then
|
||
print_info "Enabling service..."
|
||
run_command systemctl enable "$SERVICE_NAME"
|
||
print_success "Service enabled"
|
||
|
||
print_info "Starting service..."
|
||
run_command systemctl start "$SERVICE_NAME"
|
||
print_success "Service started"
|
||
else
|
||
print_info "Restarting service..."
|
||
run_command systemctl restart "$SERVICE_NAME"
|
||
print_success "Service restarted"
|
||
fi
|
||
|
||
# Wait for service to start
|
||
print_info "Waiting for service to start..."
|
||
sleep 3
|
||
|
||
# Check service status
|
||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||
print_success "Service is running"
|
||
else
|
||
print_error "Service failed to start"
|
||
echo ""
|
||
echo "Service status:"
|
||
systemctl status "$SERVICE_NAME" --no-pager
|
||
echo ""
|
||
echo "Recent logs:"
|
||
journalctl -u "$SERVICE_NAME" -n 20 --no-pager
|
||
exit 1
|
||
fi
|
||
|
||
# Test API health endpoint
|
||
print_info "Testing API health endpoint..."
|
||
if curl -sf http://localhost:5010/health > /dev/null; then
|
||
print_success "API is responding at http://localhost:5010"
|
||
else
|
||
print_warning "API health check failed - service may still be starting"
|
||
fi
|
||
fi
|
||
|
||
# Deploy Frontend
|
||
if [ "$BACKEND_ONLY" != true ]; then
|
||
print_header "Deploying Frontend (PHP)"
|
||
|
||
# Create frontend directory if it doesn't exist
|
||
if [ ! -d "$FRONTEND_DIR" ]; then
|
||
print_info "Creating frontend directory..."
|
||
run_command mkdir -p "$FRONTEND_DIR"
|
||
fi
|
||
|
||
# Copy frontend files
|
||
print_info "Copying frontend files..."
|
||
|
||
# PHP files
|
||
run_command cp "$BACKEND_DIR"/*.php "$FRONTEND_DIR/"
|
||
|
||
# Config files
|
||
run_command cp "$BACKEND_DIR/.htaccess" "$FRONTEND_DIR/"
|
||
run_command cp "$BACKEND_DIR/.user.ini" "$FRONTEND_DIR/"
|
||
|
||
# Assets
|
||
run_command cp "$BACKEND_DIR/style.css" "$FRONTEND_DIR/"
|
||
if [ -f "$BACKEND_DIR/V2T.svg" ]; then
|
||
run_command cp "$BACKEND_DIR/V2T.svg" "$FRONTEND_DIR/"
|
||
fi
|
||
|
||
# Composer vendor directory (REQUIRED)
|
||
if [ ! -d "$BACKEND_DIR/vendor" ]; then
|
||
print_error "vendor/ directory not found in backend!"
|
||
print_info "This should have been created during backend deployment"
|
||
exit 1
|
||
fi
|
||
|
||
print_info "Copying Composer dependencies..."
|
||
run_command cp -r "$BACKEND_DIR/vendor" "$FRONTEND_DIR/"
|
||
|
||
# VERIFY vendor/ was copied successfully
|
||
if [ ! -f "$FRONTEND_DIR/vendor/autoload.php" ]; then
|
||
print_error "Failed to copy vendor/ to frontend!"
|
||
print_info "Check permissions and disk space"
|
||
exit 1
|
||
fi
|
||
|
||
print_success "Composer dependencies copied and verified"
|
||
print_success "Frontend files copied"
|
||
|
||
# Handle .env file for frontend
|
||
if [ ! -f "$FRONTEND_DIR/.env" ]; then
|
||
print_warning ".env file not found in $FRONTEND_DIR"
|
||
if [ -f "$BACKEND_DIR/.env.example" ]; then
|
||
print_info "Copying .env.example to frontend..."
|
||
run_command cp "$BACKEND_DIR/.env.example" "$FRONTEND_DIR/.env"
|
||
print_warning "IMPORTANT: Edit $FRONTEND_DIR/.env with production credentials!"
|
||
fi
|
||
else
|
||
print_success ".env file exists in frontend (not overwriting)"
|
||
fi
|
||
|
||
# Create outputs directory symlink or copy
|
||
if [ ! -d "$FRONTEND_DIR/outputs" ]; then
|
||
print_info "Linking outputs directory..."
|
||
run_command ln -s "$BACKEND_DIR/outputs" "$FRONTEND_DIR/outputs"
|
||
print_success "Outputs directory linked"
|
||
fi
|
||
|
||
# Set proper ownership and permissions
|
||
print_info "Setting frontend permissions..."
|
||
run_command chown -R www-data:www-data "$FRONTEND_DIR"
|
||
run_command chmod -R 755 "$FRONTEND_DIR"
|
||
print_success "Frontend permissions set"
|
||
fi
|
||
|
||
# Final summary
|
||
print_header "Deployment Summary"
|
||
|
||
if [ "$BACKEND_ONLY" != true ]; then
|
||
echo -e "${GREEN}Frontend:${NC}"
|
||
echo " Location: $FRONTEND_DIR"
|
||
echo " Files: *.php, style.css, .htaccess, vendor/"
|
||
fi
|
||
|
||
if [ "$FRONTEND_ONLY" != true ]; then
|
||
echo -e "${GREEN}Backend:${NC}"
|
||
echo " Location: $BACKEND_DIR"
|
||
echo " Service: $SERVICE_NAME"
|
||
echo " Status: $(systemctl is-active $SERVICE_NAME)"
|
||
echo " API: http://localhost:5010"
|
||
fi
|
||
|
||
echo ""
|
||
print_success "Deployment completed successfully!"
|
||
echo ""
|
||
|
||
# Show useful commands
|
||
print_header "Useful Commands"
|
||
echo "Service management:"
|
||
echo " systemctl status $SERVICE_NAME # Check service status"
|
||
echo " systemctl restart $SERVICE_NAME # Restart service"
|
||
echo " systemctl stop $SERVICE_NAME # Stop service"
|
||
echo ""
|
||
echo "View logs:"
|
||
echo " journalctl -u $SERVICE_NAME -f # Follow live logs"
|
||
echo " journalctl -u $SERVICE_NAME -n 50 # Last 50 log entries"
|
||
echo ""
|
||
echo "Test API:"
|
||
echo " curl http://localhost:5010/health # Health check"
|
||
echo ""
|
||
|
||
if [ -f "$FRONTEND_DIR/.env" ] && grep -q "DEV_MODE=true" "$FRONTEND_DIR/.env" 2>/dev/null; then
|
||
print_warning "WARNING: DEV_MODE=true detected in .env!"
|
||
print_warning "Remember to set DEV_MODE=false for production"
|
||
fi
|