mirror of
https://github.com/Genshin-bots/gsuid_core.git
synced 2025-05-12 06:55:49 +08:00
✨ 启动时自动检查插件依赖是否安装, 并自动安装缺失依赖
This commit is contained in:
parent
92b010f0a9
commit
332c94b37e
@ -1,15 +1,24 @@
|
|||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import asyncio
|
import asyncio
|
||||||
import importlib
|
import importlib
|
||||||
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Callable
|
from typing import Dict, List, Callable
|
||||||
|
|
||||||
|
import toml
|
||||||
|
import pkg_resources
|
||||||
from fastapi import WebSocket
|
from fastapi import WebSocket
|
||||||
|
|
||||||
from gsuid_core.bot import _Bot
|
from gsuid_core.bot import _Bot
|
||||||
from gsuid_core.logger import logger
|
from gsuid_core.logger import logger
|
||||||
|
from gsuid_core.utils.plugins_config.gs_config import core_plugins_config
|
||||||
|
|
||||||
|
auto_install_dep: bool = core_plugins_config.get_config('AutoInstallDep').data
|
||||||
|
start_venv: str = core_plugins_config.get_config('StartVENV').data
|
||||||
core_start_def = set()
|
core_start_def = set()
|
||||||
|
installed_dependencies = []
|
||||||
|
ignore_dep = ['python', 'fastapi', 'pydantic']
|
||||||
|
|
||||||
|
|
||||||
def on_core_start(func: Callable):
|
def on_core_start(func: Callable):
|
||||||
@ -18,6 +27,22 @@ def on_core_start(func: Callable):
|
|||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
def check_start_tool():
|
||||||
|
path = Path(__file__).parent.parent
|
||||||
|
pdm_python_path = path / '.pdm-python'
|
||||||
|
if start_venv == 'auto':
|
||||||
|
if pdm_python_path.exists():
|
||||||
|
return 'pdm run pip'
|
||||||
|
else:
|
||||||
|
return 'poetry run pip'
|
||||||
|
elif start_venv == 'pdm':
|
||||||
|
return 'pdm run pip'
|
||||||
|
elif start_venv == 'poetry':
|
||||||
|
return 'poetry run pip'
|
||||||
|
else:
|
||||||
|
return start_venv.strip()
|
||||||
|
|
||||||
|
|
||||||
class GsServer:
|
class GsServer:
|
||||||
_instance = None
|
_instance = None
|
||||||
is_initialized = False
|
is_initialized = False
|
||||||
@ -38,11 +63,15 @@ class GsServer:
|
|||||||
|
|
||||||
def load_plugins(self):
|
def load_plugins(self):
|
||||||
logger.info('开始导入插件...')
|
logger.info('开始导入插件...')
|
||||||
|
get_installed_dependencies()
|
||||||
sys.path.append(str(Path(__file__).parents[1]))
|
sys.path.append(str(Path(__file__).parents[1]))
|
||||||
plug_path = Path(__file__).parent / 'plugins'
|
plug_path = Path(__file__).parent / 'plugins'
|
||||||
# 遍历插件文件夹内所有文件
|
# 遍历插件文件夹内所有文件
|
||||||
for plugin in plug_path.iterdir():
|
for plugin in plug_path.iterdir():
|
||||||
# 如果发现文件夹,则视为插件包
|
# 如果发现文件夹,则视为插件包
|
||||||
|
logger.info('===============')
|
||||||
|
logger.info(f'导入{plugin}中...')
|
||||||
|
logger.info('===============')
|
||||||
try:
|
try:
|
||||||
if plugin.is_dir():
|
if plugin.is_dir():
|
||||||
plugin_path = plugin / '__init__.py'
|
plugin_path = plugin / '__init__.py'
|
||||||
@ -54,6 +83,9 @@ class GsServer:
|
|||||||
self.load_dir_plugins(plugin)
|
self.load_dir_plugins(plugin)
|
||||||
elif nest_path.exists():
|
elif nest_path.exists():
|
||||||
path = nest_path.parent / plugin.name
|
path = nest_path.parent / plugin.name
|
||||||
|
pyproject = plugin / 'pyproject.toml'
|
||||||
|
if auto_install_dep and pyproject.exists:
|
||||||
|
check_pyproject(pyproject)
|
||||||
if path.exists():
|
if path.exists():
|
||||||
self.load_dir_plugins(path, True)
|
self.load_dir_plugins(path, True)
|
||||||
# 如果文件夹内有__init_.py,则视为单个插件包
|
# 如果文件夹内有__init_.py,则视为单个插件包
|
||||||
@ -115,3 +147,78 @@ class GsServer:
|
|||||||
if func not in cls.bot_connect_def:
|
if func not in cls.bot_connect_def:
|
||||||
cls.bot_connect_def.add(func)
|
cls.bot_connect_def.add(func)
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
def check_pyproject(pyproject: Path):
|
||||||
|
with open(pyproject, 'rb') as f:
|
||||||
|
file_content = f.read().decode('utf-8')
|
||||||
|
if "extend-exclude = '''" in file_content:
|
||||||
|
file_content = file_content.replace(
|
||||||
|
"extend-exclude = '''", ''
|
||||||
|
).replace("'''", '', 1)
|
||||||
|
toml_data = toml.loads(file_content)
|
||||||
|
if 'project' in toml_data:
|
||||||
|
dependencies = toml_data['project'].get('dependencies')
|
||||||
|
elif 'tool' in toml_data and 'poetry' in toml_data['tool']:
|
||||||
|
dependencies = toml_data['tool']['poetry'].get('dependencies')
|
||||||
|
else:
|
||||||
|
dependencies = None
|
||||||
|
|
||||||
|
if isinstance(dependencies, List):
|
||||||
|
dependencies = parse_dependency(dependencies)
|
||||||
|
|
||||||
|
if dependencies:
|
||||||
|
install_dependencies(dependencies)
|
||||||
|
|
||||||
|
|
||||||
|
def install_dependencies(dependencies: Dict):
|
||||||
|
global installed_dependencies
|
||||||
|
# 解析依赖项
|
||||||
|
for (
|
||||||
|
dependency,
|
||||||
|
version,
|
||||||
|
) in dependencies.items():
|
||||||
|
if (
|
||||||
|
dependency not in installed_dependencies
|
||||||
|
and dependency not in ignore_dep
|
||||||
|
):
|
||||||
|
logger.info(f'安装依赖 {dependency} 中...')
|
||||||
|
result = subprocess.run(
|
||||||
|
f'{check_start_tool()} install {dependency}',
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
# 检查命令执行结果
|
||||||
|
if result.returncode == 0:
|
||||||
|
logger.success(f"依赖 {dependency} 安装成功!")
|
||||||
|
else:
|
||||||
|
logger.warning("依赖安装失败。错误信息:")
|
||||||
|
logger.warning(result.stderr)
|
||||||
|
installed_dependencies = get_installed_dependencies()
|
||||||
|
|
||||||
|
|
||||||
|
def get_installed_dependencies():
|
||||||
|
global installed_dependencies
|
||||||
|
installed_packages = pkg_resources.working_set
|
||||||
|
installed_dependencies = [package.key for package in installed_packages]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_dependency(dependency: List):
|
||||||
|
dep = {}
|
||||||
|
for i in dependency:
|
||||||
|
dep.update(parse_dependency_string(i))
|
||||||
|
return dep
|
||||||
|
|
||||||
|
|
||||||
|
def parse_dependency_string(dependency_string: str):
|
||||||
|
pattern = r'([\w\-_\.]+)([<>=!]+)([\w\-_\.]+)'
|
||||||
|
matches = re.findall(pattern, dependency_string)
|
||||||
|
|
||||||
|
dependencies = {}
|
||||||
|
for match in matches:
|
||||||
|
dependency = match[0]
|
||||||
|
operator = match[1]
|
||||||
|
version = match[2]
|
||||||
|
dependencies[dependency] = f"{operator}{version}"
|
||||||
|
|
||||||
|
return dependencies
|
||||||
|
@ -168,7 +168,7 @@ class SV:
|
|||||||
|
|
||||||
for _k in keyword_list:
|
for _k in keyword_list:
|
||||||
if _k not in self.TL:
|
if _k not in self.TL:
|
||||||
logger.info(f'载入{type}触发器【{_k}】!')
|
logger.debug(f'载入{type}触发器【{_k}】!')
|
||||||
self.TL[_k] = Trigger(
|
self.TL[_k] = Trigger(
|
||||||
type, _k, modify_func(func), block, to_me
|
type, _k, modify_func(func), block, to_me
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user