|
@@ -21,31 +21,52 @@ from lodel.exceptions import *
|
21
|
21
|
# - main.py containing hooks registration etc
|
22
|
22
|
# - confspec.py containing a configuration specification dictionary named CONFSPEC
|
23
|
23
|
|
|
24
|
+## @defgroup plugin_init_specs Plugins <code>__init__.py</code> specifications
|
|
25
|
+#@{
|
|
26
|
+
|
24
|
27
|
##@brief The package in which we will load plugins modules
|
25
|
28
|
VIRTUAL_PACKAGE_NAME = 'lodel.plugins'
|
26
|
29
|
##@brief The temporary package to import python sources
|
27
|
30
|
VIRTUAL_TEMP_PACKAGE_NAME = 'lodel.plugin_tmp'
|
28
|
31
|
##@brief Plugin init filename
|
29
|
32
|
INIT_FILENAME = '__init__.py' # Loaded with settings
|
|
33
|
+##@brief Name of the variable containing the plugin name
|
30
|
34
|
PLUGIN_NAME_VARNAME = '__plugin_name__'
|
|
35
|
+##@brief Name of the variable containing the plugin type
|
31
|
36
|
PLUGIN_TYPE_VARNAME = '__plugin_type__'
|
|
37
|
+##@brief Name of the variable containing the plugin version
|
32
|
38
|
PLUGIN_VERSION_VARNAME = '__version__'
|
|
39
|
+##@brief Name of the variable containing the confpsec filename
|
33
|
40
|
CONFSPEC_FILENAME_VARNAME = '__confspec__'
|
|
41
|
+##@brief Name of the variable containing the confspecs
|
34
|
42
|
CONFSPEC_VARNAME = 'CONFSPEC'
|
|
43
|
+##@brief Name of the variable containing the loader filename
|
35
|
44
|
LOADER_FILENAME_VARNAME = '__loader__'
|
|
45
|
+##@brief Name of the variable containing the plugin dependencies
|
36
|
46
|
PLUGIN_DEPS_VARNAME = '__plugin_deps__'
|
|
47
|
+##@brief Name of the optionnal activate method
|
37
|
48
|
ACTIVATE_METHOD_NAME = '_activate'
|
38
|
49
|
##@brief Discover stage cache filename
|
39
|
50
|
DISCOVER_CACHE_FILENAME = '.plugin_discover_cache.json'
|
40
|
51
|
##@brief Default & failover value for plugins path list
|
41
|
52
|
DEFAULT_PLUGINS_PATH_LIST = ['./plugins']
|
42
|
53
|
|
|
54
|
+##@brief List storing the mandatory variables expected in a plugin __init__.py
|
|
55
|
+#file
|
43
|
56
|
MANDATORY_VARNAMES = [PLUGIN_NAME_VARNAME, LOADER_FILENAME_VARNAME,
|
44
|
57
|
PLUGIN_VERSION_VARNAME]
|
45
|
58
|
|
|
59
|
+##@brief Default plugin type
|
46
|
60
|
DEFAULT_PLUGIN_TYPE = 'extension' #Value found in lodel/plugin/extensions.py::Extensions._type_conf_name
|
47
|
61
|
|
|
62
|
+## @}
|
|
63
|
+
|
48
|
64
|
##@brief Describe and handle version numbers
|
|
65
|
+#
|
|
66
|
+#A version number can be represented by a string like MAJOR.MINOR.PATCH
|
|
67
|
+#or by a list [MAJOR, MINOR,PATCH ].
|
|
68
|
+#
|
|
69
|
+#The class implements basics comparison function and string repr
|
49
|
70
|
class PluginVersion(object):
|
50
|
71
|
|
51
|
72
|
PROPERTY_LIST = ['major', 'minor', 'revision' ]
|
|
@@ -82,14 +103,17 @@ but %d arguments found" % len(args))
|
82
|
103
|
for i,v in enumerate(args):
|
83
|
104
|
self.__version[i] = v
|
84
|
105
|
|
|
106
|
+ ##@brief Property to access major version number
|
85
|
107
|
@property
|
86
|
108
|
def major(self):
|
87
|
109
|
return self.__version[0]
|
88
|
110
|
|
|
111
|
+ ##@brief Property to access minor version number
|
89
|
112
|
@property
|
90
|
113
|
def minor(self):
|
91
|
114
|
return self.__version[1]
|
92
|
115
|
|
|
116
|
+ ##@brief Property to access patch version number
|
93
|
117
|
@property
|
94
|
118
|
def revision(self):
|
95
|
119
|
return self.__version[2]
|
|
@@ -147,8 +171,7 @@ to generic PluginVersion comparison function : '%s'" % cmp_fun_name)
|
147
|
171
|
return {'major': self.major, 'minor': self.minor,
|
148
|
172
|
'revision': self.revision}
|
149
|
173
|
|
150
|
|
-##@brief Plugin metaclass that allows to "catch" child class
|
151
|
|
-#declaration
|
|
174
|
+##@brief Plugin metaclass that allows to "catch" child class declaration
|
152
|
175
|
#
|
153
|
176
|
#Automatic script registration on child class declaration
|
154
|
177
|
class MetaPlugType(type):
|
|
@@ -158,6 +181,7 @@ class MetaPlugType(type):
|
158
|
181
|
#key is the _type_conf_name and value is the class
|
159
|
182
|
_all_ptypes = dict()
|
160
|
183
|
|
|
184
|
+ ##@brief type constructor reimplementation
|
161
|
185
|
def __init__(self, name, bases, attrs):
|
162
|
186
|
#Here we can store all child classes of Plugin
|
163
|
187
|
super().__init__(name, bases, attrs)
|
|
@@ -165,15 +189,24 @@ class MetaPlugType(type):
|
165
|
189
|
return
|
166
|
190
|
#Regitering a new plugin type
|
167
|
191
|
MetaPlugType._all_ptypes[self._type_conf_name] = self
|
168
|
|
-
|
|
192
|
+
|
|
193
|
+ ##@brief Accessor to the list of plugin types
|
|
194
|
+ #@return A copy of _all_ptypes attribute (a dict with typename as key
|
|
195
|
+ #and the class as value)
|
169
|
196
|
@classmethod
|
170
|
197
|
def all_types(cls):
|
171
|
198
|
return copy.copy(cls._all_ptypes)
|
172
|
|
-
|
|
199
|
+
|
|
200
|
+ ##@brief Accessor to the list of plugin names
|
|
201
|
+ #@return a list of plugin name
|
173
|
202
|
@classmethod
|
174
|
203
|
def all_ptype_names(cls):
|
175
|
204
|
return list(cls._all_ptypes.keys())
|
176
|
|
-
|
|
205
|
+
|
|
206
|
+ ##@brief Given a plugin type name return a Plugin child class
|
|
207
|
+ #@param ptype_name str : a plugin type name
|
|
208
|
+ #@return A Plugin child class
|
|
209
|
+ #@throw PluginError if ptype_name is not an exsiting plugin type name
|
177
|
210
|
@classmethod
|
178
|
211
|
def type_from_name(cls, ptype_name):
|
179
|
212
|
if ptype_name not in cls._all_ptypes:
|
|
@@ -225,14 +258,18 @@ class Plugin(object, metaclass=MetaPlugType):
|
225
|
258
|
# @throw PluginError
|
226
|
259
|
def __init__(self, plugin_name):
|
227
|
260
|
|
|
261
|
+ ##@brief The plugin name
|
228
|
262
|
self.name = plugin_name
|
|
263
|
+ ##@brief The plugin package path
|
229
|
264
|
self.path = self.plugin_path(plugin_name)
|
230
|
265
|
|
231
|
266
|
##@brief Stores the plugin module
|
232
|
267
|
self.module = None
|
233
|
|
- ##@breif Stores the plugin loader module
|
|
268
|
+ ##@brief Stores the plugin loader module
|
234
|
269
|
self.__loader_module = None
|
|
270
|
+ ##@brief The plugin confspecs
|
235
|
271
|
self.__confspecs = dict()
|
|
272
|
+ ##@brief Boolean flag telling if the plugin is loaded or not
|
236
|
273
|
self.loaded = False
|
237
|
274
|
|
238
|
275
|
# Importing __init__.py infos in it
|
|
@@ -295,7 +332,6 @@ class Plugin(object, metaclass=MetaPlugType):
|
295
|
332
|
self.__type = DEFAULT_PLUGIN_TYPE
|
296
|
333
|
self.__type = str(self.__type).lower()
|
297
|
334
|
if self.__type not in MetaPlugType.all_ptype_names():
|
298
|
|
- print("FUCK : ", MetaPlugType.all_ptype_names())
|
299
|
335
|
raise PluginError("Unknown plugin type '%s'" % self.__type)
|
300
|
336
|
# Load plugin name from init file (just for checking)
|
301
|
337
|
try:
|
|
@@ -474,6 +510,9 @@ name differ from the one found in plugin's init file"
|
474
|
510
|
def confspecs(self):
|
475
|
511
|
return copy.copy(self.__confspecs)
|
476
|
512
|
|
|
513
|
+ ##@brief Accessor to confspec indicating where we can find the plugin list
|
|
514
|
+ #@note Abtract method implemented only for Plugin child classes
|
|
515
|
+ #This attribute indicate where we fetch the plugin list.
|
477
|
516
|
@classmethod
|
478
|
517
|
def plist_confspecs(cls):
|
479
|
518
|
if cls._plist_confspecs is None:
|
|
@@ -546,7 +585,6 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
|
546
|
585
|
if ptype not in MetaPlugType.all_ptype_names():
|
547
|
586
|
raise PluginError("Unknown plugin type '%s'" % ptype)
|
548
|
587
|
pcls = MetaPlugType.type_from_name(ptype)
|
549
|
|
- print("\n\n\nINSTANCIATING : ", pcls, " from name : ", ptype)
|
550
|
588
|
plugin = pcls(plugin_name)
|
551
|
589
|
cls._plugin_instances[plugin_name] = plugin
|
552
|
590
|
logger.debug("Plugin %s available." % plugin)
|
|
@@ -582,7 +620,14 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
|
582
|
620
|
pass
|
583
|
621
|
|
584
|
622
|
return plist[plugin_name]['path']
|
585
|
|
-
|
|
623
|
+
|
|
624
|
+ ##@brief Return the plugin module name
|
|
625
|
+ #
|
|
626
|
+ #This module name is the "virtual" module where we imported the plugin.
|
|
627
|
+ #
|
|
628
|
+ #Typically composed like VIRTUAL_PACKAGE_NAME.PLUGIN_NAME
|
|
629
|
+ #@param plugin_name str : a plugin name
|
|
630
|
+ #@return a string representing a module name
|
586
|
631
|
@classmethod
|
587
|
632
|
def plugin_module_name(cls, plugin_name):
|
588
|
633
|
return "%s.%s" % (VIRTUAL_PACKAGE_NAME, plugin_name)
|
|
@@ -596,7 +641,8 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
|
596
|
641
|
def start(cls, plugins):
|
597
|
642
|
for plugin_name in plugins:
|
598
|
643
|
cls.register(plugin_name)
|
599
|
|
-
|
|
644
|
+
|
|
645
|
+ ##@brief Attempt to "restart" the Plugin class
|
600
|
646
|
@classmethod
|
601
|
647
|
def clear(cls):
|
602
|
648
|
if cls._plugin_directories is not None:
|