新增依赖管理功能,支持安装和卸载虚拟环境依赖,同时优化相关API和数据模型 (#1936)

This commit is contained in:
HibiKier 2025-07-11 10:10:53 +08:00 committed by GitHub
parent bd62698ea5
commit 4bcc5aeea5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 52 additions and 6 deletions

View File

@ -4,6 +4,7 @@ from fastapi.responses import JSONResponse
from zhenxun.models.plugin_info import PluginInfo as DbPluginInfo from zhenxun.models.plugin_info import PluginInfo as DbPluginInfo
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.utils.enum import BlockType, PluginType from zhenxun.utils.enum import BlockType, PluginType
from zhenxun.utils.manager.virtual_env_package_manager import VirtualEnvPackageManager
from ....base_model import Result from ....base_model import Result
from ....utils import authentication, clear_help_image from ....utils import authentication, clear_help_image
@ -11,6 +12,7 @@ from .data_source import ApiDataSource
from .model import ( from .model import (
BatchUpdatePlugins, BatchUpdatePlugins,
BatchUpdateResult, BatchUpdateResult,
InstallDependenciesPayload,
PluginCount, PluginCount,
PluginDetail, PluginDetail,
PluginInfo, PluginInfo,
@ -162,9 +164,9 @@ async def _(module: str) -> Result[PluginDetail]:
dependencies=[authentication()], dependencies=[authentication()],
response_model=Result[BatchUpdateResult], response_model=Result[BatchUpdateResult],
response_class=JSONResponse, response_class=JSONResponse,
summary="批量更新插件配置", description="批量更新插件配置",
) )
async def batch_update_plugin_config_api( async def _(
params: BatchUpdatePlugins, params: BatchUpdatePlugins,
) -> Result[BatchUpdateResult]: ) -> Result[BatchUpdateResult]:
"""批量更新插件配置,如开关、类型等""" """批量更新插件配置,如开关、类型等"""
@ -187,9 +189,9 @@ async def batch_update_plugin_config_api(
"/menu_type/rename", "/menu_type/rename",
dependencies=[authentication()], dependencies=[authentication()],
response_model=Result, response_model=Result,
summary="重命名菜单类型", description="重命名菜单类型",
) )
async def rename_menu_type_api(payload: RenameMenuTypePayload) -> Result: async def _(payload: RenameMenuTypePayload) -> Result[str]:
try: try:
result = await ApiDataSource.rename_menu_type( result = await ApiDataSource.rename_menu_type(
old_name=payload.old_name, new_name=payload.new_name old_name=payload.old_name, new_name=payload.new_name
@ -213,3 +215,24 @@ async def rename_menu_type_api(payload: RenameMenuTypePayload) -> Result:
except Exception as e: except Exception as e:
logger.error(f"{router.prefix}/menu_type/rename 调用错误", "WebUi", e=e) logger.error(f"{router.prefix}/menu_type/rename 调用错误", "WebUi", e=e)
return Result.fail(info=f"发生未知错误: {type(e).__name__}") return Result.fail(info=f"发生未知错误: {type(e).__name__}")
@router.post(
"/install_dependencies",
dependencies=[authentication()],
response_model=Result,
response_class=JSONResponse,
description="安装/卸载依赖",
)
async def _(payload: InstallDependenciesPayload) -> Result:
try:
if not payload.dependencies:
return Result.fail("依赖列表不能为空")
if payload.handle_type == "install":
result = VirtualEnvPackageManager.install(payload.dependencies)
else:
result = VirtualEnvPackageManager.uninstall(payload.dependencies)
return Result.ok(result)
except Exception as e:
logger.error(f"{router.prefix}/install_dependencies 调用错误", "WebUi", e=e)
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")

View File

@ -1,4 +1,4 @@
from typing import Any from typing import Any, Literal
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@ -162,3 +162,15 @@ class BatchUpdateResult(BaseModel):
default_factory=list, description="错误信息列表" default_factory=list, description="错误信息列表"
) )
"""错误信息列表""" """错误信息列表"""
class InstallDependenciesPayload(BaseModel):
"""
安装依赖
"""
handle_type: Literal["install", "uninstall"] = Field(..., description="处理类型")
"""处理类型"""
dependencies: list[str] = Field(..., description="依赖列表")
"""依赖列表"""

