2009-03-02 15:03:06 +01:00
|
|
|
# Copyright (C) 2006 Novell Inc. All rights reserved.
|
2006-07-14 19:39:46 +02:00
|
|
|
# This program is free software; it may be used, copied, modified
|
|
|
|
# and distributed under the terms of the GNU General Public Licence,
|
|
|
|
# either version 2, or (at your option) any later version.
|
|
|
|
|
|
|
|
import sys, os
|
|
|
|
import urllib2
|
|
|
|
from urlgrabber.grabber import URLGrabber, URLGrabError
|
|
|
|
from urlgrabber.mirror import MirrorGroup
|
2009-06-16 14:15:41 +02:00
|
|
|
from core import data_from_rpm
|
2006-07-14 19:39:46 +02:00
|
|
|
try:
|
|
|
|
from meter import TextMeter
|
|
|
|
except:
|
|
|
|
TextMeter = None
|
|
|
|
|
|
|
|
|
|
|
|
def join_url(self, base_url, rel_url):
|
|
|
|
"""to override _join_url of MirrorGroup, because we want to
|
|
|
|
pass full URLs instead of base URL where relative_url is added later...
|
|
|
|
IOW, we make MirrorGroup ignore relative_url"""
|
|
|
|
return base_url
|
|
|
|
|
|
|
|
|
|
|
|
class Fetcher:
|
2009-02-28 16:56:32 +01:00
|
|
|
def __init__(self, cachedir = '/tmp', api_host_options = {}, urllist = [], http_debug = False, cookiejar = None):
|
2006-07-14 19:39:46 +02:00
|
|
|
|
|
|
|
__version__ = '0.1'
|
|
|
|
__user_agent__ = 'osbuild/%s' % __version__
|
|
|
|
|
|
|
|
# set up progress bar callback
|
|
|
|
if sys.stdout.isatty() and TextMeter:
|
|
|
|
self.progress_obj = TextMeter(fo=sys.stdout)
|
|
|
|
else:
|
|
|
|
self.progress_obj = None
|
|
|
|
|
|
|
|
|
|
|
|
self.cachedir = cachedir
|
|
|
|
self.urllist = urllist
|
2007-09-10 14:22:13 +02:00
|
|
|
self.http_debug = http_debug
|
2006-07-14 19:39:46 +02:00
|
|
|
|
|
|
|
passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
|
2008-08-20 11:45:49 +02:00
|
|
|
for host in api_host_options.keys():
|
|
|
|
passmgr.add_password(None, host, api_host_options[host]['user'], api_host_options[host]['pass'])
|
2009-02-28 16:56:32 +01:00
|
|
|
openers = (urllib2.HTTPBasicAuthHandler(passmgr), )
|
|
|
|
if cookiejar:
|
|
|
|
openers += (urllib2.HTTPCookieProcessor(cookiejar), )
|
2006-07-14 19:39:46 +02:00
|
|
|
self.gr = URLGrabber(user_agent=__user_agent__,
|
|
|
|
keepalive=1,
|
2009-02-28 16:56:32 +01:00
|
|
|
opener = urllib2.build_opener(*openers),
|
2006-07-14 19:39:46 +02:00
|
|
|
progress_obj=self.progress_obj,
|
|
|
|
failure_callback=(self.failureReport,(),{}),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def failureReport(self, errobj):
|
|
|
|
"""failure output for failovers from urlgrabber"""
|
|
|
|
|
|
|
|
#log(0, '%s: %s' % (errobj.url, str(errobj.exception)))
|
|
|
|
#log(0, 'Trying other mirror.')
|
2009-04-27 09:32:00 +02:00
|
|
|
print 'Trying openSUSE Build Service server for %s (%s), since it is not on %s.' \
|
2006-07-14 19:39:46 +02:00
|
|
|
% (self.curpac, self.curpac.project, errobj.url.split('/')[2])
|
|
|
|
raise errobj.exception
|
|
|
|
|
|
|
|
|
|
|
|
def fetch(self, pac):
|
|
|
|
# for use by the failure callback
|
|
|
|
self.curpac = pac
|
|
|
|
|
|
|
|
MirrorGroup._join_url = join_url
|
|
|
|
mg = MirrorGroup(self.gr, pac.urllist)
|
|
|
|
|
2007-09-10 14:22:13 +02:00
|
|
|
if self.http_debug:
|
|
|
|
print
|
|
|
|
print 'URLs to try for package \'%s\':' % pac
|
|
|
|
print '\n'.join(pac.urllist)
|
|
|
|
print
|
|
|
|
|
2006-07-14 19:39:46 +02:00
|
|
|
try:
|
|
|
|
# it returns the filename
|
|
|
|
ret = mg.urlgrab(pac.filename,
|
2009-07-15 21:48:16 +02:00
|
|
|
filename = pac.fullpartname,
|
2006-07-14 19:39:46 +02:00
|
|
|
text = '(%s) %s' %(pac.project, pac.filename))
|
|
|
|
|
|
|
|
except URLGrabError, e:
|
|
|
|
print
|
|
|
|
print >>sys.stderr, 'Error:', e.strerror
|
|
|
|
print >>sys.stderr, 'Failed to retrieve %s from the following locations (in order):' % pac.filename
|
|
|
|
print >>sys.stderr, '\n'.join(pac.urllist)
|
|
|
|
|
|
|
|
sys.exit(1)
|
2009-06-16 14:15:41 +02:00
|
|
|
|
2009-07-15 21:48:16 +02:00
|
|
|
if pac.partname.endswith('.rpm.part'):
|
|
|
|
rpm_data = data_from_rpm(pac.fullpartname, 'Name:', 'Version:', 'Release:', 'Arch:', 'SourceRPM:', 'NoSource:', 'NoPatch:')
|
2009-06-16 14:15:41 +02:00
|
|
|
if rpm_data:
|
|
|
|
arch = rpm_data['Arch:']
|
|
|
|
if not rpm_data['SourceRPM:']:
|
|
|
|
if rpm_data['NoSource:'] or rpm_data['NoPatch:']:
|
|
|
|
arch = "nosrc"
|
|
|
|
else:
|
|
|
|
arch = "src"
|
|
|
|
canonname = "%s-%s-%s.%s.rpm" % (rpm_data['Name:'], rpm_data['Version:'], rpm_data['Release:'], arch)
|
|
|
|
head, tail = os.path.split(pac.fullfilename)
|
|
|
|
pac.filename = canonname
|
|
|
|
pac.fullfilename = os.path.join(head, canonname)
|
|
|
|
|
2009-07-15 21:48:16 +02:00
|
|
|
os.rename(pac.fullpartname, pac.fullfilename);
|
2006-07-14 19:39:46 +02:00
|
|
|
|
|
|
|
def dirSetup(self, pac):
|
|
|
|
dir = os.path.join(self.cachedir, pac.localdir)
|
|
|
|
if not os.path.exists(dir):
|
2006-07-14 20:23:20 +02:00
|
|
|
try:
|
|
|
|
os.makedirs(dir, mode=0755)
|
|
|
|
except OSError, e:
|
2007-04-25 23:10:49 +02:00
|
|
|
print >>sys.stderr, 'packagecachedir is not writable for you?'
|
|
|
|
print >>sys.stderr, e
|
2006-07-14 20:23:20 +02:00
|
|
|
sys.exit(1)
|
2006-07-14 19:39:46 +02:00
|
|
|
|
|
|
|
|
|
|
|
def run(self, buildinfo):
|
|
|
|
for i in buildinfo.deps:
|
|
|
|
i.makeurls(self.cachedir, self.urllist)
|
|
|
|
|
|
|
|
if os.path.exists(os.path.join(i.localdir, i.fullfilename)):
|
|
|
|
#print 'cached:', i.fullfilename
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
self.dirSetup(i)
|
|
|
|
try:
|
|
|
|
# if there isn't a progress bar, there is no output at all
|
|
|
|
if not self.progress_obj:
|
|
|
|
print '(%s) %s' % (i.project, i.filename)
|
|
|
|
self.fetch(i)
|
|
|
|
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
print 'Cancelled by user (ctrl-c)'
|
|
|
|
print 'Exiting.'
|
2009-07-15 21:48:16 +02:00
|
|
|
if os.path.exists(i.fullpartname):
|
|
|
|
print 'Cleaning up incomplete file', i.fullpartname
|
|
|
|
os.unlink(i.fullpartname)
|
2006-07-14 19:39:46 +02:00
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def verify_pacs(pac_list):
|
|
|
|
"""Take a list of rpm filenames and run rpm -K on them.
|
|
|
|
|
|
|
|
In case of failure, exit.
|
|
|
|
|
|
|
|
Check all packages in one go, since this takes only 6 seconds on my Athlon 700
|
|
|
|
instead of 20 when calling 'rpm -K' for each of them.
|
|
|
|
"""
|
2008-10-11 22:26:45 +02:00
|
|
|
import subprocess
|
2006-07-14 19:39:46 +02:00
|
|
|
|
2007-06-26 13:19:41 +02:00
|
|
|
if not pac_list:
|
|
|
|
return
|
|
|
|
|
2008-10-11 22:26:45 +02:00
|
|
|
# don't care about the return value because we check the
|
|
|
|
# output anyway, and rpm always writes to stdout.
|
2007-12-10 15:10:40 +01:00
|
|
|
|
|
|
|
# save locale first (we rely on English rpm output here)
|
|
|
|
saved_LC_ALL = os.environ.get('LC_ALL')
|
|
|
|
os.environ['LC_ALL'] = 'en_EN'
|
|
|
|
|
2008-12-19 16:06:36 +01:00
|
|
|
o = subprocess.Popen(['rpm', '-K'] + pac_list, stdout=subprocess.PIPE,
|
2008-10-11 22:26:45 +02:00
|
|
|
stderr=subprocess.STDOUT, close_fds=True).stdout
|
2006-07-14 19:39:46 +02:00
|
|
|
|
2007-12-10 15:10:40 +01:00
|
|
|
# restore locale
|
|
|
|
if saved_LC_ALL: os.environ['LC_ALL'] = saved_LC_ALL;
|
|
|
|
else: os.environ.pop('LC_ALL')
|
|
|
|
|
2006-07-14 19:39:46 +02:00
|
|
|
for line in o.readlines():
|
|
|
|
|
|
|
|
if not 'OK' in line:
|
|
|
|
print
|
|
|
|
print >>sys.stderr, 'The following package could not be verified:'
|
|
|
|
print >>sys.stderr, line
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if 'NOT OK' in line:
|
|
|
|
print
|
|
|
|
print >>sys.stderr, 'The following package could not be verified:'
|
|
|
|
print >>sys.stderr, line
|
|
|
|
|
|
|
|
if 'MISSING KEYS' in line:
|
|
|
|
missing_key = line.split('#')[-1].split(')')[0]
|
|
|
|
|
|
|
|
print >>sys.stderr, """
|
|
|
|
- If the key is missing, install it first.
|
2007-05-02 21:17:10 +02:00
|
|
|
For example, do the following:
|
2006-07-17 14:07:19 +02:00
|
|
|
gpg --keyserver pgp.mit.edu --recv-keys %(name)s
|
2007-05-02 21:17:10 +02:00
|
|
|
gpg --armor --export %(name)s > %(dir)s/keyfile-%(name)s
|
|
|
|
and, as root:
|
|
|
|
rpm --import %(dir)s/keyfile-%(name)s
|
2006-07-14 19:39:46 +02:00
|
|
|
|
|
|
|
Then, just start the build again.
|
2008-01-24 19:06:45 +01:00
|
|
|
|
2009-02-20 13:49:17 +01:00
|
|
|
- If you do not trust the packages, you should configure osc build for XEN or KVM
|
|
|
|
|
|
|
|
- You may use --no-verify to skip the verification (which is a risk for your system).
|
2007-05-02 21:17:10 +02:00
|
|
|
""" % {'name': missing_key,
|
|
|
|
'dir': os.path.expanduser('~')}
|
2006-07-14 19:39:46 +02:00
|
|
|
|
|
|
|
else:
|
|
|
|
print >>sys.stderr, """
|
|
|
|
- If the signature is wrong, you may try deleting the package manually
|
|
|
|
and re-run this program, so it is fetched again.
|
|
|
|
"""
|
|
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|