add .nfi to filescanner for NFIFlash plugin, whitespace cleanup, change md5sum check...
[enigma2.git] / lib / python / Components / DreamInfoHandler.py
1 import xml.sax
2 from Tools.Directories import crawlDirectory, resolveFilename, SCOPE_CONFIG, SCOPE_SKIN, copyfile, copytree
3 from Components.NimManager import nimmanager
4 from Components.Ipkg import IpkgComponent
5 from Components.config import config, configfile
6 from Tools.HardwareInfo import HardwareInfo
7 from enigma import eConsoleAppContainer, eDVBDB
8 import os
9
10 class InfoHandlerParseError(Exception):
11         def __init__(self, value):
12                 self.value = value
13         def __str__(self):
14                 return repr(self.value)
15
16 class InfoHandler(xml.sax.ContentHandler):
17         def __init__(self, prerequisiteMet, directory):
18                 self.attributes = {}
19                 self.directory = directory
20                 self.list = []
21                 self.globalprerequisites = {}
22                 self.prerequisites = {}
23                 self.elements = []
24                 self.validFileTypes = ["skin", "config", "services", "favourites", "package"]
25                 self.prerequisitesMet = prerequisiteMet
26                 
27         def printError(self, error):
28                 print "Error in defaults xml files:", error
29                 raise InfoHandlerParseError, error
30     
31         def startElement(self, name, attrs):
32                 #print name, ":", attrs.items()
33                 self.elements.append(name)
34                 if name in ["hardware", "bcastsystem", "satellite", "tag"]:
35                         if not attrs.has_key("type"):
36                                         self.printError(str(name) + " tag with no type attribute")
37                         if self.elements[-3] == "default":
38                                 prerequisites = self.globalprerequisites
39                         else:
40                                 prerequisites = self.prerequisites
41                         if not prerequisites.has_key(name):
42                                 prerequisites[name] = []
43                         prerequisites[name].append(str(attrs["type"]))
44                 if name == "files":
45                         if attrs.has_key("type"):
46                                 if attrs["type"] == "directories":
47                                         self.attributes["filestype"] = "directories"
48                                 # TODO add a compressed archive type
49                 if name == "file":
50                         self.prerequisites = {}
51                         if not attrs.has_key("type"):
52                                 self.printError("file tag with no type attribute")
53                         else:
54                                 if not attrs.has_key("name"):
55                                         self.printError("file tag with no name attribute")
56                                 else:   
57                                         if not attrs.has_key("directory"):
58                                                 directory = self.directory
59                                         type = attrs["type"]
60                                         if not type in self.validFileTypes:
61                                                 self.printError("file tag with invalid type attribute")
62                                         else:
63                                                 self.filetype = type
64                                                 self.fileattrs = attrs
65         def endElement(self, name):
66                 #print "end", name
67                 #print "self.elements:", self.elements
68                 self.elements.pop()
69                 if name == "file":
70                         #print "prerequisites:", self.prerequisites
71                         if len(self.prerequisites) == 0 or self.prerequisitesMet(self.prerequisites):
72                                 if not self.attributes.has_key(self.filetype):
73                                         self.attributes[self.filetype] = []
74                                 if self.fileattrs.has_key("directory"):
75                                         directory = str(self.fileattrs["directory"])
76                                         if len(directory) < 1 or directory[0] != "/":
77                                                 directory = self.directory + directory
78                                 else:
79                                         directory = self.directory
80                                 self.attributes[self.filetype].append({ "name": str(self.fileattrs["name"]), "directory": directory })
81     
82                 if name == "default":
83                         self.list.append({"attributes": self.attributes, 'prerequisites': self.globalprerequisites})
84                         self.attributes = {}
85                         self.globalprerequisites = {}
86     
87         def characters(self, data):
88                 if self.elements[-1] == "author":
89                         self.attributes["author"] = str(data)
90                 if self.elements[-1] == "name":
91                         self.attributes["name"] = str(data)
92                 #print "characters", data
93                 
94 class DreamInfoHandler:
95         STATUS_WORKING = 0
96         STATUS_DONE = 1
97         STATUS_ERROR = 2
98         STATUS_INIT = 4
99         
100         def __init__(self, statusCallback, blocking = False, neededTag = None):
101                 self.hardware_info = HardwareInfo()
102                 self.directory = "/"
103                 
104                 self.neededTag = neededTag
105                 
106                 # caution: blocking should only be used, if further execution in enigma2 depends on the outcome of
107                 # the installer!
108                 self.blocking = blocking
109                 
110                 self.currentlyInstallingMetaIndex = None
111                 
112                 self.console = eConsoleAppContainer()
113                 self.console.appClosed.get().append(self.installNext)
114                 self.reloadFavourites = False
115                 
116                 self.statusCallback = statusCallback
117                 self.setStatus(self.STATUS_INIT)
118                                 
119                 self.packageslist = []
120                         
121         def readInfo(self, directory, file):
122                 print "Reading .info file", file
123                 handler = InfoHandler(self.prerequisiteMet, directory)
124                 try:
125                         xml.sax.parse(file, handler)
126                         for entry in handler.list:
127                                 self.packageslist.append((entry,file)) 
128                 except InfoHandlerParseError:
129                         print "file", file, "ignored due to errors in the file"
130                 print handler.list
131         
132         # prerequisites = True: give only packages matching the prerequisites
133         def fillPackagesList(self, prerequisites = True):
134                 self.packageslist = []
135                 packages = []
136                 if not isinstance(self.directory, list):
137                         self.directory = [self.directory]
138                 
139                 for directory in self.directory:
140                         packages += crawlDirectory(directory, ".*\.info$")
141
142                 for package in packages:
143                         self.readInfo(package[0] + "/", package[0] + "/" + package[1])
144                         
145                 if prerequisites:
146                         for package in self.packageslist[:]:
147                                 if not self.prerequisiteMet(package[0]["prerequisites"]):
148                                         self.packageslist.remove(package)
149                 return self.packageslist
150                         
151         def prerequisiteMet(self, prerequisites):
152                 # TODO: we need to implement a hardware detection here...
153                 print "prerequisites:", prerequisites
154                 met = True
155                 if self.neededTag is None:
156                         if prerequisites.has_key("tag"):
157                                 return False
158                 else:
159                         if prerequisites.has_key("tag"):
160                                 if not self.neededTag in prerequisites["tag"]:
161                                         return False
162                         else:
163                                 return False
164                                 
165                 if prerequisites.has_key("satellite"):
166                         for sat in prerequisites["satellite"]:
167                                 if int(sat) not in nimmanager.getConfiguredSats():
168                                         return False                    
169                 if prerequisites.has_key("bcastsystem"):
170                         has_system = False
171                         for bcastsystem in prerequisites["bcastsystem"]:
172                                 if nimmanager.hasNimType(bcastsystem):
173                                         has_system = True
174                         if not has_system:
175                                 return False
176                 if prerequisites.has_key("hardware"):
177                         hardware_found = False
178                         for hardware in prerequisites["hardware"]:
179                                 if hardware == self.hardware_info.device_name:
180                                         hardware_found = True
181                         if not hardware_found:
182                                 return False
183                 return True
184         
185         def installPackages(self, indexes):
186                 print "installing packages", indexes
187                 if len(indexes) == 0:
188                         self.setStatus(self.STATUS_DONE)
189                         return
190                 self.installIndexes = indexes
191                 print "+++++++++++++++++++++++bla"
192                 self.currentlyInstallingMetaIndex = 0
193                 self.installPackage(self.installIndexes[self.currentlyInstallingMetaIndex])
194
195         def installPackage(self, index):
196                 print "self.packageslist:", self.packageslist
197                 if len(self.packageslist) <= index:
198                         print "no package with index", index, "found... installing nothing"
199                         return
200                 print "installing package with index", index, "and name", self.packageslist[index][0]["attributes"]["name"]
201                 
202                 attributes = self.packageslist[index][0]["attributes"]
203                 self.installingAttributes = attributes
204                 self.attributeNames = ["skin", "config", "favourites", "package", "services"]
205                 self.currentAttributeIndex = 0
206                 self.currentIndex = -1
207                 self.installNext()
208                 
209         def setStatus(self, status):
210                 self.status = status
211                 self.statusCallback(self.status, None)
212                                                 
213         def installNext(self, *args, **kwargs):
214                 if self.reloadFavourites:
215                         self.reloadFavourites = False
216                         db = eDVBDB.getInstance().reloadBouquets()
217
218                 self.currentIndex += 1
219                 attributes = self.installingAttributes
220                 #print "attributes:", attributes
221                 
222                 if self.currentAttributeIndex >= len(self.attributeNames): # end of package reached
223                         print "end of package reached"
224                         if self.currentlyInstallingMetaIndex is None or self.currentlyInstallingMetaIndex >= len(self.installIndexes) - 1:
225                                 print "set status to DONE"
226                                 self.setStatus(self.STATUS_DONE)
227                                 return
228                         else:
229                                 print "increment meta index to install next package"
230                                 self.currentlyInstallingMetaIndex += 1
231                                 self.currentAttributeIndex = 0
232                                 self.installPackage(self.installIndexes[self.currentlyInstallingMetaIndex])
233                                 return
234                 
235                 self.setStatus(self.STATUS_WORKING)             
236                 
237                 print "currentAttributeIndex:", self.currentAttributeIndex
238                 currentAttribute = self.attributeNames[self.currentAttributeIndex]
239                 
240                 print "installing", currentAttribute, "with index", self.currentIndex
241                 
242                 if attributes.has_key(currentAttribute):
243                         if self.currentIndex >= len(attributes[currentAttribute]): # all jobs done for current attribute
244                                 self.currentIndex = -1
245                                 self.currentAttributeIndex += 1
246                                 self.installNext()
247                                 return
248                 else: # nothing to install here
249                         self.currentIndex = -1
250                         self.currentAttributeIndex += 1
251                         self.installNext()
252                         return
253                         
254                 if currentAttribute == "skin":
255                         skin = attributes["skin"][self.currentIndex]
256                         self.installSkin(skin["directory"], skin["name"])
257                 elif currentAttribute == "config":
258                         if self.currentIndex == 0:
259                                 from Components.config import configfile
260                                 configfile.save()
261                         config = attributes["config"][self.currentIndex]
262                         self.mergeConfig(config["directory"], config["name"])
263                 elif currentAttribute == "favourites":
264                         favourite = attributes["favourites"][self.currentIndex]
265                         self.installFavourites(favourite["directory"], favourite["name"])
266                 elif currentAttribute == "package":
267                         package = attributes["package"][self.currentIndex]
268                         self.installIPK(package["directory"], package["name"])
269                 elif currentAttribute == "services":
270                         service = attributes["services"][self.currentIndex]
271                         self.mergeServices(service["directory"], service["name"])
272                                 
273         def readfile(self, filename):
274                 if not os.path.isfile(filename):
275                         return []
276                 fd = open(filename)
277                 lines = fd.readlines()
278                 fd.close()
279                 return lines
280                         
281         def mergeConfig(self, directory, name, merge = True):
282                 print "merging config:", directory, " - ", name
283                 if os.path.isfile(directory + name):
284                         config.loadFromFile(directory + name)
285                         configfile.save()
286                 self.installNext()
287                 
288         def installIPK(self, directory, name):
289                 if self.blocking:
290                         os.system("ipkg install " + directory + name)
291                         self.installNext()
292                 else:
293                         self.ipkg = IpkgComponent()
294                         self.ipkg.addCallback(self.ipkgCallback)
295                         self.ipkg.startCmd(IpkgComponent.CMD_INSTALL, {'package': directory + name})
296                 
297         def ipkgCallback(self, event, param):
298                 print "ipkgCallback"
299                 if event == IpkgComponent.EVENT_DONE:
300                         self.installNext()
301                 elif event == IpkgComponent.EVENT_ERROR:
302                         self.installNext()
303         
304         def installSkin(self, directory, name):
305                 print "installing skin:", directory, " - ", name
306                 print "cp -a %s %s" % (directory, resolveFilename(SCOPE_SKIN))
307                 if self.blocking:
308                         copytree(directory, resolveFilename(SCOPE_SKIN))
309                         self.installNext()
310                 else:
311                         if self.console.execute("cp -a %s %s" % (directory, resolveFilename(SCOPE_SKIN))):
312                                 print "execute failed"
313                                 self.installNext()
314
315         def mergeServices(self, directory, name, merge = False):
316                 print "merging services:", directory, " - ", name
317                 if os.path.isfile(directory + name):
318                         db = eDVBDB.getInstance()
319                         db.reloadServicelist()
320                         db.loadServicelist(directory + name)
321                         db.saveServicelist()
322                 self.installNext()
323
324         def installFavourites(self, directory, name):
325                 print "installing favourites:", directory, " - ", name
326                 self.reloadFavourites = True
327
328                 if self.blocking:
329                         copyfile(directory + name, resolveFilename(SCOPE_CONFIG))
330                         self.installNext()
331                 else:
332                         if self.console.execute("cp %s %s" % ((directory + name), resolveFilename(SCOPE_CONFIG))):
333                                 print "execute failed"
334                                 self.installNext()