View File

@ -31,7 +31,9 @@ class VirtualEnvPackageManager:
def __get_command(cls) -> list[str]: def __get_command(cls) -> list[str]:
if path := Config.get_config("virtualenv", "python_path"): if path := Config.get_config("virtualenv", "python_path"):
return [path, "-m", "pip"] return [path, "-m", "pip"]
return cls.WIN_COMMAND if BAT_FILE.exists() else cls.DEFAULT_COMMAND return (
cls.WIN_COMMAND.copy() if BAT_FILE.exists() else cls.DEFAULT_COMMAND.copy()
)
@classmethod @classmethod
def install(cls, package: list[str] | str): def install(cls, package: list[str] | str):
@ -57,8 +59,10 @@ class VirtualEnvPackageManager:
f"安装虚拟环境包指令执行完成: {result.stdout}", f"安装虚拟环境包指令执行完成: {result.stdout}",
LOG_COMMAND, LOG_COMMAND,
) )
return result.stdout
except CalledProcessError as e: except CalledProcessError as e:
logger.error(f"安装虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND) logger.error(f"安装虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
return e.stderr
@classmethod @classmethod
def uninstall(cls, package: list[str] | str): def uninstall(cls, package: list[str] | str):
@ -72,6 +76,7 @@ class VirtualEnvPackageManager:
try: try:
command = cls.__get_command() command = cls.__get_command()
command.append("uninstall") command.append("uninstall")
command.append("-y")
command.append(" ".join(package)) command.append(" ".join(package))
logger.info(f"执行虚拟环境卸载包指令: {command}", LOG_COMMAND) logger.info(f"执行虚拟环境卸载包指令: {command}", LOG_COMMAND)
result = subprocess.run( result = subprocess.run(
@ -84,8 +89,10 @@ class VirtualEnvPackageManager:
f"卸载虚拟环境包指令执行完成: {result.stdout}", f"卸载虚拟环境包指令执行完成: {result.stdout}",
LOG_COMMAND, LOG_COMMAND,
) )
return result.stdout
except CalledProcessError as e: except CalledProcessError as e:
logger.error(f"卸载虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND) logger.error(f"卸载虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
return e.stderr
@classmethod @classmethod
def update(cls, package: list[str] | str): def update(cls, package: list[str] | str):
@ -109,8 +116,10 @@ class VirtualEnvPackageManager:
text=True, text=True,
) )
logger.debug(f"更新虚拟环境包指令执行完成: {result.stdout}", LOG_COMMAND) logger.debug(f"更新虚拟环境包指令执行完成: {result.stdout}", LOG_COMMAND)
return result.stdout
except CalledProcessError as e: except CalledProcessError as e:
logger.error(f"更新虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND) logger.error(f"更新虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
return e.stderr
@classmethod @classmethod
def install_requirement(cls, requirement_file: Path): def install_requirement(cls, requirement_file: Path):
@ -140,11 +149,13 @@ class VirtualEnvPackageManager:
f"安装虚拟环境依赖文件指令执行完成: {result.stdout}", f"安装虚拟环境依赖文件指令执行完成: {result.stdout}",
LOG_COMMAND, LOG_COMMAND,
) )
return result.stdout
except CalledProcessError as e: except CalledProcessError as e:
logger.error( logger.error(
f"安装虚拟环境依赖文件指令执行失败: {e.stderr}.", f"安装虚拟环境依赖文件指令执行失败: {e.stderr}.",
LOG_COMMAND, LOG_COMMAND,
) )
return e.stderr
@classmethod @classmethod
def list(cls) -> str: def list(cls) -> str: