From 56bb311c2be24c00a3325ac1693e5f03162066d3 Mon Sep 17 00:00:00 2001 From: HibiKier <775757368@qq.com> Date: Fri, 1 Aug 2025 17:01:21 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20webui=E4=B8=8Eresources=E6=94=AF?= =?UTF-8?q?=E6=8C=81git=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builtin_plugins/auto_update/__init__.py | 4 +- .../auto_update/_data_source.py | 28 ++++++++++-- zhenxun/builtin_plugins/auto_update/config.py | 2 + zhenxun/builtin_plugins/hooks/auth_checker.py | 5 +++ zhenxun/utils/manager/resource_manager.py | 44 ++++++++++++------- zhenxun/utils/repo_utils/aliyun_manager.py | 34 +++++++++----- zhenxun/utils/repo_utils/base_manager.py | 2 +- zhenxun/utils/repo_utils/github_manager.py | 4 +- zhenxun/utils/repo_utils/utils.py | 11 +++++ 9 files changed, 99 insertions(+), 35 deletions(-) diff --git a/zhenxun/builtin_plugins/auto_update/__init__.py b/zhenxun/builtin_plugins/auto_update/__init__.py index 8f4584a5..0cee97ba 100644 --- a/zhenxun/builtin_plugins/auto_update/__init__.py +++ b/zhenxun/builtin_plugins/auto_update/__init__.py @@ -109,10 +109,10 @@ async def _( logger.error("版本更新失败...", "检查更新", session=session, e=e) await MessageUtils.build_message(f"更新版本失败...e: {e}").finish() elif ver_type.result == "webui": - result = await UpdateManager.update_webui() + result = await UpdateManager.update_webui(zip.result, source.result) if resource.result or ver_type.result == "resource": try: - await ResourceManager.init_resources(True) + await ResourceManager.init_resources(True, zip.result, source.result) result += "\n资源文件更新成功!" except DownloadResourceException: result += "\n资源更新下载失败..." diff --git a/zhenxun/builtin_plugins/auto_update/_data_source.py b/zhenxun/builtin_plugins/auto_update/_data_source.py index a5a5fc98..e726928c 100644 --- a/zhenxun/builtin_plugins/auto_update/_data_source.py +++ b/zhenxun/builtin_plugins/auto_update/_data_source.py @@ -7,7 +7,7 @@ import zipfile from nonebot.adapters import Bot from nonebot.utils import run_sync -from zhenxun.configs.path_config import DATA_PATH +from zhenxun.configs.path_config import DATA_PATH, TEMP_PATH from zhenxun.services.log import logger from zhenxun.utils.github_utils import GithubUtils from zhenxun.utils.github_utils.models import RepoInfo @@ -15,6 +15,7 @@ from zhenxun.utils.http_utils import AsyncHttpx from zhenxun.utils.manager.virtual_env_package_manager import VirtualEnvPackageManager from zhenxun.utils.platform import PlatformUtils from zhenxun.utils.repo_utils import AliyunRepoManager, GithubRepoManager +from zhenxun.utils.repo_utils.utils import clean_git from .config import ( BACKUP_PATH, @@ -25,6 +26,7 @@ from .config import ( DOWNLOAD_GZ_FILE, DOWNLOAD_ZIP_FILE, GIT_GITHUB_URL, + GIT_WEBUI_UI_URL, PYPROJECT_FILE, PYPROJECT_FILE_STRING, PYPROJECT_LOCK_FILE, @@ -120,7 +122,7 @@ def _file_handle(latest_version: str | None): class UpdateManager: @classmethod - async def update_webui(cls) -> str: + async def update_webui(cls, is_zip: bool, source: str) -> str: from zhenxun.builtin_plugins.web_ui.public.data_source import ( update_webui_assets, ) @@ -133,8 +135,26 @@ class UpdateManager: shutil.rmtree(BACKUP_PATH) WEBUI_PATH.rename(BACKUP_PATH) try: - await update_webui_assets() - logger.info("更新webui成功...", COMMAND) + if is_zip: + await update_webui_assets() + logger.info("更新webui成功...", COMMAND) + else: + TMP_PATH = TEMP_PATH / "_webui_tmp" + if TMP_PATH.exists(): + await clean_git(TMP_PATH) + shutil.rmtree(TMP_PATH) + if source == "ali": + result = await AliyunRepoManager.update( + GIT_WEBUI_UI_URL, TMP_PATH, "dist" + ) + else: + result = await GithubRepoManager.update( + GIT_WEBUI_UI_URL, TMP_PATH, "dist" + ) + if not result.success: + return f"Webui更新失败...错误: {result.error_message}" + shutil.rmtree(WEBUI_PATH, ignore_errors=True) + shutil.copytree(TMP_PATH / "dist", WEBUI_PATH) if BACKUP_PATH.exists(): logger.debug(f"删除旧的webui文件夹 {BACKUP_PATH}", COMMAND) shutil.rmtree(BACKUP_PATH) diff --git a/zhenxun/builtin_plugins/auto_update/config.py b/zhenxun/builtin_plugins/auto_update/config.py index 2b484aa3..17d5483e 100644 --- a/zhenxun/builtin_plugins/auto_update/config.py +++ b/zhenxun/builtin_plugins/auto_update/config.py @@ -7,6 +7,8 @@ GIT_GITHUB_URL = "https://github.com/zhenxun-org/zhenxun_bot.git" DEFAULT_GITHUB_URL = "https://github.com/HibiKier/zhenxun_bot/tree/main" RELEASE_URL = "https://api.github.com/repos/HibiKier/zhenxun_bot/releases/latest" +GIT_WEBUI_UI_URL = "https://github.com/HibiKier/zhenxun_bot_webui.git" + VERSION_FILE_STRING = "__version__" VERSION_FILE = Path() / VERSION_FILE_STRING diff --git a/zhenxun/builtin_plugins/hooks/auth_checker.py b/zhenxun/builtin_plugins/hooks/auth_checker.py index 9e9c4e0d..cf2c97c7 100644 --- a/zhenxun/builtin_plugins/hooks/auth_checker.py +++ b/zhenxun/builtin_plugins/hooks/auth_checker.py @@ -148,6 +148,11 @@ async def get_plugin_and_user( user = await with_timeout( user_dao.safe_get_or_none(user_id=user_id), name="get_user" ) + except IntegrityError: + await asyncio.sleep(0.5) + plugin, user = await with_timeout( + asyncio.gather(plugin_task, user_task), name="get_plugin_and_user" + ) if not plugin: raise PermissionExemption(f"插件:{module} 数据不存在,已跳过权限检查...") diff --git a/zhenxun/utils/manager/resource_manager.py b/zhenxun/utils/manager/resource_manager.py index a859d6b9..38e90654 100644 --- a/zhenxun/utils/manager/resource_manager.py +++ b/zhenxun/utils/manager/resource_manager.py @@ -3,12 +3,14 @@ from pathlib import Path import shutil import zipfile -from zhenxun.configs.path_config import FONT_PATH +from zhenxun.configs.path_config import FONT_PATH, TEMP_PATH from zhenxun.services.log import logger from zhenxun.utils.github_utils import GithubUtils from zhenxun.utils.http_utils import AsyncHttpx +from zhenxun.utils.repo_utils import AliyunRepoManager, GithubRepoManager +from zhenxun.utils.repo_utils.utils import clean_git -CMD_STRING = "ResourceManager" +LOG_COMMAND = "ResourceManager" class DownloadResourceException(Exception): @@ -20,29 +22,41 @@ class ResourceManager: RESOURCE_PATH = Path() / "resources" - TMP_PATH = Path() / "_resource_tmp" + TMP_PATH = TEMP_PATH / "_resource_tmp" ZIP_FILE = TMP_PATH / "resources.zip" UNZIP_PATH = None @classmethod - async def init_resources(cls, force: bool = False): + async def init_resources( + cls, force: bool = False, is_zip: bool = False, git_source: str = "ali" + ): if (FONT_PATH.exists() and os.listdir(FONT_PATH)) and not force: return if cls.TMP_PATH.exists(): logger.debug( - "resources临时文件夹已存在,移除resources临时文件夹", CMD_STRING + "resources临时文件夹已存在,移除resources临时文件夹", LOG_COMMAND ) - shutil.rmtree(cls.TMP_PATH) - cls.TMP_PATH.mkdir(parents=True, exist_ok=True) - try: - await cls.__download_resources() + await clean_git(cls.TMP_PATH) + shutil.rmtree(cls.TMP_PATH, ignore_errors=True) + if is_zip: + cls.TMP_PATH.mkdir(parents=True, exist_ok=True) + try: + await cls.__download_resources() + cls.file_handle() + except Exception as e: + logger.error("获取resources资源包失败", LOG_COMMAND, e=e) + else: + if git_source == "ali": + await AliyunRepoManager.update(cls.GITHUB_URL, cls.TMP_PATH) + else: + await GithubRepoManager.update(cls.GITHUB_URL, cls.TMP_PATH) + cls.UNZIP_PATH = cls.TMP_PATH / "resources" cls.file_handle() - except Exception as e: - logger.error("获取resources资源包失败", CMD_STRING, e=e) if cls.TMP_PATH.exists(): - logger.debug("移除resources临时文件夹", CMD_STRING) + logger.debug("移除resources临时文件夹", LOG_COMMAND) + await clean_git(cls.TMP_PATH) shutil.rmtree(cls.TMP_PATH) @classmethod @@ -68,17 +82,17 @@ class ResourceManager: """获取resources文件夹""" repo_info = GithubUtils.parse_github_url(cls.GITHUB_URL) url = await repo_info.get_archive_download_urls() - logger.debug("开始下载resources资源包...", CMD_STRING) + logger.debug("开始下载resources资源包...", LOG_COMMAND) if not await AsyncHttpx.download_file(url, cls.ZIP_FILE, stream=True): logger.error( "下载resources资源包失败,请尝试重启重新下载或前往 " "https://github.com/zhenxun-org/zhenxun-bot-resources 手动下载..." ) raise DownloadResourceException("下载resources资源包失败...") - logger.debug("下载resources资源文件压缩包完成...", CMD_STRING) + logger.debug("下载resources资源文件压缩包完成...", LOG_COMMAND) tf = zipfile.ZipFile(cls.ZIP_FILE) tf.extractall(cls.TMP_PATH) - logger.debug("解压文件压缩包完成...", CMD_STRING) + logger.debug("解压文件压缩包完成...", LOG_COMMAND) download_file_path = cls.TMP_PATH / next( x for x in os.listdir(cls.TMP_PATH) if (cls.TMP_PATH / x).is_dir() ) diff --git a/zhenxun/utils/repo_utils/aliyun_manager.py b/zhenxun/utils/repo_utils/aliyun_manager.py index 248aada6..863a5620 100644 --- a/zhenxun/utils/repo_utils/aliyun_manager.py +++ b/zhenxun/utils/repo_utils/aliyun_manager.py @@ -69,7 +69,7 @@ class AliyunCodeupManager(BaseRepoManager): self._check_config() # 获取仓库名称(从URL中提取) - repo_url = repo_url.split("/")[-1].replace(".git", "") + repo_url = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") # 获取仓库最新提交ID newest_commit = await self._get_newest_commit(repo_url, branch) @@ -77,7 +77,9 @@ class AliyunCodeupManager(BaseRepoManager): # 创建结果对象 result = RepoUpdateResult( repo_type=RepoType.ALIYUN, - repo_name=repo_url.split("/")[-1].replace(".git", ""), + repo_name=repo_url.split("/tree/")[0] + .split("/")[-1] + .replace(".git", ""), owner=self.config.aliyun_codeup.organization_id, old_version="", # 将在后面更新 new_version=newest_commit, @@ -99,7 +101,7 @@ class AliyunCodeupManager(BaseRepoManager): local_path.mkdir(parents=True, exist_ok=True) # 获取仓库名称(从URL中提取) - repo_name = repo_url.split("/")[-1].replace(".git", "") + repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") # 获取变更的文件列表 changed_files = await self._get_changed_files( @@ -135,7 +137,7 @@ class AliyunCodeupManager(BaseRepoManager): except RepoUpdateError as e: logger.error(f"更新仓库失败: {e}") # 从URL中提取仓库名称 - repo_name = repo_url.split("/")[-1].replace(".git", "") + repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") return RepoUpdateResult( repo_type=RepoType.ALIYUN, repo_name=repo_name, @@ -147,7 +149,7 @@ class AliyunCodeupManager(BaseRepoManager): except Exception as e: logger.error(f"更新仓库失败: {e}") # 从URL中提取仓库名称 - repo_name = repo_url.split("/")[-1].replace(".git", "") + repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") return RepoUpdateResult( repo_type=RepoType.ALIYUN, repo_name=repo_name, @@ -181,12 +183,16 @@ class AliyunCodeupManager(BaseRepoManager): self._check_config() # 获取仓库名称(从URL中提取) - repo_identifier = repo_url.split("/")[-1].replace(".git", "") + repo_identifier = ( + repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") + ) # 创建结果对象 result = FileDownloadResult( repo_type=RepoType.ALIYUN, - repo_name=repo_url.split("/")[-1].replace(".git", ""), + repo_name=repo_url.split("/tree/")[0] + .split("/")[-1] + .replace(".git", ""), file_path=file_path, version=branch, ) @@ -206,7 +212,7 @@ class AliyunCodeupManager(BaseRepoManager): except RepoDownloadError as e: logger.error(f"下载文件失败: {e}") # 从URL中提取仓库名称 - repo_name = repo_url.split("/")[-1].replace(".git", "") + repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") return FileDownloadResult( repo_type=RepoType.ALIYUN, repo_name=repo_name, @@ -217,7 +223,7 @@ class AliyunCodeupManager(BaseRepoManager): except Exception as e: logger.error(f"下载文件失败: {e}") # 从URL中提取仓库名称 - repo_name = repo_url.split("/")[-1].replace(".git", "") + repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") return FileDownloadResult( repo_type=RepoType.ALIYUN, repo_name=repo_name, @@ -250,7 +256,9 @@ class AliyunCodeupManager(BaseRepoManager): self._check_config() # 获取仓库名称(从URL中提取) - repo_identifier = repo_url.split("/")[-1].replace(".git", "") + repo_identifier = ( + repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") + ) # 获取文件列表 search_type = "RECURSIVE" if recursive else "DIRECT" @@ -298,7 +306,9 @@ class AliyunCodeupManager(BaseRepoManager): self._check_config() # 获取仓库名称(从URL中提取) - repo_identifier = repo_url.split("/")[-1].replace(".git", "") + repo_identifier = ( + repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") + ) # 获取提交信息 # 注意:这里假设AliyunFileInfo有get_commit_info方法,如果没有,需要实现 @@ -440,7 +450,7 @@ class AliyunCodeupManager(BaseRepoManager): def prepare_aliyun_url(repo_url: str) -> str: import base64 - repo_name = repo_url.split("/")[-1].replace(".git", "") + repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") # 构建仓库URL # 阿里云CodeUp的仓库URL格式通常为: # https://codeup.aliyun.com/{organization_id}/{organization_name}/{repo_name}.git diff --git a/zhenxun/utils/repo_utils/base_manager.py b/zhenxun/utils/repo_utils/base_manager.py index c096f222..c3b77803 100644 --- a/zhenxun/utils/repo_utils/base_manager.py +++ b/zhenxun/utils/repo_utils/base_manager.py @@ -230,7 +230,7 @@ class BaseRepoManager(ABC): """ from .models import RepoType - repo_name = repo_url.split("/")[-1].replace(".git", "") + repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "") try: # 创建结果对象 diff --git a/zhenxun/utils/repo_utils/github_manager.py b/zhenxun/utils/repo_utils/github_manager.py index bab58eec..462c2723 100644 --- a/zhenxun/utils/repo_utils/github_manager.py +++ b/zhenxun/utils/repo_utils/github_manager.py @@ -172,7 +172,9 @@ class GithubManager(BaseRepoManager): 返回: FileDownloadResult: 下载结果 """ - repo_name = repo_url.split("/")[-1].replace(".git", "").strip() + repo_name = ( + repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "").strip() + ) try: # 解析仓库URL repo_info = GithubUtils.parse_github_url(repo_url) diff --git a/zhenxun/utils/repo_utils/utils.py b/zhenxun/utils/repo_utils/utils.py index f335ef6c..194e021e 100644 --- a/zhenxun/utils/repo_utils/utils.py +++ b/zhenxun/utils/repo_utils/utils.py @@ -31,6 +31,17 @@ async def check_git() -> bool: return False +async def clean_git(cwd: Path): + """ + 清理git仓库 + + 参数: + cwd: 工作目录 + """ + await run_git_command("reset --hard", cwd) + await run_git_command("clean -xdf", cwd) + + async def run_git_command( command: str, cwd: Path | None = None ) -> tuple[bool, str, str]: