don't allow leaving the software update plugin while ipkg is running
[enigma2.git] / lib / python / Plugins / SystemPlugins / SoftwareUpdate / plugin.py
1 from enigma import eTimer, quitMainloop
2 from Screens.Screen import Screen
3 from Screens.MessageBox import MessageBox
4 from Components.ActionMap import ActionMap, NumberActionMap
5 from Components.ScrollLabel import ScrollLabel
6 from Components.GUIComponent import *
7 from Components.MenuList import MenuList
8 from Components.Input import Input
9 from Screens.Console import Console
10 from Screens.MessageBox import MessageBox
11 from Plugins.Plugin import PluginDescriptor
12 from Screens.ImageWizard import ImageWizard
13 from Components.Ipkg import Ipkg
14 from Components.Slider import Slider
15 from Components.Label import Label
16
17 import os
18
19 class UpdatePluginMenu(Screen):
20         skin = """
21                 <screen position="200,100" size="300,250" title="Update..." >
22                         <widget name="menu" position="10,10" size="290,175" scrollbarMode="showOnDemand" />
23                 </screen>"""
24                 
25         def __init__(self, session, args = 0):
26                 self.skin = UpdatePluginMenu.skin
27                 Screen.__init__(self, session)
28                 
29                 self.menu = args
30                 
31                 list = []
32                 if self.menu == 0:
33                         list.append((_("Image-Upgrade"), "image"))
34                         list.append((_("Online-Upgrade"), "upgrade"))
35                         list.append((_("Advanced"), "advanced"))
36                 elif self.menu == 1:
37                         list.append((_("Choose source"), "source"))
38                         list.append((_("Packet management"), "ipkg"))
39                         list.append((_("Settings"), "setup"))
40                 
41                 self["menu"] = MenuList(list)
42                                 
43                 self["actions"] = ActionMap(["WizardActions", "DirectionActions"], 
44                 {
45                         "ok": self.go,
46                         "back": self.close,
47                 }, -1)
48                 
49         def go(self):
50                 if self.menu == 0:
51                         if (self["menu"].l.getCurrentSelection()[1] == "image"):
52                                 self.session.open(ImageWizard)
53                         if (self["menu"].l.getCurrentSelection()[1] == "upgrade"):
54                                 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to update your Dreambox?\nAfter pressing OK, please wait!"))
55                         if (self["menu"].l.getCurrentSelection()[1] == "advanced"):
56                                 self.session.open(UpdatePluginMenu, 1)
57                 if self.menu == 1:
58                         if (self["menu"].l.getCurrentSelection()[1] == "source"):
59                                 self.session.open(IPKGSource)
60                         elif (self["menu"].l.getCurrentSelection()[1] == "ipkg"):
61                                 self.session.open(Ipkg)
62                         elif (self["menu"].l.getCurrentSelection()[1] == "setup"):
63                                 self.session.open(MessageBox, _("Function not yet implemented"), MessageBox.TYPE_ERROR)
64         
65         def runUpgrade(self, result):
66                 if result:
67                         self.session.open(Console, title = "Upgrade running...", cmdlist = ["ipkg update", "ipkg upgrade -force-defaults -force-overwrite"], finishedCallback = self.runFinished)
68
69         def runFinished(self):
70                 self.session.openWithCallback(self.reboot, MessageBox, _("Upgrade finished. Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
71                 
72         def reboot(self, result):
73                 if result is None:
74                         return
75                 if result:
76                         quitMainloop(3)
77
78 class IPKGSource(Screen):
79         skin = """
80                 <screen position="100,100" size="550,60" title="IPKG source" >
81                         <widget name="text" position="0,0" size="550,25" font="Regular;20" />
82                 </screen>"""
83                 
84         def __init__(self, session, args = None):
85                 self.skin = IPKGSource.skin
86                 Screen.__init__(self, session)
87                 
88                 fp = file('/etc/ipkg/official-feed.conf', 'r')
89                 sources = fp.readlines()
90                 fp.close()
91                 
92                 self["text"] = Input(sources[0], maxSize=False, type=Input.TEXT)
93                                 
94                 self["actions"] = NumberActionMap(["WizardActions", "InputActions"], 
95                 {
96                         "ok": self.go,
97                         "back": self.close,
98                         "left": self.keyLeft,
99                         "right": self.keyRight,
100                         "1": self.keyNumberGlobal,
101                         "2": self.keyNumberGlobal,
102                         "3": self.keyNumberGlobal,
103                         "4": self.keyNumberGlobal,
104                         "5": self.keyNumberGlobal,
105                         "6": self.keyNumberGlobal,
106                         "7": self.keyNumberGlobal,
107                         "8": self.keyNumberGlobal,
108                         "9": self.keyNumberGlobal,
109                         "0": self.keyNumberGlobal
110                 }, -1)
111                 
112         def go(self):
113                 fp = file('/etc/ipkg/official-feed.conf', 'w')
114                 fp.write(self["text"].getText())
115                 fp.close()
116                 self.close()
117                 
118         def keyLeft(self):
119                 self["text"].left()
120         
121         def keyRight(self):
122                 self["text"].right()
123         
124         def keyNumberGlobal(self, number):
125                 print "pressed", number
126                 self["text"].number(number)
127
128 RT_HALIGN_LEFT = 0
129 RT_HALIGN_RIGHT = 1
130 RT_HALIGN_CENTER = 2
131 RT_HALIGN_BLOCK = 4
132
133 RT_VALIGN_TOP = 0
134 RT_VALIGN_CENTER = 8
135 RT_VALIGN_BOTTOM = 16
136
137 def PacketEntryComponent(packet):
138         res = [ packet ]
139         
140         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 0,250, 30, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, packet[0]))
141         res.append((eListboxPythonMultiContent.TYPE_TEXT, 250, 0, 200, 30, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, packet[1]))
142         res.append((eListboxPythonMultiContent.TYPE_TEXT, 450, 0, 100, 30, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, packet[2]))
143         return res
144
145 class PacketList(GUIComponent):
146         def __init__(self, list):
147                 GUIComponent.__init__(self)
148                 self.l = eListboxPythonMultiContent()
149                 self.l.setList(list)
150                 self.l.setFont(0, gFont("Regular", 20))
151                 self.l.setFont(1, gFont("Regular", 18))
152         
153         def getCurrent(self):
154                 return self.l.getCurrentSelection()
155         
156         def GUIcreate(self, parent):
157                 self.instance = eListbox(parent)
158                 self.instance.setContent(self.l)
159                 self.instance.setItemHeight(30)
160         
161         def GUIdelete(self):
162                 self.instance.setContent(None)
163                 self.instance = None
164
165         def invalidate(self):
166                 self.l.invalidate()
167
168 class Ipkg2(Screen):
169         skin = """
170                 <screen position="100,100" size="550,400" title="IPKG upgrade..." >
171                         <widget name="list" position="0,0" size="550,400" scrollbarMode="showOnDemand" />
172                 </screen>"""
173                 
174         def __init__(self, session, args = None):
175                 self.skin = Ipkg.skin
176                 Screen.__init__(self, session)
177         
178                 list = []
179                 self.list = list
180                 self.fillPacketList()
181
182                 self["list"] = PacketList(self.list)
183                                 
184                 self["actions"] = ActionMap(["WizardActions"], 
185                 {
186                         "ok": self.close,
187                         "back": self.close
188                 }, -1)
189                 
190
191         def fillPacketList(self):
192                 lines = os.popen("ipkg list", "r").readlines()
193                 packetlist = []
194                 for x in lines:
195                         split = x.split(' - ')
196                         packetlist.append([split[0].strip(), split[1].strip()])
197                 
198                 lines = os.popen("ipkg list_installed", "r").readlines()
199                 
200                 installedlist = {}
201                 for x in lines:
202                         split = x.split(' - ')
203                         installedlist[split[0].strip()] = split[1].strip()
204                 
205                 for x in packetlist:
206                         status = ""
207                         if installedlist.has_key(x[0]):
208                                 if installedlist[x[0]] == x[1]:
209                                         status = "installed"
210                                 else:
211                                         status = "upgradable"
212                         self.list.append(PacketEntryComponent([x[0], x[1], status]))
213                 
214         def go(self):
215                 if self.update:
216                         self.session.openWithCallback(self.doUpdate, MessageBox, _("Do you want to update your Dreambox?\nAfter pressing OK, please wait!"))            
217                 else:
218                         self.close()
219         
220         def doUpdateDelay(self):
221                 lines = os.popen("ipkg update && ipkg upgrade", "r").readlines()
222                 string = ""
223                 for x in lines:
224                         string += x
225                 self["text"].setText(_("Updating finished. Here is the result:") + "\n\n" + string)
226                 self.update = False
227                         
228         
229         def doUpdate(self, val = False):
230                 if val == True:
231                         self["text"].setText(_("Updating... Please wait... This can take some minutes..."))
232                         self.delayTimer.start(0, 1)
233                 else:
234                         self.close()
235                         
236 class UpdatePlugin(Screen):
237         skin = """
238                 <screen position="100,100" size="550,200" title="Software Update..." >
239                         <widget name="activityslider" position="0,0" size="550,5"  />
240                         <widget name="slider" position="0,100" size="550,30"  />
241                         <widget name="package" position="10,30" size="420,20" font="Regular;18"/>
242                         <widget name="status" position="10,60" size="420,45" font="Regular;18"/>
243                 </screen>"""
244                 
245         def __init__(self, session, args = None):
246                 self.skin = UpdatePlugin.skin
247                 Screen.__init__(self, session)
248                 
249                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
250                 
251                 self.slider = Slider(0, 4)
252                 self["slider"] = self.slider
253                 self.activityslider = Slider(0, 100)
254                 self["activityslider"] = self.activityslider
255                 self.status = Label(_("Upgrading Dreambox... Please wait"))
256                 self["status"] = self.status
257                 self.package = Label()
258                 self["package"] = self.package
259                 
260                 self.packages = 0
261                 self.error = 0
262                 
263                 self.activity = 0
264                 self.activityTimer = eTimer()
265                 self.activityTimer.timeout.get().append(self.doActivityTimer)
266                 self.activityTimer.start(100, False)
267                                 
268                 self.ipkg = Ipkg()
269                 self.ipkg.addCallback(self.ipkgCallback)
270                 
271                 self.updating = True
272                 self.package.setText(_("Package list update"))
273                 self.ipkg.cmdUpdate()
274                         
275                 self["actions"] = ActionMap(["WizardActions"], 
276                 {
277                         "ok": self.exit,
278                         "back": self.exit
279                 }, -1)
280                 
281         def doActivityTimer(self):
282                 self.activity += 1
283                 if self.activity == 100:
284                         self.activity = 0
285                 self.activityslider.setValue(self.activity)
286                 
287         def ipkgCallback(self, event, param):
288                 if event == Ipkg.EVENT_DOWNLOAD:
289                         self.status.setText(_("Downloading"))
290                 elif event == Ipkg.EVENT_UPGRADE:
291                         if self.sliderPackages.has_key(param):
292                                 self.slider.setValue(self.sliderPackages[param])
293                         self.package.setText(param)
294                         self.status.setText(_("Upgrading"))
295                         self.packages += 1
296                 elif event == Ipkg.EVENT_INSTALL:
297                         self.package.setText(param)
298                         self.status.setText(_("Installing"))
299                         self.packages += 1
300                 elif event == Ipkg.EVENT_CONFIGURING:
301                         self.package.setText(param)
302                         self.status.setText(_("Configuring"))
303                 elif event == Ipkg.EVENT_ERROR:
304                         self.error += 1
305                 elif event == Ipkg.EVENT_DONE:
306                         if self.updating:
307                                 self.updating = False
308                                 self.ipkg.cmdUpgrade(test_only = False)
309                         elif self.error == 0:
310                                 self.slider.setValue(4)
311                                 
312                                 self.activityTimer.stop()
313                                 self.activityslider.setValue(0)
314                                 
315                                 self.package.setText("")
316                                 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
317                         else:
318                                 self.activityTimer.stop()
319                                 self.activityslider.setValue(0)
320                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
321                                 if self.packages == 0:
322                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
323                                 if self.updating:
324                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
325                                 self.status.setText(_("Error") +  " - " + error)
326                 #print event, "-", param
327                 pass
328         
329         def exit(self):
330                 if not self.ipkg.isRunning():
331                         if self.packages != 0 and self.error == 0:
332                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished. Do you want to reboot your Dreambox?"))
333                         else:
334                                 self.close()
335                         
336         def exitAnswer(self, result):
337                 if result is not None and result:
338                         quitMainloop(2)
339                 self.close()
340
341 def UpgradeMain(session, **kwargs):
342         session.open(UpdatePlugin)
343
344 def Plugins(**kwargs):
345         return PluginDescriptor(name="Softwareupdate", description=_("Updates your receiver's software"), icon="update.png", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=UpgradeMain)