检查更新支持webui更新 (#1925)

*  检查更新支持webui跟新

* 🎨 移除无用导入
This commit is contained in:
HibiKier 2025-07-11 10:11:14 +08:00 committed by GitHub
parent 4bcc5aeea5
commit acfed0837a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 90 additions and 34 deletions

View File

@ -29,6 +29,7 @@
"unban",
"Uninfo",
"userinfo",
"webui",
"zhenxun"
],
"python.analysis.autoImportCompletions": true,

View File

@ -13,7 +13,11 @@ from pytest_mock import MockerFixture
from respx import MockRouter
from tests.config import BotId, GroupId, MessageId, UserId
from tests.utils import _v11_group_message_event, _v11_private_message_send
from tests.utils import (
_v11_group_message_event,
_v11_private_message_send,
get_reply_cq,
)
from tests.utils import get_response_json as _get_response_json
@ -311,6 +315,12 @@ async def test_check_update_release(
to_me=True,
)
ctx.receive_event(bot, event)
ctx.should_call_send(
event=event,
message=Message(f"{get_reply_cq(MessageId.MESSAGE_ID)}正在进行检查更新..."),
result=None,
bot=bot,
)
ctx.should_call_api(
"send_msg",
_v11_private_message_send(
@ -401,6 +411,12 @@ async def test_check_update_main(
to_me=True,
)
ctx.receive_event(bot, event)
ctx.should_call_send(
event=event,
message=Message(f"{get_reply_cq(MessageId.MESSAGE_ID)}正在进行检查更新..."),
result=None,
bot=bot,
)
ctx.should_call_api(
"send_msg",
_v11_private_message_send(

View File

@ -5,6 +5,10 @@ from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageSegme
from nonebot.adapters.onebot.v11.event import Sender
def get_reply_cq(uid: int | str) -> str:
return f"[CQ:reply,id={uid}]"
def get_response_json(base_path: Path, file: str) -> dict:
try:
return json.loads(

View File

@ -11,7 +11,7 @@ from nonebot_plugin_alconna import (
on_alconna,
store_true,
)
from nonebot_plugin_session import EventSession
from nonebot_plugin_uninfo import Uninfo
from zhenxun.configs.utils import PluginExtraData
from zhenxun.services.log import logger
@ -22,7 +22,7 @@ from zhenxun.utils.manager.resource_manager import (
)
from zhenxun.utils.message import MessageUtils
from ._data_source import UpdateManage
from ._data_source import UpdateManager
__plugin_meta__ = PluginMetadata(
name="自动更新",
@ -32,16 +32,18 @@ __plugin_meta__ = PluginMetadata(
检查更新真寻最新版本包括了自动更新
资源文件大小一般在130mb左右除非必须更新一般仅更新代码文件
指令
检查更新 [main|release|resource] ?[-r]
检查更新 [main|release|resource|webui] ?[-r]
main: main分支
release: 最新release
resource: 资源文件
webui: webui文件
-r: 下载资源文件一般在更新main或release时使用
示例:
检查更新 main
检查更新 main -r
检查更新 release -r
检查更新 resource
检查更新 webui
""".strip(),
extra=PluginExtraData(
author="HibiKier",
@ -53,7 +55,7 @@ __plugin_meta__ = PluginMetadata(
_matcher = on_alconna(
Alconna(
"检查更新",
Args["ver_type?", ["main", "release", "resource"]],
Args["ver_type?", ["main", "release", "resource", "webui"]],
Option("-r|--resource", action=store_true, help_text="下载资源文件"),
),
priority=1,
@ -66,23 +68,24 @@ _matcher = on_alconna(
@_matcher.handle()
async def _(
bot: Bot,
session: EventSession,
session: Uninfo,
ver_type: Match[str],
resource: Query[bool] = Query("resource", False),
):
if not session.id1:
await MessageUtils.build_message("用户id为空...").finish()
result = ""
await MessageUtils.build_message("正在进行检查更新...").send(reply_to=True)
if ver_type.result in {"main", "release"}:
if not ver_type.available:
result = await UpdateManage.check_version()
result = await UpdateManager.check_version()
logger.info("查看当前版本...", "检查更新", session=session)
await MessageUtils.build_message(result).finish()
try:
result = await UpdateManage.update(bot, session.id1, ver_type.result)
result = await UpdateManager.update(bot, session.user.id, ver_type.result)
except Exception as e:
logger.error("版本更新失败...", "检查更新", session=session, e=e)
await MessageUtils.build_message(f"更新版本失败...e: {e}").finish()
elif ver_type.result == "webui":
result = await UpdateManager.update_webui()
if resource.result or ver_type.result == "resource":
try:
await ResourceManager.init_resources(True)

View File

@ -7,6 +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.services.log import logger
from zhenxun.utils.github_utils import GithubUtils
from zhenxun.utils.github_utils.models import RepoInfo
@ -17,6 +18,7 @@ from .config import (
BACKUP_PATH,
BASE_PATH,
BASE_PATH_STRING,
COMMAND,
DEFAULT_GITHUB_URL,
DOWNLOAD_GZ_FILE,
DOWNLOAD_ZIP_FILE,
@ -38,7 +40,7 @@ def install_requirement():
if not requirement_path.exists():
logger.debug(
f"没有找到zhenxun的requirement.txt,目标路径为{requirement_path}", "插件管理"
f"没有找到zhenxun的requirement.txt,目标路径为{requirement_path}", COMMAND
)
return
try:
@ -48,9 +50,9 @@ def install_requirement():
capture_output=True,
text=True,
)
logger.debug(f"成功安装真寻依赖,日志:\n{result.stdout}", "插件管理")
logger.debug(f"成功安装真寻依赖,日志:\n{result.stdout}", COMMAND)
except subprocess.CalledProcessError as e:
logger.error(f"安装真寻依赖失败,错误:\n{e.stderr}", "插件管理", e=e)
logger.error(f"安装真寻依赖失败,错误:\n{e.stderr}", COMMAND, e=e)
@run_sync
@ -61,7 +63,7 @@ def _file_handle(latest_version: str | None):
latest_version: 版本号
"""
BACKUP_PATH.mkdir(exist_ok=True, parents=True)
logger.debug("开始解压文件压缩包...", "检查更新")
logger.debug("开始解压文件压缩包...", COMMAND)
download_file = DOWNLOAD_GZ_FILE
if DOWNLOAD_GZ_FILE.exists():
tf = tarfile.open(DOWNLOAD_GZ_FILE)
@ -69,7 +71,7 @@ def _file_handle(latest_version: str | None):
download_file = DOWNLOAD_ZIP_FILE
tf = zipfile.ZipFile(DOWNLOAD_ZIP_FILE)
tf.extractall(TMP_PATH)
logger.debug("解压文件压缩包完成...", "检查更新")
logger.debug("解压文件压缩包完成...", COMMAND)
download_file_path = TMP_PATH / next(
x for x in os.listdir(TMP_PATH) if (TMP_PATH / x).is_dir()
)
@ -79,52 +81,52 @@ def _file_handle(latest_version: str | None):
extract_path = download_file_path / BASE_PATH_STRING
target_path = BASE_PATH
if PYPROJECT_FILE.exists():
logger.debug(f"移除备份文件: {PYPROJECT_FILE}", "检查更新")
logger.debug(f"移除备份文件: {PYPROJECT_FILE}", COMMAND)
shutil.move(PYPROJECT_FILE, BACKUP_PATH / PYPROJECT_FILE_STRING)
if PYPROJECT_LOCK_FILE.exists():
logger.debug(f"移除备份文件: {PYPROJECT_LOCK_FILE}", "检查更新")
logger.debug(f"移除备份文件: {PYPROJECT_LOCK_FILE}", COMMAND)
shutil.move(PYPROJECT_LOCK_FILE, BACKUP_PATH / PYPROJECT_LOCK_FILE_STRING)
if REQ_TXT_FILE.exists():
logger.debug(f"移除备份文件: {REQ_TXT_FILE}", "检查更新")
logger.debug(f"移除备份文件: {REQ_TXT_FILE}", COMMAND)
shutil.move(REQ_TXT_FILE, BACKUP_PATH / REQ_TXT_FILE_STRING)
if _pyproject.exists():
logger.debug("移动文件: pyproject.toml", "检查更新")
logger.debug("移动文件: pyproject.toml", COMMAND)
shutil.move(_pyproject, PYPROJECT_FILE)
if _lock_file.exists():
logger.debug("移动文件: poetry.lock", "检查更新")
logger.debug("移动文件: poetry.lock", COMMAND)
shutil.move(_lock_file, PYPROJECT_LOCK_FILE)
if _req_file.exists():
logger.debug("移动文件: requirements.txt", "检查更新")
logger.debug("移动文件: requirements.txt", COMMAND)
shutil.move(_req_file, REQ_TXT_FILE)
for folder in REPLACE_FOLDERS:
"""移动指定文件夹"""
_dir = BASE_PATH / folder
_backup_dir = BACKUP_PATH / folder
if _backup_dir.exists():
logger.debug(f"删除备份文件夹 {_backup_dir}", "检查更新")
logger.debug(f"删除备份文件夹 {_backup_dir}", COMMAND)
shutil.rmtree(_backup_dir)
if _dir.exists():
logger.debug(f"移动旧文件夹 {_dir}", "检查更新")
logger.debug(f"移动旧文件夹 {_dir}", COMMAND)
shutil.move(_dir, _backup_dir)
else:
logger.warning(f"文件夹 {_dir} 不存在,跳过删除", "检查更新")
logger.warning(f"文件夹 {_dir} 不存在,跳过删除", COMMAND)
for folder in REPLACE_FOLDERS:
src_folder_path = extract_path / folder
dest_folder_path = target_path / folder
if src_folder_path.exists():
logger.debug(
f"移动文件夹: {src_folder_path} -> {dest_folder_path}", "检查更新"
f"移动文件夹: {src_folder_path} -> {dest_folder_path}", COMMAND
)
shutil.move(src_folder_path, dest_folder_path)
else:
logger.debug(f"源文件夹不存在: {src_folder_path}", "检查更新")
logger.debug(f"源文件夹不存在: {src_folder_path}", COMMAND)
if tf:
tf.close()
if download_file.exists():
logger.debug(f"删除下载文件: {download_file}", "检查更新")
logger.debug(f"删除下载文件: {download_file}", COMMAND)
download_file.unlink()
if extract_path.exists():
logger.debug(f"删除解压文件夹: {extract_path}", "检查更新")
logger.debug(f"删除解压文件夹: {extract_path}", COMMAND)
shutil.rmtree(extract_path)
if TMP_PATH.exists():
shutil.rmtree(TMP_PATH)
@ -134,7 +136,35 @@ def _file_handle(latest_version: str | None):
install_requirement()
class UpdateManage:
class UpdateManager:
@classmethod
async def update_webui(cls) -> str:
from zhenxun.builtin_plugins.web_ui.public.data_source import (
update_webui_assets,
)
WEBUI_PATH = DATA_PATH / "web_ui" / "public"
BACKUP_PATH = DATA_PATH / "web_ui" / "backup_public"
if WEBUI_PATH.exists():
if BACKUP_PATH.exists():
logger.debug(f"删除旧的备份webui文件夹 {BACKUP_PATH}", COMMAND)
shutil.rmtree(BACKUP_PATH)
WEBUI_PATH.rename(BACKUP_PATH)
try:
await update_webui_assets()
logger.info("更新webui成功...", COMMAND)
if BACKUP_PATH.exists():
logger.debug(f"删除旧的webui文件夹 {BACKUP_PATH}", COMMAND)
shutil.rmtree(BACKUP_PATH)
return "Webui更新成功"
except Exception as e:
logger.error("更新webui失败...", COMMAND, e=e)
if BACKUP_PATH.exists():
logger.debug(f"恢复旧的webui文件夹 {BACKUP_PATH}", COMMAND)
BACKUP_PATH.rename(WEBUI_PATH)
raise e
return ""
@classmethod
async def check_version(cls) -> str:
"""检查更新版本
@ -166,7 +196,7 @@ class UpdateManage:
返回:
str | None: 返回消息
"""
logger.info("开始下载真寻最新版文件....", "检查更新")
logger.info("开始下载真寻最新版文件....", COMMAND)
cur_version = cls.__get_version()
url = None
new_version = None
@ -186,11 +216,11 @@ class UpdateManage:
if not url:
return "获取版本下载链接失败..."
if TMP_PATH.exists():
logger.debug(f"删除临时文件夹 {TMP_PATH}", "检查更新")
logger.debug(f"删除临时文件夹 {TMP_PATH}", COMMAND)
shutil.rmtree(TMP_PATH)
logger.debug(
f"开始更新版本:{cur_version} -> {new_version} | 下载链接:{url}",
"检查更新",
COMMAND,
)
await PlatformUtils.send_superuser(
bot,
@ -201,7 +231,7 @@ class UpdateManage:
DOWNLOAD_GZ_FILE if version_type == "release" else DOWNLOAD_ZIP_FILE
)
if await AsyncHttpx.download_file(url, download_file, stream=True):
logger.debug("下载真寻最新版文件完成...", "检查更新")
logger.debug("下载真寻最新版文件完成...", COMMAND)
await _file_handle(new_version)
result = "版本更新完成"
return (
@ -210,7 +240,7 @@ class UpdateManage:
"请重新启动真寻以完成更新!"
)
else:
logger.debug("下载真寻最新版文件失败...", "检查更新")
logger.debug("下载真寻最新版文件失败...", COMMAND)
return ""
@classmethod

View File

@ -34,3 +34,5 @@ REPLACE_FOLDERS = [
"models",
"configs",
]
COMMAND = "检查更新"