2 Integrates download callbacks with an external mainloop.
5 # Copyright (C) 2006, Thomas Leonard
6 # See the README file for details, or visit http://0install.net.
9 from logging
import debug
, info
, warn
11 from zeroinstall
.injector
import model
, download
12 from zeroinstall
.injector
.iface_cache
import iface_cache
14 class Handler(object):
16 Integrates download callbacks with an external mainloop.
17 While things are being downloaded, Zero Install returns control to your program.
18 Your mainloop is responsible for monitoring the state of the downloads and notifying
19 Zero Install when they are complete.
21 To do this, you supply a L{Handler} to the L{policy}. To integrate with your own
22 mainloop, you can either subclass or replace this.
25 __slots__
= ['monitored_downloads']
27 self
.monitored_downloads
= {} # URL -> (error_stream, Download)
29 def monitor_download(self
, dl
):
30 """Called when a new L{download} is started.
31 Call L{download.Download.start} to start the download and get the error
32 stream, and then call L{download.Download.error_stream_data} whenever
33 you read any data from it, including nothing (end-of-file), which
34 indicates that the download is finished."""
35 error_stream
= dl
.start()
36 self
.monitored_downloads
[dl
.url
] = (error_stream
, dl
)
38 def wait_for_downloads(self
):
39 """Monitor all downloads, waiting until they are complete. This is suitable
40 for use by non-interactive programs."""
41 while self
.monitored_downloads
:
42 info("Currently downloading:")
43 for url
in self
.monitored_downloads
:
46 for e
, dl
in self
.monitored_downloads
.values():
49 dl
.error_stream_data(errors
)
52 del self
.monitored_downloads
[dl
.url
]
54 dl
.error_stream_closed()
56 def get_download(self
, url
, force
= False):
57 """Return the Download object currently downloading 'url'.
58 If no download for this URL has been started, start one now (and
60 If the download failed and force is False, return it anyway.
61 If force is True, abort any current or failed download and start
63 @rtype: L{download.Download}
66 e
, dl
= self
.monitored_downloads
[url
]
71 dl
= download
.Download(url
)
72 self
.monitor_download(dl
)
75 def confirm_trust_keys(self
, interface
, sigs
, iface_xml
):
76 """We don't trust any of the signatures yet. Ask the user.
77 When done update the L{trust} database, and then call L{trust.TrustDB.notify}.
78 @arg interface: the interface being updated
79 @arg sigs: a list of signatures (from L{gpg.check_stream})
80 @arg iface_xml: the downloaded data (not yet trusted)
82 from zeroinstall
.injector
import trust
, gpg
84 valid_sigs
= [s
for s
in sigs
if isinstance(s
, gpg
.ValidSig
)]
86 raise model
.SafeException('No valid signatures found. Signatures:' +
87 ''.join(['\n- ' + str(s
) for s
in sigs
]))
89 domain
= trust
.domain_from_url(interface
.uri
)
91 print "\nInterface:", interface
.uri
92 print "The interface is correctly signed with the following keys:"
96 if len(valid_sigs
) == 1:
97 print "Do you want to trust this key to sign feeds from '%s'?" % domain
99 print "Do you want to trust all of these keys to sign feeds from '%s'?" % domain
101 i
= raw_input("Trust [Y/N] ")
104 raise model
.SafeException('Not signed with a trusted key')
107 for key
in valid_sigs
:
108 print "Trusting", key
.fingerprint
, "for", domain
109 trust
.trust_db
.trust_key(key
.fingerprint
, domain
)
111 trust
.trust_db
.notify()
113 def report_error(self
, exception
):
114 """Report an exception to the user.
115 @param exception: the exception to report
116 @type exception: L{SafeException}
118 warn("%s", exception
)