🎨 大幅优化启动自动更新/安装依赖的方式, 允许插件添加gscore_auto_update_dep列表强制更新依赖

This commit is contained in:
KimigaiiWuyi 2024-09-28 05:26:30 +08:00
parent e3389087e1
commit a7a19a3024
5 changed files with 117 additions and 61 deletions

1
game_record.json Normal file
View File

@ -0,0 +1 @@
{}

View File

@ -4,9 +4,9 @@ from gsuid_core.models import Event
from gsuid_core.logger import logger from gsuid_core.logger import logger
from gsuid_core.utils.plugins_config.gs_config import core_plugins_config from gsuid_core.utils.plugins_config.gs_config import core_plugins_config
from gsuid_core.utils.plugins_update._plugins import ( from gsuid_core.utils.plugins_update._plugins import (
run_install,
check_retcode, check_retcode,
update_from_git, update_from_git,
run_poetry_install,
update_all_plugins, update_all_plugins,
set_proxy_all_plugins, set_proxy_all_plugins,
) )
@ -54,7 +54,7 @@ async def send_core_update_proxy(bot: Bot, ev: Event):
@sv_core_config.on_fullmatch(('core更新依赖')) @sv_core_config.on_fullmatch(('core更新依赖'))
async def send_core_poetry_install(bot: Bot, ev: Event): async def send_core_poetry_install(bot: Bot, ev: Event):
logger.info('开始执行[更新] 早柚核心依赖') logger.info('开始执行[更新] 早柚核心依赖')
retcode = await run_poetry_install() retcode = await run_install()
im = check_retcode(retcode) im = check_retcode(retcode)
await bot.send(im) await bot.send(im)

View File

