2 Check for updates in a background process. If we can start a program immediately, but some of our information
3 is rather old (longer that the freshness threshold) then we run it anyway, and check for updates using a new
4 process that runs quietly in the background.
6 This avoids the need to annoy people with a 'checking for updates' box when they're trying to run things.
10 from logging
import info
11 from zeroinstall
.injector
.iface_cache
import iface_cache
12 from zeroinstall
.injector
import handler
14 # Copyright (C) 2007, Thomas Leonard
15 # See the README file for details, or visit http://0install.net.
21 session_bus
= dbus
.SessionBus()
23 remote_object
= session_bus
.get_object('org.freedesktop.Notifications',
24 '/org/freedesktop/Notifications')
26 notification_service
= dbus
.Interface(remote_object
,
27 'org.freedesktop.Notifications')
29 # The Python bindings insist on printing a pointless introspection
30 # warning to stderr if the service is missing. Force it to be done
31 # now so we can skip it
32 old_stderr
= sys
.stderr
35 notification_service
.GetCapabilities()
37 sys
.stderr
= old_stderr
39 #notification_service.connect_to_signal('NotificationClosed', _NotificationClosed)
40 #notification_service.connect_to_signal('ActionInvoked', _ActionInvoked)
42 have_notifications
= True
44 info("Failed to import D-BUS bindings: %s", ex
)
45 have_notifications
= False
51 def notify(title
, message
, timeout
= 0, actions
= []):
52 if not have_notifications
:
53 info('%s: %s', title
, message
)
61 hints
['urgency'] = dbus
.types
.Byte(NORMAL
)
63 hints
['urgency'] = dbus
.types
.Byte(LOW
)
65 notification_service
.Notify('Zero Install',
74 def _exec_gui(uri
, *args
):
75 os
.execvp('0launch', ['0launch', '--download-only', '--gui'] + list(args
) + [uri
])
77 class BackgroundHandler(handler
.Handler
):
78 def __init__(self
, title
):
79 handler
.Handler
.__init
__(self
)
82 def confirm_trust_keys(self
, interface
, sigs
, iface_xml
):
83 notify("Zero Install", "Can't update interface; signature not yet trusted. Running GUI...", timeout
= 2)
84 _exec_gui(interface
.uri
, '--refresh')
86 def report_error(self
, exception
):
87 notify("Zero Install", "Error updating %s: %s" % (title
, str(exception
)))
90 """Fork a detached grandchild.
91 @return: True if we are the original."""
94 pid
, status
= os
.waitpid(child
, 0)
98 grandchild
= os
.fork()
100 os
._exit
(0) # Parent's waitpid returns and grandchild continues
104 def _check_for_updates(policy
, verbose
):
105 root_iface
= iface_cache
.get_interface(policy
.root
).get_name()
106 info("Checking for updates to '%s' in a background process", root_iface
)
108 notify("Zero Install", "Checking for updates to '%s'..." % root_iface
, timeout
= 1)
110 policy
.handler
= BackgroundHandler(root_iface
)
112 policy
.handler
.wait_for_downloads()
113 # We could even download the archives here, but for now just
114 # update the interfaces.
116 if not policy
.need_download():
118 notify("Zero Install", "No updates to download.", timeout
= 1)
121 if not have_notifications
:
122 notify("Zero Install", "Updates ready to download for '%s'." % root_iface
)
126 ctx
= gobject
.main_context_default()
127 loop
= gobject
.MainLoop(ctx
)
129 def _NotificationClosed(*unused
):
132 def _ActionInvoked(nid
, action
):
133 if action
== 'download':
134 _exec_gui(policy
.root
)
137 notification_service
.connect_to_signal('NotificationClosed', _NotificationClosed
)
138 notification_service
.connect_to_signal('ActionInvoked', _ActionInvoked
)
140 notify("Zero Install", "Updates ready to download for '%s'." % root_iface
,
141 actions
= ['download', 'Download'])
145 def spawn_background_update(policy
, verbose
):
146 # Mark all feeds as being updated. Do this before forking, so that if someone is
147 # running lots of 0launch commands in series on the same program we don't start
148 # huge numbers of processes.
150 from zeroinstall
.injector
import writer
151 now
= int(time
.time())
152 for x
in policy
.implementation
:
153 x
.last_check_attempt
= now
154 writer
.save_interface(x
)
156 for f
in policy
.usable_feeds(x
):
157 feed_iface
= iface_cache
.get_interface(f
.uri
)
158 feed_iface
.last_check_attempt
= now
159 writer
.save_interface(feed_iface
)
166 _check_for_updates(policy
, verbose
)
171 traceback
.print_exc()