做安装包版本
This commit is contained in:
+73
-5
@@ -7,12 +7,15 @@ import os
|
||||
import sys
|
||||
import subprocess
|
||||
import tempfile
|
||||
import json
|
||||
from PyQt6.QtCore import QThread, pyqtSignal, QObject
|
||||
from PyQt6.QtWidgets import QProgressDialog, QMessageBox, QApplication
|
||||
import urllib.request
|
||||
|
||||
|
||||
UPDATE_CHECK_URL = "https://api.yunzer.cn/api/softwareupgrade/check?code=niumasortware"
|
||||
APP_NAME = "CleanDesktopOrganizer"
|
||||
UPDATE_TASK_NAME = r"CleanDesktopOrganizer\Update"
|
||||
|
||||
|
||||
def _current_version() -> str:
|
||||
@@ -74,6 +77,51 @@ class _DownloadWorker(QThread):
|
||||
self.error.emit(str(e))
|
||||
|
||||
|
||||
def _programdata_dir() -> str:
|
||||
base = os.environ.get("PROGRAMDATA") or r"C:\ProgramData"
|
||||
return os.path.join(base, APP_NAME)
|
||||
|
||||
|
||||
def _ensure_dir(p: str):
|
||||
try:
|
||||
os.makedirs(p, exist_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _update_work_dir() -> str:
|
||||
"""
|
||||
全局安装场景下,Program Files 不可写;更新文件与请求文件统一放 ProgramData。
|
||||
该目录应由安装器创建并赋予 Users Modify 权限。
|
||||
"""
|
||||
d = os.path.join(_programdata_dir(), "updates")
|
||||
_ensure_dir(d)
|
||||
if os.path.isdir(d):
|
||||
return d
|
||||
return tempfile.gettempdir()
|
||||
|
||||
|
||||
def _request_file_path() -> str:
|
||||
d = _programdata_dir()
|
||||
_ensure_dir(d)
|
||||
return os.path.join(d, "update_request.json")
|
||||
|
||||
|
||||
def _run_update_task() -> bool:
|
||||
try:
|
||||
r = subprocess.run(
|
||||
["schtasks", "/Run", "/TN", UPDATE_TASK_NAME],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
creationflags=subprocess.CREATE_NO_WINDOW,
|
||||
)
|
||||
return r.returncode == 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _replace_and_restart(new_exe: str):
|
||||
"""
|
||||
onedir 模式:只替换 exe 本身,dll 等文件不变。
|
||||
@@ -178,11 +226,8 @@ class Updater(QObject):
|
||||
QMessageBox.warning(self._parent_widget, "检查更新失败", f"无法连接更新服务器:\n{err}")
|
||||
|
||||
def _download(self, url: str):
|
||||
# 下载到原 exe 同目录,避免跨盘 move 失败
|
||||
if getattr(sys, "frozen", False):
|
||||
dest_dir = os.path.dirname(sys.executable)
|
||||
else:
|
||||
dest_dir = tempfile.gettempdir()
|
||||
# 全局安装:不要下载到安装目录(通常在 Program Files,不可写)
|
||||
dest_dir = _update_work_dir() if getattr(sys, "frozen", False) else tempfile.gettempdir()
|
||||
dest = os.path.join(dest_dir, "_update_new.exe")
|
||||
|
||||
self._progress = QProgressDialog("正在下载更新...", "取消", 0, 100, self._parent_widget)
|
||||
@@ -199,6 +244,29 @@ class Updater(QObject):
|
||||
|
||||
def _on_download_done(self, path: str):
|
||||
self._progress.close()
|
||||
# frozen 且全局安装:交给计划任务(最高权限)覆盖安装目录 exe
|
||||
if getattr(sys, "frozen", False):
|
||||
try:
|
||||
req = {
|
||||
"src": path,
|
||||
"dst": sys.executable,
|
||||
"pid": os.getpid(),
|
||||
"restart": True,
|
||||
}
|
||||
with open(_request_file_path(), "w", encoding="utf-8") as f:
|
||||
json.dump(req, f, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self._parent_widget, "更新失败", f"无法准备更新任务:\n{e}")
|
||||
return
|
||||
|
||||
if _run_update_task():
|
||||
QApplication.quit()
|
||||
return
|
||||
|
||||
# 兜底:如果计划任务不存在/失败,尝试旧的自替换方式(仅当安装目录可写时有效)
|
||||
_replace_and_restart(path)
|
||||
return
|
||||
|
||||
_replace_and_restart(path)
|
||||
|
||||
def _on_download_error(self, err: str):
|
||||
|
||||
Reference in New Issue
Block a user