[yum] update to latest HEAD Some edge case depsolver bug fixes. Output the GPG fingerprint when showing th

James Antill james at fedoraproject.org
Fri Oct 14 20:35:21 UTC 2011


commit ea3e2fd63cbaf71cf5d5a1057eed9268dc634bc3
Author: James Antill <james at and.org>
Date:   Fri Oct 14 16:34:44 2011 -0400

    update to latest HEAD
    Some edge case depsolver bug fixes.
    Output the GPG fingerprint when showing the GPG key.
    Update bugtracker URL back to redhat.
    Allow reinstall and remove arguments to history redo command.
    Let resolvedep look for installed packages.

 yum-HEAD.patch |  849 ++++++++++++++++++++++++++++++++++++++++++++++----------
 yum.spec       |   10 +-
 2 files changed, 710 insertions(+), 149 deletions(-)
---
diff --git a/yum-HEAD.patch b/yum-HEAD.patch
index 3aed55d..a1ad8f8 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..2f4cabc
+index 6056d38..bbe8e55
 --- a/cli.py
 +++ b/cli.py
 @@ -25,7 +25,7 @@ import sys
@@ -768,7 +768,7 @@ index 6056d38..2f4cabc
          old_sdup = self.conf.showdupesfromrepos
          # For output, as searchPackageProvides() is always in showdups mode
          self.conf.showdupesfromrepos = True
-@@ -1163,8 +1383,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1163,20 +1383,68 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, []
      
      def resolveDepCli(self, args):
@@ -789,8 +789,25 @@ index 6056d38..2f4cabc
 +        """
          for arg in args:
              try:
++                ipkg = self.returnInstalledPackageByDep(arg)
++            except yum.Errors.YumBaseError:
++                ipkg = None
++            else:
++                self.verbose_logger.info("%s %s" % (ipkg.envra,
++                                                    ipkg.ui_from_repo))
++            try:
                  pkg = self.returnPackageByDep(arg)
-@@ -1177,6 +1408,34 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+             except yum.Errors.YumBaseError:
+-                self.logger.critical(_('No Package Found for %s'), arg)
++                if not ipkg:
++                    self.logger.critical(_('No Package Found for %s'), arg)
+             else:
+-                msg = '%s:%s-%s-%s.%s' % (pkg.epoch, pkg.name, pkg.version, pkg.release, pkg.arch)
+-                self.verbose_logger.info(msg)
++                if not pkg.verEQ(ipkg):
++                    self.verbose_logger.info("%s %s" % (pkg.envra,
++                                                        pkg.ui_from_repo))
+ 
          return 0, []
      
      def cleanCli(self, userlist):
@@ -825,7 +842,7 @@ index 6056d38..2f4cabc
          hdrcode = pkgcode = xmlcode = dbcode = expccode = 0
          pkgresults = hdrresults = xmlresults = dbresults = expcresults = []
          msg = self.fmtKeyValFill(_('Cleaning repos: '), 
-@@ -1228,7 +1487,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1228,7 +1496,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return code, []
  
      def returnGroupLists(self, userlist):
@@ -835,9 +852,9 @@ index 6056d38..2f4cabc
 +        :param extcmds: a list of names or wildcards specifying
 +           groups to list
 +        :return: (exit_code, [ errors ])
-+
-+        exit_code is::
  
++        exit_code is::
++
 +            0 = we're done, exit
 +            1 = we've errored, exit with error string
 +            2 = we've got work yet to do, onto the next stage        
@@ -845,7 +862,7 @@ index 6056d38..2f4cabc
          uservisible=1
              
          if len(userlist) > 0:
-@@ -1283,7 +1554,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1283,7 +1563,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, [_('Done')]
  
      def returnGroupSummary(self, userlist):
@@ -856,9 +873,9 @@ index 6056d38..2f4cabc
 +           groups to summarise. If *userlist* is an empty list, all
 +           installed and available packages will be summarised
 +        :return: (exit_code, [ errors ])
- 
-+        exit_code is::
 +
++        exit_code is::
+ 
 +            0 = we're done, exit
 +            1 = we've errored, exit with error string
 +            2 = we've got work yet to do, onto the next stage
@@ -866,7 +883,7 @@ index 6056d38..2f4cabc
          uservisible=1
              
          if len(userlist) > 0:
-@@ -1327,7 +1611,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1327,7 +1620,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, [_('Done')]
      
      def returnGroupInfo(self, userlist):
@@ -887,7 +904,7 @@ index 6056d38..2f4cabc
          for strng in userlist:
              group_matched = False
              for group in self.comps.return_groups(strng):
-@@ -1340,8 +1636,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1340,8 +1645,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return 0, []
          
      def installGroups(self, grouplist):
@@ -908,7 +925,7 @@ index 6056d38..2f4cabc
          pkgs_used = []
          
          for group_string in grouplist:
-@@ -1368,8 +1674,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1368,8 +1683,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):
@@ -928,7 +945,7 @@ index 6056d38..2f4cabc
          pkgs_used = []
          for group_string in grouplist:
              try:
-@@ -1389,7 +1705,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1389,7 +1714,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
  
      def _promptWanted(self):
          # shortcut for the always-off/always-on options
@@ -937,7 +954,7 @@ index 6056d38..2f4cabc
              return False
          if self.conf.alwaysprompt:
              return True
-@@ -1400,7 +1716,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1400,7 +1725,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 \
@@ -945,7 +962,7 @@ index 6056d38..2f4cabc
                     txmbr.name not in self.extcmds:
                  return True
          
-@@ -1408,11 +1723,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1408,11 +1732,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return False
  
      def usage(self):
@@ -959,7 +976,7 @@ index 6056d38..2f4cabc
          sys.stdout.write(self.optparser.get_usage())
      
      def _installable(self, pkg, ematch=False):
-@@ -1468,9 +1783,9 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1468,9 +1792,9 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
          return False
  
  class YumOptionParser(OptionParser):
@@ -971,7 +988,7 @@ index 6056d38..2f4cabc
  
      def __init__(self,base, **kwargs):
          # check if this is called with a utils=True/False parameter
-@@ -1488,13 +1803,23 @@ class YumOptionParser(OptionParser):
+@@ -1488,13 +1812,23 @@ class YumOptionParser(OptionParser):
          self._addYumBasicOptions()
  
      def error(self, msg):
@@ -997,7 +1014,7 @@ index 6056d38..2f4cabc
          try:
              args = _filtercmdline(
                          ('--noplugins','--version','-q', '-v', "--quiet", "--verbose"), 
-@@ -1521,7 +1846,15 @@ class YumOptionParser(OptionParser):
+@@ -1521,7 +1855,15 @@ class YumOptionParser(OptionParser):
          return ret
          
      def setupYumConfig(self, args=None):
@@ -1014,7 +1031,7 @@ index 6056d38..2f4cabc
          if not args:
              (opts, cmds) = self.parse_args()
          else:
-@@ -1536,7 +1869,9 @@ class YumOptionParser(OptionParser):
+@@ -1536,7 +1878,9 @@ class YumOptionParser(OptionParser):
                  
              # Handle remaining options
              if opts.assumeyes:
@@ -1025,7 +1042,7 @@ index 6056d38..2f4cabc
  
              #  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 +1975,14 @@ class YumOptionParser(OptionParser):
+@@ -1640,6 +1984,14 @@ class YumOptionParser(OptionParser):
          sys.exit(1)
  
      def getRoot(self,opts):
@@ -1040,7 +1057,7 @@ index 6056d38..2f4cabc
          self._checkAbsInstallRoot(opts)
          # If the conf file is inside the  installroot - use that.
          # otherwise look for it in the normal root
-@@ -1713,6 +2056,10 @@ class YumOptionParser(OptionParser):
+@@ -1713,6 +2065,10 @@ class YumOptionParser(OptionParser):
                          help=_("verbose operation"))
          group.add_option("-y", "--assumeyes", dest="assumeyes",
                  action="store_true", help=_("answer yes for all questions"))
@@ -1650,10 +1667,18 @@ index 0000000..d2a0ed1
 +if __name__ == "__main__":
 +    generateAll(os.getcwd(), os.getcwd())
 diff --git a/docs/yum.8 b/docs/yum.8
-index 1a8202a..255c755 100644
+index 1a8202a..499da41 100644
 --- a/docs/yum.8
 +++ b/docs/yum.8
-@@ -69,7 +69,9 @@ gnome\-packagekit application\&.
+@@ -52,6 +52,7 @@ gnome\-packagekit application\&.
+ .I \fR * shell [filename]
+ .br
+ .I \fR * resolvedep dep1 [dep2] [\&.\&.\&.] 
++    (maintained for legacy reasons only - use repoquery or yum provides)
+ .br
+ .I \fR * localinstall rpmfile1 [rpmfile2] [\&.\&.\&.] 
+     (maintained for legacy reasons only - use install)
+@@ -69,7 +70,9 @@ gnome\-packagekit application\&.
  .br
  .I \fR * version [ all | installed | available | group-* | nogroups* | grouplist | groupinfo ]
  .br
@@ -1664,7 +1689,41 @@ index 1a8202a..255c755 100644
  .br
  .I \fR * check
  .br 
-@@ -321,15 +323,17 @@ and so takes sub-commands:
+@@ -235,12 +238,13 @@ that file is executed in yum shell mode. See \fIyum-shell(8)\fP for more info
+ .IP
+ .IP "\fBresolvedep\fP"
+ Is used to list packages providing the specified dependencies, at most one
+-package is listed per dependency. 
++package is listed per dependency. This command is maintained for legacy
++reasons only, use repoquery instead.
+ .IP
+ .IP "\fBlocalinstall\fP"
+ Is used to install a set of local rpm files. If required the enabled 
+ repositories will be used to resolve dependencies. Note that the install command
+-will do a local install, if given a filename. This option is maintained for legacy
++will do a local install, if given a filename. This command is maintained for legacy
+ reasons only.
+ .IP
+ .IP "\fBlocalupdate\fP"
+@@ -248,7 +252,7 @@ Is used to update the system by specifying local rpm files. Only the specified
+ rpm files of which an older version is already installed will be installed,
+ the remaining specified packages will be ignored.
+ If required the enabled repositories will be used to resolve dependencies. Note
+-that the update command will do a local update, if given a filename. This option is maintained for
++that the update command will do a local update, if given a filename. This command is maintained for
+ legacy reasons only.
+ .IP
+ .IP "\fBreinstall\fP"
+@@ -260,7 +264,7 @@ on groups, files, provides and filelists just like the "install" command\&.
+ Will try and downgrade a package from the version currently installed to the
+ previously highest version (or the specified version).
+ The depsolver will not necessarily work, but if you specify all the packages it
+-should work (and thus. all the simple cases will work). Also this does not
++should work (thus, all the simple cases will work). Also this does not
+ work for "installonly" packages, like Kernels. downgrade operates
+ on groups, files, provides, filelists and rpm files just like the "install" command\&.
+ .IP
+@@ -321,20 +325,27 @@ and so takes sub-commands:
  .IP "\fBhistory\fP"
  The history command allows the user to view what has happened in past
  transactions (assuming the history_record config. option is set). You can use
@@ -1686,7 +1745,17 @@ index 1a8202a..255c755 100644
  
  The undo/redo/rollback commands take either a single transaction id or the
  keyword last and an offset from the last transaction (Eg. if you've done 250
-@@ -349,6 +353,12 @@ transactions 1 and 4.
+ transactions, "last" refers to transaction 250, and "last-4" refers to
+ transaction 246).
++The redo command can also take some optional arguments before you specify the
++transaction. "force-reinstall" tells it reinstall any packages that were
++installed in that transaction (via. install, upgrade or downgrade).
++"force-remove" tells it to forcibly remove any packages that were updated or
++downgraded.
+ 
+ The undo/redo commands act on the specified transaction, undo'ing or repeating
+ the work of that transaction. While the rollback command will undo all
+@@ -349,6 +360,12 @@ transactions 1 and 4.
  The addon-info command takes a transaction ID, and the packages-list command
  takes a package (with wildcards).
  
@@ -1699,7 +1768,7 @@ index 1a8202a..255c755 100644
  In "history list" you can change the behaviour of the 2nd column via. the
  configuration option history_list_view.
  
-@@ -371,6 +381,15 @@ end of the package column in the packages-list command).
+@@ -371,6 +388,15 @@ end of the package column in the packages-list command).
  .I \fBs\fR - The transaction completed fine, but --skip-broken was enabled and had to skip some packages.
  .br
  
@@ -1715,7 +1784,7 @@ index 1a8202a..255c755 100644
  .IP
  .IP "\fBcheck\fP"
  Checks the local rpmdb and produces information on any problems it finds. You
-@@ -401,6 +420,11 @@ Assume yes; assume that the answer to any question which would be asked
+@@ -401,6 +427,11 @@ Assume yes; assume that the answer to any question which would be asked
  is yes\&.
  .br
  Configuration Option: \fBassumeyes\fP
@@ -2165,7 +2234,7 @@ index c60fa08..0000000
 -ts run
 -exit
 diff --git a/etc/yum.bash b/etc/yum.bash
-index f1e06e8..2faeb59 100644
+index f1e06e8..b998341 100644
 --- a/etc/yum.bash
 +++ b/etc/yum.bash
 @@ -45,7 +45,7 @@ _yum_grouplist()
@@ -2203,6 +2272,17 @@ index f1e06e8..2faeb59 100644
  # arguments:
  #   1 = current word to be completed
  #   2 = previous word
+@@ -184,8 +194,8 @@ _yum()
+     # Commands offered as completions
+     local cmds=( check check-update clean deplist distro-sync downgrade
+         groupinfo groupinstall grouplist groupremove help history info install
+-        list makecache provides reinstall remove repolist resolvedep search
+-        shell update upgrade version )
++        list makecache provides reinstall remove repolist search shell update
++        upgrade version )
+ 
+     local i c cmd subcmd
+     for (( i=1; i < ${#words[@]}-1; i++ )) ; do
 @@ -231,13 +241,15 @@ _yum()
              ;;
  
@@ -8807,6 +8887,24 @@ index e22318e..b9cb8aa 100755
      if syes[0] != sy:
          print >>sys.stderr, """\
  ERROR: yes/y translations don't match in: %s
