406 lines
12 KiB
Bash
Executable file
406 lines
12 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 "Clone the repo first: git clone <repo-url> $BACKEND_DIR"
|
||
exit 1
|
||
fi
|
||
print_success "Backend directory exists: $BACKEND_DIR"
|
||
|
||
# Check if we're in a git repo
|
||
cd "$BACKEND_DIR"
|
||
if [ ! -d .git ]; then
|
||
print_error "Not a git repository: $BACKEND_DIR"
|
||
exit 1
|
||
fi
|
||
print_success "Git repository verified"
|
||
|
||
# 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 git status
|
||
print_header "Verifying Code Status"
|
||
|
||
# Show current branch and commit
|
||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||
CURRENT_COMMIT=$(git rev-parse --short HEAD)
|
||
COMMIT_MESSAGE=$(git log -1 --pretty=%B | head -n 1)
|
||
|
||
print_info "Current branch: ${GREEN}${CURRENT_BRANCH}${NC}"
|
||
print_info "Current commit: ${GREEN}${CURRENT_COMMIT}${NC}"
|
||
print_info "Commit message: ${CURRENT_COMMIT} - ${COMMIT_MESSAGE}"
|
||
|
||
# Check if there are uncommitted changes
|
||
if [ -n "$(git status --porcelain)" ]; then
|
||
print_warning "There are uncommitted changes in the working directory:"
|
||
git status --short
|
||
echo ""
|
||
fi
|
||
|
||
# Check if local is behind remote
|
||
git fetch origin --quiet
|
||
LOCAL=$(git rev-parse @)
|
||
REMOTE=$(git rev-parse @{u} 2>/dev/null || echo "")
|
||
if [ -n "$REMOTE" ] && [ "$LOCAL" != "$REMOTE" ]; then
|
||
print_warning "Your local branch is not up to date with remote!"
|
||
print_info "Remote has newer commits. Consider: git pull origin ${CURRENT_BRANCH}"
|
||
fi
|
||
|
||
# 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 " You should pull the desired code BEFORE running this script."
|
||
echo ""
|
||
read -p "Have you pulled the latest code you want to deploy? (y/n) " -n 1 -r
|
||
echo ""
|
||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||
print_error "Deployment cancelled. Pull your code first, then run this script again."
|
||
exit 1
|
||
fi
|
||
print_success "Git status verified - proceeding with deployment"
|
||
else
|
||
if [ "$SKIP_GIT_CHECK" = true ]; then
|
||
print_info "Skipping git verification (--skip-git-check)"
|
||
fi
|
||
print_success "Proceeding with deployment of current code"
|
||
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
|
||
if command -v composer &> /dev/null; then
|
||
print_info "Installing PHP dependencies (Composer)..."
|
||
run_command composer install --no-dev --optimize-autoloader
|
||
print_success "Composer dependencies installed"
|
||
else
|
||
print_warning "Composer not found - skipping PHP dependencies"
|
||
fi
|
||
|
||
# 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
|
||
if [ -d "$BACKEND_DIR/vendor" ]; then
|
||
print_info "Copying Composer dependencies..."
|
||
run_command cp -r "$BACKEND_DIR/vendor" "$FRONTEND_DIR/"
|
||
fi
|
||
|
||
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
|