check for file existence
[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 enigma import eConsoleAppContainer
6 import os
7
8 class InfoHandlerParseError(Exception):
9         def __init__(self, value):
10                 self.value = value
11         def __str__(self):
12                 return repr(self.value)
13
14 class InfoHandler(xml.sax.ContentHandler):
15         def __init__(self, prerequisiteMet, directory):
16                 self.attributes = {}
17                 self.directory = directory
18                 self.list = []
19                 self.globalprerequisites = {}
20                 self.prerequisites = {}
21                 self.elements = []
22                 self.validFileTypes = ["skin", "config", "services", "favourites", "package"]
23                 self.prerequisitesMet = prerequisiteMet
24         
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"]:
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):
100                 self.directory = "/"
101                 
102                 self.console = eConsoleAppContainer()
103                 self.console.appClosed.get().append(self.installNext)
104                 
105                 self.statusCallback = statusCallback
106                 self.setStatus(self.STATUS_INIT)
107                                 
108                 self.packageslist = []
109         
110         def readInfo(self, directory, file):
111                 print "Reading .info file", file
112                 handler = InfoHandler(self.prerequisiteMet, directory)
113                 try:
114                         xml.sax.parse(file, handler)
115                         for entry in handler.list:
116                                 self.packageslist.append((entry,file)) 
117                 except InfoHandlerParseError:
118                         print "file", file, "ignored due to errors in the file"
119                 print handler.list
120         
121         # prerequisites = True: give only packages matching the prerequisites
122         def fillPackagesList(self, prerequisites = True):
123                 self.packageslist = []
124                 packages = crawlDirectory(self.directory, ".*\.info$")
125                 for package in packages:
126                         self.readInfo(package[0] + "/", package[0] + "/" + package[1])
127                         
128                 if prerequisites:
129                         for package in self.packageslist[:]:
130                                 if not self.prerequisiteMet(package[0]["prerequisites"]):
131                                         self.packageslist.remove(package)
132                 return packages
133                         
134         def prerequisiteMet(self, prerequisites):
135                 # TODO: we need to implement a hardware detection here...
136                 print "prerequisites:", prerequisites
137                 met = True
138                 if prerequisites.has_key("bcastsystem"):
139                         for bcastsystem in prerequisites["bcastsystem"]:
140                                 if nimmanager.hasNimType(bcastsystem):
141                                         return True
142                         return False
143                 if prerequisites.has_key("hardware"):
144                         for hardware in prerequisites["hardware"]:
145                                 # TODO: hardware detection
146                                 met = True
147                 return True
148                         
149         def installPackage(self, index):
150                 print "installing package with index", index, "and name", self.packageslist[index][0]["attributes"]["name"]
151                 
152                 attributes = self.packageslist[index][0]["attributes"]
153                 self.installingAttributes = attributes
154                 self.attributeNames = ["skin", "config", "favourites", "package", "services"]
155                 self.currentAttributeIndex = 0
156                 self.currentIndex = -1
157                 self.installNext()
158                 
159         def setStatus(self, status):
160                 self.status = status
161                 self.statusCallback(self.status, None)
162                                                 
163         def installNext(self, *args, **kwargs):
164                 self.currentIndex += 1
165                 attributes = self.installingAttributes
166                 
167                 if self.currentAttributeIndex >= len(self.attributeNames): # end reached
168                         self.setStatus(self.STATUS_DONE)
169                         return
170                 
171                 self.setStatus(self.STATUS_WORKING)             
172                 
173                 currentAttribute = self.attributeNames[self.currentAttributeIndex]
174                 
175                 print "installing", currentAttribute, "with index", self.currentIndex
176                 
177                 if attributes.has_key(currentAttribute):
178                         if self.currentIndex >= len(attributes[currentAttribute]): # all jobs done for current attribute
179                                 self.currentIndex = -1
180                                 self.currentAttributeIndex += 1
181                                 self.installNext()
182                                 return
183                 else: # nothing to install here
184                         self.currentAttributeIndex += 1
185                         self.installNext()
186                         return
187                         
188                 if currentAttribute == "skin":
189                         skin = attributes["skin"][self.currentIndex]
190                         self.installSkin(skin["directory"], skin["name"])
191                 elif currentAttribute == "config":
192                         if self.currentIndex == 0:
193                                 from Components.config import configfile
194                                 configfile.save()
195                         config = attributes["config"][self.currentIndex]
196                         self.mergeConfig(config["directory"], config["name"])
197                 elif currentAttribute == "favourites":
198                         favourite = attributes["favourites"][self.currentIndex]
199                         self.installFavourites(favourite["directory"], favourite["name"])
200                 elif currentAttribute == "package":
201                         package = attributes["package"][self.currentIndex]
202                         self.installIPK(package["directory"], package["name"])
203                 elif currentAttribute == "services":
204                         service = attributes["services"][self.currentIndex]
205                         self.mergeServices(service["directory"], service["name"])
206                                 
207         def readfile(self, filename):
208                 if not os.path.isfile(filename):
209                         return []
210                 fd = open(filename)
211                 lines = fd.readlines()
212                 fd.close()
213                 return lines
214                         
215         def mergeConfig(self, directory, name, merge = True):
216                 print "merging config:", directory, " - ", name
217
218                 newconfig = self.readfile(directory + name)
219                 newconfig.sort()
220                 print newconfig
221                 
222                 if merge:
223                         oldconfig = self.readfile(resolveFilename(SCOPE_CONFIG) + "settings")
224                         oldconfig.sort()
225                         print oldconfig
226                 else:
227                         oldconfig = []
228                 
229                 # merge with duplicate removal through dictionary
230                 mergeddict = {}
231                 for list in oldconfig, newconfig:
232                         for entry in list:
233                                 splitentry = entry.split("=")
234                                 if len(splitentry) != 2: # wrong entry
235                                         continue
236                                 mergeddict[splitentry[0]] = splitentry[1].strip()
237                 
238                 print "new:"
239                 fd = open(resolveFilename(SCOPE_CONFIG) + "settings", "w")
240                 for entry in mergeddict.keys():
241                         print entry + "=" + mergeddict[entry]
242                         fd.write(entry + "=" + mergeddict[entry] + '\n')
243                 fd.close()
244                 self.installNext()
245                 #configfile.load()
246                 
247                 
248         def installIPK(self, directory, name):
249                 self.ipkg = IpkgComponent()
250                 self.ipkg.addCallback(self.ipkgCallback)
251                 self.ipkg.startCmd(IpkgComponent.CMD_INSTALL, {'package': directory + name})
252                 
253         def ipkgCallback(self, event, param):
254                 print "ipkgCallback"
255                 if event == IpkgComponent.EVENT_DONE:
256                         self.installNext()
257                 elif event == IpkgComponent.EVENT_ERROR:
258                         self.installNext()
259         
260         def installSkin(self, directory, name):
261                 print "installing skin:", directory, " - ", name
262                 print "cp -a %s %s" % (directory, resolveFilename(SCOPE_SKIN))
263                 if self.console.execute("cp -a %s %s" % (directory, resolveFilename(SCOPE_SKIN))):
264                         print "execute failed"
265                         self.installNext()
266
267         def readServices(self, filename):
268                 newservicesfile = self.readfile(filename)
269                 
270                 transponders = []
271                 services = []
272                 status = 0 # 0 = start, 1 = transponders, 2 = services
273                 count = 0
274                 while count < len(newservicesfile):
275                         if status == 0:
276                                 if newservicesfile[count].strip() == "transponders":
277                                         status = 1
278                         elif status == 1: # reading transponders
279                                 if newservicesfile[count].strip() == "end": # finished reading transponders
280                                         pass
281                                 elif newservicesfile[count].strip() == "services": # start of services section
282                                         status = 2
283                                 else:
284                                         transponders.append(''.join(newservicesfile[count:count + 3]))
285                                         count += 2
286                         elif status == 2: # reading services
287                                 if newservicesfile[count].strip() == "end": # finished reading file
288                                         break
289                                 else:
290                                         services.append(''.join(newservicesfile[count:count + 3]))
291                                         count += 2
292                         count += 1
293                 return (transponders, services)
294         
295         def mergeServices(self, directory, name, merge = False):
296                 print "merging services:", directory, " - ", name
297                 
298                 newtransponders, newservices = self.readServices(directory + name)
299                 if merge:
300                         oldtransponders, oldservices = self.readServices(resolveFilename(SCOPE_CONFIG) + "lamedb")
301                 else:
302                         oldtransponders, oldservices = [], []
303                 
304                 fp = open(resolveFilename(SCOPE_CONFIG) + "lamedb", "w")
305                 fp.write("eDVB services /3/\n")
306                 
307                 fp.write("transponders\n")
308                 for transponderlist in oldtransponders, newtransponders:
309                         for transponder in transponderlist:
310                                 fp.write(transponder)
311                 fp.write("end\n")
312                 
313                 fp.write("services\n")
314                 for serviceslist in oldservices, newservices:
315                         for service in serviceslist:
316                                 fp.write(service)
317                 fp.write("end\n")
318                 
319                 fp.close()
320                 self.installNext()
321
322         def installFavourites(self, directory, name):
323                 print "installing favourites:", directory, " - ", name
324
325                 if self.console.execute("cp %s %s" % ((directory + name), resolveFilename(SCOPE_CONFIG))):
326                         print "execute failed"
327                         self.installNext()