+diff --git a/test/depsolvetests.py b/test/depsolvetests.py
+index 7af3f16..ea47b03 100644
+--- a/test/depsolvetests.py
++++ b/test/depsolvetests.py
+@@ -1130,9 +1130,10 @@ class DepsolveTests(DepsolveTests):
+         # FIXME: Does it make sense to ignore the obsoletes here? esp. as we
+         # don't ignore the conflicts above? ... I'm guessing ignoring it is
+         # by accident too? bah.
+-        # self.assertEquals('err', *self.resolveCode())
+-        self.assertEquals('ok', *self.resolveCode())
+-        self.assertResult((ipo1, po1))
++        self.assertEquals('err', *self.resolveCode())
++        # Old behaviour:
++        # self.assertEquals('ok', *self.resolveCode())
++        # self.assertResult((ipo1, po1))
+ 
+     def testUpdate_so_req_diff_arch(self):
+         rpo1 = FakePackage('foozoomer')
 diff --git a/test/simpleobsoletestests.py b/test/simpleobsoletestests.py
 index 97a9923..70dde98 100644
 --- a/test/simpleobsoletestests.py
@@ -8854,22 +8952,112 @@ index 97a9923..70dde98 100644
      def _MultiObsHelper(self):
          ret = {'zsh'  : FakePackage('zsh', '1', '1', '0', 'noarch'),
                 'ksh'  : FakePackage('ksh', '1', '1', '0', 'noarch'),
+diff --git a/test/simpleupdatetests.py b/test/simpleupdatetests.py
+index 6177fb1..2c8bcb3 100644
+--- a/test/simpleupdatetests.py
++++ b/test/simpleupdatetests.py
+@@ -990,3 +990,72 @@ class SimpleUpdateTests(OperationsTests):
+         # Nothing to do...
+         self.assert_(res==0, msg)
+ 
++    def testUpdateReqFail_1(self):
++        foo11 = FakePackage('foo', '1', '1', '0', 'i386')
++        foo11.addRequires('bar', 'EQ', ('0', '1', '1'))
++        foo12 = FakePackage('foo', '1', '2', '0', 'i386')
++        foo12.addRequires('bar', 'EQ', ('0', '1', '1'))
++
++        bar11 = FakePackage('bar', '1', '1', '0', 'i386')
++        bar12 = FakePackage('bar', '1', '2', '0', 'i386')
++
++        res, msg = self.runOperation(['update', 'bar'],
++                                     [foo11, bar11],
++                                     [foo11, foo12, bar11, bar12])
++        # Should fail...
++        self.assert_(res=='err', msg)
++
++    def testUpdateReqFail_2(self):
++        foo11 = FakePackage('foo', '1', '1', '0', 'i386')
++        foo11.addRequires('bar', 'EQ', ('0', '1', '1'))
++        foo12 = FakePackage('foo', '1', '2', '0', 'i386')
++        foo12.addRequires('bar', 'LE', ('0', '1', '1'))
++
++        bar11 = FakePackage('bar', '1', '1', '0', 'i386')
++        bar12 = FakePackage('bar', '1', '2', '0', 'i386')
++
++        res, msg = self.runOperation(['update', 'bar'],
++                                     [foo11, bar11],
++                                     [foo11, foo12, bar11, bar12])
++        # Should fail...
++        self.assert_(res=='err', msg)
++
++    def testUpdateReqFail_3(self):
++        foo11 = FakePackage('foo', '1', '1', '0', 'i386')
++        foo11.addRequires('bar', 'EQ', ('0', '1', '1'))
++        foo12 = FakePackage('foo', '1', '2', '0', 'i386')
++        foo12.addRequires('bar', 'EQ', ('0', '1', '1'))
++
++        bar11 = FakePackage('bar', '1', '1', '0', 'i386')
++        bar12 = FakePackage('bar', '1', '2', '0', 'i386')
++
++        cbar11 = FakePackage('compat-bar', '1', '1', '0', 'i386')
++        cbar11.addProvides('bar', 'EQ', ('0', '1', '1'))
++
++        res, msg = self.runOperation(['update', 'bar'],
++                                     [foo11, bar11],
++                                     [foo11, foo12, bar11, bar12, cbar11])
++        self.assert_(res=='ok', msg)
++        # Ideal:
++        # self.assertResult((foo11, bar12, cbar11))
++        self.assertResult((foo12, bar12, cbar11))
++
++    def testUpdateReqFail_4(self):
++        foo11 = FakePackage('foo', '1', '1', '0', 'i386')
++        foo11.addRequires('bar', 'EQ', ('0', '1', '1'))
++        foo12 = FakePackage('foo', '1', '2', '0', 'i386')
++        foo12.addRequires('bar', 'LE', ('0', '1', '1'))
++
++        bar11 = FakePackage('bar', '1', '1', '0', 'i386')
++        bar12 = FakePackage('bar', '1', '2', '0', 'i386')
++
++        cbar11 = FakePackage('compat-bar', '1', '1', '0', 'i386')
++        cbar11.addProvides('bar', 'EQ', ('0', '1', '1'))
++
++        res, msg = self.runOperation(['update', 'bar'],
++                                     [foo11, bar11],
++                                     [foo11, foo12, bar11, bar12, cbar11])
++        self.assert_(res=='ok', msg)
++        # Ideal:
++        # self.assertResult((foo11, bar12, cbar11))
++        self.assertResult((foo12, bar12, cbar11))
+diff --git a/test/testbase.py b/test/testbase.py
+index d0f22be..c185a7f 100644
+--- a/test/testbase.py
++++ b/test/testbase.py
+@@ -55,6 +55,7 @@ class FakeConf(object):
+         self.protected_packages = []
+         self.protected_multilib = False
+         self.clean_requirements_on_remove = True
++        self.upgrade_requirements_on_install = False
+ 
+ class FakeSack:
+     """ Fake PackageSack to use with FakeRepository"""
 diff --git a/utils.py b/utils.py
 old mode 100644
 new mode 100755
-index ced6ba0..99533a6
+index ced6ba0..08b09fb
 --- a/utils.py
 +++ b/utils.py
-@@ -13,6 +13,8 @@
+@@ -13,6 +13,9 @@
  # along with this program; if not, write to the Free Software
  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  
 +"""Various utility functions, and a utility class."""
 +
++import os
  import sys
  import time
  import exceptions
-@@ -21,7 +23,7 @@ import yum
+@@ -21,14 +24,23 @@ import yum
  from cli import *
  from yum import Errors
  from yum import _
@@ -8878,9 +9066,15 @@ index ced6ba0..99533a6
  from yum import logginglevels
  from optparse import OptionGroup
  
-@@ -29,6 +31,9 @@ import yum.plugins as plugins
+ import yum.plugins as plugins
  from urlgrabber.progress import format_number
  
++try:
++    _USER_HZ = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
++except (AttributeError, KeyError):
++    # Huh, non-Unix platform? Or just really old?
++    _USER_HZ = 100
++
  def suppress_keyboard_interrupt_message():
 +    """Change settings so that nothing will be printed to the
 +    terminal after an uncaught :class:`exceptions.KeyboardInterrupt`.
@@ -8888,18 +9082,19 @@ index ced6ba0..99533a6
      old_excepthook = sys.excepthook
  
      def new_hook(type, value, traceback):
-@@ -40,10 +45,23 @@ def suppress_keyboard_interrupt_message():
+@@ -40,10 +52,22 @@ def suppress_keyboard_interrupt_message():
      sys.excepthook = new_hook
  
  def jiffies_to_seconds(jiffies):
-+    """Convert a number of jiffies to seconds, using the convention
-+    that 100 jiffies = 1 second.
+-    Hertz = 100 # FIXME: Hack, need to get this, AT_CLKTCK elf note *sigh*
+-    return int(jiffies) / Hertz
++    """Convert a number of jiffies to seconds. How many jiffies are in a second
++    is system-dependent, e.g. 100 jiffies = 1 second is common.
 +
 +    :param jiffies: a number of jiffies
 +    :return: the equivalent number of seconds
 +    """
-     Hertz = 100 # FIXME: Hack, need to get this, AT_CLKTCK elf note *sigh*
-     return int(jiffies) / Hertz
++    return int(jiffies) / _USER_HZ
  
  def seconds_to_ui_time(seconds):
 +    """Return a human-readable string representation of the length of
@@ -8912,7 +9107,7 @@ index ced6ba0..99533a6
      if seconds >= 60 * 60 * 24:
          return "%d day(s) %d:%02d:%02d" % (seconds / (60 * 60 * 24),
                                             (seconds / (60 * 60)) % 24,
-@@ -55,6 +73,12 @@ def seconds_to_ui_time(seconds):
+@@ -55,6 +79,12 @@ def seconds_to_ui_time(seconds):
      return "%02d:%02d" % ((seconds / 60), seconds % 60)
  
  def get_process_info(pid):
@@ -8925,7 +9120,7 @@ index ced6ba0..99533a6
      if not pid:
          return
  
-@@ -106,6 +130,16 @@ def get_process_info(pid):
+@@ -106,6 +136,16 @@ def get_process_info(pid):
      return ps
  
  def show_lock_owner(pid, logger):
@@ -8942,7 +9137,7 @@ index ced6ba0..99533a6
      ps = get_process_info(pid)
      if not ps:
          return None
-@@ -129,28 +163,9 @@ def show_lock_owner(pid, logger):
+@@ -129,28 +169,9 @@ def show_lock_owner(pid, logger):
      return ps
  
  
@@ -8973,7 +9168,7 @@ index ced6ba0..99533a6
      def __init__(self,name,ver,usage):
          YumBaseCli.__init__(self)
          self._parser = YumOptionParser(base=self,utils=True,usage=usage)
-@@ -167,11 +182,22 @@ class YumUtilBase(YumBaseCli):
+@@ -167,11 +188,22 @@ class YumUtilBase(YumBaseCli):
              self.run_with_package_names.add("yum-utils")
  
      def exUserCancel(self):
@@ -8996,7 +9191,7 @@ index ced6ba0..99533a6
          if e.errno == 32:
              self.logger.critical(_('\n\nExiting on Broken Pipe'))
          else:
-@@ -180,10 +206,13 @@ class YumUtilBase(YumBaseCli):
+@@ -180,10 +212,13 @@ class YumUtilBase(YumBaseCli):
          return 1
  
      def exPluginExit(self, e):
@@ -9013,7 +9208,7 @@ index ced6ba0..99533a6
          exitmsg = exception2msg(e)
          if exitmsg:
              self.logger.warn('\n\n%s', exitmsg)
-@@ -191,11 +220,20 @@ class YumUtilBase(YumBaseCli):
+@@ -191,11 +226,20 @@ class YumUtilBase(YumBaseCli):
          return 1
  
      def exFatal(self, e):
@@ -9034,7 +9229,7 @@ index ced6ba0..99533a6
          try:
              self.closeRpmDB()
              self.doUnlock()
-@@ -205,13 +243,27 @@ class YumUtilBase(YumBaseCli):
+@@ -205,13 +249,27 @@ class YumUtilBase(YumBaseCli):
          
          
      def getOptionParser(self):
@@ -9063,7 +9258,7 @@ index ced6ba0..99533a6
          lockerr = ""
          while True:
              try:
-@@ -233,6 +285,13 @@ class YumUtilBase(YumBaseCli):
+@@ -233,6 +291,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,)):
@@ -9077,7 +9272,7 @@ index ced6ba0..99533a6
          # Parse only command line options that affect basic yum setup
          opts = self._parser.firstParse(args)
  
-@@ -305,8 +364,9 @@ class YumUtilBase(YumBaseCli):
+@@ -305,8 +370,9 @@ class YumUtilBase(YumBaseCli):
          return opts
  
      def doUtilYumSetup(self):
@@ -9089,7 +9284,7 @@ index ced6ba0..99533a6
          # FIXME - we need another way to do this, I think.
          try:
              self.waitForLock()
-@@ -319,6 +379,11 @@ class YumUtilBase(YumBaseCli):
+@@ -319,6 +385,11 @@ class YumUtilBase(YumBaseCli):
              sys.exit(1)
  
      def doUtilBuildTransaction(self, unfinished_transactions_check=True):
@@ -9101,7 +9296,7 @@ index ced6ba0..99533a6
          try:
              (result, resultmsgs) = self.buildTransaction(unfinished_transactions_check = unfinished_transactions_check)
          except plugins.PluginYumExit, e:
-@@ -361,6 +426,7 @@ class YumUtilBase(YumBaseCli):
+@@ -361,6 +432,7 @@ class YumUtilBase(YumBaseCli):
          self.verbose_logger.log(logginglevels.INFO_2, _('\nDependencies Resolved'))
          
      def doUtilTransaction(self):
@@ -10464,7 +10659,7 @@ index abd203f..b78a9f6 100644
  - 3.4.1
  - umask bug fix.
 diff --git a/yum/__init__.py b/yum/__init__.py
-index 99039e0..5fb7c00 100644
+index 99039e0..53043de 100644
 --- a/yum/__init__.py
 +++ b/yum/__init__.py
 @@ -82,7 +82,7 @@ from packages import YumAvailablePackage, YumLocalPackage, YumInstalledPackage
@@ -11572,7 +11767,42 @@ index 99039e0..5fb7c00 100644
          if not depstring:
              return []
  
-@@ -3202,10 +3477,17 @@ class YumBase(depsolve.Depsolve):
+@@ -3184,6 +3459,34 @@ class YumBase(depsolve.Depsolve):
+ 
+         return self.rpmdb.getProvides(depname, depflags, depver).keys()
+ 
++    def returnInstalledPackageByDep(self, depstring):
++        """Return the best, or first, installed 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, installed 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:
++            errstring = str(depstring)
++        
++        try:
++            pkglist = self.returnInstalledPackagesByDep(depstring)
++        except Errors.YumBaseError:
++            raise Errors.YumBaseError, _('No Package found for %s') % errstring
++        
++        ps = ListPackageSack(pkglist)
++        result = self._bestPackageFromList(ps.returnNewestByNameArch())
++        if result is None:
++            raise Errors.YumBaseError, _('No Package found for %s') % errstring
++        
++        return result
++
+     def _bestPackageFromList(self, pkglist):
+         """take list of package objects and return the best package object.
+            If the list is empty, return None. 
+@@ -3202,10 +3505,17 @@ class YumBase(depsolve.Depsolve):
          return bestlist[0][0]
  
      def bestPackagesFromList(self, pkglist, arch=None, single_name=False):
@@ -11594,7 +11824,7 @@ index 99039e0..5fb7c00 100644
          returnlist = []
          compatArchList = self.arch.get_arch_list(arch)
          multiLib = []
-@@ -3438,13 +3720,35 @@ class YumBase(depsolve.Depsolve):
+@@ -3438,13 +3748,35 @@ class YumBase(depsolve.Depsolve):
                  self.tsInfo.probFilterFlags.append(flag)
  
      def install(self, po=None, **kwargs):
@@ -11636,7 +11866,7 @@ index 99039e0..5fb7c00 100644
          pkgs = []
          was_pattern = False
          if po:
-@@ -3600,23 +3904,23 @@ class YumBase(depsolve.Depsolve):
+@@ -3600,23 +3932,23 @@ class YumBase(depsolve.Depsolve):
                      already_obs = pkgs[0]
  
                  if already_obs:
@@ -11667,7 +11897,7 @@ index 99039e0..5fb7c00 100644
                      continue
  
              # make sure we don't have a name.arch of this already installed
-@@ -3630,7 +3934,7 @@ class YumBase(depsolve.Depsolve):
+@@ -3630,7 +3962,7 @@ class YumBase(depsolve.Depsolve):
                          found = True
                          break
                  if not found:
@@ -11676,7 +11906,7 @@ index 99039e0..5fb7c00 100644
                      txmbrs = self.update(po=po)
                      tx_return.extend(txmbrs)
                      continue
-@@ -3719,14 +4023,33 @@ class YumBase(depsolve.Depsolve):
+@@ -3719,14 +4051,33 @@ class YumBase(depsolve.Depsolve):
          return txmbr
  
      def update(self, po=None, requiringPo=None, update_to=False, **kwargs):
@@ -11717,7 +11947,7 @@ index 99039e0..5fb7c00 100644
          # 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):
+@@ -3985,11 +4336,18 @@ class YumBase(depsolve.Depsolve):
          return tx_return
          
      def remove(self, po=None, **kwargs):
@@ -11741,7 +11971,7 @@ index 99039e0..5fb7c00 100644
          if not po and not kwargs:
              raise Errors.RemoveError, 'Nothing specified to remove'
          
-@@ -4055,17 +4385,19 @@ class YumBase(depsolve.Depsolve):
+@@ -4055,17 +4413,19 @@ class YumBase(depsolve.Depsolve):
          return tx_return
  
      def installLocal(self, pkg, po=None, updateonly=False):
@@ -11771,7 +12001,7 @@ index 99039e0..5fb7c00 100644
          # 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):
+@@ -4183,16 +4543,15 @@ class YumBase(depsolve.Depsolve):
          return tx_return
  
      def reinstallLocal(self, pkg, po=None):
@@ -11796,7 +12026,7 @@ index 99039e0..5fb7c00 100644
          if not po:
              try:
                  po = YumUrlPackage(self, ts=self.rpmdb.readOnlyTS(), url=pkg,
-@@ -4215,9 +4546,19 @@ class YumBase(depsolve.Depsolve):
+@@ -4215,9 +4574,19 @@ class YumBase(depsolve.Depsolve):
          return self.reinstall(po=po)
  
      def reinstall(self, po=None, **kwargs):
@@ -11819,7 +12049,7 @@ index 99039e0..5fb7c00 100644
          self._add_prob_flags(rpm.RPMPROB_FILTER_REPLACEPKG,
                               rpm.RPMPROB_FILTER_REPLACENEWFILES,
                               rpm.RPMPROB_FILTER_REPLACEOLDFILES)
-@@ -4259,16 +4600,15 @@ class YumBase(depsolve.Depsolve):
+@@ -4259,16 +4628,15 @@ class YumBase(depsolve.Depsolve):
          return tx_mbrs
          
      def downgradeLocal(self, pkg, po=None):
@@ -11844,7 +12074,7 @@ index 99039e0..5fb7c00 100644
          if not po:
              try:
                  po = YumUrlPackage(self, ts=self.rpmdb.readOnlyTS(), url=pkg,
-@@ -4309,13 +4649,19 @@ class YumBase(depsolve.Depsolve):
+@@ -4309,13 +4677,19 @@ class YumBase(depsolve.Depsolve):
          return False
          
      def downgrade(self, po=None, **kwargs):
@@ -11871,24 +12101,82 @@ index 99039e0..5fb7c00 100644
          if not po and not kwargs:
              raise Errors.DowngradeError, 'Nothing specified to downgrade'
  
-@@ -4501,8 +4847,14 @@ class YumBase(depsolve.Depsolve):
+@@ -4500,12 +4874,24 @@ class YumBase(depsolve.Depsolve):
+ 
          return returndict
  
-     def history_redo(self, transaction):
+-    def history_redo(self, transaction):
 -        """ Given a valid historical transaction object, try and repeat
 -            that transaction. """
++    def history_redo(self, transaction,
++                     force_reinstall=False, force_changed_removal=False):
 +        """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
++        :param force_reinstall: bool - do we want to reinstall anything that was
++           installed/updated/downgraded/etc.
++        :param force_changed_removal: bool - do we want to force remove anything
++           that was downgraded or upgraded.
 +        :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):
++
+         old_conf_obs = self.conf.obsoletes
+         self.conf.obsoletes = False
+         done = False
+@@ -4515,19 +4901,46 @@ class YumBase(depsolve.Depsolve):
+                     done = True
+         for pkg in transaction.trans_data:
+             if pkg.state == 'Downgrade':
++                if force_reinstall and self.rpmdb.searchPkgTuple(pkg.pkgtup):
++                    if self.reinstall(pkgtup=pkg.pkgtup):
++                        done = True
++                    continue
++
+                 try:
+                     if self.downgrade(pkgtup=pkg.pkgtup):
+                         done = True
+                 except yum.Errors.DowngradeError:
+                     self.logger.critical(_('Failed to downgrade: %s'), pkg)
+         for pkg in transaction.trans_data:
++            if force_changed_removal and pkg.state == 'Downgraded':
++                if self.tsInfo.getMembers(pkg.pkgtup):
++                    continue
++                if self.remove(pkgtup=pkg.pkgtup, silence_warnings=True):
++                    done = True
++        for pkg in transaction.trans_data:
+             if pkg.state == 'Update':
++                if force_reinstall and self.rpmdb.searchPkgTuple(pkg.pkgtup):
++                    if self.reinstall(pkgtup=pkg.pkgtup):
++                        done = True
++                    continue
++
+                 if self.update(pkgtup=pkg.pkgtup):
+                     done = True
+                 else:
+                     self.logger.critical(_('Failed to upgrade: %s'), pkg)
+         for pkg in transaction.trans_data:
++            if force_changed_removal and pkg.state == 'Updated':
++                if self.tsInfo.getMembers(pkg.pkgtup):
++                    continue
++                if self.remove(pkgtup=pkg.pkgtup, silence_warnings=True):
++                    done = True
++        for pkg in transaction.trans_data:
+             if pkg.state in ('Install', 'True-Install', 'Obsoleting'):
++                if force_reinstall and self.rpmdb.searchPkgTuple(pkg.pkgtup):
++                    if self.reinstall(pkgtup=pkg.pkgtup):
++                        done = True
++                    continue
++
+                 if self.install(pkgtup=pkg.pkgtup):
+                     done = True
+         for pkg in transaction.trans_data:
+@@ -4538,8 +4951,14 @@ class YumBase(depsolve.Depsolve):
          return done
  
      def history_undo(self, transaction):
@@ -11905,7 +12193,31 @@ index 99039e0..5fb7c00 100644
          # 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):
+@@ -4674,34 +5093,37 @@ class YumBase(depsolve.Depsolve):
+             if pkgs:
+                 pkgs = sorted(pkgs)[-1]
+                 msg = (_('Importing %s key 0x%s:\n'
+-                         ' Userid : %s\n'
+-                         ' Package: %s (%s)\n'
+-                         ' From   : %s') %
++                         ' Userid     : "%s"\n'
++                         ' Fingerprint: %s\n'
++                         ' Package    : %s (%s)\n'
++                         ' From       : %s') %
+                        (keytype, info['hexkeyid'], to_unicode(info['userid']),
++                        misc.gpgkey_fingerprint_ascii(info),
+                         pkgs, pkgs.ui_from_repo,
+                         keyurl.replace("file://","")))
+         if msg is None:
+             msg = (_('Importing %s key 0x%s:\n'
+-                     ' Userid: "%s"\n'
+-                     ' From  : %s') %
++                     ' Userid     : "%s"\n'
++                     ' Fingerprint: %s\n'
++                     ' From       : %s') %
+                    (keytype, info['hexkeyid'], to_unicode(info['userid']),
++                    misc.gpgkey_fingerprint_ascii(info),
+                     keyurl.replace("file://","")))
          self.logger.critical("%s", msg)
  
      def getKeyForPackage(self, po, askcb = None, fullaskcb = None):
@@ -11937,7 +12249,7 @@ index 99039e0..5fb7c00 100644
          """
          repo = self.repos.getRepo(po.repoid)
          keyurls = repo.gpgkey
-@@ -4725,7 +5082,9 @@ class YumBase(depsolve.Depsolve):
+@@ -4725,7 +5147,9 @@ class YumBase(depsolve.Depsolve):
                      # Try installing/updating GPG key
                      self._getKeyImportMessage(info, keyurl)
                      rc = False
@@ -11948,7 +12260,7 @@ index 99039e0..5fb7c00 100644
                          rc = True
                          
                      # grab the .sig/.asc for the keyurl, if it exists
-@@ -4819,8 +5178,11 @@ class YumBase(depsolve.Depsolve):
+@@ -4819,8 +5243,11 @@ class YumBase(depsolve.Depsolve):
                  if not key_installed:
                      self._getKeyImportMessage(info, keyurl, keytype)
                      rc = False
@@ -11961,7 +12273,7 @@ index 99039e0..5fb7c00 100644
                      elif callback:
                          rc = callback({"repo": repo, "userid": info['userid'],
                                          "hexkeyid": info['hexkeyid'], "keyurl": keyurl,
-@@ -4861,26 +5223,23 @@ class YumBase(depsolve.Depsolve):
+@@ -4861,26 +5288,23 @@ class YumBase(depsolve.Depsolve):
                    'this repository.') % (repo.name)
  
      def getKeyForRepo(self, repo, callback=None):
@@ -12000,7 +12312,7 @@ index 99039e0..5fb7c00 100644
          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):
+@@ -4959,19 +5383,22 @@ class YumBase(depsolve.Depsolve):
              txmbr.depends_on.append(rel)
  
      def processTransaction(self, callback=None,rpmTestDisplay=None, rpmDisplay=None):
@@ -12036,7 +12348,7 @@ index 99039e0..5fb7c00 100644
          
          if not callback:
              callback = callbacks.ProcessTransNoOutputCallback()
-@@ -5114,13 +5476,19 @@ class YumBase(depsolve.Depsolve):
+@@ -5114,13 +5541,19 @@ class YumBase(depsolve.Depsolve):
          return results
  
      def add_enable_repo(self, repoid, baseurls=[], mirrorlist=None, **kwargs):
@@ -12063,7 +12375,7 @@ index 99039e0..5fb7c00 100644
          # 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):
+@@ -5167,9 +5600,15 @@ class YumBase(depsolve.Depsolve):
  
      def setCacheDir(self, force=False, tmpdir=None, reuse=True,
                      suffix='/$basearch/$releasever'):
@@ -12082,7 +12394,7 @@ index 99039e0..5fb7c00 100644
          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):
+@@ -5220,13 +5659,24 @@ class YumBase(depsolve.Depsolve):
          self.history.write_addon_data('config-repos', myrepos)
          
      def verify_plugins_cb(self, verify_package):
@@ -12110,7 +12422,7 @@ index 99039e0..5fb7c00 100644
          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):
+@@ -5234,7 +5684,7 @@ class YumBase(depsolve.Depsolve):
              raise Errors.YumBaseError(_("Dependencies not solved. Will not save unresolved transaction."))
          
          if not filename:
@@ -12119,7 +12431,7 @@ index 99039e0..5fb7c00 100644
              fd,filename = tempfile.mkstemp(suffix='.yumtx', prefix=prefix)
              f = os.fdopen(fd, 'w')
          else:
-@@ -5266,7 +5651,17 @@ class YumBase(depsolve.Depsolve):
+@@ -5266,7 +5716,17 @@ class YumBase(depsolve.Depsolve):
  
          
      def load_ts(self, filename, ignorerpm=None, ignoremissing=None):
@@ -12138,7 +12450,7 @@ index 99039e0..5fb7c00 100644
          # 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):
+@@ -5292,6 +5752,16 @@ class YumBase(depsolve.Depsolve):
          # 3+numrepos = num pkgs
          # 3+numrepos+1 -> EOF= txmembers
          
@@ -12303,7 +12615,7 @@ index 7ad25ce..a9a8e53 100644
          pass
          
 diff --git a/yum/config.py b/yum/config.py
-index d09511f..ef1b9e1 100644
+index d09511f..fffd0d1 100644
 --- a/yum/config.py
 +++ b/yum/config.py
 @@ -47,13 +47,12 @@ __pkgs_gpgcheck_default__ = False
@@ -13007,6 +13319,15 @@ index d09511f..ef1b9e1 100644
  
      http_caching = SelectionOption('all', ('none', 'packages', 'all'))
      metadata_expire = SecondsOption(60 * 60 * 6) # Time in seconds (6h).
+@@ -703,7 +795,7 @@ class YumConf(StartupConf):
+                  # all == install any/all arches you can
+                  # best == use the 'best  arch' for the system
+                  
+-    bugtracker_url = Option('http://yum.baseurl.org/report')
++    bugtracker_url = Option('https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&version=rawhide&component=yum')
+ 
+     color = SelectionOption('auto', ('auto', 'never', 'always'),
+                             mapper={'on' : 'always', 'yes' : 'always',
 @@ -747,6 +839,7 @@ class YumConf(StartupConf):
      
      clean_requirements_on_remove = BoolOption(False)
@@ -13203,11 +13524,16 @@ index d09511f..ef1b9e1 100644
  
          if name not in cfgOptions and option.default == value:
 diff --git a/yum/depsolve.py b/yum/depsolve.py
-index 6d744c0..8fe4952 100644
+index 6d744c0..c518311 100644
 --- a/yum/depsolve.py
 +++ b/yum/depsolve.py
-@@ -60,10 +60,7 @@ flags = {"GT": rpm.RPMSENSE_GREATER,
+@@ -58,12 +58,12 @@ flags = {"GT": rpm.RPMSENSE_GREATER,
+          "LE": rpm.RPMSENSE_LESS | rpm.RPMSENSE_EQUAL,
+          "EQ": rpm.RPMSENSE_EQUAL,
           None: 0 }
++_rflags = {}
++for f in flags:
++    _rflags[flags[f]] = f
  
  class Depsolve(object):
 -
@@ -13218,7 +13544,7 @@ index 6d744c0..8fe4952 100644
  
      def __init__(self):
          self._ts = None
-@@ -81,6 +78,8 @@ class Depsolve(object):
+@@ -81,6 +81,8 @@ class Depsolve(object):
          self.installedUnresolvedFileRequires = None
  
      def doTsSetup(self):
@@ -13227,7 +13553,7 @@ index 6d744c0..8fe4952 100644
          warnings.warn(_('doTsSetup() will go away in a future version of Yum.\n'),
                  Errors.YumFutureDeprecationWarning, stacklevel=2)
          return self._getTs()
-@@ -131,7 +130,7 @@ class Depsolve(object):
+@@ -131,7 +133,7 @@ class Depsolve(object):
          
  
      def initActionTs(self):
@@ -13236,7 +13562,7 @@ index 6d744c0..8fe4952 100644
          
          self._ts = rpmUtils.transaction.TransactionWrapper(self.conf.installroot)
          ts_flags_to_rpm = { 'noscripts': rpm.RPMTRANS_FLAG_NOSCRIPTS,
-@@ -158,19 +157,31 @@ class Depsolve(object):
+@@ -158,19 +160,31 @@ class Depsolve(object):
          self._ts.setProbFilter(probfilter)
  
      def whatProvides(self, name, flags, version):
@@ -13275,7 +13601,7 @@ index 6d744c0..8fe4952 100644
          iopkgs = set(self.conf.installonlypkgs)
          if po.name in iopkgs:
              return True
-@@ -182,8 +193,11 @@ class Depsolve(object):
+@@ -182,8 +196,11 @@ class Depsolve(object):
          return False
  
      def populateTs(self, test=0, keepold=1):
@@ -13288,7 +13614,37 @@ index 6d744c0..8fe4952 100644
          if self.dsCallback: self.dsCallback.transactionPopulation()
          ts_elem = {}
          
-@@ -696,6 +710,13 @@ class Depsolve(object):
+@@ -393,9 +410,27 @@ class Depsolve(object):
+             self.conf.obsoletes = 0
+             txmbrs = self.update(po=requiringPo, requiringPo=requiringPo)
+             self.conf.obsoletes = origobs
+-            if not txmbrs:
++
++            def _check_update_worked(txmbrs, obs=False):
++                #  Old code assumed that if there was an update, we were good:
++                #    if txmbrs: return True
++                # ..however we have a problem when foo-1 and foo-2 both require
++                # bar-1, and bar-2 is being installed. If the req. is identical
++                # then we'll skip checking it in _checkInstall(), so we need to
++                # check it here.
++                for txmbr in txmbrs:
++                    if obs or txmbr.name == requiringPo.name:
++                        n,f,v = requirement
++                        creq = (n, _rflags[f],
++                                rpmUtils.miscutils.stringToVersion(v))
++                        # If it's identical ... checkInstall will skip it.
++                        if creq not in txmbr.po.requires:
++                            return True
++                return False
++
++            if not _check_update_worked(txmbrs):
+                 txmbrs = self.update(po=requiringPo, requiringPo=requiringPo)
+-                if not txmbrs:
++                if not _check_update_worked(txmbrs, obs=True):
+                     msg = self._err_missing_requires(requiringPo, requirement)
+                     self.verbose_logger.log(logginglevels.DEBUG_2, _('No update paths found for %s. Failure!'), requiringPo)
+                     return self._requiringFromTransaction(requiringPo, requirement, errorlist)
+@@ -696,6 +731,13 @@ class Depsolve(object):
                  self.tsInfo.remove(txmbr.pkgtup)
  
      def prof_resolveDeps(self):
@@ -13302,7 +13658,7 @@ index 6d744c0..8fe4952 100644
          fn = "anaconda.prof.0"
          import hotshot, hotshot.stats
          prof = hotshot.Profile(fn)
-@@ -709,6 +730,13 @@ class Depsolve(object):
+@@ -709,6 +751,13 @@ class Depsolve(object):
          return rc
  
      def cprof_resolveDeps(self):
@@ -13316,7 +13672,7 @@ index 6d744c0..8fe4952 100644
          import cProfile, pstats
          prof = cProfile.Profile()
          rc = prof.runcall(self.resolveDeps)
-@@ -722,7 +750,17 @@ class Depsolve(object):
+@@ -722,7 +771,17 @@ class Depsolve(object):
          return rc
  
      def resolveDeps(self, full_check=True, skipping_broken=False):
@@ -13335,7 +13691,33 @@ index 6d744c0..8fe4952 100644
          if not len(self.tsInfo):
              return (0, [_('Success - empty transaction')])
  
-@@ -1150,6 +1188,11 @@ class Depsolve(object):
+@@ -778,6 +837,25 @@ class Depsolve(object):
+                     if checkdep:
+                         break # The next conflict might be the same pkg
+ 
++                # check Obsoletes
++                #  Atm. This is _just_ checking for transaction members which
++                # obsolete each other. Because rpm will now auto. obs. those
++                # anyway. We _don't_ check for installed pkgs. which might obs.
++                # something to be installed, even though rpm will also do that.
++                for txmbr in self.tsInfo.getMembersWithState(None, output_states=TS_INSTALL_STATES):
++                    for obs_n in txmbr.po.obsoletes_names:
++                        for otxmbr in self.tsInfo.matchNaevr(name=obs_n):
++                            if otxmbr.output_state not in TS_INSTALL_STATES:
++                                continue
++                            if otxmbr.po.obsoletedBy([txmbr.po]):
++                                self.tsInfo.remove(otxmbr.pkgtup)
++                                #  We need to remove an obsoleted entry that
++                                # was maybe used to resolve something ... ?
++                                CheckDeps = True
++                                self._last_req = None
++                                self.pkgSack.delPackage(otxmbr.po)
++                                self.up.delPackage(otxmbr.pkgtup)
++
+                 if CheckDeps:
+                     if self.dsCallback: self.dsCallback.restartLoop()
+                     self.verbose_logger.log(logginglevels.DEBUG_1, _('Restarting Loop'))
+@@ -1150,6 +1228,11 @@ class Depsolve(object):
          return ret
  
      def isPackageInstalled(self, pkgname):
@@ -13347,7 +13729,7 @@ index 6d744c0..8fe4952 100644
          lst = self.tsInfo.matchNaevr(name = pkgname)
          for txmbr in lst:
              if txmbr.output_state in TS_INSTALL_STATES:
-@@ -1393,42 +1436,52 @@ class Depsolve(object):
+@@ -1393,42 +1476,52 @@ class Depsolve(object):
  
  
  class DepCheck(object):
@@ -13390,12 +13772,12 @@ index 6d744c0..8fe4952 100644
  
  class Requires(object):
 -
+-    """
+-    A pure data class for holding a package and the list of things it
+-    requires.
 +    """A pure data class for holding a package and the list of things
 +    it requires.
      """
--    A pure data class for holding a package and the list of things it
--    requires.
--    """
 -
      def __init__(self, pkg,requires):
          self.pkg = pkg # po of requiring pkg
@@ -13404,12 +13786,12 @@ index 6d744c0..8fe4952 100644
  
  class Conflicts(object):
 -
+-    """
+-    A pure data class for holding a package and the list of things it
+-    conflicts.
 +    """A pure data class for holding a list packages and what the
 +    conflict between them is.
      """
--    A pure data class for holding a package and the list of things it
--    conflicts.
--    """
 -
      def __init__(self, pkglist, conflict):
          self.pkglist = pkglist # list of conflicting package objects
@@ -13550,7 +13932,7 @@ index bca9651..00c17ad 100644
              index = self.failures
          else:
 diff --git a/yum/history.py b/yum/history.py
-index 5385bd1..8e62f50 100644
+index 5385bd1..d27fa44 100644
 --- a/yum/history.py
 +++ b/yum/history.py
 @@ -97,9 +97,58 @@ def _setupHistorySearchSQL(patterns=None, ignore_case=False):
@@ -13820,7 +14202,20 @@ index 5385bd1..8e62f50 100644
              obj.main = row[6] == 'TRUE'
              ret.append(obj)
          return ret
-@@ -1151,6 +1264,127 @@ class YumHistory:
+@@ -1091,7 +1204,11 @@ class YumHistory:
+         if tids and len(tids) <= yum.constants.PATTERNS_INDEXED_MAX:
+             params = tids = list(set(tids))
+             sql += " WHERE tid IN (%s)" % ", ".join(['?'] * len(tids))
+-        sql += " ORDER BY beg_ts DESC, tid ASC"
++        #  This relies on the fact that the PRIMARY KEY in sqlite will always
++        # increase with each transaction. In theory we can use:
++        # ORDER BY beg_ts DESC ... except sometimes people do installs with a
++        # system clock that is very broken, and using that screws them forever.
++        sql += " ORDER BY tid DESC"
+         if limit is not None:
+             sql += " LIMIT " + str(limit)
+         executeSQL(cur, sql, params)
+@@ -1151,6 +1268,127 @@ class YumHistory:
          assert len(ret) == 1
          return ret[0]
  
@@ -13948,7 +14343,7 @@ index 5385bd1..8e62f50 100644
      def _yieldSQLDataList(self, patterns, fields, ignore_case):
          """Yields all the package data for the given params. """
  
-@@ -1220,6 +1454,47 @@ class YumHistory:
+@@ -1220,6 +1458,47 @@ class YumHistory:
              tids.add(row[0])
          return tids
  
@@ -13996,7 +14391,7 @@ index 5385bd1..8e62f50 100644
      _update_ops_2 = ['''\
  \
   CREATE TABLE trans_skip_pkgs (
-@@ -1374,6 +1649,8 @@ class YumHistory:
+@@ -1374,6 +1653,8 @@ class YumHistory:
              cur.execute(op)
          for op in self._update_ops_2:
              cur.execute(op)
@@ -14045,10 +14440,36 @@ index 9889bf6..85ad15e 100755
      '''
      Setup the yum translation domain and make _() and P_() translation wrappers
 diff --git a/yum/misc.py b/yum/misc.py
-index 2f6ddfe..04490a6 100644
+index 2f6ddfe..5321003 100644
 --- a/yum/misc.py
 +++ b/yum/misc.py
-@@ -940,14 +940,16 @@ def unlink_f(filename):
+@@ -8,6 +8,7 @@ import os
+ import os.path
+ from cStringIO import StringIO
+ import base64
++import binascii
+ import struct
+ import re
+ import errno
+@@ -410,6 +411,17 @@ def procgpgkey(rawkey):
+     # Decode and return
+     return base64.decodestring(block.getvalue())
+ 
++def gpgkey_fingerprint_ascii(info, chop=4):
++    ''' Given a key_info data from getgpgkeyinfo(), return an ascii
++    fingerprint. Chop every 4 ascii values, as that is what GPG does. '''
++    # First "duh" ... it's a method...
++    fp = info['fingerprint']()
++    fp = binascii.hexlify(fp)
++    if chop:
++        fp = [fp[i:i+chop] for i in range(0, len(fp), chop)]
++        fp = " ".join(fp)
++    return fp
++
+ def getgpgkeyinfo(rawkey, multiple=False):
+     '''Return a dict of info for the given ASCII armoured key text
+ 
+@@ -940,14 +952,16 @@ def unlink_f(filename):
          if e.errno != errno.ENOENT:
              raise
  
@@ -14069,7 +14490,7 @@ index 2f6ddfe..04490a6 100644
  
  def _getloginuid():
      """ Get the audit-uid/login-uid, if available. None is returned if there
-@@ -1112,10 +1114,12 @@ def decompress(filename, dest=None, fn_only=False, check_timestamps=False):
+@@ -1112,10 +1126,12 @@ def decompress(filename, dest=None, fn_only=False, check_timestamps=False):
          if check_timestamps:
              fi = stat_f(filename)
              fo = stat_f(out)
@@ -14084,25 +14505,118 @@ index 2f6ddfe..04490a6 100644
      return out
      
 diff --git a/yum/packages.py b/yum/packages.py
-index 5ef9951..f72c068 100644
+index 5ef9951..15316c8 100644
 --- a/yum/packages.py
 +++ b/yum/packages.py
-@@ -271,6 +271,14 @@ class PackageObject(object):
-         return out
+@@ -243,34 +243,87 @@ class PackageObject(object):
+         
+     def _ui_envra(self):
+         if self.epoch == '0':
+-            out = '%s-%s-%s.%s' % (self.name, 
+-                                   self.version,
+-                                   self.release, 
+-                                   self.arch)
++            return self.nvra
+         else:
+-            out = '%s:%s-%s-%s.%s' % (self.epoch,
+-                                      self.name,  
+-                                      self.version, 
+-                                      self.release, 
+-                                      self.arch)
+-        return out
++            return self.envra
+     ui_envra = property(fget=lambda self: self._ui_envra())
+ 
+     def _ui_nevra(self):
+         if self.epoch == '0':
+-            out = '%s-%s-%s.%s' % (self.name,
+-                                   self.version,
+-                                   self.release,
+-                                   self.arch)
++            return self.nvra
+         else:
+-            out = '%s-%s:%s-%s.%s' % (self.name,
+-                                      self.epoch,
+-                                      self.version,
+-                                      self.release,
+-                                      self.arch)
+-        return out
++            return self.nevra
      ui_nevra = property(fget=lambda self: self._ui_nevra())
  
 +    def _ui_evr(self):
 +        if self.epoch == '0':
-+            out = '%s-%s' % (self.version, self.release)
++            return self.vr
 +        else:
-+            out = '%s:%s-%s' % (self.epoch, self.version, self.release)
-+        return out
++            return self.evr
 +    ui_evr = property(fget=lambda self: self._ui_evr())
 +
++    def _ui_evra(self):
++        if self.epoch == '0':
++            return self.vra
++        else:
++            return self.evra
++    ui_evra = property(fget=lambda self: self._ui_evra())
++
++    def _ui_nevr(self):
++        if self.epoch == '0':
++            return self.nvr
++        else:
++            return self.nevr
++    ui_nevr = property(fget=lambda self: self._ui_nevr())
++
++    def _na(self):
++        return '%s.%s' % (self.name, self.arch)
++    na = property(fget=lambda self: self._na())
++
++    def _vr(self):
++        return '%s-%s' % (self.version, self.release)
++    vr = property(fget=lambda self: self._vr())
++
++    def _vra(self):
++        return '%s-%s.%s' % (self.version, self.release, self.arch)
++    vra = property(fget=lambda self: self._vra())
++
++    def _evr(self):
++        return '%s:%s-%s' % (self.epoch, self.version, self.release)
++    evr = property(fget=lambda self: self._evr())
++
++    def _evra(self):
++        return '%s:%s-%s.%s' % (self.epoch,self.version,self.release, self.arch)
++    evra = property(fget=lambda self: self._evra())
++
++    def _nvr(self):
++        return '%s-%s-%s' % (self.name, self.version, self.release)
++    nvr = property(fget=lambda self: self._nvr())
++
++    def _nvra(self):
++        return '%s-%s-%s.%s' % (self.name, self.version,self.release, self.arch)
++    nvra = property(fget=lambda self: self._nvra())
++
++    def _nevr(self):
++        return '%s-%s:%s-%s' % (self.name, self.epoch,self.version,self.release)
++    nevr = property(fget=lambda self: self._nevr())
++
++    def _nevra(self):
++        return '%s-%s:%s-%s.%s' % (self.name,
++                                   self.epoch, self.version, self.release,
++                                   self.arch)
++    nevra = property(fget=lambda self: self._nevra())
++
++    def _envr(self):
++        return '%s:%s-%s-%s' % (self.epoch,self.name, self.version,self.release)
++    envr = property(fget=lambda self: self._envr())
++
++    def _envra(self):
++        return '%s:%s-%s-%s.%s' % (self.epoch, self.name,
++                                   self.version, self.release,
++                                   self.arch)
++    envra = property(fget=lambda self: self._envra())
++
      def __str__(self):
          return self.ui_envra
  
-@@ -1083,7 +1091,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1083,7 +1136,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
           misc.to_unicode(misc.to_xml(self.summary)), 
           misc.to_unicode(misc.to_xml(self.description)), 
           packager, url, self.filetime, 
@@ -14111,7 +14625,7 @@ index 5ef9951..f72c068 100644
          
          msg += self._return_remote_location()
          return msg
-@@ -1133,7 +1141,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1133,7 +1186,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
          msg = ""
          mylist = getattr(self, pcotype)
          if mylist: msg = "\n    <rpm:%s>\n" % pcotype
@@ -14120,7 +14634,7 @@ index 5ef9951..f72c068 100644
              pcostring = '''      <rpm:entry name="%s"''' % misc.to_xml(name, attrib=True)
              if flags:
                  pcostring += ''' flags="%s"''' % misc.to_xml(flags, attrib=True)
-@@ -1161,11 +1169,11 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1161,11 +1214,11 @@ class YumAvailablePackage(PackageObject, RpmBase):
              dirs = self.returnFileEntries('dir', primary_only=True)
              ghosts = self.returnFileEntries('ghost', primary_only=True)
                  
@@ -14135,7 +14649,7 @@ index 5ef9951..f72c068 100644
              msg += """    <file type="ghost">%s</file>\n""" % misc.to_xml(fn)
          
          return msg
-@@ -1194,8 +1202,8 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1194,8 +1247,8 @@ class YumAvailablePackage(PackageObject, RpmBase):
                          continue
                      newlist.append(i)
                  mylist = newlist
@@ -14146,7 +14660,7 @@ index 5ef9951..f72c068 100644
              if name.startswith('rpmlib('):
                  continue
              # this drops out requires that the pkg provides for itself.
-@@ -1217,13 +1225,16 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1217,13 +1270,16 @@ class YumAvailablePackage(PackageObject, RpmBase):
                      prcostring += ''' ver="%s"''' % misc.to_xml(v, attrib=True)
                  if r:
                      prcostring += ''' rel="%s"''' % misc.to_xml(r, attrib=True)
@@ -14165,7 +14679,7 @@ index 5ef9951..f72c068 100644
          return msg
  
      def _dump_changelog(self, clog_limit):
-@@ -1299,7 +1310,8 @@ class YumHeaderPackage(YumAvailablePackage):
+@@ -1299,7 +1355,8 @@ class YumHeaderPackage(YumAvailablePackage):
          self.pkgid = self.hdr[rpm.RPMTAG_SHA1HEADER]
          if not self.pkgid:
              self.pkgid = "%s.%s" %(self.hdr['name'], self.hdr['buildtime'])
@@ -14892,7 +15406,7 @@ index e5e9ece..91b7dde 100644
                  return None
              raise
 diff --git a/yumcommands.py b/yumcommands.py
-index 4dcbea7..2ab9a28 100644
+index 4dcbea7..a862064 100644
 --- a/yumcommands.py
 +++ b/yumcommands.py
 @@ -43,16 +43,22 @@ def _err_mini_usage(base, basecmd):
@@ -15997,7 +16511,7 @@ index 4dcbea7..2ab9a28 100644
          self.doneCommand(base, _("Setting up Local Package Process"))
  
          updateonly = basecmd == 'localupdate'
-@@ -755,19 +1399,57 @@ class LocalInstallCommand(YumCommand):
+@@ -755,19 +1399,61 @@ class LocalInstallCommand(YumCommand):
              return 1, [str(e)]
  
      def needTs(self, base, basecmd, extcmds):
@@ -16016,6 +16530,10 @@ index 4dcbea7..2ab9a28 100644
 +    resolvedep command.
 +    """
 +
++    def __init__(self):
++        YumCommand.__init__(self)
++        self.hidden = True
++
      def getNames(self):
 +        """Return a list containing the names of this command.  This
 +        command can be called from the command line by using any of these names.
@@ -16032,11 +16550,12 @@ index 4dcbea7..2ab9a28 100644
          return "DEPENDENCY"
  
      def getSummary(self):
+-        return _("Determine which package provides the given dependency")
 +        """Return a one line summary of this command.
 +
 +        :return: a one line summary of this command
 +        """
-         return _("Determine which package provides the given dependency")
++        return "repoquery --pkgnarrow=all --whatprovides --qf '%{envra} %{ui_from_repo}'"
  
      def doCommand(self, base, basecmd, extcmds):
 +        """Execute this command.
@@ -16055,7 +16574,7 @@ index 4dcbea7..2ab9a28 100644
          base.logger.debug(_("Searching Packages for Dependency:"))
          try:
              return base.resolveDepCli(extcmds)
-@@ -775,19 +1457,56 @@ class ResolveDepCommand(YumCommand):
+@@ -775,19 +1461,56 @@ class ResolveDepCommand(YumCommand):
              return 1, [str(e)]
  
  class ShellCommand(YumCommand):
@@ -16112,7 +16631,7 @@ index 4dcbea7..2ab9a28 100644
          self.doneCommand(base, _('Setting up Yum Shell'))
          try:
              return base.doShell()
-@@ -795,23 +1514,69 @@ class ShellCommand(YumCommand):
+@@ -795,23 +1518,69 @@ class ShellCommand(YumCommand):
              return 1, [str(e)]
  
      def needTs(self, base, basecmd, extcmds):
@@ -16182,7 +16701,7 @@ index 4dcbea7..2ab9a28 100644
          self.doneCommand(base, _("Finding dependencies: "))
          try:
              return base.deplist(extcmds)
-@@ -820,17 +1585,46 @@ class DepListCommand(YumCommand):
+@@ -820,17 +1589,46 @@ class DepListCommand(YumCommand):
  
  
  class RepoListCommand(YumCommand):
@@ -16229,7 +16748,7 @@ index 4dcbea7..2ab9a28 100644
          def _repo_size(repo):
              ret = 0
              for pkg in repo.sack.returnPackages():
-@@ -1088,21 +1882,54 @@ class RepoListCommand(YumCommand):
+@@ -1088,21 +1886,54 @@ class RepoListCommand(YumCommand):
          return 0, ['repolist: ' +to_unicode(locale.format("%d", tot_num, True))]
  
      def needTs(self, base, basecmd, extcmds):
@@ -16284,7 +16803,7 @@ index 4dcbea7..2ab9a28 100644
          if len(extcmds) == 0:
              base.usage()
              raise cli.CliError
-@@ -1147,28 +1974,85 @@ class HelpCommand(YumCommand):
+@@ -1147,28 +1978,85 @@ class HelpCommand(YumCommand):
          return help_output
  
      def doCommand(self, base, basecmd, extcmds):
@@ -16370,7 +16889,7 @@ index 4dcbea7..2ab9a28 100644
          self.doneCommand(base, _("Setting up Reinstall Process"))
          try:
              return base.reinstallPkgs(extcmds)
-@@ -1177,25 +2061,73 @@ class ReInstallCommand(YumCommand):
+@@ -1177,25 +2065,73 @@ class ReInstallCommand(YumCommand):
              return 1, [to_unicode(e)]
  
      def getSummary(self):
@@ -16444,7 +16963,7 @@ index 4dcbea7..2ab9a28 100644
          self.doneCommand(base, _("Setting up Downgrade Process"))
          try:
              return base.downgradePkgs(extcmds)
-@@ -1203,23 +2135,65 @@ class DowngradeCommand(YumCommand):
+@@ -1203,23 +2139,65 @@ class DowngradeCommand(YumCommand):
              return 1, [str(e)]
  
      def getSummary(self):
@@ -16510,7 +17029,7 @@ index 4dcbea7..2ab9a28 100644
          vcmd = 'installed'
          if extcmds:
              vcmd = extcmds[0]
-@@ -1344,6 +2318,14 @@ class VersionCommand(YumCommand):
+@@ -1344,6 +2322,14 @@ class VersionCommand(YumCommand):
          return 0, ['version']
  
      def needTs(self, base, basecmd, extcmds):
@@ -16525,7 +17044,7 @@ index 4dcbea7..2ab9a28 100644
          vcmd = 'installed'
          if extcmds:
              vcmd = extcmds[0]
-@@ -1354,13 +2336,30 @@ class VersionCommand(YumCommand):
+@@ -1354,23 +2340,62 @@ class VersionCommand(YumCommand):
  
  
  class HistoryCommand(YumCommand):
@@ -16556,7 +17075,40 @@ index 4dcbea7..2ab9a28 100644
          return _("Display, or use, the transaction history")
  
      def _hcmd_redo(self, base, extcmds):
-@@ -1426,12 +2425,54 @@ class HistoryCommand(YumCommand):
++        kwargs = {'force_reinstall' : False,
++                  'force_changed_removal' : False,
++                  }
++        kwargs_map = {'reinstall' : 'force_reinstall',
++                      'force-reinstall' : 'force_reinstall',
++                      'remove' : 'force_changed_removal',
++                      'force-remove' : 'force_changed_removal',
++                      }
++        while len(extcmds) > 1:
++            done = False
++            for arg in extcmds[1].replace(' ', ',').split(','):
++                if arg not in kwargs_map:
++                    continue
++
++                done = True
++                key = kwargs_map[extcmds[1]]
++                kwargs[key] = not kwargs[key]
++
++            if not done:
++                break
++            extcmds = [extcmds[0]] + extcmds[2:]
++
+         old = base._history_get_transaction(extcmds)
+         if old is None:
+             return 1, ['Failed history redo']
+         tm = time.ctime(old.beg_timestamp)
+         print "Repeating transaction %u, from %s" % (old.tid, tm)
+         base.historyInfoCmdPkgsAltered(old)
+-        if base.history_redo(old):
++        if base.history_redo(old, **kwargs):
+             return 2, ["Repeating transaction %u" % (old.tid,)]
+ 
+     def _hcmd_undo(self, base, extcmds):
+@@ -1426,12 +2451,54 @@ class HistoryCommand(YumCommand):
      def _hcmd_new(self, base, extcmds):
          base.history._create_db_file()
  
@@ -16612,7 +17164,7 @@ index 4dcbea7..2ab9a28 100644
          if extcmds and extcmds[0] not in cmds:
              base.logger.critical(_('Invalid history sub-command, use: %s.'),
                                   ", ".join(cmds))
-@@ -1444,6 +2485,19 @@ class HistoryCommand(YumCommand):
+@@ -1444,6 +2511,19 @@ class HistoryCommand(YumCommand):
              raise cli.CliError
  
      def doCommand(self, base, basecmd, extcmds):
@@ -16632,7 +17184,7 @@ index 4dcbea7..2ab9a28 100644
          vcmd = 'list'
          if extcmds:
              vcmd = extcmds[0]
-@@ -1468,12 +2522,26 @@ class HistoryCommand(YumCommand):
+@@ -1468,12 +2548,26 @@ class HistoryCommand(YumCommand):
              ret = self._hcmd_rollback(base, extcmds)
          elif vcmd == 'new':
              ret = self._hcmd_new(base, extcmds)
@@ -16659,7 +17211,7 @@ index 4dcbea7..2ab9a28 100644
          vcmd = 'list'
          if extcmds:
              vcmd = extcmds[0]
-@@ -1481,16 +2549,46 @@ class HistoryCommand(YumCommand):
+@@ -1481,16 +2575,46 @@ class HistoryCommand(YumCommand):
  
  
  class CheckRpmdbCommand(YumCommand):
@@ -16706,7 +17258,7 @@ index 4dcbea7..2ab9a28 100644
          chkcmd = 'all'
          if extcmds:
              chkcmd = extcmds
-@@ -1505,19 +2603,57 @@ class CheckRpmdbCommand(YumCommand):
+@@ -1505,19 +2629,57 @@ class CheckRpmdbCommand(YumCommand):
          return rc, ['%s %s' % (basecmd, chkcmd)]
  
      def needTs(self, base, basecmd, extcmds):
@@ -16764,7 +17316,7 @@ index 4dcbea7..2ab9a28 100644
          if not extcmds:
              base.logger.critical(_("No saved transaction file specified."))
              raise cli.CliError
-@@ -1533,5 +2669,13 @@ class LoadTransactionCommand(YumCommand):
+@@ -1533,5 +2695,13 @@ class LoadTransactionCommand(YumCommand):
  
  
      def needTs(self, base, basecmd, extcmds):
@@ -16779,7 +17331,7 @@ index 4dcbea7..2ab9a28 100644
          return True
  
 diff --git a/yummain.py b/yummain.py
-index 9f79f4f..4b1112a 100755
+index 9f79f4f..58179d2 100755
 --- a/yummain.py
 +++ b/yummain.py
 @@ -29,13 +29,13 @@ from yum import Errors
@@ -16799,6 +17351,25 @@ index 9f79f4f..4b1112a 100755
  
      yum.misc.setup_locale(override_time=True)
  
+@@ -102,15 +102,15 @@ def main(args):
+         return exFatal(e)
+ 
+     # Try to open the current directory to see if we have 
+-    # read and write access. If not, chdir to /
++    # read and execute access. If not, chdir to /
+     try:
+         f = open(".")
+     except IOError, e:
+         if e.errno == errno.EACCES:
+-            logger.critical(_('No read/write access in current directory, moving to /'))
++            logger.critical(_('No read/execute access in current directory, moving to /'))
+             os.chdir("/")
+     else:
+-        close(f)
++        f.close()
+ 
+     lockerr = ""
+     while True:
 @@ -120,16 +120,16 @@ def main(args):
              if exception2msg(e) != lockerr:
                  lockerr = exception2msg(e)
@@ -16948,21 +17519,3 @@ index 9b265f9..4d468dc 100644
                          'repackaging': _('Repackaging')}
          # The fileaction are not translated, most sane IMHO / Tim
          self.fileaction = { TS_UPDATE: 'Updated', 
-commit bd68865d70245943a3f208a018975be38f6e1d3d
-Author: James Antill <james at and.org>
-Date:   Wed Sep 21 17:12:29 2011 -0400
-
-    Fix most of the tests due to missing FakeConf value.
-
-diff --git a/test/testbase.py b/test/testbase.py
-index d0f22be..c185a7f 100644
---- a/test/testbase.py
-+++ b/test/testbase.py
-@@ -55,6 +55,7 @@ class FakeConf(object):
-         self.protected_packages = []
-         self.protected_multilib = False
-         self.clean_requirements_on_remove = True
-+        self.upgrade_requirements_on_install = False
- 
- class FakeSack:
-     """ Fake PackageSack to use with FakeRepository"""
diff --git a/yum.spec b/yum.spec
index 9c09879..72f6f9a 100644
--- a/yum.spec
+++ b/yum.spec
@@ -18,7 +18,7 @@
 Summary: RPM package installer/updater/manager
 Name: yum
 Version: 3.4.3
-Release: 10%{?dist}
+Release: 11%{?dist}
 License: GPLv2+
 Group: System Environment/Base
 Source0: http://yum.baseurl.org/download/3.4/%{name}-%{version}.tar.gz
@@ -316,6 +316,14 @@ exit 0
 %endif
 
 %changelog
+* Fri Oct 14 2011 James Antill <james at fedoraproject.org> - 3.4.3-11
+- update to latest HEAD
+- Some edge case depsolver bug fixes.
+- Output the GPG fingerprint when showing the GPG key.
+- Update bugtracker URL back to redhat.
+- Allow reinstall and remove arguments to history redo command.
+- Let resolvedep look for installed packages.
+
 * Tue Sep 21 2011 James Antill <james at fedoraproject.org> - 3.4.3-10
 - update to latest HEAD
 - Fix for history sync, and saving on install.


More information about the scm-commits mailing list