From e2c8c0c5f5ed7e2674380a37d4bd760cdc5e1289 Mon Sep 17 00:00:00 2001 From: Jonathan Dieter Date: Wed, 28 Mar 2007 17:40:25 +0300 Subject: Bump to 0.3.0. Start downloading deltarpms ourselves. Signed-off-by: Jonathan Dieter --- shared/deltarpm.py | 2 +- shared/prestoDownload.py | 169 ++++++++++++++++++++++++++++++++++++++++++++ shared/prestoRepo.py | 16 ++++- shared/prestoTransaction.py | 18 ++++- 4 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 shared/prestoDownload.py (limited to 'shared') diff --git a/shared/deltarpm.py b/shared/deltarpm.py index a2aea2e..710a8bb 100644 --- a/shared/deltarpm.py +++ b/shared/deltarpm.py @@ -80,7 +80,7 @@ class DeltaRpmWrapper: constructs file names and paths based on given RpmDescription and instance settings for directories""" self.conduit.info(7, '%s.verify(%s)' % (self.__class__, sequence)) p = Process(self.conduit) - p.run(APPLY, '-c', '-s', sequence) + p.run(APPLY, '-s', sequence) if p.returnCode(): # in case of error, raise exception raise Exception("Could not verify sequence of deltarpm: %d" % (p.returnCode())) diff --git a/shared/prestoDownload.py b/shared/prestoDownload.py new file mode 100644 index 0000000..45318ba --- /dev/null +++ b/shared/prestoDownload.py @@ -0,0 +1,169 @@ +# 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) + + 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'] + po.simple['deltalocalpath'] = deltalocal + + # 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" + + # 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 + + diff --git a/shared/prestoRepo.py b/shared/prestoRepo.py index f9c4648..582dc2f 100644 --- a/shared/prestoRepo.py +++ b/shared/prestoRepo.py @@ -158,11 +158,11 @@ class PrestoRepository(Repository): def dump(self): output = '[%s]\n' % self.id - vars = ['name', 'bandwidth', 'enabled', + vars = ['id', 'bandwidth', 'enabled', 'keepalive', 'proxy', 'proxy_password', 'proxy_username', 'retries', 'throttle', 'timeout', 'mirrorlist', - 'cachedir', 'deltasdir' ] + 'cachedir' ] vars.sort() for attr in vars: output = output + '%s = %s\n' % (attr, getattr(self, attr)) @@ -367,6 +367,18 @@ class PrestoRepository(Repository): return result + def getPackage(self, package, checkfunc = None, text = None, cache = True): + remote = package.returnSimple('relativepath') + local = package.localPkg() + basepath = package.returnSimple('basepath') + + return self.__get(url=basepath, + relative=remote, + local=local, + checkfunc=checkfunc, + text=text, + cache=cache + ) def metadataCurrent(self): """Check if there is a metadata_cookie and check its age. If the diff --git a/shared/prestoTransaction.py b/shared/prestoTransaction.py index 71b90f3..3d387a4 100644 --- a/shared/prestoTransaction.py +++ b/shared/prestoTransaction.py @@ -24,15 +24,29 @@ def find_available_drpms(conduit, newpkg): rpmdb = conduit.getRpmDB() + is_local = False + # Set p_repo to be packages delta repository or set to False if # there is no delta repository try: p_repo = newpkg.po.repo.p_repo drpm_enabled = p_repo.enabled - if os.path.exists(newpkg.po.localpath): + + po = newpkg.po + if hasattr(po, 'pkgtype') and po.pkgtype == 'local': is_local = True else: - is_local = False + local = po.localPkg() + if os.path.exists(local): + cursize = os.stat(local)[6] + totsize = long(po.size) + if not po.verifyLocalPkg(): + if cursize >= totsize: # otherwise keep it around for regetting + os.unlink(local) + else: + conduit.info(5, "using local copy of %s" % po) + is_local = True + except: conduit.info(5, "No Presto repository information for %s.%s %i:%s-%s" % (newpkg.name, newpkg.arch, int(newpkg.epoch), newpkg.version, newpkg.release)) drpm_enabled = False -- cgit