换位置

This commit is contained in:
lwt
2026-06-09 14:01:20 +08:00
parent 6d86678e11
commit 0b34f2e3d0
53 changed files with 1762 additions and 603 deletions
+19 -19
View File
@@ -2,10 +2,10 @@
"""
仿 Cursor / VS Code 的无感增量更新模块(Tkinter 入口用)
【打包前提】采用 PyInstaller 文件夹模式 (-D)。安装目录含 main.exe 与 _internal 等依赖。
【增量范围】.patch 仅针对 main.exe:在 TEMP 合成 main_new.exe 并校验 SHA256
替换时只覆盖安装目录下的 main.exe,绝不修改 _internal 或其它文件。
【临时清理】替换脚本会清理 TEMP 中的 .patch 与 main_new.exe,不留下垃圾。
【打包前提】采用 PyInstaller 文件夹模式 (-D)。安装目录含 ServerManager.exe 与 _internal 等依赖。
【增量范围】.patch 仅针对 ServerManager.exe:在 TEMP 合成 ServerManager_new.exe 并校验 SHA256
替换时只覆盖安装目录下的 ServerManager.exe,绝不修改 _internal 或其它文件。
【临时清理】替换脚本会清理 TEMP 中的 .patch 与 ServerManager_new.exe,不留下垃圾。
依赖:bsdiff4, hashlib, requests, threading, os, sys, subprocess, tkinter。
远端 version.json 支持两种键名:delta 或 delta_updates(兼容旧配置)。
@@ -91,9 +91,9 @@ def apply_update_and_restart(
if not os.path.isfile(new_exe_path):
return
install_dir = os.path.normpath(os.path.dirname(current_exe_path))
target_name = (target_exe_name or os.path.basename(current_exe_path) or "main.exe").strip() or "main.exe"
target_name = (target_exe_name or os.path.basename(current_exe_path) or "ServerManager.exe").strip() or "ServerManager.exe"
# 优先使用安装目录下的 mini_updater.exe(与 main.exe 同目录),必须用绝对路径
# 优先使用安装目录下的 mini_updater.exe(与 ServerManager.exe 同目录),必须用绝对路径
mini_updater_exe = os.path.normpath(os.path.join(install_dir, "mini_updater.exe"))
if sys.platform == "win32" and os.path.isfile(mini_updater_exe):
try:
@@ -185,14 +185,14 @@ def _get_delta_map(manifest: dict) -> dict:
class SeamlessUpdater:
"""
隐形增量更新:后台守护线程静默准备,就绪后主线程弹一次「重启以更新」,
用户确认后极速替换 main.exe(或静默安装完整包)并退出。
用户确认后极速替换 ServerManager.exe(或静默安装完整包)并退出。
"""
def __init__(self, root: tk.Tk, local_version: str, version_url: str = None):
self.root = root
self.local_version = (local_version or "").strip()
self.version_url = (version_url or VERSION_JSON_URL).strip()
self._ready_delta_path = None # TEMP 下 main_new.exe 路径(增量就绪)
self._ready_delta_path = None # TEMP 下 ServerManager_new.exe 路径(增量就绪)
self._ready_full_path = None # TEMP 下 Setup.exe 路径(全量就绪)
self._ready_remote_version = None
self._lock = threading.Lock()
@@ -242,8 +242,8 @@ class SeamlessUpdater:
def _try_delta_path(self, manifest: dict) -> bool:
"""
若存在当前版本的 delta:在 TEMP 静默下载 .patch -> bsdiff4 合成 main_new.exe -> 校验 SHA256。
仅针对 main.exe,不涉及 _internal。合成后删除 TEMP 中的 .patch。
若存在当前版本的 delta:在 TEMP 静默下载 .patch -> bsdiff4 合成 ServerManager_new.exe -> 校验 SHA256。
仅针对 ServerManager.exe,不涉及 _internal。合成后删除 TEMP 中的 .patch。
成功则设置 self._ready_delta_path 并返回 True;任何一步失败返回 False。
"""
delta_map = _get_delta_map(manifest)
@@ -386,7 +386,7 @@ import tkinter as tk
from scripts.update.tk_updater import SeamlessUpdater, VERSION_JSON_URL
# 从 version.json 或常量读取本地版本号
LOCAL_VERSION = "1.1.3" # 需与 version.json / 安装包一致
LOCAL_VERSION = "1.1.8" # 需与 version.json / 安装包一致
def main():
root = tk.Tk()
@@ -408,20 +408,20 @@ if __name__ == "__main__":
# 开发者:如何生成 .patch 文件(发版流程)
# ---------------------------------------------------------------------------
"""
【重要】采用 PyInstaller 文件夹模式 (-D)。增量仅针对 main.exe,不包含 _internal
用户端替换时只覆盖 main.exe,绝不修改 _internal 或其它文件。
【重要】采用 PyInstaller 文件夹模式 (-D)。增量仅针对 ServerManager.exe,不包含 _internal
用户端替换时只覆盖 ServerManager.exe,绝不修改 _internal 或其它文件。
1. 打包:使用 PyInstaller 文件夹模式生成当前版本:
pyinstaller -D -w your_main.py
得到 dist/your_main/main.exe(或 dist/main.exe
pyinstaller -D -w -n ServerManager entrypoints/main.py
得到 dist/ServerManager/ServerManager.exe。
2. 保存上一版本的 main.exe(仅此单文件,无需 _internal):
将上一发版时的 main.exe 保存为 build/output/main_1.0.2.exe(版本号与 version.json 中 delta 的键一致)。
2. 保存上一版本的 ServerManager.exe(仅此单文件,无需 _internal):
将上一发版时的 ServerManager.exe 保存为 build/output/ServerManager_1.0.2.exe(版本号与 version.json 中 delta 的键一致)。
3. 生成差分补丁(需安装 bsdiff4pip install bsdiff4):
import bsdiff4
old = open('build/output/main_1.0.2.exe', 'rb').read()
new = open('dist/your_main/main.exe', 'rb').read()
old = open('build/output/ServerManager_1.0.2.exe', 'rb').read()
new = open('dist/ServerManager/ServerManager.exe', 'rb').read()
patch = bsdiff4.diff(old, new)
open('build/output/patches/v1.0.2_to_v1.0.3.patch', 'wb').write(patch)