zhenxun_bot/zhenxun/utils/manager/virtual_env_package_manager.py

187 lines
6.0 KiB
Python
Raw Normal View History

2025-07-31 19:04:14 +08:00
import asyncio
from pathlib import Path
import subprocess
from subprocess import CalledProcessError
from typing import ClassVar
from zhenxun.configs.config import Config
from zhenxun.services.log import logger
BAT_FILE = Path() / "win启动.bat"
LOG_COMMAND = "VirtualEnvPackageManager"
Config.add_plugin_config(
"virtualenv",
"python_path",
None,
help="虚拟环境python路径为空时使用系统环境的poetry",
)
class VirtualEnvPackageManager:
WIN_COMMAND: ClassVar[list[str]] = [
"./Python310/python.exe",
"-m",
"pip",
]
DEFAULT_COMMAND: ClassVar[list[str]] = ["poetry", "run", "pip"]
@classmethod
def __get_command(cls) -> list[str]:
if path := Config.get_config("virtualenv", "python_path"):
return [path, "-m", "pip"]
return (
cls.WIN_COMMAND.copy() if BAT_FILE.exists() else cls.DEFAULT_COMMAND.copy()
)
@classmethod
2025-07-31 19:04:14 +08:00
async def install(cls, package: list[str] | str):
"""安装依赖包
参数:
package: 安装依赖包名称或列表
"""
if isinstance(package, str):
package = [package]
try:
command = cls.__get_command()
command.append("install")
command.append(" ".join(package))
logger.info(f"执行虚拟环境安装包指令: {command}", LOG_COMMAND)
2025-07-31 19:04:14 +08:00
result = await asyncio.to_thread(
subprocess.run,
command,
check=True,
capture_output=True,
text=True,
)
logger.debug(
f"安装虚拟环境包指令执行完成: {result.stdout}",
LOG_COMMAND,
)
return result.stdout
except CalledProcessError as e:
logger.error(f"安装虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
return e.stderr
@classmethod
2025-07-31 19:04:14 +08:00
async def uninstall(cls, package: list[str] | str):
"""卸载依赖包
参数:
package: 卸载依赖包名称或列表
"""
if isinstance(package, str):
package = [package]
try:
command = cls.__get_command()
command.append("uninstall")
command.append("-y")
command.append(" ".join(package))
logger.info(f"执行虚拟环境卸载包指令: {command}", LOG_COMMAND)
2025-07-31 19:04:14 +08:00
result = await asyncio.to_thread(
subprocess.run,
command,
check=True,
capture_output=True,
text=True,
)
logger.debug(
f"卸载虚拟环境包指令执行完成: {result.stdout}",
LOG_COMMAND,
)
return result.stdout
except CalledProcessError as e:
logger.error(f"卸载虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
return e.stderr
@classmethod
2025-07-31 19:04:14 +08:00
async def update(cls, package: list[str] | str):
"""更新依赖包
参数:
package: 更新依赖包名称或列表
"""
if isinstance(package, str):
package = [package]
try:
command = cls.__get_command()
command.append("install")
command.append("--upgrade")
command.append(" ".join(package))
logger.info(f"执行虚拟环境更新包指令: {command}", LOG_COMMAND)
2025-07-31 19:04:14 +08:00
result = await asyncio.to_thread(
subprocess.run,
command,
check=True,
capture_output=True,
text=True,
)
logger.debug(f"更新虚拟环境包指令执行完成: {result.stdout}", LOG_COMMAND)
return result.stdout
except CalledProcessError as e:
logger.error(f"更新虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
return e.stderr
@classmethod
2025-07-31 19:04:14 +08:00
async def install_requirement(cls, requirement_file: Path):
"""安装依赖文件
参数:
requirement_file: requirement文件路径
异常:
FileNotFoundError: 文件不存在
"""
if not requirement_file.exists():
raise FileNotFoundError(f"依赖文件 {requirement_file} 不存在", LOG_COMMAND)
try:
command = cls.__get_command()
command.append("install")
command.append("-r")
command.append(str(requirement_file.absolute()))
logger.info(f"执行虚拟环境安装依赖文件指令: {command}", LOG_COMMAND)
2025-07-31 19:04:14 +08:00
result = await asyncio.to_thread(
subprocess.run,
command,
check=True,
capture_output=True,
text=True,
)
logger.debug(
f"安装虚拟环境依赖文件指令执行完成: {result.stdout}",
LOG_COMMAND,
)
return result.stdout
except CalledProcessError as e:
logger.error(
f"安装虚拟环境依赖文件指令执行失败: {e.stderr}.",
LOG_COMMAND,
)
return e.stderr
@classmethod
2025-07-31 19:04:14 +08:00
async def list(cls) -> str:
"""列出已安装的依赖包"""
try:
command = cls.__get_command()
command.append("list")
logger.info(f"执行虚拟环境列出包指令: {command}", LOG_COMMAND)
2025-07-31 19:04:14 +08:00
result = await asyncio.to_thread(
subprocess.run,
command,
check=True,
capture_output=True,
text=True,
)
logger.debug(
f"列出虚拟环境包指令执行完成: {result.stdout}",
LOG_COMMAND,
)
return result.stdout
except CalledProcessError as e:
logger.error(f"列出虚拟环境包指令执行失败: {e.stderr}.", LOG_COMMAND)
return ""