- bump version (0.7)
[opensuse:osc.git] / osc / fetch.py
1 #!/usr/bin/python
2
3 # Copyright (C) 2006 Peter Poeml.  All rights reserved.
4 # This program is free software; it may be used, copied, modified
5 # and distributed under the terms of the GNU General Public Licence,
6 # either version 2, or (at your option) any later version.
7
8 import sys, os
9 import urllib2
10 from urlgrabber.grabber import URLGrabber, URLGrabError
11 from urlgrabber.mirror import MirrorGroup
12 try:
13     from meter import TextMeter
14 except:
15     TextMeter = None
16
17
18 def join_url(self, base_url, rel_url):
19     """to override _join_url of MirrorGroup, because we want to
20     pass full URLs instead of base URL where relative_url is added later...
21     IOW, we make MirrorGroup ignore relative_url""" 
22     return base_url
23
24
25 class Fetcher:
26     def __init__(self, cachedir = '/tmp', auth_dict = {}, urllist = []):
27
28         __version__ = '0.1'
29         __user_agent__ = 'osbuild/%s' % __version__
30
31         # set up progress bar callback
32         if sys.stdout.isatty() and TextMeter:
33             self.progress_obj = TextMeter(fo=sys.stdout)
34         else:
35             self.progress_obj = None
36
37
38         self.cachedir = cachedir
39         self.urllist = urllist
40
41         passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
42         for host in auth_dict.keys():
43             passmgr.add_password(None, host, auth_dict[host]['user'], auth_dict[host]['pass'])
44         authhandler = urllib2.HTTPBasicAuthHandler(passmgr)
45         self.gr = URLGrabber(user_agent=__user_agent__,
46                             keepalive=1,
47                             opener = urllib2.build_opener(authhandler),
48                             progress_obj=self.progress_obj,
49                             failure_callback=(self.failureReport,(),{}),
50                             )
51
52
53     def failureReport(self, errobj):
54         """failure output for failovers from urlgrabber"""
55
56         #log(0, '%s: %s' % (errobj.url, str(errobj.exception)))
57         #log(0, 'Trying other mirror.')
58         print 'Trying upstream server for %s (%s), since it is not on %s.' \
59                 % (self.curpac, self.curpac.project, errobj.url.split('/')[2])
60         raise errobj.exception
61
62
63     def fetch(self, pac):
64         # for use by the failure callback
65         self.curpac = pac
66
67         MirrorGroup._join_url = join_url
68         mg = MirrorGroup(self.gr, pac.urllist)
69
70         try:
71             # it returns the filename
72             ret = mg.urlgrab(pac.filename, 
73                              filename=pac.fullfilename, 
74                              text = '(%s) %s' %(pac.project, pac.filename))
75
76         except URLGrabError, e:
77             print
78             print >>sys.stderr, 'Error:', e.strerror
79             print >>sys.stderr, 'Failed to retrieve %s from the following locations (in order):' % pac.filename
80             print >>sys.stderr, '\n'.join(pac.urllist)
81
82             sys.exit(1)
83         
84
85     def dirSetup(self, pac):
86         dir = os.path.join(self.cachedir, pac.localdir)
87         if not os.path.exists(dir):
88             os.makedirs(dir, mode=0755)
89
90
91     def run(self, buildinfo):
92         for i in buildinfo.deps:
93             i.makeurls(self.cachedir, self.urllist)
94
95             if os.path.exists(os.path.join(i.localdir, i.fullfilename)):
96                 #print 'cached:', i.fullfilename
97                 pass
98             else:
99                 self.dirSetup(i)
100
101                 try:
102                     # if there isn't a progress bar, there is no output at all
103                     if not self.progress_obj:
104                         print '(%s) %s' % (i.project, i.filename)
105                     self.fetch(i)
106
107                 except KeyboardInterrupt:
108                     print 'Cancelled by user (ctrl-c)'
109                     print 'Exiting.'
110                     if os.path.exists(i.fullfilename):
111                         print 'Cleaning up incomplete file', i.fullfilename
112                         os.unlink(i.fullfilename)
113                     sys.exit(0)
114
115
116
117 def verify_pacs(pac_list):
118     """Take a list of rpm filenames and run rpm -K on them. 
119
120        In case of failure, exit.
121
122        Check all packages in one go, since this takes only 6 seconds on my Athlon 700
123        instead of 20 when calling 'rpm -K' for each of them.
124        """
125
126
127
128     # we can use os.popen4 because we don't care about the return value.
129     # we check the output anyway, and rpm always writes to stdout.
130     (i, o) = os.popen4(['/bin/rpm', '-K'] + pac_list)
131
132     i.close()
133
134     for line in o.readlines():
135
136         if not 'OK' in line:
137             print 
138             print >>sys.stderr, 'The following package could not be verified:'
139             print >>sys.stderr, line
140             sys.exit(1)
141
142         if 'NOT OK' in line:
143             print 
144             print >>sys.stderr, 'The following package could not be verified:'
145             print >>sys.stderr, line
146
147             if 'MISSING KEYS' in line:
148                 missing_key = line.split('#')[-1].split(')')[0]
149
150                 print >>sys.stderr, """
151 - If the key is missing, install it first.
152   For example, do the following as root:
153     gpg --keyserver pgp.mit.edu --recv-keys %s
154     gpg --armor --export %s > keyfile
155     rpm --import keyfile
156
157   Then, just start the build again.
158 """ %(missing_key, missing_key)
159
160             else:
161                 print >>sys.stderr, """
162 - If the signature is wrong, you may try deleting the package manually
163   and re-run this program, so it is fetched again.
164 """
165
166             sys.exit(1)
167
168