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