Без опису
Ви не можете вибрати більше 25 тем Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. import operator
  2. import shutil
  3. import tempfile
  4. import os, os.path
  5. from lodel.context import LodelContext
  6. LodelContext.expose_modules(globals(), {
  7. 'lodel.plugin.scripts': 'lodel_script',
  8. 'lodel.logger': 'logger'})
  9. ##@package lodel.plugin.core_scripts
  10. #@brief Lodel2 internal scripts declaration
  11. #@ingroup lodel2_plugins
  12. #@ingroup lodel2_script
  13. ##@brief Implements lodel_admin.py list-plugins action
  14. #@ingroup lodel2_plugins
  15. #@ingroup lodel2_script
  16. #
  17. class ListPlugins(lodel_script.LodelScript):
  18. _action = 'plugins-list'
  19. _description = "List all installed plugins"
  20. @classmethod
  21. def argparser_config(cls, parser):
  22. parser.add_argument('-v', '--verbose',
  23. help="Display more informations on installed plugins",
  24. action='store_true')
  25. parser.add_argument('-c', '--csv',
  26. help="Format output in CSV format",
  27. action='store_true')
  28. @classmethod
  29. def run(cls, args):
  30. import lodel.plugin.plugins
  31. from lodel.plugin.plugins import Plugin
  32. if args.verbose:
  33. #_discover do not returns duplicated names
  34. tmp_plist = Plugin._discover(lodel.plugin.plugins.PLUGINS_PATH)
  35. plist = []
  36. #ordering the list by plugin's name
  37. for pname in sorted(set([d['name'] for d in tmp_plist])):
  38. for pinfos in tmp_plist:
  39. if pinfos['name'] == pname:
  40. plist.append(pinfos)
  41. else:
  42. pdict = Plugin.discover()
  43. #casting to a list ordered by names
  44. plist = []
  45. for pname in sorted(pdict.keys()):
  46. plist.append(pdict[pname])
  47. if args.csv:
  48. if args.verbose:
  49. res = "name,version,path\n"
  50. fmt = "%s,%s,%s\n"
  51. else:
  52. res = "name,version\n"
  53. fmt = "%s,%s\n"
  54. else:
  55. res = "Installed plugins list :\n"
  56. if args.verbose:
  57. fmt = "\t- %s(%s) in %s\n"
  58. else:
  59. fmt = "\t- %s(%s)\n"
  60. for pinfos in plist:
  61. if args.verbose:
  62. res += fmt % (
  63. pinfos['name'], pinfos['version'], pinfos['path'])
  64. else:
  65. res += fmt % (pinfos['name'], pinfos['version'])
  66. print(res)
  67. ##@brief Handle install & uninstall of lodel plugins
  68. class PluginManager(lodel_script.LodelScript):
  69. _action = 'plugins'
  70. _description = "Install/Uninstall plugins"
  71. @classmethod
  72. def argparser_config(cls, parser):
  73. parser.add_argument('-u', '--uninstall',
  74. help="Uninstall specified plugin",
  75. action='store_true')
  76. parser.add_argument('-c', '--clean',
  77. help="Uninstall duplicated plugins with smallest version number",
  78. action="store_true")
  79. parser.add_argument('-n', '--plugin-name', nargs='*',
  80. default = list(),
  81. help="Indicate a plugin name to uninstall",
  82. type=str)
  83. parser.add_argument('-a', '--archive', nargs='*',
  84. default = list(),
  85. help="(NOT IMPLEMENTED) Specify a tarball containing a plugin \
  86. to install",
  87. type=str)
  88. parser.add_argument('-d', '--directory', nargs='*',
  89. default = list(),
  90. help="Specify a plugin by its directory",
  91. type=str)
  92. parser.add_argument('-f', '--force', action="store_true",
  93. help="Force plugin directory deletion in case of check errors")
  94. @classmethod
  95. def run(cls, args):
  96. if args.clean:
  97. if args.uninstall or len(args.directory) > 0 \
  98. or len(args.archive) > 0:
  99. raise RuntimeError("When using -c --clean option you can \
  100. only use option -n --name to clean plugins with specified names")
  101. return cls.clean(args)
  102. if args.uninstall:
  103. return cls.uninstall(args)
  104. return cls.install(args)
  105. ##@brief Handles plugins install
  106. @classmethod
  107. def install(cls, args):
  108. import lodel.plugin.plugins
  109. from lodel.plugin.plugins import Plugin
  110. from lodel.plugin.exceptions import PluginError
  111. if len(args.plugin_name) > 0:
  112. raise RuntimeError("Unable to install a plugin from its name !\
  113. We do not know where to find it...")
  114. plist = Plugin.discover()
  115. errors = dict()
  116. if len(args.archive) > 0:
  117. raise NotImplementedError("Not supported yet")
  118. plugins_infos = {}
  119. for cur_dir in args.directory:
  120. try:
  121. res = Plugin.dir_is_plugin(cur_dir, assert_in_package = False)
  122. if res is False:
  123. errors[cur_dir] = PluginError("Not a plugin")
  124. else:
  125. plugins_infos[res['name']] = res
  126. except Exception as e:
  127. errors[cur_dir] = e
  128. #Abording because of previous errors
  129. if len(errors) > 0:
  130. msg = "Abording installation because of following errors :\n"
  131. for path, expt in errors.items():
  132. msg += ("\t- For path '%s' : %s\n" % (path, expt))
  133. raise RuntimeError(msg)
  134. #No errors continuing to install
  135. for pname, pinfos in plugins_infos.items():
  136. if pname in plist:
  137. #Found an installed plugin with the same name
  138. #Cehcking both versions
  139. if plist[pname]['version'] == pinfos['version']:
  140. errors[pinfos['path']] = 'Abording installation of %s \
  141. found in %s because it seems to be allready installed in %s' % (
  142. pname, pinfos['path'], plist[pname]['path'])
  143. continue
  144. if plist[pname]['version'] > pinfos['version']:
  145. errors[pinfos['path']] = 'Abording installation of %s \
  146. found in %s because the same plugins with a greater version seems to be \
  147. installed in %s' % (pname, pinfos['path'], plist[pname]['path'])
  148. continue
  149. logger.info("Found a plugin with the same name but with an \
  150. inferior version. Continuing to install")
  151. #Checking that we can safely copy our plugin
  152. dst_path = os.path.join(lodel.plugin.plugins.PLUGINS_PATH,
  153. os.path.basename(os.path.dirname(pinfos['path'])))
  154. orig_path = dst_path
  155. if os.path.isdir(dst_path):
  156. dst_path = tempfile.mkdtemp(
  157. prefix = os.path.basename(dst_path)+'_',
  158. dir = lodel.plugin.plugins.PLUGINS_PATH)
  159. logger.warning("A plugin allready exists in %s. Installing \
  160. in %s" % (orig_path, dst_path))
  161. shutil.rmtree(dst_path)
  162. #Installing the plugin
  163. shutil.copytree(pinfos['path'], dst_path, symlinks = False)
  164. print("%s(%s) installed in %s" % (
  165. pname, pinfos['version'], dst_path))
  166. if len(errors) > 0:
  167. msg = "Following errors occurs during instalation process :\n"
  168. for path, error_msg in errors.items():
  169. msg += "\t- For '%s' : %s" % (path, error_msg)
  170. print(msg)
  171. ##@brief Handles plugins uninstall
  172. #@todo uninstall by path is broken
  173. @classmethod
  174. def uninstall(cls, args):
  175. import lodel.plugin.plugins
  176. from lodel.plugin.plugins import Plugin
  177. if len(args.archive) > 0:
  178. raise RuntimeError("Cannot uninstall plugin using -f --file \
  179. oprtions. Use -d --directory instead")
  180. to_delete = dict() #Path to delete accumulator
  181. errors = dict()
  182. if len(args.directory) > 0:
  183. #processing & checking -d --directory arguments
  184. for path in args.directory:
  185. apath = os.path.abspath(path)
  186. if not apath.startswith(lodel.plugin.plugins.PLUGINS_PATH):
  187. errors[path] = "Not a subdir of %s"
  188. errors[path] %= lodel.plugin.plugins.PLUGINS_PATH
  189. continue
  190. try:
  191. pinfos = Plugin.dir_is_plugin(apath)
  192. except Exception as e:
  193. if not args.force:
  194. errors[path] = e
  195. continue
  196. to_delete[path] = pinfos
  197. if len(args.plugin_name) > 0:
  198. #Processing -n --plugin-name arguments
  199. plist = Plugin._discover(lodel.plugin.plugins.PLUGINS_PATH)
  200. for pinfos in plist:
  201. if pinfos['name'] in args.plugin_name:
  202. to_delete[pinfos['path']] = pinfos
  203. if len(errors) > 0:
  204. msg = "Following errors detected before begining deletions :\n"
  205. for path, errmsg in errors.items():
  206. msg += "\t- For %s : %s" % (path, errmsg)
  207. print(msg)
  208. if not args.force:
  209. exit(1)
  210. print("Begining deletion :")
  211. for path, pinfos in to_delete.items():
  212. #shutil.rmtree(path)
  213. print("rm -R %s" % path)
  214. print("\t%s(%s) in %s deleted" % (
  215. pinfos['name'], pinfos['version'], pinfos['path']))
  216. ##@brief Handles plugins clean
  217. @classmethod
  218. def clean(cls, args):
  219. import lodel.plugin.plugins
  220. from lodel.plugin.plugins import Plugin
  221. if len(args.archive) > 0:
  222. raise RuntimeError("Cannot specify plugins to uninstall using \
  223. -f --file option. You have to use -d --directory or -n --name")
  224. if len(args.plugin_name) > 0:
  225. names = args.plugin_name
  226. else:
  227. names = list(Plugin.discover().keys())
  228. #_dicover do not remove duplicated names
  229. full_list = Plugin._discover(lodel.plugin.plugins.PLUGINS_PATH)
  230. #Casting into a dict with list of plugins infos
  231. pdict = dict()
  232. for pinfos in full_list:
  233. if pinfos['name'] in names:
  234. if pinfos['name'] in pdict:
  235. pdict[pinfos['name']].append(pinfos)
  236. else:
  237. pdict[pinfos['name']] = [pinfos]
  238. to_clean = list()
  239. clean_count = 0
  240. for pname, pinfos_l in pdict.items():
  241. if len(pinfos_l) > 1:
  242. #There are some plugins to clean
  243. tmp_l = sorted(pinfos_l, key=lambda item: item['version'])
  244. to_clean += tmp_l[:-1]
  245. msg = "Found %s(%s). Cleaning " % (
  246. pname, tmp_l[-1]['version'])
  247. for pinfos in to_clean:
  248. clean_count += 1
  249. str_info = '%s(%s)' % (pname, pinfos['version'])
  250. msg += "%s, " % (str_info)
  251. shutil.rmtree(pinfos['path'])
  252. print(msg)
  253. if clean_count > 0:
  254. print("%d plugins were uninstalled" % clean_count)
  255. else:
  256. print("Allready clean")
  257. ##@brief Implements lodel_admin.py **hooks-list** action
  258. #@ingroup lodel2_script
  259. #@ingroup lodel2_hooks
  260. class ListHooks(lodel_script.LodelScript):
  261. _action = 'hooks-list'
  262. _description = 'Generate a list of registered hooks once instance started'
  263. @classmethod
  264. def argparser_config(cls, parser):
  265. pass
  266. @classmethod
  267. def run(cls, args):
  268. import loader
  269. loader.start()
  270. from lodel.plugin.hooks import LodelHook
  271. hlist = LodelHook.hook_list()
  272. print("Registered hooks : ")
  273. for name in sorted(hlist.keys()):
  274. print("\t- %s is registered by :" % name)
  275. for hfun, priority in hlist[name]:
  276. msg = "\t\t- {modname}.{funname} with priority : {priority}"
  277. print(msg.format(
  278. modname = hfun.__module__,
  279. funname = hfun.__name__,
  280. priority = priority))
  281. print("\n")