# This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # Copyright 2005 Duke University # Copyright 2007 Jonathan Dieter import os from yum import misc from yum import Errors from yum import types from urlgrabber.grabber import URLGrabError import deltarpm def verifyDelta(fo, po, conduit, raiseError): """verifies the deltarpm is what we expect it to be raiseError = defaults to 0 - if 1 then will raise a URLGrabError if the file does not check out. otherwise it returns false for a failure, true for success""" if type(fo) is types.InstanceType: fo = fo.filename try: verifyChecksum(fo, po.returnSimple('deltachecksumtype'), po.returnSimple('deltachecksum')) except: if raiseError: raise URLGrabError(-1, 'Package does not match intended download') else: return False return True def verifyChecksum(filename, checksumType, csum): """Verify the checksum of the file versus the provided checksum""" try: filesum = misc.checksum(checksumType, filename) except Errors.MiscError, e: raise URLGrabError(-3, 'Could not perform checksum') if filesum != csum: raise URLGrabError(-1, 'Package does not match checksum') return 0 def downloadPkgs(conduit, pkglist): """download list of package objects handed to you, return errors""" opts, commands = conduit.getCmdLine() errors = {} def adderror(po, msg): errors.setdefault(po, []).append(msg) # Check whether drpm is already downloaded repo_cached = False remote_pkgs = [] rebuild_pkgs = [] for po in conduit.getDownloadPackages(): if hasattr(po, 'has_drpm') and po.has_drpm: po.to.pkgtup = po.to.realpkgtup local = po.returnSimple('deltalocalpath') if os.path.exists(local): cursize = os.stat(local)[6] totsize = long(po.returnSimple('deltasize')) try: verifyChecksum(local, po.returnSimple('deltachecksumtype'), po.returnSimple('deltachecksum')) except: if po.repo.p_repo.cache: repo_cached = True adderror(po, 'package fails checksum but caching is ' 'enabled for %s' % po.repo.p_repo.id) if cursize >= totsize: # otherwise keep it around for regetting os.unlink(local) else: # Deltarpm is local and good, let's put it in the rebuild list conduit.info(5, "using local copy of deltarpm for %s" % po) rebuild_pkgs.append(po) continue remote_pkgs.append(po) # Download deltarpms i = 0 for po in remote_pkgs: i += 1 checkfunc = (verifyDelta, (po, conduit, 1), {}) cache = po.repo.p_repo.http_caching != 'none' dirstat = os.statvfs(po.repo.deltasdir) if (dirstat.f_bavail * dirstat.f_bsize) <= long(po.size): adderror(po, 'Insufficient space in download directory %s ' 'to download' % po.repo.deltasdir) continue po.simple['reallocalpath'] = po.localpath po.localpath = po.returnSimple('deltalocalpath') po.simple['realrelativepath'] = po.returnSimple('relativepath') po.simple['relativepath'] = po.returnSimple('deltarelativepath') try: text = '(%s/%s): %s' % (i, len(remote_pkgs), os.path.basename(po.returnSimple('deltarelativepath'))) deltalocal = po.repo.p_repo.getPackage(po, checkfunc=checkfunc, text=text, cache=cache) except Errors.RepoError, e: adderror(po, str(e)) else: rebuild_pkgs.append(po) po.simple['deltalocalpath'] = deltalocal if errors.has_key(po): del errors[po] po.simple['relativepath'] = po.returnSimple('realrelativepath') po.localpath = po.returnSimple('reallocalpath') if po.simple.has_key('realpackagesize'): po.simple['packagesize'] = po.returnSimple('realpackagesize') del po.simple['realpackagesize'] del po.simple['realrelativepath'] del po.simple['reallocalpath'] # Rebuild rpms from downloaded deltarpms for po in rebuild_pkgs: deltalocal = po.returnSimple('deltalocalpath') drpm = deltarpm.DeltaRpmWrapper(conduit) try: conduit.info(2, "Building %s from %s" % (os.path.basename(po.localpath), os.path.basename(deltalocal))) drpm.apply(po.localpath, deltalocal) except: conduit.info(2, "Error rebuilding rpm from %s! Will download full package." % os.path.basename(deltalocal)) try: os.unlink(po.localpath) except: pass else: # Set package type to local, so yum doesn't try to download it later # po.pkgtype = "local" # If we set this, we can't auto-install public keys # and yum is smart enough to detect the full rpm and # not redownload it. # Check to see whether or not we should keep the drpms # FIXME: Is there any way to see whether or not a Boolean option was not set? if conduit.confBool('main', 'neverkeepdeltas'): delete = True elif conduit.confBool('main', 'keepdeltas'): delete = False elif conduit.getConf().keepcache != 0: delete = False else: delete = True if delete: try: os.unlink(deltalocal) except: pass return errors