@ -14,12 +14,14 @@ 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 from gsuid_core.utils.plugins_config.gs_config import core_plugins_config
from gsuid_core.utils.plugins_update._plugins import ( from gsuid_core.utils.plugins_update._plugins import (
check_start_tool,
sync_get_plugin_url, sync_get_plugin_url,
sync_change_plugin_url, sync_change_plugin_url,
) )
auto_install_dep: bool = core_plugins_config.get_config('AutoInstallDep').data auto_install_dep: bool = core_plugins_config.get_config('AutoInstallDep').data
start_venv: str = core_plugins_config.get_config('StartVENV').data auto_update_dep: bool = core_plugins_config.get_config('AutoUpdateDep').data
core_start_def = set() core_start_def = set()
core_shutdown_def = set() core_shutdown_def = set()
installed_dependencies = [] installed_dependencies = []
@ -38,39 +40,6 @@ def on_core_shutdown(func: Callable):
return func return func
def check_start_tool(is_pip: bool = False):
PDM = 'pdm'
POETRY = 'poetry'
OTHER = start_venv.strip()
if is_pip:
PIP = ' run python -m pip'
PDM += PIP
POETRY += PIP
if OTHER == 'python':
OTHER = 'python -m pip'
else:
OTHER += PIP
path = Path(__file__).parent.parent
pdm_python_path = path / '.pdm-python'
if start_venv == 'auto':
if pdm_python_path.exists():
command = PDM
else:
command = POETRY
elif start_venv == 'pdm':
command = PDM
elif start_venv == 'poetry':
command = POETRY
else:
command = start_venv.strip()
return command
class GsServer: class GsServer:
_instance = None _instance = None
is_initialized = False is_initialized = False
@ -115,7 +84,7 @@ class GsServer:
elif nest_path.exists() or src_path.exists(): elif nest_path.exists() or src_path.exists():
path = nest_path.parent / plugin.name path = nest_path.parent / plugin.name
pyproject = plugin / 'pyproject.toml' pyproject = plugin / 'pyproject.toml'
if auto_install_dep and pyproject.exists: if pyproject.exists:
check_pyproject(pyproject) check_pyproject(pyproject)
if path.exists(): if path.exists():
self.load_dir_plugins(path, True) self.load_dir_plugins(path, True)
@ -213,23 +182,42 @@ def check_pyproject(pyproject: Path):
"extend-exclude = '''", '' "extend-exclude = '''", ''
).replace("'''", '', 1) ).replace("'''", '', 1)
toml_data = toml.loads(file_content) toml_data = toml.loads(file_content)
if 'project' in toml_data:
dependencies = toml_data['project'].get('dependencies') if auto_install_dep or auto_update_dep:
elif 'tool' in toml_data and 'poetry' in toml_data['tool']: if 'project' in toml_data:
dependencies = toml_data['tool']['poetry'].get('dependencies') dependencies = toml_data['project'].get('dependencies')
else: elif 'tool' in toml_data and 'poetry' in toml_data['tool']:
dependencies = None dependencies = toml_data['tool']['poetry'].get('dependencies')
else:
dependencies = None
if isinstance(dependencies, List): if isinstance(dependencies, List):
dependencies = parse_dependency(dependencies) dependencies = parse_dependency(dependencies)
else:
dependencies = {}
if 'project' in toml_data:
sp_dep = toml_data['project'].get('gscore_auto_update_dep')
if sp_dep:
sp_dep = parse_dependency(sp_dep)
logger.debug('[安装/更新依赖] 特殊依赖列表如下:')
logger.debug(sp_dep)
logger.debug('========')
install_dependencies(sp_dep, True)
if dependencies: if dependencies:
install_dependencies(dependencies) if auto_update_dep:
install_dependencies(dependencies, True)
else:
install_dependencies(dependencies, False)
def install_dependencies(dependencies: Dict): def install_dependencies(dependencies: Dict, need_update: bool = False):
global installed_dependencies global installed_dependencies
start_tool = check_start_tool(True) start_tool = check_start_tool(True)
logger.debug(f'[安装/更新依赖] 当前启动工具:{start_tool}')
if start_tool == 'pdm': if start_tool == 'pdm':
result = subprocess.run( result = subprocess.run(
'pdm run python -m ensurepip', 'pdm run python -m ensurepip',
@ -241,19 +229,44 @@ def install_dependencies(dependencies: Dict):
logger.warning("PDM中pip环境检查失败。错误信息") logger.warning("PDM中pip环境检查失败。错误信息")
logger.warning(result.stderr) logger.warning(result.stderr)
return return
logger.trace(
f'[安装/更新依赖] 开始安装/更新依赖...模式是否为更新:{need_update}'
)
if need_update:
extra = '-U'
else:
extra = ''
logger.trace('[安装/更新依赖] 需检查依赖列表如下:')
logger.trace(dependencies)
logger.trace('========')
# 解析依赖项 # 解析依赖项
for ( for (
dependency, dependency,
version, version,
) in dependencies.items(): ) in dependencies.items():
if ( if need_update:
installed_dependencies condi = dependency not in ignore_dep
and dependency not in installed_dependencies else:
and dependency not in ignore_dep condi = (
): installed_dependencies
logger.info(f'安装依赖 {dependency} 中...') and dependency not in installed_dependencies
and dependency not in ignore_dep
)
logger.trace(
f'[安装/更新依赖] 检测到依赖 {dependency}, 是否满足条件 {condi}'
)
if condi:
logger.info(f'[安装/更新依赖] {dependency} 中...')
CMD = f'{start_tool} install "{dependency}{version}" {extra}'
logger.info(f'[安装/更新依赖] 开始执行:{CMD}')
result = subprocess.run( result = subprocess.run(
f'{start_tool} install {dependency}', CMD,
capture_output=True, capture_output=True,
text=True, text=True,
) )

View File

@ -74,10 +74,15 @@ CONIFG_DEFAULT: Dict[str, GSC] = {
'自动重启Core时间设置', '每晚自动重启Core时间设置(时, 分)', ['4', '40'] '自动重启Core时间设置', '每晚自动重启Core时间设置(时, 分)', ['4', '40']
), ),
'AutoInstallDep': GsBoolConfig( 'AutoInstallDep': GsBoolConfig(
'自动安装/更新依赖', '自动安装依赖',
'更新/安装插件时将会自动更新/安装依赖', '安装插件时将会自动安装依赖',
True, True,
), ),
'AutoUpdateDep': GsBoolConfig(
'自动更新依赖',
'启动Core时将会自动更新插件依赖',
False,
),
'EnablePicSrv': GsBoolConfig( 'EnablePicSrv': GsBoolConfig(
'启用将图片转链接发送(需公网)', '启用将图片转链接发送(需公网)',
'发送图片转链接', '发送图片转链接',

View File

@ -17,9 +17,43 @@ from .api import CORE_PATH, PLUGINS_PATH, plugins_lib
plugins_list: Dict[str, Dict[str, str]] = {} plugins_list: Dict[str, Dict[str, str]] = {}
start_venv: str = core_plugins_config.get_config('StartVENV').data
is_install_dep = core_plugins_config.get_config('AutoInstallDep').data is_install_dep = core_plugins_config.get_config('AutoInstallDep').data
def check_start_tool(is_pip: bool = False):
PDM = 'pdm'
POETRY = 'poetry'
OTHER = start_venv.strip()
if is_pip:
PIP = ' run python -m pip'
PDM += PIP
POETRY += ' run pip'
if OTHER == 'python':
OTHER = 'python -m pip'
else:
OTHER += PIP
path = Path(__file__).parent.parent.parent.parent
pdm_python_path = path / '.pdm-python'
if start_venv == 'auto':
if pdm_python_path.exists():
command = PDM
else:
command = POETRY
elif start_venv == 'pdm':
command = PDM
elif start_venv == 'poetry':
command = POETRY
else:
command = start_venv.strip()
return command
async def check_plugin_exist(name: str): async def check_plugin_exist(name: str):
name = name.lower() name = name.lower()
if name in ['core_command', 'gs_test']: if name in ['core_command', 'gs_test']:
@ -37,22 +71,25 @@ async def uninstall_plugin(path: Path):
# 传入一个path对象 # 传入一个path对象
async def run_poetry_install(path: Optional[Path] = None) -> int: async def run_install(path: Optional[Path] = None) -> int:
tools = check_start_tool()
if tools == 'pip':
logger.warning('你使用的是PIP环境, 无需进行 PDM/Poetry install!')
return -200
if path is None: if path is None:
path = CORE_PATH path = CORE_PATH
# 检测path是否是一个目录 # 检测path是否是一个目录
if not path.is_dir(): if not path.is_dir():
raise ValueError(f"{path} is not a directory") raise ValueError(f"{path} is not a directory")
# 检测path下是否存在poetry.lock文件
lock_file = path / "poetry.lock"
if not lock_file.is_file():
raise FileNotFoundError(f"{lock_file} does not exist")
# 异步执行poetry install命令并返回返回码 # 异步执行poetry install命令并返回返回码
env = os.environ.copy() env = os.environ.copy()
env["PYTHONIOENCODING"] = "utf8" env["PYTHONIOENCODING"] = "utf8"
proc = await asyncio.create_subprocess_shell( proc = await asyncio.create_subprocess_shell(
'poetry install', f'{tools} install',
cwd=path, cwd=path,
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
shell=True, shell=True,
@ -356,7 +393,7 @@ def update_from_git(
repo = Repo(CORE_PATH) repo = Repo(CORE_PATH)
plugin_name = '早柚核心' plugin_name = '早柚核心'
if is_install_dep: if is_install_dep:
asyncio.create_task(run_poetry_install(CORE_PATH)) asyncio.create_task(run_install(CORE_PATH))
elif isinstance(repo_like, Path): elif isinstance(repo_like, Path):
repo = Repo(repo_like) repo = Repo(repo_like)
plugin_name = repo_like.name plugin_name = repo_like.name