From 1f1d7ddbda3d26477388ff88d4f9f1c9953459e1 Mon Sep 17 00:00:00 2001 From: CentOS Buildsys Date: Apr 08 2014 16:44:28 +0000 Subject: import yum-3.4.3-117.el7.src.rpm --- diff --git a/SOURCES/BZ-1033416-yum-error-on-non-us-locale.patch b/SOURCES/BZ-1033416-yum-error-on-non-us-locale.patch new file mode 100644 index 0000000..57a2ea8 --- /dev/null +++ b/SOURCES/BZ-1033416-yum-error-on-non-us-locale.patch @@ -0,0 +1,43 @@ +diff --git a/test/misc-tests.py b/test/misc-tests.py +index 7d7d06f..11fd041 100644 +--- a/test/misc-tests.py ++++ b/test/misc-tests.py +@@ -150,6 +150,19 @@ class MiscTests(DepsolveTests): + self.assertEqual(type(actual), type(expected)) + self.assertEqual(actual, expected) + ++ def testOptparse(self): ++ # make 'Usage: %s\n' translated ++ import gettext ++ def dgettext(domain, msg, orig=gettext.dgettext): ++ if domain=='messages' and msg == 'Usage: %s\n': ++ return 'Pou\xc5\xbeit\xc3\xad: %s\n' ++ return orig(domain, msg) ++ gettext.dgettext = dgettext ++ # run "yum --help" ++ from optparse import OptionParser ++ parser = OptionParser(usage=u'\u011b\u0161\u010d') ++ self.assertRaises(SystemExit, parser.parse_args, args=['--help']) ++ + def setup_logging(): + logging.basicConfig() + plainformatter = logging.Formatter("%(message)s") +diff --git a/yum/i18n.py b/yum/i18n.py +index 76a258d..2c0cbce 100755 +--- a/yum/i18n.py ++++ b/yum/i18n.py +@@ -500,6 +500,14 @@ try: + t = gettext.translation('yum', fallback=True) + _ = t.ugettext + P_ = t.ungettext ++ ++ # we describe yum commands and options with unicode but optparse ++ # mixes this with non-unicode translations so "yum --help" may fail. ++ # It's much easier to fix this in optparse than in yum. BZ 1033416 ++ import optparse ++ if optparse._ is gettext.gettext: ++ #optparse._ = lambda msg: to_unicode(gettext.gettext(msg)) ++ optparse._ = gettext.translation('messages', fallback=True).ugettext + except: + ''' + Something went wrong so we make a dummy _() wrapper there is just diff --git a/SOURCES/BZ-1040619-yum-cron-reporting.patch b/SOURCES/BZ-1040619-yum-cron-reporting.patch new file mode 100644 index 0000000..9964b7e --- /dev/null +++ b/SOURCES/BZ-1040619-yum-cron-reporting.patch @@ -0,0 +1,231 @@ +commit 1fb713cdabf46694e76df4092615607fa09016fe +Author: Zdenek Pavlas +Date: Thu Dec 19 10:43:07 2013 +0100 + + yum-cron: initialize both debuglevel and errorlevel + + When warnings or errors are disabled in verbose + logger, disable them in error logger too. + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index a1fd10b..19436e5 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -380,16 +380,16 @@ class YumCronBase(yum.YumBase, YumOutput): + self.preconf.fn = self.opts.yum_config_file + + # This needs to be set early, errors are handled later. +- try: self.preconf.debuglevel = int(self._confparser.get('base', 'debuglevel')) +- except: pass ++ try: level = int(self._confparser.get('base', 'debuglevel')) ++ except: level = -2 ++ self.preconf.debuglevel = level ++ if -4 <= level <= -2: ++ self.preconf.errorlevel = level + 4 + + # if we are not root do the special subdir thing + if os.geteuid() != 0: + self.setCacheDir() + +- # Create the configuration +- self.conf +- + # override base yum options + self.conf.populate(self._confparser, 'base') + del self._confparser +commit d0441397dc5a5e4f4d3ccc3a99c4cda57b228009 +Author: Valentina Mukhamedzhanova +Date: Mon Jan 6 14:12:46 2014 +0100 + + Remove emitCheckFailed(), change it to logger.warn(). BZ 1048391 + + Make acquireLock() respect debuglevel. + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index b96dd13..386a7a0 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -86,17 +86,6 @@ class UpdateEmitter(object): + % errmsg) + self.sendMessages() + +- def lockFailed(self, errmsg): +- """Append a message to the output list stating that the +- program failed to acquire the yum lock, then call sendMessages +- to emit the output. +- +- :param errmsg: a string that contains the error message +- """ +- self.output.append("Failed to acquire the yum lock with the following error message: \n%s" +- % errmsg) +- self.sendMessages() +- + def checkFailed(self, errmsg): + """Append a message to the output stating that checking for + updates failed, then call sendMessages to emit the output. +@@ -196,16 +185,6 @@ class EmailEmitter(UpdateEmitter): + self.subject = "Yum: Failed to perform setup on %s" % self.opts.system_name + super(EmailEmitter, self).setupFailed(errmsg) + +- def lockFailed(self, errmsg): +- """Append a message to the output list stating that the +- program failed to acquire the yum lock, then call sendMessages +- to emit the output, and set an appropriate subject line. +- +- :param errmsg: a string that contains the error message +- """ +- self.subject = "Yum: Failed to acquire the yum lock on %s" % self.opts.system_name +- super(EmailEmitter, self).lockFailed(errmsg) +- + def checkFailed(self, errmsg): + """Append a message to the output stating that checking for + updates failed, then call sendMessages to emit the output, and +@@ -406,7 +385,7 @@ class YumCronBase(yum.YumBase, YumOutput): + try: + self.doLock() + except yum.Errors.LockError, e: +- self.emitLockFailed("%s" % e) ++ self.logger.warn("Failed to acquire the yum lock: %s", e) + sys.exit(1) + + def populateUpdateMetadata(self): +@@ -675,10 +654,6 @@ class YumCronBase(yum.YumBase, YumOutput): + """Emit a notice stating that checking for updates failed.""" + map(lambda x: x.setupFailed(error), self.emitters) + +- def emitLockFailed(self, errmsg): +- """Emit a notice that we failed to acquire the yum lock.""" +- map(lambda x: x.lockFailed(errmsg), self.emitters) +- + def emitCheckFailed(self, error): + """Emit a notice stating that checking for updates failed.""" + map(lambda x: x.checkFailed(error), self.emitters) +commit 13f69f68876fade7611bcbab6f612937e1c02bff +Author: Zdenek Pavlas +Date: Wed Jan 15 09:11:30 2014 +0100 + + yum-cron: emitUpdateFailed() expects str, not an array. + + Avoid Python noise in the report. Also, use implicit conversion + instead of str() for unicode interoperability. + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index 87b3e69..6cbed94 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -545,7 +545,7 @@ class YumCronBase(yum.YumBase, YumOutput): + try: + self.getKeyForPackage(po) + except yum.Errors.YumBaseError, errmsg: +- self.emitUpdateFailed([str(errmsg)]) ++ self.emitUpdateFailed(errmsg) + return False + else: + self.emitUpdateFailed(err) +@@ -563,8 +563,7 @@ class YumCronBase(yum.YumBase, YumOutput): + try: + self.runTransaction(cb=cb) + except yum.Errors.YumBaseError, err: +- +- self.emitUpdateFailed([str(err)]) ++ self.emitUpdateFailed(err) + sys.exit(1) + + if emit : +@@ -675,9 +674,9 @@ class YumCronBase(yum.YumBase, YumOutput): + """Emit a notice stating that downloading the updates failed.""" + map(lambda x: x.downloadFailed(error), self.emitters) + +- def emitUpdateFailed(self, errmsgs): ++ def emitUpdateFailed(self, errmsg): + """Emit a notice stating that automatic updates failed.""" +- map(lambda x: x.updatesFailed(errmsgs), self.emitters) ++ map(lambda x: x.updatesFailed(errmsg), self.emitters) + + def emitMessages(self): + """Emit the messages from the emitters.""" +commit 048af21d6704d40e93e09c65f5c1b547a68e431e +Author: Zdenek Pavlas +Date: Mon Jan 20 10:59:58 2014 +0100 + + yum-cron: EmailEmitter failure should not be fatal. BZ 1055042 + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index 6cbed94..bfa580e 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -146,8 +146,9 @@ class UpdateEmitter(object): + class EmailEmitter(UpdateEmitter): + """Emitter class to send messages via email.""" + +- def __init__(self, opts): ++ def __init__(self, opts, logger): + super(EmailEmitter, self).__init__(opts) ++ self.logger = logger + self.subject = "" + + def updatesAvailable(self, summary): +@@ -229,10 +230,13 @@ class EmailEmitter(UpdateEmitter): + msg['To'] = ",".join(self.opts.email_to) + + # Send the email +- s = smtplib.SMTP() +- s.connect(self.opts.email_host) +- s.sendmail(self.opts.email_from, self.opts.email_to, msg.as_string()) +- s.close() ++ try: ++ s = smtplib.SMTP() ++ s.connect(self.opts.email_host) ++ s.sendmail(self.opts.email_from, self.opts.email_to, msg.as_string()) ++ s.close() ++ except Exception, e: ++ self.logger.error("Failed to send an email to %s: %s" % (self.opts.email_host, e)) + + + class StdIOEmitter(UpdateEmitter): +@@ -293,7 +297,7 @@ class YumCronBase(yum.YumBase, YumOutput): + # Create the emitters, and add them to the list + self.emitters = [] + if 'email' in self.opts.emit_via: +- self.emitters.append(EmailEmitter(self.opts)) ++ self.emitters.append(EmailEmitter(self.opts, self.logger)) + if 'stdio' in self.opts.emit_via: + self.emitters.append(StdIOEmitter(self.opts)) + +commit 8d21de54f5b267af8710c1358fd3a0475aed6bbb +Author: Zdenek Pavlas +Date: Mon Jan 20 11:41:15 2014 +0100 + + yum-cron: Add a retry loop around doLock(). + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index bfa580e..e1028be 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -262,6 +262,8 @@ class YumCronConfig(BaseConfig): + system_name = Option(gethostname()) + output_width = IntOption(80) + random_sleep = IntOption(0) ++ lock_retries = IntOption(5) ++ lock_sleep = IntOption(60) + emit_via = ListOption(['email','stdio']) + email_to = ListOption(["root"]) + email_from = Option("root") +@@ -386,9 +388,14 @@ class YumCronBase(yum.YumBase, YumOutput): + def acquireLock(self): + """ Wrapper method around doLock to emit errors correctly.""" + +- try: +- self.doLock() +- except yum.Errors.LockError, e: ++ i = 0 ++ while True: ++ try: self.doLock(); break ++ except yum.Errors.LockError, e: ++ i += 1 ++ if i < self.opts.lock_retries: ++ sleep(self.opts.lock_sleep) ++ continue + self.logger.warn("Failed to acquire the yum lock: %s", e) + sys.exit(1) + diff --git a/SOURCES/BZ-1041395-depsolve-loop-limit.patch b/SOURCES/BZ-1041395-depsolve-loop-limit.patch new file mode 100644 index 0000000..8a8c5b3 --- /dev/null +++ b/SOURCES/BZ-1041395-depsolve-loop-limit.patch @@ -0,0 +1,63 @@ +commit cfd0f0f8ad4bb285755ecc66e528a807f864b4ca +Author: Zdenek Pavlas +Date: Wed Dec 11 15:09:28 2013 +0100 + + depsolve_loop_limit= should try forever + +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index da13dc8..48ced00 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -882,7 +882,7 @@ Default is: !*/swap !*/lv_swap glob:/etc/yum/fssnap.d/*.conf + Set the number of times any attempt to depsolve before we just give up. This + shouldn't be needed as yum should always solve or fail, however it has been + observed that it can loop forever with very large system upgrades. Setting +-this to `0' (or "forever") makes yum try forever. Default is `100'. ++this to `0' (or "") makes yum try forever. Default is `100'. + + + .SH "[repository] OPTIONS" +diff --git a/yum/depsolve.py b/yum/depsolve.py +index 8b438bb..81bfdf8 100644 +--- a/yum/depsolve.py ++++ b/yum/depsolve.py +@@ -870,7 +870,7 @@ class Depsolve(object): + if self.dsCallback: self.dsCallback.start() + + depsolve_loop_count = 0 +- while depsolve_loop_count < self.conf.depsolve_loop_limit: ++ while depsolve_loop_count != (self.conf.depsolve_loop_limit or -1): + depsolve_loop_count += 1 + + CheckDeps = True +commit 57f063c11cc8712ce8055d9e9429d897d7d0072c +Author: Zdenek Pavlas +Date: Thu Dec 12 10:32:49 2013 +0100 + + Test depsolve_loop_count vs depsolve_loop_limit only once + +diff --git a/yum/depsolve.py b/yum/depsolve.py +index 81bfdf8..95c21bc 100644 +--- a/yum/depsolve.py ++++ b/yum/depsolve.py +@@ -870,7 +870,9 @@ class Depsolve(object): + if self.dsCallback: self.dsCallback.start() + + depsolve_loop_count = 0 +- while depsolve_loop_count != (self.conf.depsolve_loop_limit or -1): ++ while True: ++ if depsolve_loop_count == (self.conf.depsolve_loop_limit or -1): ++ return (1, [_("Depsolving loop limit reached.")] + unique(errors)) + depsolve_loop_count += 1 + + CheckDeps = True +@@ -922,9 +924,6 @@ class Depsolve(object): + + break + +- if depsolve_loop_count >= self.conf.depsolve_loop_limit: +- return (1, [_("Depsolving loop limit reached.")] + unique(errors)) +- + # FIXME: this doesn't belong here at all... + for txmbr in self.tsInfo.getMembers(): + if self.allowedMultipleInstalls(txmbr.po) and \ diff --git a/SOURCES/BZ-1050902-manpage-formatting-errrors.patch b/SOURCES/BZ-1050902-manpage-formatting-errrors.patch new file mode 100644 index 0000000..87894d0 --- /dev/null +++ b/SOURCES/BZ-1050902-manpage-formatting-errrors.patch @@ -0,0 +1,28 @@ +diff -up yum-3.4.3/docs/yum.8.old yum-3.4.3/docs/yum.8 +--- yum-3.4.3/docs/yum.8.old 2014-01-10 16:20:19.181475331 +0100 ++++ yum-3.4.3/docs/yum.8 2014-01-10 16:20:34.704480487 +0100 +@@ -383,19 +383,19 @@ version of each package that matches (th + using --showduplicates) and it only shows the newest providers (which can be + changed by using --verbose). + .IP +-.IP "\fBrepolist\fP" "\fBrepoinfo\fP" ++.IP "\fBrepolist\fP" + Produces a list of configured repositories. The default is to list all + enabled repositories. If you pass \-v, for verbose mode, or use repoinfo then +-more information is listed. If the first argument is 'enabled', 'disabled' or +-'all' then the command will list those types of repos. ++more information is listed. If the first argument is \'enabled\', \'disabled\' or ++\'all\' then the command will list those types of repos. + + You can pass repo id or name arguments, or wildcards which to match against + both of those. However if the id or name matches exactly then the repo will + be listed even if you are listing enabled repos. and it is disabled. + +-In non-verbose mode the first column will start with a '*' if the repo. has ++In non-verbose mode the first column will start with a \'*\' if the repo. has + metalink data and the latest metadata is not local and will start with a +-'!' if the repo. has metadata that is expired. For non-verbose mode the ++\'!\' if the repo. has metadata that is expired. For non-verbose mode the + last column will also display the number of packages in the repo. and (if there + are any user specified excludes) the number of packages excluded. + diff --git a/SOURCES/BZ-1052436-group-bundle-docs.patch b/SOURCES/BZ-1052436-group-bundle-docs.patch new file mode 100644 index 0000000..6d0271b --- /dev/null +++ b/SOURCES/BZ-1052436-group-bundle-docs.patch @@ -0,0 +1,86 @@ +commit 3fda2738b0c78df0454e72691a43b459c2e57c21 +Author: James Antill +Date: Tue Mar 11 15:09:18 2014 -0400 + + Change man page text for RHEL-7 group_command=object feedback. + +diff --git a/docs/yum.8 b/docs/yum.8 +index 6794581..1ab8534 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -250,20 +250,34 @@ Is used to download and make usable all the metadata for the currently enabled + sure the repos. are current (much like "yum clean expire-cache"). + .IP + .IP "\fBgroups\fP" +-A command, new in 3.4.2, that collects all the subcommands that act on groups together. +- +-"\fBgroup install\fP" is used to install all of the individual packages in a group, of the specified +-types (this works as if you'd taken each of those package names and put them on +-the command line for a "yum install" command). ++A command, new in 3.4.2, that collects all the subcommands that act on groups ++together. Note that recent yum using distributions (Fedora-19+, RHEL-7+) have ++configured group_command=objects which changes how group commands act in some ++important ways. ++ ++"\fBgroup install\fP" is used to install all of the individual packages in a ++group, of the specified types (this works as if you'd taken each of those ++package names and put them on the command line for a "yum install" command). + The group_package_types configuration option specifies which types will + be installed. +- +-"\fBgroup update\fP" is just an alias for groupinstall, which will do the right thing because +-"yum install X" and "yum update X" do the same thing, when X is already +-installed. +- +-"\fBgroup list\fP" is used to list the available groups from all \fByum\fP repos. Groups are marked +-as "installed" if all mandatory packages are installed, or if a group doesn't ++ If you wish to "reinstall" a group so that you get a package that is currently ++blacklisted the easiest way to do that currently is to install the package ++manually and then run "groups mark packages-sync mygroup mypackagename" (or ++use yumdb to set the group_member of the package(s)). ++ ++"\fBgroup update\fP" is just an alias for group install, when using ++group_command=compat. This will install packages in the group not already ++installed and upgrade existing packages. With group_command=simple it will just ++upgrade already installed packages. With group_command=objects it will try to ++upgrade the group object, installing any available packages not blacklisted ++(marked '-' in group info) and will upgrade the installed packages. ++ ++"\fBgroup list\fP" is used to list the available groups from all \fByum\fP ++repos. When group_command=objects the group is installed if the user ++explicitly installed it (or used the group mark* commands to mark it installed). ++It does not need to have any packages installed. ++When not using group_command=objects groups are shown as "installed" if all ++mandatory packages are installed, or if a group doesn't + have any mandatory packages then it is installed if any of the optional or + default package are installed (when not in group_command=objects mode). + You can pass optional arguments to the list/summary commands: installed, +@@ -300,6 +314,9 @@ meaning of these markers is: + .br + "=" = Package is installed, and was installed via the group. + ++you can move an installed package into an installed group using either ++"group mark package-sync/package-sync-forced" or "yumdb set group_member". ++ + "\fBgroup summary\fP" is used to give a quick summary of how many groups + are installed and available. + +commit e15943868e2a05e4304247f1e19d2520701e9cca +Author: James Antill +Date: Tue Mar 25 00:12:26 2014 -0400 + + Documentation tweak for group info and blacklisted packages. + +diff --git a/docs/yum.8 b/docs/yum.8 +index 1ab8534..3f028f8 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -306,7 +306,7 @@ to each package saying how that package relates to the group object. The + meaning of these markers is: + + .br +-"-" = Package isn't installed, and won't be installed as part of the group (Eg. group install foo -pkgA … this will have pkgA marked as '-') ++"-" = Package isn't installed, and won't be installed as part of the group (Eg. "yum group install foo -pkgA" or "yum group install foo; yum remove pkgA" … this will have pkgA marked as '-') + .br + "+" = Package isn't installed, but will be the next time you run "yum upgrade" or "yum group upgrade foo" + .br diff --git a/SOURCES/BZ-1052436-group-bundle-pre-f20-fixes.patch b/SOURCES/BZ-1052436-group-bundle-pre-f20-fixes.patch new file mode 100644 index 0000000..1e6265e --- /dev/null +++ b/SOURCES/BZ-1052436-group-bundle-pre-f20-fixes.patch @@ -0,0 +1,741 @@ +commit 8b977a860595a02dc13b5eefd5f8783ba23e4acf +Author: James Antill +Date: Mon Nov 18 17:14:48 2013 -0500 + + Add _ugroup_member to txmbr, list installed for groups pkgs. BZ 1031374. + +diff --git a/output.py b/output.py +index cf9e985..e42702e 100755 +--- a/output.py ++++ b/output.py +@@ -1506,7 +1506,30 @@ class YumOutput: + a_wid = max(a_wid, len(a)) + return a_wid + +- for (action, pkglist) in [(_('Installing'), self.tsInfo.installed), ++ ninstalled = self.tsInfo.installed ++ ginstalled = {} ++ if self.conf.group_command == 'objects' and ninstalled: ++ # Show new pkgs. that are installed via. a group. ++ ninstalled = [] ++ for txmbr in self.tsInfo.installed: ++ if not hasattr(txmbr, '_ugroup_member'): ++ ninstalled.append(txmbr) ++ continue ++ if txmbr._ugroup_member not in ginstalled: ++ ginstalled[txmbr._ugroup_member] = [] ++ ginstalled[txmbr._ugroup_member].append(txmbr) ++ ++ for grp in sorted(ginstalled, key=lambda x: x.ui_name): ++ action = _('Installing for group upgrade "%s"') % grp.ui_name ++ pkglist = ginstalled[grp] ++ ++ lines = [] ++ for txmbr in pkglist: ++ a_wid = _add_line(lines, data, a_wid, txmbr.po, txmbr.obsoletes) ++ ++ pkglist_lines.append((action, lines)) ++ ++ for (action, pkglist) in [(_('Installing'), ninstalled), + (_('Updating'), self.tsInfo.updated), + (_('Removing'), self.tsInfo.removed), + (_('Reinstalling'), self.tsInfo.reinstalled), +diff --git a/yum/__init__.py b/yum/__init__.py +index 6bd5962..f212884 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -3845,6 +3845,8 @@ much more problems). + pkg_warning_level='debug2') + for txmbr in txmbrs: + txmbr.group_member = thisgroup.groupid ++ if lupgrade: # For list transaction. ++ txmbr._ugroup_member = thisgroup + except Errors.InstallError, e: + self.verbose_logger.debug(_('No package named %s available to be installed'), + pkg) +commit 4a84e0f3d3954fdf0a94ecf61775ae9af43f2a4d +Author: James Antill +Date: Mon Dec 16 16:03:57 2013 -0500 + + Remove old FIXME for env. groups, fixes "group lists" without patterns. + +diff --git a/yum/__init__.py b/yum/__init__.py +index caafae4..69e8043 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -3520,8 +3520,7 @@ much more problems). + if self.conf.group_command == 'objects': + igrps = self.igroups.groups.values() + evgrps = self.comps.environments +- if False and self.conf.group_command == 'objects': +- # FIXME: Environment groups. ++ if self.conf.group_command == 'objects': + ievgrps = self.igroups.environments.values() + return igrps, grps, ievgrps, evgrps + +commit 42c82dd60dc498e7a2419b291a2392e77ffa5ded +Author: James Antill +Date: Mon Dec 16 16:31:33 2013 -0500 + + Confirm/assert new mocked igrps/ievgrps behaviour. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 69e8043..230a2e3 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -3629,6 +3629,12 @@ much more problems). + if ievgrps is None: + ievgrps = {} + ++ # Note that we used to get here with igrps/ievgrps that didn't exist ++ # in comps. but we mock them in comps now because it was hard to deal ++ # with that everywhere ... so just to confirm. ++ assert not igrps ++ assert not ievgrps ++ + for igrp in igrps.values(): + # These are installed groups that aren't in comps anymore. so we + # create fake comps groups for them. +commit e2c3d3f909088ba5e1cc237d2b57eab669e7befd +Author: James Antill +Date: Mon Dec 16 15:29:06 2013 -0500 + + Warn iff return_{groups, environments} returned an empty list. BZ 1043207. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 230a2e3..d051a1c 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -4458,24 +4458,31 @@ much more problems). + if group_string and group_string[0] == '^': + group_string = group_string[1:] + # Actually dealing with "environment groups". ++ found = False + for env_grp in comps.return_environments(group_string): ++ found = True + try: + txmbrs = self.selectEnvironment(env_grp.environmentid, + upgrade=upgrade) + tx_return.extend(txmbrs) + except yum.Errors.GroupsError: +- self.logger.critical(_('Warning: Environment Group %s does not exist.'), group_string) ++ assert False, "Checked in for loop." + continue ++ if not found: ++ self.logger.error(_('Warning: Environment group %s does not exist.'), ++ group_string) + return tx_return + ++ found = False + for group in comps.return_groups(group_string): ++ found = True + try: + txmbrs = self.selectGroup(group.groupid, upgrade=upgrade) + tx_return.extend(txmbrs) + except yum.Errors.GroupsError: +- self.logger.critical(_('Warning: Group %s does not exist.'), group_string) ++ assert False, "Checked in for loop." + continue +- else: ++ if not found: + self.logger.error(_('Warning: group %s does not exist.'), + group_string) + +commit 406dae058a021cf1171666c4e779721ef7ac680e +Author: James Antill +Date: Mon Dec 16 17:34:40 2013 -0500 + + Remove old test to allow comma separated grpid for selectGroup(). + +diff --git a/yum/__init__.py b/yum/__init__.py +index d051a1c..2709225 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -3771,9 +3771,6 @@ much more problems). + transaction set by this function + """ + +- if not self.comps.has_group(grpid): +- raise Errors.GroupsError, _("No Group named %s exists") % to_unicode(grpid) +- + txmbrs_used = [] + thesegroups = self.comps.return_groups(grpid) + +commit 1cedb184fe356252b0f22988ef8cd88d2de365ce +Author: James Antill +Date: Mon Dec 16 17:37:16 2013 -0500 + + Contain selectGroup() exceptions when selecting environments. BZ 1014202. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 2709225..72052ab 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -4007,10 +4007,13 @@ much more problems). + evgrp.allgroups) + grps = ",".join(sorted(grps)) + +- txs = self.selectGroup(grps, +- group_package_types, +- enable_group_conditionals, upgrade, +- ievgrp=ievgrp) ++ try: ++ txs = self.selectGroup(grps, ++ group_package_types, ++ enable_group_conditionals, upgrade, ++ ievgrp=ievgrp) ++ except Errors.GroupsError: ++ continue + ret.extend(txs) + return ret + +commit 23b51f3242f066ebfa3d79df1a1122293f8ab432 +Author: James Antill +Date: Mon Dec 16 17:38:22 2013 -0500 + + Add groups from installed environments, and unique, so we don't miss any. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 72052ab..633bd76 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -3991,7 +3991,7 @@ much more problems). + elif self.conf.group_command == 'objects': + igroup_data = self._groupInstalledEnvData(evgrp) + +- grps = [] ++ grps = set() + for grpid in evgrp.groups: + if (grpid not in igroup_data or + igroup_data[grpid].startswith('blacklisted')): +@@ -3999,9 +3999,10 @@ much more problems). + self.verbose_logger.log(logginglevels.DEBUG_2, + msg, grpid, evgrp.environmentid) + continue +- grps.append(grpid) ++ grps.add(grpid) + if evgrp.environmentid in self.igroups.environments: + ievgrp = self.igroups.environments[evgrp.environmentid] ++ grps.update(ievgrp.grp_names) + else: + self.igroups.add_environment(evgrp.environmentid, + evgrp.allgroups) +commit 4926655b7acd588de34322b07a5cf54de24f33dc +Author: James Antill +Date: Mon Dec 16 17:48:16 2013 -0500 + + Change groupupdate command to call "group update" back compat. too confusing. + +diff --git a/yumcommands.py b/yumcommands.py +index b346128..e01c96d 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -890,7 +890,7 @@ class GroupsCommand(YumCommand): + + direct_commands = {'grouplist' : 'list', + 'groupinstall' : 'install', +- 'groupupdate' : 'install', ++ 'groupupdate' : 'update', + 'groupremove' : 'remove', + 'grouperase' : 'remove', + 'groupinfo' : 'info'} +commit 0a07500f2c4c76a1cb1ef428a7585238802e0a86 +Author: James Antill +Date: Mon Dec 16 17:49:15 2013 -0500 + + Have "yum group upgrade" do all, as "yum upgrade" does in objs. mode. + +diff --git a/cli.py b/cli.py +index 180ba99..be8c46f 100755 +--- a/cli.py ++++ b/cli.py +@@ -1913,6 +1913,14 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + 2 = we've got work yet to do, onto the next stage + """ + pkgs_used = [] ++ ++ if not grouplist and self.conf.group_command == 'objects': ++ # Do what "yum upgrade" does when upgrade_group_objects_upgrade is ++ # set. ++ for ievgrp in self.igroups.environments: ++ pkgs_used.extend(self._at_groupupgrade('@^' + ievgrp)) ++ for igrp in self.igroups.groups: ++ pkgs_used.extend(self._at_groupupgrade('@' + igrp)) + + for group_string in grouplist: + +commit c8f16477b2deaeaf78ba88b9ea38b565061412a9 +Author: James Antill +Date: Tue Dec 17 10:48:44 2013 -0500 + + Don't add all grps in the installed evgrp, just those that belong. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 633bd76..b7eedf4 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -4002,7 +4002,15 @@ much more problems). + grps.add(grpid) + if evgrp.environmentid in self.igroups.environments: + ievgrp = self.igroups.environments[evgrp.environmentid] +- grps.update(ievgrp.grp_names) ++ # Add groups from the installed evgrp, for Eg. installed ++ # only evgrps. ++ for grp_name in ievgrp.grp_names: ++ if grp_name not in self.igroups.groups: ++ continue ++ grp_evgrpid = self.igroups.groups[grp_name].environment ++ if grp_evgrpid != evgrp.environmentid: ++ continue ++ grps.add(grp_name) + else: + self.igroups.add_environment(evgrp.environmentid, + evgrp.allgroups) +commit a6f1124787cff91c435f9c8da2d658fe241ad026 +Author: James Antill +Date: Tue Dec 17 16:36:31 2013 -0500 + + Don't confuse output by giving data for optional when it's off. + +diff --git a/output.py b/output.py +index 041910c..eb38d7d 100755 +--- a/output.py ++++ b/output.py +@@ -1131,10 +1131,14 @@ class YumOutput: + if group.langonly: + print _(' Language: %s') % group.langonly + +- sections = ((_(' Mandatory Packages:'), group.mandatory_packages), +- (_(' Default Packages:'), group.default_packages), +- (_(' Optional Packages:'), group.optional_packages), +- (_(' Conditional Packages:'), group.conditional_packages)) ++ sections = (('mandatory', _(' Mandatory Packages:'), ++ group.mandatory_packages), ++ ('default', _(' Default Packages:'), ++ group.default_packages), ++ ('optional', _(' Optional Packages:'), ++ group.optional_packages), ++ (None, _(' Conditional Packages:'), ++ group.conditional_packages)) + columns = None + if verb: + data = {'envra' : {}, 'rid' : {}} +@@ -1145,12 +1149,21 @@ class YumOutput: + columns = self.calcColumns(data) + columns = (-columns[0], -columns[1]) + +- for (section_name, pkg_names) in sections: ++ for (section_type, section_name, pkg_names) in sections: ++ # Only display igroup data for things that we'll actually try to ++ # install. ++ if section_type is None: ++ tigroup_data = igroup_data ++ elif section_type in self.conf.group_package_types: ++ tigroup_data = igroup_data ++ else: ++ tigroup_data = None ++ + if len(pkg_names) > 0: + print section_name + self._displayPkgsFromNames(pkg_names, verb, pkg_names2pkgs, + columns=columns, +- igroup_data=igroup_data) ++ igroup_data=tigroup_data) + if igrp_only: + print _(' Installed Packages:') + self._displayPkgsFromNames(igrp_only, verb, pkg_names2pkgs, +commit 14bf13706a708764065e729998a30a991541906e +Author: James Antill +Date: Tue Dec 17 16:40:00 2013 -0500 + + Pass the ievgrp to groups for new installed envs., so they belong. BZ 1043231 + +diff --git a/yum/__init__.py b/yum/__init__.py +index b7eedf4..1c17768 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -4012,8 +4012,8 @@ much more problems). + continue + grps.add(grp_name) + else: +- self.igroups.add_environment(evgrp.environmentid, +- evgrp.allgroups) ++ ievgrp = self.igroups.add_environment(evgrp.environmentid, ++ evgrp.allgroups) + grps = ",".join(sorted(grps)) + + try: +commit d6ddfc90cda8c4e735a55628960ff623f40b27f6 +Author: James Antill +Date: Tue Dec 17 17:01:13 2013 -0500 + + Fix typo with simple groups compile of environment with only options. + +diff --git a/yum/comps.py b/yum/comps.py +index 706e2a4..92e87ba 100755 +--- a/yum/comps.py ++++ b/yum/comps.py +@@ -879,7 +879,7 @@ class Comps(object): + break + else: + evgroup.installed = False +- for grpname in evgroup.optional: ++ for grpname in evgroup.options: + if grpname in inst_grp_names: + evgroup.installed = True + break +commit 926f893eaa933b086d442957ee271348bfb1d2a3 +Author: James Antill +Date: Tue Dec 17 16:56:19 2013 -0500 + + Fix mark-convert-whitelist, and add mark-convert-blacklist (default). + +diff --git a/docs/yum.8 b/docs/yum.8 +index dff88af..e0bd5da 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -320,9 +320,19 @@ the packages as a member of the group. + "\fBgroup mark packages-force\fP" works like mark packages, but doesn't care if + the packages are already members of another group. + +-"\fBgroup mark convert\fP" converts the automatic data you get without using +-groups as objects into groups as objects data. This makes it much easier to +-convert to groups as objects without having to reinstall. ++"\fBgroup mark convert-blacklist\fP" ++ ++"\fBgroup mark convert-whitelist\fP" ++ ++"\fBgroup mark convert\fP" converts the automatic data you get ++without using groups as objects into groups as objects data, in other words ++this will make "yum --setopt=group_command=objects groups list" look as similar ++as possible to the current output of ++"yum --setopt=group_command=simple groups list". This makes it much ++easier to convert to groups as objects without having to reinstall. For groups ++that are installed the whitelist variant will mark all uninstalled packages for ++the group as to be installed on the next "yum group upgrade", the blacklist ++variant (current default) will mark them all as blacklisted. + + "\fBgroup unmark packages\fP" remove a package as a member from any groups. + .IP +diff --git a/yumcommands.py b/yumcommands.py +index e01c96d..f07d270 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -973,6 +973,7 @@ class GroupsCommand(YumCommand): + 'mark-groups-sync', 'mark-groups-sync-force') + + ocmds_all = ('mark-install', 'mark-remove', 'mark-convert', ++ 'mark-convert-whitelist', 'mark-convert-blacklist', + 'mark-packages', 'mark-packages-force', + 'unmark-packages', + 'mark-packages-sync', 'mark-packages-sync-force', +@@ -1002,13 +1003,13 @@ class GroupsCommand(YumCommand): + pass + elif not os.path.exists(os.path.dirname(base.igroups.filename)): + base.logger.critical(_("There is no installed groups file.")) +- base.logger.critical(_("Maybe run: yum groups mark convert")) ++ base.logger.critical(_("Maybe run: yum groups mark convert (see man yum)")) + elif not os.access(os.path.dirname(base.igroups.filename), os.R_OK): + base.logger.critical(_("You don't have access to the groups DBs.")) + raise cli.CliError + elif not os.path.exists(base.igroups.filename): + base.logger.critical(_("There is no installed groups file.")) +- base.logger.critical(_("Maybe run: yum groups mark convert")) ++ base.logger.critical(_("Maybe run: yum groups mark convert (see man yum)")) + elif not os.access(base.igroups.filename, os.R_OK): + base.logger.critical(_("You don't have access to the groups DB.")) + raise cli.CliError +@@ -1157,14 +1158,15 @@ class GroupsCommand(YumCommand): + return 0, ['Marked groups-sync: ' + ','.join(extcmds)] + + # FIXME: This doesn't do environment groups atm. +- if cmd == 'mark-convert': ++ if cmd in ('mark-convert', ++ 'mark-convert-whitelist', 'mark-convert-blacklist'): + # Convert old style info. into groups as objects. + + def _convert_grp(grp): + if not grp.installed: + return + pkg_names = [] +- for pkg in base.rpmdb.searchNames(pkg_names): ++ for pkg in base.rpmdb.searchNames(grp.packages): + if 'group_member' in pkg.yumdb_info: + continue + pkg.yumdb_info.group_member = grp.groupid +@@ -1173,7 +1175,10 @@ class GroupsCommand(YumCommand): + # We only mark the packages installed as a known part of + # the group. This way "group update" will work and install + # any remaining packages, as it would before the conversion. +- base.igroups.add_group(grp.groupid, pkg_names) ++ if cmd == 'mark-convert-whitelist': ++ base.igroups.add_group(grp.groupid, pkg_names) ++ else: ++ base.igroups.add_group(grp.groupid, grp.packages) + + # Blank everything. + for gid in base.igroups.groups.keys(): +commit 22f07ea55219b325b17e93406ee272a1ba492378 +Author: James Antill +Date: Tue Dec 17 17:19:12 2013 -0500 + + Add _igroup_member, so we can find installing groups for output. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 1c17768..b86c451 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -3849,6 +3849,8 @@ much more problems). + txmbr.group_member = thisgroup.groupid + if lupgrade: # For list transaction. + txmbr._ugroup_member = thisgroup ++ else: ++ txmbr._igroup_member = thisgroup + except Errors.InstallError, e: + self.verbose_logger.debug(_('No package named %s available to be installed'), + pkg) +commit d8794ef4df1704b65f2dbb97ad5a94c7c02b134e +Author: James Antill +Date: Tue Dec 17 17:19:28 2013 -0500 + + Show install groups as well as upgrading groups in transaction output. + +diff --git a/output.py b/output.py +index eb38d7d..38045e9 100755 +--- a/output.py ++++ b/output.py +@@ -1525,16 +1525,26 @@ class YumOutput: + # Show new pkgs. that are installed via. a group. + ninstalled = [] + for txmbr in self.tsInfo.installed: +- if not hasattr(txmbr, '_ugroup_member'): ++ if hasattr(txmbr, '_igroup_member'): ++ key = ('i', txmbr._igroup_member) ++ if key not in ginstalled: ++ ginstalled[key] = [] ++ ginstalled[key].append(txmbr) ++ elif hasattr(txmbr, '_ugroup_member'): ++ key = ('u', txmbr._ugroup_member) ++ if key not in ginstalled: ++ ginstalled[key] = [] ++ ginstalled[key].append(txmbr) ++ else: + ninstalled.append(txmbr) +- continue +- if txmbr._ugroup_member not in ginstalled: +- ginstalled[txmbr._ugroup_member] = [] +- ginstalled[txmbr._ugroup_member].append(txmbr) + +- for grp in sorted(ginstalled, key=lambda x: x.ui_name): +- action = _('Installing for group upgrade "%s"') % grp.ui_name +- pkglist = ginstalled[grp] ++ for (T, grp) in sorted(ginstalled, key=lambda x: x[1].ui_name): ++ if T == 'u': ++ msg = _('Installing for group upgrade "%s"') ++ else: ++ msg = _('Installing for group install "%s"') ++ action = msg % grp.ui_name ++ pkglist = ginstalled[(T, grp)] + + lines = [] + for txmbr in pkglist: +commit 5bd3c6aa6926a427a7ef660868ac7aa1adbd83f9 +Author: James Antill +Date: Tue Dec 17 17:24:17 2013 -0500 + + Canonicalize the "no group" warnings to env. group and pkg group. + +diff --git a/cli.py b/cli.py +index be8c46f..2873656 100755 +--- a/cli.py ++++ b/cli.py +@@ -1944,7 +1944,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + txmbrs = self.selectEnvironment(group.environmentid, + upgrade=upgrade) + except yum.Errors.GroupsError: +- self.logger.critical(_('Warning: environment %s does not exist.'), group_string) ++ self.logger.critical(_('Warning: Environment group %s does not exist.'), group_string) + continue + else: + pkgs_used.extend(txmbrs) +@@ -1958,7 +1958,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + try: + txmbrs = self.selectGroup(group.groupid, upgrade=upgrade) + except yum.Errors.GroupsError: +- self.logger.critical(_('Warning: group %s does not exist.'), group_string) ++ self.logger.critical(_('Warning: Package group %s does not exist.'), group_string) + continue + else: + pkgs_used.extend(txmbrs) +diff --git a/yum/__init__.py b/yum/__init__.py +index b86c451..41c932c 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -4494,7 +4494,7 @@ much more problems). + assert False, "Checked in for loop." + continue + if not found: +- self.logger.error(_('Warning: group %s does not exist.'), ++ self.logger.error(_('Warning: Package group %s does not exist.'), + group_string) + + return tx_return +commit 31ef7b51e3d079e0f0203af1366e38577cdc8947 +Author: James Antill +Date: Tue Dec 17 17:38:22 2013 -0500 + + Tell users how to mark install/remove groups without packages. + +diff --git a/cli.py b/cli.py +index 2873656..c05a4cf 100755 +--- a/cli.py ++++ b/cli.py +@@ -1968,6 +1968,8 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + continue + + if not pkgs_used: ++ if base.conf.group_command == 'objects': ++ self.logger.critical(_("Maybe run: yum groups mark install (see man yum)")) + return 0, [_('No packages in any requested group available to install or update')] + else: + return 2, [P_('%d package to Install', '%d packages to Install', len(pkgs_used)) % len(pkgs_used)] +@@ -2024,6 +2026,8 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + pkgs_used.extend(txmbrs) + + if not pkgs_used: ++ if base.conf.group_command == 'objects': ++ self.logger.critical(_("Maybe run: yum groups mark remove (see man yum)")) + return 0, [_('No packages to remove from groups')] + else: + return 2, [P_('%d package to remove', '%d packages to remove', len(pkgs_used)) % len(pkgs_used)] +commit 3722c9a8f3d1435462dd1abcf62a571a1b4b4d29 +Author: James Antill +Date: Tue Dec 17 17:38:26 2013 -0500 + + Add "groups mark blacklist" command to get out of the upgrade problem. + +diff --git a/docs/yum.8 b/docs/yum.8 +index e0bd5da..0e211eb 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -320,6 +320,10 @@ the packages as a member of the group. + "\fBgroup mark packages-force\fP" works like mark packages, but doesn't care if + the packages are already members of another group. + ++"\fBgroup mark blacklist\fP" will blacklist all packages marked to be installed ++for a group. After this command a "yum group upgrade" will not install any new ++packages as part of the group. ++ + "\fBgroup mark convert-blacklist\fP" + + "\fBgroup mark convert-whitelist\fP" +diff --git a/yumcommands.py b/yumcommands.py +index f07d270..291eae5 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -965,6 +965,7 @@ class GroupsCommand(YumCommand): + ocmds_arg = [] + if base.conf.group_command == 'objects': + ocmds_arg = ('mark-install', 'mark-remove', ++ 'mark-blacklist', + 'mark-packages', 'mark-packages-force', + 'unmark-packages', + 'mark-packages-sync', 'mark-packages-sync-force', +@@ -974,6 +975,7 @@ class GroupsCommand(YumCommand): + + ocmds_all = ('mark-install', 'mark-remove', 'mark-convert', + 'mark-convert-whitelist', 'mark-convert-blacklist', ++ 'mark-blacklist', + 'mark-packages', 'mark-packages-force', + 'unmark-packages', + 'mark-packages-sync', 'mark-packages-sync-force', +@@ -1063,6 +1065,24 @@ class GroupsCommand(YumCommand): + base.igroups.save() + return 0, ['Marked install: ' + ','.join(extcmds)] + ++ if cmd == 'mark-blacklist': ++ gRG = base._groupReturnGroups(extcmds,ignore_case=False) ++ igrps, grps, ievgrps, evgrps = gRG ++ for ievgrp in ievgrps: ++ evgrp = base.comps.return_environment(igrp.evgid) ++ if not evgrp: ++ continue ++ base.igroups.changed = True ++ ievgrp.grp_names.update(grp.groups) ++ for igrp in igrps: ++ grp = base.comps.return_group(igrp.gid) ++ if not grp: ++ continue ++ base.igroups.changed = True ++ igrp.pkg_names.update(grp.packages) ++ base.igroups.save() ++ return 0, ['Marked upgrade blacklist: ' + ','.join(extcmds)] ++ + if cmd in ('mark-packages', 'mark-packages-force'): + if len(extcmds) < 2: + return 1, ['No group or package given'] +commit 1ec588666b376e5a61446c6ca1cd5ae764e0a590 +Author: James Antill +Date: Wed Dec 18 16:19:10 2013 -0500 + + Fix typo in new mark install/remove messages. + +diff --git a/cli.py b/cli.py +index c05a4cf..5b44b2c 100755 +--- a/cli.py ++++ b/cli.py +@@ -1968,7 +1968,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + continue + + if not pkgs_used: +- if base.conf.group_command == 'objects': ++ if self.conf.group_command == 'objects': + self.logger.critical(_("Maybe run: yum groups mark install (see man yum)")) + return 0, [_('No packages in any requested group available to install or update')] + else: +@@ -2026,7 +2026,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + pkgs_used.extend(txmbrs) + + if not pkgs_used: +- if base.conf.group_command == 'objects': ++ if self.conf.group_command == 'objects': + self.logger.critical(_("Maybe run: yum groups mark remove (see man yum)")) + return 0, [_('No packages to remove from groups')] + else: +commit 48f1ff768211fc5c6b7e0254b0e655b4a4ba451e +Author: James Antill +Date: Thu Dec 19 00:00:26 2013 -0500 + + Delete extra break from for to if change, which now breaks outer loop. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 41c932c..9fb88d4 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -3506,7 +3506,6 @@ much more problems). + + if igrp.environment == evgroup.environmentid: + ret[grp_name] = 'installed' +- break + else: + ret[grp_name] = 'blacklisted-installed' + +commit 9d4dae82c83df81197502b4a4bebc73c1cb3bd3e +Author: James Antill +Date: Fri Dec 20 14:46:33 2013 -0500 + + Fix traceback in group info -v. + +diff --git a/output.py b/output.py +index 38045e9..2787d86 100755 +--- a/output.py ++++ b/output.py +@@ -1142,7 +1142,7 @@ class YumOutput: + columns = None + if verb: + data = {'envra' : {}, 'rid' : {}} +- for (section_name, pkg_names) in sections: ++ for (section_type, section_name, pkg_names) in sections: + self._calcDataPkgColumns(data, pkg_names, pkg_names2pkgs, + igroup_data=igroup_data) + data = [data['envra'], data['rid']] diff --git a/SOURCES/BZ-1052994-yum-cron-install-unsigned-packages.patch b/SOURCES/BZ-1052994-yum-cron-install-unsigned-packages.patch new file mode 100644 index 0000000..9a02364 --- /dev/null +++ b/SOURCES/BZ-1052994-yum-cron-install-unsigned-packages.patch @@ -0,0 +1,22 @@ +From: Zdenek Pavlas +Date: Tue, 14 Jan 2014 14:41:45 +0000 (+0100) +Subject: yum-cron: fail when sigCheckPkg() returns 2. BZ 1052440 +X-Git-Url: http://yum.baseurl.org/gitweb?p=yum.git;a=commitdiff_plain;h=9df69e579496ccb6df5c3f5b5b7bab8d648b06b4 + +yum-cron: fail when sigCheckPkg() returns 2. BZ 1052440 +--- + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index 386a7a0..87b3e69 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -547,6 +547,9 @@ class YumCronBase(yum.YumBase, YumOutput): + except yum.Errors.YumBaseError, errmsg: + self.emitUpdateFailed([str(errmsg)]) + return False ++ else: ++ self.emitUpdateFailed(err) ++ return False + + del self.ts + self.initActionTs() # make a new, blank ts to populate diff --git a/SOURCES/BZ-1053289-misc-perf+UI+simple-bug+docs-fixes.patch b/SOURCES/BZ-1053289-misc-perf+UI+simple-bug+docs-fixes.patch new file mode 100644 index 0000000..57e724f --- /dev/null +++ b/SOURCES/BZ-1053289-misc-perf+UI+simple-bug+docs-fixes.patch @@ -0,0 +1,1469 @@ +commit 1b14f27c1ff77ca3fb0af7dccc890a6c8bf36d42 +Author: Zdenek Pavlas +Date: Wed Nov 6 14:42:59 2013 +0100 + + docs: Suggest "--" when using "-" to exclude packages. BZ 1026598 + +diff --git a/docs/yum.8 b/docs/yum.8 +index e42bf49..2cbdf72 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -103,9 +103,13 @@ satisfied\&. (See \fBSpecifying package names\fP for more information) + If no package matches the given package name(s), they are assumed to be a shell + glob and any matches are then installed\&. If the name starts with @^ then it + is treated as an environment group (group install @^foo), an @ character and +-it's treated as a group (plain group install)\&. If the name starts with +-a - character, then a search is done within +-the transaction and any matches are removed. If the name is a file, then install works ++it's treated as a group (plain group install)\&. ++ ++If the name starts with a "-" character, then a search is done within the ++transaction and any matches are removed. Note that Yum options use the same ++syntax and it may be necessary to use "--" to resolve any possible conflicts. ++ ++If the name is a file, then install works + like localinstall\&. If the name doesn't match a package, then package + "provides" are searched (e.g. "_sqlitecache.so()(64bit)") as are + filelists (Eg. "/usr/bin/yum"). Also note that for filelists, wildcards will +commit d78b1258ec9fd8ed312c4fede9a68db1623bb124 +Author: Zdenek Pavlas +Date: Mon Nov 11 08:58:52 2013 +0100 + + docs: exactarch option is removed. + +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index 5d8578d..53cef2e 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -158,12 +158,6 @@ Can be disabled using --disableexcludes. + Command-line option: \fB\-x\fP + + .IP +-\fBexactarch\fR +-Either `1' or `0'. Set to `1' to make yum update only update the architectures +-of packages that you have installed. ie: with this enabled yum will not install +-an i686 package to update an i386 package. Default is `1'. +- +-.IP + \fBinstallonlypkgs \fR + List of package provides that should only ever be installed, never updated. + Kernels in particular fall into this category. Defaults to kernel, +commit d6378e152ad8751b5d135d7e8aba49e16f8a374a +Author: James Antill +Date: Mon Nov 18 15:57:53 2013 -0500 + + Add distupgrade command as alias for distro-sync, to be compat. with zypper. + +diff --git a/yumcommands.py b/yumcommands.py +index 1530161..a542ade 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -506,7 +506,7 @@ class DistroSyncCommand(YumCommand): + + :return: a list containing the names of this command + """ +- return ['distribution-synchronization', 'distro-sync'] ++ return ['distribution-synchronization', 'distro-sync', 'distupgrade'] + + def getUsage(self): + """Return a usage string for this command. +commit aae263a57b9e1695d54d463df36f191f3facfb48 +Author: James Antill +Date: Mon Nov 18 15:58:19 2013 -0500 + + Add upgrade_group_objects_upgrade config. so people can turn it off. + +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index 53cef2e..b93ad32 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -270,6 +270,12 @@ packages for all groups). + Default is: compat + + .IP ++\fBupgrade_group_objects_upgrade\fR ++Either `0' or `1'. Set this to `0' to disable the automatic running of ++"group upgrade" when running the "upgrade" command, and group_command is set to ++"objects". Default is `1' (perform the check). ++ ++.IP + \fBinstallroot \fR + Specifies an alternative installroot, relative to which all packages will be + installed. +diff --git a/yum/__init__.py b/yum/__init__.py +index 6a6f1fc..6bd5962 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -5000,7 +5000,8 @@ much more problems). + tx_return.extend(self.update(po=new)) + + # Upgrade the installed groups, as part of generic "yum upgrade" +- if self.conf.group_command == 'objects': ++ if (self.conf.group_command == 'objects' and ++ self.conf.upgrade_group_objects_upgrade): + for ievgrp in self.igroups.environments: + tx_return.extend(self._at_groupupgrade('@^' + ievgrp)) + for igrp in self.igroups.groups: +diff --git a/yum/config.py b/yum/config.py +index ecb8490..c43c41b 100644 +--- a/yum/config.py ++++ b/yum/config.py +@@ -792,6 +792,7 @@ class YumConf(StartupConf): + group_package_types = ListOption(['mandatory', 'default']) + group_command = SelectionOption(__group_command_default__, + ('compat', 'objects', 'simple')) ++ upgrade_group_objects_upgrade = BoolOption(True) + + timeout = FloatOption(30.0) # FIXME: Should use variation of SecondsOption + +commit 944f42f65e8a2d4bf0928e85850bf81e2876e233 +Author: James Antill +Date: Mon Nov 18 16:05:33 2013 -0500 + + Add autocheck_running_kernel config. so people can turn it off. + +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index b93ad32..6fae41d 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -273,7 +273,14 @@ Default is: compat + \fBupgrade_group_objects_upgrade\fR + Either `0' or `1'. Set this to `0' to disable the automatic running of + "group upgrade" when running the "upgrade" command, and group_command is set to +-"objects". Default is `1' (perform the check). ++"objects". Default is `1' (perform the operation). ++ ++.IP ++\fBautocheck_running_kernel\fR ++Either `0' or `1'. Set this to `0' to disable the automatic checking of the ++running kernel against updateinfo ("yum updateinfo check-running-kernel"), in ++the "check-update" and "updateinfo summary" commands. ++Default is `1' (perform the check). + + .IP + \fBinstallroot \fR +diff --git a/yumcommands.py b/yumcommands.py +index a542ade..2b1c9c0 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -1609,7 +1609,8 @@ class CheckUpdateCommand(YumCommand): + result = 100 + + # Add check_running_kernel call, if updateinfo is available. +- if updateinfo._repos_downloaded(base.repos.listEnabled()): ++ if (base.conf.autocheck_running_kernel and ++ updateinfo._repos_downloaded(base.repos.listEnabled())): + def _msg(x): + base.verbose_logger.info("%s", x) + updateinfo._check_running_kernel(base, base.upinfo, _msg) +@@ -3850,7 +3851,8 @@ class UpdateinfoCommand(YumCommand): + if maxsize < size: + maxsize = size + if not maxsize: +- _upi._check_running_kernel(base, md_info, _msg) ++ if base.conf.autocheck_running_kernel: ++ _upi._check_running_kernel(base, md_info, _msg) + return + + outT = {'newpackage' : 'New Package', +@@ -3880,7 +3882,8 @@ class UpdateinfoCommand(YumCommand): + for sn in sorted(sev_counts, key=_sev_sort_key): + args = (maxsize, sev_counts[sn],sn or '?', outT['security']) + print " %*u %s %s notice(s)" % args +- _upi._check_running_kernel(base, md_info, _msg) ++ if base.conf.autocheck_running_kernel: ++ _upi._check_running_kernel(base, md_info, _msg) + self.show_pkg_info_done = {} + + def _get_new_pkgs(self, md_info): +commit ecf31eee67bd3c5668f8b244c086365ebc510c05 +Author: James Antill +Date: Tue Nov 19 11:57:13 2013 -0500 + + Actually add the config. for autocheck_running_kernel. + +diff --git a/yum/config.py b/yum/config.py +index c43c41b..45abfd6 100644 +--- a/yum/config.py ++++ b/yum/config.py +@@ -898,6 +898,8 @@ class YumConf(StartupConf): + + depsolve_loop_limit = PositiveIntOption(100, names_of_0=[""]) + ++ autocheck_running_kernel = BoolOption(True) ++ + _reposlist = [] + + def dump(self): +commit 977a79be0f79069febde1ad81d8c71d240d08605 +Author: James Antill +Date: Tue Nov 19 14:28:03 2013 -0500 + + Add deltarpm_metadata_percentage config. so people can configure MD downloads. + +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index 6fae41d..4e79298 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -420,6 +420,15 @@ Use `0' to turn off delta rpm processing. Local repositories (with file:// + baseurl) have delta rpms turned off by default. + + .IP ++\fBdeltarpm_metadata_percentage\fR ++When the relative size of deltarpm metadata vs pkgs is larger than this, ++deltarpm metadata is not downloaded from the repo. ++Default value is 100 (Deltarpm metadata must be smaller than the packages from ++the repo). Note that you can give values over 100, so 200 means that the ++metadata is required to be half the size of the packages. ++Use `0' to turn off this check, and always download metadata. ++ ++.IP + \fBsslcacert \fR + Path to the directory containing the databases of the certificate authorities + yum should use to verify SSL certificates. Defaults to none - uses system +@@ -1043,6 +1052,11 @@ Overrides the \fBdeltarpm_percentage\fR option from the [main] section + for this repository. + + .IP ++\fBdeltarpm_metadata_percentage\fR ++Overrides the \fBdeltarpm_metadata_percentage\fR option from the [main] section ++for this repository. ++ ++.IP + \fBsslcacert \fR + Overrides the \fBsslcacert\fR option from the [main] section for this + repository. +diff --git a/yum/config.py b/yum/config.py +index cdad4bc..b891f82 100644 +--- a/yum/config.py ++++ b/yum/config.py +@@ -805,6 +805,7 @@ class YumConf(StartupConf): + max_connections = IntOption(0, range_min=0) + deltarpm = IntOption(2, range_min=-16, range_max=128) + deltarpm_percentage = IntOption(75, range_min=0, range_max=100) ++ deltarpm_metadata_percentage = IntOption(100, range_min=0) + + http_caching = SelectionOption('all', ('none', 'packages', 'all')) + metadata_expire = SecondsOption(60 * 60 * 6) # Time in seconds (6h). +@@ -977,7 +978,12 @@ class RepoConf(BaseConfig): + throttle = Inherit(YumConf.throttle) + timeout = Inherit(YumConf.timeout) + ip_resolve = Inherit(YumConf.ip_resolve) ++ # This isn't inherited so that we can automatically disable file:// _only_ ++ # repos. if they haven't set an explicit deltarpm_percentage for the repo. + deltarpm_percentage = IntOption(None, range_min=0, range_max=100) ++ # Rely on the above config. to do automatic disabling, and thus. no hack ++ # needed here. ++ deltarpm_metadata_percentage = Inherit(YumConf.deltarpm_metadata_percentage) + + http_caching = Inherit(YumConf.http_caching) + metadata_expire = Inherit(YumConf.metadata_expire) +diff --git a/yum/drpm.py b/yum/drpm.py +index 1fd7a11..42bf70e 100644 +--- a/yum/drpm.py ++++ b/yum/drpm.py +@@ -168,8 +168,13 @@ class DeltaInfo: + self.verbose_logger.info(_('No Presto metadata available for %s'), repo) + continue + path = repo.cachedir +'/'+ os.path.basename(data.location[1]) +- if not os.path.exists(path) and int(data.size) > reposize[repo]: +- self.verbose_logger.info(_('Not downloading Presto metadata for %s'), repo) ++ perc = repo.deltarpm_metadata_percentage ++ data_size = int(data.size) * (perc / 100.0) ++ if perc and not os.path.exists(path) and data_size > reposize[repo]: ++ msg = _('Not downloading deltainfo for %s, MD is %s and rpms are %s') ++ self.verbose_logger.info(msg, repo, ++ progress.format_number(data_size), ++ progress.format_number(reposize[repo])) + continue + + def failfunc(e, name=name, repo=repo): +commit b70d74e732f360a0a31cfcb9174982fb65369c54 +Author: James Antill +Date: Wed Nov 27 14:00:32 2013 -0500 + + Add check_config_file_age, so we can turn that off for rhsm repos. BZ 1035440. + +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index 4e79298..da13dc8 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -290,6 +290,18 @@ installed. + Command-line option: \fB\-\-installroot\fP + + .IP ++\fBconfig_file_path \fR ++Specifies the path to main the configuration file. ++Default is /etc/yum/yum.conf. ++ ++.IP ++\fBcheck_config_file_age \fR ++Either `0' or `1'. Specifies whether yum should auto metadata expire repos. ++that are older than any of the configuration files that led to them (usually ++the yum.conf file and the foo.repo file). ++Default is `1' (perform the check). ++ ++.IP + \fBdistroverpkg\fR + The package used by yum to determine the "version" of the distribution, this + sets $releasever for use in config. files. This +diff --git a/yum/config.py b/yum/config.py +index ea6c1ac..c38d574 100644 +--- a/yum/config.py ++++ b/yum/config.py +@@ -901,6 +901,8 @@ class YumConf(StartupConf): + + autocheck_running_kernel = BoolOption(True) + ++ check_config_file_age = BoolOption(True) ++ + _reposlist = [] + + def dump(self): +@@ -1005,6 +1007,9 @@ class RepoConf(BaseConfig): + async = BoolOption(True) + + ui_repoid_vars = Inherit(YumConf.ui_repoid_vars) ++ ++ check_config_file_age = Inherit(YumConf.check_config_file_age) ++ + + class VersionGroupConf(BaseConfig): + """Option definitions for version groups.""" +diff --git a/yum/yumRepo.py b/yum/yumRepo.py +index 67bb7c9..35359e2 100644 +--- a/yum/yumRepo.py ++++ b/yum/yumRepo.py +@@ -1170,6 +1170,9 @@ Insufficient space in download directory %s + elif cookie_info[8] > time.time(): + val = False + ++ if not self.check_config_file_age: ++ return val ++ + # make sure none of our config files for this repo are newer than + # us + if cookie_info[8] < int(self.repo_config_age): +commit a88b3ee54bd6f3b7c6855e0595d443fa6a453798 +Author: James Antill +Date: Sun Dec 1 19:41:18 2013 -0500 + + Better doc. comment for re_primary_filename(). + +diff --git a/yum/misc.py b/yum/misc.py +index b817cc0..f551102 100644 +--- a/yum/misc.py ++++ b/yum/misc.py +@@ -134,8 +134,9 @@ def re_filename(s): + + def re_primary_filename(filename): + """ Tests if a filename string, can be matched against just primary. +- Note that this can produce false negatives (but not false +- positives). Note that this is a superset of re_primary_dirname(). """ ++ Note that this can produce false negatives (Eg. /b?n/zsh) but not false ++ positives (because the former is a perf hit, and the later is a ++ failure). Note that this is a superset of re_primary_dirname(). """ + if re_primary_dirname(filename): + return True + if filename == '/usr/lib/sendmail': +commit 32e2da9c3e068722f82ae346c761a55ac9d969c9 +Author: James Antill +Date: Thu Dec 5 16:31:02 2013 -0500 + + Fix needTs check with repo-pkgs list/info. + +diff --git a/yumcommands.py b/yumcommands.py +index 2b1c9c0..db1b9d3 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -3712,7 +3712,7 @@ class RepoPkgsCommand(YumCommand): + if len(extcmds) > 1: + cmd = extcmds[1] + if cmd in ('info', 'list'): +- return InfoCommand().cacheRequirement(base, cmd, extcmds[2:]) ++ return InfoCommand().needTs(base, cmd, extcmds[2:]) + + return True + +commit 88a93e8de73066a796bbb698c5c6f59b66174448 +Author: James Antill +Date: Thu Dec 5 16:36:54 2013 -0500 + + Add command variation aliases to check-update. + +diff --git a/yumcommands.py b/yumcommands.py +index db1b9d3..3412a60 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -1531,7 +1531,8 @@ class CheckUpdateCommand(YumCommand): + + :return: a list containing the names of this command + """ +- return ['check-update'] ++ return ['check-update', 'check-updates', ++ 'check-upgrade', 'check-upgrades'] + + def getUsage(self): + """Return a usage string for this command. +commit ade4e34d1578ad4046b5efe3c3a97ca6bc1791f5 +Author: James Antill +Date: Thu Dec 5 16:37:07 2013 -0500 + + Add check-update sub-command to repo-pkgs. + +diff --git a/docs/yum.8 b/docs/yum.8 +index 0914765..dff88af 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -423,6 +423,9 @@ only shows packages from the given repository. + "repository\-packages info" - Works like the "yum info" command, but + only shows packages from the given repository. + ++"repository\-packages check-update" - Works like the ++"yum check-update" command, but only shows packages from the given repository. ++ + "repository\-packages install" - Install all of the packages in the + repository, basically the same as: yum install $(repoquery --repoid= -a). + Specific packages/wildcards can be specified. +diff --git a/yumcommands.py b/yumcommands.py +index 3412a60..b346128 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -1558,7 +1558,7 @@ class CheckUpdateCommand(YumCommand): + """ + checkEnabledRepo(base) + +- def doCommand(self, base, basecmd, extcmds): ++ def doCommand(self, base, basecmd, extcmds, repoid=None): + """Execute this command. + + :param base: a :class:`yum.Yumbase` object +@@ -1577,10 +1577,10 @@ class CheckUpdateCommand(YumCommand): + base.extcmds.insert(0, 'updates') + result = 0 + if True: +- ypl = base.returnPkgLists(extcmds) ++ ypl = base.returnPkgLists(extcmds, repoid=repoid) + if (base.conf.obsoletes or + base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)): +- typl = base.returnPkgLists(obscmds) ++ typl = base.returnPkgLists(obscmds, repoid=repoid) + ypl.obsoletes = typl.obsoletes + ypl.obsoletesTuples = typl.obsoletesTuples + +@@ -1606,7 +1606,7 @@ class CheckUpdateCommand(YumCommand): + for obtup in sorted(ypl.obsoletesTuples, + key=operator.itemgetter(0)): + base.updatesObsoletesList(obtup, 'obsoletes', +- columns=columns) ++ columns=columns, repoid=repoid) + result = 100 + + # Add check_running_kernel call, if updateinfo is available. +@@ -3516,6 +3516,9 @@ class RepoPkgsCommand(YumCommand): + 'remove-or-distribution-synchronization' : 'remove-or-sync', + 'upgrade' : 'update', # Hack, but meh. + 'upgrade-to' : 'update-to', # Hack, but meh. ++ 'check-upgrade' : 'check-update', # Hack, but meh. ++ 'check-upgrades' : 'check-update', # Hack, but meh. ++ 'check-updates' : 'check-update', # Hack, but meh. + } + cmd = remap.get(cmd, cmd) + +@@ -3524,6 +3527,8 @@ class RepoPkgsCommand(YumCommand): + return ListCommand().doCommand(base, cmd, args, repoid=repoid) + elif cmd == 'info': + return InfoCommand().doCommand(base, cmd, args, repoid=repoid) ++ elif cmd == 'check-update': ++ return CheckUpdateCommand().doCommand(base, cmd, args,repoid=repoid) + + elif cmd == 'install': # install is simpler version of installPkgs... + for arg in args: +@@ -3730,6 +3735,9 @@ class RepoPkgsCommand(YumCommand): + cmd = extcmds[1] + if cmd in ('info', 'list'): + return InfoCommand().cacheRequirement(base, cmd, extcmds[2:]) ++ if cmd in ('check-update', 'check-upgrade', ++ 'check-updates', 'check-upgrades'): ++ return CheckUpdateCommand().cacheRequirement(base, cmd, extcmds[2:]) + return 'write' + + # Using this a lot, so make it easier... +commit 84876b27c49056a8d86112020a9ec4ec7a13e852 +Author: James Antill +Date: Fri Dec 6 11:04:31 2013 -0500 + + Fix cacheReq manipulation. BZ 1039028. + + Only look at enabled repos. for cacheReq cookie comparisons. BZ 1039028. + + Move all the cacheReq repo. setting into a function. + + Use the function everywhere so we don't overwrite the manipulated value with + the generic value. + +diff --git a/cli.py b/cli.py +index 7f6643f..180ba99 100755 +--- a/cli.py ++++ b/cli.py +@@ -390,6 +390,13 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + self.basecmd, sys.argv[0]) + raise CliError + ++ self._set_repos_cache_req() ++ ++ self.yum_cli_commands[self.basecmd].doCheck(self, self.basecmd, self.extcmds) ++ ++ def _set_repos_cache_req(self, warning=True): ++ """ Set the cacheReq attribute from the commands to the repos. """ ++ + cmd = self.yum_cli_commands[self.basecmd] + cacheReq = 'write' + if hasattr(cmd, 'cacheRequirement'): +@@ -404,7 +411,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + # they are _really_ old. + ts_min = None + ts_max = None +- for repo in self.repos.sort(): ++ for repo in self.repos.listEnabled(): + if not os.path.exists(repo.metadata_cookie): + ts_min = None + break +@@ -428,14 +435,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + + if not ts_min: + cacheReq = 'write' +- elif (time.time() - ts_max) > (60 * 60 * 24 * 14): ++ elif warning and (time.time() - ts_max) > (60 * 60 * 24 * 14): + self.logger.warning(_("Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast")) + + for repo in self.repos.sort(): + repo._metadata_cache_req = cacheReq + +- self.yum_cli_commands[self.basecmd].doCheck(self, self.basecmd, self.extcmds) +- + def _shell_history_write(self): + if not hasattr(self, '_shell_history_cmds'): + return +@@ -560,11 +565,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + + # This should already have been done at doCheck() time, but just in + # case repos. got added or something do it again. +- cacheReq = 'write' +- if hasattr(cmd, 'cacheRequirement'): +- cacheReq = cmd.cacheRequirement(self, self.basecmd, self.extcmds) +- for repo in self.repos.sort(): +- repo._metadata_cache_req = cacheReq ++ self._set_repos_cache_req(warning=False) + + return self.yum_cli_commands[self.basecmd].doCommand(self, self.basecmd, self.extcmds) + +commit 8c4c81b8f958ffaf6f3cf710225eee48426ce767 +Author: James Antill +Date: Fri Dec 6 11:11:05 2013 -0500 + + Add comment about magic float timestamp compat. problem. + +diff --git a/yum/repoMDObject.py b/yum/repoMDObject.py +index 97e6797..c2a349e 100755 +--- a/yum/repoMDObject.py ++++ b/yum/repoMDObject.py +@@ -172,6 +172,9 @@ class RepoMD: + thisdata = old + self.repoData[thisdata.type] = thisdata + try: ++ # NOTE: This will fail on float timestamps, this is ++ # required for compatability. Fix is to not generate ++ # float timestamps in repomd.xml. + nts = int(thisdata.timestamp) + if nts > self.timestamp: # max() not in old python + self.timestamp = nts +commit 833be09639371c9e0c88bc125e40ef682bbc4a30 +Author: Zdenek Pavlas +Date: Mon Dec 9 17:58:25 2013 +0100 + + Align the time formatting in the "Total" output with urlgrabber.progress + +diff --git a/output.py b/output.py +index e42702e..041910c 100755 +--- a/output.py ++++ b/output.py +@@ -1837,7 +1837,7 @@ to exit. + if dl_time <= 0: # This stops divide by zero, among other problems + dl_time = 0.01 + ui_size = tl.add(' | %5sB' % self.format_number(remote_size)) +- ui_time = tl.add(' %9s' % self.format_time(dl_time)) ++ ui_time = tl.add(' %s' % self.format_time(dl_time, tl._llen > 80)) + ui_end = tl.add(' ' * 5) + ui_bs = tl.add(' %5sB/s' % self.format_number(remote_size / dl_time)) + msg = "%s%s%s%s%s" % (utf8_width_fill(_("Total"), tl.rest(), tl.rest()), +commit e1db5d6a94dee861d1fa0552277bc03f037c6e3a +Author: Zdenek Pavlas +Date: Tue Dec 10 08:47:48 2013 +0100 + + yum-cron: stderr/email: no output if no messages + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index dd0a4c6..f53fbfb 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -685,6 +685,9 @@ class EmailEmitter(UpdateEmitter): + """Combine the stored messages that have been stored into a + single email message, and send this message. + """ ++ # Don't send empty emails ++ if not self.output: ++ return + # Build up the email to be sent + msg = MIMEText(''.join(self.output)) + msg['Subject'] = self.subject +@@ -708,6 +711,9 @@ class StdIOEmitter(UpdateEmitter): + """Combine the stored messages that have been stored into a + single email message, and send this message to standard output. + """ ++ # Don't print blank lines ++ if not self.output: ++ return + print "".join(self.output) + + +commit 78c4435ddbb00d11bf42040e8afb34ee1cf107b5 +Author: Zdenek Pavlas +Date: Tue Dec 10 10:02:29 2013 +0100 + + Fix a gettext string (typo). + +diff --git a/yum/__init__.py b/yum/__init__.py +index f212884..caafae4 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -1929,7 +1929,7 @@ much more problems). + # maybe a file log here, too + # but raising an exception is not going to do any good + self.logger.critical(_('%s was supposed to be installed' \ +- ' but is not!' % txmbr.po)) ++ ' but is not!') % txmbr.po) + # Note: Get Panu to do te.Failed() so we don't have to + txmbr.output_state = TS_FAILED + count = _call_txmbr_cb(txmbr, count) +commit cc0d8d11c90515ead4f3e1018e0f82b2edbc8274 +Author: Zdenek Pavlas +Date: Tue Dec 10 16:15:57 2013 +0100 + + completion-helper: No pkg list when len(prefix) < 1. BZ 1040033 + +diff --git a/etc/yum.bash b/etc/yum.bash +index 40541af..aae8992 100644 +--- a/etc/yum.bash ++++ b/etc/yum.bash +@@ -19,6 +19,8 @@ _yum_list() + { + # Fail fast for things that look like paths or options. + [[ $2 == */* || $2 == [.~-]* ]] && return ++ # Listing all packages takes way too long ++ [[ ${#2} -lt 1 ]] && return + _yum_helper list "$@" + } + +commit 7479c24ff5196f740614338247a7c513fe56486b +Author: Zdenek Pavlas +Date: Fri Dec 13 09:01:14 2013 +0100 + + completion-helper: accept empty prefix when listing installed pkgs + +diff --git a/etc/yum.bash b/etc/yum.bash +index aae8992..16d096c 100644 +--- a/etc/yum.bash ++++ b/etc/yum.bash +@@ -19,8 +19,8 @@ _yum_list() + { + # Fail fast for things that look like paths or options. + [[ $2 == */* || $2 == [.~-]* ]] && return +- # Listing all packages takes way too long +- [[ ${#2} -lt 1 ]] && return ++ # Listing all available packages takes way too long ++ [[ $1 != "installed" && ${#2} -lt 1 ]] && return + _yum_helper list "$@" + } + +commit 05846f0ce0ec09e6030f18f6e508a75347f529c0 +Author: James Antill +Date: Mon Nov 18 17:41:17 2013 -0500 + + Copy/Paste install for group upgrade lists into yum-cron output. BZ 1031374. + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index 79c1907..dd0a4c6 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -426,10 +426,31 @@ class UpdateEmitter(object): + + return a_wid + +- ++ ninstalled = self.tsInfo.installed ++ ginstalled = {} ++ if self.conf.group_command == 'objects' and ninstalled: ++ # Show new pkgs. that are installed via. a group. ++ ninstalled = [] ++ for txmbr in self.tsInfo.installed: ++ if not hasattr(txmbr, '_ugroup_member'): ++ ninstalled.append(txmbr) ++ continue ++ if txmbr._ugroup_member not in ginstalled: ++ ginstalled[txmbr._ugroup_member] = [] ++ ginstalled[txmbr._ugroup_member].append(txmbr) ++ ++ for grp in sorted(ginstalled, key=lambda x: x.ui_name): ++ action = _('Installing for group upgrade "%s"') % grp.ui_name ++ pkglist = ginstalled[grp] ++ ++ lines = [] ++ for txmbr in pkglist: ++ a_wid = _add_line(lines, data, a_wid, txmbr.po, txmbr.obsoletes) ++ ++ pkglist_lines.append((action, lines)) + + # Iterate through the different groups of packages +- for (action, pkglist) in [(_('Installing'), tsInfo.installed), ++ for (action, pkglist) in [(_('Installing'), ninstalled), + (_('Updating'), tsInfo.updated), + (_('Removing'), tsInfo.removed), + (_('Reinstalling'), tsInfo.reinstalled), +commit d0bba60912ec09dd6bbbc1dfbf2b27688bec3e68 +Author: Zdenek Pavlas +Date: Fri Dec 13 09:39:36 2013 +0100 + + yum-cron: Inherit YumOutput. BZ 1040109 + + When yum-cron can use bits from output.py, we don't have to + duplicate about 450 lines of code. + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index f53fbfb..5661fbb 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -21,6 +21,7 @@ from yum.misc import setup_locale + + # FIXME: is it really sane to use this from here? + sys.path.append('/usr/share/yum-cli') ++from output import YumOutput + import callback + + default_config_file = '/etc/yum/yum-cron.conf' +@@ -155,447 +156,9 @@ class UpdateEmitter(object): + """ + pass + +- def _format_number(self, number, SI=0, space=' '): +- """Return a human-readable metric-like string representation +- of a number. +- +- :param number: the number to be converted to a human-readable form +- :param SI: If is 0, this function will use the convention +- that 1 kilobyte = 1024 bytes, otherwise, the convention +- that 1 kilobyte = 1000 bytes will be used +- :param space: string that will be placed between the number +- and the SI prefix +- :return: a human-readable metric-like string representation of +- *number* +- """ +- symbols = [ ' ', # (none) +- 'k', # kilo +- 'M', # mega +- 'G', # giga +- 'T', # tera +- 'P', # peta +- 'E', # exa +- 'Z', # zetta +- 'Y'] # yotta +- +- if SI: step = 1000.0 +- else: step = 1024.0 +- +- thresh = 999 +- depth = 0 +- max_depth = len(symbols) - 1 +- +- # we want numbers between 0 and thresh, but don't exceed the length +- # of our list. In that event, the formatting will be screwed up, +- # but it'll still show the right number. +- while number > thresh and depth < max_depth: +- depth = depth + 1 +- number = number / step +- +- if type(number) == type(1) or type(number) == type(1L): +- format = '%i%s%s' +- elif number < 9.95: +- # must use 9.95 for proper sizing. For example, 9.99 will be +- # rounded to 10.0 with the .1f format string (which is too long) +- format = '%.1f%s%s' +- else: +- format = '%.0f%s%s' +- +- return(format % (float(number or 0), space, symbols[depth])) +- +- def _fmtColumns(self, columns, msg=u'', end=u'', text_width=utf8_width): +- """Return a row of data formatted into a string for output. +- Items can overflow their columns. +- +- :param columns: a list of tuples containing the data to +- output. Each tuple contains first the item to be output, +- then the amount of space allocated for the column, and then +- optionally a type of highlighting for the item +- :param msg: a string to begin the line of output with +- :param end: a string to end the line of output with +- :param text_width: a function to find the width of the items +- in the columns. This defaults to utf8 but can be changed +- to len() if you know it'll be fine +- :return: a row of data formatted into a string for output +- """ +- total_width = len(msg) +- data = [] +- for col_data in columns[:-1]: +- (val, width) = col_data +- +- if not width: # Don't count this column, invisible text +- msg += u"%s" +- data.append(val) +- continue +- +- (align, width) = self._fmt_column_align_width(width) +- val_width = text_width(val) +- if val_width <= width: +- # Don't use utf8_width_fill() because it sucks performance +- # wise for 1,000s of rows. Also allows us to use len(), when +- # we can. +- msg += u"%s%s " +- if (align == u'-'): +- data.extend([val, " " * (width - val_width)]) +- else: +- data.extend([" " * (width - val_width), val]) +- else: +- msg += u"%s\n" + " " * (total_width + width + 1) +- data.append(val) +- total_width += width +- total_width += 1 +- (val, width) = columns[-1] +- (align, width) = self._fmt_column_align_width(width) +- val = utf8_width_fill(val, width, left=(align == u'-')) +- msg += u"%%s%s" % end +- data.append(val) +- return msg % tuple(data) +- +- def _calcColumns(self, data, total_width, columns=None, remainder_column=0, indent=''): +- """Dynamically calculate the widths of the columns that the +- fields in data should be placed into for output. +- +- :param data: a list of dictionaries that represent the data to +- be output. Each dictionary in the list corresponds to annn +- column of output. The keys of the dictionary are the +- lengths of the items to be output, and the value associated +- with a key is the number of items of that length. +- :param total_width: the total width of the output. +- :param columns: a list containing the minimum amount of space +- that must be allocated for each row. This can be used to +- ensure that there is space available in a column if, for +- example, the actual lengths of the items being output +- cannot be given in *data* +- :param remainder_column: number of the column to receive a few +- extra spaces that may remain after other allocation has +- taken place +- :param indent: string that will be prefixed to a line of +- output to create e.g. an indent +- :return: a list of the widths of the columns that the fields +- in data should be placed into for output +- """ +- if total_width is None: +- total_width = self.term.columns +- +- cols = len(data) +- # Convert the data to ascending list of tuples, (field_length, pkgs) +- pdata = data +- data = [None] * cols # Don't modify the passed in data +- for d in range(0, cols): +- data[d] = sorted(pdata[d].items()) +- +- # We start allocating 1 char to everything but the last column, and a +- # space between each (again, except for the last column). Because +- # at worst we are better with: +- # |one two three| +- # | four | +- # ...than: +- # |one two three| +- # | f| +- # |our | +- # ...the later being what we get if we pre-allocate the last column, and +- # thus. the space, due to "three" overflowing it's column by 2 chars. +- if columns is None: +- columns = [1] * (cols - 1) +- columns.append(0) +- +- total_width -= (sum(columns) + (cols - 1) + +- utf8_width(indent)) +- if not columns[-1]: +- total_width += 1 +- while total_width > 0: +- # Find which field all the spaces left will help best +- helps = 0 +- val = 0 +- for d in xrange(0, cols): +- thelps = self._calc_columns_spaces_helps(columns[d], data[d], +- total_width) +- if not thelps: +- continue +- # We prefer to overflow: the last column, and then earlier +- # columns. This is so that in the best case (just overflow the +- # last) ... grep still "works", and then we make it prettier. +- if helps and (d == (cols - 1)) and (thelps / 2) < helps: +- continue +- if thelps < helps: +- continue +- helps = thelps +- val = d +- +- # If we found a column to expand, move up to the next level with +- # that column and start again with any remaining space. +- if helps: +- diff = data[val].pop(0)[0] - columns[val] +- if not columns[val] and (val == (cols - 1)): +- # If we are going from 0 => N on the last column, take 1 +- # for the space before the column. +- total_width -= 1 +- columns[val] += diff +- total_width -= diff +- continue +- +- overflowed_columns = 0 +- for d in xrange(0, cols): +- if not data[d]: +- continue +- overflowed_columns += 1 +- if overflowed_columns: +- # Split the remaining spaces among each overflowed column +- # equally +- norm = total_width / overflowed_columns +- for d in xrange(0, cols): +- if not data[d]: +- continue +- columns[d] += norm +- total_width -= norm +- +- # Split the remaining spaces among each column equally, except the +- # last one. And put the rest into the remainder column +- cols -= 1 +- norm = total_width / cols +- for d in xrange(0, cols): +- columns[d] += norm +- columns[remainder_column] += total_width - (cols * norm) +- total_width = 0 +- +- return columns +- +- @staticmethod +- def _fmt_column_align_width(width): +- if width < 0: +- return (u"-", -width) +- return (u"", width) +- +- @staticmethod +- def _calc_columns_spaces_helps(current, data_tups, left): +- """ Spaces left on the current field will help how many pkgs? """ +- ret = 0 +- for tup in data_tups: +- if left < (tup[0] - current): +- break +- ret += tup[1] +- return ret +- + def _formatTransaction(self, tsInfo): +- """Return a string containing a human-readable formatted +- summary of the transaction. +- +- :param tsInfo: :class:`yum.transactioninfo.TransactionData` +- instance that contains information about the transaction +- :return: a string that contains a formatted summary of the +- transaction +- """ +- # Sort the packages in the transaction into different lists, +- # e.g. installed, updated etc +- tsInfo.makelists(True, True) +- +- # For each package list, pkglist_lines will contain a tuple +- # that contains the name of the list, and a list of tuples +- # with information about each package in the list +- pkglist_lines = [] +- data = {'n' : {}, 'v' : {}, 'r' : {}} +- a_wid = 0 # Arch can't get "that big" ... so always use the max. +- +- +- def _add_line(lines, data, a_wid, po, obsoletes=[]): +- # Create a tuple of strings that contain the name, arch, +- # version, repository, size, and obsoletes of the package +- # given in po. Then, append this tuple to lines. The +- # strings are formatted so that the tuple can be easily +- # joined together for output. +- +- +- (n,a,e,v,r) = po.pkgtup +- +- # Retrieve the version, repo id, and size of the package +- # in human-readable form +- evr = po.printVer() +- repoid = po.ui_from_repo +- size = self._format_number(float(po.size)) +- +- if a is None: # gpgkeys are weird +- a = 'noarch' +- +- lines.append((n, a, evr, repoid, size, obsoletes)) +- # Create a dict of field_length => number of packages, for +- # each field. +- for (d, v) in (("n",len(n)), ("v",len(evr)), ("r",len(repoid))): +- data[d].setdefault(v, 0) +- data[d][v] += 1 +- a_wid = max(a_wid, len(a)) +- +- return a_wid +- +- ninstalled = self.tsInfo.installed +- ginstalled = {} +- if self.conf.group_command == 'objects' and ninstalled: +- # Show new pkgs. that are installed via. a group. +- ninstalled = [] +- for txmbr in self.tsInfo.installed: +- if not hasattr(txmbr, '_ugroup_member'): +- ninstalled.append(txmbr) +- continue +- if txmbr._ugroup_member not in ginstalled: +- ginstalled[txmbr._ugroup_member] = [] +- ginstalled[txmbr._ugroup_member].append(txmbr) +- +- for grp in sorted(ginstalled, key=lambda x: x.ui_name): +- action = _('Installing for group upgrade "%s"') % grp.ui_name +- pkglist = ginstalled[grp] +- +- lines = [] +- for txmbr in pkglist: +- a_wid = _add_line(lines, data, a_wid, txmbr.po, txmbr.obsoletes) +- +- pkglist_lines.append((action, lines)) +- +- # Iterate through the different groups of packages +- for (action, pkglist) in [(_('Installing'), ninstalled), +- (_('Updating'), tsInfo.updated), +- (_('Removing'), tsInfo.removed), +- (_('Reinstalling'), tsInfo.reinstalled), +- (_('Downgrading'), tsInfo.downgraded), +- (_('Installing for dependencies'), tsInfo.depinstalled), +- (_('Updating for dependencies'), tsInfo.depupdated), +- (_('Removing for dependencies'), tsInfo.depremoved)]: +- # Create a list to hold the tuples of strings for each package +- lines = [] +- +- # Append the tuple for each package to lines, and update a_wid +- for txmbr in pkglist: +- a_wid = _add_line(lines, data, a_wid, txmbr.po, txmbr.obsoletes) +- +- # Append the lines instance for this package list to pkglist_lines +- pkglist_lines.append((action, lines)) +- +- # # Iterate through other package lists +- # for (action, pkglist) in [(_('Skipped (dependency problems)'), +- # self.skipped_packages), +- # (_('Not installed'), self._not_found_i.values()), +- # (_('Not available'), self._not_found_a.values())]: +- # lines = [] +- # for po in pkglist: +- # a_wid = _add_line(lines, data, a_wid, po) +- +- # pkglist_lines.append((action, lines)) +- +- if not data['n']: +- return u'' +- else: +- # Change data to a list with the correct number of +- # columns, in the correct order +- data = [data['n'], {}, data['v'], data['r'], {}] +- +- +- +- # Calculate the space needed for each column +- columns = [1, a_wid, 1, 1, 5] +- +- columns = self._calcColumns(data, self.opts.output_width, +- columns, remainder_column = 2, indent=" ") +- +- (n_wid, a_wid, v_wid, r_wid, s_wid) = columns +- assert s_wid == 5 +- +- # out will contain the output as a list of strings, that +- # can be later joined together +- out = [u""" +-%s +-%s +-%s +-""" % ('=' * self.opts.output_width, +- self._fmtColumns(((_('Package'), -n_wid), (_('Arch'), -a_wid), +- (_('Version'), -v_wid), (_('Repository'), -r_wid), +- (_('Size'), s_wid)), u" "), +- '=' * self.opts.output_width)] +- +- # Add output for each package list in pkglist_lines +- for (action, lines) in pkglist_lines: +- #If the package list is empty, skip it +- if not lines: +- continue +- +- # Add the name of the package list +- totalmsg = u"%s:\n" % action +- # Add a line of output about an individual package +- for (n, a, evr, repoid, size, obsoletes) in lines: +- columns = ((n, -n_wid), (a, -a_wid), +- (evr, -v_wid), (repoid, -r_wid), (size, s_wid)) +- msg = self._fmtColumns(columns, u" ", u"\n") +- for obspo in sorted(obsoletes): +- appended = _(' replacing %s.%s %s\n') +- appended %= (obspo.name, +- obspo.arch, obspo.printVer()) +- msg = msg+appended +- totalmsg = totalmsg + msg +- +- # Append the line about the individual package to out +- out.append(totalmsg) +- +- # Add a summary of the transaction +- out.append(_(""" +-Transaction Summary +-%s +-""") % ('=' * self.opts.output_width)) +- summary_data = ( +- (_('Install'), len(tsInfo.installed), +- len(tsInfo.depinstalled)), +- (_('Upgrade'), len(tsInfo.updated), +- len(tsInfo.depupdated)), +- (_('Remove'), len(tsInfo.removed), +- len(tsInfo.depremoved)), +- (_('Reinstall'), len(tsInfo.reinstalled), 0), +- (_('Downgrade'), len(tsInfo.downgraded), 0), +- # (_('Skipped (dependency problems)'), len(self.skipped_packages), 0), +- # (_('Not installed'), len(self._not_found_i.values()), 0), +- # (_('Not available'), len(self._not_found_a.values()), 0), +- ) +- max_msg_action = 0 +- max_msg_count = 0 +- max_msg_pkgs = 0 +- max_msg_depcount = 0 +- for action, count, depcount in summary_data: +- if not count and not depcount: +- continue +- +- msg_pkgs = P_('Package', 'Packages', count) +- len_msg_action = utf8_width(action) +- len_msg_count = utf8_width(str(count)) +- len_msg_pkgs = utf8_width(msg_pkgs) +- +- if depcount: +- len_msg_depcount = utf8_width(str(depcount)) +- else: +- len_msg_depcount = 0 +- +- max_msg_action = max(len_msg_action, max_msg_action) +- max_msg_count = max(len_msg_count, max_msg_count) +- max_msg_pkgs = max(len_msg_pkgs, max_msg_pkgs) +- max_msg_depcount = max(len_msg_depcount, max_msg_depcount) +- +- for action, count, depcount in summary_data: +- msg_pkgs = P_('Package', 'Packages', count) +- if depcount: +- msg_deppkgs = P_('Dependent package', 'Dependent packages', +- depcount) +- if count: +- msg = '%s %*d %s (+%*d %s)\n' +- out.append(msg % (utf8_width_fill(action, max_msg_action), +- max_msg_count, count, +- utf8_width_fill(msg_pkgs, max_msg_pkgs), +- max_msg_depcount, depcount, msg_deppkgs)) +- else: +- msg = '%s %*s %s ( %*d %s)\n' +- out.append(msg % (utf8_width_fill(action, max_msg_action), +- max_msg_count, '', +- utf8_width_fill('', max_msg_pkgs), +- max_msg_depcount, depcount, msg_deppkgs)) +- elif count: +- msg = '%s %*d %s\n' +- out.append(msg % (utf8_width_fill(action, max_msg_action), +- max_msg_count, count, msg_pkgs)) +- +- return ''.join(out) ++ assert self.opts._base.tsInfo == tsInfo ++ return self.opts._base.listTransaction() + + + class EmailEmitter(UpdateEmitter): +@@ -738,7 +301,7 @@ class YumCronConfig(BaseConfig): + group_package_types = ListOption(['mandatory', 'default']) + + +-class YumCronBase(yum.YumBase): ++class YumCronBase(yum.YumBase, YumOutput): + """Main class to check for and apply the updates.""" + + def __init__(self, config_file_name = None): +@@ -748,9 +311,13 @@ class YumCronBase(yum.YumBase): + config file to use. + """ + yum.YumBase.__init__(self) ++ YumOutput.__init__(self) + + # Read the config file + self.readConfigFile(config_file_name) ++ self.term.reinit(color='never') ++ self.term.columns = self.opts.output_width ++ self.opts._base = self + + + # Create the emitters, and add them to the list +commit 1f4b4a800516ec56215a4bed36293f62b77e1239 +Author: Zdenek Pavlas +Date: Fri Dec 13 10:11:34 2013 +0100 + + yum-cron: remove _formatTransaction() + + By moving the formatting out of emitters, we loose a bit of flexibility, + but at least run the formatting only once, and don't have to pass YumBase + references to emitters. + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index 5661fbb..a1fd10b 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -37,25 +37,23 @@ class UpdateEmitter(object): + self.opts = opts + self.output = [] + +- def updatesAvailable(self, tsInfo): ++ def updatesAvailable(self, summary): + """Appends a message to the output list stating that there are + updates available. + +- :param tsInfo: A :class:`yum.transactioninfo.TransactionData` +- instance that contains information about the transaction. ++ :param summary: A human-readable summary of the transaction. + """ + self.output.append('The following updates are available on %s:' % self.opts.system_name) +- self.output.append(self._formatTransaction(tsInfo)) ++ self.output.append(summary) + +- def updatesDownloading(self, tsInfo): ++ def updatesDownloading(self, summary): + """Append a message to the output list stating that + downloading updates has started. + +- :param tsInfo: A :class:`yum.transactioninfo.TransactionData` +- instance that contains information about the transaction. ++ :param summary: A human-readable summary of the transaction. + """ + self.output.append('The following updates will be downloaded on %s:' % self.opts.system_name) +- self.output.append(self._formatTransaction(tsInfo)) ++ self.output.append(summary) + + def updatesDownloaded(self): + """Append a message to the output list stating that updates +@@ -63,15 +61,14 @@ class UpdateEmitter(object): + """ + self.output.append("Updates downloaded successfully.") + +- def updatesInstalling(self, tsInfo): ++ def updatesInstalling(self, summary): + """Append a message to the output list stating that + installing updates has started. + +- :param tsInfo: A :class:`yum.transactioninfo.TransactionData` +- instance that contains information about the transaction. ++ :param summary: A human-readable summary of the transaction. + """ + self.output.append('The following updates will be applied on %s:' % self.opts.system_name) +- self.output.append(self._formatTransaction(tsInfo)) ++ self.output.append(summary) + + def updatesInstalled(self): + """Append a message to the output list stating that updates +@@ -156,10 +153,6 @@ class UpdateEmitter(object): + """ + pass + +- def _formatTransaction(self, tsInfo): +- assert self.opts._base.tsInfo == tsInfo +- return self.opts._base.listTransaction() +- + + class EmailEmitter(UpdateEmitter): + """Emitter class to send messages via email.""" +@@ -168,14 +161,13 @@ class EmailEmitter(UpdateEmitter): + super(EmailEmitter, self).__init__(opts) + self.subject = "" + +- def updatesAvailable(self, tsInfo): ++ def updatesAvailable(self, summary): + """Appends a message to the output list stating that there are + updates available, and set an appropriate subject line. + +- :param tsInfo: A :class:`yum.transactioninfo.TransactionData` +- instance that contains information about the transaction. ++ :param summary: A human-readable summary of the transaction. + """ +- super(EmailEmitter, self).updatesAvailable(tsInfo) ++ super(EmailEmitter, self).updatesAvailable(summary) + self.subject = "Yum: Updates Available on %s" % self.opts.system_name + + def updatesDownloaded(self): +@@ -317,7 +309,6 @@ class YumCronBase(yum.YumBase, YumOutput): + self.readConfigFile(config_file_name) + self.term.reinit(color='never') + self.term.columns = self.opts.output_width +- self.opts._base = self + + + # Create the emitters, and add them to the list +@@ -655,11 +646,13 @@ class YumCronBase(yum.YumBase, YumOutput): + + def emitAvailable(self): + """Emit a notice stating whether updates are available.""" +- map(lambda x: x.updatesAvailable(self.tsInfo), self.emitters) ++ summary = self.listTransaction() ++ map(lambda x: x.updatesAvailable(summary), self.emitters) + + def emitDownloading(self): + """Emit a notice stating that updates are downloading.""" +- map(lambda x: x.updatesDownloading(self.tsInfo), self.emitters) ++ summary = self.listTransaction() ++ map(lambda x: x.updatesDownloading(summary), self.emitters) + + def emitDownloaded(self): + """Emit a notice stating that updates have downloaded.""" +@@ -669,7 +662,8 @@ class YumCronBase(yum.YumBase, YumOutput): + """Emit a notice stating that automatic updates are about to + be applied. + """ +- map(lambda x: x.updatesInstalling(self.tsInfo), self.emitters) ++ summary = self.listTransaction() ++ map(lambda x: x.updatesInstalling(summary), self.emitters) + + def emitInstalled(self): + """Emit a notice stating that automatic updates have been applied.""" +commit f8579cb9c08f5ea962f555d1610bb58449139ed2 +Author: Zdenek Pavlas +Date: Mon Dec 23 15:29:51 2013 +0100 + + Skip unavailable repos. BZ 1046076 + + By populating all repos at once we honor skip_if_unavailable, + and also download metadata in parallel (although this does not + matter that much since yum-cron is not interactive). + +diff --git a/yum-cron/yum-cron.py b/yum-cron/yum-cron.py +index 19436e5..b96dd13 100755 +--- a/yum-cron/yum-cron.py ++++ b/yum-cron/yum-cron.py +@@ -414,7 +414,9 @@ class YumCronBase(yum.YumBase, YumOutput): + + for repo in self.repos.sort(): + repo.metadata_expire = 0 ++ repo.skip_if_unavailable = True + ++ self.pkgSack # honor skip_if_unavailable + self.upinfo + + def refreshUpdates(self): +commit a00fcf5e9ce765fd6aba2db327bfb072f23ac465 +Author: Jonathan Wakely +Date: Sun Dec 22 11:39:49 2013 +0000 + + docs: yum.conf.5: Fix typo. + +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index 48ced00..c66eba8 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -148,7 +148,7 @@ Command-line option: \fB\-t\fP + .IP + \fBexclude\fR + List of packages to exclude from all repositories, so yum works +-as if that package was never in the repositories.. This should be a space ++as if that package was never in the repositories. This should be a space + separated list. + This is commonly used so a package isn't upgraded or installed accidentally, but + can be used to remove packages in any way that "yum list" will show packages. +commit c26740594afdf86c503c3406f1370dbb6ad0608b +Author: James Antill +Date: Thu Jan 2 10:57:08 2014 -0500 + + docs: Update --downloadonly section of man page. + +diff --git a/docs/yum.8 b/docs/yum.8 +index 0e211eb..f7d6ec3 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -871,7 +871,8 @@ This option makes yum go slower, checking for things that shouldn't be possible + making it more tolerant of external errors. + .br + .IP "\fB\-\-downloadonly\fP" +-Don't update, just download. ++Don't update, just download. This is done in the background, so the yum lock is released for other operations. This can also be chosen by typing 'd'ownloadonly ++at the transaction confirmation prompt. + .br + .IP "\fB\-\-downloaddir=directory\fP" + Specifies an alternate directory to store packages. +commit 6ddb350b207cfa54d96232c23606444cd0b79341 +Author: Zdenek Pavlas +Date: Mon Jan 13 16:12:33 2014 +0100 + + yum-cron: Enable random_sleep by default. + +diff --git a/etc/yum-cron-hourly.conf b/etc/yum-cron-hourly.conf +index 2d52349..7871a46 100644 +--- a/etc/yum-cron-hourly.conf ++++ b/etc/yum-cron-hourly.conf +@@ -25,7 +25,7 @@ apply_updates = no + # minutes before running. This is useful for e.g. staggering the + # times that multiple systems will access update servers. If + # random_sleep is 0 or negative, the program will run immediately. +-random_sleep = 0 ++random_sleep = 15 + + + [emitters] +diff --git a/etc/yum-cron.conf b/etc/yum-cron.conf +index a97d881..f8de068 100644 +--- a/etc/yum-cron.conf ++++ b/etc/yum-cron.conf +@@ -24,7 +24,7 @@ apply_updates = no + # minutes before running. This is useful for e.g. staggering the + # times that multiple systems will access update servers. If + # random_sleep is 0 or negative, the program will run immediately. +-random_sleep = 0 ++random_sleep = 6*60 + + + [emitters] +commit 2715047a195b29d6ac7d985166b985954267a0bb +Author: James Antill +Date: Tue Jan 14 15:29:03 2014 -0500 + + Fix yum-cron.conf default, as ini parser can't do Math. + +diff --git a/etc/yum-cron.conf b/etc/yum-cron.conf +index f8de068..b0f7839 100644 +--- a/etc/yum-cron.conf ++++ b/etc/yum-cron.conf +@@ -24,7 +24,8 @@ apply_updates = no + # minutes before running. This is useful for e.g. staggering the + # times that multiple systems will access update servers. If + # random_sleep is 0 or negative, the program will run immediately. +-random_sleep = 6*60 ++# 6*60 = 360 ++random_sleep = 360 + + + [emitters] diff --git a/SOURCES/BZ-1058297-remove-del-for-weird-anaconda-C-NULL-exception.patch b/SOURCES/BZ-1058297-remove-del-for-weird-anaconda-C-NULL-exception.patch new file mode 100644 index 0000000..61aac61 --- /dev/null +++ b/SOURCES/BZ-1058297-remove-del-for-weird-anaconda-C-NULL-exception.patch @@ -0,0 +1,18 @@ +commit 4ec4888593f739328600d42c1ad5a33d6b72674a +Author: Vratislav Podzimek +Date: Tue Apr 8 09:37:01 2014 -0400 + + Remove extra del(fo) for weird C NULL execption (it is valid). BZ 1058297. + +diff --git a/yum/misc.py b/yum/misc.py +index 347a07a..cdc08a0 100644 +--- a/yum/misc.py ++++ b/yum/misc.py +@@ -360,7 +360,6 @@ def checksum(sumtype, file, CHUNK=2**16, datasize=None): + + if type(file) is types.StringType: + fo.close() +- del fo + + # This screws up the length, but that shouldn't matter. We only care + # if this checksum == what we expect. diff --git a/SOURCES/BZ-1062959-add-fs-command.patch b/SOURCES/BZ-1062959-add-fs-command.patch new file mode 100644 index 0000000..bf59df3 --- /dev/null +++ b/SOURCES/BZ-1062959-add-fs-command.patch @@ -0,0 +1,1406 @@ +commit b6f5e550048705c0979f0e5bb88f0b83d5750daf +Author: James Antill +Date: Wed Feb 12 15:59:20 2014 -0500 + + Fix yum repo-pkgs install exist-other-repo. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 0604d63..622bc14 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -4714,6 +4714,8 @@ much more problems). + arg) + + mypkgs = self.returnPackagesByDep(arg) ++ if repoid: ++ mypkgs = misc.filter_pkgs_repoid(mypkgs, repoid) + if not misc.re_glob(arg): + mypkgs = self.bestPackagesFromList(mypkgs, + single_name=True, +commit 26128173b362474456e8f0642073ecb0322ed031 +Author: James Antill +Date: Wed Feb 12 16:06:00 2014 -0500 + + Add override_install_langs configuration, for container install needs. + +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index c66eba8..bf3c442 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -329,6 +329,12 @@ context of an rpm transaction set you're best leaving it alone. Default is + an empty list. + + .IP ++\fBoverride_install_langs\fR ++This is a way to override rpm's _install_langs macro. without having to change ++it within rpm's macro file. ++Default is nothing (so does nothing). ++ ++.IP + \fBrecent\fR + Number of days back to look for `recent' packages added to a repository. + Used by the \fBlist recent\fR command. Default is `7'. +diff --git a/yum/config.py b/yum/config.py +index c38d574..09a4dcc 100644 +--- a/yum/config.py ++++ b/yum/config.py +@@ -768,6 +768,7 @@ class YumConf(StartupConf): + 'kernel-hugemem', 'kernel-enterprise', 'kernel-bigmem', + 'kernel-devel', 'kernel-PAE', 'kernel-PAE-debug']) + tsflags = ListOption() ++ override_install_langs = Option() + + assumeyes = BoolOption(False) + assumeno = BoolOption(False) +diff --git a/yum/depsolve.py b/yum/depsolve.py +index 8a675eb..1840b43 100644 +--- a/yum/depsolve.py ++++ b/yum/depsolve.py +@@ -180,6 +180,13 @@ class Depsolve(object): + def initActionTs(self): + """Set up the transaction set that will be used for all the work.""" + ++ # LOL, override rpm transaction macro. ++ # Must be done before rpmtsCreate() ++ if self.conf.override_install_langs: ++ old_install_langs = rpm.expandMacro("%_install_langs") ++ rpm.expandMacro("%define _install_langs " + ++ self.conf.override_install_langs) ++ + self._ts = rpmUtils.transaction.TransactionWrapper(self.conf.installroot) + ts_flags_to_rpm = { 'noscripts': rpm.RPMTRANS_FLAG_NOSCRIPTS, + 'notriggers': rpm.RPMTRANS_FLAG_NOTRIGGERS, +commit 99540142d78484327716643daab03581fef6ee4b +Author: James Antill +Date: Wed Feb 12 16:06:56 2014 -0500 + + Install yumdb keys for install_langs and tsflags values. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 622bc14..3b6ed82 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -1915,6 +1915,13 @@ much more problems). + txmbr_cb(txmbr, count) + return count + ++ oil = self.conf.override_install_langs ++ if not oil: ++ oil = rpm.expandMacro("%_install_langs") ++ if oil == 'all': ++ oil = '' ++ elif oil: ++ oil = ":".join(sorted(oil.split(':'))) + vt_st = time.time() + self.plugins.run('preverifytrans') + count = 0 +@@ -1942,6 +1949,17 @@ much more problems). + if var == 'arch': continue + # Skip uuid? + setattr(po.yumdb_info, 'var_' + var, self.conf.yumvar[var]) ++ if oil: ++ po.yumdb_info.ts_install_langs = oil ++ if 'nocontexts' in self.conf.tsflags: ++ po.yumdb_info.tsflag_nocontexts = 'true' ++ if 'nodocs' in self.conf.tsflags: ++ po.yumdb_info.tsflag_nodocs = 'true' ++ if 'noscripts' in self.conf.tsflags: ++ po.yumdb_info.tsflag_noscripts = 'true' ++ if 'notriggers' in self.conf.tsflags: ++ po.yumdb_info.tsflag_notriggers = 'true' ++ + if hasattr(self, 'args') and self.args: + po.yumdb_info.command_line = ' '.join(self.args) + elif hasattr(self, 'cmds') and self.cmds: +commit 598b2f64f06dc625fca3e5a3b9ef0000f973eb7f +Author: James Antill +Date: Wed Feb 12 16:07:40 2014 -0500 + + Add _writeRawConfigFile() so we can change yum.conf values. + +diff --git a/yum/config.py b/yum/config.py +index 09a4dcc..f213fc1 100644 +--- a/yum/config.py ++++ b/yum/config.py +@@ -1301,6 +1301,48 @@ def writeRawRepoFile(repo,only=None): + fp.write(str(ini)) + fp.close() + ++# Copied from yum-config-manager ... how we alter yu.conf ... used in "yum fs" ++def _writeRawConfigFile(filename, section_id, yumvar, ++ cfgoptions, items, optionobj, ++ only=None): ++ """ ++ From writeRawRepoFile, but so we can alter [main] too. ++ """ ++ ini = INIConfig(open(filename)) ++ ++ osection_id = section_id ++ # b/c repoids can have $values in them we need to map both ways to figure ++ # out which one is which ++ if section_id not in ini._sections: ++ for sect in ini._sections.keys(): ++ if varReplace(sect, yumvar) == section_id: ++ section_id = sect ++ ++ # Updated the ConfigParser with the changed values ++ cfgOptions = cfgoptions(osection_id) ++ for name,value in items(): ++ if value is None: # Proxy ++ continue ++ ++ if only is not None and name not in only: ++ continue ++ ++ option = optionobj(name) ++ ovalue = option.tostring(value) ++ # If the value is the same, but just interpreted ... when we don't want ++ # to keep the interpreted values. ++ if (name in ini[section_id] and ++ ovalue == varReplace(ini[section_id][name], yumvar)): ++ ovalue = ini[section_id][name] ++ ++ if name not in cfgOptions and option.default == value: ++ continue ++ ++ ini[section_id][name] = ovalue ++ fp =file(filename, "w") ++ fp.write(str(ini)) ++ fp.close() ++ + #def main(): + # mainconf = readMainConfig(readStartupConfig('/etc/yum/yum.conf', '/')) + # print mainconf.cachedir +commit 6a415f0b18c0533dfdc97fdab3306ec8ccebb52d +Author: James Antill +Date: Wed Feb 12 16:55:45 2014 -0500 + + Add fs sub-command and docs. Mostly for small installroot creation. + +diff --git a/cli.py b/cli.py +index eed63a2..7173688 100755 +--- a/cli.py ++++ b/cli.py +@@ -112,6 +112,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput): + self.registerCommand(yumcommands.UpdateinfoCommand()) + self.registerCommand(yumcommands.UpdateMinimalCommand()) + self.registerCommand(yumcommands.FSSnapshotCommand()) ++ self.registerCommand(yumcommands.FSCommand()) + + def registerCommand(self, command): + """Register a :class:`yumcommands.YumCommand` so that it can be called by +diff --git a/docs/yum.8 b/docs/yum.8 +index c9b529e..31c1c88 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -86,6 +86,8 @@ gnome\-packagekit application\&. + .br + .I \fR * fssnapshot [summary | list | have-space | create | delete] + .br ++.I \fR * fs [filters | refilter | refilter-cleanup | du] ++.br + .I \fR * check + .br + .I \fR * help [command] +@@ -718,6 +720,36 @@ then you can create and delete snapshots using: + Configuration Options: \fBfssnap_automatic_pre\fP, \fBfssnap_automatic_post\fP, \fBfssnap_automatic_keep\fP, \fBfssnap_percentage\fP, \fBfssnap_devices\fP + + .IP ++.IP "\fBfs\fP" ++This command has a few sub-commands to act on the filesystem data of the host, ++mainly for removing languages/documentation for minimal installs: ++ ++.br ++.I \fR yum fs filters ++ ++.br ++.I \fR yum fs filter languages en:es ++ ++.br ++.I \fR yum fs filter documentation ++ ++.br ++.I \fR yum fs refilter [package(s)] ++ ++.br ++.I \fR yum fs refilter-cleanup [package(s)] ++ ++.br ++.I \fR yum fs du [path] ++ ++the first 3 being a simple interface to change yum.conf altering the tsflags ++and override_install_langs configurations. The refilter command is an optimized ++way of calling "yum reinstall" to reinstall the packages with the new filters ++applied. The refilter-cleanup command is needed because rpm doesn't actually ++remove the files on reinstall, as it should. And the du command is included so ++you can easily see the space used/saved. ++ ++.IP + .IP "\fBcheck\fP" + Checks the local rpmdb and produces information on any problems it finds. You + can pass the check command the arguments "dependencies", "duplicates", "obsoletes" or "provides", +diff --git a/docs/yum.conf.5 b/docs/yum.conf.5 +index bf3c442..4ec7689 100644 +--- a/docs/yum.conf.5 ++++ b/docs/yum.conf.5 +@@ -327,12 +327,14 @@ with newer rpm versions. + You can set all/any of them. However, if you don't know what these do in the + context of an rpm transaction set you're best leaving it alone. Default is + an empty list. ++Also see the "yum fs" command, for excluding docs. + + .IP + \fBoverride_install_langs\fR + This is a way to override rpm's _install_langs macro. without having to change + it within rpm's macro file. + Default is nothing (so does nothing). ++Also see the "yum fs" command. + + .IP + \fBrecent\fR +diff --git a/yumcommands.py b/yumcommands.py +index 4214383..03450c4 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -4291,3 +4291,457 @@ class FSSnapshotCommand(YumCommand): + print msg % (len(snaps), base.format_number(used), len(dev_oris)) + + return 0, [basecmd + ' ' + subcommand + ' done'] ++ ++ ++class FSCommand(YumCommand): ++ def getNames(self): ++ return ['fs'] ++ ++ def getUsage(self): ++ return "[]" ++ ++ def getSummary(self): ++ return _("Creates filesystem snapshots, or lists/deletes current snapshots.") ++ ++ def doCheck(self, base, basecmd, extcmds): ++ """Verify that conditions are met so that this command can run. ++ These include that the program is being run by the root user, ++ that there are enabled repositories with gpg keys, and that ++ this command is called with appropriate arguments. ++ ++ :param base: a :class:`yum.Yumbase` object ++ :param basecmd: the name of the command ++ :param extcmds: the command line arguments passed to *basecmd* ++ """ ++ checkRootUID(base) ++ ++ def _fs_pkg_walk(self, pkgs, prefix, modified=False, verbose=False): ++ ++ pfr = {'norm' : {}, ++ 'mod' : {}, ++ 'ghost' : {}, ++ 'miss' : {}, ++ 'not' : {} ++ } ++ ++ def quick_match(pkgs): ++ for pkg in pkgs: ++ for fname in pkg.filelist + pkg.dirlist: ++ if not fname.startswith(prefix): ++ continue ++ pfr['norm'][fname] = pkg ++ for fname in pkg.ghostlist: ++ if not fname.startswith(prefix): ++ continue ++ pfr['ghost'][fname] = pkg ++ return pfr ++ ++ def _quick_match_iter(pkgs): ++ # Walking the fi information is much slower than filelist/dirlist ++ for pkg in pkgs: ++ found = False ++ for fname in pkg.dirlist: ++ if fname.startswith(prefix): ++ yield pkg ++ found = True ++ break ++ if found: ++ continue ++ for fname in pkg.filelist: ++ if fname.startswith(prefix): ++ yield pkg ++ found = True ++ break ++ if found: ++ continue ++ for fname in pkg.ghostlist: ++ if fname.startswith(prefix): ++ yield pkg ++ break ++ ++ def verify_match(pkgs): ++ _pfs = [] ++ def scoop_pfs(pfs): ++ _pfs.append(pfs) ++ ++ if not modified: ++ return [] ++ ++ return pfs ++ ++ if prefix != '/': ++ pkgs = _quick_match_iter(pkgs) ++ for pkg in pkgs: ++ _pfs = [] ++ probs = pkg.verify(patterns=[prefix+'*'], fake_problems=False, ++ callback=scoop_pfs) ++ ++ for pf in _pfs[0]: ++ if pf.filename in probs: ++ pfr['mod'][pf.filename] = pkg ++ elif pf.rpmfile_state == 'not installed': ++ pfr['not'][pf.filename] = pkg ++ elif 'ghost' in pf.rpmfile_types: ++ pfr['ghost'][pf.filename] = pkg ++ elif 'missing ok' in pf.rpmfile_types: ++ pfr['miss'][pf.filename] = pkg ++ else: ++ pfr['norm'][pf.filename] = pkg ++ return pfr ++ ++ # return quick_match(pkgs) ++ return verify_match(pkgs) ++ ++ def _fs_du(self, base, extcmds): ++ def _dir_prefixes(path): ++ while path != '/': ++ path = os.path.dirname(path) ++ yield path ++ ++ def loc_num(x): ++ """ String of a number in the readable "locale" format. """ ++ return locale.format("%d", int(x), True) ++ ++ data = {'pkgs_size' : {}, ++ 'pkgs_not_size' : {}, ++ 'pkgs_ghost_size' : {}, ++ 'pkgs_miss_size' : {}, ++ 'pkgs_mod_size' : {}, ++ ++ 'pres_size' : {}, ++ 'data_size' : {}, ++ 'data_not_size' : {}, ++ ++ 'pkgs_count' : 0, ++ 'pkgs_not_count' : 0, ++ 'pkgs_ghost_count' : 0, ++ 'pkgs_miss_count' : 0, ++ 'pkgs_mod_count' : 0, ++ ++ 'data_count' : 0} # data_not_count == pkgs_not_count ++ ++ def _add_size(d, v, size): ++ if v not in d: ++ d[v] = 0 ++ d[v] += size ++ ++ def deal_with_file(fpath, need_prefix=True): ++ size = os.path.getsize(fpath) ++ if fpath in pfr['norm']: ++ data['pkgs_count'] += size ++ _add_size(data['pkgs_size'], pfr['norm'][fpath], size) ++ elif fpath in pfr['ghost']: ++ data['pkgs_ghost_count'] += size ++ _add_size(data['pkgs_ghost_size'], pfr['ghost'][fpath], size) ++ elif fpath in pfr['not']: ++ data['pkgs_not_count'] += size ++ _add_size(data['pkgs_not_size'], pfr['not'][fpath], size) ++ data['data_not_size'][fpath] = size ++ elif fpath in pfr['miss']: ++ data['pkgs_miss_count'] += size ++ _add_size(data['pkgs_miss_size'], pfr['miss'][fpath], size) ++ elif fpath in pfr['mod']: ++ data['pkgs_mod_count'] += size ++ _add_size(data['pkgs_mod_size'], pfr['mod'][fpath], size) ++ elif need_prefix and False: ++ for fpre_path in _dir_prefixes(fpath): ++ if fpre_path not in pkg_files: ++ continue ++ _add_size(data['pres_size'], pkg_files[fpre_path], size) ++ break ++ data['data_count'] += size ++ data['data_size'][fpath] = size ++ else: ++ data['data_count'] += size ++ data['data_size'][fpath] = size ++ ++ prefix = "." ++ if extcmds: ++ prefix = extcmds[0] ++ extcmds = extcmds[1:] ++ ++ if not os.path.exists(prefix): ++ return 1, [_('No such file or directory: ' + prefix)] ++ ++ max_show_len = 4 ++ if extcmds: ++ try: ++ max_show_len = int(extcmds[0]) ++ except: ++ pass ++ ++ verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3) ++ ++ pfr = self._fs_pkg_walk(base.rpmdb, prefix, verbose=verbose) ++ ++ base.closeRpmDB() # C-c ftw. ++ ++ num = 0 ++ if os.path.isfile(prefix): ++ num += 1 ++ deal_with_file(prefix) ++ ++ for root, dirs, files in os.walk(prefix): ++ for fname in files: ++ num += 1 ++ fpath = os.path.normpath(root + '/' + fname) ++ if os.path.islink(fpath): ++ continue ++ ++ deal_with_file(fpath, need_prefix=verbose) ++ ++ # output ++ print "Files :", loc_num(num) ++ tot = 0 ++ tot += data['pkgs_count'] ++ tot += data['pkgs_ghost_count'] ++ tot += data['pkgs_not_count'] ++ tot += data['pkgs_miss_count'] ++ tot += data['pkgs_mod_count'] ++ tot += data['data_count'] ++ print "Total size :", base.format_number(tot) ++ if not tot: ++ return ++ ++ num = data['pkgs_count'] ++ if not verbose: ++ num += data['pkgs_ghost_count'] ++ num += data['pkgs_miss_count'] ++ num += data['pkgs_mod_count'] ++ print " Pkgs size :", "%-5s" % base.format_number(num), ++ print "(%3.0f%%)" % ((num * 100.0) / tot) ++ if verbose: ++ for (title, num) in ((_(" Ghost pkgs size :"), ++ data['pkgs_ghost_count']), ++ (_(" Not pkgs size :"), ++ data['pkgs_not_count']), ++ (_(" Miss pkgs size :"), ++ data['pkgs_miss_count']), ++ (_(" Mod. pkgs size :"), ++ data['pkgs_mod_count'])): ++ if not num: ++ continue ++ print title, "%-5s" % base.format_number(num), ++ print "(%3.0f%%)" % ((num * 100.0) / tot) ++ num = data['data_count'] ++ if not verbose: ++ num += data['pkgs_not_count'] ++ print _(" Data size :"), "%-5s" % base.format_number(num), ++ print "(%3.0f%%)" % ((num * 100.0) / tot) ++ if verbose: ++ print '' ++ print _("Pkgs :"), loc_num(len(data['pkgs_size'])) ++ print _("Ghost Pkgs :"), loc_num(len(data['pkgs_ghost_size'])) ++ print _("Not Pkgs :"), loc_num(len(data['pkgs_not_size'])) ++ print _("Miss. Pkgs :"), loc_num(len(data['pkgs_miss_size'])) ++ print _("Mod. Pkgs :"), loc_num(len(data['pkgs_mod_size'])) ++ ++ def _pkgs(p_size, msg): ++ tot = min(max_show_len, len(p_size)) ++ if tot: ++ print '' ++ print msg % tot ++ num = 0 ++ for pkg in sorted(p_size, key=lambda x: p_size[x], reverse=True): ++ num += 1 ++ print _("%*d. %60s %-5s") % (len(str(tot)), num, pkg, ++ base.format_number(p_size[pkg])) ++ if num >= tot: ++ break ++ ++ if verbose: ++ _pkgs(data['pkgs_size'], _('Top %d packages:')) ++ _pkgs(data['pkgs_ghost_size'], _('Top %d ghost packages:')) ++ _pkgs(data['pkgs_not_size'], _('Top %d not. packages:')) ++ _pkgs(data['pkgs_miss_size'], _('Top %d miss packages:')) ++ _pkgs(data['pkgs_mod_size'], _('Top %d mod. packages:')) ++ _pkgs(data['pres_size'], _('Top %d prefix packages:')) ++ else: ++ tmp = {} ++ tmp.update(data['pkgs_size']) ++ for d in data['pkgs_ghost_size']: ++ _add_size(tmp, d, data['pkgs_ghost_size'][d]) ++ for d in data['pkgs_miss_size']: ++ _add_size(tmp, d, data['pkgs_miss_size'][d]) ++ for d in data['pkgs_mod_size']: ++ _add_size(tmp, d, data['pkgs_mod_size'][d]) ++ _pkgs(tmp, _('Top %d packages:')) ++ ++ print '' ++ if verbose: ++ data_size = data['data_size'] ++ else: ++ data_size = {} ++ data_size.update(data['data_size']) ++ data_size.update(data['data_not_size']) ++ ++ tot = min(max_show_len, len(data_size)) ++ if tot: ++ print _('Top %d non-package files:') % tot ++ num = 0 ++ for fname in sorted(data_size, ++ key=lambda x: data_size[x], ++ reverse=True): ++ num += 1 ++ dsznum = data_size[fname] ++ print _("%*d. %60s %-5s") % (len(str(tot)), num, fname, ++ base.format_number(dsznum)) ++ if num >= tot: ++ break ++ ++ def _fs_filters(self, base, extcmds): ++ writeRawConfigFile = yum.config._writeRawConfigFile ++ ++ if not extcmds: ++ oil = base.conf.override_install_langs ++ if not oil: ++ oil = "rpm: " + rpm.expandMacro("%_install_langs") ++ print "File system filters:" ++ print " Nodocs:", 'nodocs' in base.conf.tsflags ++ print " Languages:", oil ++ elif extcmds[0] in ('docs', 'nodocs', ++ 'documentation', 'nodocumentation'): ++ c_f = 'nodocs' in base.conf.tsflags ++ n_f = extcmds[0].startswith('no') ++ if n_f == c_f: ++ return ++ ++ nts = base.conf.tsflags ++ if n_f: ++ nts = nts + ['nodocs'] ++ else: ++ nts = [x for x in nts if x != 'nodocs'] ++ base.conf.tsflags = " ".join(nts) ++ ++ fn = '/etc/yum/yum.conf' ++ if not os.path.exists(fn): ++ # Try the old default ++ fn = '/etc/yum.conf' ++ ybc = base.conf ++ writeRawConfigFile(fn, 'main', ybc.yumvar, ++ ybc.cfg.options, ybc.iteritems, ++ ybc.optionobj, ++ only=['tsflags']) ++ elif extcmds[0] in ('langs', 'nolangs', 'lang', 'nolang', ++ 'languages', 'nolanguages', ++ 'language', 'nolanguage'): ++ if extcmds[0].startswith('no') or len(extcmds) < 2 or 'all' in extcmds: ++ val = 'all' ++ else: ++ val = ":".join(extcmds[1:]) ++ ++ if val == base.conf.override_install_langs: ++ return ++ ++ base.conf.override_install_langs = val ++ ++ fn = '/etc/yum/yum.conf' ++ if not os.path.exists(fn): ++ # Try the old default ++ fn = '/etc/yum.conf' ++ ybc = base.conf ++ writeRawConfigFile(fn, 'main', ybc.yumvar, ++ ybc.cfg.options, ybc.iteritems, ++ ybc.optionobj, ++ only=['override_install_langs']) ++ else: ++ return 1, [_('Not a valid sub-command of fs filter')] ++ ++ def _fs_refilter(self, base, extcmds): ++ c_f = 'nodocs' in base.conf.tsflags ++ # FIXME: C&P from init. ++ oil = base.conf.override_install_langs ++ if not oil: ++ oil = rpm.expandMacro("%_install_langs") ++ if oil == 'all': ++ oil = '' ++ elif oil: ++ oil = ":".join(sorted(oil.split(':'))) ++ ++ found = False ++ num = 0 ++ for pkg in base.rpmdb.returnPackages(patterns=extcmds): ++ if False: pass ++ elif oil != pkg.yumdb_info.get('ts_install_langs', ''): ++ txmbrs = base.reinstall(po=pkg) ++ num += len(txmbrs) ++ elif c_f != ('true' == pkg.yumdb_info.get('tsflag_nodocs')): ++ txmbrs = base.reinstall(po=pkg) ++ num += len(txmbrs) ++ else: ++ found = True ++ ++ if num: ++ return 2,P_('%d package to reinstall','%d packages to reinstall', ++ num) ++ ++ if not found: ++ return 1, [_('No valid packages: %s') % " ".join(extcmds)] ++ ++ def _fs_refilter_cleanup(self, base, extcmds): ++ pkgs = base.rpmdb.returnPackages(patterns=extcmds) ++ ++ verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3) ++ ++ pfr = self._fs_pkg_walk(pkgs, "/", verbose=verbose, modified=True) ++ ++ base.closeRpmDB() # C-c ftw. ++ ++ for fname in sorted(pfr['not']): ++ print _('Removing:'), fname ++ misc.unlink_f(fname) ++ ++ def _fs_diff(self, base, extcmds): ++ pass ++ def _fs_status(self, base, extcmds): ++ pass ++ ++ def doCommand(self, base, basecmd, extcmds): ++ """Execute this command. ++ ++ :param base: a :class:`yum.Yumbase` object ++ :param basecmd: the name of the command ++ :param extcmds: the command line arguments passed to *basecmd* ++ :return: (exit_code, [ errors ]) ++ ++ 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 ++ """ ++ if extcmds and extcmds[0] in ('filters', 'filter', ++ 'refilter', 'refilter-cleanup', ++ 'du', 'status', 'diff'): ++ subcommand = extcmds[0] ++ extcmds = extcmds[1:] ++ else: ++ subcommand = 'filters' ++ ++ if False: pass ++ ++ elif subcommand == 'du': ++ ret = self._fs_du(base, extcmds) ++ ++ elif subcommand in ('filter', 'filters'): ++ ret = self._fs_filters(base, extcmds) ++ ++ elif subcommand == 'refilter': ++ ret = self._fs_refilter(base, extcmds) ++ ++ elif subcommand == 'refilter-cleanup': ++ ret = self._fs_refilter_cleanup(base, extcmds) ++ ++ elif False and subcommand == 'diff': ++ ret = self._fs_diff(base, extcmds) ++ ++ elif False and subcommand == 'status': ++ ret = self._fs_status(base, extcmds) ++ ++ else: ++ return 1, [_('Not a valid sub-command of %s') % basecmd] ++ ++ if ret is not None: ++ return ret ++ ++ return 0, [basecmd + ' ' + subcommand + ' done'] +commit 5dd124173de6c9ac1ce53b507f9aaa9cae6d030a +Author: James Antill +Date: Wed Feb 12 16:56:33 2014 -0500 + + Optimize pkg.verify() for "fs du" and "fs refilter". + +diff --git a/yum/packages.py b/yum/packages.py +index cc1f1e3..1b3061b 100644 +--- a/yum/packages.py ++++ b/yum/packages.py +@@ -1779,6 +1779,7 @@ class YUMVerifyPackage: + self._files = {} + + ++_last_fnmatch = {} + class _RPMVerifyPackage(YUMVerifyPackage): + def __init__(self, po, fi, def_csum_type, patterns, all): + YUMVerifyPackage.__init__(self, po) +@@ -1791,18 +1792,30 @@ class _RPMVerifyPackage(YUMVerifyPackage): + (fi, def_csum_type, patterns, all) = self._presetup + del self._presetup + ++ global _last_fnmatch ++ _this_fnmatch = {} + for ft in fi: + fn = ft[0] + if patterns: + matched = False + for p in patterns: +- if fnmatch.fnmatch(fn, p): ++ if p in _last_fnmatch: ++ match = _last_fnmatch[p] ++ elif p in _this_fnmatch: ++ match = _this_fnmatch[p] ++ else: ++ match = misc.compile_pattern(p) ++ _this_fnmatch[p] = match ++ ++ if match(fn): + matched = True + break + if not matched: + continue + + self.add(_RPMVerifyPackageFile(fi, ft, def_csum_type, all)) ++ if _this_fnmatch: ++ _last_fnmatch = _this_fnmatch + + def __contains__(self, *args, **kwargs): + self._setup() +@@ -1834,7 +1847,8 @@ class YumInstalledPackage(YumHeaderPackage): + self.yumdb_info = yumdb.get_package(self) + + def verify(self, patterns=[], deps=False, script=False, +- fake_problems=True, all=False, fast=False, callback=None): ++ fake_problems=True, all=False, fast=False, callback=None, ++ failfast=False): + """verify that the installed files match the packaged checksum + optionally verify they match only if they are in the 'pattern' list + returns a tuple """ +@@ -1973,6 +1987,8 @@ class YumInstalledPackage(YumHeaderPackage): + verify_digest = pf.verify_digest + if fast and not problems and (my_st_size == pf.size): + verify_digest = False ++ if failfast and problems: ++ verify_digest = False + if not pf.digest: + verify_digest = False + +diff --git a/yumcommands.py b/yumcommands.py +index 03450c4..c5abfba 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -4374,7 +4374,7 @@ class FSCommand(YumCommand): + for pkg in pkgs: + _pfs = [] + probs = pkg.verify(patterns=[prefix+'*'], fake_problems=False, +- callback=scoop_pfs) ++ callback=scoop_pfs, failfast=True) + + for pf in _pfs[0]: + if pf.filename in probs: +commit 6e4a68cf40283f3a110c049d5e81db886ef593e1 +Author: James Antill +Date: Wed Feb 12 17:56:42 2014 -0500 + + Add the fs status/diff commands. + +diff --git a/docs/yum.8 b/docs/yum.8 +index 31c1c88..6794581 100644 +--- a/docs/yum.8 ++++ b/docs/yum.8 +@@ -742,12 +742,19 @@ mainly for removing languages/documentation for minimal installs: + .br + .I \fR yum fs du [path] + ++.br ++.I \fR yum fs status [path] ++ ++.br ++.I \fR yum fs diff [path] ++ ++ + the first 3 being a simple interface to change yum.conf altering the tsflags + and override_install_langs configurations. The refilter command is an optimized + way of calling "yum reinstall" to reinstall the packages with the new filters + applied. The refilter-cleanup command is needed because rpm doesn't actually +-remove the files on reinstall, as it should. And the du command is included so +-you can easily see the space used/saved. ++remove the files on reinstall, as it should. And the du/status/diff commands are ++included so you can easily see the space used/saved and any other changes. + + .IP + .IP "\fBcheck\fP" +diff --git a/yumcommands.py b/yumcommands.py +index c5abfba..b4e172c 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -21,6 +21,7 @@ Classes for subcommands of the yum command line interface. + """ + + import os ++import sys + import cli + from yum import logginglevels + from yum import _, P_ +@@ -4692,9 +4693,112 @@ class FSCommand(YumCommand): + misc.unlink_f(fname) + + def _fs_diff(self, base, extcmds): +- pass ++ def deal_with_file(fpath): ++ if fpath in pfr['norm']: ++ pass ++ elif fpath in pfr['ghost']: ++ pass ++ elif fpath in pfr['not']: ++ print >>sys.stderr, _('Not installed:'), fpath ++ elif fpath in pfr['miss']: ++ pass ++ elif fpath in pfr['mod']: ++ pkg = apkgs[pfr['mod'][fpath].pkgtup] ++ # Hacky ... but works. ++ sys.stdout.flush() ++ extract_cmd = "cd %s; rpm2cpio %s | cpio --quiet -id .%s" ++ extract_cmd = extract_cmd % (tmpdir, pkg.localPkg(), fpath) ++ os.system(extract_cmd) ++ diff_cmd = "diff -ru %s %s" % (tmpdir + fpath, fpath) ++ print diff_cmd ++ sys.stdout.flush() ++ os.system(diff_cmd) ++ else: ++ print >>sys.stderr, _('Not packaged?:'), fpath ++ ++ prefix = "." ++ if extcmds: ++ prefix = extcmds[0] ++ extcmds = extcmds[1:] ++ ++ pkgs = base.rpmdb.returnPackages(patterns=extcmds) ++ ++ verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3) ++ ++ pfr = self._fs_pkg_walk(pkgs, prefix, verbose=verbose, modified=True) ++ ++ base.closeRpmDB() # C-c ftw. ++ ++ apkgs = {} ++ downloadpkgs = [] ++ for ipkg in set(pfr['mod'].values()): ++ for apkg in base.pkgSack.searchPkgTuple(ipkg.pkgtup): ++ iyi = ipkg.yumdb_info ++ if ('checksum_type' in iyi and ++ 'checksum_data' in iyi and ++ iyi.checksum_type == apkg.checksum_type and ++ iyi.checksum_data == apkg.pkgId): ++ apkgs[ipkg.pkgtup] = apkg ++ downloadpkgs.append(apkg) ++ break ++ if ipkg.pkgtup not in apkgs: ++ raise yum.Errors.YumBaseError, _("Can't find package: %s") %ipkg ++ ++ if downloadpkgs: ++ tmpdir = tempfile.mkdtemp() ++ problems = base.downloadPkgs(downloadpkgs, callback_total=base.download_callback_total_cb) ++ if len(problems) > 0: ++ errstring = '' ++ errstring += _('Error downloading packages:\n') ++ for key in problems: ++ errors = yum.misc.unique(problems[key]) ++ for error in errors: ++ errstring += ' %s: %s\n' % (key, error) ++ raise yum.Errors.YumBaseError, errstring ++ ++ for root, dirs, files in os.walk(prefix): ++ for fname in files: ++ fpath = os.path.normpath(root + '/' + fname) ++ if os.path.islink(fpath): ++ continue ++ ++ deal_with_file(fpath) ++ + def _fs_status(self, base, extcmds): +- pass ++ def deal_with_file(fpath): ++ if fpath in pfr['norm']: ++ pass ++ elif fpath in pfr['ghost']: ++ pass ++ elif fpath in pfr['not']: ++ print _('Not installed:'), fpath ++ elif fpath in pfr['miss']: ++ pass ++ elif fpath in pfr['mod']: ++ print _('Modified:'), fpath ++ else: ++ print _('Not packaged?:'), fpath ++ ++ prefix = "." ++ if extcmds: ++ prefix = extcmds[0] ++ extcmds = extcmds[1:] ++ ++ pkgs = base.rpmdb.returnPackages(patterns=extcmds) ++ ++ verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3) ++ ++ pfr = self._fs_pkg_walk(pkgs, prefix, verbose=verbose, modified=True) ++ ++ base.closeRpmDB() # C-c ftw. ++ ++ for root, dirs, files in os.walk(prefix): ++ for fname in files: ++ fpath = os.path.normpath(root + '/' + fname) ++ if os.path.islink(fpath): ++ continue ++ ++ deal_with_file(fpath) + + def doCommand(self, base, basecmd, extcmds): + """Execute this command. +@@ -4732,10 +4836,10 @@ class FSCommand(YumCommand): + elif subcommand == 'refilter-cleanup': + ret = self._fs_refilter_cleanup(base, extcmds) + +- elif False and subcommand == 'diff': ++ elif subcommand == 'diff': + ret = self._fs_diff(base, extcmds) + +- elif False and subcommand == 'status': ++ elif subcommand == 'status': + ret = self._fs_status(base, extcmds) + + else: +commit df42263f375b032b73d9732a8b051e57a35973ab +Author: James Antill +Date: Wed Feb 12 18:17:31 2014 -0500 + + Move exactarchlist_default to ditro. variable. + +diff --git a/yum/config.py b/yum/config.py +index f213fc1..69f8e2e 100644 +--- a/yum/config.py ++++ b/yum/config.py +@@ -50,6 +50,10 @@ __main_multilib_policy_default__ = 'all' + __main_failovermethod_default__ = 'roundrobin' + __main_installonly_limit_default__ = 0 + __group_command_default__ = 'compat' ++__exactarchlist_default__ = ['kernel', 'kernel-smp', ++ 'kernel-hugemem', 'kernel-enterprise', ++ 'kernel-bigmem', ++ 'kernel-devel', 'kernel-PAE', 'kernel-PAE-debug'] + + class Option(object): + """ +@@ -764,9 +768,7 @@ class YumConf(StartupConf): + names_of_0=["0", ""]) + kernelpkgnames = ListOption(['kernel','kernel-smp', 'kernel-enterprise', + 'kernel-bigmem', 'kernel-BOOT', 'kernel-PAE', 'kernel-PAE-debug']) +- exactarchlist = ListOption(['kernel', 'kernel-smp', +- 'kernel-hugemem', 'kernel-enterprise', 'kernel-bigmem', +- 'kernel-devel', 'kernel-PAE', 'kernel-PAE-debug']) ++ exactarchlist = ListOption(__exactarchlist_default__) + tsflags = ListOption() + override_install_langs = Option() + +commit 7e890388473519d8374e228783150f4e11dff3e0 +Author: James Antill +Date: Wed Feb 12 18:59:42 2014 -0500 + + Add override_install_langs to test.FakeConf. + +diff --git a/test/testbase.py b/test/testbase.py +index 9d331c6..e2a1d05 100644 +--- a/test/testbase.py ++++ b/test/testbase.py +@@ -66,6 +66,7 @@ class FakeConf(object): + self.reposdir = '/tmp/XXXX' + self.diskspacecheck = True + self.depsolve_loop_limit = 10 ++ self.override_install_langs = '' + + class FakeSack: + """ Fake PackageSack to use with FakeRepository""" +commit 57e62d0ab105727689a2cbc690ff5d62137be676 +Author: James Antill +Date: Fri Feb 14 14:58:31 2014 -0500 + + Auto-enable repos. that contain packages we need in fs diff. + +diff --git a/yumcommands.py b/yumcommands.py +index b4e172c..475d982 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -4732,8 +4732,14 @@ class FSCommand(YumCommand): + apkgs = {} + downloadpkgs = [] + for ipkg in set(pfr['mod'].values()): ++ iyi = ipkg.yumdb_info ++ if 'from_repo' in iyi: # Updates-testing etc. ++ if iyi.from_repo in base.repos.repos: ++ repo = base.repos.getRepo(iyi.from_repo) ++ if not repo.isEnabled(): ++ base.repos.enableRepo(repo.id) ++ + for apkg in base.pkgSack.searchPkgTuple(ipkg.pkgtup): +- iyi = ipkg.yumdb_info + if ('checksum_type' in iyi and + 'checksum_data' in iyi and + iyi.checksum_type == apkg.checksum_type and +commit 81b9dc2fc39ed6960f061cdc1c84f37aada0fd0a +Author: James Antill +Date: Fri Feb 14 15:02:58 2014 -0500 + + Cleanup tmpdir for fs diff. + +diff --git a/yumcommands.py b/yumcommands.py +index 475d982..c93faa1 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -33,6 +33,7 @@ import fnmatch + import time + from yum.i18n import utf8_width, utf8_width_fill, to_unicode, exception2msg + import tempfile ++import shutil + import glob + + import yum.config +@@ -4770,6 +4771,9 @@ class FSCommand(YumCommand): + + deal_with_file(fpath) + ++ if downloadpkgs: ++ shutil.rmtree(tmpdir) ++ + def _fs_status(self, base, extcmds): + def deal_with_file(fpath): + if fpath in pfr['norm']: +commit f932ddc40d8452c1a7d46d7c7fd8eb90b6f5cac2 +Author: James Antill +Date: Fri Feb 21 16:15:01 2014 -0500 + + Add spec requires for fs sub-command. + +diff --git a/yum.spec b/yum.spec +index 93cfa14..854baf3 100644 +--- a/yum.spec ++++ b/yum.spec +@@ -98,6 +98,9 @@ Requires: pygpgme + Requires: pyliblzma + # Not really a suggests anymore, due to metadata using it. + Requires: pyxattr ++# Suggests, needed for yum fs diff ++Requires: diffutils ++Requires: cpio + + Conflicts: rpm >= 5-0 + # Zif is a re-implementation of yum in C, however: +commit 00aec000813db1b45a7b38e1aa396b1bb8764eb7 +Author: James Antill +Date: Fri Feb 21 16:19:28 2014 -0500 + + Copy packages in/out of an installroot, for no downloads creating containers. + +diff --git a/yum/__init__.py b/yum/__init__.py +index 37ab468..dc468cb 100644 +--- a/yum/__init__.py ++++ b/yum/__init__.py +@@ -45,6 +45,7 @@ import logging + import logging.config + import operator + import tempfile ++import shutil + + import yum.i18n + # This is required to make gaftonmode work... +@@ -689,6 +690,12 @@ class YumBase(depsolve.Depsolve): + if hasattr(self, 'prerepoconf'): + self.conf # touch the config class first + ++ if (self.conf.installroot != '/' and ++ not hasattr(self, '_old_cachedir')): ++ # Try loading cache from outside... ++ ir = len(self.conf.installroot) ++ self._old_cachedir = self.conf.cachedir[ir:] ++ + self.getReposFromConfig() + + # For rhnplugin, and in theory other stuff, calling +@@ -2398,6 +2405,9 @@ much more problems). + self.verbose_logger.warn(_("ignoring a dupe of %s") % po) + return True + beenthere.add(local) ++ if downloadonly and not os.path.exists(local): ++ # Check before we munge the name... ++ po.repo._preload_pkg_from_system_cache(po) + if os.path.exists(local): + if self.verifyPkg(local, po, False): + self.verbose_logger.debug(_("using local copy of %s") % po) +@@ -2442,6 +2452,22 @@ much more problems). + format_number(rpmsize), format_number(deltasize), 100 - deltasize*100.0/rpmsize) + + if downloadonly: ++ if hasattr(self, '_old_cachedir'): ++ # Try to link/copy them out, if we have somewhere to put them. ++ ++ for po in pkglist: ++ if not po.localpath.startswith(self.conf.cachedir): ++ continue ++ ++ end = po.localpath[len(self.conf.cachedir):] ++ try: ++ os.link(po.localpath, self._old_cachedir + end) ++ except: ++ try: ++ shutil.copy2(po.localpath, self._old_cachedir + end) ++ except: ++ pass ++ + # close DBs, unlock + self.repos.close() + self.closeRpmDB() +commit fcec4d88fa18c30e1aeabf724bec11dcfb1e2655 +Author: James Antill +Date: Fri Feb 21 16:16:23 2014 -0500 + + A few cleanups for the fs sub-command: + + . Add checks for diff/cpio/rpm2cpio. + . Add missing import for rpm, when override_install_langs isn't set. + . Allow users to run some of the commands. + . Map fs snap to fssnap command. + . Add translations and add messages when you alter the filters. + . Save config. file inside the chroot. + +diff --git a/yumcommands.py b/yumcommands.py +index 52b8c90..4385a34 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -23,6 +23,7 @@ Classes for subcommands of the yum command line interface. + import os + import sys + import cli ++import rpm + from yum import logginglevels + from yum import _, P_ + from yum import misc +@@ -34,6 +35,7 @@ import time + from yum.i18n import utf8_width, utf8_width_fill, to_unicode, exception2msg + import tempfile + import shutil ++import distutils.spawn + import glob + + import yum.config +@@ -4334,6 +4336,14 @@ class FSCommand(YumCommand): + :param basecmd: the name of the command + :param extcmds: the command line arguments passed to *basecmd* + """ ++ if extcmds and extcmds[0] in ('du', 'status', 'diff'): ++ # Anyone can go for it... ++ return ++ ++ if len(extcmds) == 1 and extcmds[0] in ('filters', 'filter'): ++ # Can look, but not touch. ++ return ++ + checkRootUID(base) + + def _fs_pkg_walk(self, pkgs, prefix, modified=False, verbose=False): +@@ -4611,22 +4621,48 @@ class FSCommand(YumCommand): + break + + def _fs_filters(self, base, extcmds): +- writeRawConfigFile = yum.config._writeRawConfigFile ++ def _save(confkey): ++ writeRawConfigFile = yum.config._writeRawConfigFile ++ ++ # Always create installroot, so we can change it. ++ if not os.path.exists(base.conf.installroot + '/etc/yum'): ++ os.makedirs(base.conf.installroot + '/etc/yum') ++ ++ fn = base.conf.installroot+'/etc/yum/yum.conf' ++ if not os.path.exists(fn): ++ # Try the old default ++ nfn = base.conf.installroot+'/etc/yum.conf' ++ if not os.path.exists(nfn): ++ shutil.copy2(base.conf.config_file_path, fn) ++ ybc = base.conf ++ writeRawConfigFile(fn, 'main', ybc.yumvar, ++ ybc.cfg.options, ybc.iteritems, ++ ybc.optionobj, ++ only=[confkey]) + + if not extcmds: + oil = base.conf.override_install_langs + if not oil: + oil = "rpm: " + rpm.expandMacro("%_install_langs") +- print "File system filters:" +- print " Nodocs:", 'nodocs' in base.conf.tsflags +- print " Languages:", oil ++ print _("File system filters:") ++ print _(" Nodocs:"), 'nodocs' in base.conf.tsflags ++ print _(" Languages:"), oil + elif extcmds[0] in ('docs', 'nodocs', + 'documentation', 'nodocumentation'): + c_f = 'nodocs' in base.conf.tsflags +- n_f = extcmds[0].startswith('no') ++ n_f = not extcmds[0].startswith('no') + if n_f == c_f: ++ if n_f: ++ print _("Already enabled documentation filter.") ++ else: ++ print _("Already disabled documentation filter.") + return + ++ if n_f: ++ print _("Enabling documentation filter.") ++ else: ++ print _("Disabling documentation filter.") ++ + nts = base.conf.tsflags + if n_f: + nts = nts + ['nodocs'] +@@ -4634,15 +4670,8 @@ class FSCommand(YumCommand): + nts = [x for x in nts if x != 'nodocs'] + base.conf.tsflags = " ".join(nts) + +- fn = '/etc/yum/yum.conf' +- if not os.path.exists(fn): +- # Try the old default +- fn = '/etc/yum.conf' +- ybc = base.conf +- writeRawConfigFile(fn, 'main', ybc.yumvar, +- ybc.cfg.options, ybc.iteritems, +- ybc.optionobj, +- only=['tsflags']) ++ _save('tsflags') ++ + elif extcmds[0] in ('langs', 'nolangs', 'lang', 'nolang', + 'languages', 'nolanguages', + 'language', 'nolanguage'): +@@ -4652,19 +4681,21 @@ class FSCommand(YumCommand): + val = ":".join(extcmds[1:]) + + if val == base.conf.override_install_langs: ++ if val: ++ print _("Already filtering languages to: %s") % val ++ else: ++ print _("Already disabled language filter.") + return + ++ if val: ++ print _("Setting language filter to: %s") % val ++ else: ++ print _("Disabling language filter.") ++ + base.conf.override_install_langs = val + +- fn = '/etc/yum/yum.conf' +- if not os.path.exists(fn): +- # Try the old default +- fn = '/etc/yum.conf' +- ybc = base.conf +- writeRawConfigFile(fn, 'main', ybc.yumvar, +- ybc.cfg.options, ybc.iteritems, +- ybc.optionobj, +- only=['override_install_langs']) ++ _save('override_install_langs') ++ + else: + return 1, [_('Not a valid sub-command of fs filter')] + +@@ -4736,6 +4767,14 @@ class FSCommand(YumCommand): + else: + print >>sys.stderr, _('Not packaged?:'), fpath + ++ if not distutils.spawn.find_executable("diff"): ++ raise yum.Errors.YumBaseError, _("Can't find diff command") ++ # These just shouldn't happen... ++ if not distutils.spawn.find_executable("cpio"): ++ raise yum.Errors.YumBaseError, _("Can't find cpio command") ++ if not distutils.spawn.find_executable("rpm2cpio"): ++ raise yum.Errors.YumBaseError, _("Can't find rpm2cpio command") ++ + prefix = "." + if extcmds: + prefix = extcmds[0] +@@ -4845,7 +4884,7 @@ class FSCommand(YumCommand): + """ + if extcmds and extcmds[0] in ('filters', 'filter', + 'refilter', 'refilter-cleanup', +- 'du', 'status', 'diff'): ++ 'du', 'status', 'diff', 'snap'): + subcommand = extcmds[0] + extcmds = extcmds[1:] + else: +@@ -4871,6 +4910,9 @@ class FSCommand(YumCommand): + elif subcommand == 'status': + ret = self._fs_status(base, extcmds) + ++ elif subcommand == 'snap': ++ ret = FSSnapshotCommand().doCommand(base, 'fs snap', args) ++ + else: + return 1, [_('Not a valid sub-command of %s') % basecmd] + +commit 77c85efcb09f0121d6a611d92e1fc6a237179656 +Author: James Antill +Date: Sun Feb 23 20:57:06 2014 -0500 + + Choose yum.conf correctly for fs filter saving. + +diff --git a/yumcommands.py b/yumcommands.py +index 4385a34..ef84c1f 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -4632,7 +4632,9 @@ class FSCommand(YumCommand): + if not os.path.exists(fn): + # Try the old default + nfn = base.conf.installroot+'/etc/yum.conf' +- if not os.path.exists(nfn): ++ if os.path.exists(nfn): ++ fn = nfn ++ else: + shutil.copy2(base.conf.config_file_path, fn) + ybc = base.conf + writeRawConfigFile(fn, 'main', ybc.yumvar, +commit 02a2d73afe6ea19ae17cbab2192c1d7e12be5ec2 +Author: James Antill +Date: Mon Mar 24 16:17:19 2014 -0400 + + No error for refilter cleanup, rm dirs. and eat all errors. BZ 1062959. + +diff --git a/yumcommands.py b/yumcommands.py +index 75b3ce2..c76e192 100644 +--- a/yumcommands.py ++++ b/yumcommands.py +@@ -37,6 +37,7 @@ import tempfile + import shutil + import distutils.spawn + import glob ++import errno + + import yum.config + from yum import updateinfo +@@ -4742,7 +4743,16 @@ class FSCommand(YumCommand): + + for fname in sorted(pfr['not']): + print _('Removing:'), fname +- misc.unlink_f(fname) ++ try: # Ignore everything, unlink_f() doesn't. ++ os.unlink(fname) ++ except OSError, e: ++ if e.errno == errno.EISDIR: ++ try: ++ os.rmdir(fname) ++ except: ++ pass ++ except: ++ pass + + def _fs_diff(self, base, extcmds): + def deal_with_file(fpath): diff --git a/SOURCES/no-more-exactarchlist.patch b/SOURCES/no-more-exactarchlist.patch deleted file mode 100644 index 23572c6..0000000 --- a/SOURCES/no-more-exactarchlist.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- yum/config.py~ 2009-07-22 12:47:52.000000000 -0400 -+++ yum/config.py 2009-07-22 12:48:39.000000000 -0400 -@@ -631,9 +631,7 @@ - names_of_0=["0", ""]) - kernelpkgnames = ListOption(['kernel','kernel-smp', 'kernel-enterprise', - 'kernel-bigmem', 'kernel-BOOT', 'kernel-PAE', 'kernel-PAE-debug']) -- exactarchlist = ListOption(['kernel', 'kernel-smp', -- 'kernel-hugemem', 'kernel-enterprise', 'kernel-bigmem', -- 'kernel-devel', 'kernel-PAE', 'kernel-PAE-debug']) -+ exactarchlist = ListOption([]) - tsflags = ListOption() - - assumeyes = BoolOption(False) diff --git a/SOURCES/yum-distro-configs.patch b/SOURCES/yum-distro-configs.patch index 5abeece..f014c7d 100644 --- a/SOURCES/yum-distro-configs.patch +++ b/SOURCES/yum-distro-configs.patch @@ -1,7 +1,7 @@ diff -ru yum-3.4.3-orig/yum/config.py yum-3.4.3/yum/config.py --- yum-3.4.3-orig/yum/config.py 2011-12-02 15:45:41.617448597 -0500 +++ yum-3.4.3/yum/config.py 2011-12-02 15:46:20.576285275 -0500 -@@ -45,10 +45,10 @@ +@@ -49,14 +49,11 @@ # Alter/patch these to change the default checking... __pkgs_gpgcheck_default__ = False __repo_gpgcheck_default__ = False @@ -9,14 +9,18 @@ diff -ru yum-3.4.3-orig/yum/config.py yum-3.4.3/yum/config.py -__main_failovermethod_default__ = 'roundrobin' -__main_installonly_limit_default__ = 0 -__group_command_default__ = 'compat' +-__exactarchlist_default__ = ['kernel', 'kernel-smp', +- 'kernel-hugemem', 'kernel-enterprise', +- 'kernel-bigmem', +- 'kernel-devel', 'kernel-PAE', 'kernel-PAE-debug'] +__main_multilib_policy_default__ = 'best' +__main_failovermethod_default__ = 'priority' +__main_installonly_limit_default__ = 3 +__group_command_default__ = 'objects' ++__exactarchlist_default__ = [] class Option(object): """ -Only in yum-3.4.3/yum: config.py~ --- a/docs/yum.conf.5.orig 2010-06-21 17:39:17.000000000 -0400 +++ b/docs/yum.conf.5 2010-09-14 12:11:40.897615896 -0400 @@ -141,7 +141,7 @@ @@ -28,3 +32,12 @@ Only in yum-3.4.3/yum: config.py~ functionality used to be in the "installonlyn" plugin, where this option was altered via tokeep. Note that as of version 3.2.24, yum will now look in the yumdb for a installonly +@@ -267,7 +267,7 @@ group, and won't remove those on "group remove". + Running "yum upgrade" will also run "yum group upgrade" (thus. adding new + packages for all groups). + +-Default is: compat ++Default is: objects + + .IP + \fBupgrade_group_objects_upgrade\fR diff --git a/SPECS/yum.spec b/SPECS/yum.spec index 00d171d..a345edb 100644 --- a/SPECS/yum.spec +++ b/SPECS/yum.spec @@ -14,11 +14,6 @@ BuildRequires: bash-completion %endif -%if 0%{?fedora} <= 18 -# yum in Fedora <= 18 doesn't use systemd unit files... -%define yum_cron_systemd 0 -%endif - %if %{auto_sitelib} %{!?python_sitelib: %define python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} @@ -41,14 +36,13 @@ BuildRequires: bash-completion Summary: RPM package installer/updater/manager Name: yum Version: 3.4.3 -Release: 106.2%{?dist} +Release: 117%{?dist} License: GPLv2+ Group: System Environment/Base Source0: http://yum.baseurl.org/download/3.4/%{name}-%{version}.tar.gz Source1: yum.conf.fedora Source2: yum-updatesd.conf.fedora Patch1: yum-distro-configs.patch -Patch4: no-more-exactarchlist.patch Patch5: geode-arch.patch Patch6: yum-HEAD.patch Patch7: yum-ppc64-preferred.patch @@ -58,6 +52,16 @@ Patch21: yum-completion-helper.patch # rhel-7.0 Patch30: BZ-801067-remove-kernel-modules-from-installonly.patch patch31: BZ-1002977-use-the-provide-version.patch +patch32: BZ-1033416-yum-error-on-non-us-locale.patch +patch33: BZ-1050902-manpage-formatting-errrors.patch +patch34: BZ-1052994-yum-cron-install-unsigned-packages.patch +patch35: BZ-1041395-depsolve-loop-limit.patch +patch36: BZ-1053289-misc-perf+UI+simple-bug+docs-fixes.patch +patch37: BZ-1052436-group-bundle-pre-f20-fixes.patch +patch38: BZ-1040619-yum-cron-reporting.patch +patch39: BZ-1062959-add-fs-command.patch +patch40: BZ-1052436-group-bundle-docs.patch +patch41: BZ-1058297-remove-del-for-weird-anaconda-C-NULL-exception.patch URL: http://yum.baseurl.org/ BuildArchitectures: noarch @@ -86,6 +90,10 @@ Requires: pygpgme Requires: pyliblzma # Not really a suggests anymore, due to metadata using it. Requires: pyxattr +# Suggests, needed for yum fs diff +Requires: diffutils +Requires: cpio + Conflicts: rpm >= 5-0 # Zif is a re-implementation of yum in C, however: @@ -176,17 +184,28 @@ Install this package if you want auto yum updates nightly via cron. %prep %setup -q -%patch4 -p0 %patch5 -p1 %patch6 -p1 %patch7 -p1 %patch20 -p1 %patch21 -p1 -%patch1 -p1 # rhel-7.0 %patch30 -p1 %patch31 -p1 +%patch32 -p1 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 -p1 + +# Do distro config. changes after everything else. +%patch1 -p1 %build make @@ -411,7 +430,59 @@ exit 0 %endif %changelog -* Wed Nov 21 2013 Zdenek Pavlas - 3.4.3-106.2 +* Tue Apr 8 2014 James Antill - 3.4.3-117 +- Remove del for weird anaconda C NULL exception. +- Resolves: rhbz#1058297 + +* Tue Mar 25 2014 James Antill - 3.4.3-116 +- Fix traceback on removing doc dirs. +- Resolves: rhbz#1062959 +- Tweak docs for groups info, showing yum remove results. +- Resolves: rhbz#833087 + +* Tue Mar 11 2014 James Antill - 3.4.3-115 +- Change docs for groups to make group_command=objects clearer. +- Resolves: rhbz#833087 + +* Sun Feb 23 2014 James Antill - 3.4.3-114 +- Fix /etc/yum.conf saving in fs filter. +- Resolves: rhbz#1062959 + +* Fri Feb 21 2014 James Antill - 3.4.3-113 +- Add fs sub-command and container creation fixes/optimizations. +- Resolves: rhbz#1062959 + +* Thu Jan 23 2014 Zdenek Pavlas - 3.4.3-112 +- Improve yum-cron messages and error handling. +- Resolves: rhbz#1040619 +- Enable yum_cron_systemd +- Resolves: rhbz#1040620 +- Update "yum check" description. +- Resolves: rhbz#1015000 + +* Mon Jan 20 2014 James Antill - 3.4.3-111 +- A few simple perf, UI, bug, and docs. fixes. +- Resolves: rhbz#1053289 +- A few group related bug fixes from pre-f20 testing. +- Resolves: rhbz#1052436 + +* Wed Jan 15 2014 Valentina Mukhamedzhanova - 3.4.3-110 +- yum-cron: fail when sigCheckPkg() returns 2 +- Resolves: bug#1052994 +- depsolve_loop_limit= should try forever + +* Fri Jan 10 2014 Valentina Mukhamedzhanova - 3.4.3-109 +- Fix quotes in the manpage +- Resolves: bug#1050902 + +* Wed Jan 8 2014 Valentina Mukhamedzhanova - 3.4.3-108 +- Replace optparse._ with ugettext +- Related: bug#1033416 + +* Fri Dec 27 2013 Daniel Mach - 3.4.3-107 +- Mass rebuild 2013-12-27 + +* Thu Nov 21 2013 Zdenek Pavlas - 3.4.3-106.2 - _getsysver(): compat behavior when both pkg name and provide match. - Related: bug#1002977