Files

119 lines
4.4 KiB
Python

"""Fast-forward a clean Git installation from the public O1Key release repo."""
import os
import subprocess
from pathlib import Path
PLUGIN_DIR = Path(__file__).resolve().parent.parent
RELEASE_REPOSITORY_URL = "https://git.o1key.com/publisher/comfyui_o1key.git"
class UpdateError(Exception):
def __init__(self, code, message, suggestion, status=409):
super().__init__(message)
self.code = code
self.suggestion = suggestion
self.status = status
def as_dict(self):
return {
"code": self.code,
"error": str(self),
"suggestion": self.suggestion,
}
def _git(*args, timeout=60, check=True):
env = os.environ.copy()
env["GIT_TERMINAL_PROMPT"] = "0"
env["GCM_INTERACTIVE"] = "Never"
try:
result = subprocess.run(
["git", *args], cwd=PLUGIN_DIR, env=env,
capture_output=True, text=True, encoding="utf-8",
errors="replace", timeout=timeout,
)
except FileNotFoundError as exc:
raise UpdateError(
"git_missing", "未找到 Git。", "安装 Git 后重启 ComfyUI,再重新检查更新。", 503,
) from exc
except subprocess.TimeoutExpired as exc:
raise UpdateError(
"timeout", "连接发布仓库超时。", "检查网络连接,稍后再试。", 504,
) from exc
if check and result.returncode:
raise UpdateError(
"git_failed", "Git 操作未完成。", "检查插件目录的 Git 状态后重试。",
)
return result
def _check_release():
"""Inspect the release before considering any local file changes."""
if not (PLUGIN_DIR / ".git").exists():
raise UpdateError(
"not_git", "当前插件不是 Git 安装。",
"请从发布仓库重新以 Git 安装;现有配置文件先单独备份。",
)
branch = _git("symbolic-ref", "--quiet", "--short", "HEAD", check=False)
if branch.returncode or branch.stdout.strip() != "main":
raise UpdateError(
"wrong_branch", "当前不在 main 分支。",
"请先检查并切换分支;本地分支上的修改不会自动合并。",
)
old_commit = _git("rev-parse", "HEAD").stdout.strip()
fetched = _git("fetch", "--no-tags", RELEASE_REPOSITORY_URL, "main", timeout=90, check=False)
if fetched.returncode:
raise UpdateError(
"fetch_failed", "无法获取发布仓库的 main 分支。",
"检查 git.o1key.com 的网络连接与仓库读取权限,稍后重试。", 503,
)
new_commit = _git("rev-parse", "FETCH_HEAD").stdout.strip()
if old_commit == new_commit:
return old_commit, new_commit
if _git("merge-base", "--is-ancestor", "HEAD", "FETCH_HEAD", check=False).returncode:
raise UpdateError(
"diverged", "本地提交与发布仓库已分叉,无法自动快进。",
"请手动比较两个分支并合并,不要强制重置本地文件。",
)
if _git("status", "--porcelain", "--untracked-files=no").stdout.strip():
raise UpdateError(
"local_changes", "插件目录有未提交的代码修改。",
"请先保存、提交或暂存修改;更新不会覆盖这些文件。",
)
return old_commit, new_commit
def check_for_update():
"""Check whether the installed version can be updated without changing files."""
old_commit, new_commit = _check_release()
return {"update_available": old_commit != new_commit}
def update_package():
"""Fetch the release main branch and fast-forward only a clean local main."""
old_commit, new_commit = _check_release()
if old_commit == new_commit:
return {"updated": False, "version": old_commit[:7], "requirements_changed": False}
old_requirements = _git("show", "HEAD:requirements.txt", check=False).stdout
new_requirements = _git("show", "FETCH_HEAD:requirements.txt", check=False).stdout
merged = _git("merge", "--ff-only", "FETCH_HEAD", check=False)
if merged.returncode:
raise UpdateError(
"merge_blocked", "更新被本地文件阻止。",
"检查是否有与新版本重名的未跟踪文件,保留文件后手动处理。",
)
requirements_changed = old_requirements != new_requirements
return {
"updated": True,
"version": new_commit[:7],
"requirements_changed": requirements_changed,
}