3 from optparse
import OptionParser
4 import sys
, shutil
, tempfile
, urlparse
5 import urllib2
, os
, httplib
7 from logging
import info
9 from zeroinstall
import SafeException
10 from zeroinstall
.injector
import model
, gpg
, reader
14 parser
= OptionParser(usage
="usage: %prog [options] feed.xml")
15 parser
.add_option("-v", "--verbose", help="more verbose output", action
='count')
16 parser
.add_option("-V", "--version", help="display version information", action
='store_true')
18 (options
, args
) = parser
.parse_args()
21 print "FeedLint (zero-install) " + version
22 print "Copyright (C) 2007 Thomas Leonard"
23 print "This program comes with ABSOLUTELY NO WARRANTY,"
24 print "to the extent permitted by law."
25 print "You may redistribute copies of this program"
26 print "under the terms of the GNU General Public License."
27 print "For more information about these matters, see the file named COPYING."
31 logger
= logging
.getLogger()
32 if options
.verbose
== 1:
33 logger
.setLevel(logging
.INFO
)
35 logger
.setLevel(logging
.DEBUG
)
44 to_check
= [model
.canonical_iface_uri(a
) for a
in args
]
45 except SafeException
, ex
:
46 if options
.verbose
: raise
47 print >>sys
.stderr
, ex
50 def check_key(feed
, fingerprint
):
51 for line
in os
.popen('gpg --with-colons --list-keys %s' % s
.fingerprint
):
52 if line
.startswith('pub:'):
53 key_id
= line
.split(':')[4]
56 raise SafeException('Failed to find key with fingerprint %s on your keyring' % fingerprint
)
58 key_url
= urlparse
.urljoin(feed
, '%s.gpg' % key_id
)
59 print "Checking", key_url
61 if key_url
in checked
:
62 info("(already checked key URL)")
64 urllib2
.urlopen(key_url
).read()
67 def check_source(source
):
68 if hasattr(source
, 'url'):
69 print " Checking archive", source
.url
70 address
= urlparse
.urlparse(source
.url
)
71 http
= httplib
.HTTPConnection(address
.netloc
, address
.port
or 80)
72 http
.request('HEAD', source
.url
)
73 response
= http
.getresponse()
75 if response
.status
!= 200:
76 raise SafeException("HTTP error: got status code %s" % response
.status
)
77 actual_size
= int(response
.getheader('Content-Length'))
78 if actual_size
!= source
.size
:
79 raise SafeException("Expected archive to have a size of %d, but server says it is %d",
80 source
.size
, actual_size
)
84 elif hasattr(source
, 'steps'):
85 for step
in source
.steps
:
93 info("Already checked feed %s", feed
)
98 print "Checking", feed
101 tmp
= tempfile
.TemporaryFile(prefix
= 'feedlint-')
103 stream
= urllib2
.urlopen(feed
)
104 shutil
.copyfileobj(stream
, tmp
)
105 data
, sigs
= gpg
.check_stream(tmp
)
108 if isinstance(s
, gpg
.ValidSig
):
109 check_key(feed
, s
.fingerprint
)
111 raise SafeException("Can't check sig: %s" % s
)
113 feed_tmp
= tempfile
.NamedTemporaryFile(prefix
= 'feedlint-')
115 shutil
.copyfileobj(data
, feed_tmp
)
117 iface
= model
.Interface(feed
)
118 reader
.update(iface
, feed_tmp
.name
)
120 for f
in iface
.feeds
:
121 info("Will check feed %s", f
.uri
)
122 to_check
.append(f
.uri
)
128 for impl
in iface
.implementations
.values():
129 for r
in impl
.dependencies
.values():
130 if r
.interface
not in checked
:
131 info("Will check dependency %s", r
)
132 to_check
.append(r
.interface
)
133 if hasattr(impl
, 'download_sources'):
134 for source
in impl
.download_sources
:
135 pass #check_source(source)
138 except urllib2
.HTTPError
, ex
:
139 print >>sys
.stderr
, ex
141 except SafeException
, ex
:
142 if options
.verbose
: raise
143 print >>sys
.stderr
, ex
149 print "\nERRORS FOUND:", n_errors