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