修复安装脚本的潜在问题
This commit is contained in:
259
update.sh
259
update.sh
@@ -1,132 +1,187 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Update Script for PromdataPanel
|
||||
# -------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
set -e
|
||||
|
||||
# Config
|
||||
SERVICE_NAME="promdatapanel"
|
||||
DEFAULT_APP_DIR="/opt/promdata-panel"
|
||||
ZIP_URL="https://git.littlediary.cn/CN-JS-HuiBai/PromdataPanel/archive/main.zip"
|
||||
|
||||
# 1. Colors & Banner
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
APP_DIR=""
|
||||
TEMP_DIR=""
|
||||
BACKUP_DIR=""
|
||||
ROLLBACK_REQUIRED=false
|
||||
|
||||
echo -e "${BLUE}=== Starting PromdataPanel Update ===${NC}"
|
||||
|
||||
# 2. Detect APP_DIR automatically from systemd service
|
||||
if systemctl list-unit-files | grep -q "^$SERVICE_NAME.service"; then
|
||||
echo "Detecting application directory from systemd service..."
|
||||
# Get WorkingDirectory from systemd (using env to handle it safely)
|
||||
SERVICE_DIR=$(systemctl show -p WorkingDirectory "$SERVICE_NAME" | cut -d= -f2-)
|
||||
if [ -n "$SERVICE_DIR" ] && [ -d "$SERVICE_DIR" ]; then
|
||||
APP_DIR="$SERVICE_DIR"
|
||||
cleanup() {
|
||||
if [ -n "${TEMP_DIR}" ] && [ -d "${TEMP_DIR}" ]; then
|
||||
rm -rf "${TEMP_DIR}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Fallback 1: Current directory if it contains package.json
|
||||
if [ -z "$APP_DIR" ]; then
|
||||
if [ -f "package.json" ]; then
|
||||
APP_DIR=$(pwd)
|
||||
else
|
||||
rollback() {
|
||||
if [ "$ROLLBACK_REQUIRED" != true ] || [ -z "${BACKUP_DIR}" ] || [ ! -d "${BACKUP_DIR}" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Update failed. Restoring previous application state...${NC}"
|
||||
rsync -a --delete --exclude '.env' "${BACKUP_DIR}/" "${APP_DIR}/"
|
||||
}
|
||||
|
||||
trap 'rollback' ERR
|
||||
trap cleanup EXIT
|
||||
|
||||
validate_app_dir() {
|
||||
local dir="$1"
|
||||
[ -n "$dir" ] || return 1
|
||||
[ -d "$dir" ] || return 1
|
||||
[ -f "$dir/package.json" ] || return 1
|
||||
[ -f "$dir/server/index.js" ] || return 1
|
||||
[ -f "$dir/public/index.html" ] || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
detect_app_dir() {
|
||||
local service_dir=""
|
||||
if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files | grep -q "^${SERVICE_NAME}\.service"; then
|
||||
echo "Detecting application directory from systemd service..."
|
||||
service_dir=$(systemctl show -p WorkingDirectory "$SERVICE_NAME" | cut -d= -f2-)
|
||||
if validate_app_dir "$service_dir"; then
|
||||
APP_DIR="$service_dir"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
local current_dir
|
||||
current_dir=$(pwd)
|
||||
if validate_app_dir "$current_dir"; then
|
||||
APP_DIR="$current_dir"
|
||||
return
|
||||
fi
|
||||
|
||||
if validate_app_dir "$DEFAULT_APP_DIR"; then
|
||||
APP_DIR="$DEFAULT_APP_DIR"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Application directory: $APP_DIR${NC}"
|
||||
|
||||
if [ ! -d "$APP_DIR" ]; then
|
||||
echo -e "${RED}Error: Could not find application directory at $APP_DIR. Check if you installed it correctly.${NC}"
|
||||
echo -e "${RED}Error: Could not locate a valid PromdataPanel application directory.${NC}"
|
||||
echo -e "${YELLOW}Expected markers: package.json, server/index.js, public/index.html${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
cd "$APP_DIR"
|
||||
|
||||
# 2. Update logic
|
||||
if [ -d ".git" ]; then
|
||||
echo -e "${BLUE}Git repository detected. Pulling latest code...${NC}"
|
||||
git pull
|
||||
else
|
||||
echo -e "${BLUE}No git repository found. Updating via ZIP archive...${NC}"
|
||||
|
||||
# URL for zip download
|
||||
ZIP_URL="https://git.littlediary.cn/CN-JS-HuiBai/PromdataPanel/archive/main.zip"
|
||||
TEMP_DIR="/tmp/promdata_update_$(date +%s)"
|
||||
|
||||
mkdir -p "$TEMP_DIR"
|
||||
echo "Downloading latest version (main branch)..."
|
||||
curl -L "$ZIP_URL" -o "$TEMP_DIR/latest.zip"
|
||||
|
||||
# Ensure unzip is available
|
||||
if ! command -v unzip &> /dev/null; then
|
||||
echo -e "${BLUE}unzip is not installed. Attempting to install it...${NC}"
|
||||
if command -v apt-get &> /dev/null; then
|
||||
sudo apt-get update && sudo apt-get install -y unzip
|
||||
elif command -v dnf &> /dev/null; then
|
||||
sudo dnf install -y unzip
|
||||
elif command -v yum &> /dev/null; then
|
||||
sudo yum install -y yum-utils && sudo yum install -y unzip
|
||||
elif command -v apk &> /dev/null; then
|
||||
sudo apk add unzip
|
||||
fi
|
||||
ensure_tool() {
|
||||
local cmd="$1"
|
||||
if command -v "$cmd" >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Extracting archive..."
|
||||
unzip -q "$TEMP_DIR/latest.zip" -d "$TEMP_DIR"
|
||||
|
||||
# The extracted folder is usually named project-main or similar
|
||||
EXTRACTED_FOLDER=$(ls -d "$TEMP_DIR"/*/ | head -n 1)
|
||||
|
||||
# Ensure rsync is available (Auto-install if missing)
|
||||
if ! command -v rsync &> /dev/null; then
|
||||
echo -e "${BLUE}rsync is not installed. Attempting to install it...${NC}"
|
||||
if command -v apt-get &> /dev/null; then
|
||||
sudo apt-get update && sudo apt-get install -y rsync
|
||||
elif command -v dnf &> /dev/null; then
|
||||
sudo dnf install -y rsync
|
||||
elif command -v yum &> /dev/null; then
|
||||
sudo yum install -y rsync
|
||||
elif command -v apk &> /dev/null; then
|
||||
sudo apk add rsync
|
||||
else
|
||||
echo -e "${RED}Error: 'rsync' is not installed and could not auto-install. Please install it manually.${NC}"
|
||||
rm -rf "$TEMP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$EXTRACTED_FOLDER" ]; then
|
||||
echo "Applying updates (preserving .env)..."
|
||||
# Copy everything except .env
|
||||
rsync -av --exclude '.env' --exclude 'node_modules' "$EXTRACTED_FOLDER" ./
|
||||
echo -e "${BLUE}${cmd} is not installed. Attempting to install it...${NC}"
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "$cmd"
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
sudo dnf install -y "$cmd"
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
sudo yum install -y "$cmd"
|
||||
elif command -v apk >/dev/null 2>&1; then
|
||||
sudo apk add "$cmd"
|
||||
else
|
||||
echo -e "${RED}Extraction failed. Please check the archive structure.${NC}"
|
||||
echo -e "${RED}Error: '${cmd}' is not installed and could not be auto-installed.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -rf "$TEMP_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
# 3. Update dependencies
|
||||
echo -e "${BLUE}Updating npm dependencies...${NC}"
|
||||
npm install --production
|
||||
update_from_git() {
|
||||
echo -e "${BLUE}Git repository detected. Pulling latest code...${NC}"
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo -e "${RED}Error: Working tree has local changes. Commit or stash them before updating.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
git pull --ff-only
|
||||
}
|
||||
|
||||
# 4. Restart service
|
||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||
echo -e "${BLUE}Restarting systemd service: $SERVICE_NAME...${NC}"
|
||||
sudo systemctl restart "$SERVICE_NAME"
|
||||
echo -e "${GREEN}Update completed and service restarted!${NC}"
|
||||
elif command -v pm2 &> /dev/null && pm2 list | grep -q "$SERVICE_NAME"; then
|
||||
echo -e "${BLUE}Restarting with PM2...${NC}"
|
||||
pm2 restart "$SERVICE_NAME"
|
||||
echo -e "${GREEN}Update completed and PM2 restarted!${NC}"
|
||||
update_from_zip() {
|
||||
echo -e "${BLUE}No git repository found. Updating via ZIP archive with staging and rollback...${NC}"
|
||||
ensure_tool curl
|
||||
ensure_tool unzip
|
||||
ensure_tool rsync
|
||||
|
||||
TEMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/promdatapanel-update-XXXXXX")
|
||||
BACKUP_DIR="${TEMP_DIR}/backup"
|
||||
local archive_path="${TEMP_DIR}/latest.zip"
|
||||
local extracted_folder=""
|
||||
local staging_dir=""
|
||||
|
||||
echo "Downloading latest version (main branch)..."
|
||||
curl -fL "$ZIP_URL" -o "$archive_path"
|
||||
|
||||
echo "Extracting archive..."
|
||||
unzip -q "$archive_path" -d "$TEMP_DIR"
|
||||
extracted_folder=$(find "$TEMP_DIR" -mindepth 1 -maxdepth 1 -type d ! -name backup | head -n 1)
|
||||
|
||||
if ! validate_app_dir "$extracted_folder"; then
|
||||
echo -e "${RED}Extraction failed or archive structure is invalid.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
staging_dir="${TEMP_DIR}/staging"
|
||||
mkdir -p "$staging_dir"
|
||||
rsync -a --exclude '.git' "$extracted_folder/" "$staging_dir/"
|
||||
|
||||
if [ -f "${APP_DIR}/.env" ]; then
|
||||
cp "${APP_DIR}/.env" "${staging_dir}/.env"
|
||||
fi
|
||||
|
||||
echo "Installing dependencies in staging directory..."
|
||||
(
|
||||
cd "$staging_dir"
|
||||
npm install --production
|
||||
)
|
||||
|
||||
echo "Creating rollback backup..."
|
||||
rsync -a --delete --exclude '.env' "${APP_DIR}/" "${BACKUP_DIR}/"
|
||||
|
||||
echo "Applying staged update..."
|
||||
ROLLBACK_REQUIRED=true
|
||||
rsync -a --delete --exclude '.env' "${staging_dir}/" "${APP_DIR}/"
|
||||
}
|
||||
|
||||
restart_service() {
|
||||
if command -v systemctl >/dev/null 2>&1 && systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||
echo -e "${BLUE}Restarting systemd service: ${SERVICE_NAME}...${NC}"
|
||||
sudo systemctl restart "$SERVICE_NAME"
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v pm2 >/dev/null 2>&1 && pm2 list | grep -q "$SERVICE_NAME"; then
|
||||
echo -e "${BLUE}Restarting with PM2...${NC}"
|
||||
pm2 restart "$SERVICE_NAME"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Warning: Could not detect an active systemd service or PM2 process named '${SERVICE_NAME}'.${NC}"
|
||||
echo -e "${YELLOW}Please restart the application manually.${NC}"
|
||||
}
|
||||
|
||||
detect_app_dir
|
||||
echo -e "${BLUE}Application directory: ${APP_DIR}${NC}"
|
||||
cd "$APP_DIR"
|
||||
|
||||
if [ -d ".git" ]; then
|
||||
update_from_git
|
||||
echo -e "${BLUE}Updating npm dependencies...${NC}"
|
||||
npm install --production
|
||||
else
|
||||
echo -e "${RED}Warning: Could not detect an active systemd service or PM2 process named '$SERVICE_NAME'.${NC}"
|
||||
echo -e "${RED}Please restart the application manually.${NC}"
|
||||
update_from_zip
|
||||
fi
|
||||
|
||||
restart_service
|
||||
ROLLBACK_REQUIRED=false
|
||||
|
||||
echo -e "${GREEN}=== Update successfully finished ===${NC}"
|
||||
|
||||
Reference in New Issue
Block a user