[patch] 新增自动更新功能 模块Test-center

This commit is contained in:
2025-10-28 17:15:56 +08:00
parent 5945e1b0e7
commit 16d5d95c4e
2 changed files with 134 additions and 33 deletions

View File

@@ -133,12 +133,14 @@ class UpdateDownloader(QThread):
def install_update_and_restart(installer_path):
"""
启动静默安装并自动重启程序
简化版更新安装文件替换方式不使用NSIS安装
工作流程:
1. 启动NSIS安装包静默模式
2. 启动重启启动器(等待安装完成后重启)
3. 当前程序退出
1. 将安装包移动到程序目录
2. 创建替换脚本
3. 脚本等待程序退出
4. 脚本解压并替换文件
5. 重启程序
Args:
installer_path: 安装包路径
@@ -156,55 +158,153 @@ def install_update_and_restart(installer_path):
else:
# 开发环境
current_exe = os.path.abspath("main.py")
current_dir = os.getcwd()
current_dir = os.path.dirname(os.path.abspath(__file__))
exe_name = "main.exe"
print(f"[Updater] 当前程序: {current_exe}")
print(f"[Updater] 安装目录: {current_dir}")
print(f"[Updater] 程序目录: {current_dir}")
print(f"[Updater] 主程序名: {exe_name}")
print(f"[Updater] 安装包路径: {installer_path}")
# 创建重启启动器脚本
restart_script_path = create_restart_launcher(current_dir, exe_name)
# 🔥 关键改进:将安装包移动到程序目录(避免跨盘符问题)
installer_name = os.path.basename(installer_path)
target_installer_path = os.path.join(current_dir, installer_name)
# 启动NSIS安装包
# 参数说明:
# /S - 静默安装
# /D=目录 - 指定安装目录(必须是最后一个参数)
install_cmd = [
# 如果安装包不在程序目录,移动过去
if os.path.abspath(installer_path) != os.path.abspath(target_installer_path):
try:
import shutil
shutil.move(installer_path, target_installer_path)
print(f"[Updater] 安装包已移动到程序目录: {target_installer_path}")
installer_path = target_installer_path
except Exception as e:
print(f"[Updater] 移动安装包失败,使用原路径: {e}")
# 创建更新脚本
update_script_path = create_update_installer_script(
installer_path,
'/S', # 静默安装
f'/D={current_dir}' # 安装到当前目录(覆盖)
]
current_dir,
exe_name
)
print(f"[Updater] 启动安装命令: {' '.join(install_cmd)}")
# 启动安装进程(独立进程,不受父进程影响)
# 启动更新脚本(独立进程)
print(f"[Updater] 启动更新脚本: {update_script_path}")
subprocess.Popen(
install_cmd,
['cmd', '/c', update_script_path],
creationflags=subprocess.CREATE_NO_WINDOW | subprocess.DETACHED_PROCESS,
close_fds=True
)
print(f"[Updater] ✅ 安装包已启动")
# 同时启动重启启动器延迟15秒启动确保安装完成
subprocess.Popen(
['cmd', '/c', restart_script_path],
creationflags=subprocess.CREATE_NO_WINDOW | subprocess.DETACHED_PROCESS,
close_fds=True
)
print(f"[Updater] ✅ 重启启动器已启动")
print(f"[Updater] ✅ 更新脚本已启动")
return True
except Exception as e:
print(f"[Updater] ❌ 启动安装失败: {e}")
print(f"[Updater] ❌ 启动更新失败: {e}")
import traceback
traceback.print_exc()
return False
def create_update_installer_script(installer_path, install_dir, exe_name):
"""
创建更新安装脚本(在程序目录下执行)
工作流程:
1. 等待主程序退出
2. 在程序目录下执行NSIS安装
3. 清理安装包
4. 重启程序
Args:
installer_path: 安装包路径(应该已经在程序目录下)
install_dir: 程序安装目录
exe_name: 主程序文件名
Returns:
str: 脚本路径
"""
# 脚本放在程序目录下,避免权限问题
script_path = os.path.join(install_dir, "update_installer.bat")
# 转换为绝对路径(处理引号问题)
installer_path = os.path.abspath(installer_path)
install_dir = os.path.abspath(install_dir)
script_content = f"""@echo off
chcp 65001 > nul
title 水滴AI客服智能助手 - 自动更新
echo ============================================
echo 水滴AI客服智能助手 - 自动更新
echo ============================================
echo.
REM 切换到程序目录
cd /d "{install_dir}"
echo [INFO] 程序目录: {install_dir}
echo.
REM 等待主程序退出最多等待30秒
echo [INFO] 等待主程序退出...
set count=0
:wait_main_exit
tasklist /FI "IMAGENAME eq {exe_name}" 2>NUL | find /I "{exe_name}" >NUL
if NOT ERRORLEVEL 1 (
if %count% LSS 30 (
timeout /t 1 /nobreak > nul
set /a count+=1
goto wait_main_exit
) else (
echo [WARN] 主程序未正常退出,强制继续安装
)
)
echo [OK] 主程序已退出
echo.
REM 执行静默安装(在当前目录下)
echo [INFO] 开始安装更新...
echo [INFO] 安装包: "{installer_path}"
echo [INFO] 目标目录: "{install_dir}"
echo.
REM 使用完整路径和引号避免空格问题
"{installer_path}" /S /D="{install_dir}"
REM 等待安装完成
echo [INFO] 等待安装完成...
timeout /t 20 /nobreak > nul
REM 清理安装包
echo [INFO] 清理安装包...
del /f /q "{installer_path}" 2>nul
REM 启动新版本程序
echo [INFO] 正在启动新版本...
if exist "{install_dir}\\{exe_name}" (
start "" "{install_dir}\\{exe_name}"
echo [OK] ✅ 程序已启动
) else (
echo [ERROR] ❌ 找不到程序文件: {exe_name}
echo [INFO] 请手动启动程序
pause
)
REM 延迟后删除自己
timeout /t 2 /nobreak > nul
del /f /q "%~f0" 2>nul
exit
"""
try:
with open(script_path, 'w', encoding='utf-8-sig') as f:
f.write(script_content)
print(f"[Updater] 更新脚本已创建: {script_path}")
except Exception as e:
print(f"[Updater] 创建更新脚本失败: {e}")
return script_path
def create_restart_launcher(install_dir, exe_name):
"""
创建重启启动器脚本

View File

@@ -1233,7 +1233,8 @@ class LoginWindow(QMainWindow):
"""显示更新对话框(信号槽函数,始终在主线程中执行)"""
try:
self.add_log(f"🎯 主线程收到更新信号: v{latest_version}", "INFO")
self.show_update_notification(latest_version, download_url)
# 🔥 修改调用新的trigger_update方法支持自动更新
self.trigger_update(download_url, latest_version)
except Exception as e:
self.add_log(f"❌ 显示更新对话框失败: {e}", "ERROR")
import traceback