From a6031ee091a661f9f404852a7d2a51273a64db58 Mon Sep 17 00:00:00 2001 From: HibiKier <775757368@qq.com> Date: Thu, 28 Aug 2025 22:04:39 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E5=A2=9E=E5=BC=BA=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E5=95=86=E5=BA=97=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=B7=BB=E5=8A=A0=E6=8F=92=E4=BB=B6=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=EF=BC=8C=E6=98=8E=E7=A1=AE?= =?UTF-8?q?=E5=8C=BA=E5=88=86=E6=8F=92=E4=BB=B6=E6=A8=A1=E5=9D=97=E5=92=8C?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E3=80=82=E6=96=B0=E5=A2=9E=20Windows=20?= =?UTF-8?q?=E4=B8=8B=E5=88=A0=E9=99=A4=E5=8F=AA=E8=AF=BB=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C=E6=8F=90?= =?UTF-8?q?=E5=8D=87=E6=8F=92=E4=BB=B6=E7=AE=A1=E7=90=86=E7=9A=84=E7=A8=B3?= =?UTF-8?q?=E5=AE=9A=E6=80=A7=E5=92=8C=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builtin_plugins/plugin_store/__init__.py | 4 ++- .../plugin_store/data_source.py | 5 ++-- zhenxun/utils/utils.py | 26 ++++++++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/zhenxun/builtin_plugins/plugin_store/__init__.py b/zhenxun/builtin_plugins/plugin_store/__init__.py index f7998310..2f8d756b 100644 --- a/zhenxun/builtin_plugins/plugin_store/__init__.py +++ b/zhenxun/builtin_plugins/plugin_store/__init__.py @@ -104,7 +104,9 @@ async def _(session: EventSession, plugin_id: str, source: Match[str]): if is_number(plugin_id): await MessageUtils.build_message(f"正在添加插件 Id: {plugin_id}").send() else: - await MessageUtils.build_message(f"正在添加插件 Module: {plugin_id}").send() + await MessageUtils.build_message( + f"正在添加插件 Module/名称: {plugin_id}" + ).send() source_str = source.result if source.available else None if source_str and source_str not in ["ali", "git"]: await MessageUtils.build_message( diff --git a/zhenxun/builtin_plugins/plugin_store/data_source.py b/zhenxun/builtin_plugins/plugin_store/data_source.py index 63dd50dc..7b8f4bc6 100644 --- a/zhenxun/builtin_plugins/plugin_store/data_source.py +++ b/zhenxun/builtin_plugins/plugin_store/data_source.py @@ -14,7 +14,7 @@ from zhenxun.utils.image_utils import BuildImage, ImageTemplate, RowStyle from zhenxun.utils.manager.virtual_env_package_manager import VirtualEnvPackageManager from zhenxun.utils.repo_utils import RepoFileManager from zhenxun.utils.repo_utils.models import RepoFileInfo, RepoType -from zhenxun.utils.utils import is_number +from zhenxun.utils.utils import is_number, win_on_rm_error from .config import ( BASE_PATH, @@ -352,7 +352,8 @@ class StoreManager: return f"插件 {plugin_info.name} 不存在..." logger.debug(f"尝试移除插件 {plugin_info.name} 文件: {path}", LOG_COMMAND) if plugin_info.is_dir: - shutil.rmtree(path) + # 处理 Windows 下 .git 等目录内只读文件导致的 WinError 5 + shutil.rmtree(path, onerror=win_on_rm_error) else: path.unlink() await PluginInitManager.remove(f"zhenxun.{plugin_info.module_path}") diff --git a/zhenxun/utils/utils.py b/zhenxun/utils/utils.py index f793d3db..d5921803 100644 --- a/zhenxun/utils/utils.py +++ b/zhenxun/utils/utils.py @@ -1,9 +1,12 @@ +from collections.abc import Callable from dataclasses import dataclass from datetime import datetime import os from pathlib import Path +import stat import time -from typing import ClassVar +from types import TracebackType +from typing import Any, ClassVar import httpx from nonebot_plugin_uninfo import Uninfo @@ -241,3 +244,24 @@ def is_number(text: str) -> bool: return True except ValueError: return False + + +def win_on_rm_error( + func: Callable[[str], Any], + path: str, + _exc_info: tuple[type[BaseException], BaseException, TracebackType], +) -> None: + """Windows下删除只读文件/目录时的回调。 + + 去除只读属性后重试删除,避免 WinError 5。 + """ + try: + os.chmod(path, stat.S_IWRITE) + except Exception: + # 即使去除权限失败也继续尝试 + pass + try: + func(path) + except Exception: + # 仍失败则记录调试日志并忽略,交由上层继续处理 + logger.debug(f"删除失败重试仍失败: {path}")