source: lliurex-up/trunk/fuentes/lliurex-up-indicator/usr/bin/lliurex-up-indicator @ 5599

Last change on this file since 5599 was 5599, checked in by jrpelegrina, 3 years ago

Wip in lliurex-up-indicator

  • Property svn:executable set to *
File size: 9.0 KB
Line 
1#!/usr/bin/env python
2
3import gi
4gi.require_version('Gtk', '3.0')
5from gi.repository import Gtk, Pango, GdkPixbuf, Gdk, Gio, GObject, GLib
6gi.require_version('AppIndicator3', '0.1')
7from gi.repository import AppIndicator3 as appindicator
8
9import os
10import subprocess
11import threading
12import notify2
13import sys
14import grp
15import re
16import time
17import multiprocessing
18
19from aptdaemon import client
20
21import pyinotify
22from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
23
24import signal
25signal.signal(signal.SIGINT, signal.SIG_DFL)
26
27
28
29
30RSRC="/usr/share/lliurex-up/"
31SP1=RSRC+"rsrc/sp1.png"
32SP2=RSRC+"rsrc/sp2.png"
33SP3=RSRC+"rsrc/sp3.png"
34SP4=RSRC+"rsrc/sp4.png"
35SP5=RSRC+"rsrc/sp5.png"
36
37TARGET_FILE="/var/run/lliurexUp.lock"
38
39
40
41class UpgradeIndicator:
42
43        ID="net.lliurex.UpgradeIndicator"
44        GROUPS=["admins","adm"]
45        WATCH_DIR=os.path.expanduser("/var/run")
46
47        def __init__(self,icon_name):
48
49                self.sp_cont=0
50                self.sp_img=0
51
52                self.FREQUENCY=3600
53                self.updatedInfo=False
54                self.remoteUpdateInfo=False
55                self.is_working=False
56                self.is_cache_updated=True
57                self.last_check=0
58                self.lliurexUp_running=False
59                self.get_flavour()
60                self.get_user_group()
61                #self.remote_executing=False
62
63                self.app_indicator=appindicator.Indicator.new(UpgradeIndicator.ID,icon_name,appindicator.IndicatorCategory.APPLICATION_STATUS)
64                self.app_indicator.set_status(appindicator.IndicatorStatus.PASSIVE)
65                self.menu = Gtk.Menu()
66               
67                self.menu.add_events(Gdk.EventMask.ALL_EVENTS_MASK)
68                self.app_indicator.set_menu(self.menu)
69               
70
71                self.populate_menu()
72                self.start_inotify()
73
74                self.is_alive()
75
76                if self.updatedInfo:
77                        self.fcache=Gio.File.new_for_path("/var/cache/apt/pkgcache.bin")
78                        self.mcache=self.fcache.monitor_file(Gio.FileMonitorFlags.NONE,None)
79                        self.mcache.connect("changed",self.on_cache_changed)
80
81                GLib.timeout_add_seconds(5, self.worker)
82
83        #def __init__   
84                       
85
86        def worker(self):
87                """ Timeout thread """
88               
89               
90               
91                if(self.is_working==False):
92                        if self.updatedInfo:
93                                if(self.is_cache_updated==True):
94                                        if not self.remoteUpdateInfo:
95                                                self.upgrade()
96                                                self.last_check=0
97                                else:
98                                        self.last_check+=5
99                                        if(self.last_check>self.FREQUENCY):
100                                                if not self.remoteUpdateInfo:
101                                                        self.last_check=0
102                                                        self.upgrade() 
103
104                        if self.lliurexUp_running==True and not self.remoteUpdateInfo: 
105                                self.is_alive()
106                                       
107                return True     
108
109        #def worker     
110
111        def get_flavour(self):
112
113                cmd='lliurex-version -v'
114                p=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
115                result=p.communicate()
116                self.flavours = [ x.strip() for x in result[0].split(',') ]     
117
118        #def get_flavour                       
119       
120
121        def get_user_group(self):
122               
123                #check if the user is in the enabled group, otherwise the indicator is closed
124                user=os.environ["USER"]
125                self.group_found=False
126               
127                for g in grp.getgrall():
128                        if(g.gr_name in UpgradeIndicator.GROUPS):
129                                for member in g.gr_mem:
130                                        if(member==user):
131                                                self.group_found=True
132                                                break
133
134        #def get_user_group                                     
135                                       
136        def populate_menu(self):
137       
138
139                label_item=("LliureX-Up is being executed")
140                item=Gtk.ImageMenuItem()
141                item.set_label(label_item)
142                img=Gtk.Image.new_from_file(SP1)
143                item.set_image(img)
144                item.set_always_show_image(True)
145                item.remote=True
146                self.menu.insert(item,0)
147
148                if self.group_found and 'client' not in self.flavours:
149                        self.updatedInfo=True
150                        item=Gtk.ImageMenuItem()
151                        label_item=("Update the system now")
152                        item.set_label(label_item)
153                        img=Gtk.Image()
154                        img.set_from_stock(Gtk.STOCK_PREFERENCES,Gtk.IconSize.MENU)
155                        item.set_image(img)
156                        item.set_always_show_image(True)
157                        item.connect("activate",self.open_gui)
158                        item.remote=False
159                        self.menu.insert(item,1)
160
161        #def populate_menu             
162
163        def start_inotify(self):
164
165                t=threading.Thread(target=self._inotify)
166                t.daemon=True
167                t.start()               
168
169        #def start_inotify     
170
171        def _inotify(self):
172               
173               
174                wm=WatchManager()
175                mask=pyinotify.IN_CREATE
176                       
177                class Process_handler(ProcessEvent):
178                               
179                        def __init__(self,main):
180                               
181                                self.main=main
182                               
183                        def process_IN_CREATE(self,event):
184
185                                if os.path.expanduser(event.pathname)=='/var/run/lliurexUp.lock':
186                                        self.main.lliurexUp_running=True
187                               
188       
189                notifier=Notifier(wm,Process_handler(self))
190                wdd=wm.add_watch(UpgradeIndicator.WATCH_DIR,mask,rec=True)
191                       
192                while True:
193                        try:
194                                       
195                                notifier.process_events()
196                                if notifier.check_events():
197                                        notifier.read_events()
198                               
199                        except Exception as e:
200                                notifier.stop()
201                                       
202                return False   
203
204        #def _inotify   
205
206        def remote_execute(self):
207
208                cont=0
209                remote_pts=[]
210                remote_executing=False
211
212                cmd='who | grep -v "(:0"'
213                p=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
214                result=p.communicate()
215                remote_users=[ x.strip() for x in result[0].split('\n') ]
216                remote_users.pop()
217
218                for item in remote_users:
219                        tmp=re.search('(pts/\w)',item)
220                        try:
221                                remote_pts.append(tmp.group(1))
222                        except Exception as e:
223                                pass
224
225
226                cmd='ps -ef | grep "lliurex-upgrade"'
227                p=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
228                result=p.communicate()
229                isrunning= [ x.strip() for x in result[0].split('\n') ]
230                isrunning.pop()
231
232
233                for item in isrunning:
234                        if '?' in item:
235                                cont=cont+1
236                        for t in remote_pts:
237                                if t in item:
238                                        cont=cont+1
239
240                if cont>0:
241                        remote_executing=True
242
243                return remote_executing                         
244
245        #def remote_execute     
246
247        def is_alive(self):
248
249                if os.path.exists(TARGET_FILE):
250                        check=self.remote_execute()
251                        if check:
252                                self.is_working=True
253                                self.remoteUpdateInfo=True
254                                self.menu.show_all()
255                                for item in self.menu.get_children():
256                                        if not item.remote:
257                                                item.set_visible(False)
258                                self.app_indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
259                                GLib.timeout_add(100,self.check_status)
260                        else:
261                                self.app_indicator.set_status(appindicator.IndicatorStatus.PASSIVE)
262                               
263                return
264
265        #def is_alive   
266               
267        def check_status(self):
268
269                if os.path.exists(TARGET_FILE):
270                        self.spinner_sync()
271                        for item in self.menu.get_children():
272                                if item.remote:
273                                #item=self.menu.get_children()[0]
274                                        item.set_image(self.sp_img)
275                                        self.sp_cont=self.sp_cont+1     
276                        return True
277                       
278                else:
279                        img=Gtk.Image.new_from_file(SP1)
280                        for item in self.menu.get_children():
281                                if item.remote:
282                                        item.set_image(img)
283                       
284                        message="Process has ended"
285                        self.show_message(message)
286                        self.app_indicator.set_status(appindicator.IndicatorStatus.PASSIVE)
287                        time.sleep(2)
288                        self.remoteUpdateInfo=False
289                        self.lliurexUp_running=False
290                        self.is_working=False
291               
292                return         
293
294        #def check_status       
295       
296        def spinner_sync(self):
297       
298                if self.sp_cont>50:
299                        self.sp_cont=0
300                       
301                if self.sp_cont==0:
302                        img=Gtk.Image.new_from_file(SP1)
303                        self.sp_img=img
304                elif self.sp_cont==10:
305                        img=Gtk.Image.new_from_file(SP2)
306                        self.sp_img=img                 
307                elif self.sp_cont==20:
308                        img=Gtk.Image.new_from_file(SP3)
309                        self.sp_img=img
310                elif self.sp_cont==30:
311                        img=Gtk.Image.new_from_file(SP4)
312                        self.sp_img=img
313                elif self.sp_cont==40:
314                        img=Gtk.Image.new_from_file(SP5)
315                        self.sp_img=img
316                               
317        #def spinner_sync               
318
319
320
321        def on_cache_changed(self,monitor,file,other,type):
322                """Apt cache notification event"""
323       
324               
325                if(type==Gio.FileMonitorEvent.CHANGES_DONE_HINT and self.last_check>120): #ignore cache updates at intervals smaller than 2 minutes
326                        self.is_cache_updated=True
327                       
328       
329        #def on_cache_changed
330
331
332        def upgrade(self):
333                """
334                Performs an upgrade simulation.
335                Cache will be updated if needed.
336                """
337       
338                self.is_working=True
339
340               
341                apt_client=client.AptClient()
342               
343                if(self.is_cache_updated==False):
344                        apt_client.update_cache(wait=True)
345                        self.is_cache_updated=True
346                       
347                transaction=apt_client.upgrade_system()
348
349                transaction.simulate()
350                #this sync is needed in order to update transaction properties after simulation
351                #credits go to Lubuntu Team as this is completly undocumented :)
352                transaction.sync()
353
354
355                #transaction dependencies []
356                # install reinstall remove purge upgrade downgrade
357               
358                packages=[]
359               
360                for d in transaction.dependencies:
361                        for p in d:
362                                packages.append(d)
363               
364               
365               
366                if(len(packages)>0):
367                        self.menu.show_all()
368                        for item in self.menu.get_children():
369                                if item.remote:
370                                                item.set_visible(False)
371
372                        self.app_indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
373
374                        message=("There are new packages ready to be updated or installed")
375                        self.show_message(message)
376                                               
377               
378                self.is_working=False
379                self.is_cache_updated=False
380       
381        #def upgrade
382
383        def show_message(self,message):
384
385                p=multiprocessing.Process(target=self._show_message,args=(message,))
386                p.daemon=True
387                p.start()
388
389        #def show_message
390
391        def _show_message(self,message):
392               
393                notify2.init(UpgradeIndicator.ID)
394
395                n=notify2.Notification("LliureX-Up",message,"lliurex-up")
396                n.show()
397
398                return
399
400        #def _show_message     
401
402        def open_gui(self,widget):
403               
404                if not os.path.exists(TARGET_FILE):
405                        self.app_indicator.set_status(appindicator.IndicatorStatus.PASSIVE)
406                        cmd='gksu lliurex-up' + "&"
407                        os.system(cmd)
408
409        #def open_gui           
410
411        def quit(self):
412
413                Gtk.main_quit() 
414
415        #def quit       
416       
417#class UpgradeIndicator
418
419if __name__=="__main__":
420
421
422        mode=0
423        args=sys.argv[1:]
424
425        for arg in args:
426                if (arg=="--remote"):
427                        mode=1
428               
429                               
430        lliurexup=UpgradeIndicator("lliurex-up")
431        GObject.threads_init()
432        Gtk.main()
Note: See TracBrowser for help on using the repository browser.