[patch] 新增自动更新功能 模块Test-center
This commit is contained in:
164
auto_updater.py
164
auto_updater.py
@@ -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):
|
||||
"""
|
||||
创建重启启动器脚本
|
||||
|
||||
3
main.py
3
main.py
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user