3030
3131from app .runtime .cache import cached , is_fresh
3232from app .runtime .config import settings
33- from app .db .oper .systemconfig import SystemConfigOper
3433from app .adapters .system .package import PackageInstallRequest , build_package_install_strategies
3534from app .runtime .log import logger
36- from app .schemas .types import SystemConfigKey
3735from app .adapters .network .http import RequestUtils , AsyncRequestUtils
3836from app .foundation .singleton import WeakSingleton
3937
5957 "v3" : ["v2" ],
6058}
6159
60+ InstalledPluginsProvider = Callable [[], List [str ]]
61+
62+
63+ def _empty_installed_plugins () -> List [str ]:
64+ """组合根尚未注入配置读取器时返回空安装清单。"""
65+ return []
66+
67+
68+ _installed_plugins_provider : InstalledPluginsProvider = _empty_installed_plugins
69+
70+
71+ def configure_installed_plugins_provider (
72+ provider : InstalledPluginsProvider ,
73+ ) -> None :
74+ """由启动组合层注入已安装插件读取器,避免市场适配器访问数据库。"""
75+ global _installed_plugins_provider
76+ _installed_plugins_provider = provider
77+
6278
6379def normalize_plugin_market_repo_url (repo_url : str ) -> Optional [str ]:
6480 """规范化插件仓库地址,便于跨来源合并去重。"""
@@ -165,10 +181,6 @@ class PluginHelper(metaclass=WeakSingleton):
165181 "sqlalchemy, starlette, uvicorn; from pydantic import BaseModel, Field"
166182 )
167183
168- def __init__ (self ):
169- """初始化插件仓库配置访问器。"""
170- self .systemconfig = SystemConfigOper ()
171-
172184 @staticmethod
173185 def is_local_repo_url (repo_url : Optional [str ]) -> bool :
174186 """
@@ -1173,7 +1185,7 @@ def __collect_plugin_wheels_dirs(self) -> List[Path]:
11731185 try :
11741186 install_plugins = {
11751187 plugin_id .lower ()
1176- for plugin_id in self . systemconfig . get ( SystemConfigKey . UserInstalledPlugins ) or []
1188+ for plugin_id in _installed_plugins_provider ( ) or []
11771189 }
11781190 for plugin_id in install_plugins :
11791191 wheels_dir = PLUGIN_DIR / plugin_id / "wheels"
@@ -2099,68 +2111,26 @@ def __install_from_release(self, pid: str, user_repo: str, release_tag: str) ->
20992111 return False , f"解压 Release 压缩包失败:{ e } "
21002112
21012113 def find_missing_dependencies (self ) -> List [str ]:
2102- """
2103- 收集所有需要安装或更新的依赖项
2104- 1. 收集所有插件的依赖项,合并版本约束
2105- 2. 获取已安装的包及其版本
2106- 3. 比较已安装的包与所需的依赖项,找出需要安装或升级的包
2107- :return: 需要安装或更新的依赖项列表,例如 ["package1>=1.0.0", "package2"]
2108- """
2109- try :
2110- # 收集所有插件的依赖项
2111- plugin_dependencies = self .__find_plugin_dependencies () # 返回格式为 {package_name: version_specifier}
2112- # 获取已安装的包及其版本
2113- installed_packages = self .__get_installed_packages () # 返回格式为 {package_name: Version}
2114- # 需要安装或更新的依赖项列表
2115- dependencies_to_install = []
2116- for pkg_name , version_specifier in plugin_dependencies .items ():
2117- spec_set = SpecifierSet (version_specifier )
2118- installed_version = installed_packages .get (pkg_name )
2119- if installed_version is None :
2120- # 包未安装,需要安装
2121- if version_specifier :
2122- dependencies_to_install .append (f"{ pkg_name } { version_specifier } " )
2123- else :
2124- dependencies_to_install .append (pkg_name )
2125- elif not spec_set .contains (installed_version , prereleases = True ):
2126- # 已安装的版本不满足版本约束,需要升级或降级
2127- if version_specifier :
2128- dependencies_to_install .append (f"{ pkg_name } { version_specifier } " )
2129- else :
2130- dependencies_to_install .append (pkg_name )
2131- # 已安装的版本满足要求,无需操作
2132- return dependencies_to_install
2133- except Exception as e :
2134- logger .error (f"收集所有需要安装或更新的依赖项时发生错误:{ e } " )
2135- return []
2114+ """兼容旧市场入口,转发到独立依赖适配器。"""
2115+ installer = importlib .import_module (
2116+ "app.adapters.system.plugin.dependency"
2117+ ).PluginDependencyInstaller
2118+ return installer (
2119+ self ,
2120+ installed_plugins_provider = _installed_plugins_provider ,
2121+ plugin_dir = PLUGIN_DIR ,
2122+ ).find_missing ()
21362123
21372124 def install_dependencies (self , dependencies : List [str ]) -> Tuple [bool , str ]:
2138- """
2139- 安装指定的依赖项列表
2140- :param dependencies: 需要安装或更新的依赖项列表
2141- :return: (success, message)
2142- """
2143- if not dependencies :
2144- return False , "没有传入需要安装的依赖项"
2145-
2146- try :
2147- logger .debug (f"需要安装或更新的依赖项:{ dependencies } " )
2148- # 创建临时的 requirements.txt 文件用于批量安装
2149- requirements_temp_file = Path (settings .TEMP_PATH ) / "plugin_dependencies" / "requirements.txt"
2150- requirements_temp_file .parent .mkdir (parents = True , exist_ok = True )
2151- with open (requirements_temp_file , "w" , encoding = "utf-8" ) as f :
2152- for dep in dependencies :
2153- f .write (dep + "\n " )
2154- try :
2155- # 使用自动降级策略安装依赖
2156- wheels_dirs = self .__collect_plugin_wheels_dirs ()
2157- return self .pip_install_with_fallback (requirements_temp_file , wheels_dirs )
2158- finally :
2159- # 删除临时文件
2160- requirements_temp_file .unlink ()
2161- except Exception as e :
2162- logger .error (f"安装依赖项时发生错误:{ e } " )
2163- return False , f"安装依赖项时发生错误:{ e } "
2125+ """兼容旧市场入口,转发到独立依赖适配器。"""
2126+ installer = importlib .import_module (
2127+ "app.adapters.system.plugin.dependency"
2128+ ).PluginDependencyInstaller
2129+ return installer (
2130+ self ,
2131+ installed_plugins_provider = _installed_plugins_provider ,
2132+ plugin_dir = PLUGIN_DIR ,
2133+ ).install (dependencies )
21642134
21652135 @classmethod
21662136 def __get_installed_packages (cls ) -> Dict [str , Version ]:
@@ -2203,9 +2173,7 @@ def __find_plugin_dependencies(self) -> Dict[str, str]:
22032173 try :
22042174 install_plugins = {
22052175 plugin_id .lower () # 对应插件的小写目录名
2206- for plugin_id in SystemConfigOper ().get (
2207- SystemConfigKey .UserInstalledPlugins
2208- ) or []
2176+ for plugin_id in _installed_plugins_provider () or []
22092177 }
22102178 for plugin_dir in PLUGIN_DIR .iterdir ():
22112179 if plugin_dir .is_dir ():
@@ -2739,34 +2707,15 @@ async def __async_install_dependencies_if_required(self, pid: str) -> Tuple[bool
27392707 return False , False , "不存在依赖"
27402708
27412709 async def async_install_dependencies (self , dependencies : List [str ]) -> Tuple [bool , str ]:
2742- """
2743- 异步安装指定的依赖项列表
2744- :param dependencies: 需要安装或更新的依赖项列表
2745- :return: (success, message)
2746- """
2747- if not dependencies :
2748- return False , "没有传入需要安装的依赖项"
2749-
2750- try :
2751- logger .debug (f"需要安装或更新的依赖项:{ dependencies } " )
2752- # 创建临时的 requirements.txt 文件用于批量安装
2753- requirements_temp_file = AsyncPath (settings .TEMP_PATH ) / "plugin_dependencies" / "requirements.txt"
2754- await requirements_temp_file .parent .mkdir (parents = True , exist_ok = True )
2755-
2756- async with aiofiles .open (requirements_temp_file , "w" , encoding = "utf-8" ) as f :
2757- for dep in dependencies :
2758- await f .write (dep + "\n " )
2759-
2760- try :
2761- # 使用自动降级策略安装依赖
2762- wheels_dirs = self .__collect_plugin_wheels_dirs ()
2763- return await self .__async_pip_install_with_fallback (Path (requirements_temp_file ), wheels_dirs )
2764- finally :
2765- # 删除临时文件
2766- await requirements_temp_file .unlink ()
2767- except Exception as e :
2768- logger .error (f"安装依赖项时发生错误:{ e } " )
2769- return False , f"安装依赖项时发生错误:{ e } "
2710+ """兼容旧异步市场入口,转发到独立依赖适配器。"""
2711+ installer = importlib .import_module (
2712+ "app.adapters.system.plugin.dependency"
2713+ ).PluginDependencyInstaller
2714+ return await installer (
2715+ self ,
2716+ installed_plugins_provider = _installed_plugins_provider ,
2717+ plugin_dir = PLUGIN_DIR ,
2718+ ).async_install (dependencies )
27702719
27712720 async def __async_find_plugin_dependencies (self ) -> Dict [str , str ]:
27722721 """
@@ -2779,9 +2728,7 @@ async def __async_find_plugin_dependencies(self) -> Dict[str, str]:
27792728 try :
27802729 install_plugins = {
27812730 plugin_id .lower () # 对应插件的小写目录名
2782- for plugin_id in SystemConfigOper ().get (
2783- SystemConfigKey .UserInstalledPlugins
2784- ) or []
2731+ for plugin_id in _installed_plugins_provider () or []
27852732 }
27862733
27872734 plugin_dir_path = AsyncPath (PLUGIN_DIR )
@@ -2838,40 +2785,15 @@ async def __async_parse_requirements(self, requirements_file: AsyncPath) -> Dict
28382785 return {}
28392786
28402787 async def async_find_missing_dependencies (self ) -> List [str ]:
2841- """
2842- 异步收集所有需要安装或更新的依赖项
2843- 1. 收集所有插件的依赖项,合并版本约束
2844- 2. 获取已安装的包及其版本
2845- 3. 比较已安装的包与所需的依赖项,找出需要安装或升级的包
2846- :return: 需要安装或更新的依赖项列表,例如 ["package1>=1.0.0", "package2"]
2847- """
2848- try :
2849- # 收集所有插件的依赖项
2850- plugin_dependencies = await self .__async_find_plugin_dependencies () # 返回格式为 {package_name: version_specifier}
2851- # 获取已安装的包及其版本
2852- installed_packages = self .__get_installed_packages () # 返回格式为 {package_name: Version}
2853- # 需要安装或更新的依赖项列表
2854- dependencies_to_install = []
2855- for pkg_name , version_specifier in plugin_dependencies .items ():
2856- spec_set = SpecifierSet (version_specifier )
2857- installed_version = installed_packages .get (pkg_name )
2858- if installed_version is None :
2859- # 包未安装,需要安装
2860- if version_specifier :
2861- dependencies_to_install .append (f"{ pkg_name } { version_specifier } " )
2862- else :
2863- dependencies_to_install .append (pkg_name )
2864- elif not spec_set .contains (installed_version , prereleases = True ):
2865- # 已安装的版本不满足版本约束,需要升级或降级
2866- if version_specifier :
2867- dependencies_to_install .append (f"{ pkg_name } { version_specifier } " )
2868- else :
2869- dependencies_to_install .append (pkg_name )
2870- # 已安装的版本满足要求,无需操作
2871- return dependencies_to_install
2872- except Exception as e :
2873- logger .error (f"收集所有需要安装或更新的依赖项时发生错误:{ e } " )
2874- return []
2788+ """兼容旧异步市场入口,转发到独立依赖适配器。"""
2789+ installer = importlib .import_module (
2790+ "app.adapters.system.plugin.dependency"
2791+ ).PluginDependencyInstaller
2792+ return await installer (
2793+ self ,
2794+ installed_plugins_provider = _installed_plugins_provider ,
2795+ plugin_dir = PLUGIN_DIR ,
2796+ ).async_find_missing ()
28752797
28762798 async def async_install (self , pid : str , repo_url : str , package_version : Optional [str ] = None ,
28772799 release_version : Optional [str ] = None ,
0 commit comments