webui与resources支持git更新

This commit is contained in:
HibiKier 2025-08-01 17:01:21 +08:00
parent ab7aad0488
commit 56bb311c2b
9 changed files with 99 additions and 35 deletions

View File

@ -109,10 +109,10 @@ async def _(
logger.error("版本更新失败...", "检查更新", session=session, e=e) logger.error("版本更新失败...", "检查更新", session=session, e=e)
await MessageUtils.build_message(f"更新版本失败...e: {e}").finish() await MessageUtils.build_message(f"更新版本失败...e: {e}").finish()
elif ver_type.result == "webui": 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": if resource.result or ver_type.result == "resource":
try: try:
await ResourceManager.init_resources(True) await ResourceManager.init_resources(True, zip.result, source.result)
result += "\n资源文件更新成功!" result += "\n资源文件更新成功!"
except DownloadResourceException: except DownloadResourceException:
result += "\n资源更新下载失败..." result += "\n资源更新下载失败..."

View File

@ -7,7 +7,7 @@ import zipfile
from nonebot.adapters import Bot from nonebot.adapters import Bot
from nonebot.utils import run_sync 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.services.log import logger
from zhenxun.utils.github_utils import GithubUtils from zhenxun.utils.github_utils import GithubUtils
from zhenxun.utils.github_utils.models import RepoInfo 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.manager.virtual_env_package_manager import VirtualEnvPackageManager
from zhenxun.utils.platform import PlatformUtils from zhenxun.utils.platform import PlatformUtils
from zhenxun.utils.repo_utils import AliyunRepoManager, GithubRepoManager from zhenxun.utils.repo_utils import AliyunRepoManager, GithubRepoManager
from zhenxun.utils.repo_utils.utils import clean_git
from .config import ( from .config import (
BACKUP_PATH, BACKUP_PATH,
@ -25,6 +26,7 @@ from .config import (
DOWNLOAD_GZ_FILE, DOWNLOAD_GZ_FILE,
DOWNLOAD_ZIP_FILE, DOWNLOAD_ZIP_FILE,
GIT_GITHUB_URL, GIT_GITHUB_URL,
GIT_WEBUI_UI_URL,
PYPROJECT_FILE, PYPROJECT_FILE,
PYPROJECT_FILE_STRING, PYPROJECT_FILE_STRING,
PYPROJECT_LOCK_FILE, PYPROJECT_LOCK_FILE,
@ -120,7 +122,7 @@ def _file_handle(latest_version: str | None):
class UpdateManager: class UpdateManager:
@classmethod @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 ( from zhenxun.builtin_plugins.web_ui.public.data_source import (
update_webui_assets, update_webui_assets,
) )
@ -133,8 +135,26 @@ class UpdateManager:
shutil.rmtree(BACKUP_PATH) shutil.rmtree(BACKUP_PATH)
WEBUI_PATH.rename(BACKUP_PATH) WEBUI_PATH.rename(BACKUP_PATH)
try: try:
await update_webui_assets() if is_zip:
logger.info("更新webui成功...", COMMAND) 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(): if BACKUP_PATH.exists():
logger.debug(f"删除旧的webui文件夹 {BACKUP_PATH}", COMMAND) logger.debug(f"删除旧的webui文件夹 {BACKUP_PATH}", COMMAND)
shutil.rmtree(BACKUP_PATH) shutil.rmtree(BACKUP_PATH)

View File

@ -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" DEFAULT_GITHUB_URL = "https://github.com/HibiKier/zhenxun_bot/tree/main"
RELEASE_URL = "https://api.github.com/repos/HibiKier/zhenxun_bot/releases/latest" 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_STRING = "__version__"
VERSION_FILE = Path() / VERSION_FILE_STRING VERSION_FILE = Path() / VERSION_FILE_STRING

View File

@ -148,6 +148,11 @@ async def get_plugin_and_user(
user = await with_timeout( user = await with_timeout(
user_dao.safe_get_or_none(user_id=user_id), name="get_user" 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: if not plugin:
raise PermissionExemption(f"插件:{module} 数据不存在,已跳过权限检查...") raise PermissionExemption(f"插件:{module} 数据不存在,已跳过权限检查...")

View File

@ -3,12 +3,14 @@ from pathlib import Path
import shutil import shutil
import zipfile 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.services.log import logger
from zhenxun.utils.github_utils import GithubUtils from zhenxun.utils.github_utils import GithubUtils
from zhenxun.utils.http_utils import AsyncHttpx 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): class DownloadResourceException(Exception):
@ -20,29 +22,41 @@ class ResourceManager:
RESOURCE_PATH = Path() / "resources" RESOURCE_PATH = Path() / "resources"
TMP_PATH = Path() / "_resource_tmp" TMP_PATH = TEMP_PATH / "_resource_tmp"
ZIP_FILE = TMP_PATH / "resources.zip" ZIP_FILE = TMP_PATH / "resources.zip"
UNZIP_PATH = None UNZIP_PATH = None
@classmethod @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: if (FONT_PATH.exists() and os.listdir(FONT_PATH)) and not force:
return return
if cls.TMP_PATH.exists(): if cls.TMP_PATH.exists():
logger.debug( logger.debug(
"resources临时文件夹已存在移除resources临时文件夹", CMD_STRING "resources临时文件夹已存在移除resources临时文件夹", LOG_COMMAND
) )
shutil.rmtree(cls.TMP_PATH) await clean_git(cls.TMP_PATH)
cls.TMP_PATH.mkdir(parents=True, exist_ok=True) shutil.rmtree(cls.TMP_PATH, ignore_errors=True)
try: if is_zip:
await cls.__download_resources() 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() cls.file_handle()
except Exception as e:
logger.error("获取resources资源包失败", CMD_STRING, e=e)
if cls.TMP_PATH.exists(): 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) shutil.rmtree(cls.TMP_PATH)
@classmethod @classmethod
@ -68,17 +82,17 @@ class ResourceManager:
"""获取resources文件夹""" """获取resources文件夹"""
repo_info = GithubUtils.parse_github_url(cls.GITHUB_URL) repo_info = GithubUtils.parse_github_url(cls.GITHUB_URL)
url = await repo_info.get_archive_download_urls() 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): if not await AsyncHttpx.download_file(url, cls.ZIP_FILE, stream=True):
logger.error( logger.error(
"下载resources资源包失败请尝试重启重新下载或前往 " "下载resources资源包失败请尝试重启重新下载或前往 "
"https://github.com/zhenxun-org/zhenxun-bot-resources 手动下载..." "https://github.com/zhenxun-org/zhenxun-bot-resources 手动下载..."
) )
raise DownloadResourceException("下载resources资源包失败...") raise DownloadResourceException("下载resources资源包失败...")
logger.debug("下载resources资源文件压缩包完成...", CMD_STRING) logger.debug("下载resources资源文件压缩包完成...", LOG_COMMAND)
tf = zipfile.ZipFile(cls.ZIP_FILE) tf = zipfile.ZipFile(cls.ZIP_FILE)
tf.extractall(cls.TMP_PATH) tf.extractall(cls.TMP_PATH)
logger.debug("解压文件压缩包完成...", CMD_STRING) logger.debug("解压文件压缩包完成...", LOG_COMMAND)
download_file_path = cls.TMP_PATH / next( download_file_path = cls.TMP_PATH / next(
x for x in os.listdir(cls.TMP_PATH) if (cls.TMP_PATH / x).is_dir() x for x in os.listdir(cls.TMP_PATH) if (cls.TMP_PATH / x).is_dir()
) )

View File

@ -69,7 +69,7 @@ class AliyunCodeupManager(BaseRepoManager):
self._check_config() self._check_config()
# 获取仓库名称从URL中提取 # 获取仓库名称从URL中提取
repo_url = repo_url.split("/")[-1].replace(".git", "") repo_url = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
# 获取仓库最新提交ID # 获取仓库最新提交ID
newest_commit = await self._get_newest_commit(repo_url, branch) newest_commit = await self._get_newest_commit(repo_url, branch)
@ -77,7 +77,9 @@ class AliyunCodeupManager(BaseRepoManager):
# 创建结果对象 # 创建结果对象
result = RepoUpdateResult( result = RepoUpdateResult(
repo_type=RepoType.ALIYUN, 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, owner=self.config.aliyun_codeup.organization_id,
old_version="", # 将在后面更新 old_version="", # 将在后面更新
new_version=newest_commit, new_version=newest_commit,
@ -99,7 +101,7 @@ class AliyunCodeupManager(BaseRepoManager):
local_path.mkdir(parents=True, exist_ok=True) local_path.mkdir(parents=True, exist_ok=True)
# 获取仓库名称从URL中提取 # 获取仓库名称从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( changed_files = await self._get_changed_files(
@ -135,7 +137,7 @@ class AliyunCodeupManager(BaseRepoManager):
except RepoUpdateError as e: except RepoUpdateError as e:
logger.error(f"更新仓库失败: {e}") logger.error(f"更新仓库失败: {e}")
# 从URL中提取仓库名称 # 从URL中提取仓库名称
repo_name = repo_url.split("/")[-1].replace(".git", "") repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
return RepoUpdateResult( return RepoUpdateResult(
repo_type=RepoType.ALIYUN, repo_type=RepoType.ALIYUN,
repo_name=repo_name, repo_name=repo_name,
@ -147,7 +149,7 @@ class AliyunCodeupManager(BaseRepoManager):
except Exception as e: except Exception as e:
logger.error(f"更新仓库失败: {e}") logger.error(f"更新仓库失败: {e}")
# 从URL中提取仓库名称 # 从URL中提取仓库名称
repo_name = repo_url.split("/")[-1].replace(".git", "") repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
return RepoUpdateResult( return RepoUpdateResult(
repo_type=RepoType.ALIYUN, repo_type=RepoType.ALIYUN,
repo_name=repo_name, repo_name=repo_name,
@ -181,12 +183,16 @@ class AliyunCodeupManager(BaseRepoManager):
self._check_config() self._check_config()
# 获取仓库名称从URL中提取 # 获取仓库名称从URL中提取
repo_identifier = repo_url.split("/")[-1].replace(".git", "") repo_identifier = (
repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
)
# 创建结果对象 # 创建结果对象
result = FileDownloadResult( result = FileDownloadResult(
repo_type=RepoType.ALIYUN, 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, file_path=file_path,
version=branch, version=branch,
) )
@ -206,7 +212,7 @@ class AliyunCodeupManager(BaseRepoManager):
except RepoDownloadError as e: except RepoDownloadError as e:
logger.error(f"下载文件失败: {e}") logger.error(f"下载文件失败: {e}")
# 从URL中提取仓库名称 # 从URL中提取仓库名称
repo_name = repo_url.split("/")[-1].replace(".git", "") repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
return FileDownloadResult( return FileDownloadResult(
repo_type=RepoType.ALIYUN, repo_type=RepoType.ALIYUN,
repo_name=repo_name, repo_name=repo_name,
@ -217,7 +223,7 @@ class AliyunCodeupManager(BaseRepoManager):
except Exception as e: except Exception as e:
logger.error(f"下载文件失败: {e}") logger.error(f"下载文件失败: {e}")
# 从URL中提取仓库名称 # 从URL中提取仓库名称
repo_name = repo_url.split("/")[-1].replace(".git", "") repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
return FileDownloadResult( return FileDownloadResult(
repo_type=RepoType.ALIYUN, repo_type=RepoType.ALIYUN,
repo_name=repo_name, repo_name=repo_name,
@ -250,7 +256,9 @@ class AliyunCodeupManager(BaseRepoManager):
self._check_config() self._check_config()
# 获取仓库名称从URL中提取 # 获取仓库名称从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" search_type = "RECURSIVE" if recursive else "DIRECT"
@ -298,7 +306,9 @@ class AliyunCodeupManager(BaseRepoManager):
self._check_config() self._check_config()
# 获取仓库名称从URL中提取 # 获取仓库名称从URL中提取
repo_identifier = repo_url.split("/")[-1].replace(".git", "") repo_identifier = (
repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
)
# 获取提交信息 # 获取提交信息
# 注意这里假设AliyunFileInfo有get_commit_info方法如果没有需要实现 # 注意这里假设AliyunFileInfo有get_commit_info方法如果没有需要实现
@ -440,7 +450,7 @@ class AliyunCodeupManager(BaseRepoManager):
def prepare_aliyun_url(repo_url: str) -> str: def prepare_aliyun_url(repo_url: str) -> str:
import base64 import base64
repo_name = repo_url.split("/")[-1].replace(".git", "") repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
# 构建仓库URL # 构建仓库URL
# 阿里云CodeUp的仓库URL格式通常为 # 阿里云CodeUp的仓库URL格式通常为
# https://codeup.aliyun.com/{organization_id}/{organization_name}/{repo_name}.git # https://codeup.aliyun.com/{organization_id}/{organization_name}/{repo_name}.git

View File

@ -230,7 +230,7 @@ class BaseRepoManager(ABC):
""" """
from .models import RepoType from .models import RepoType
repo_name = repo_url.split("/")[-1].replace(".git", "") repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
try: try:
# 创建结果对象 # 创建结果对象

View File

@ -172,7 +172,9 @@ class GithubManager(BaseRepoManager):
返回: 返回:
FileDownloadResult: 下载结果 FileDownloadResult: 下载结果
""" """
repo_name = repo_url.split("/")[-1].replace(".git", "").strip() repo_name = (
repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "").strip()
)
try: try:
# 解析仓库URL # 解析仓库URL
repo_info = GithubUtils.parse_github_url(repo_url) repo_info = GithubUtils.parse_github_url(repo_url)

View File

@ -31,6 +31,17 @@ async def check_git() -> bool:
return False 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( async def run_git_command(
command: str, cwd: Path | None = None command: str, cwd: Path | None = None
) -> tuple[bool, str, str]: ) -> tuple[bool, str, str]: