[yum: 1/2] update to latest HEAD Fix syncing of yum DB data in history. Add upgrade_requirements_on_install con

James Antill james at fedoraproject.org
Fri Aug 19 20:47:34 UTC 2011


commit b8b2a22656dc997f013dfd9c59bacf30ba162592
Author: James Antill <james at and.org>
Date:   Fri Aug 5 13:39:22 2011 -0400

    update to latest HEAD
    Fix syncing of yum DB data in history.
    Add upgrade_requirements_on_install config. option.
    Don't look for releasever if it's set directly (anaconda).
    Expose ip_resolve urlgrabber option.

 yum-HEAD.patch | 3007 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 yum.spec       |   17 +-
 2 files changed, 2846 insertions(+), 178 deletions(-)
---
diff --git a/yum-HEAD.patch b/yum-HEAD.patch
index 74ff6ed..588bb37 100644
--- a/yum-HEAD.patch
+++ b/yum-HEAD.patch
@@ -60,7 +60,7 @@ index 2f6154e..2e5a052 100644
 diff --git a/cli.py b/cli.py
 old mode 100644
 new mode 100755
-index 6056d38..43c0e1d
+index 6056d38..3a68616
 --- a/cli.py
 +++ b/cli.py
 @@ -25,7 +25,7 @@ import sys
@@ -72,6 +72,15 @@ index 6056d38..43c0e1d
  import rpm
  
  from weakref import proxy as weakref
+@@ -43,7 +43,7 @@ from yum.rpmtrans import RPMTransaction
+ import signal
+ import yumcommands
+ 
+-from yum.i18n import to_unicode, to_utf8
++from yum.i18n import to_unicode, to_utf8, exception2msg
+ 
+ #  This is for yum-utils/yumdownloader in RHEL-5, where it isn't importing this
+ # directly but did do "from cli import *", and we did have this in 3.2.22. I
 @@ -51,23 +51,24 @@ from yum.i18n import to_unicode, to_utf8
  from yum.packages import parsePackages
  
@@ -132,8 +141,33 @@ index 6056d38..43c0e1d
          if self._repos and thisrepo is None:
              return self._repos
              
-@@ -183,10 +193,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -163,8 +173,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+         mainopts = yum.misc.GenericHolder()
+         mainopts.items = []
+ 
++        bad_setopt_tm = []
++        bad_setopt_ne = []
++
+         for item in setopts:
+-            k,v = item.split('=')
++            vals = item.split('=')
++            if len(vals) > 2:
++                bad_setopt_tm.append(item)
++                continue
++            if len(vals) < 2:
++                bad_setopt_ne.append(item)
++                continue
++            k,v = vals
+             period = k.find('.') 
+             if period != -1:
+                 repo = k[:period]
+@@ -180,13 +200,15 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          
+         self.main_setopts = mainopts
+         self.repo_setopts = repoopts
+-        
++
++        return bad_setopt_tm, bad_setopt_ne
          
      def getOptionsConfig(self, args):
 -        """parses command line arguments, takes cli args:
@@ -148,7 +182,29 @@ index 6056d38..43c0e1d
          self.optparser = YumOptionParser(base=self, usage=self._makeUsage())
          
          # Parse only command line options that affect basic yum setup
-@@ -318,9 +329,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -199,7 +221,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+             opts.verbose = False
+ 
+         # go through all the setopts and set the global ones
+-        self._parseSetOpts(opts.setopts)
++        bad_setopt_tm, bad_setopt_ne = self._parseSetOpts(opts.setopts)
+         
+         if self.main_setopts:
+             for opt in self.main_setopts.items:
+@@ -229,6 +251,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+             pc.releasever = opts.releasever
+             self.conf
+             
++            for item in  bad_setopt_tm:
++                msg = "Setopt argument has multiple values: %s"
++                self.logger.warning(msg % item)
++            for item in  bad_setopt_ne:
++                msg = "Setopt argument has no value: %s"
++                self.logger.warning(msg % item)
+             # now set  all the non-first-start opts from main from our setopts
+             if self.main_setopts:
+                 for opt in self.main_setopts.items:
+@@ -318,9 +346,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          time.sleep(sleeptime)
          
      def parseCommands(self):
@@ -163,7 +219,7 @@ index 6056d38..43c0e1d
          self.verbose_logger.debug('Yum Version: %s', yum.__version__)
          self.verbose_logger.log(yum.logginglevels.DEBUG_4,
                                  'COMMAND: %s', self.cmdstring)
-@@ -365,7 +378,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -365,7 +395,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          self.history.write_addon_data('shell-cmds', data)
  
      def doShell(self):
@@ -176,7 +232,7 @@ index 6056d38..43c0e1d
  
          yumshell = shell.YumShell(base=self)
  
-@@ -382,8 +399,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -382,8 +416,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return yumshell.result, yumshell.resultmsgs
  
      def errorSummary(self, errstring):
@@ -191,7 +247,7 @@ index 6056d38..43c0e1d
          summary = ''
          # do disk space report first
          p = re.compile('needs (\d+)MB on the (\S+) filesystem')
-@@ -408,16 +429,17 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -408,16 +446,17 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
  
  
      def doCommands(self):
@@ -219,7 +275,13 @@ index 6056d38..43c0e1d
          # at this point we know the args are valid - we don't know their meaning
          # but we know we're not being sent garbage
          
-@@ -440,9 +462,13 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -435,14 +474,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+             try:
+                 self._getTs(needTsRemove)
+             except yum.Errors.YumBaseError, e:
+-                return 1, [str(e)]
++                return 1, [exception2msg(e)]
+ 
          return self.yum_cli_commands[self.basecmd].doCommand(self, self.basecmd, self.extcmds)
  
      def doTransaction(self):
@@ -236,7 +298,7 @@ index 6056d38..43c0e1d
          # just make sure there's not, well, nothing to do
          if len(self.tsInfo) == 0:
              self.verbose_logger.info(_('Trying to run the transaction but nothing to do. Exiting.'))
-@@ -453,7 +479,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -453,7 +496,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          lsts = self.listTransaction()
          if self.verbose_logger.isEnabledFor(yum.logginglevels.INFO_1):
              self.verbose_logger.log(yum.logginglevels.INFO_1, lsts)
@@ -245,7 +307,7 @@ index 6056d38..43c0e1d
              #  If we are in quiet, and assumeyes isn't on we want to output
              # at least the transaction list anyway.
              self.logger.warn(lsts)
-@@ -491,7 +517,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -491,7 +534,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          
          # confirm with user
          if self._promptWanted():
@@ -254,7 +316,7 @@ index 6056d38..43c0e1d
                  self.verbose_logger.info(_('Exiting on user Command'))
                  return -1
  
-@@ -609,12 +635,14 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -609,12 +652,14 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return resultobject.return_code
          
      def gpgsigcheck(self, pkgs):
@@ -274,7 +336,7 @@ index 6056d38..43c0e1d
          for po in pkgs:
              result, errmsg = self.sigCheckPkg(po)
  
-@@ -623,7 +651,8 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -623,7 +668,8 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
                  continue            
  
              elif result == 1:
@@ -284,9 +346,46 @@ index 6056d38..43c0e1d
                      raise yum.Errors.YumBaseError, \
                              _('Refusing to automatically import keys when running ' \
                              'unattended.\nUse "-y" to override.')
-@@ -692,11 +721,22 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -691,12 +737,59 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+                                      ", ".join(matches))
              self.verbose_logger.log(yum.logginglevels.INFO_2, msg)
  
++    def _install_upgraded_requires(self, txmbrs):
++        """Go through the given txmbrs, and for any to be installed packages
++        look for their installed deps. and try to upgrade them, if the
++        configuration is set. Returning any new transaction members to be
++        isntalled.
++
++        :param txmbrs: a list of :class:`yum.transactioninfo.TransactionMember` objects
++        :return: a list of :class:`yum.transactioninfo.TransactionMember` objects
++        """
++
++        if not self.conf.upgrade_requirements_on_install:
++            return []
++
++        ret = []
++        done = set()
++        def _pkg2ups(pkg, reqpo=None):
++            if pkg.name in done:
++                return []
++            if reqpo is None:
++                reqpo = pkg
++
++            done.add(pkg.name)
++
++            uret = []
++            for req in pkg.requires:
++                for npkg in self.returnInstalledPackagesByDep(req):
++                    uret += self.update(pattern=npkg.name, requiringPo=reqpo)
++                    uret += _pkg2ups(npkg, reqpo=reqpo)
++            return uret
++
++        for txmbr in txmbrs:
++            print "JDBG:", txmbr
++            ret += _pkg2ups(txmbr.po)
++
++        return ret
++
      def installPkgs(self, userlist):
 -        """Attempts to take the user specified list of packages/wildcards
 -           and install them, or if they are installed, update them to a newer
@@ -312,7 +411,30 @@ index 6056d38..43c0e1d
          # get the list of available packages
          # iterate over the user's list
          # add packages to Transaction holding class if they match.
-@@ -732,9 +772,27 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -710,11 +803,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+         for arg in userlist:
+             if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
+                                           os.path.exists(arg))):
+-                self.localInstall(filelist=[arg])
++                txmbrs = self.installLocal(arg)
++                self._install_upgraded_requires(txmbrs)
+                 continue # it was something on disk and it ended in rpm 
+                          # no matter what we don't go looking at repos
+             try:
+-                self.install(pattern=arg)
++                txmbrs = self.install(pattern=arg)
+             except yum.Errors.InstallError:
+                 self.verbose_logger.log(yum.logginglevels.INFO_2,
+                                         _('No package %s%s%s available.'),
+@@ -723,6 +817,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+                 self._maybeYouMeant(arg)
+             else:
+                 done = True
++                self._install_upgraded_requires(txmbrs)
+         if len(self.tsInfo) > oldcount:
+             change = len(self.tsInfo) - oldcount
+             return 2, [P_('%d package to install', '%d packages to install', change) % change]
+@@ -732,9 +827,27 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, [_('Nothing to do')]
          
      def updatePkgs(self, userlist, quiet=0, update_to=False):
@@ -343,7 +465,36 @@ index 6056d38..43c0e1d
          # if there is no userlist, then do global update below
          # this is probably 90% of the calls
          # if there is a userlist then it's for updating pkgs, not obsoleting
-@@ -770,9 +828,24 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -745,20 +858,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ 
+         else:
+             # go through the userlist - look for items that are local rpms. If we find them
+-            # pass them off to localInstall() and then move on
++            # pass them off to installLocal() and then move on
+             localupdates = []
+             for item in userlist:
+                 if (item.endswith('.rpm') and (yum.misc.re_remote_url(item) or
+                                                os.path.exists(item))):
+-                    localupdates.append(item)
+-            
+-            if len(localupdates) > 0:
+-                self.localInstall(filelist=localupdates, updateonly=1)
+-                for item in localupdates:
+-                    userlist.remove(item)
+-                
+-            for arg in userlist:
+-                if not self.update(pattern=arg, update_to=update_to):
++                    txmbrs = self.installLocal(item, updateonly=1)
++                    self._install_upgraded_requires(txmbrs)
++                    continue
++
++                txmbrs = self.update(pattern=item, update_to=update_to)
++                self._install_upgraded_requires(txmbrs)
++                if not txmbrs:
+                     self._checkMaybeYouMeant(arg)
+ 
+         if len(self.tsInfo) > oldcount:
+@@ -770,9 +881,24 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
      #  Note that we aren't in __init__ yet for a couple of reasons, but we 
      # probably will get there for 3.2.28.
      def distroSyncPkgs(self, userlist):
@@ -371,7 +522,7 @@ index 6056d38..43c0e1d
  
          level = 'diff'
          if userlist and userlist[0] in ('full', 'diff', 'different'):
-@@ -866,9 +939,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -866,9 +992,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
              return 0, [_('No Packages marked for Distribution Synchronization')]
  
      def erasePkgs(self, userlist):
@@ -394,7 +545,7 @@ index 6056d38..43c0e1d
          oldcount = len(self.tsInfo)
  
          all_rms = []
-@@ -884,9 +967,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -884,9 +1020,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
              return 0, [_('No Packages marked for removal')]
      
      def downgradePkgs(self, userlist):
@@ -418,7 +569,7 @@ index 6056d38..43c0e1d
  
          oldcount = len(self.tsInfo)
          
-@@ -911,8 +1005,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -911,20 +1058,32 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, [_('Nothing to do')]
          
      def reinstallPkgs(self, userlist):
@@ -440,7 +591,31 @@ index 6056d38..43c0e1d
  
          oldcount = len(self.tsInfo)
  
-@@ -946,9 +1051,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+         for arg in userlist:
+             if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
+                                           os.path.exists(arg))):
+-                self.reinstallLocal(arg)
++                txmbrs = self.reinstallLocal(arg)
++                self._install_upgraded_requires(txmbrs)
+                 continue # it was something on disk and it ended in rpm
+                          # no matter what we don't go looking at repos
+ 
+             try:
+-                self.reinstall(pattern=arg)
++                txmbrs = self.reinstall(pattern=arg)
+             except yum.Errors.ReinstallRemoveError:
+                 self._checkMaybeYouMeant(arg, always_output=False)
+             except yum.Errors.ReinstallInstallError, e:
+@@ -940,15 +1099,27 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+             except yum.Errors.ReinstallError, e:
+                 assert False, "Shouldn't happen, but just in case"
+                 self.verbose_logger.log(yum.logginglevels.INFO_2, e)
++            else:
++                self._install_upgraded_requires(txmbrs)
++
+         if len(self.tsInfo) > oldcount:
+             change = len(self.tsInfo) - oldcount
+             return 2, [P_('%d package to reinstall', '%d packages to reinstall', change) % change]
          return 0, [_('Nothing to do')]
  
      def localInstall(self, filelist, updateonly=0):
@@ -462,7 +637,7 @@ index 6056d38..43c0e1d
          # read in each package into a YumLocalPackage Object
          # append it to self.localPackages
          # check if it can be installed or updated based on nevra versus rpmdb
-@@ -972,20 +1086,25 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -972,20 +1143,25 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, [_('Nothing to do')]
  
      def returnPkgLists(self, extcmds, installed_available=False):
@@ -502,7 +677,7 @@ index 6056d38..43c0e1d
          special = ['available', 'installed', 'all', 'extras', 'updates', 'recent',
                     'obsoletes']
          
-@@ -1017,8 +1136,25 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1017,8 +1193,25 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return ypl
  
      def search(self, args):
@@ -530,7 +705,7 @@ index 6056d38..43c0e1d
          
          # call the yum module search function with lists of tags to search
          # and what to search for
-@@ -1108,9 +1244,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1108,9 +1301,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, matching
  
      def deplist(self, args):
@@ -539,11 +714,11 @@ index 6056d38..43c0e1d
 +        """Print out a formatted list of dependencies for a list of
 +        packages.  This is a cli wrapper method for
 +        :class:`yum.YumBase.findDeps`.
- 
++
 +        :param args: a list of names or wildcards specifying packages
 +           that should have their dependenices printed
 +        :return: (exit_code, [ errors ])
-+
+ 
 +        exit_code is::
 +
 +            0 = we're done, exit
@@ -553,7 +728,7 @@ index 6056d38..43c0e1d
          pkgs = []
          for arg in args:
              if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
-@@ -1131,10 +1278,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1131,10 +1335,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, []
  
      def provides(self, args):
@@ -577,7 +752,7 @@ index 6056d38..43c0e1d
          old_sdup = self.conf.showdupesfromrepos
          # For output, as searchPackageProvides() is always in showdups mode
          self.conf.showdupesfromrepos = True
-@@ -1163,8 +1319,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1163,8 +1376,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, []
      
      def resolveDepCli(self, args):
@@ -599,7 +774,7 @@ index 6056d38..43c0e1d
          for arg in args:
              try:
                  pkg = self.returnPackageByDep(arg)
-@@ -1177,6 +1344,34 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1177,6 +1401,34 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, []
      
      def cleanCli(self, userlist):
@@ -634,7 +809,7 @@ index 6056d38..43c0e1d
          hdrcode = pkgcode = xmlcode = dbcode = expccode = 0
          pkgresults = hdrresults = xmlresults = dbresults = expcresults = []
          msg = self.fmtKeyValFill(_('Cleaning repos: '), 
-@@ -1228,7 +1423,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1228,7 +1480,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return code, []
  
      def returnGroupLists(self, userlist):
@@ -654,18 +829,18 @@ index 6056d38..43c0e1d
          uservisible=1
              
          if len(userlist) > 0:
-@@ -1283,7 +1490,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1283,7 +1547,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, [_('Done')]
  
      def returnGroupSummary(self, userlist):
 +        """Print a summary of the groups that match the given names or
 +        wildcards.
-+
+ 
 +        :param userlist: a list of names or wildcards specifying the
 +           groups to summarise. If *userlist* is an empty list, all
 +           installed and available packages will be summarised
 +        :return: (exit_code, [ errors ])
- 
++
 +        exit_code is::
 +
 +            0 = we're done, exit
@@ -675,7 +850,7 @@ index 6056d38..43c0e1d
          uservisible=1
              
          if len(userlist) > 0:
-@@ -1327,7 +1547,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1327,7 +1604,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, [_('Done')]
      
      def returnGroupInfo(self, userlist):
@@ -696,7 +871,7 @@ index 6056d38..43c0e1d
          for strng in userlist:
              group_matched = False
              for group in self.comps.return_groups(strng):
-@@ -1340,8 +1572,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1340,8 +1629,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, []
          
      def installGroups(self, grouplist):
@@ -717,7 +892,7 @@ index 6056d38..43c0e1d
          pkgs_used = []
          
          for group_string in grouplist:
-@@ -1368,8 +1610,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1368,8 +1667,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
              return 2, [P_('%d package to Install', '%d packages to Install', len(pkgs_used)) % len(pkgs_used)]
  
      def removeGroups(self, grouplist):
@@ -737,7 +912,7 @@ index 6056d38..43c0e1d
          pkgs_used = []
          for group_string in grouplist:
              try:
-@@ -1389,7 +1641,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1389,7 +1698,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
  
      def _promptWanted(self):
          # shortcut for the always-off/always-on options
@@ -746,7 +921,7 @@ index 6056d38..43c0e1d
              return False
          if self.conf.alwaysprompt:
              return True
-@@ -1400,7 +1652,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1400,7 +1709,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          #  package wasn't explictly given on the command line
          for txmbr in self.tsInfo.getMembers():
              if txmbr.isDep or \
@@ -754,7 +929,7 @@ index 6056d38..43c0e1d
                     txmbr.name not in self.extcmds:
                  return True
          
-@@ -1408,11 +1659,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1408,11 +1716,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return False
  
      def usage(self):
@@ -768,7 +943,7 @@ index 6056d38..43c0e1d
          sys.stdout.write(self.optparser.get_usage())
      
      def _installable(self, pkg, ematch=False):
-@@ -1468,9 +1719,9 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1468,9 +1776,9 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return False
  
  class YumOptionParser(OptionParser):
@@ -780,7 +955,7 @@ index 6056d38..43c0e1d
  
      def __init__(self,base, **kwargs):
          # check if this is called with a utils=True/False parameter
-@@ -1488,13 +1739,23 @@ class YumOptionParser(OptionParser):
+@@ -1488,13 +1796,23 @@ class YumOptionParser(OptionParser):
          self._addYumBasicOptions()
  
      def error(self, msg):
@@ -806,7 +981,7 @@ index 6056d38..43c0e1d
          try:
              args = _filtercmdline(
                          ('--noplugins','--version','-q', '-v', "--quiet", "--verbose"), 
-@@ -1521,7 +1782,15 @@ class YumOptionParser(OptionParser):
+@@ -1521,7 +1839,15 @@ class YumOptionParser(OptionParser):
          return ret
          
      def setupYumConfig(self, args=None):
@@ -823,7 +998,7 @@ index 6056d38..43c0e1d
          if not args:
              (opts, cmds) = self.parse_args()
          else:
-@@ -1536,7 +1805,9 @@ class YumOptionParser(OptionParser):
+@@ -1536,7 +1862,9 @@ class YumOptionParser(OptionParser):
                  
              # Handle remaining options
              if opts.assumeyes:
@@ -834,7 +1009,7 @@ index 6056d38..43c0e1d
  
              #  Instead of going cache-only for a non-root user, try to use a
              # user writable cachedir. If that fails fall back to cache-only.
-@@ -1640,6 +1911,14 @@ class YumOptionParser(OptionParser):
+@@ -1640,6 +1968,14 @@ class YumOptionParser(OptionParser):
          sys.exit(1)
  
      def getRoot(self,opts):
@@ -849,7 +1024,7 @@ index 6056d38..43c0e1d
          self._checkAbsInstallRoot(opts)
          # If the conf file is inside the  installroot - use that.
          # otherwise look for it in the normal root
-@@ -1713,6 +1992,10 @@ class YumOptionParser(OptionParser):
+@@ -1713,6 +2049,10 @@ class YumOptionParser(OptionParser):
                          help=_("verbose operation"))
          group.add_option("-y", "--assumeyes", dest="assumeyes",
                  action="store_true", help=_("answer yes for all questions"))
@@ -1537,7 +1712,7 @@ index 1a8202a..255c755 100644
  Specifies the config file location - can take HTTP and FTP URLs and local file
  paths\&.
 diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
-index 515aa73..bd86eea 100644
+index 515aa73..607e9fc 100644
 --- a/docs/yum.conf.5
 +++ b/docs/yum.conf.5
 @@ -114,15 +114,27 @@ are causing problems from the transaction.
@@ -1580,6 +1755,46 @@ index 515aa73..bd86eea 100644
  .br
  Command-line option: \fB\-t\fP
  
+@@ -300,6 +313,14 @@ with the \fBthrottle\fR option (above). If \fBthrottle\fR is a percentage and
+ ignored. Default is `0' (no bandwidth throttling). 
+ 
+ .IP
++\fBip_resolve \fR
++Determines how yum resolves host names.
++
++`4' or `IPv4': resolve to IPv4 addresses only.
++
++`6' or `IPv6': resolve to IPv6 addresses only.
++
++.IP
+ \fBsslcacert \fR
+ Path to the directory containing the databases of the certificate authorities
+ yum should use to verify SSL certificates. Defaults to none - uses system
+@@ -595,6 +616,12 @@ package's dependencies. If any of them are no longer required by any other
+ package then also mark them to be removed.
+ Boolean (1, 0, True, False, yes,no) Defaults to False
+ 
++.IP
++\fBupgrade_requirements_on_install \fR
++When installing/reinstalling/upgrading packages go through each package's
++installed dependencies and check for an update.
++Boolean (1, 0, True, False, yes,no) Defaults to False
++
+ 
+ 
+ .SH "[repository] OPTIONS"
+@@ -755,6 +782,11 @@ repository.
+ Overrides the \fBbandwidth\fR option from the [main] section for this
+ repository.
+ 
++.IP
++\fBip_resolve \fR
++Overrides the \fBip_resolve\fR option from the [main] section for this
++repository.
++
+ 
+ .IP
+ \fBsslcacert \fR
 diff --git a/etc/0yum.cron b/etc/0yum.cron
 deleted file mode 100755
 index 0cfaa4b..0000000
@@ -3566,7 +3781,7 @@ index 97a9923..70dde98 100644
 diff --git a/utils.py b/utils.py
 old mode 100644
 new mode 100755
-index ced6ba0..90b6fd4
+index ced6ba0..99533a6
 --- a/utils.py
 +++ b/utils.py
 @@ -13,6 +13,8 @@
@@ -3578,6 +3793,15 @@ index ced6ba0..90b6fd4
  import sys
  import time
  import exceptions
+@@ -21,7 +23,7 @@ import yum
+ from cli import *
+ from yum import Errors
+ from yum import _
+-from yum.i18n import utf8_width
++from yum.i18n import utf8_width, exception2msg
+ from yum import logginglevels
+ from optparse import OptionGroup
+ 
 @@ -29,6 +31,9 @@ import yum.plugins as plugins
  from urlgrabber.progress import format_number
  
@@ -3642,36 +3866,38 @@ index ced6ba0..90b6fd4
      ps = get_process_info(pid)
      if not ps:
          return None
-@@ -130,9 +164,16 @@ def show_lock_owner(pid, logger):
+@@ -129,28 +163,9 @@ def show_lock_owner(pid, logger):
+     return ps
  
  
- def exception2msg(e):
+-def exception2msg(e):
 -    """ DIE python DIE! Which one works:
 -        to_unicode(e.value); unicode(e); str(e); 
 -        Call this so you don't have to care. """
-+    """Convert an exception to a message.  This function will convert
-+    the exception using to_unicode, unicode, or str, whichever works correctly.
-+
-+    :param e: an exception
-+    :return: a string representation of the exception
-+    """
-+
-+    # DIE python DIE! Which one works:
-+    # to_unicode(e.value); unicode(e); str(e); 
-+    # Call this so you don't have to care.
-     try:
-         return to_unicode(e.value)
-     except:
-@@ -151,6 +192,8 @@ def exception2msg(e):
- 
- 
+-    try:
+-        return to_unicode(e.value)
+-    except:
+-        pass
+-
+-    try:
+-        return unicode(e)
+-    except:
+-        pass
+-
+-    try:
+-        return str(e)
+-    except:
+-        pass
+-    return "<exception failed to convert to text>"
+-
+-
  class YumUtilBase(YumBaseCli):
 +    """A class to extend the yum cli for utilities."""
 +    
      def __init__(self,name,ver,usage):
          YumBaseCli.__init__(self)
          self._parser = YumOptionParser(base=self,utils=True,usage=usage)
-@@ -167,11 +210,22 @@ class YumUtilBase(YumBaseCli):
+@@ -167,11 +182,22 @@ class YumUtilBase(YumBaseCli):
              self.run_with_package_names.add("yum-utils")
  
      def exUserCancel(self):
@@ -3694,7 +3920,7 @@ index ced6ba0..90b6fd4
          if e.errno == 32:
              self.logger.critical(_('\n\nExiting on Broken Pipe'))
          else:
-@@ -180,10 +234,13 @@ class YumUtilBase(YumBaseCli):
+@@ -180,10 +206,13 @@ class YumUtilBase(YumBaseCli):
          return 1
  
      def exPluginExit(self, e):
@@ -3711,7 +3937,7 @@ index ced6ba0..90b6fd4
          exitmsg = exception2msg(e)
          if exitmsg:
              self.logger.warn('\n\n%s', exitmsg)
-@@ -191,11 +248,20 @@ class YumUtilBase(YumBaseCli):
+@@ -191,11 +220,20 @@ class YumUtilBase(YumBaseCli):
          return 1
  
      def exFatal(self, e):
@@ -3732,7 +3958,7 @@ index ced6ba0..90b6fd4
          try:
              self.closeRpmDB()
              self.doUnlock()
-@@ -205,13 +271,27 @@ class YumUtilBase(YumBaseCli):
+@@ -205,13 +243,27 @@ class YumUtilBase(YumBaseCli):
          
          
      def getOptionParser(self):
@@ -3761,7 +3987,7 @@ index ced6ba0..90b6fd4
          lockerr = ""
          while True:
              try:
-@@ -233,6 +313,13 @@ class YumUtilBase(YumBaseCli):
+@@ -233,6 +285,13 @@ class YumUtilBase(YumBaseCli):
          print "%s - %s (yum - %s)" % (self._utilName,self._utilVer,yum.__version__)
          
      def doUtilConfigSetup(self,args = sys.argv[1:],pluginsTypes=(plugins.TYPE_CORE,)):
@@ -3775,7 +4001,7 @@ index ced6ba0..90b6fd4
          # Parse only command line options that affect basic yum setup
          opts = self._parser.firstParse(args)
  
-@@ -305,8 +392,9 @@ class YumUtilBase(YumBaseCli):
+@@ -305,8 +364,9 @@ class YumUtilBase(YumBaseCli):
          return opts
  
      def doUtilYumSetup(self):
@@ -3787,7 +4013,7 @@ index ced6ba0..90b6fd4
          # FIXME - we need another way to do this, I think.
          try:
              self.waitForLock()
-@@ -319,6 +407,11 @@ class YumUtilBase(YumBaseCli):
+@@ -319,6 +379,11 @@ class YumUtilBase(YumBaseCli):
              sys.exit(1)
  
      def doUtilBuildTransaction(self, unfinished_transactions_check=True):
@@ -3799,7 +4025,7 @@ index ced6ba0..90b6fd4
          try:
              (result, resultmsgs) = self.buildTransaction(unfinished_transactions_check = unfinished_transactions_check)
          except plugins.PluginYumExit, e:
-@@ -361,6 +454,7 @@ class YumUtilBase(YumBaseCli):
+@@ -361,6 +426,7 @@ class YumUtilBase(YumBaseCli):
          self.verbose_logger.log(logginglevels.INFO_2, _('\nDependencies Resolved'))
          
      def doUtilTransaction(self):
@@ -4886,18 +5112,236 @@ index 1ce4720..25e3022
      gobject.threads_init()
      dbus.glib.threads_init()
 diff --git a/yum.spec b/yum.spec
-index abd203f..825f745 100644
+index abd203f..b78a9f6 100644
 --- a/yum.spec
 +++ b/yum.spec
-@@ -1,6 +1,6 @@
- Summary: RPM installer/updater
+@@ -1,24 +1,51 @@
+-Summary: RPM installer/updater
++%define move_yum_conf_back 1
++%define auto_sitelib 1
++%define yum_updatesd 0
++%define disable_check 0
++
++%if %{auto_sitelib}
++
++%{!?python_sitelib: %define python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
++
++%else
++%define python_sitelib /usr/lib/python?.?/site-packages
++%endif
++
++# We always used /usr/lib here, even on 64bit ... so it's a bit meh.
++%define yum_pluginslib   /usr/lib/yum-plugins
++%define yum_pluginsshare /usr/share/yum-plugins
++
++Summary: RPM package installer/updater/manager
  Name: yum
 -Version: 3.4.2
 +Version: 3.4.3
  Release: 0
  License: GPLv2+
  Group: System Environment/Base
-@@ -193,13 +193,14 @@ exit 0
+ Source: %{name}-%{version}.tar.gz
+ URL: http://yum.baseurl.org/
+-BuildRoot: %{_tmppath}/%{name}-%{version}root
+ BuildArchitectures: noarch
+ BuildRequires: python
+ BuildRequires: gettext
+ BuildRequires: intltool
+-
++# This is really CheckRequires ...
++BuildRequires: python-nose
++BuildRequires: python >= 2.4
++BuildRequires: rpm-python, rpm >= 0:4.4.2
++BuildRequires: python-iniparse
++BuildRequires: python-sqlite
++BuildRequires: python-urlgrabber >= 3.9.0-8
++BuildRequires: yum-metadata-parser >= 1.1.0
++BuildRequires: pygpgme
++# End of CheckRequires
++Conflicts: pirut < 1.1.4
+ Requires: python >= 2.4
+ Requires: rpm-python, rpm >= 0:4.4.2
++Requires: python-iniparse
+ Requires: python-sqlite
+-Requires: urlgrabber >= 3.9.2
++Requires: python-urlgrabber >= 3.9.0-8
+ Requires: yum-metadata-parser >= 1.1.0
+-Requires: python-iniparse
+ Requires: pygpgme
++
+ Conflicts: rpm >= 5-0
+ # Zif is a re-implementation of yum in C, however:
+ #
+@@ -34,18 +61,26 @@ Conflicts: rpm >= 5-0
+ # zif experts).
+ #
+ # ...so we have two sane choices: i) Conflict with it. 2) Stop developing yum.
+-Conflicts: zif
++#
++#  Upstream says that #2 will no longer be true after this release.
++Conflicts: zif <= 0.1.3-3.fc15
++
+ Obsoletes: yum-skip-broken <= 1.1.18
++Provides: yum-skip-broken = 1.1.18.yum
+ Obsoletes: yum-basearchonly <= 1.1.9
++Obsoletes: yum-plugin-basearchonly <= 1.1.9
++Provides: yum-basearchonly = 1.1.9.yum
++Provides: yum-plugin-basearchonly = 1.1.9.yum
+ Obsoletes: yum-allow-downgrade < 1.1.20-0
+ Obsoletes: yum-plugin-allow-downgrade < 1.1.22-0
++Provides: yum-allow-downgrade = 1.1.20-0.yum
++Provides: yum-plugin-allow-downgrade = 1.1.22-0.yum
+ Obsoletes: yum-plugin-protect-packages < 1.1.27-0
+-Provides: yum-skip-broken
+-Provides: yum-basearchonly
+-Provides: yum-allow-downgrade
+-Provides: yum-plugin-allow-downgrade
+-Provides: yum-protect-packages
+-Provides: yum-plugin-protect-packages
++Provides: yum-protect-packages = 1.1.27-0.yum
++Provides: yum-plugin-protect-packages = 1.1.27-0.yum
++Obsoletes: yum-plugin-download-order <= 0.2-2
++BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
++
+ 
+ %description
+ Yum is a utility that can check for and automatically download and
+@@ -58,9 +93,11 @@ Group: Applications/System
+ Requires: yum = %{version}-%{release}
+ Requires: dbus-python
+ Requires: pygobject2
+-Requires(preun): /sbin/chkconfig 
++Requires(preun): /sbin/chkconfig
++Requires(post): /sbin/chkconfig
+ Requires(preun): /sbin/service
+-Requires(postun): /sbin/chkconfig 
++Requires(post): /sbin/service
++Requires(postun): /sbin/chkconfig
+ Requires(postun): /sbin/service
+ 
+ 
+@@ -83,18 +120,46 @@ Requires(postun): /sbin/service
+ These are the files needed to run yum updates as a cron job.
+ Install this package if you want auto yum updates nightly via cron.
+ 
++
++
+ %prep
+ %setup -q
+ 
+ %build
+ make
+ 
++%if !%{disable_check}
++%check
++make check
++%endif
++
+ 
+ %install
+ [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+ make DESTDIR=$RPM_BUILD_ROOT install
+-# install -m 644 %{SOURCE1} $RPM_BUILD_ROOT/etc/yum/yum.conf
+-# install -m 755 %{SOURCE2} $RPM_BUILD_ROOT/etc/cron.daily/yum.cron
++install -m 644 %{SOURCE1} $RPM_BUILD_ROOT/%{_sysconfdir}/yum.conf
++mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/yum/pluginconf.d $RPM_BUILD_ROOT/%{yum_pluginslib}
++mkdir -p $RPM_BUILD_ROOT/%{yum_pluginsshare}
++
++%if %{move_yum_conf_back}
++# for now, move repodir/yum.conf back
++mv $RPM_BUILD_ROOT/%{_sysconfdir}/yum/repos.d $RPM_BUILD_ROOT/%{_sysconfdir}/yum.repos.d
++rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/yum/yum.conf
++%endif
++
++%if %{yum_updatesd}
++echo Keeping local yum-updatesd
++%else
++
++# yum-updatesd has moved to the separate source version
++rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/yum/yum-updatesd.conf 
++rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/rc.d/init.d/yum-updatesd
++rm -f $RPM_BUILD_ROOT/%{_sysconfdir}/dbus-1/system.d/yum-updatesd.conf
++rm -f $RPM_BUILD_ROOT/%{_sbindir}/yum-updatesd
++rm -f $RPM_BUILD_ROOT/%{_mandir}/man*/yum-updatesd*
++rm -f $RPM_BUILD_ROOT/%{_datadir}/yum-cli/yumupd.py*
++
++%endif
+ 
+ # Ghost files:
+ mkdir -p $RPM_BUILD_ROOT/var/lib/yum/history
+@@ -102,12 +167,18 @@ mkdir -p $RPM_BUILD_ROOT/var/lib/yum/plugins
+ mkdir -p $RPM_BUILD_ROOT/var/lib/yum/yumdb
+ touch $RPM_BUILD_ROOT/var/lib/yum/uuid
+ 
++# rpmlint bogus stuff...
++chmod +x $RPM_BUILD_ROOT/%{_datadir}/yum-cli/*.py
++chmod +x $RPM_BUILD_ROOT/%{python_sitelib}/yum/*.py
++chmod +x $RPM_BUILD_ROOT/%{python_sitelib}/rpmUtils/*.py
++
+ %find_lang %name
+ 
+ %clean
+ [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+ 
+ 
++%if %{yum_updatesd}
+ %post updatesd
+ /sbin/chkconfig --add yum-updatesd
+ /sbin/service yum-updatesd condrestart >/dev/null 2>&1
+@@ -119,6 +190,7 @@ if [ $1 = 0 ]; then
+  /sbin/service yum-updatesd stop >/dev/null 2>&1
+ fi
+ exit 0
++%endif
+ 
+ 
+ %post cron
+@@ -165,21 +237,29 @@ exit 0
+ 
+ 
+ %files -f %{name}.lang
+-%defattr(-, root, root)
++%defattr(-, root, root, -)
+ %doc README AUTHORS COPYING TODO INSTALL ChangeLog PLUGINS
++%if %{move_yum_conf_back}
++%config(noreplace) %{_sysconfdir}/yum.conf
++%dir %{_sysconfdir}/yum.repos.d
++%else
+ %config(noreplace) %{_sysconfdir}/yum/yum.conf
++%dir %{_sysconfdir}/yum/repos.d
++%endif
+ %config(noreplace) %{_sysconfdir}/yum/version-groups.conf
+ %dir %{_sysconfdir}/yum
+ %dir %{_sysconfdir}/yum/protected.d
+-%dir %{_sysconfdir}/yum/repos.d
+ %dir %{_sysconfdir}/yum/vars
+-%config %{_sysconfdir}/logrotate.d/%{name}
++%config(noreplace) %{_sysconfdir}/logrotate.d/%{name}
+ %{_sysconfdir}/bash_completion.d
++%dir %{_datadir}/yum-cli
+ %{_datadir}/yum-cli/*
++%if %{yum_updatesd}
+ %exclude %{_datadir}/yum-cli/yumupd.py*
++%endif
+ %{_bindir}/yum
+-/usr/lib/python?.?/site-packages/yum
+-/usr/lib/python?.?/site-packages/rpmUtils
++%{python_sitelib}/yum
++%{python_sitelib}/rpmUtils
+ %dir /var/cache/yum
+ %dir /var/lib/yum
+ %ghost /var/lib/yum/uuid
+@@ -188,20 +268,24 @@ exit 0
+ %ghost /var/lib/yum/yumdb
+ %{_mandir}/man*/yum.*
+ %{_mandir}/man*/yum-shell*
+-
++# plugin stuff
++%dir %{_sysconfdir}/yum/pluginconf.d 
++%dir %{yum_pluginslib}
++%dir %{yum_pluginsshare}
+ 
  %files cron
  %defattr(-,root,root)
  %doc COPYING
@@ -4909,16 +5353,22 @@ index abd203f..825f745 100644
  %{_sysconfdir}/rc.d/init.d/yum-cron
 +%{_sbindir}/yum-cron
  %config(noreplace) %{_sysconfdir}/sysconfig/yum-cron
--
--
 +%dir %{_datadir}/yum-cron   
 +%{_datadir}/yum-cron/update.yum
 +%{_datadir}/yum-cron/cleanup.yum
  
- 
+-
+-
+-
++%if %{yum_updatesd}
  %files updatesd
-@@ -212,6 +213,9 @@ exit 0
+ %defattr(-, root, root)
+ %config(noreplace) %{_sysconfdir}/yum/yum-updatesd.conf
+@@ -210,8 +294,12 @@ exit 0
+ %{_datadir}/yum-cli/yumupd.py*
+ %{_sbindir}/yum-updatesd
  %{_mandir}/man*/yum-updatesd*
++%endif
  
  %changelog
 +* Thu Jul 28 2011 Matthew Miller <mattdm at mattdm.org>
@@ -4928,10 +5378,320 @@ index abd203f..825f745 100644
  - 3.4.1
  - umask bug fix.
 diff --git a/yum/__init__.py b/yum/__init__.py
-index 99039e0..530bfd4 100644
+index 99039e0..5fb7c00 100644
 --- a/yum/__init__.py
 +++ b/yum/__init__.py
-@@ -881,7 +881,8 @@ class YumBase(depsolve.Depsolve):
+@@ -82,7 +82,7 @@ from packages import YumAvailablePackage, YumLocalPackage, YumInstalledPackage
+ from packages import YumUrlPackage, YumNotFoundPackage
+ from constants import *
+ from yum.rpmtrans import RPMTransaction,SimpleCliCallBack
+-from yum.i18n import to_unicode, to_str
++from yum.i18n import to_unicode, to_str, exception2msg
+ 
+ import string
+ import StringIO
+@@ -102,10 +102,12 @@ default_grabber.opts.user_agent += " yum/" + __version__
+ 
+ 
+ class _YumPreBaseConf:
+-    """This is the configuration interface for the YumBase configuration.
+-       So if you want to change if plugins are on/off, or debuglevel/etc.
+-       you tweak it here, and when yb.conf does it's thing ... it happens. """
+-
++    """This is the configuration interface for the :class:`YumBase`
++    configuration.  To change configuration settings such as whether
++    plugins are on or off, or the value of debuglevel, change the
++    values here. Later, when :func:`YumBase.conf` is first called, all
++    of the options will be automatically configured.
++    """
+     def __init__(self):
+         self.fn = '/etc/yum/yum.conf'
+         self.root = '/'
+@@ -125,10 +127,12 @@ class _YumPreBaseConf:
+ 
+ 
+ class _YumPreRepoConf:
+-    """This is the configuration interface for the repos configuration.
+-       So if you want to change callbacks etc. you tweak it here, and when
+-       yb.repos does it's thing ... it happens. """
+-
++    """This is the configuration interface for the repos configuration
++    configuration.  To change configuration settings such what
++    callbacks are used, change the values here. Later, when
++    :func:`YumBase.repos` is first called, all of the options will be
++    automatically configured.
++    """
+     def __init__(self):
+         self.progressbar = None
+         self.callback = None
+@@ -164,11 +168,11 @@ class _YumCostExclude:
+         return False
+ 
+ class YumBase(depsolve.Depsolve):
+-    """This is a primary structure and base class. It houses the objects and
+-       methods needed to perform most things in yum. It is almost an abstract
+-       class in that you will need to add your own class above it for most
+-       real use."""
+-    
++    """This is a primary structure and base class. It houses the
++    objects and methods needed to perform most things in yum. It is
++    almost an abstract class in that you will need to add your own
++    class above it for most real use.
++    """
+     def __init__(self):
+         depsolve.Depsolve.__init__(self)
+         self._conf = None
+@@ -213,6 +217,8 @@ class YumBase(depsolve.Depsolve):
+         for cb in self._cleanup: cb()
+ 
+     def close(self):
++        """Close the history and repo objects."""
++
+         # We don't want to create the object, so we test if it's been created
+         if self._history is not None:
+             self.history.close()
+@@ -225,15 +231,33 @@ class YumBase(depsolve.Depsolve):
+         return transactioninfo.TransactionData()
+ 
+     def doGenericSetup(self, cache=0):
+-        """do a default setup for all the normal/necessary yum components,
+-           really just a shorthand for testing"""
++        """Do a default setup for all the normal or necessary yum
++        components.  This function is really just a shorthand for
++        testing purposes.
+ 
++        :param cache: whether to run in cache only mode, which will
++           run only from the system cache
++        """
+         self.preconf.init_plugins = False
+         self.conf.cache = cache
+ 
+     def doConfigSetup(self, fn='/etc/yum/yum.conf', root='/', init_plugins=True,
+             plugin_types=(plugins.TYPE_CORE,), optparser=None, debuglevel=None,
+             errorlevel=None):
++        """Deprecated.  Perform configuration setup.
++
++        :param fn: the name of the configuration file to use
++        :param root: the root directory to use
++        :param init_plugins: whether to initialize plugins before
++           running yum
++        :param plugin_types: a tuple containing the types to plugins
++           to load
++        :param optparser: the option parser to use for configuration
++        :param debuglevel: the minimum debug logging level to output
++           messages from
++        :param errorlevel: the minimum error logging level to output
++           messages from
++        """
+         warnings.warn(_('doConfigSetup() will go away in a future version of Yum.\n'),
+                 Errors.YumFutureDeprecationWarning, stacklevel=2)
+ 
+@@ -297,7 +321,7 @@ class YumBase(depsolve.Depsolve):
+             # Try the old default
+             fn = '/etc/yum.conf'
+ 
+-        startupconf = config.readStartupConfig(fn, root)
++        startupconf = config.readStartupConfig(fn, root, releasever)
+         startupconf.arch = arch
+         startupconf.basearch = self.arch.basearch
+         if uuid:
+@@ -367,22 +391,36 @@ class YumBase(depsolve.Depsolve):
+     def doLoggingSetup(self, debuglevel, errorlevel,
+                        syslog_ident=None, syslog_facility=None,
+                        syslog_device='/dev/log'):
+-        '''
+-        Perform logging related setup.
+-
+-        @param debuglevel: Debug logging level to use.
+-        @param errorlevel: Error logging level to use.
+-        '''
++        """Perform logging related setup.
++
++        :param debuglevel: the minimum debug logging level to output
++           messages from
++        :param errorlevel: the minimum error logging level to output
++           messages from
++        :param syslog_ident: the ident of the syslog to use
++        :param syslog_facility: the name of the syslog facility to use
++        :param syslog_device: the syslog device to use
++        """
+         logginglevels.doLoggingSetup(debuglevel, errorlevel,
+                                      syslog_ident, syslog_facility,
+                                      syslog_device)
+ 
+     def doFileLogSetup(self, uid, logfile):
++        """Set up the logging file.
++
++        :param uid: the user id of the current user
++        :param logfile: the name of the file to use for logging
++        """
+         logginglevels.setFileLog(uid, logfile, self._cleanup)
+ 
+     def getReposFromConfigFile(self, repofn, repo_age=None, validate=None):
+-        """read in repositories from a config .repo file"""
++        """Read in repositories from a config .repo file.
+ 
++        :param repofn: a string specifying the path of the .repo file
++           to read
++        :param repo_age: the last time that the .repo file was
++           modified, in seconds since the epoch
++        """
+         if repo_age is None:
+             repo_age = os.stat(repofn)[8]
+         
+@@ -448,8 +486,11 @@ class YumBase(depsolve.Depsolve):
+                 self.logger.warning(e)
+         
+     def getReposFromConfig(self):
+-        """read in repositories from config main and .repo files"""
+-
++        """Read in repositories from the main yum conf file, and from
++        .repo files.  The location of the main yum conf file is given
++        by self.conf.config_file_path, and the location of the
++        directory of .repo files is given by self.conf.reposdir.
++        """
+         # Read .repo files from directories specified by the reposdir option
+         # (typically /etc/yum/repos.d)
+         repo_config_age = self.conf.config_file_age
+@@ -472,12 +513,13 @@ class YumBase(depsolve.Depsolve):
+                     self.getReposFromConfigFile(repofn, repo_age=thisrepo_age)
+ 
+     def readRepoConfig(self, parser, section):
+-        '''Parse an INI file section for a repository.
++        """Parse an INI file section for a repository.
+ 
+-        @param parser: ConfParser or similar to read INI file values from.
+-        @param section: INI file section to read.
+-        @return: YumRepository instance.
+-        '''
++        :param parser: :class:`ConfigParser` or similar object to read
++           INI file values from
++        :param section: INI file section to read
++        :return: :class:`yum.yumRepo.YumRepository` instance
++        """
+         repo = yumRepo.YumRepository(section)
+         try:
+             repo.populate(parser, section, self.conf)
+@@ -500,31 +542,31 @@ class YumBase(depsolve.Depsolve):
+         return repo
+ 
+     def disablePlugins(self):
+-        '''Disable yum plugins
+-        '''
++        """Disable yum plugins."""
++
+         self.plugins = plugins.DummyYumPlugins()
+     
+     def doPluginSetup(self, optparser=None, plugin_types=None, searchpath=None,
+             confpath=None,disabled_plugins=None,enabled_plugins=None):
+-        '''Initialise and enable yum plugins. 
+-
+-        Note: _getConfig() will initialise plugins if instructed to. Only
+-        call this method directly if not calling _getConfig() or calling
+-        doConfigSetup(init_plugins=False).
+-
+-        @param optparser: The OptionParser instance for this run (optional)
+-        @param plugin_types: A sequence specifying the types of plugins to load.
+-            This should be a sequence containing one or more of the
+-            yum.plugins.TYPE_...  constants. If None (the default), all plugins
+-            will be loaded.
+-        @param searchpath: A list of directories to look in for plugins. A
+-            default will be used if no value is specified.
+-        @param confpath: A list of directories to look in for plugin
+-            configuration files. A default will be used if no value is
+-            specified.
+-        @param disabled_plugins: Plugins to be disabled    
+-        @param enabled_plugins: Plugins to be enabled
+-        '''
++        """Initialise and enable yum plugins.
++        Note: _getConfig() will also initialise plugins if instructed
++        to. Only call this method directly if not calling _getConfig()
++        or calling doConfigSetup(init_plugins=False).
++
++        :param optparser: the :class:`OptionParser` instance to use
++           for this run
++        :param plugin_types: a sequence specifying the types of plugins to load.
++           This should be a sequence containing one or more of the
++           yum.plugins.TYPE_...  constants. If None (the default), all plugins
++           will be loaded
++        :param searchpath: a list of directories to look in for plugins. A
++           default will be used if no value is specified
++        :param confpath: a list of directories to look in for plugin
++           configuration files. A default will be used if no value is
++           specified
++        :param disabled_plugins: a list of plugins to be disabled    
++        :param enabled_plugins: a list plugins to be enabled
++        """
+         if isinstance(self.plugins, plugins.YumPlugins):
+             raise RuntimeError(_("plugins already initialised"))
+ 
+@@ -533,6 +575,8 @@ class YumBase(depsolve.Depsolve):
+ 
+     
+     def doRpmDBSetup(self):
++        """Deprecated.  Set up the rpm database."""
++
+         warnings.warn(_('doRpmDBSetup() will go away in a future version of Yum.\n'),
+                 Errors.YumFutureDeprecationWarning, stacklevel=2)
+ 
+@@ -552,7 +596,8 @@ class YumBase(depsolve.Depsolve):
+         return self._rpmdb
+ 
+     def closeRpmDB(self):
+-        """closes down the instances of the rpmdb we have wangling around"""
++        """Closes down the instances of rpmdb that could be open."""
++
+         if self._rpmdb is not None:
+             self._rpmdb.ts = None
+             self._rpmdb.dropCachedData()
+@@ -567,6 +612,12 @@ class YumBase(depsolve.Depsolve):
+         self._ts = None
+ 
+     def doRepoSetup(self, thisrepo=None):
++        """Deprecated. Set up the yum repositories.
++
++        :param thisrepo: the repository to set up.  If None, all
++           repositories will be set up
++        :return: the set up repos
++        """
+         warnings.warn(_('doRepoSetup() will go away in a future version of Yum.\n'),
+                 Errors.YumFutureDeprecationWarning, stacklevel=2)
+ 
+@@ -630,6 +681,14 @@ class YumBase(depsolve.Depsolve):
+         self._repos = RepoStorage(self)
+     
+     def doSackSetup(self, archlist=None, thisrepo=None):
++        """Deprecated. Populate the package sacks with information
++        from our repositories.
++
++        :param archlist: a list of the names of archs to include.  If
++           None, all arches are set up
++        :param thisrepo: the repository to use.  If None, all enabled
++           repositories are used
++        """
+         warnings.warn(_('doSackSetup() will go away in a future version of Yum.\n'),
+                 Errors.YumFutureDeprecationWarning, stacklevel=2)
+ 
+@@ -711,6 +770,9 @@ class YumBase(depsolve.Depsolve):
+             
+            
+     def doUpdateSetup(self):
++        """Deprecated. Set up the update object in the base class and populate the
++        updates, obsoletes, and other lists.
++        """
+         warnings.warn(_('doUpdateSetup() will go away in a future version of Yum.\n'),
+                 Errors.YumFutureDeprecationWarning, stacklevel=2)
+ 
+@@ -765,6 +827,8 @@ class YumBase(depsolve.Depsolve):
+         return self._up
+     
+     def doGroupSetup(self):
++        """Deprecated. Create and populate the groups object."""
++
+         warnings.warn(_('doGroupSetup() will go away in a future version of Yum.\n'),
+                 Errors.YumFutureDeprecationWarning, stacklevel=2)
+ 
+@@ -881,7 +945,8 @@ class YumBase(depsolve.Depsolve):
          if self._history is None:
              pdb_path = self.conf.persistdir + "/history"
              self._history = yum.history.YumHistory(root=self.conf.installroot,
@@ -4941,7 +5701,56 @@ index 99039e0..530bfd4 100644
          return self._history
      
      # properties so they auto-create themselves with defaults
-@@ -1242,13 +1243,15 @@ class YumBase(depsolve.Depsolve):
+@@ -928,9 +993,10 @@ class YumBase(depsolve.Depsolve):
+     
+     
+     def doSackFilelistPopulate(self):
+-        """convenience function to populate the repos with the filelist metadata
+-           it also is simply to only emit a log if anything actually gets populated"""
+-        
++        """Convenience function to populate the repositories with the
++        filelist metadata, and emit a log message only if new
++        information is actually populated.
++        """
+         necessary = False
+         
+         # I can't think of a nice way of doing this, we have to have the sack here
+@@ -951,8 +1017,12 @@ class YumBase(depsolve.Depsolve):
+             self.repos.populateSack(mdtype='filelists')
+            
+     def yumUtilsMsg(self, func, prog):
+-        """ Output a message that the tool requires the yum-utils package,
+-            if not installed. """
++        """Output a message that the given tool requires the yum-utils
++        package, if it not installed.
++
++        :param func: the function to output the message
++        :param prog: the name of the tool that requires yum-utils
++        """
+         if self.rpmdb.contains(name="yum-utils"):
+             return
+ 
+@@ -964,8 +1034,17 @@ class YumBase(depsolve.Depsolve):
+              (hibeg, prog, hiend))
+ 
+     def buildTransaction(self, unfinished_transactions_check=True):
+-        """go through the packages in the transaction set, find them in the
+-           packageSack or rpmdb, and pack up the ts accordingly"""
++        """Go through the packages in the transaction set, find them
++        in the packageSack or rpmdb, and pack up the transaction set
++        accordingly.
++
++        :param unfinished_transactions_check: whether to check for
++           unfinished transactions before building the new transaction
++        """
++        # FIXME: This is horrible, see below and yummain. Maybe create a real
++        #        rescode object? :(
++        self._depsolving_failed = False
++
+         if (unfinished_transactions_check and
+             misc.find_unfinished_transactions(yumlibpath=self.conf.persistdir)):
+             msg = _('There are unfinished transactions remaining. You might ' \
+@@ -1242,13 +1321,15 @@ class YumBase(depsolve.Depsolve):
          if None in pkgtup:
              return None
          return pkgtup
@@ -4961,7 +5770,41 @@ index 99039e0..530bfd4 100644
          if pkgtup is None:
              return
          self._not_found_i[pkgtup] = YumNotFoundPackage(pkgtup)
-@@ -1645,6 +1648,9 @@ class YumBase(depsolve.Depsolve):
+@@ -1454,8 +1535,14 @@ class YumBase(depsolve.Depsolve):
+         return probs
+ 
+     def runTransaction(self, cb):
+-        """takes an rpm callback object, performs the transaction"""
++        """Perform the transaction.
+ 
++        :param cb: an rpm callback object to use in the transaction
++        :return: a :class:`yum.misc.GenericHolder` containing
++           information about the results of the transaction
++        :raises: :class:`yum.Errors.YumRPMTransError` if there is a
++           transaction cannot be completed
++        """
+         self.plugins.run('pretrans')
+ 
+         #  We may want to put this other places, eventually, but for now it's
+@@ -1571,9 +1658,14 @@ class YumBase(depsolve.Depsolve):
+         return resultobject
+ 
+     def verifyTransaction(self, resultobject=None):
+-        """checks that the transaction did what we expected it to do. Also 
+-           propagates our external yumdb info"""
+-        
++        """Check that the transaction did what was expected, and 
++        propagate external yumdb information.  Output error messages
++        if the transaction did not do what was expected.
++
++        :param resultobject: the :class:`yum.misc.GenericHolder`
++           object returned from the :func:`runTransaction` call that
++           ran the transaction
++        """
+         # check to see that the rpmdb and the tsInfo roughly matches
+         # push package object metadata outside of rpmdb into yumdb
+         # delete old yumdb metadata entries
+@@ -1645,6 +1737,9 @@ class YumBase(depsolve.Depsolve):
                  elif loginuid is not None:
                      po.yumdb_info.installed_by = str(loginuid)
  
@@ -4971,66 +5814,753 @@ index 99039e0..530bfd4 100644
          # Remove old ones after installing new ones, so we can copy values.
          for txmbr in self.tsInfo:
              if txmbr.output_state in TS_INSTALL_STATES:
-@@ -2939,7 +2945,7 @@ class YumBase(depsolve.Depsolve):
-                 self.verbose_logger.log(logginglevels.DEBUG_2,
-                     _('Adding package %s from group %s'), pkg, thisgroup.groupid)
-                 try:
--                    txmbrs = self.install(name = pkg)
-+                    txmbrs = self.install(name=pkg, pkg_warning_level='debug2')
-                 except Errors.InstallError, e:
-                     self.verbose_logger.debug(_('No package named %s available to be installed'),
-                         pkg)
-@@ -3049,7 +3055,7 @@ class YumBase(depsolve.Depsolve):
-         pkgs = self.pkgSack.searchPkgTuple(pkgtup)
+@@ -1680,10 +1775,11 @@ class YumBase(depsolve.Depsolve):
+         self.verbose_logger.debug('VerifyTransaction time: %0.3f' % (time.time() - vt_st))
  
-         if len(pkgs) == 0:
--            self._add_not_found_a(pkgs, pkgtup)
-+            self._add_not_found_a(pkgs, pkgtup=pkgtup)
-             if allow_missing: #  This can happen due to excludes after .up has
-                 return None   # happened.
-             raise Errors.DepError, _('Package tuple %s could not be found in packagesack') % str(pkgtup)
-@@ -3071,7 +3077,7 @@ class YumBase(depsolve.Depsolve):
- 
-         pkgs = self.rpmdb.searchPkgTuple(pkgtup)
-         if len(pkgs) == 0:
--            self._add_not_found_i(pkgs, pkgtup)
-+            self._add_not_found_i(pkgs, pkgtup=pkgtup)
-             raise Errors.RpmDBError, _('Package tuple %s could not be found in rpmdb') % str(pkgtup)
+     def costExcludePackages(self):
+-        """ Create an excluder for repos. with higher cost. Eg.
+-            repo-A:cost=1 repo-B:cost=2 ... here we setup an excluder on repo-B
+-            that looks for pkgs in repo-B."""
+-        
++        """Create an excluder for repositories with higher costs. For
++        example, if repo-A:cost=1 and repo-B:cost=2, this function
++        will set up an excluder on repo-B that looks for packages in
++        repo-B.
++        """
+         # if all the repo.costs are equal then don't bother running things
+         costs = {}
+         for r in self.repos.listEnabled():
+@@ -1705,10 +1801,12 @@ class YumBase(depsolve.Depsolve):
+             done = True
+ 
+     def excludePackages(self, repo=None):
+-        """removes packages from packageSacks based on global exclude lists,
+-           command line excludes and per-repository excludes, takes optional 
+-           repo object to use."""
++        """Remove packages from packageSacks based on global exclude
++        lists, command line excludes and per-repository excludes.
+ 
++        :param repo: a repo object to use.  If not given, all
++           repositories are used
++        """
+         if "all" in self.conf.disable_excludes:
+             return
+         
+@@ -1735,9 +1833,11 @@ class YumBase(depsolve.Depsolve):
+             self.pkgSack.addPackageExcluder(repoid, exid,'exclude.match', match)
  
-         # Dito. FIXME from getPackageObject() for len() > 1 ... :)
-@@ -3445,6 +3451,21 @@ class YumBase(depsolve.Depsolve):
-            
-            """
+     def includePackages(self, repo):
+-        """removes packages from packageSacks based on list of packages, to include.
+-           takes repoid as a mandatory argument."""
+-        
++        """Remove packages from packageSacks based on list of
++        packages to include.  
++
++        :param repo: the repository to use
++        """
+         includelist = repo.getIncludePkgList()
          
+         if len(includelist) == 0:
+@@ -1757,8 +1857,11 @@ class YumBase(depsolve.Depsolve):
+         self.pkgSack.addPackageExcluder(repo.id, exid, 'exclude.marked')
+         
+     def doLock(self, lockfile = YUM_PID_FILE):
+-        """perform the yum locking, raise yum-based exceptions, not OSErrors"""
+-        
++        """Acquire the yum lock.
 +
-+        #  This is kind of hacky, we really need a better way to do errors than
-+        # doing them directly from .install/etc. ... but this is easy. *sigh*.
-+        #  We are only using this in "groupinstall" atm. ... so we don't have
-+        # a long list of "blah already installed." messages when people run
-+        # "groupinstall mygroup" in yum-cron etc.
-+        pkg_warn = kwargs.get('pkg_warning_level', 'flibble')
-+        def _dbg2(*args, **kwargs):
-+            self.verbose_logger.log(logginglevels.DEBUG_2, *args, **kwargs)
-+        level2func = {'debug2' : _dbg2,
-+                      'warning' : self.verbose_logger.warning}
-+        if pkg_warn not in level2func:
-+            pkg_warn = 'warning'
-+        pkg_warn = level2func[pkg_warn]
++        :param lockfile: the file to use for the lock
++        :raises: :class:`yum.Errors.LockError`
++        """
+         if self.conf.uid != 0:
+             #  If we are a user, assume we are using the root cache ... so don't
+             # bother locking.
+@@ -1804,8 +1907,12 @@ class YumBase(depsolve.Depsolve):
+         self._lockfile = lockfile
+     
+     def doUnlock(self, lockfile=None):
+-        """do the unlock for yum"""
+-        
++        """Release the yum lock.
 +
-         pkgs = []
-         was_pattern = False
-         if po:
-@@ -3600,23 +3621,23 @@ class YumBase(depsolve.Depsolve):
-                     already_obs = pkgs[0]
++        :param lockfile: the lock file to use.  If not given, the file
++           that was given as a parameter to the :func:`doLock` call
++           that closed the lock is used
++        """
+         # if we're not root then we don't lock - just return nicely
+         #  Note that we can get here from __del__, so if we haven't created
+         # YumBase.conf we don't want to do so here as creating stuff inside
+@@ -1836,25 +1943,36 @@ class YumBase(depsolve.Depsolve):
+             if not os.path.exists(lockdir):
+                 os.makedirs(lockdir, mode=0755)
+             fd = os.open(filename, os.O_EXCL|os.O_CREAT|os.O_WRONLY, mode)    
++            os.write(fd, contents)
++            os.close(fd)
++            return 1
+         except OSError, msg:
+             if not msg.errno == errno.EEXIST: 
+                 # Whoa. What the heck happened?
+                 errmsg = _('Could not create lock at %s: %s ') % (filename, str(msg))
+                 raise Errors.LockError(msg.errno, errmsg, int(contents))
+             return 0
+-        else:
+-            os.write(fd, contents)
+-            os.close(fd)
+-            return 1
+     
+     def _unlock(self, filename):
+         misc.unlink_f(filename)
+ 
+     def verifyPkg(self, fo, po, raiseError):
+-        """verifies the package 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"""
++        """Check that the checksum of a remote package matches what we
++        expect it to be.  If the checksum of the package file is
++        wrong, and the file is also larger than expected, it cannot be
++        redeemed, so delete it.
++
++        :param fo: the file object of the package
++        :param po: the package object to verify
++        :param raiseError: if *raiseError* is 1, and the package
++           does not check out, a :class:`URLGrabError will be raised.
++           Defaults to 0
++        :return: True if the package is verified successfully.
++           Otherwise, False will be returned, unless *raiseError* is
++           1, in which case a :class:`URLGrabError` will be raised
++        :raises: :class:`URLGrabError` if verification fails, and
++           *raiseError* is 1
++        """
+         failed = False
+ 
+         if type(fo) is types.InstanceType:
+@@ -1894,9 +2012,16 @@ class YumBase(depsolve.Depsolve):
+         
+         
+     def verifyChecksum(self, fo, checksumType, csum):
+-        """Verify the checksum of the file versus the 
+-           provided checksum"""
+-
++        """Verify that the checksum of the given file matches the
++        given checksum.
++
++        :param fo: the file object to verify the checksum of
++        :param checksumType: the type of checksum to use
++        :parm csum: the checksum to check against
++        :return: 0 if the checksums match
++        :raises: :class:`URLGrabError` if there is an error performing
++           the checksums, or the checksums do not match
++        """
+         try:
+             filesum = misc.checksum(checksumType, fo)
+         except Errors.MiscError, e:
+@@ -1908,6 +2033,17 @@ class YumBase(depsolve.Depsolve):
+         return 0
+ 
+     def downloadPkgs(self, pkglist, callback=None, callback_total=None):
++        """Download the packages specified by the given list of
++        package objects.
++
++        :param pkglist: a list of package objects specifying the
++           packages to download
++        :param callback: unused
++        :param callback_total: a callback to output messages about the
++           download operation
++        :return: a dictionary containing errors from the downloading process
++        :raises: :class:`URLGrabError`
++        """
+         def mediasort(apo, bpo):
+             # FIXME: we should probably also use the mediaid; else we
+             # could conceivably ping-pong between different disc1's
+@@ -1998,16 +2134,6 @@ class YumBase(depsolve.Depsolve):
+                     os.unlink(local)
+ 
+             checkfunc = (self.verifyPkg, (po, 1), {})
+-            dirstat = os.statvfs(po.repo.pkgdir)
+-            if (dirstat.f_bavail * dirstat.f_bsize) <= long(po.size):
+-                adderror(po, _('Insufficient space in download directory %s\n'
+-                        "    * free   %s\n"
+-                        "    * needed %s") %
+-                         (po.repo.pkgdir,
+-                          format_number(dirstat.f_bavail * dirstat.f_bsize),
+-                          format_number(po.size)))
+-                continue
+-            
+             try:
+                 if i == 1 and not local_size and remote_size == po.size:
+                     text = os.path.basename(po.relativepath)
+@@ -2032,7 +2158,7 @@ class YumBase(depsolve.Depsolve):
+                 done_repos.add(po.repoid)
+ 
+             except Errors.RepoError, e:
+-                adderror(po, str(e))
++                adderror(po, exception2msg(e))
+             else:
+                 po.localpath = mylocal
+                 if po in errors:
+@@ -2052,7 +2178,22 @@ class YumBase(depsolve.Depsolve):
+         return errors
+ 
+     def verifyHeader(self, fo, po, raiseError):
+-        """check the header out via it's naevr, internally"""
++        """Check that the header of the given file object and matches
++        the given package.
++
++        :param fo: the file object to check
++        :param po: the package object to check
++        :param raiseError: if *raiseError* is True, a
++           :class:`URLGrabError` will be raised if the header matches
++           the package object, or cannot be read from the file.  If
++           *raiseError* is False, 0 will be returned in the above
++           cases
++        :return: 1 if the header matches the package object, and 0 if
++           they do not match, and *raiseError* is False
++        :raises: :class:`URLGrabError` if *raiseError* is True, and
++           the header does not match the package object or cannot be
++           read from the file
++        """
+         if type(fo) is types.InstanceType:
+             fo = fo.filename
+             
+@@ -2076,9 +2217,12 @@ class YumBase(depsolve.Depsolve):
+         return 1
+         
+     def downloadHeader(self, po):
+-        """download a header from a package object.
+-           output based on callback, raise yum.Errors.YumBaseError on problems"""
++        """Download a header from a package object.
  
-                 if already_obs:
--                    self.verbose_logger.warning(_('Package %s is obsoleted by %s which is already installed'), 
--                                                po, already_obs)
-+                    pkg_warn(_('Package %s is obsoleted by %s which is already installed'), 
-+                             po, already_obs)
-                 else:
-                     if 'provides_for' in kwargs:
-                         if not obsoleting_pkg.provides_for(kwargs['provides_for']):
++        :param po: the package object to download the header from
++        :raises: :class:`yum.Errors.RepoError` if there are errors
++           obtaining the header
++        """
+         if hasattr(po, 'pkgtype') and po.pkgtype == 'local':
+             return
+                 
+@@ -2122,15 +2266,17 @@ class YumBase(depsolve.Depsolve):
+             return
+ 
+     def sigCheckPkg(self, po):
+-        '''
+-        Take a package object and attempt to verify GPG signature if required
++        """Verify the GPG signature of the given package object.
+ 
+-        Returns (result, error_string) where result is:
+-            - 0 - GPG signature verifies ok or verification is not required.
+-            - 1 - GPG verification failed but installation of the right GPG key
+-                  might help.
+-            - 2 - Fatal GPG verification error, give up.
+-        '''
++        :param po: the package object to verify the signature of
++        :return: (result, error_string) 
++           where result is::
++
++              0 = GPG signature verifies ok or verification is not required.
++              1 = GPG verification failed but installation of the right GPG key
++                    might help.
++              2 = Fatal GPG verification error, give up.
++        """
+         if self._override_sigchecks:
+             check = False
+             hasgpgkey = 0
+@@ -2181,6 +2327,9 @@ class YumBase(depsolve.Depsolve):
+         return result, msg
+ 
+     def cleanUsedHeadersPackages(self):
++        """Delete the header and package files used in the
++        transaction from the yum cache.
++        """
+         filelist = []
+         for txmbr in self.tsInfo:
+             if txmbr.po.state not in TS_INSTALL_STATES:
+@@ -2218,27 +2367,40 @@ class YumBase(depsolve.Depsolve):
+                     _('%s removed'), fn)
+         
+     def cleanHeaders(self):
++        """Delete the header files from the yum cache."""
++
+         exts = ['hdr']
+         return self._cleanFiles(exts, 'hdrdir', 'header')
+ 
+     def cleanPackages(self):
++        """Delete the package files from the yum cache."""
++
+         exts = ['rpm']
+         return self._cleanFiles(exts, 'pkgdir', 'package')
+ 
+     def cleanSqlite(self):
++        """Delete the sqlite files from the yum cache."""
++
+         exts = ['sqlite', 'sqlite.bz2', 'sqlite-journal']
+         return self._cleanFiles(exts, 'cachedir', 'sqlite')
+ 
+     def cleanMetadata(self):
++        """Delete the metadata files from the yum cache."""
++
+         exts = ['xml.gz', 'xml', 'cachecookie', 'mirrorlist.txt', 'asc']
+         # Metalink is also here, but is a *.xml file
+         return self._cleanFiles(exts, 'cachedir', 'metadata') 
+ 
+     def cleanExpireCache(self):
++        """Delete the local data saying when the metadata and mirror
++           lists were downloaded for each repository."""
++
+         exts = ['cachecookie', 'mirrorlist.txt']
+         return self._cleanFiles(exts, 'cachedir', 'metadata')
+ 
+     def cleanRpmDB(self):
++        """Delete any cached data from the local rpmdb."""
++
+         cachedir = self.conf.persistdir + "/rpmdb-indexes/"
+         if not os.path.exists(cachedir):
+             filelist = []
+@@ -2272,8 +2434,29 @@ class YumBase(depsolve.Depsolve):
+ 
+     def doPackageLists(self, pkgnarrow='all', patterns=None, showdups=None,
+                        ignore_case=False):
+-        """generates lists of packages, un-reduced, based on pkgnarrow option"""
+-
++        """Return a :class:`yum.misc.GenericHolder` containing
++        lists of package objects.  The contents of the lists are
++        specified in various ways by the arguments.
++
++        :param pkgnarrow: a string specifying which types of packages
++           lists to produces, such as updates, installed, available,
++           etc.
++        :param patterns: a list of names or wildcards specifying
++           packages to list
++        :param showdups: whether to include duplicate packages in the
++           lists
++        :param ignore_case: whether to ignore case when searching by
++           package names
++        :return: a :class:`yum.misc.GenericHolder` instance with the
++           following lists defined::
++
++             available = list of packageObjects
++             installed = list of packageObjects
++             updates = tuples of packageObjects (updating, installed)
++             extras = list of packageObjects
++             obsoletes = tuples of packageObjects (obsoleting, installed)
++             recent = list of packageObjects
++        """
+         if showdups is None:
+             showdups = self.conf.showdupesfromrepos
+         ygh = misc.GenericHolder(iter=pkgnarrow)
+@@ -2461,14 +2644,13 @@ class YumBase(depsolve.Depsolve):
+ 
+         
+     def findDeps(self, pkgs):
+-        """
+-        Return the dependencies for a given package object list, as well
+-        possible solutions for those dependencies.
++        """Return the dependencies for a given package object list, as well
++        as possible solutions for those dependencies.
+            
+-        Returns the deps as a dict of dicts::
+-            packageobject = [reqs] = [list of satisfying pkgs]
++        :param pkgs: a list of package objects
++        :return: the dependencies as a dictionary of dictionaries:
++           packageobject = [reqs] = [list of satisfying pkgs]
+         """
+-        
+         results = {}
+ 
+         for pkg in pkgs:
+@@ -2495,10 +2677,22 @@ class YumBase(depsolve.Depsolve):
+     # pre 3.2.10 API used to always showdups, so that's the default atm.
+     def searchGenerator(self, fields, criteria, showdups=True, keys=False, 
+                                              searchtags=True, searchrpmdb=True):
+-        """Generator method to lighten memory load for some searches.
+-           This is the preferred search function to use. Setting keys to True
+-           will use the search keys that matched in the sorting, and return
+-           the search keys in the results. """
++        """Yield the packages that match the given search criteria.
++        This generator method will lighten memory load for some
++        searches, and is the preferred search function to use.
++
++        :param fields: the fields to search
++        :param criteria: a list of strings specifying the criteria to
++           search for
++        :param showdups: whether to yield duplicate packages from
++           different repositories
++        :param keys: setting *keys* to True will use the search keys
++           that matched in the sorting, and return the search keys in
++           the results
++        :param searchtags: whether to search the package tags
++        :param searchrpmdb: whether to search the rmpdb
++           
++        """
+         sql_fields = []
+         for f in fields:
+             sql_fields.append(RPM_TO_SQLITE.get(f, f))
+@@ -2661,6 +2855,14 @@ class YumBase(depsolve.Depsolve):
+                     yield (po, vs)
+ 
+     def searchPackageTags(self, criteria):
++        """Search for and return a list packages that have tags
++        matching the given criteria.
++
++        :param criteria: a list of strings specifying the criteria to
++           search for
++        :return: a list of package objects that have tags matching the
++           given criteria
++        """
+         results = {} # name = [(criteria, taglist)]
+         for c in criteria:
+             c = c.lower()
+@@ -2677,11 +2879,16 @@ class YumBase(depsolve.Depsolve):
+         return results
+         
+     def searchPackages(self, fields, criteria, callback=None):
+-        """Search specified fields for matches to criteria
+-           optional callback specified to print out results
+-           as you go. Callback is a simple function of:
+-           callback(po, matched values list). It will 
+-           just return a dict of dict[po]=matched values list"""
++        """Deprecated.  Search the specified fields for packages that
++        match the given criteria, and return a list of the results.
++
++        :param fields: the fields to seach
++        :param criteria: a list of strings specifying the criteria to
++           search for
++        :param callback: a function to print out the results as they
++           are found.  *callback* should have the form callback(po,
++           matched values list)
++        """
+         warnings.warn(_('searchPackages() will go away in a future version of Yum.\
+                       Use searchGenerator() instead. \n'),
+                 Errors.YumFutureDeprecationWarning, stacklevel=2)           
+@@ -2700,6 +2907,19 @@ class YumBase(depsolve.Depsolve):
+     
+     def searchPackageProvides(self, args, callback=None,
+                               callback_has_matchfor=False):
++        """Search for and return a list package objects that provide
++        the given files or features.
++
++        :param args: a list of strings specifying the files and
++           features to search for the packages that provide
++        :param callback: a callback function to print out the results
++           as they are found
++        :param callback_has_matchfor: whether the callback function
++           will accept a list of strings to highlight in its output.
++           If this is true, *args* will be passed to *callback* so
++           that the files or features that were searched for can be
++           highlighted
++        """
+         def _arg_data(arg):
+             if not misc.re_glob(arg):
+                 isglob = False
+@@ -2818,11 +3038,17 @@ class YumBase(depsolve.Depsolve):
+         return matches
+ 
+     def doGroupLists(self, uservisible=0, patterns=None, ignore_case=True):
+-        """returns two lists of groups, installed groups and available groups
+-           optional 'uservisible' bool to tell it whether or not to return
+-           only groups marked as uservisible"""
+-        
+-        
++        """Return two lists of groups: installed groups and available
++        groups.
++
++        :param uservisible: If True, only groups marked as uservisible
++           will be returned. Otherwise, all groups will be returned
++        :param patterns: a list of stings.  If given, only groups
++           with names that match the patterns will be included in the
++           lists.  If not given, all groups will be included
++        :param ignore_case: whether to ignore case when determining
++           whether group names match the strings in *patterns*
++        """
+         installed = []
+         available = []
+ 
+@@ -2852,8 +3078,13 @@ class YumBase(depsolve.Depsolve):
+     
+     
+     def groupRemove(self, grpid):
+-        """mark all the packages in this group to be removed"""
+-        
++        """Mark all the packages in the given group to be removed.
++
++        :param grpid: the name of the group containing the packages to
++           mark for removal
++        :return: a list of transaction members added to the
++           transaction set by this function
++        """
+         txmbrs_used = []
+         
+         thesegroups = self.comps.return_groups(grpid)
+@@ -2872,9 +3103,10 @@ class YumBase(depsolve.Depsolve):
+         return txmbrs_used
+ 
+     def groupUnremove(self, grpid):
+-        """unmark any packages in the group from being removed"""
+-        
++        """Unmark any packages in the given group from being removed.
+ 
++        :param grpid: the name of the group to unmark the packages of
++        """
+         thesegroups = self.comps.return_groups(grpid)
+         if not thesegroups:
+             raise Errors.GroupsError, _("No Group named %s exists") % to_unicode(grpid)
+@@ -2899,12 +3131,16 @@ class YumBase(depsolve.Depsolve):
+         
+         
+     def selectGroup(self, grpid, group_package_types=[], enable_group_conditionals=None):
+-        """mark all the packages in the group to be installed
+-           returns a list of transaction members it added to the transaction 
+-           set
+-           Optionally take:
+-           group_package_types=List - overrides self.conf.group_package_types
+-           enable_group_conditionals=Bool - overrides self.conf.enable_group_conditionals
++        """Mark all the packages in the given group to be installed.
++
++        :param grpid: the name of the group containing the packages to
++           mark for installation
++        :param group_package_types: a list of the types of groups to
++           work with.  This overrides self.conf.group_package_types
++        :param enable_group_conditionals: overrides
++           self.conf.enable_group_conditionals
++        :return: a list of transaction members added to the
++           transaction set by this function
+         """
+ 
+         if not self.comps.has_group(grpid):
+@@ -2939,7 +3175,7 @@ class YumBase(depsolve.Depsolve):
+                 self.verbose_logger.log(logginglevels.DEBUG_2,
+                     _('Adding package %s from group %s'), pkg, thisgroup.groupid)
+                 try:
+-                    txmbrs = self.install(name = pkg)
++                    txmbrs = self.install(name=pkg, pkg_warning_level='debug2')
+                 except Errors.InstallError, e:
+                     self.verbose_logger.debug(_('No package named %s available to be installed'),
+                         pkg)
+@@ -2997,10 +3233,14 @@ class YumBase(depsolve.Depsolve):
+         return txmbrs_used
+ 
+     def deselectGroup(self, grpid, force=False):
+-        """ Without the force option set, this removes packages from being
+-            installed that were added as part of installing one of the
+-            group(s). If the force option is set, then all installing packages
+-            in the group(s) are force removed from the transaction. """
++        """Unmark the packages in the given group from being
++        installed.
++
++        :param grpid: the name of the group containing the packages to
++           unmark from installation
++        :param force: if True, force remove all the packages in the
++           given group from the transaction
++        """
+         
+         if not self.comps.has_group(grpid):
+             raise Errors.GroupsError, _("No Group named %s exists") % to_unicode(grpid)
+@@ -3035,12 +3275,21 @@ class YumBase(depsolve.Depsolve):
+                             self.tsInfo.remove(pkg.pkgtup)
+         
+     def getPackageObject(self, pkgtup, allow_missing=False):
+-        """retrieves a packageObject from a pkgtuple - if we need
+-           to pick and choose which one is best we better call out
+-           to some method from here to pick the best pkgobj if there are
+-           more than one response - right now it's more rudimentary."""
+-           
+-        
++        """Return a package object that corresponds to the given
++        package tuple.
++
++        :param pkgtup: the package tuple specifying the package object
++           to return
++
++        :param allow_missing: If no package corresponding to the given
++           package tuple can be found, None is returned if
++           *allow_missing* is True, and a :class:`yum.Errors.DepError` is
++           raised if *allow_missing* is False.
++        :return: a package object corresponding to the given package tuple
++        :raises: a :class:`yum.Errors.DepError` if no package
++           corresponding to the given package tuple can be found, and
++           *allow_missing* is False
++        """
+         # look it up in the self.localPackages first:
+         for po in self.localPackages:
+             if po.pkgtup == pkgtup:
+@@ -3049,7 +3298,7 @@ class YumBase(depsolve.Depsolve):
+         pkgs = self.pkgSack.searchPkgTuple(pkgtup)
+ 
+         if len(pkgs) == 0:
+-            self._add_not_found_a(pkgs, pkgtup)
++            self._add_not_found_a(pkgs, pkgtup=pkgtup)
+             if allow_missing: #  This can happen due to excludes after .up has
+                 return None   # happened.
+             raise Errors.DepError, _('Package tuple %s could not be found in packagesack') % str(pkgtup)
+@@ -3065,13 +3314,21 @@ class YumBase(depsolve.Depsolve):
+         return result
+ 
+     def getInstalledPackageObject(self, pkgtup):
+-        """ Returns a YumInstalledPackage object for the pkgtup specified, or
+-            raises an exception. You should use this instead of
+-            searchPkgTuple() if you are assuming there is a value. """
+-
++        """Return a :class:`yum.packages.YumInstalledPackage` object that
++        corresponds to the given package tuple.  This function should
++        be used instead of :func:`searchPkgTuple` if you are assuming
++        that the package object exists.
++
++        :param pkgtup: the package tuple specifying the package object
++           to return
++        :return: a :class:`yum.packages.YumInstalledPackage` object corresponding
++           to the given package tuple
++        :raises: a :class:`yum.Errors.RpmDBError` if the specified package
++           object cannot be found
++        """
+         pkgs = self.rpmdb.searchPkgTuple(pkgtup)
+         if len(pkgs) == 0:
+-            self._add_not_found_i(pkgs, pkgtup)
++            self._add_not_found_i(pkgs, pkgtup=pkgtup)
+             raise Errors.RpmDBError, _('Package tuple %s could not be found in rpmdb') % str(pkgtup)
+ 
+         # Dito. FIXME from getPackageObject() for len() > 1 ... :)
+@@ -3079,9 +3336,11 @@ class YumBase(depsolve.Depsolve):
+         return po
+         
+     def gpgKeyCheck(self):
+-        """checks for the presence of gpg keys in the rpmdb
+-           returns 0 if no keys returns 1 if keys"""
++        """Checks for the presence of GPG keys in the rpmdb.
+ 
++        :return: 0 if there are no GPG keys in the rpmdb, and 1 if
++           there are keys
++        """
+         gpgkeyschecked = self.conf.cachedir + '/.gpgkeyschecked.yum'
+         if os.path.exists(gpgkeyschecked):
+             return 1
+@@ -3106,9 +3365,13 @@ class YumBase(depsolve.Depsolve):
+             return 1
+ 
+     def returnPackagesByDep(self, depstring):
+-        """Pass in a generic [build]require string and this function will 
+-           pass back the packages it finds providing that dep."""
++        """Return a list of package objects that provide the given
++        dependencies. 
+ 
++        :param depstring: a string specifying the dependency to return
++           the packages that fulfil
++        :return: a list of packages that fulfil the given dependency
++        """
+         if not depstring:
+             return []
+ 
+@@ -3135,9 +3398,16 @@ class YumBase(depsolve.Depsolve):
+         return self.pkgSack.getProvides(depname, depflags, depver).keys()
+ 
+     def returnPackageByDep(self, depstring):
+-        """Pass in a generic [build]require string and this function will 
+-           pass back the best(or first) package it finds providing that dep."""
+-        
++        """Return the best, or first, package object that provides the
++        given dependencies.
++
++        :param depstring: a string specifying the dependency to return
++           the package that fulfils
++        :return: the best, or first, package that fulfils the given
++           dependency
++        :raises: a :class:`yum.Errors.YumBaseError` if no packages that
++           fulfil the given dependency can be found
++        """
+         # we get all sorts of randomness here
+         errstring = depstring
+         if type(depstring) not in types.StringTypes:
+@@ -3156,9 +3426,14 @@ class YumBase(depsolve.Depsolve):
+         return result
+ 
+     def returnInstalledPackagesByDep(self, depstring):
+-        """Pass in a generic [build]require string and this function will 
+-           pass back the installed packages it finds providing that dep."""
+-        
++        """Return a list of installed package objects that provide the
++        given dependencies.
++
++        :param depstring: a string specifying the dependency to return
++           the packages that fulfil
++        :return: a list of installed packages that fulfil the given
++           dependency
++        """
+         if not depstring:
+             return []
+ 
+@@ -3202,10 +3477,17 @@ class YumBase(depsolve.Depsolve):
+         return bestlist[0][0]
+ 
+     def bestPackagesFromList(self, pkglist, arch=None, single_name=False):
+-        """Takes a list of packages, returns the best packages.
+-           This function is multilib aware so that it will not compare
+-           multilib to singlelib packages""" 
+-    
++        """Return the best packages from a list of packages.  This
++        function is multilib aware, so that it will not compare
++        multilib to singlelib packages.
++
++        :param pkglist: the list of packages to return the best
++           packages from
++        :param arch: packages will be selected that are compatible
++           with the architecture specified by *arch*
++        :param single_name: whether to return a single package name
++        :return: a list of the best packages from *pkglist*
++        """
+         returnlist = []
+         compatArchList = self.arch.get_arch_list(arch)
+         multiLib = []
+@@ -3438,13 +3720,35 @@ class YumBase(depsolve.Depsolve):
+                 self.tsInfo.probFilterFlags.append(flag)
+ 
+     def install(self, po=None, **kwargs):
+-        """try to mark for install the item specified. Uses provided package 
+-           object, if available. If not it uses the kwargs and gets the best
+-           packages from the keyword options provided 
+-           returns the list of txmbr of the items it installs
+-           
+-           """
++        """Mark the specified item for installation.  If a package
++        object is given, mark it for installation.  Otherwise, mark
++        the best package specified by the key word arguments for
++        installation.
++
++        :param po: a package object to install
++        :param kwargs: if *po* is not specified, these keyword
++           arguments will be used to find the best package to install
++        :return: a list of the transaction members added to the
++           transaction set by this function
++        :raises: :class:`yum.Errors.InstallError` if there is a problem
++           installing the package
++        """
+         
++
++        #  This is kind of hacky, we really need a better way to do errors than
++        # doing them directly from .install/etc. ... but this is easy. *sigh*.
++        #  We are only using this in "groupinstall" atm. ... so we don't have
++        # a long list of "blah already installed." messages when people run
++        # "groupinstall mygroup" in yum-cron etc.
++        pkg_warn = kwargs.get('pkg_warning_level', 'flibble')
++        def _dbg2(*args, **kwargs):
++            self.verbose_logger.log(logginglevels.DEBUG_2, *args, **kwargs)
++        level2func = {'debug2' : _dbg2,
++                      'warning' : self.verbose_logger.warning}
++        if pkg_warn not in level2func:
++            pkg_warn = 'warning'
++        pkg_warn = level2func[pkg_warn]
++
+         pkgs = []
+         was_pattern = False
+         if po:
+@@ -3600,23 +3904,23 @@ class YumBase(depsolve.Depsolve):
+                     already_obs = pkgs[0]
+ 
+                 if already_obs:
+-                    self.verbose_logger.warning(_('Package %s is obsoleted by %s which is already installed'), 
+-                                                po, already_obs)
++                    pkg_warn(_('Package %s is obsoleted by %s which is already installed'), 
++                             po, already_obs)
+                 else:
+                     if 'provides_for' in kwargs:
+                         if not obsoleting_pkg.provides_for(kwargs['provides_for']):
 -                            self.verbose_logger.warning(_('Package %s is obsoleted by %s, but obsoleting package does not provide for requirements'),
 -                                                  po.name, obsoleting_pkg.name)
 +                            pkg_warn(_('Package %s is obsoleted by %s, but obsoleting package does not provide for requirements'),
@@ -5051,7 +6581,7 @@ index 99039e0..530bfd4 100644
                      continue
  
              # make sure we don't have a name.arch of this already installed
-@@ -3630,7 +3651,7 @@ class YumBase(depsolve.Depsolve):
+@@ -3630,7 +3934,7 @@ class YumBase(depsolve.Depsolve):
                          found = True
                          break
                  if not found:
@@ -5060,7 +6590,268 @@ index 99039e0..530bfd4 100644
                      txmbrs = self.update(po=po)
                      tx_return.extend(txmbrs)
                      continue
-@@ -4725,7 +4746,9 @@ class YumBase(depsolve.Depsolve):
+@@ -3719,14 +4023,33 @@ class YumBase(depsolve.Depsolve):
+         return txmbr
+ 
+     def update(self, po=None, requiringPo=None, update_to=False, **kwargs):
+-        """try to mark for update the item(s) specified. 
+-            po is a package object - if that is there, mark it for update,
+-            if possible
+-            else use **kwargs to match the package needing update
+-            if nothing is specified at all then attempt to update everything
++        """Mark the specified items to be updated.  If a package
++        object is given, mark it.  Else, if a package is specified by
++        the keyword arguments, mark it.  Finally, if nothing is given,
++        mark all installed packages to be updated.
++
++
++        :param po: the package object to be marked for updating
++        :param requiringPo: the package object that requires the
++           upgrade
++        :param update_to: if *update_to* is True, the update will only
++           be run if it will update the given package to the given
++           version.  For example, if the package foo-1-2 is installed,::
++
++             updatePkgs(["foo-1-2], update_to=False)
++           will work identically to::
+             
+-            returns the list of txmbr of the items it marked for update"""
+-        
++             updatePkgs(["foo"])
++           but::
++
++             updatePkgs(["foo-1-2"], update_to=True)
++           
++           will do nothing
++        :param kwargs: if *po* is not given, the names or wildcards in
++           *kwargs* will be used to find the packages to update
++        :return: a list of transaction members added to the
++           transaction set by this function
++        """
+         # check for args - if no po nor kwargs, do them all
+         # if po, do it, ignore all else
+         # if no po do kwargs
+@@ -3985,11 +4308,18 @@ class YumBase(depsolve.Depsolve):
+         return tx_return
+         
+     def remove(self, po=None, **kwargs):
+-        """try to find and mark for remove the specified package(s) -
+-            if po is specified then that package object (if it is installed) 
+-            will be marked for removal.
+-            if no po then look at kwargs, if neither then raise an exception"""
+-
++        """Mark the specified packages for removal. If a package
++        object is given, mark it for removal.  Otherwise, mark the
++        package specified by the keyword arguments.
++
++        :param po: the package object to mark for installation
++        :param kwargs: If *po* is not given, the keyword arguments
++           will be used to specify a package to mark for installation
++        :return: a list of the transaction members that were added to
++           the transaction set by this method
++        :raises: :class:`yum.Errors.RemoveError` if nothing is specified
++           to mark for removal
++        """
+         if not po and not kwargs:
+             raise Errors.RemoveError, 'Nothing specified to remove'
+         
+@@ -4055,17 +4385,19 @@ class YumBase(depsolve.Depsolve):
+         return tx_return
+ 
+     def installLocal(self, pkg, po=None, updateonly=False):
++        """Mark a package on the local filesystem (i.e. not from a
++        repository) for installation. 
++        
++        :param pkg: a string specifying the path to an rpm file in the
++           local filesystem to be marked for installation
++        :param po: a :class:`yum.packages.YumLocalPackage` 
++        :param updateonly: if True, the given package will only be
++           marked for installation if it is an upgrade for a package
++           that is already installed.  If False, this restriction is
++           not enforced
++        :return: a list of the transaction members added to the
++           transaction set by this method
+         """
+-        handles installs/updates of rpms provided on the filesystem in a
+-        local dir (ie: not from a repo)
+-
+-        Return the added transaction members.
+-
+-        @param pkg: a path to an rpm file on disk.
+-        @param po: A YumLocalPackage
+-        @param updateonly: Whether or not true installs are valid.
+-        """
+-
+         # read in the package into a YumLocalPackage Object
+         # append it to self.localPackages
+         # check if it can be installed or updated based on nevra versus rpmdb
+@@ -4183,16 +4515,15 @@ class YumBase(depsolve.Depsolve):
+         return tx_return
+ 
+     def reinstallLocal(self, pkg, po=None):
++        """Mark a package on the local filesystem (i.e. not from a
++        repository) for reinstallation. 
++        
++        :param pkg: a string specifying the path to an rpm file in the
++           local filesystem to be marked for reinstallation
++        :param po: a :class:`yum.packages.YumLocalPackage` 
++        :return: a list of the transaction members added to the
++           transaction set by this method
+         """
+-        handles reinstall of rpms provided on the filesystem in a
+-        local dir (ie: not from a repo)
+-
+-        Return the added transaction members.
+-
+-        @param pkg: a path to an rpm file on disk.
+-        @param po: A YumLocalPackage
+-        """
+-
+         if not po:
+             try:
+                 po = YumUrlPackage(self, ts=self.rpmdb.readOnlyTS(), url=pkg,
+@@ -4215,9 +4546,19 @@ class YumBase(depsolve.Depsolve):
+         return self.reinstall(po=po)
+ 
+     def reinstall(self, po=None, **kwargs):
+-        """Setup the problem filters to allow a reinstall to work, then
+-           pass everything off to install"""
+-           
++        """Mark the given package for reinstallation.  This is
++        accomplished by setting problem filters to allow a reinstall
++        take place, then calling :func:`install`.
++
++        :param po: the package object to mark for reinstallation
++        :param kwargs: if po is not given, the keyword will be used to
++           specify a package for reinstallation
++        :return: a list of the transaction members added to the
++           transaction set by this method
++        :raises: :class:`yum.Errors.ReinstallRemoveError` or
++           :class:`yum.Errors.ReinstallInstallError` depending the nature
++           of the error that is encountered
++        """
+         self._add_prob_flags(rpm.RPMPROB_FILTER_REPLACEPKG,
+                              rpm.RPMPROB_FILTER_REPLACENEWFILES,
+                              rpm.RPMPROB_FILTER_REPLACEOLDFILES)
+@@ -4259,16 +4600,15 @@ class YumBase(depsolve.Depsolve):
+         return tx_mbrs
+         
+     def downgradeLocal(self, pkg, po=None):
++        """Mark a package on the local filesystem (i.e. not from a
++        repository) to be downgraded.
++        
++        :param pkg: a string specifying the path to an rpm file in the
++           local filesystem to be marked to be downgraded
++        :param po: a :class:`yum.packages.YumLocalPackage` 
++        :return: a list of the transaction members added to the
++           transaction set by this method
+         """
+-        handles downgrades of rpms provided on the filesystem in a
+-        local dir (ie: not from a repo)
+-
+-        Return the added transaction members.
+-
+-        @param pkg: a path to an rpm file on disk.
+-        @param po: A YumLocalPackage
+-        """
+-
+         if not po:
+             try:
+                 po = YumUrlPackage(self, ts=self.rpmdb.readOnlyTS(), url=pkg,
+@@ -4309,13 +4649,19 @@ class YumBase(depsolve.Depsolve):
+         return False
+         
+     def downgrade(self, po=None, **kwargs):
+-        """ Try to downgrade a package. Works like:
+-            % yum shell <<EOL
+-            remove  abcd
+-            install abcd-<old-version>
+-            run
+-            EOL """
+-
++        """Mark a package to be downgraded.  This is equivalent to
++        first removing the currently installed package, and then
++        installing the older version.
++
++        :param po: the package object to be marked to be downgraded
++        :param kwargs: if a package object is not given, the keyword
++           arguments will be used to specify a package to be marked to
++           be downgraded
++        :return: a list of the transaction members added to the
++           transaction set by this method
++        :raises: :class:`yum.Errors.DowngradeError` if no packages are
++           specified or available for downgrade
++        """
+         if not po and not kwargs:
+             raise Errors.DowngradeError, 'Nothing specified to downgrade'
+ 
+@@ -4501,8 +4847,14 @@ class YumBase(depsolve.Depsolve):
+         return returndict
+ 
+     def history_redo(self, transaction):
+-        """ Given a valid historical transaction object, try and repeat
+-            that transaction. """
++        """Repeat the transaction represented by the given
++        :class:`yum.history.YumHistoryTransaction` object.
++
++        :param transaction: a
++           :class:`yum.history.YumHistoryTransaction` object
++           representing the transaction to be repeated
++        :return: whether the transaction was repeated successfully
++        """
+         # NOTE: This is somewhat basic atm. ... see comment in undo.
+         #  Also note that redo doesn't force install Dep-Install packages,
+         # which is probably what is wanted the majority of the time.
+@@ -4538,8 +4890,14 @@ class YumBase(depsolve.Depsolve):
+         return done
+ 
+     def history_undo(self, transaction):
+-        """ Given a valid historical transaction object, try and undo
+-            that transaction. """
++        """Undo the transaction represented by the given
++        :class:`yum.history.YumHistoryTransaction` object.
++
++        :param transaction: a
++           :class:`yum.history.YumHistoryTransaction` object
++           representing the transaction to be undone
++        :return: whether the transaction was undone successfully
++        """
+         # NOTE: This is somewhat basic atm. ... for instance we don't check
+         #       that we are going from the old new version. However it's still
+         #       better than the RHN rollback code, and people pay for that :).
+@@ -4689,19 +5047,18 @@ class YumBase(depsolve.Depsolve):
+         self.logger.critical("%s", msg)
+ 
+     def getKeyForPackage(self, po, askcb = None, fullaskcb = None):
+-        """
+-        Retrieve a key for a package. If needed, prompt for if the key should
+-        be imported using askcb.
+-        
+-        @param po: Package object to retrieve the key of.
+-        @param askcb: Callback function to use for asking for permission to
+-                      import a key. This is verification, but also "choice".
+-                      Takes arguments of the po, the userid for the key, and
+-                      the keyid.
+-        @param fullaskcb: Callback function to use for asking for permission to
+-                          import a key. This is verification, but also "choice".
+-                          Differs from askcb in that it gets passed a
+-                          dictionary so that we can expand the values passed.
++        """Retrieve a key for a package. If needed, use the given
++        callback to prompt whether the key should be imported.
++
++        :param po: the package object to retrieve the key of
++        :param askcb: Callback function to use to ask permission to
++           import a key.  The arguments *askck* should take are the
++           package object, the userid of the key, and the keyid
++        :param fullaskcb: Callback function to use to ask permission to
++           import a key.  This differs from *askcb* in that it gets
++           passed a dictionary so that we can expand the values passed.
++        :raises: :class:`yum.Errors.YumBaseError` if there are errors
++           retrieving the keys
+         """
+         repo = self.repos.getRepo(po.repoid)
+         keyurls = repo.gpgkey
+@@ -4725,7 +5082,9 @@ class YumBase(depsolve.Depsolve):
                      # Try installing/updating GPG key
                      self._getKeyImportMessage(info, keyurl)
                      rc = False
@@ -5071,7 +6862,7 @@ index 99039e0..530bfd4 100644
                          rc = True
                          
                      # grab the .sig/.asc for the keyurl, if it exists
-@@ -4819,8 +4842,11 @@ class YumBase(depsolve.Depsolve):
+@@ -4819,8 +5178,11 @@ class YumBase(depsolve.Depsolve):
                  if not key_installed:
                      self._getKeyImportMessage(info, keyurl, keytype)
                      rc = False
@@ -5084,7 +6875,156 @@ index 99039e0..530bfd4 100644
                      elif callback:
                          rc = callback({"repo": repo, "userid": info['userid'],
                                          "hexkeyid": info['hexkeyid'], "keyurl": keyurl,
-@@ -5234,7 +5260,7 @@ class YumBase(depsolve.Depsolve):
+@@ -4861,26 +5223,23 @@ class YumBase(depsolve.Depsolve):
+                   'this repository.') % (repo.name)
+ 
+     def getKeyForRepo(self, repo, callback=None):
+-        """
+-        Retrieve a key for a repository If needed, prompt for if the key should
+-        be imported using callback
+-        
+-        @param repo: Repository object to retrieve the key of.
+-        @param callback: Callback function to use for asking for verification
+-                          of a key. Takes a dictionary of key info.
++        """Retrieve a key for a repository.  If needed, use the given
++        callback to prompt whether the key should be imported.
++
++        :param repo: repository object to retrieve the key of
++        :param callback: callback function to use for asking for
++           verification of key information
+         """
+         self._getAnyKeyForRepo(repo, repo.gpgdir, repo.gpgkey, is_cakey=False, callback=callback)
+ 
+     def getCAKeyForRepo(self, repo, callback=None):
+-        """
+-        Retrieve a key for a repository If needed, prompt for if the key should
+-        be imported using callback
+-        
+-        @param repo: Repository object to retrieve the key of.
+-        @param callback: Callback function to use for asking for verification
+-                          of a key. Takes a dictionary of key info.
+-        """
++        """Retrieve a key for a repository.  If needed, use the given
++        callback to prompt whether the key should be imported.
+ 
++        :param repo: repository object to retrieve the key of
++        :param callback: callback function to use for asking for
++           verification of key information
++        """
+         self._getAnyKeyForRepo(repo, repo.gpgcadir, repo.gpgcakey, is_cakey=True, callback=callback)
+ 
+     def _limit_installonly_pkgs(self):
+@@ -4959,19 +5318,22 @@ class YumBase(depsolve.Depsolve):
+             txmbr.depends_on.append(rel)
+ 
+     def processTransaction(self, callback=None,rpmTestDisplay=None, rpmDisplay=None):
+-        '''
+-        Process the current Transaction
+-        - Download Packages
+-        - Check GPG Signatures.
+-        - Run Test RPM Transaction
+-        - Run RPM Transaction
+-        
+-        callback.event method is called at start/end of each process.
+-        
+-        @param callback: callback object (must have an event method)
+-        @param rpmTestDisplay: Name of display class to use in RPM Test Transaction 
+-        @param rpmDisplay: Name of display class to use in RPM Transaction 
+-        '''
++        """Process the current transaction.  This involves the
++        following steps:
++          - Download the packages
++          - Check the GPG signatures of the packages
++          - Run the test RPM transaction
++          - Run the RPM Transaction
++        The *callback*.event method is called at the start, and
++        between each step.
++
++        :param callback: a callback object, which must have an event
++           method
++        :param rpmTestDisplay: name of the display class to use in the
++           RPM test transaction
++        :param rpmDisplay: name of the display class to use in the rpm
++           transaction
++        """
+         
+         if not callback:
+             callback = callbacks.ProcessTransNoOutputCallback()
+@@ -5114,13 +5476,19 @@ class YumBase(depsolve.Depsolve):
+         return results
+ 
+     def add_enable_repo(self, repoid, baseurls=[], mirrorlist=None, **kwargs):
+-        """add and enable a repo with just a baseurl/mirrorlist and repoid
+-           requires repoid and at least one of baseurl and mirrorlist
+-           additional optional kwargs are:
+-           variable_convert=bool (defaults to true)
+-           and any other attribute settable to the normal repo setup
+-           ex: metadata_expire, enable_groups, gpgcheck, cachedir, etc
+-           returns the repo object it added"""
++        """Add and enable a repository.
++
++        :param repoid: a string specifying the name of the repository
++        :param baseurls: a list of strings specifying the urls for
++           the repository.  At least one base url, or one mirror, must
++           be given
++        :param mirrorlist: a list of strings specifying a list of
++           mirrors for the repository.  At least one base url, or one
++           mirror must be given
++        :param kwargs: key word arguments to set any normal repository
++           attribute
++        :return: the new repository that has been added and enabled
++        """
+         # out of place fixme - maybe we should make this the default repo addition
+         # routine and use it from getReposFromConfigFile(), etc.
+         newrepo = yumRepo.YumRepository(repoid)
+@@ -5167,9 +5535,15 @@ class YumBase(depsolve.Depsolve):
+ 
+     def setCacheDir(self, force=False, tmpdir=None, reuse=True,
+                     suffix='/$basearch/$releasever'):
+-        ''' Set a new cache dir, using misc.getCacheDir() and var. replace
+-            on suffix. '''
+-
++        """Set a new cache directory.
++
++        :param force: whether to force the cache directory to be
++           changed
++        :param tmpdir: a temporary directory
++        :param reuse: whether the temporary directory can be reused
++        :param suffix: suffix to attach to the directory name
++        :return: whether the new cache directory is successfully set
++        """
+         if not force and os.geteuid() == 0:
+             return True # We are root, not forced, so happy with the global dir.
+         if tmpdir is None:
+@@ -5220,13 +5594,24 @@ class YumBase(depsolve.Depsolve):
+         self.history.write_addon_data('config-repos', myrepos)
+         
+     def verify_plugins_cb(self, verify_package):
+-        """ Callback to call a plugin hook for pkg.verify(). """
++        """Callback to call a plugin hook for pkg.verify().
++
++        :param verify_package: a conduit for the callback
++        :return: *verify_package*
++        """
+         self.plugins.run('verify_package', verify_package=verify_package)
+         return verify_package
+ 
+     def save_ts(self, filename=None, auto=False):
+-        """saves out a transaction to .yumtx file to be loaded later"""
+-        
++        """Save out a transaction to a .yumtx file to be loaded later.
++
++        :param filename: the name of the file to save the transaction
++           in.  If *filename* is not given, a name will be generated
++        :param auto: whether to output errors to the logger, rather
++           than raising exceptions
++        :raises: :class:`yum.Errors.YumBaseError` if there are errors
++           saving the transaction
++        """
+         if self.tsInfo._unresolvedMembers:
+             if auto:
+                 self.logger.critical(_("Dependencies not solved. Will not save unresolved transaction."))
+@@ -5234,7 +5619,7 @@ class YumBase(depsolve.Depsolve):
              raise Errors.YumBaseError(_("Dependencies not solved. Will not save unresolved transaction."))
          
          if not filename:
@@ -5093,7 +7033,26 @@ index 99039e0..530bfd4 100644
              fd,filename = tempfile.mkstemp(suffix='.yumtx', prefix=prefix)
              f = os.fdopen(fd, 'w')
          else:
-@@ -5292,6 +5318,16 @@ class YumBase(depsolve.Depsolve):
+@@ -5266,7 +5651,17 @@ class YumBase(depsolve.Depsolve):
+ 
+         
+     def load_ts(self, filename, ignorerpm=None, ignoremissing=None):
+-        """loads a transaction from a .yumtx file"""
++        """Load a transaction from a .yumtx file.
++
++        :param filename: the name of the file to load the transaction
++           from
++        :param ignorerpm: whether to ignore messages from rpm
++        :param ignoremissing: whether to ignore that there may be
++           transaction members missing
++        :return: the members of the loaded transaction
++        :raises: :class:`yum.Errors.YumBaseError` if there are problems
++           loading the transaction
++        """
+         # check rpmversion - if not match throw a fit
+         # check repoversions  (and repos)- if not match throw a fit
+         # load each txmbr - if pkgs being updated don't exist, bail w/error
+@@ -5292,6 +5687,16 @@ class YumBase(depsolve.Depsolve):
          # 3+numrepos = num pkgs
          # 3+numrepos+1 -> EOF= txmembers
          
@@ -5258,7 +7217,7 @@ index 7ad25ce..a9a8e53 100644
          pass
          
 diff --git a/yum/config.py b/yum/config.py
-index d09511f..bbeca66 100644
+index d09511f..ef1b9e1 100644
 --- a/yum/config.py
 +++ b/yum/config.py
 @@ -47,13 +47,12 @@ __pkgs_gpgcheck_default__ = False
@@ -5719,11 +7678,11 @@ index d09511f..bbeca66 100644
 -        Invalid inputs: -10, -0.1, 45.6L, 123Mb
 -
 -        Return value will always be an integer
+-
+-        1k = 1024 bytes.
 +        Valid inputs: 100, 123M, 45.6k, 12.4G, 100K, 786.3, 0.
 +        Invalid inputs: -10, -0.1, 45.6L, 123Mb.
  
--        1k = 1024 bytes.
--
 -        ValueError will be raised if the option couldn't be parsed.
 +        :param s: the string to parse
 +        :return: the number of bytes represented by *s*
@@ -5952,7 +7911,25 @@ index d09511f..bbeca66 100644
      alwaysprompt = BoolOption(True)
      exactarch = BoolOption(True)
      tolerant = BoolOption(True)
-@@ -756,6 +845,12 @@ class YumConf(StartupConf):
+@@ -686,6 +775,9 @@ class YumConf(StartupConf):
+ 
+     bandwidth = BytesOption(0)
+     throttle = ThrottleOption(0)
++    ip_resolve = CaselessSelectionOption(
++            allowed = ('ipv4', 'ipv6', 'whatever'),
++            mapper  = {'4': 'ipv4', '6': 'ipv6'})
+ 
+     http_caching = SelectionOption('all', ('none', 'packages', 'all'))
+     metadata_expire = SecondsOption(60 * 60 * 6) # Time in seconds (6h).
+@@ -747,6 +839,7 @@ class YumConf(StartupConf):
+     
+     clean_requirements_on_remove = BoolOption(False)
+ 
++    upgrade_requirements_on_install = BoolOption(False)
+ 
+     history_list_view = SelectionOption('single-user-commands',
+                                         ('single-user-commands', 'users',
+@@ -756,6 +849,12 @@ class YumConf(StartupConf):
      _reposlist = []
  
      def dump(self):
@@ -5965,7 +7942,7 @@ index d09511f..bbeca66 100644
          output = '[main]\n'
          # we exclude all vars which start with _ or are in this list:
          excluded_vars = ('cfg', 'uid', 'yumvar', 'progress_obj', 'failure_obj',
-@@ -778,14 +873,12 @@ class YumConf(StartupConf):
+@@ -778,14 +877,12 @@ class YumConf(StartupConf):
          return output
  
  class RepoConf(BaseConfig):
@@ -5983,7 +7960,16 @@ index d09511f..bbeca66 100644
          ck = self.__cached_keys
          if not isinstance(self, RepoConf):
              ck = set()
-@@ -839,23 +932,23 @@ class RepoConf(BaseConfig):
+@@ -823,6 +920,8 @@ class RepoConf(BaseConfig):
+     bandwidth = Inherit(YumConf.bandwidth)
+     throttle = Inherit(YumConf.throttle)
+     timeout = Inherit(YumConf.timeout)
++    ip_resolve = Inherit(YumConf.ip_resolve)
++
+     http_caching = Inherit(YumConf.http_caching)
+     metadata_expire = Inherit(YumConf.metadata_expire)
+     mirrorlist_expire = Inherit(YumConf.mirrorlist_expire)
+@@ -839,23 +938,23 @@ class RepoConf(BaseConfig):
      skip_if_unavailable = BoolOption(False)
      
  class VersionGroupConf(BaseConfig):
@@ -5993,12 +7979,13 @@ index d09511f..bbeca66 100644
      run_with_packages = BoolOption(False)
  
  
- def readStartupConfig(configfile, root):
+-def readStartupConfig(configfile, root):
 -    '''
 -    Parse Yum's main configuration file and return a StartupConf instance.
 -    
 -    This is required in order to access configuration settings required as Yum
 -    starts up.
++def readStartupConfig(configfile, root, releasever=None):
 +    """Parse Yum's main configuration file and return a
 +    :class:`StartupConf` instance.  This is required in order to
 +    access configuration settings required as Yum starts up.
@@ -6017,7 +8004,21 @@ index d09511f..bbeca66 100644
  
      # ' xemacs syntax hack
  
-@@ -884,12 +977,11 @@ def readStartupConfig(configfile, root):
+@@ -876,20 +975,24 @@ def readStartupConfig(configfile, root):
+             raise Errors.ConfigError("All plugin search paths must be absolute")
+     # Stuff this here to avoid later re-parsing
+     startupconf._parser = parser
++
+     # setup the release ver here
+-    startupconf.releasever = _getsysver(startupconf.installroot, startupconf.distroverpkg)
++    if releasever is None:
++        releasever = _getsysver(startupconf.installroot,
++                                startupconf.distroverpkg)
++    startupconf.releasever = releasever
++
+     uuidfile = '%s/%s/uuid' % (startupconf.installroot, startupconf.persistdir)
+     startupconf.uuid = get_uuid(uuidfile)
+ 
      return startupconf
  
  def readMainConfig(startupconf):
@@ -6034,7 +8035,7 @@ index d09511f..bbeca66 100644
      
      # ' xemacs syntax hack
  
-@@ -956,6 +1048,12 @@ def readMainConfig(startupconf):
+@@ -956,6 +1059,12 @@ def readMainConfig(startupconf):
      return yumconf
  
  def readVersionGroupsConfig(configfile="/etc/yum/version-groups.conf"):
@@ -6047,7 +8048,7 @@ index d09511f..bbeca66 100644
      parser = ConfigParser()
      confpp_obj = ConfigPreProcessor(configfile)
      try:
-@@ -970,17 +1068,16 @@ def readVersionGroupsConfig(configfile="/etc/yum/version-groups.conf"):
+@@ -970,17 +1079,16 @@ def readVersionGroupsConfig(configfile="/etc/yum/version-groups.conf"):
  
  
  def getOption(conf, section, name, option):
@@ -6075,7 +8076,7 @@ index d09511f..bbeca66 100644
      try: 
          val = conf.get(section, name)
      except (NoSectionError, NoOptionError):
-@@ -1028,7 +1125,10 @@ def _getsysver(installroot, distroverpkg):
+@@ -1028,7 +1136,10 @@ def _getsysver(installroot, distroverpkg):
      if idx.count() == 0:
          releasever = '$releasever'
      else:
@@ -6087,7 +8088,7 @@ index d09511f..bbeca66 100644
          releasever = hdr['version']
          del hdr
      del idx
-@@ -1036,13 +1136,12 @@ def _getsysver(installroot, distroverpkg):
+@@ -1036,13 +1147,12 @@ def _getsysver(installroot, distroverpkg):
      return releasever
  
  def writeRawRepoFile(repo,only=None):
@@ -6106,7 +8107,7 @@ index d09511f..bbeca66 100644
      if not _use_iniparse:
          return
  
-@@ -1069,7 +1168,7 @@ def writeRawRepoFile(repo,only=None):
+@@ -1069,7 +1179,7 @@ def writeRawRepoFile(repo,only=None):
          #  If the value is the same, but just interpreted ... when we don't want
          # to keep the interpreted values.
          if (name in ini[section_id] and
@@ -6463,7 +8464,7 @@ index bca9651..00c17ad 100644
              index = self.failures
          else:
 diff --git a/yum/history.py b/yum/history.py
-index 5385bd1..c91c33a 100644
+index 5385bd1..a9b12cf 100644
 --- a/yum/history.py
 +++ b/yum/history.py
 @@ -97,9 +97,58 @@ def _setupHistorySearchSQL(patterns=None, ignore_case=False):
@@ -6725,7 +8726,7 @@ index 5385bd1..c91c33a 100644
              obj.main = row[6] == 'TRUE'
              ret.append(obj)
          return ret
-@@ -1151,6 +1262,123 @@ class YumHistory:
+@@ -1151,6 +1262,127 @@ class YumHistory:
          assert len(ret) == 1
          return ret[0]
  
@@ -6762,7 +8763,7 @@ index 5385bd1..c91c33a 100644
 +
 +        sql = """INSERT INTO pkg_%(db)sdb (pkgtupid, %(db)sdb_key, %(db)sdb_val)
 +                        VALUES (?, ?, ?)""" % {'db' : db}
-+        executeSQL(cur, sql, (pid, attr, val))
++        executeSQL(cur, sql, (pid, attr, to_unicode(val)))
 +        for row in cur:
 +            return row[0]
 +
@@ -6780,7 +8781,9 @@ index 5385bd1..c91c33a 100644
 +            val = getattr(ipkg, attr, None)
 +            if val is None:
 +                continue
-+            self._save_anydb_key(ipkg, "rpm", attr, val)
++            if not self._save_anydb_key(ipkg, "rpm", attr, val):
++                return False
++        return True
 +
 +    def _save_yumdb(self, ipkg):
 +        """ Save all the data for yumdb for this installed pkg, assumes
@@ -6789,7 +8792,9 @@ index 5385bd1..c91c33a 100644
 +            val = ipkg.yumdb_info.get(attr)
 +            if val is None:
 +                continue
-+            self._save_anydb_key(ipkg, "yum", attr, val)
++            if not self._save_anydb_key(ipkg, "yum", attr, val):
++                return False
++        return True
 +
 +    def _wipe_anydb(self, pkg, db):
 +        """ Delete all the data for rpmdb/yumdb for this installed pkg. """
@@ -6849,7 +8854,7 @@ index 5385bd1..c91c33a 100644
      def _yieldSQLDataList(self, patterns, fields, ignore_case):
          """Yields all the package data for the given params. """
  
-@@ -1220,6 +1448,47 @@ class YumHistory:
+@@ -1220,6 +1452,47 @@ class YumHistory:
              tids.add(row[0])
          return tids
  
@@ -6897,7 +8902,7 @@ index 5385bd1..c91c33a 100644
      _update_ops_2 = ['''\
  \
   CREATE TABLE trans_skip_pkgs (
-@@ -1374,6 +1643,8 @@ class YumHistory:
+@@ -1374,6 +1647,8 @@ class YumHistory:
              cur.execute(op)
          for op in self._update_ops_2:
              cur.execute(op)
@@ -6906,6 +8911,45 @@ index 5385bd1..c91c33a 100644
          self._commit()
  
  # Pasted from sqlitesack
+diff --git a/yum/i18n.py b/yum/i18n.py
+index 9889bf6..85ad15e 100755
+--- a/yum/i18n.py
++++ b/yum/i18n.py
+@@ -462,6 +462,34 @@ def str_eq(a, b):
+     
+     return False
+     
++def exception2msg(e):
++    """Convert an exception to a message.  This function will convert
++    the exception using to_unicode, unicode, or str, whichever works correctly.
++
++    :param e: an exception
++    :return: a string representation of the exception
++    """
++
++    # DIE python DIE! Which one works:
++    # to_unicode(e.value); unicode(e); str(e); 
++    # Call this so you don't have to care.
++    try:
++        return to_unicode(e.value)
++    except:
++        pass
++
++    try:
++        return unicode(e)
++    except:
++        pass
++
++    try:
++        return str(e)
++    except:
++        pass
++    return "<exception failed to convert to text>"
++
++
+ try: 
+     '''
+     Setup the yum translation domain and make _() and P_() translation wrappers
 diff --git a/yum/misc.py b/yum/misc.py
 index 2f6ddfe..37c572b 100644
 --- a/yum/misc.py
@@ -7023,8 +9067,518 @@ index 5ef9951..f72c068 100644
          self.__mode_cache = {}
          self.__prcoPopulated = False
  
+diff --git a/yum/plugins.py b/yum/plugins.py
+index bfc49b7..9ddcae6 100644
+--- a/yum/plugins.py
++++ b/yum/plugins.py
+@@ -66,9 +66,9 @@ from yum.i18n import utf8_width
+ API_VERSION = '2.6'
+ 
+ class DeprecatedInt(int):
+-    '''
+-    A simple int subclass that used to check when a deprecated constant is used.
+-    '''
++    """A simple int subclass that is used to check when a deprecated
++    constant is used.
++    """
+ 
+ # Plugin types
+ TYPE_CORE = 0
+@@ -105,8 +105,8 @@ SLOT_TO_CONDUIT = {
+ SLOTS = sorted(SLOT_TO_CONDUIT.keys())
+ 
+ class PluginYumExit(Exception):
+-    '''Used by plugins to signal that yum should stop
+-    '''
++    """Exception that can be raised by plugins to signal that yum should stop."""
++
+     def __init__(self, value="", translation_domain=""):
+         self.value = value
+         self.translation_domain = translation_domain
+@@ -117,9 +117,7 @@ class PluginYumExit(Exception):
+             return self.value
+     
+ class YumPlugins:
+-    '''
+-    Manager class for Yum plugins.
+-    '''
++    """Manager class for Yum plugins."""
+ 
+     def __init__(self, base, searchpath, optparser=None, types=None, 
+             pluginconfpath=None,disabled=None,enabled=None):
+@@ -167,8 +165,13 @@ class YumPlugins:
+         self.run('config')
+ 
+     def run(self, slotname, **kwargs):
+-        '''Run all plugin functions for the given slot.
+-        '''
++        """Run all plugin functions for the given slot.
++
++        :param slotname: a string representing the name of the slot to
++           run the plugins for
++        :param kwargs: keyword arguments that will be simply passed on
++           to the plugins
++        """
+         # Determine handler class to use
+         conduitcls = SLOT_TO_CONDUIT.get(slotname, None)
+         if conduitcls is None:
+@@ -356,23 +359,35 @@ class YumPlugins:
+         return parser
+ 
+     def setCmdLine(self, opts, commands):
+-        '''Set the parsed command line options so that plugins can access them
+-        '''
++        """Set the parsed command line options so that plugins can
++        access them.
++
++        :param opts: a dictionary containing the values of the command
++           line options
++        :param commands: a list of command line arguments passed to yum
++        """
+         self.cmdline = (opts, commands)
+ 
+ 
+ class DummyYumPlugins:
+-    '''
+-    This class provides basic emulation of the YumPlugins class. It exists so
+-    that calls to plugins.run() don't fail if plugins aren't in use.
+-    '''
++    """This class provides basic emulation of the :class:`YumPlugins`
++    class. It exists so that calls to plugins.run() don't fail if
++    plugins aren't in use.
++    """
+     def run(self, *args, **kwargs):
++        """Do nothing.  All arguments are unused."""
++
+         pass
+ 
+     def setCmdLine(self, *args, **kwargs):
++        """Do nothing.  All arguments are unused."""
++
+         pass
+ 
+ class PluginConduit:
++    """A conduit class to transfer information between yum and the
++    plugin.
++    """
+     def __init__(self, parent, base, conf):
+         self._parent = parent
+         self._base = base
+@@ -382,14 +397,30 @@ class PluginConduit:
+         self.verbose_logger = logging.getLogger("yum.verbose.plugin")
+ 
+     def info(self, level, msg):
++        """Send an info message to the logger.
++
++        :param level: the level of the message to send
++        :param msg: the message to send
++        """
+         converted_level = logginglevels.logLevelFromDebugLevel(level)
+         self.verbose_logger.log(converted_level, msg)
+ 
+     def error(self, level, msg):
++        """Send an error message to the logger.
++
++        :param level: the level of the message to send
++        :param msg: the message to send
++        """
+         converted_level = logginglevels.logLevelFromErrorLevel(level)
+         self.logger.log(converted_level, msg)
+ 
+     def promptYN(self, msg):
++        """Return a yes or no response, either from assumeyes already
++        being set, or from prompting the user.
++
++        :param msg: the message to prompt the user with
++        :return: 1 if the response is yes, and 0 if the response is no
++        """
+         self.info(2, msg)
+         if self._base.conf.assumeyes:
+             return 1
+@@ -397,88 +428,96 @@ class PluginConduit:
+             return self._base.userconfirm()
+ 
+     def getYumVersion(self):
++        """Return a string representing the current version of yum."""
++
+         import yum
+         return yum.__version__
+ 
+     def getOptParser(self):
+-        '''Return the optparse.OptionParser instance for this execution of Yum
+-
+-        In the "config" and "init" slots a plugin may add extra options to this
+-        instance to extend the command line options that Yum exposes.
+-
+-        In all other slots a plugin may only read the OptionParser instance.
+-        Any modification of the instance at this point will have no effect. 
+-        
+-        See the getCmdLine() method for details on how to retrieve the parsed
+-        values of command line options.
+-
+-        @return: the global optparse.OptionParser instance used by Yum. May be
+-            None if an OptionParser isn't in use.
+-        '''
++        """Return the :class:`optparse.OptionParser` instance for this
++        execution of Yum.  In the "config" and "init" slots a plugin
++        may add extra options to this instance to extend the command
++        line options that Yum exposes.  In all other slots a plugin
++        may only read the :class:`OptionParser` instance.  Any
++        modification of the instance at this point will have no
++        effect.  See the
++        :func:`PreRepoSetupPluginConduit.getCmdLine` method for
++        details on how to retrieve the parsed values of command line
++        options.
++
++        :return: the global :class:`optparse.OptionParser` instance used by
++           Yum. May be None if an OptionParser isn't in use
++        """
+         # ' xemacs highlighting hack
+         # This isn't API compatible :(
+         # return self._parent.optparser.plugin_option_group
+         return self._parent.optparser
+ 
+     def confString(self, section, opt, default=None):
+-        '''Read a string value from the plugin's own configuration file
++        """Read a string value from the plugin's own configuration file.
+ 
+-        @param section: Configuration file section to read.
+-        @param opt: Option name to read.
+-        @param default: Value to read if option is missing.
+-        @return: String option value read, or default if option was missing.
+-        '''
++        :param section: configuration file section to read
++        :param opt: option name to read
++        :param default: value to read if the option is missing
++        :return: string option value read, or default if option was missing
++        """
+         # ' xemacs highlighting hack
+         return config.getOption(self._conf, section, opt, config.Option(default))
+ 
+     def confInt(self, section, opt, default=None):
+-        '''Read an integer value from the plugin's own configuration file
++        """Read an integer value from the plugin's own configuration file.
+ 
+-        @param section: Configuration file section to read.
+-        @param opt: Option name to read.
+-        @param default: Value to read if option is missing.
+-        @return: Integer option value read, or default if option was missing or
+-            could not be parsed.
+-        '''
++        :param section: configuration file section to read
++        :param opt: option name to read
++        :param default: value to read if the option is missing
++
++        :return: the integer option value read, or *default* if the
++            option was missing or could not be parsed
++        """
+         return config.getOption(self._conf, section, opt, config.IntOption(default))
+ 
+     def confFloat(self, section, opt, default=None):
+-        '''Read a float value from the plugin's own configuration file
+-
+-        @param section: Configuration file section to read.
+-        @param opt: Option name to read.
+-        @param default: Value to read if option is missing.
+-        @return: Float option value read, or default if option was missing or
+-            could not be parsed.
+-        '''
++        """Read a float value from the plugin's own configuration file.
++
++        :param section: configuration file section to read
++        :param opt: option name to read
++        :param default: value to read if the option is missing
++        :return: float option value read, or *default* if the option was
++            missing or could not be parsed
++        """
+         return config.getOption(self._conf, section, opt, config.FloatOption(default))
+ 
+     def confBool(self, section, opt, default=None):
+-        '''Read a boolean value from the plugin's own configuration file
+-
+-        @param section: Configuration file section to read.
+-        @param opt: Option name to read.
+-        @param default: Value to read if option is missing.
+-        @return: Boolean option value read, or default if option was missing or
+-            could not be parsed.
+-        '''
++        """Read a boolean value from the plugin's own configuration file
++
++        :param section: configuration file section to read
++        :param opt: option name to read
++        :param default: value to read if the option is missing
++        :return: boolean option value read, or *default* if the option
++            was missing or could not be parsed
++        """
+         return config.getOption(self._conf, section, opt, config.BoolOption(default))
+ 
+     def registerPackageName(self, name):
++        """Register the name of a package to use.
++
++        :param name: the name of the package to register
++        """
+         self._base.run_with_package_names.add(name)
+ 
+ 
+ class ConfigPluginConduit(PluginConduit):
++    """A conduit for use in the config slot."""
+ 
+     def registerOpt(self, name, valuetype, where, default):
+-        '''Register a yum configuration file option.
+-
+-        @param name: Name of the new option.
+-        @param valuetype: Option type (PLUG_OPT_BOOL, PLUG_OPT_STRING ...)
+-        @param where: Where the option should be available in the config file.
+-            (PLUG_OPT_WHERE_MAIN, PLUG_OPT_WHERE_REPO, ...)
+-        @param default: Default value for the option if not set by the user.
+-        '''
++        """Deprecated.  Register a yum configuration file option.
++
++        :param name: name of the new option
++        :param valuetype: option type (PLUG_OPT_BOOL, PLUG_OPT_STRING, etc.)
++        :param where: where the option should be available in the config file
++            (PLUG_OPT_WHERE_MAIN, PLUG_OPT_WHERE_REPO, etc)
++        :param default: default value for the option if it is not set by the user
++        """
+         warnings.warn('registerOpt() will go away in a future version of Yum.\n'
+                 'Please manipulate config.YumConf and config.RepoConf directly.',
+                 DeprecationWarning)
+@@ -502,64 +541,93 @@ class ConfigPluginConduit(PluginConduit):
+             setattr(config.RepoConf, name, config.Inherit(option))
+ 
+     def registerCommand(self, command):
++        """Register a new command.
++
++        :param command: the command to register
++        :raises: :class:`yum.Errors.ConfigError` if the registration
++           of commands is not supported
++        """
+         if hasattr(self._base, 'registerCommand'):
+             self._base.registerCommand(command)
+         else:
+             raise Errors.ConfigError(_('registration of commands not supported'))
+ 
+ class PostConfigPluginConduit(ConfigPluginConduit):
++    """Conduit for use in the postconfig slot."""
+ 
+     def getConf(self):
++        """Return a dictionary containing the values of the
++        configuration options.
++
++        :return: a dictionary containing the values of the
++           configuration options
++        """
+         return self._base.conf
+ 
+ class InitPluginConduit(PluginConduit):
++    """Conduit for use in the init slot."""
+ 
+     def getConf(self):
++        """Return a dictionary containing the values of the
++        configuration options.
++
++        :return: a dictionary containing the values of the
++           configuration options
++        """
+         return self._base.conf
+ 
+     def getRepos(self):
+-        '''Return Yum's container object for all configured repositories.
++        """Return Yum's container object for all configured repositories.
+ 
+-        @return: Yum's RepoStorage instance
+-        '''
++        :return: Yum's :class:`yum.repos.RepoStorage` instance
++        """
+         return self._base.repos
+ 
+ class ArgsPluginConduit(InitPluginConduit):
++    """Conduit for dealing with command line arguments."""
+ 
+     def __init__(self, parent, base, conf, args):
+         InitPluginConduit.__init__(self, parent, base, conf)
+         self._args = args
+ 
+     def getArgs(self):
++        """Return a list of the command line arguments passed to yum.
++
++        :return: a list of the command line arguments passed to yum
++        """
+         return self._args
+ 
+ class PreRepoSetupPluginConduit(InitPluginConduit):
++    """Conduit for use in the prererosetup slot."""
++
+ 
+     def getCmdLine(self):
+-        '''Return parsed command line options.
++        """Return parsed command line options.
+ 
+-        @return: (options, commands) as returned by OptionParser.parse_args()
+-        '''
++        :return: (options, commands) as returned by :class:`OptionParser.parse_args()`
++        """
+         return self._parent.cmdline
+ 
+     def getRpmDB(self):
+-        '''Return a representation of local RPM database. This allows querying
+-        of installed packages.
++        """Return a representation of the local RPM database. This
++        allows querying of installed packages.
+ 
+-        @return: rpmUtils.RpmDBHolder instance
+-        '''
++        :return: a :class:`yum.rpmUtils.RpmDBHolder` instance
++        """
+         return self._base.rpmdb
+ 
+ class PostRepoSetupPluginConduit(PreRepoSetupPluginConduit):
++    """Conduit for use in the postreposetup slot."""
+ 
+     def getGroups(self):
+-        '''Return group information.
++        """Return group information.
+ 
+-        @return: yum.comps.Comps instance
+-        '''
++        :return: :class:`yum.comps.Comps` instance
++        """
+         return self._base.comps
+ 
+ class DownloadPluginConduit(PostRepoSetupPluginConduit):
++    """Conduit for use in the download slots."""
+ 
+     def __init__(self, parent, base, conf, pkglist, errors=None):
+         PostRepoSetupPluginConduit.__init__(self, parent, base, conf)
+@@ -567,24 +635,35 @@ class DownloadPluginConduit(PostRepoSetupPluginConduit):
+         self._errors = errors
+ 
+     def getDownloadPackages(self):
+-        '''Return a list of package objects representing packages to be
++        """Return a list of package objects representing packages to be
+         downloaded.
+-        '''
++
++        :return: a list of package object representing packages to be
++           downloaded
++        """
+         return self._pkglist
+ 
+     def getErrors(self):
+-        '''Return a dictionary of download errors. 
++        """Return a dictionary of download errors. 
+         
+-        The returned dictionary is indexed by package object. Each element is a
+-        list of strings describing the error.
+-        '''
++        :return: a dictionary of download errors. This dictionary is
++           indexed by package object. Each element is a list of
++           strings describing the error
++        """
+         if not self._errors:
+             return {}
+         return self._errors
+ 
+ class MainPluginConduit(PostRepoSetupPluginConduit):
+-
++    """Main conduit class for plugins.  Many other conduit classes
++    will inherit from this class.
++    """
+     def getPackages(self, repo=None):
++        """Return a list of packages.
++
++        :param repo: the repo to return a packages from
++        :return: a list of package objects
++        """
+         if repo:
+             arg = repo.id
+         else:
+@@ -592,50 +671,76 @@ class MainPluginConduit(PostRepoSetupPluginConduit):
+         return self._base.pkgSack.returnPackages(arg)
+ 
+     def getPackageByNevra(self, nevra):
+-        '''Retrieve a package object from the packages loaded by Yum using
+-        nevra information 
++        """Retrieve a package object from the packages loaded by Yum using
++        nevra information.
+         
+-        @param nevra: A tuple holding (name, epoch, version, release, arch)
++        :param nevra: a tuple holding (name, epoch, version, release, arch)
+             for a package
+-        @return: A PackageObject instance (or subclass)
+-        '''
++        :return: a :class:`yum.packages.PackageObject` instance (or subclass)
++        """
+         return self._base.getPackageObject(nevra)
+ 
+     def delPackage(self, po):
++        """Delete the given package from the package sack.
++
++        :param po: the package object to delete
++        """
+         po.repo.sack.delPackage(po)
+ 
+     def getTsInfo(self):
++        """Return transaction set.
++
++        :return: the transaction set
++        """
+         return self._base.tsInfo
+ 
+ class DepsolvePluginConduit(MainPluginConduit):
++    """Conduit for use in solving dependencies."""
++
+     def __init__(self, parent, base, conf, rescode=None, restring=[]):
+         MainPluginConduit.__init__(self, parent, base, conf)
+         self.resultcode = rescode
+         self.resultstring = restring
+ 
+ class CompareProvidersPluginConduit(MainPluginConduit):
++    """Conduit to compare different providers of packages."""
++
+     def __init__(self, parent, base, conf, providers_dict={}, reqpo=None):
+         MainPluginConduit.__init__(self, parent, base, conf)
+         self.packages = providers_dict
+         self.reqpo = reqpo
+ 
+ class HistoryPluginConduit(MainPluginConduit):
++    """Conduit to access information about the yum history."""
++
+     def __init__(self, parent, base, conf, rescode=None, restring=[]):
+         MainPluginConduit.__init__(self, parent, base, conf)
+         self.history = self._base.history
+ 
+ class VerifyPluginConduit(MainPluginConduit):
++    """Conduit to verify packages."""
++
+     def __init__(self, parent, base, conf, verify_package):
+         MainPluginConduit.__init__(self, parent, base, conf)
+         self.verify_package = verify_package
+ 
+ def parsever(apiver):
++    """Parse a string representing an api version.
++
++    :param apiver: a string representing an api version
++    :return: a tuple containing the major and minor version numbers
++    """
+     maj, min = apiver.split('.')
+     return int(maj), int(min)
+ 
+ def apiverok(a, b):
+-    '''Return true if API version "a" supports API version "b"
+-    '''
++    """Return true if API version "a" supports API version "b"
++
++    :param a: a string representing an api version
++    :param b: a string representing an api version
++
++    :return: whether version *a* supports version *b*
++    """
+     a = parsever(a)
+     b = parsever(b)
+ 
 diff --git a/yum/rpmsack.py b/yum/rpmsack.py
-index e289a7a..ef6fbd5 100644
+index e289a7a..635f03f 100644
 --- a/yum/rpmsack.py
 +++ b/yum/rpmsack.py
 @@ -48,6 +48,17 @@ def _open_no_umask(*args):
@@ -7074,15 +9628,21 @@ index e289a7a..ef6fbd5 100644
              except (IOError, OSError), e:
                  return
  
-@@ -1562,7 +1575,7 @@ class RPMDBAdditionalData(object):
+@@ -1562,11 +1575,11 @@ class RPMDBAdditionalData(object):
          self._packages = {} # pkgid = dir
          if not os.path.exists(self.conf.db_path):
              try:
 -                os.makedirs(self.conf.db_path)
 +                _makedirs_no_umask(self.conf.db_path)
++                self.conf.writable = True
              except (IOError, OSError), e:
                  # some sort of useful thing here? A warning?
-                 return
+-                return
+-            self.conf.writable = True
++                pass
+         else:
+             if os.access(self.conf.db_path, os.W_OK):
+                 self.conf.writable = True
 @@ -1708,7 +1721,7 @@ class RPMDBAdditionalDataPackage(object):
      def _write(self, attr, value):
          # check for self._conf.writable before going on?
@@ -7114,8 +9674,71 @@ index 8a6f6f3..19193ad 100644
                  pre = "1"
              prco_set = (_share_data(ob['name']), _share_data(ob['flags']),
                          (_share_data(ob['epoch']),
+diff --git a/yum/yumRepo.py b/yum/yumRepo.py
+index e5e9ece..91b7dde 100644
+--- a/yum/yumRepo.py
++++ b/yum/yumRepo.py
+@@ -24,6 +24,7 @@ urlparse.uses_fragment.append("media")
+ import Errors
+ from urlgrabber.grabber import URLGrabber
+ from urlgrabber.grabber import default_grabber
++from urlgrabber.progress import format_number
+ import urlgrabber.mirror
+ from urlgrabber.grabber import URLGrabError
+ import repoMDObject
+@@ -35,6 +36,7 @@ import sqlitesack
+ from yum import config
+ from yum import misc
+ from yum import comps
++from yum import _
+ from constants import *
+ import metalink
+ 
+@@ -499,6 +501,7 @@ class YumRepository(Repository, config.RepoConf):
+                  'throttle': self.throttle,
+                  'proxies': self.proxy_dict,
+                  'timeout': self.timeout,
++                 'ip_resolve': self.ip_resolve,
+                  'http_headers': tuple(self.__headersListFromDict(cache=cache)),
+                  'ssl_verify_peer': self.sslverify,
+                  'ssl_verify_host': self.sslverify,
+@@ -796,6 +799,16 @@ class YumRepository(Repository, config.RepoConf):
+             except Errors.MediaError, e:
+                 verbose_logger.log(logginglevels.DEBUG_2, "Error getting package from media; falling back to url %s" %(e,))
+ 
++        if size:
++            dirstat = os.statvfs(os.path.dirname(local))
++            avail = dirstat.f_bavail * dirstat.f_bsize
++            if avail < long(size):
++                raise Errors.RepoError, _('''\
++Insufficient space in download directory %s
++    * free   %s
++    * needed %s'''
++                ) % (os.path.dirname(local), format_number(avail), format_number(long(size)))
++
+         if url and scheme != "media":
+             ugopts = self._default_grabopts(cache=cache)
+             ug = URLGrabber(progress_obj = self.callback,
+@@ -1020,7 +1033,7 @@ class YumRepository(Repository, config.RepoConf):
+             if grab_can_fail:
+                 return None
+             raise Errors.RepoError, 'Error downloading file %s: %s' % (local, e)
+-        except (Errors.NoMoreMirrorsRepoError, Errors.RepoError):
++        except Errors.RepoError:
+             misc.unlink_f(tfname)
+             if grab_can_fail:
+                 return None
+@@ -1614,7 +1627,7 @@ class YumRepository(Repository, config.RepoConf):
+                                   text=text,
+                                   cache=self.http_caching == 'all',
+                                   size=thisdata.size)
+-        except (Errors.NoMoreMirrorsRepoError, Errors.RepoError):
++        except Errors.RepoError:
+             if retrieve_can_fail:
+                 return None
+             raise
 diff --git a/yumcommands.py b/yumcommands.py
-index 4dcbea7..d9c70f3 100644
+index 4dcbea7..2ab9a28 100644
 --- a/yumcommands.py
 +++ b/yumcommands.py
 @@ -43,16 +43,22 @@ def _err_mini_usage(base, basecmd):
@@ -8779,7 +11402,7 @@ index 4dcbea7..d9c70f3 100644
          return _("Display, or use, the transaction history")
  
      def _hcmd_redo(self, base, extcmds):
-@@ -1426,12 +2425,52 @@ class HistoryCommand(YumCommand):
+@@ -1426,12 +2425,54 @@ class HistoryCommand(YumCommand):
      def _hcmd_new(self, base, extcmds):
          base.history._create_db_file()
  
@@ -8810,8 +11433,10 @@ index 4dcbea7..d9c70f3 100644
 +                continue
 +
 +            print "Syncing rpm/yum DB data for:", ipkg, "...",
-+            base.history.sync_alldb(ipkg)
-+            print "Done."
++            if base.history.sync_alldb(ipkg):
++                print "Done."
++            else:
++                print "FAILED."
 +
      def doCheck(self, base, basecmd, extcmds):
 +        """Verify that conditions are met so that this command can
@@ -8833,7 +11458,7 @@ index 4dcbea7..d9c70f3 100644
          if extcmds and extcmds[0] not in cmds:
              base.logger.critical(_('Invalid history sub-command, use: %s.'),
                                   ", ".join(cmds))
-@@ -1444,6 +2483,19 @@ class HistoryCommand(YumCommand):
+@@ -1444,6 +2485,19 @@ class HistoryCommand(YumCommand):
              raise cli.CliError
  
      def doCommand(self, base, basecmd, extcmds):
@@ -8853,7 +11478,7 @@ index 4dcbea7..d9c70f3 100644
          vcmd = 'list'
          if extcmds:
              vcmd = extcmds[0]
-@@ -1468,12 +2520,26 @@ class HistoryCommand(YumCommand):
+@@ -1468,12 +2522,26 @@ class HistoryCommand(YumCommand):
              ret = self._hcmd_rollback(base, extcmds)
          elif vcmd == 'new':
              ret = self._hcmd_new(base, extcmds)
@@ -8880,7 +11505,7 @@ index 4dcbea7..d9c70f3 100644
          vcmd = 'list'
          if extcmds:
              vcmd = extcmds[0]
-@@ -1481,16 +2547,46 @@ class HistoryCommand(YumCommand):
+@@ -1481,16 +2549,46 @@ class HistoryCommand(YumCommand):
  
  
  class CheckRpmdbCommand(YumCommand):
@@ -8927,7 +11552,7 @@ index 4dcbea7..d9c70f3 100644
          chkcmd = 'all'
          if extcmds:
              chkcmd = extcmds
-@@ -1505,19 +2601,57 @@ class CheckRpmdbCommand(YumCommand):
+@@ -1505,19 +2603,57 @@ class CheckRpmdbCommand(YumCommand):
          return rc, ['%s %s' % (basecmd, chkcmd)]
  
      def needTs(self, base, basecmd, extcmds):
@@ -8985,7 +11610,7 @@ index 4dcbea7..d9c70f3 100644
          if not extcmds:
              base.logger.critical(_("No saved transaction file specified."))
              raise cli.CliError
-@@ -1533,5 +2667,13 @@ class LoadTransactionCommand(YumCommand):
+@@ -1533,5 +2669,13 @@ class LoadTransactionCommand(YumCommand):
  
  
      def needTs(self, base, basecmd, extcmds):
@@ -9000,11 +11625,19 @@ index 4dcbea7..d9c70f3 100644
          return True
  
 diff --git a/yummain.py b/yummain.py
-index 9f79f4f..d6abd70 100755
+index 9f79f4f..4b1112a 100755
 --- a/yummain.py
 +++ b/yummain.py
-@@ -35,7 +35,7 @@ import cli
- from utils import suppress_keyboard_interrupt_message, show_lock_owner, exception2msg
+@@ -29,13 +29,13 @@ from yum import Errors
+ from yum import plugins
+ from yum import logginglevels
+ from yum import _
+-from yum.i18n import to_unicode, utf8_width
++from yum.i18n import to_unicode, utf8_width, exception2msg
+ import yum.misc
+ import cli
+-from utils import suppress_keyboard_interrupt_message, show_lock_owner, exception2msg
++from utils import suppress_keyboard_interrupt_message, show_lock_owner
  
  def main(args):
 -    """This does all the real work"""
@@ -9012,6 +11645,28 @@ index 9f79f4f..d6abd70 100755
  
      yum.misc.setup_locale(override_time=True)
  
+@@ -120,16 +120,16 @@ def main(args):
+             if exception2msg(e) != lockerr:
+                 lockerr = exception2msg(e)
+                 logger.critical(lockerr)
+-            if (e.errno not in (errno.EPERM, errno.EACCES) and
+-                not base.conf.exit_on_lock):
++            if e.errno in (errno.EPERM, errno.EACCES, errno.ENOSPC):
++                logger.critical(_("Can't create lock file; exiting"))
++                return 1
++
++            if not base.conf.exit_on_lock:
+                 logger.critical(_("Another app is currently holding the yum lock; waiting for it to exit..."))
+                 tm = 0.1
+                 if show_lock_owner(e.pid, logger):
+                     tm = 2
+                 time.sleep(tm)
+-            elif e.errno in (errno.EPERM, errno.EACCES):
+-                logger.critical(_("Can't create lock file; exiting"))
+-                return 1
+             else:
+                 logger.critical(_("Another app is currently holding the yum lock; exiting as configured by exit_on_lock"))
+                 return 1
 @@ -238,9 +238,15 @@ def main(args):
          rpmdb_warn_checks()
          return_code = result
diff --git a/yum.spec b/yum.spec
index 324a0c5..f7bc652 100644
--- a/yum.spec
+++ b/yum.spec
@@ -1,6 +1,7 @@
 %define move_yum_conf_back 1
 %define auto_sitelib 1
 %define yum_updatesd 0
+%define disable_check 1
 
 %if %{auto_sitelib}
 
@@ -17,7 +18,7 @@
 Summary: RPM package installer/updater/manager
 Name: yum
 Version: 3.4.3
-Release: 6%{?dist}
+Release: 7%{?dist}
 License: GPLv2+
 Group: System Environment/Base
 Source0: http://yum.baseurl.org/download/3.4/%{name}-%{version}.tar.gz
@@ -146,6 +147,11 @@ Install this package if you want auto yum updates nightly via cron.
 %build
 make
 
+%if !%{disable_check}
+%check
+make check
+%endif
+
 
 %install
 [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
@@ -267,7 +273,7 @@ exit 0
 %{_sysconfdir}/bash_completion.d
 %dir %{_datadir}/yum-cli
 %{_datadir}/yum-cli/*
-%if !%{yum_updatesd}
+%if %{yum_updatesd}
 %exclude %{_datadir}/yum-cli/yumupd.py*
 %endif
 %{_bindir}/yum
@@ -310,6 +316,13 @@ exit 0
 %endif
 
 %changelog
+* Fri Aug 19 2011 James Antill <james at fedoraproject.org> - 3.4.3-7
+- update to latest HEAD
+- Fix syncing of yum DB data in history.
+- Add upgrade_requirements_on_install config. option.
+- Don't look for releasever if it's set directly (anaconda).
+- Expose ip_resolve urlgrabber option.
+
 * Fri Aug  5 2011 James Antill <james at fedoraproject.org> - 3.4.3-6
 - update to latest HEAD
 - Add new yum DB data.


More information about the scm-commits mailing list