fix(update): add staging protection to switch_channel

switch_channel has three destructive code paths (git reset + clean,
git init + checkout --force, and rmtree + ZIP replace) that were
missing the _stage_preserved_items / _restore_preserved_items safety
net already applied to perform_update.

Wrap the channel-specific logic in a try/finally so preserved user
data (settings.json, civitai/, cache/, etc.) is physically moved
outside plugin_root before any git operation and always restored.
This commit is contained in:
Will Miao
2026-07-29 20:41:36 +08:00
parent f2ac790752
commit 53825500db

View File

@@ -313,8 +313,10 @@ class UpdateRoutes:
if os.path.exists(settings_path): if os.path.exists(settings_path):
with open(settings_path, 'r', encoding='utf-8') as f: with open(settings_path, 'r', encoding='utf-8') as f:
settings_backup = f.read() settings_backup = f.read()
logger.info("Backed up settings.json before channel switch") logger.info("Backed up settings.json before channel switch (%d bytes)", len(settings_backup))
staged_backup_dir, staged_items = _stage_preserved_items(plugin_root)
try:
git_folder = os.path.join(plugin_root, '.git') git_folder = os.path.join(plugin_root, '.git')
if channel == 'nightly': if channel == 'nightly':
@@ -349,11 +351,13 @@ class UpdateRoutes:
success, new_version = await UpdateRoutes._download_and_replace_zip(plugin_root) success, new_version = await UpdateRoutes._download_and_replace_zip(plugin_root)
finally: finally:
UpdateRoutes._restore_git(git_backup, git_folder, success, 'release') UpdateRoutes._restore_git(git_backup, git_folder, success, 'release')
finally:
_restore_preserved_items(plugin_root, staged_backup_dir, staged_items)
if settings_backup and success: if settings_backup and success:
with open(settings_path, 'w', encoding='utf-8') as f: with open(settings_path, 'w', encoding='utf-8') as f:
f.write(settings_backup) f.write(settings_backup)
logger.info("Restored settings.json after channel switch") logger.info("Restored settings.json content after channel switch")
if success: if success:
return web.json_response({ return web.json_response({