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 \n" % pcotype @@ -14120,7 +14634,7 @@ index 5ef9951..f72c068 100644 pcostring = ''' %s\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 -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 - 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 - 3.4.3-10 - update to latest HEAD - Fix for history sync, and saving on install.