From 638efd9e07ca4b6b5e2d9d110f5bcfd58666ffac Mon Sep 17 00:00:00 2001 From: molanp <104612722+molanp@users.noreply.github.com> Date: Sat, 24 Aug 2024 19:07:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(plugin=5Fstore):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8F=92=E4=BB=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加了更新插件的功能,现在可以通过插件商店更新已安装的插件。此更新包括了插件版本的检查和更新逻辑, 优化了插件管理的便捷性。 --- .../builtin_plugins/plugin_store/__init__.py | 28 ++++++++ .../plugin_store/data_source.py | 71 ++++++++++++++++--- 2 files changed, 89 insertions(+), 10 deletions(-) diff --git a/zhenxun/builtin_plugins/plugin_store/__init__.py b/zhenxun/builtin_plugins/plugin_store/__init__.py index afa9dd5f..9c0678e4 100644 --- a/zhenxun/builtin_plugins/plugin_store/__init__.py +++ b/zhenxun/builtin_plugins/plugin_store/__init__.py @@ -19,6 +19,7 @@ __plugin_meta__ = PluginMetadata( 添加插件 id : 添加插件 移除插件 id : 移除插件 搜索插件 name or author : 搜索插件 + 更新插件 id : 更新插件 """.strip(), extra=PluginExtraData( author="HibiKier", @@ -33,6 +34,7 @@ _matcher = on_alconna( Subcommand("add", Args["plugin_id", int]), Subcommand("remove", Args["plugin_id", int]), Subcommand("search", Args["plugin_name_or_author", str]), + Subcommand("update", Args["plugin_id", int]), ), permission=SUPERUSER, priority=1, @@ -60,6 +62,12 @@ _matcher.shortcut( prefix=True, ) +_matcher.shortcut( + r"更新插件", + command="插件商店", + arguments=["update", "{%0}"], + prefix=True, +) @_matcher.assign("$main") async def _(session: EventSession): @@ -76,6 +84,9 @@ async def _(session: EventSession): @_matcher.assign("add") async def _(session: EventSession, plugin_id: int): try: + await MessageUtils.build_message( + f"正在添加插件 Id: {plugin_id}" + ).send() result = await ShopManage.add_plugin(plugin_id) except FinishedException: pass @@ -115,3 +126,20 @@ async def _(session: EventSession, plugin_name_or_author: str): ).finish() logger.info(f"搜索插件 name: {plugin_name_or_author}", "插件商店", session=session) await MessageUtils.build_message(result).finish() + +@_matcher.assign("update") +async def _(session: EventSession, plugin_id: int): + try: + await MessageUtils.build_message( + f"正在更新插件 Id: {plugin_id}" + ).send() + result = await ShopManage.update_plugin(plugin_id) + except FinishedException: + pass + except Exception as e: + logger.error(f"更新插件 Id: {plugin_id}失败", "插件商店", session=session, e=e) + await MessageUtils.build_message( + f"更新插件 Id: {plugin_id} 失败 e: {e}" + ).finish() + logger.info(f"更新插件 Id: {plugin_id}", "插件商店", session=session) + await MessageUtils.build_message(result).finish() diff --git a/zhenxun/builtin_plugins/plugin_store/data_source.py b/zhenxun/builtin_plugins/plugin_store/data_source.py index b39ade7d..e26fca7a 100644 --- a/zhenxun/builtin_plugins/plugin_store/data_source.py +++ b/zhenxun/builtin_plugins/plugin_store/data_source.py @@ -140,8 +140,12 @@ class ShopManage: for k in data.copy(): if data[k]["plugin_type"]: data[k]["plugin_type"] = cls.type2name[data[k]["plugin_type"]] - suc_plugin = [p.name for p in nonebot.get_loaded_plugins() # type: ignore - ] + suc_plugin = { + p.name: p.metadata.extra["version"] + for p in nonebot.get_loaded_plugins() + if hasattr(p, "metadata") and hasattr(p.metadata, "type") and (p.metadata.type == 'application' or p.metadata.type is None) and "version" in p.metadata.extra.keys() + } + data_list = [ [ "已安装" if plugin_info[1]["module"] in suc_plugin else "", @@ -149,7 +153,12 @@ class ShopManage: plugin_info[0], plugin_info[1]["description"], plugin_info[1]["author"], - plugin_info[1]["version"], + ( + f"{suc_plugin[plugin_info[1]['module']]} (有更新->{plugin_info[1]['version']})" + if plugin_info[1]["module"] in suc_plugin + and plugin_info[1]["version"] != suc_plugin[plugin_info[1]["module"]] + else plugin_info[1]["version"] + ), plugin_info[1]["plugin_type"], ] for id, plugin_info in enumerate(data.items()) @@ -226,8 +235,11 @@ class ShopManage: for k in data.copy(): if data[k]["plugin_type"]: data[k]["plugin_type"] = cls.type2name[data[k]["plugin_type"]] - - suc_plugin = [p.name for p in nonebot.get_loaded_plugins()] # type: ignore + suc_plugin = { + p.name: p.metadata.extra["version"] + for p in nonebot.get_loaded_plugins() + if hasattr(p, "metadata") and hasattr(p.metadata, "type") and (p.metadata.type == 'application' or p.metadata.type is None) and "version" in p.metadata.extra.keys() + } filtered_data = [ (id, plugin_info) for id, plugin_info in enumerate(data.items()) @@ -242,19 +254,58 @@ class ShopManage: plugin_info[0], plugin_info[1]["description"], plugin_info[1]["author"], - plugin_info[1]["version"], + ( + f"{suc_plugin[plugin_info[1]['module']]} (有更新->{plugin_info[1]['version']})" + if plugin_info[1]["module"] in suc_plugin + and plugin_info[1]["version"] != suc_plugin[plugin_info[1]["module"]] + else plugin_info[1]["version"] + ), plugin_info[1]["plugin_type"], ] for id, plugin_info in filtered_data ] - if len(data_list) == 0: - return "未找到插件..." - + return "未找到相关插件..." return await ImageTemplate.table_page( "插件列表", f"通过安装/卸载插件 ID 来管理插件", column_name, data_list, text_style=row_style, - ) \ No newline at end of file + ) + + @classmethod + async def update_plugin(cls, plugin_id: int) -> str: + data: dict = await cls.__get_data() + if plugin_id < 0 or plugin_id >= len(data): + return "插件ID不存在..." + plugin_key = list(data.keys())[plugin_id] + plugin_info = data[plugin_key] + module_path_split = plugin_info["module_path"].split(".") + url_path = None + path = BASE_PATH + if len(module_path_split) == 2: + """单个文件或文件夹""" + if plugin_info["is_dir"]: + url_path = "/".join(module_path_split) + else: + url_path = "/".join(module_path_split) + ".py" + else: + """嵌套文件或文件夹""" + for p in module_path_split[:-1]: + path = path / p + path.mkdir(parents=True, exist_ok=True) + if plugin_info["is_dir"]: + url_path = f"{'/'.join(module_path_split)}" + else: + url_path = f"{'/'.join(module_path_split)}.py" + if not url_path: + return "插件下载地址构建失败..." + logger.debug(f"尝试下载插件 URL: {url_path}", "插件管理") + await download_file(DOWNLOAD_URL.format(url_path)) + + # 安装依赖 + plugin_path = BASE_PATH / "/".join(module_path_split) + install_requirement(plugin_path) + + return f"插件 {plugin_key} 更新成功!" \ No newline at end of file