修复安装脚本的潜在问题

This commit is contained in:
CN-JS-HuiBai
2026-04-09 14:02:58 +08:00
parent 9854f478c0
commit bfb40f4947
2 changed files with 356 additions and 236 deletions

259
update.sh
View File

@@ -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}"