upgrade sync: merge DATABASES only into settings after git pull (fix webmail/emailDelivery dropped from INSTALLED_APPS); add merge_production_settings.py; fix PIPESTATUS with tee

This commit is contained in:
master3395
2026-03-25 20:58:33 +01:00
parent 789b914b6f
commit bc54c9c845
3 changed files with 95 additions and 6 deletions

View File

@@ -1716,10 +1716,17 @@ Sync_CyberCP_To_Latest() {
fi
)
local sync_code=$?
# Restore production settings so panel keeps working (DB, secrets, etc.)
if [[ -f /tmp/cyberpanel_settings_backup.py ]]; then
# Merge production DATABASES into branch settings.py (preserve webmail/emailDelivery in INSTALLED_APPS)
if [[ -f /tmp/cyberpanel_settings_backup.py ]] && [[ -f /usr/local/CyberCP/upgrade_modules/merge_production_settings.py ]]; then
python3 /usr/local/CyberCP/upgrade_modules/merge_production_settings.py /tmp/cyberpanel_settings_backup.py /usr/local/CyberCP/CyberCP/settings.py 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ "${PIPESTATUS[0]}" -eq 0 ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Merged production DATABASES into branch settings.py (INSTALLED_APPS from branch preserved)" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: settings merge failed; keeping branch settings.py as-is" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
elif [[ -f /tmp/cyberpanel_settings_backup.py ]]; then
cp /tmp/cyberpanel_settings_backup.py /usr/local/CyberCP/CyberCP/settings.py
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Restored settings.py after sync" | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Restored settings.py after sync (merge script missing)" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
# LiteSpeed serves /static/ from public/static/; ensure it has latest baseTemplate static files (e.g. dashboard JS)
if [[ -d /usr/local/CyberCP/public/static ]] && [[ -d /usr/local/CyberCP/baseTemplate/static/baseTemplate ]]; then

View File

@@ -23,10 +23,18 @@ Sync_CyberCP_To_Latest() {
fi
)
local sync_code=$?
# Restore production settings so panel keeps working (DB, secrets, etc.)
if [[ -f /tmp/cyberpanel_settings_backup.py ]]; then
# Merge production DATABASES into branch settings.py so DB creds survive without stripping
# new INSTALLED_APPS (webmail, emailDelivery, etc.). Blind full restore broke integrated webmail.
if [[ -f /tmp/cyberpanel_settings_backup.py ]] && [[ -f /usr/local/CyberCP/upgrade_modules/merge_production_settings.py ]]; then
python3 /usr/local/CyberCP/upgrade_modules/merge_production_settings.py /tmp/cyberpanel_settings_backup.py /usr/local/CyberCP/CyberCP/settings.py 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log
if [[ "${PIPESTATUS[0]}" -eq 0 ]]; then
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Merged production DATABASES into branch settings.py (INSTALLED_APPS from branch preserved)" | tee -a /var/log/cyberpanel_upgrade_debug.log
else
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: settings merge failed; keeping branch settings.py as-is" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
elif [[ -f /tmp/cyberpanel_settings_backup.py ]]; then
cp /tmp/cyberpanel_settings_backup.py /usr/local/CyberCP/CyberCP/settings.py
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Restored settings.py after sync" | tee -a /var/log/cyberpanel_upgrade_debug.log
echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Restored settings.py after sync (merge script missing)" | tee -a /var/log/cyberpanel_upgrade_debug.log
fi
# LiteSpeed serves /static/ from public/static/; ensure it has latest baseTemplate static files (e.g. dashboard JS)
if [[ -d /usr/local/CyberCP/public/static ]] && [[ -d /usr/local/CyberCP/baseTemplate/static/baseTemplate ]]; then

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Merge DATABASES from a backup settings.py into the branch checkout (in-place).
Used after git sync so production DB credentials survive without replacing INSTALLED_APPS
from the branch (e.g. webmail, emailDelivery). See upgrade_modules/09_sync.sh."""
from __future__ import annotations
import sys
def _extract_assign_block(text: str, name: str) -> tuple[str | None, int | None, int | None]:
"""Return (full_assignment, start, end_exclusive) for NAME = { ... } or None."""
prefix = name + ' = '
start = text.find(prefix)
if start == -1:
return None, None, None
brace = text.find('{', start)
if brace == -1:
return None, None, None
depth = 0
for j in range(brace, len(text)):
if text[j] == '{':
depth += 1
elif text[j] == '}':
depth -= 1
if depth == 0:
end = j + 1
# Include trailing comma/newline if present (keep style)
while end < len(text) and text[end] in ' \t':
end += 1
if end < len(text) and text[end] == ',':
end += 1
return text[start:end], start, end
return None, None, None
def merge_settings(old_path: str, branch_path: str) -> int:
try:
with open(old_path, 'r', encoding='utf-8', errors='replace') as f:
old_text = f.read()
with open(branch_path, 'r', encoding='utf-8', errors='replace') as f:
branch_text = f.read()
except OSError as e:
print('merge_production_settings: read error: %s' % e, file=sys.stderr)
return 2
old_db, _, _ = _extract_assign_block(old_text, 'DATABASES')
if not old_db:
print('merge_production_settings: no DATABASES in backup, leaving branch file', file=sys.stderr)
return 1
br_db, br_start, br_end = _extract_assign_block(branch_text, 'DATABASES')
if not br_db or br_start is None or br_end is None:
print('merge_production_settings: no DATABASES in branch settings', file=sys.stderr)
return 3
merged = branch_text[:br_start] + old_db + branch_text[br_end:]
try:
with open(branch_path, 'w', encoding='utf-8', newline='\n') as f:
f.write(merged)
except OSError as e:
print('merge_production_settings: write error: %s' % e, file=sys.stderr)
return 4
print('merge_production_settings: replaced DATABASES from backup into %s' % branch_path)
return 0
if __name__ == '__main__':
if len(sys.argv) != 3:
print('Usage: merge_production_settings.py /path/to/backup_settings.py /path/to/CyberCP/settings.py', file=sys.stderr)
sys.exit(9)
sys.exit(merge_settings(sys.argv[1], sys.argv[2]))