2 Integrates download callbacks with an external mainloop.
3 While things are being downloaded, Zero Install returns control to your program.
4 Your mainloop is responsible for monitoring the state of the downloads and notifying
5 Zero Install when they are complete.
7 To do this, you supply a L{Handler} to the L{policy}.
10 # Copyright (C) 2006, Thomas Leonard
11 # See the README file for details, or visit http://0install.net.
14 from logging
import debug
, info
, warn
16 from zeroinstall
.support
import tasks
17 from zeroinstall
.injector
import model
, download
18 from zeroinstall
.injector
.iface_cache
import iface_cache
20 class Handler(object):
22 This implementation of the handler interface uses the GLib mainloop.
24 @ivar monitored_downloads: dict of downloads in progress
25 @type monitored_downloads: {URL: (error_stream, L{download.Download})}
28 __slots__
= ['monitored_downloads', '_loop', '_loop_errors']
30 def __init__(self
, mainloop
= None):
31 self
.monitored_downloads
= {}
33 self
._loop
_errors
= None
35 def monitor_download(self
, dl
):
36 """Called when a new L{download} is started.
37 This is mainly used by the GUI to display the progress bar."""
39 self
.monitored_downloads
[dl
.url
] = dl
40 self
.downloads_changed()
44 del self
.monitored_downloads
[dl
.url
]
45 self
.downloads_changed()
46 monitor
= tasks
.Task(download_done(), "download monitor")
48 def downloads_changed(self
):
49 # This is just for the GUI to override
52 def wait_for_blocker(self
, blocker
):
53 if not blocker
.happened
:
59 quit
= tasks
.Task(quitter(), "quitter")
61 assert self
._loop
is None # Avoid recursion
62 self
._loop
= gobject
.MainLoop(gobject
.main_context_default())
64 debug("Entering mainloop, waiting for %s", blocker
)
69 assert blocker
.happened
, "Someone quit the main loop!"
73 def get_download(self
, url
, force
= False):
74 """Return the Download object currently downloading 'url'.
75 If no download for this URL has been started, start one now (and
77 If the download failed and force is False, return it anyway.
78 If force is True, abort any current or failed download and start
80 @rtype: L{download.Download}
83 e
, dl
= self
.monitored_downloads
[url
]
88 dl
= download
.Download(url
)
89 self
.monitor_download(dl
)
92 def confirm_trust_keys(self
, interface
, sigs
, iface_xml
):
93 """We don't trust any of the signatures yet. Ask the user.
94 When done update the L{trust} database, and then call L{trust.TrustDB.notify}.
95 @arg interface: the interface being updated
96 @arg sigs: a list of signatures (from L{gpg.check_stream})
97 @arg iface_xml: the downloaded data (not yet trusted)
98 @return: a blocker, if confirmation will happen asynchronously, or None
100 from zeroinstall
.injector
import trust
, gpg
102 valid_sigs
= [s
for s
in sigs
if isinstance(s
, gpg
.ValidSig
)]
104 raise model
.SafeException('No valid signatures found. Signatures:' +
105 ''.join(['\n- ' + str(s
) for s
in sigs
]))
107 domain
= trust
.domain_from_url(interface
.uri
)
109 print "\nInterface:", interface
.uri
110 print "The interface is correctly signed with the following keys:"
114 if len(valid_sigs
) == 1:
115 print "Do you want to trust this key to sign feeds from '%s'?" % domain
117 print "Do you want to trust all of these keys to sign feeds from '%s'?" % domain
119 i
= raw_input("Trust [Y/N] ")
122 raise model
.SafeException('Not signed with a trusted key')
125 for key
in valid_sigs
:
126 print "Trusting", key
.fingerprint
, "for", domain
127 trust
.trust_db
.trust_key(key
.fingerprint
, domain
)
129 trust
.trust_db
.notify()
131 def report_error(self
, exception
):
132 """Report an exception to the user.
133 @param exception: the exception to report
134 @type exception: L{SafeException}
136 if self
._loop
_errors
is None:
137 warn("%s", exception
)
139 self
._loop
_errors
.append(str(exception
))
140 info("%s", exception
) # (will get reported later)