diff --git a/auto_updater.py b/auto_updater.py index 815dcca..80d63f3 100644 --- a/auto_updater.py +++ b/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 = [ - installer_path, - '/S', # 静默安装 - f'/D={current_dir}' # 安装到当前目录(覆盖) - ] + # 如果安装包不在程序目录,移动过去 + 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}") - print(f"[Updater] 启动安装命令: {' '.join(install_cmd)}") + # 创建更新脚本 + update_script_path = create_update_installer_script( + installer_path, + current_dir, + exe_name + ) - # 启动安装进程(独立进程,不受父进程影响) + # 启动更新脚本(独立进程) + 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): """ 创建重启启动器脚本 diff --git a/main.py b/main.py index fc6a176..0101216 100644 --- a/main.py +++ b/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