[minor] 新增自动更新功能 模块Test
This commit is contained in:
245
main.py
245
main.py
@@ -1324,21 +1324,111 @@ class LoginWindow(QMainWindow):
|
||||
return ""
|
||||
|
||||
def trigger_update(self, download_url, latest_version):
|
||||
"""触发更新下载(不阻塞主程序)"""
|
||||
"""触发更新下载(支持自动更新和手动下载)"""
|
||||
try:
|
||||
# 检查下载地址是否有效
|
||||
if not download_url or download_url.strip() == "":
|
||||
self.add_log("⚠️ 下载地址为空,无法更新", "WARNING")
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"下载地址缺失",
|
||||
f"版本 {latest_version} 的下载地址暂未配置。\n\n请联系管理员或稍后再试。",
|
||||
QMessageBox.Ok
|
||||
)
|
||||
return
|
||||
|
||||
# 获取更新内容
|
||||
update_content = self._get_update_content(latest_version)
|
||||
if update_content:
|
||||
content_preview = update_content[:100] + "..." if len(update_content) > 100 else update_content
|
||||
else:
|
||||
content_preview = "(暂无更新说明)"
|
||||
|
||||
# 🔥 新增:弹出三选一对话框(自动更新/手动下载/取消)
|
||||
msg_box = QMessageBox(self)
|
||||
msg_box.setWindowTitle("版本更新")
|
||||
msg_box.setText(f"发现新版本 v{latest_version},是否更新?")
|
||||
msg_box.setInformativeText(
|
||||
f"更新内容:\n{content_preview}\n\n"
|
||||
f"推荐使用「自动更新」,程序将自动下载并安装新版本。"
|
||||
)
|
||||
msg_box.setIcon(QMessageBox.Information)
|
||||
|
||||
# 添加三个按钮
|
||||
auto_button = msg_box.addButton("自动更新", QMessageBox.YesRole)
|
||||
manual_button = msg_box.addButton("手动下载", QMessageBox.NoRole)
|
||||
cancel_button = msg_box.addButton("取消", QMessageBox.RejectRole)
|
||||
msg_box.setDefaultButton(auto_button)
|
||||
|
||||
msg_box.exec_()
|
||||
clicked_button = msg_box.clickedButton()
|
||||
|
||||
if clicked_button == auto_button:
|
||||
# 🔥 自动更新:下载并安装
|
||||
self.add_log("用户选择自动更新", "INFO")
|
||||
self.start_auto_update(download_url, latest_version)
|
||||
elif clicked_button == manual_button:
|
||||
# 🔥 手动下载:打开浏览器
|
||||
self.add_log("用户选择手动下载", "INFO")
|
||||
self.start_manual_download(download_url, latest_version)
|
||||
else:
|
||||
# 取消更新
|
||||
self.add_log("用户取消更新", "INFO")
|
||||
|
||||
except Exception as e:
|
||||
self.add_log(f"更新失败: {e}", "ERROR")
|
||||
import traceback
|
||||
self.add_log(f"详细错误: {traceback.format_exc()}", "ERROR")
|
||||
|
||||
def start_auto_update(self, download_url, latest_version):
|
||||
"""启动自动更新流程(下载 → 安装 → 重启)"""
|
||||
try:
|
||||
self.add_log("🚀 启动自动更新流程", "INFO")
|
||||
|
||||
# 导入自动更新模块
|
||||
from update_dialog import UpdateProgressDialog
|
||||
from auto_updater import UpdateDownloader
|
||||
|
||||
# 创建进度对话框
|
||||
progress_dialog = UpdateProgressDialog(latest_version, self)
|
||||
|
||||
# 创建下载线程
|
||||
downloader = UpdateDownloader(download_url, latest_version, max_retries=3)
|
||||
progress_dialog.downloader = downloader
|
||||
|
||||
# 连接信号
|
||||
downloader.progress.connect(progress_dialog.update_progress)
|
||||
downloader.retry_info.connect(progress_dialog.show_retry_info)
|
||||
downloader.finished.connect(lambda path: self.on_download_finished(path, progress_dialog))
|
||||
downloader.error.connect(lambda err: self.on_download_error(err, progress_dialog, download_url, latest_version))
|
||||
|
||||
# 开始下载
|
||||
self.add_log(f"📥 开始下载: {download_url}", "INFO")
|
||||
downloader.start()
|
||||
progress_dialog.exec_()
|
||||
|
||||
except Exception as e:
|
||||
self.add_log(f"启动自动更新失败: {e}", "ERROR")
|
||||
import traceback
|
||||
self.add_log(f"详细错误: {traceback.format_exc()}", "ERROR")
|
||||
|
||||
# 失败后降级到手动下载
|
||||
reply = QMessageBox.critical(
|
||||
self,
|
||||
"自动更新失败",
|
||||
f"自动更新启动失败: {str(e)}\n\n是否改为手动下载?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.Yes
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.start_manual_download(download_url, latest_version)
|
||||
|
||||
def start_manual_download(self, download_url, latest_version):
|
||||
"""启动手动下载(打开浏览器)"""
|
||||
import webbrowser
|
||||
import threading
|
||||
|
||||
# 检查下载地址是否有效
|
||||
if not download_url or download_url.strip() == "":
|
||||
self.add_log("⚠️ 下载地址为空,无法打开更新页面", "WARNING")
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"下载地址缺失",
|
||||
f"版本 {latest_version} 的下载地址暂未配置。\n\n请联系管理员或稍后再试。",
|
||||
QMessageBox.Ok
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
# 明确提示用户即将下载
|
||||
reply = QMessageBox.information(
|
||||
self,
|
||||
@@ -1352,25 +1442,138 @@ class LoginWindow(QMainWindow):
|
||||
QMessageBox.Ok | QMessageBox.Cancel,
|
||||
QMessageBox.Ok
|
||||
)
|
||||
|
||||
|
||||
if reply == QMessageBox.Cancel:
|
||||
self.add_log("用户取消下载", "INFO")
|
||||
self.add_log("用户取消手动下载", "INFO")
|
||||
return
|
||||
|
||||
|
||||
self.add_log(f"📂 准备打开下载页面: {download_url}", "INFO")
|
||||
|
||||
# 在独立线程中打开浏览器,确保不阻塞GUI主线程
|
||||
|
||||
# 在独立线程中打开浏览器
|
||||
def open_browser_thread():
|
||||
try:
|
||||
webbrowser.open(download_url)
|
||||
self.add_log("✅ 浏览器已打开,下载即将开始", "SUCCESS")
|
||||
except Exception as e:
|
||||
self.add_log(f"❌ 打开浏览器失败: {e}", "ERROR")
|
||||
|
||||
|
||||
thread = threading.Thread(target=open_browser_thread, daemon=True)
|
||||
thread.start()
|
||||
|
||||
self.add_log("✅ 已启动下载,程序继续运行", "INFO")
|
||||
|
||||
self.add_log("✅ 已启动手动下载", "INFO")
|
||||
|
||||
def on_download_finished(self, installer_path, progress_dialog):
|
||||
"""下载完成后的处理"""
|
||||
try:
|
||||
self.add_log(f"✅ 下载完成: {installer_path}", "SUCCESS")
|
||||
|
||||
# 更新进度对话框状态
|
||||
progress_dialog.download_finished(installer_path)
|
||||
|
||||
# 延迟1秒,让用户看到"下载完成"提示
|
||||
QTimer.singleShot(1000, lambda: self.prepare_install(installer_path, progress_dialog))
|
||||
|
||||
except Exception as e:
|
||||
self.add_log(f"处理下载完成事件失败: {e}", "ERROR")
|
||||
|
||||
def prepare_install(self, installer_path, progress_dialog):
|
||||
"""准备安装"""
|
||||
try:
|
||||
# 关闭进度对话框
|
||||
progress_dialog.accept()
|
||||
|
||||
# 提示即将安装
|
||||
reply = QMessageBox.information(
|
||||
self,
|
||||
"准备安装",
|
||||
"新版本下载完成!\n\n"
|
||||
"程序将自动退出并安装新版本,\n"
|
||||
"安装完成后会自动重启。\n\n"
|
||||
"是否立即安装?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.Yes
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
from auto_updater import install_update_and_restart
|
||||
|
||||
# 启动静默安装(带自动重启)
|
||||
if install_update_and_restart(installer_path):
|
||||
self.add_log("✅ 更新安装已启动,程序即将退出", "SUCCESS")
|
||||
self.add_log("程序将在安装完成后自动重启", "INFO")
|
||||
|
||||
# 显示提示
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"正在更新",
|
||||
"程序即将退出并开始安装。\n\n"
|
||||
"安装完成后会自动重启,请稍候...",
|
||||
QMessageBox.Ok
|
||||
)
|
||||
|
||||
# 延迟1秒后退出(让用户看到提示)
|
||||
QTimer.singleShot(1000, self.quit_for_update)
|
||||
else:
|
||||
self.add_log("❌ 启动安装失败", "ERROR")
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
"安装失败",
|
||||
"无法启动安装程序,请手动运行安装包:\n\n" + installer_path,
|
||||
QMessageBox.Ok
|
||||
)
|
||||
else:
|
||||
self.add_log("用户取消安装", "INFO")
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"安装包已保存",
|
||||
f"安装包已保存到:\n{installer_path}\n\n您可以稍后手动运行安装。",
|
||||
QMessageBox.Ok
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.add_log(f"准备安装失败: {e}", "ERROR")
|
||||
import traceback
|
||||
self.add_log(f"详细错误: {traceback.format_exc()}", "ERROR")
|
||||
|
||||
def on_download_error(self, error_msg, progress_dialog, download_url, latest_version):
|
||||
"""下载失败处理"""
|
||||
try:
|
||||
self.add_log(f"❌ 下载失败: {error_msg}", "ERROR")
|
||||
|
||||
# 更新进度对话框状态
|
||||
progress_dialog.download_error(error_msg)
|
||||
|
||||
# 延迟2秒后显示降级选项
|
||||
QTimer.singleShot(2000, lambda: self.handle_download_failure(progress_dialog, download_url, latest_version, error_msg))
|
||||
|
||||
except Exception as e:
|
||||
self.add_log(f"处理下载失败事件异常: {e}", "ERROR")
|
||||
|
||||
def handle_download_failure(self, progress_dialog, download_url, latest_version, error_msg):
|
||||
"""处理下载失败,提供降级选项"""
|
||||
try:
|
||||
# 关闭进度对话框
|
||||
progress_dialog.reject()
|
||||
|
||||
# 提示用户选择手动下载
|
||||
reply = QMessageBox.critical(
|
||||
self,
|
||||
"自动下载失败",
|
||||
f"自动下载失败:\n{error_msg}\n\n是否改为手动下载?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.Yes
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.start_manual_download(download_url, latest_version)
|
||||
|
||||
except Exception as e:
|
||||
self.add_log(f"处理下载失败异常: {e}", "ERROR")
|
||||
|
||||
def quit_for_update(self):
|
||||
"""为更新而退出程序"""
|
||||
self.add_log("正在退出程序以进行更新...", "INFO")
|
||||
self.quit_application()
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
Reference in New Issue
Block a user