PluginSystem: implement new PluginDescriptor option "needsRestart" to define if a...
[vuplus_dvbapp] / lib / python / Components / PluginComponent.py
1 from os import path as os_path, listdir as os_listdir
2 from traceback import print_exc
3 from sys import stdout
4
5 from Tools.Directories import fileExists
6 from Tools.Import import my_import
7 from Plugins.Plugin import PluginDescriptor
8 import keymapparser
9
10 class PluginComponent:
11         firstRun = True
12         restartRequired = False
13         
14         def __init__(self):
15                 self.plugins = {}
16                 self.pluginList = [ ]
17                 self.setPluginPrefix("Plugins.")
18                 self.resetWarnings()
19
20         def setPluginPrefix(self, prefix):
21                 self.prefix = prefix
22
23         def addPlugin(self, plugin):
24                 if self.firstRun:
25                         self.pluginList.append(plugin)
26                         for x in plugin.where:
27                                 self.plugins.setdefault(x, []).append(plugin)
28                                 if x == PluginDescriptor.WHERE_AUTOSTART:
29                                         plugin(reason=0)
30                 else:
31                         if plugin.needsRestart is False:
32                                 self.pluginList.append(plugin)
33                                 for x in plugin.where:
34                                         self.plugins.setdefault(x, []).append(plugin)
35                                         if x == PluginDescriptor.WHERE_AUTOSTART:
36                                                 plugin(reason=0)                                
37                         else:
38                                 self.restartRequired = True
39                                 
40         def removePlugin(self, plugin):
41                 self.pluginList.remove(plugin)
42                 for x in plugin.where:
43                         self.plugins[x].remove(plugin)
44                         if x == PluginDescriptor.WHERE_AUTOSTART:
45                                 plugin(reason=1)
46
47         def readPluginList(self, directory):
48                 """enumerates plugins"""
49
50                 categories = os_listdir(directory)
51
52                 new_plugins = [ ]
53
54                 for c in categories:
55                         directory_category = directory + c
56                         if not os_path.isdir(directory_category):
57                                 continue
58                         open(directory_category + "/__init__.py", "a").close()
59                         for pluginname in os_listdir(directory_category):
60                                 path = directory_category + "/" + pluginname
61                                 if os_path.isdir(path):
62                                         if fileExists(path + "/plugin.pyc") or fileExists(path + "/plugin.pyo") or fileExists(path + "/plugin.py"):
63                                                 try:
64                                                         plugin = my_import('.'.join(["Plugins", c, pluginname, "plugin"]))
65
66                                                         if not plugin.__dict__.has_key("Plugins"):
67                                                                 print "Plugin %s doesn't have 'Plugin'-call." % (pluginname)
68                                                                 continue
69
70                                                         plugins = plugin.Plugins(path=path)
71                                                 except Exception, exc:
72                                                         print "Plugin ", c + "/" + pluginname, "failed to load:", exc
73                                                         print_exc(file=stdout)
74                                                         print "skipping plugin."
75                                                         self.warnings.append( (c + "/" + pluginname, str(exc)) )
76                                                         continue
77
78                                                 # allow single entry not to be a list
79                                                 if not isinstance(plugins, list):
80                                                         plugins = [ plugins ]
81
82                                                 for p in plugins:
83                                                         p.updateIcon(path)
84                                                         new_plugins.append(p)
85
86                                                 if fileExists(path + "/keymap.xml"):
87                                                         try:
88                                                                 keymapparser.readKeymap(path + "/keymap.xml")
89                                                         except Exception, exc:
90                                                                 print "keymap for plugin %s/%s failed to load: " % (c, pluginname), exc
91                                                                 self.warnings.append( (c + "/" + pluginname, str(exc)) )
92
93                 # build a diff between the old list of plugins and the new one
94                 # internally, the "fnc" argument will be compared with __eq__
95                 plugins_added = [p for p in new_plugins if p not in self.pluginList]
96                 plugins_removed = [p for p in self.pluginList if not p.internal and p not in new_plugins]
97                 
98                 #ignore already installed but reloaded plugins
99                 for p in plugins_removed: 
100                         for pa in plugins_added:
101                                 if pa.name == p.name and pa.where == p.where:
102                                         pa.needsRestart = False
103
104                 for p in plugins_removed:
105                         self.removePlugin(p)
106
107                 for p in plugins_added:
108                         self.addPlugin(p)
109                 
110                 if self.firstRun:
111                         self.firstRun = False
112
113         def getPlugins(self, where):
114                 """Get list of plugins in a specific category"""
115
116                 if not isinstance(where, list):
117                         where = [ where ]
118                 res = [ ]
119
120                 for x in where:
121                         res.extend(self.plugins.get(x, [ ]))
122
123                 return  res
124
125         def getPluginsForMenu(self, menuid):
126                 res = [ ]
127                 for p in self.getPlugins(PluginDescriptor.WHERE_MENU):
128                         res += p(menuid)
129                 return res
130
131         def clearPluginList(self):
132                 self.pluginList = []
133                 self.plugins = {}
134
135         def shutdown(self):
136                 for p in self.pluginList[:]:
137                         self.removePlugin(p)
138
139         def resetWarnings(self):
140                 self.warnings = [ ]
141
142         def getNextWakeupTime(self):
143                 wakeup = -1
144                 for p in self.pluginList:
145                         current = p.getWakeupTime()
146                         if current > -1 and (wakeup > current or wakeup == -1):
147                                 wakeup = current
148                 return int(wakeup)
149
150 plugins = PluginComponent()