mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-14 13:42:56 +08:00
parent
4bcc5aeea5
commit
acfed0837a
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -29,6 +29,7 @@
|
||||
"unban",
|
||||
"Uninfo",
|
||||
"userinfo",
|
||||
"webui",
|
||||
"zhenxun"
|
||||
],
|
||||
"python.analysis.autoImportCompletions": true,
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -34,3 +34,5 @@ REPLACE_FOLDERS = [
|
||||
"models",
|
||||
"configs",
|
||||
]
|
||||
|
||||
COMMAND = "检查更新"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user