22 :copyright: © 2019 by the Lin team.
33 :license: MIT, see LICENSE for more details.
44"""
5+ import json
56import re
67from importlib import import_module
7-
8+ import subprocess
89import os
910
1011from app .app import create_app
@@ -51,6 +52,10 @@ def generate_path(self):
5152 }
5253
5354 def auto_install_rely (self ):
55+ try :
56+ DependenciesResolve (app , self .path_info )
57+ except Exception as e :
58+ raise Exception ('安装插件依赖时发生错误!\n Error:' + str (e ))
5459 from subprocess import CalledProcessError
5560 for name in self .path_info :
5661 filename = 'requirements.txt'
@@ -93,7 +98,7 @@ def auto_write_setting(self):
9398 try :
9499 info_mod = import_module (self .path_info [name ]['plugin_info_path' ])
95100 except ModuleNotFoundError as e :
96- raise exit (str (e ) + '\n 未找到插件' + name + ',请检查您输入的插件名是否正确' )
101+ raise Exception (str (e ) + '\n 未找到插件' + name + ',请检查您输入的插件名是否正确' )
97102
98103 res = self ._generate_setting (name , info_mod )
99104 setting_text [name ] = res
@@ -109,9 +114,8 @@ def create_data(self):
109114 plugin_module = import_module (self .path_info [name ]['plugin_path' ] + '.app.__init__' )
110115 dir_info = dir (plugin_module )
111116 except ModuleNotFoundError as e :
112- raise exit (str (e ) + '\n 未找到插件' + name + ',请检查您输入的插件名是否正确 ' )
117+ raise Exception (str (e ) + '\n 未找到插件' + name + ',请检查您输入的插件名是否正确或插件中是否有未安装的依赖包 ' )
113118 if 'initial_data' in dir_info :
114- # TODO 解决多次初始化数据重复添加的问题
115119 plugin_module .initial_data ()
116120 print ('插件初始化成功' )
117121
@@ -158,7 +162,6 @@ def __get_all_plugins(self):
158162
159163 @classmethod
160164 def __execute_cmd (cls , cmd ):
161- import subprocess
162165 code = subprocess .check_call (cmd , shell = True , stdout = subprocess .PIPE )
163166 if code == 0 :
164167 return True
@@ -206,6 +209,145 @@ def __cal_setting(new_setting, old_setting):
206209 return final_setting
207210
208211
212+ class DependenciesResolve :
213+
214+ def __init__ (self , app_obj , path ):
215+ self .app = app_obj
216+ self .path_info = path
217+ # 主项目的依赖关系列表
218+ self .root_graph = []
219+ # 所有插件的依赖关系列表
220+ self .plugin_graph = []
221+ # 生成主项目和插件依赖关系列表
222+ self .generate_graph ()
223+ self .check_dependencies ()
224+
225+ def generate_graph (self ):
226+ try :
227+ p = subprocess .Popen (["pipenv" , "graph" , "--json" ],
228+ stdout = subprocess .PIPE )
229+
230+ r = p .communicate ()[0 ].decode ('utf-8' )
231+ self .root_graph = json .loads (r )
232+
233+ except subprocess .CalledProcessError as e :
234+ exit ("pipenv指令未安装,请先使用pip安装命令\n Error" + str (e ))
235+
236+ except Exception as e :
237+ exit ("pipenv 错误,请检测你的pipenv配置!\n Error:" + str (e ))
238+
239+ self .__generate_plugin_graph ()
240+
241+ def check_dependencies (self ):
242+ for package in self .root_graph :
243+ # 验证顶级包是否符合规范
244+ self .__check_top_dependencies (package ['package' ])
245+
246+ # 验证子包是否符合规范
247+ self .__check_sub_dependencies (package ['dependencies' ])
248+
249+ def __generate_plugin_graph (self ):
250+ for name , val in self .path_info .items ():
251+ # 首先去校验插件依赖于住项目的依赖是否存在冲突
252+ plugin_path = self .path_info [name ]['plugin_path' ].replace (
253+ '.' , '/' ).replace ('app' , '' )
254+ requirements_path = self .app .config .root_path + \
255+ plugin_path + '/requirements.txt'
256+ with open (requirements_path , 'r' ) as f :
257+ while True :
258+
259+ # 正则匹配requirements的每一行的信息
260+ line = f .readline ()
261+ if not line :
262+ break
263+
264+ pattern = '(.*?)(==|<=|>=|!=|>|<)(.*)'
265+ search_obj = re .search (pattern , line )
266+ if search_obj :
267+
268+ package_name = search_obj .group (1 )
269+ condition = search_obj .group (2 )
270+ version = search_obj .group (3 )
271+ key = search_obj .group (1 ).lower ()
272+
273+ plugin_package = dict ({'package' : {}})
274+ plugin_package ['package' ]['key' ] = key
275+ plugin_package ['package' ]['package_name' ] = package_name
276+ plugin_package ['package' ]['version' ] = version
277+ plugin_package ['package' ]['condition' ] = condition
278+ plugin_package ['package' ]['plugin_name' ] = name
279+ self .plugin_graph .append (plugin_package )
280+
281+ def __check_top_dependencies (self , top_package ):
282+ for plugin_package in self .plugin_graph :
283+ # top_version = top_package['installed_version']
284+ # plugin_version = plugin_package['version']
285+ if top_package ['key' ] == plugin_package ['package' ]['key' ]:
286+ err_msg = '由于项目主目录已经存在在包' \
287+ '' + top_package ['package_name' ] + ',但 ' + plugin_package ['package' ]['plugin_name' ]\
288+ + ' 插件尝试重复安装不同版本,请尝试手动去掉该插件的requirements.txt中的包'
289+ raise Exception (err_msg )
290+
291+ def __check_sub_dependencies (self , dep_package ):
292+ # 判断插件中要安装的依赖,是否符合主项目已安装的依赖规定的范围
293+ for dependence in dep_package :
294+ required_version = dependence ['required_version' ]
295+ dep_name = dependence ['key' ]
296+
297+ if required_version is not None :
298+ version_infos = required_version .split ("," )
299+ for version_info in version_infos :
300+ pattern = '(>=|<=|!=|==|<|>)(.*)'
301+ search_obj = re .search (pattern , version_info )
302+ condition = search_obj .group (1 )
303+ version = int (search_obj .group (2 ).replace ('.' , '' ))
304+
305+ for plugin_package in self .plugin_graph :
306+ name = plugin_package ['package' ]['key' ]
307+ if dep_name == name :
308+ plugin_package_version = int (plugin_package ['package' ]['version' ].replace ('.' , '' ))
309+ err_msg = plugin_package ['package' ]['plugin_name' ] + '插件的依赖 ' + name + \
310+ ' 与主项目依赖版本发生冲突! 请自行手动解决'
311+ if condition == '>=' :
312+ if plugin_package_version >= version :
313+ pass
314+ else :
315+ raise Exception (err_msg )
316+
317+ elif condition == '==' :
318+ if plugin_package_version == version :
319+ pass
320+ else :
321+ raise Exception (err_msg )
322+
323+ elif condition == '!=' :
324+ if plugin_package_version != version :
325+ pass
326+ else :
327+ raise Exception (err_msg )
328+
329+ elif condition == '<=' :
330+ if plugin_package_version <= version :
331+ pass
332+ else :
333+ raise Exception (err_msg )
334+
335+ elif condition == '<' :
336+ if plugin_package_version < version :
337+ pass
338+ else :
339+ raise Exception (err_msg )
340+
341+ elif condition == '>' :
342+ if plugin_package_version > version :
343+ pass
344+ else :
345+ raise Exception (err_msg )
346+ else :
347+ pass
348+
349+
209350if __name__ == '__main__' :
351+ app = create_app (register_all = False )
210352 plugin_name = input ('请输入要初始化的插件名,如果多个插件请使用空格分隔插件名,输入*表示初始化所有插件:\n ' )
211353 PluginInit (plugin_name )
0 commit comments