[yum: 1/2] update to latest HEAD Added group_command, and changed to groups as objects by default. Minor update
James Antill
james at fedoraproject.org
Fri Jan 20 21:20:18 UTC 2012
commit 91401a19c5d45bcc49e779424ec8beca17bff518
Author: James Antill <james at and.org>
Date: Fri Jan 20 16:19:12 2012 -0500
update to latest HEAD
Added group_command, and changed to groups as objects by default.
Minor updates.
yum-HEAD.patch | 2086 ++++++++++++++++++++++++++++++++++++++--------
yum-distro-configs.patch | 6 +-
yum.spec | 7 +-
3 files changed, 1758 insertions(+), 341 deletions(-)
---
diff --git a/yum-HEAD.patch b/yum-HEAD.patch
index cef02f3..eb1da45 100644
--- a/yum-HEAD.patch
+++ b/yum-HEAD.patch
@@ -12,7 +12,7 @@ index 911da19..85decd5 100644
.pydevproject
asthelper.completions
diff --git a/Makefile b/Makefile
-index 740b616..f73239b 100644
+index 740b616..e15a3f8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
@@ -21,7 +21,15 @@ index 740b616..f73239b 100644
PYFILES = $(wildcard *.py)
PYLINT_MODULES = *.py yum rpmUtils
PYLINT_IGNORE = oldUtils.py
-@@ -38,6 +38,25 @@ install:
+@@ -26,6 +26,7 @@ install:
+ for p in $(PYFILES) ; do \
+ install -m 644 $$p $(DESTDIR)/usr/share/yum-cli/$$p; \
+ done
++ chmod 755 $(DESTDIR)/usr/share/yum-cli/completion-helper.py
+ mv $(DESTDIR)/usr/share/yum-cli/yum-updatesd.py $(DESTDIR)/usr/share/yum-cli/yumupd.py
+ $(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)/usr/share/yum-cli', 1, '$(PYDIR)', 1)"
+
+@@ -38,6 +39,25 @@ install:
for d in $(SUBDIRS); do make PYTHON=$(PYTHON) DESTDIR=`cd $(DESTDIR); pwd` -C $$d install; [ $$? = 0 ] || exit 1; done
@@ -88,7 +96,7 @@ index 2f6154e..2e5a052 100644
diff --git a/cli.py b/cli.py
old mode 100644
new mode 100755
-index 6056d38..ac9522b
+index 6056d38..cd8effa
--- a/cli.py
+++ b/cli.py
@@ -25,7 +25,7 @@ import sys
@@ -348,7 +356,23 @@ index 6056d38..ac9522b
# If we are in quiet, and assumeyes isn't on we want to output
# at least the transaction list anyway.
self.logger.warn(lsts)
-@@ -491,7 +540,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -463,7 +512,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ rmpkgs = []
+ stuff_to_download = False
+ install_only = True
+- remove_only = True
+ for txmbr in self.tsInfo.getMembers():
+ if txmbr.ts_state not in ('i', 'u'):
+ install_only = False
+@@ -471,7 +519,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ if po:
+ rmpkgs.append(po)
+ else:
+- remove_only = False
+ stuff_to_download = True
+ po = txmbr.po
+ if po:
+@@ -491,7 +538,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
# confirm with user
if self._promptWanted():
@@ -357,7 +381,7 @@ index 6056d38..ac9522b
self.verbose_logger.info(_('Exiting on user Command'))
return -1
-@@ -609,12 +658,14 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -609,12 +656,14 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return resultobject.return_code
def gpgsigcheck(self, pkgs):
@@ -377,7 +401,7 @@ index 6056d38..ac9522b
for po in pkgs:
result, errmsg = self.sigCheckPkg(po)
-@@ -623,7 +674,8 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -623,7 +672,8 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
continue
elif result == 1:
@@ -387,7 +411,7 @@ index 6056d38..ac9522b
raise yum.Errors.YumBaseError, \
_('Refusing to automatically import keys when running ' \
'unattended.\nUse "-y" to override.')
-@@ -691,12 +743,62 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -691,12 +741,62 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
", ".join(matches))
self.verbose_logger.log(yum.logginglevels.INFO_2, msg)
@@ -455,7 +479,7 @@ index 6056d38..ac9522b
# get the list of available packages
# iterate over the user's list
# add packages to Transaction holding class if they match.
-@@ -710,11 +812,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -710,11 +810,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
for arg in userlist:
if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
os.path.exists(arg))):
@@ -470,7 +494,7 @@ index 6056d38..ac9522b
except yum.Errors.InstallError:
self.verbose_logger.log(yum.logginglevels.INFO_2,
_('No package %s%s%s available.'),
-@@ -723,6 +826,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -723,6 +824,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
self._maybeYouMeant(arg)
else:
done = True
@@ -478,7 +502,7 @@ index 6056d38..ac9522b
if len(self.tsInfo) > oldcount:
change = len(self.tsInfo) - oldcount
return 2, [P_('%d package to install', '%d packages to install', change) % change]
-@@ -732,9 +836,27 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -732,9 +834,27 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, [_('Nothing to do')]
def updatePkgs(self, userlist, quiet=0, update_to=False):
@@ -509,13 +533,13 @@ index 6056d38..ac9522b
# if there is no userlist, then do global update below
# this is probably 90% of the calls
# if there is a userlist then it's for updating pkgs, not obsoleting
-@@ -745,21 +867,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -745,21 +865,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
else:
# go through the userlist - look for items that are local rpms. If we find them
- # pass them off to localInstall() and then move on
+- localupdates = []
+ # pass them off to installLocal() and then move on
- localupdates = []
for item in userlist:
if (item.endswith('.rpm') and (yum.misc.re_remote_url(item) or
os.path.exists(item))):
@@ -540,7 +564,7 @@ index 6056d38..ac9522b
if len(self.tsInfo) > oldcount:
change = len(self.tsInfo) - oldcount
-@@ -770,9 +890,24 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -770,9 +887,24 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
# Note that we aren't in __init__ yet for a couple of reasons, but we
# probably will get there for 3.2.28.
def distroSyncPkgs(self, userlist):
@@ -568,7 +592,7 @@ index 6056d38..ac9522b
level = 'diff'
if userlist and userlist[0] in ('full', 'diff', 'different'):
-@@ -831,6 +966,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -831,6 +963,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
continue
nayi = napkg.yumdb_info
@@ -576,13 +600,14 @@ index 6056d38..ac9522b
for apkg in self.pkgSack.searchPkgTuple(napkg.pkgtup):
if ('checksum_type' in nayi and
'checksum_data' in nayi and
-@@ -866,9 +1002,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -866,10 +999,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, [_('No Packages marked for Distribution Synchronization')]
def erasePkgs(self, userlist):
- """take user commands and populate a transaction wrapper with packages
- to be erased/removed"""
-
+- oldcount = len(self.tsInfo)
+ """Take user commands and populate a transaction wrapper with
+ packages to be erased.
+
@@ -596,10 +621,10 @@ index 6056d38..ac9522b
+ 1 = we've errored, exit with error string
+ 2 = we've got work yet to do, onto the next stage
+ """
- oldcount = len(self.tsInfo)
all_rms = []
-@@ -884,9 +1030,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+ for arg in userlist:
+@@ -884,9 +1026,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, [_('No Packages marked for removal')]
def downgradePkgs(self, userlist):
@@ -623,7 +648,7 @@ index 6056d38..ac9522b
oldcount = len(self.tsInfo)
-@@ -911,20 +1068,32 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -911,20 +1064,32 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, [_('Nothing to do')]
def reinstallPkgs(self, userlist):
@@ -660,7 +685,7 @@ index 6056d38..ac9522b
except yum.Errors.ReinstallRemoveError:
self._checkMaybeYouMeant(arg, always_output=False)
except yum.Errors.ReinstallInstallError, e:
-@@ -940,15 +1109,27 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -940,15 +1105,27 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
except yum.Errors.ReinstallError, e:
assert False, "Shouldn't happen, but just in case"
self.verbose_logger.log(yum.logginglevels.INFO_2, e)
@@ -691,7 +716,7 @@ index 6056d38..ac9522b
# read in each package into a YumLocalPackage Object
# append it to self.localPackages
# check if it can be installed or updated based on nevra versus rpmdb
-@@ -972,20 +1153,25 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -972,20 +1149,25 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, [_('Nothing to do')]
def returnPkgLists(self, extcmds, installed_available=False):
@@ -731,7 +756,7 @@ index 6056d38..ac9522b
special = ['available', 'installed', 'all', 'extras', 'updates', 'recent',
'obsoletes']
-@@ -1017,8 +1203,25 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1017,8 +1199,25 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return ypl
def search(self, args):
@@ -759,7 +784,7 @@ index 6056d38..ac9522b
# call the yum module search function with lists of tags to search
# and what to search for
-@@ -1108,9 +1311,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1108,9 +1307,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, matching
def deplist(self, args):
@@ -782,7 +807,7 @@ index 6056d38..ac9522b
pkgs = []
for arg in args:
if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
-@@ -1131,10 +1345,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1131,10 +1341,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, []
def provides(self, args):
@@ -806,7 +831,7 @@ index 6056d38..ac9522b
old_sdup = self.conf.showdupesfromrepos
# For output, as searchPackageProvides() is always in showdups mode
self.conf.showdupesfromrepos = True
-@@ -1163,20 +1386,68 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1163,20 +1382,68 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, []
def resolveDepCli(self, args):
@@ -880,7 +905,7 @@ index 6056d38..ac9522b
hdrcode = pkgcode = xmlcode = dbcode = expccode = 0
pkgresults = hdrresults = xmlresults = dbresults = expcresults = []
msg = self.fmtKeyValFill(_('Cleaning repos: '),
-@@ -1228,7 +1499,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1228,7 +1495,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return code, []
def returnGroupLists(self, userlist):
@@ -900,7 +925,7 @@ index 6056d38..ac9522b
uservisible=1
if len(userlist) > 0:
-@@ -1254,7 +1537,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1254,7 +1533,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
msg += ' (%s)' % group.groupid
if group.langonly:
msg += ' [%s]' % group.langonly
@@ -909,7 +934,7 @@ index 6056d38..ac9522b
done = False
for group in installed:
-@@ -1283,7 +1566,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1283,7 +1562,20 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, [_('Done')]
def returnGroupSummary(self, userlist):
@@ -930,7 +955,7 @@ index 6056d38..ac9522b
uservisible=1
if len(userlist) > 0:
-@@ -1327,7 +1623,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1327,7 +1619,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 0, [_('Done')]
def returnGroupInfo(self, userlist):
@@ -951,12 +976,14 @@ index 6056d38..ac9522b
for strng in userlist:
group_matched = False
for group in self.comps.return_groups(strng):
-@@ -1340,8 +1648,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1339,9 +1643,19 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+
return 0, []
- def installGroups(self, grouplist):
+- def installGroups(self, grouplist):
- """for each group requested do 'selectGroup' on them."""
-
++ def installGroups(self, grouplist, upgrade=False):
+ """Mark the packages in the given groups for installation.
+
+ :param grouplist: a list of names or wildcards specifying
@@ -972,7 +999,16 @@ index 6056d38..ac9522b
pkgs_used = []
for group_string in grouplist:
-@@ -1368,8 +1686,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1351,7 +1665,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+
+
+ try:
+- txmbrs = self.selectGroup(group.groupid)
++ txmbrs = self.selectGroup(group.groupid, upgrade=upgrade)
+ except yum.Errors.GroupsError:
+ self.logger.critical(_('Warning: Group %s does not exist.'), group_string)
+ continue
+@@ -1368,8 +1682,18 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return 2, [P_('%d package to Install', '%d packages to Install', len(pkgs_used)) % len(pkgs_used)]
def removeGroups(self, grouplist):
@@ -992,7 +1028,7 @@ index 6056d38..ac9522b
pkgs_used = []
for group_string in grouplist:
try:
-@@ -1389,7 +1717,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1389,7 +1713,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
def _promptWanted(self):
# shortcut for the always-off/always-on options
@@ -1001,7 +1037,7 @@ index 6056d38..ac9522b
return False
if self.conf.alwaysprompt:
return True
-@@ -1400,7 +1728,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1400,7 +1724,6 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
# package wasn't explictly given on the command line
for txmbr in self.tsInfo.getMembers():
if txmbr.isDep or \
@@ -1009,7 +1045,7 @@ index 6056d38..ac9522b
txmbr.name not in self.extcmds:
return True
-@@ -1408,11 +1735,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1408,11 +1731,11 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return False
def usage(self):
@@ -1023,7 +1059,7 @@ index 6056d38..ac9522b
sys.stdout.write(self.optparser.get_usage())
def _installable(self, pkg, ematch=False):
-@@ -1468,9 +1795,9 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
+@@ -1468,9 +1791,9 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
return False
class YumOptionParser(OptionParser):
@@ -1035,7 +1071,7 @@ index 6056d38..ac9522b
def __init__(self,base, **kwargs):
# check if this is called with a utils=True/False parameter
-@@ -1488,13 +1815,23 @@ class YumOptionParser(OptionParser):
+@@ -1488,13 +1811,23 @@ class YumOptionParser(OptionParser):
self._addYumBasicOptions()
def error(self, msg):
@@ -1061,7 +1097,7 @@ index 6056d38..ac9522b
try:
args = _filtercmdline(
('--noplugins','--version','-q', '-v', "--quiet", "--verbose"),
-@@ -1521,7 +1858,15 @@ class YumOptionParser(OptionParser):
+@@ -1521,7 +1854,15 @@ class YumOptionParser(OptionParser):
return ret
def setupYumConfig(self, args=None):
@@ -1078,7 +1114,7 @@ index 6056d38..ac9522b
if not args:
(opts, cmds) = self.parse_args()
else:
-@@ -1536,13 +1881,14 @@ class YumOptionParser(OptionParser):
+@@ -1536,13 +1877,14 @@ class YumOptionParser(OptionParser):
# Handle remaining options
if opts.assumeyes:
@@ -1098,7 +1134,18 @@ index 6056d38..ac9522b
self.base.conf.cache = 1
if opts.obsoletes:
-@@ -1640,6 +1986,14 @@ class YumOptionParser(OptionParser):
+@@ -1610,10 +1952,6 @@ class YumOptionParser(OptionParser):
+ self.base.usage()
+ sys.exit(1)
+
+- # make sure the added repos are setup.
+- if len(opts.repos) > 0:
+- self.base._getRepos(doSetup=True)
+-
+ # Disable all gpg key checking, if requested.
+ if opts.nogpgcheck:
+ # Altering the normal configs. doesn't work too well, esp. with
+@@ -1640,6 +1978,14 @@ class YumOptionParser(OptionParser):
sys.exit(1)
def getRoot(self,opts):
@@ -1113,7 +1160,7 @@ index 6056d38..ac9522b
self._checkAbsInstallRoot(opts)
# If the conf file is inside the installroot - use that.
# otherwise look for it in the normal root
-@@ -1713,6 +2067,10 @@ class YumOptionParser(OptionParser):
+@@ -1713,6 +2059,10 @@ class YumOptionParser(OptionParser):
help=_("verbose operation"))
group.add_option("-y", "--assumeyes", dest="assumeyes",
action="store_true", help=_("answer yes for all questions"))
@@ -1124,6 +1171,95 @@ index 6056d38..ac9522b
group.add_option("--version", action="store_true",
help=_("show Yum version and exit"))
group.add_option("--installroot", help=_("set install root"),
+diff --git a/completion-helper.py b/completion-helper.py
+new file mode 100755
+index 0000000..e4164f7
+--- /dev/null
++++ b/completion-helper.py
+@@ -0,0 +1,83 @@
++#!/usr/bin/python -t
++# -*- coding: utf-8 -*-
++#
++# Copyright (C) 2011 Ville Skyttä
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software Foundation,
++# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++
++
++import shlex
++import sys
++
++import cli
++import yumcommands
++
++
++class GroupsCompletionCommand(yumcommands.GroupsCommand):
++ def doCommand(self, base, basecmd, extcmds):
++ cmd, extcmds = self._grp_cmd(basecmd, extcmds)
++ # case insensitivity is fine here because groupinstall etc are that too
++ installed, available = base.doGroupLists(
++ patterns=[get_pattern(extcmds)])
++ if extcmds[0] in ("installed", "all"):
++ for group in installed:
++ print group.ui_name
++ if extcmds[0] in ("available", "all"):
++ for group in available:
++ print group.ui_name
++
++class ListCompletionCommand(yumcommands.ListCommand):
++ def doCommand(self, base, basecmd, extcmds):
++ ypl = base.doPackageLists(pkgnarrow=extcmds[0],
++ patterns=[get_pattern(extcmds)])
++ if extcmds[0] in ("installed", "all"):
++ for pkg in ypl.installed:
++ print pkg.na
++ if extcmds[0] in ("available", "all"):
++ for pkg in ypl.available:
++ print pkg.na
++
++class RepoListCompletionCommand(yumcommands.RepoListCommand):
++ def doCommand(self, base, basecmd, extcmds):
++ import fnmatch
++ pattern = get_pattern(extcmds)
++ for repo in base.repos.repos.values():
++ if fnmatch.fnmatch(repo.id, pattern) \
++ and (extcmds[0] == "all" or
++ (extcmds[0] == "enabled" and repo.isEnabled()) or
++ (extcmds[0] == "disabled" and not repo.isEnabled())):
++ print repo.id
++
++
++def get_pattern(extcmds):
++ if len(extcmds) > 1 and extcmds[-1]:
++ return shlex.split(extcmds[-1])[0] + "*"
++ return "*"
++
++def main(args):
++ base = cli.YumBaseCli()
++ base.yum_cli_commands.clear()
++ base.registerCommand(GroupsCompletionCommand())
++ base.registerCommand(ListCompletionCommand())
++ base.registerCommand(RepoListCompletionCommand())
++ base.getOptionsConfig(args)
++ base.parseCommands()
++ base.doCommands()
++
++if __name__ == "__main__":
++ try:
++ main(sys.argv[1:])
++ except KeyboardInterrupt, e:
++ sys.exit(1)
diff --git a/docs/sphinxdocs/Makefile b/docs/sphinxdocs/Makefile
new file mode 100644
index 0000000..623c22b
@@ -1723,7 +1859,7 @@ index 0000000..d2a0ed1
+if __name__ == "__main__":
+ generateAll(os.getcwd(), os.getcwd())
diff --git a/docs/yum.8 b/docs/yum.8
-index 1a8202a..499da41 100644
+index 1a8202a..6cc0411 100644
--- a/docs/yum.8
+++ b/docs/yum.8
@@ -52,6 +52,7 @@ gnome\-packagekit application\&.
@@ -1745,6 +1881,33 @@ index 1a8202a..499da41 100644
.br
.I \fR * check
.br
+@@ -91,7 +94,7 @@ glob and any matches are then installed\&. If the name starts with an
+ command\&. 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
+ like localinstall\&. If the name doesn't match a package, then package
+-"provides" are searched (Eg. "_sqlitecache.so()(64bit)") as are
++"provides" are searched (e.g. "_sqlitecache.so()(64bit)") as are
+ filelists (Eg. "/usr/bin/yum"). Also note that for filelists, wildcards will
+ match multiple packages\&.
+ .IP
+@@ -111,7 +114,7 @@ changes, for example: upgrading from somelinux 8.0 to somelinux 9.
+
+ Note that "\fBupdate\fP" works on installed packages first, and only if there
+ are no matches does it look for available packages. The difference is most
+-noticable when you do "\fBupdate\fP foo-1-2" which will act exactly as
++noticeable when you do "\fBupdate\fP foo-1-2" which will act exactly as
+ "\fBupdate\fP foo" if foo-1-2 is installed. You can use the "\fBupdate-to\fP"
+ if you'd prefer that nothing happen in the above case.
+ .IP
+@@ -224,7 +227,7 @@ to only remove packages which aren't required by something else.
+
+ "\fBgroup info\fP" is used to give the description and package list of a group (and which type
+ those packages are marked as). Note that you can use the yum-filter-data and
+-yum-list-data plugins to get/use the data the other way around (Ie. what
++yum-list-data plugins to get/use the data the other way around (i.e. what
+ groups own packages need updating). If you pass the \-v option, to enable verbose
+ mode, then the package names are matched against installed/available packages
+ similar to the list command.
@@ -235,12 +238,13 @@ that file is executed in yum shell mode. See \fIyum-shell(8)\fP for more info
.IP
.IP "\fBresolvedep\fP"
@@ -1779,7 +1942,18 @@ index 1a8202a..499da41 100644
work for "installonly" packages, like Kernels. downgrade operates
on groups, files, provides, filelists and rpm files just like the "install" command\&.
.IP
-@@ -321,20 +325,27 @@ and so takes sub-commands:
+@@ -294,8 +298,8 @@ package counts/etc. will be zeroed out).
+ .IP "\fBversion\fP"
+ Produces a "version" of the rpmdb, and of the enabled repositories if "all" is
+ given as the first argument. You can also specify version groups in the
+-version-groups config. file. If you pass \-v, for verbose mode, more
+-information is listed. The version is calculated by taking a sha1 hash of the
++version-groups configuration file. If you pass \-v, for verbose mode, more
++information is listed. The version is calculated by taking an SHA1 hash of the
+ packages (in sorted order), and the checksum_type/checksum_data entries from
+ the yumdb. Note that this rpmdb version is now also used significantly within
+ yum (esp. in yum history).
+@@ -321,26 +325,33 @@ and so takes sub-commands:
.IP "\fBhistory\fP"
The history command allows the user to view what has happened in past
transactions (assuming the history_record config. option is set). You can use
@@ -1811,6 +1985,14 @@ index 1a8202a..499da41 100644
The undo/redo commands act on the specified transaction, undo'ing or repeating
the work of that transaction. While the rollback command will undo all
+-transactions upto the point of the specified transaction. For example, if you
++transactions up to the point of the specified transaction. For example, if you
+ have 3 transactions, where package A; B and C where installed respectively.
+-Then "undo 1" will try to remove pacakge A, "redo 1" will try to install package
++Then "undo 1" will try to remove package A, "redo 1" will try to install package
+ A (if it is not still installed), and "rollback 1" will try to remove packages
+ B and C. Note that after a "rollback 1" you will have a fourth transaction,
+ although the ending rpmdb version (see: yum version) should be the same in
@@ -349,6 +360,12 @@ transactions 1 and 4.
The addon-info command takes a transaction ID, and the packages-list command
takes a package (with wildcards).
@@ -1818,7 +2000,7 @@ index 1a8202a..499da41 100644
+The stats command shows some statistics about the current history DB.
+
+The sync commands allows you to change the rpmdb/yumdb data stored for any
-+installed packages, to whaever is in the current rpmdb/yumdb (this is mostly
++installed packages, to whatever is in the current rpmdb/yumdb (this is mostly
+useful when this data was not stored when the package went into the history DB).
+
In "history list" you can change the behaviour of the 2nd column via. the
@@ -1852,6 +2034,15 @@ index 1a8202a..499da41 100644
.IP "\fB\-c, \-\-config=[config file]\fP"
Specifies the config file location - can take HTTP and FTP URLs and local file
paths\&.
+@@ -420,7 +451,7 @@ Sets the error level to [number] Practical range 0 \- 10. 0 means print only cri
+ .br
+ Configuration Option: \fBerrorlevel\fP
+ .IP "\fB\-\-rpmverbosity=[name]\fP"
+-Sets the debug level to [name] for rpm scriplets. 'info' is the default, other
++Sets the debug level to [name] for rpm scriptlets. 'info' is the default, other
+ options are: 'critical', 'emergency', 'error', 'warn' and 'debug'.
+ .br
+ Configuration Option: \fBrpmverbosity\fP
diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
index 515aa73..d6fe824 100644
--- a/docs/yum.conf.5
@@ -2294,32 +2485,72 @@ index c60fa08..0000000
-ts run
-exit
diff --git a/etc/yum.bash b/etc/yum.bash
-index f1e06e8..f6a0039 100644
+index f1e06e8..6d21e51 100644
--- a/etc/yum.bash
+++ b/etc/yum.bash
-@@ -8,7 +8,7 @@ _yum_list()
- # Fail fast for things that look like paths.
- [[ $2 == */* || $2 == [.~]* ]] && return
+@@ -1,53 +1,17 @@
+ # bash completion for yum
+-# arguments:
+-# 1 = argument to "yum list" (all, available, updates etc)
+-# 2 = current word to be completed
+-_yum_list()
+-{
+- # Fail fast for things that look like paths.
+- [[ $2 == */* || $2 == [.~]* ]] && return
+-
- if [ "$1" = all ] ; then
-+ if [[ $1 == all ]] ; then
- # Try to strip in between headings like "Available Packages" - would
- # be nice if e.g. -d 0 did that for us. This will obviously only work
- # for English :P
-@@ -44,9 +44,9 @@ _yum_repolist()
- _yum_grouplist()
+- # Try to strip in between headings like "Available Packages" - would
+- # be nice if e.g. -d 0 did that for us. This will obviously only work
+- # for English :P
+- COMPREPLY+=( $( ${yum:-yum} -d 0 -C list $1 "$2*" 2>/dev/null | \
+- sed -ne '/^Available /d' -e '/^Installed /d' -e '/^Updated /d' \
+- -e 's/[[:space:]].*//p' ) )
+- else
+- # Drop first line (e.g. "Updated Packages") - would be nice if e.g.
+- # -d 0 did that for us.
+- COMPREPLY+=( $( ${yum:-yum} -d 0 -C list $1 "$2*" 2>/dev/null | \
+- sed -ne 1d -e 's/[[:space:]].*//p' ) )
+- fi
+-}
+-
+-# arguments:
+-# 1 = argument to "yum repolist" (enabled, disabled etc)
+-# 2 = current word to be completed
+-_yum_repolist()
++_yum_helper()
{
- local IFS=$'\n'
+- # TODO: add -d 0 when http://yum.baseurl.org/ticket/29 is fixed
+- # (for now --noplugins is used to get rid of "Loaded plugins: ...")
+- # Drop first ("repo id repo name") and last ("repolist: ...") rows -
+- # would be nice if e.g. -d 0 did that for us.
+- COMPREPLY+=(
+- $( compgen -W "$( ${yum:-yum} --noplugins -C repolist $1 2>/dev/null | \
+- sed -ne '/^repo\s\{1,\}id/d' -e '/^repolist:/d' \
+- -e 's/[[:space:]].*//p' )" -- "$2" ) )
++ local IFS=$'\n'
++ COMPREPLY+=( $(
++ /usr/share/yum-cli/completion-helper.py -d 0 -C "$@" 2>/dev/null ) )
+ }
+
+-# arguments:
+-# 1 = argument to "yum grouplist" (usually empty (""), or hidden)
+-# 2 = current word to be completed
+-_yum_grouplist()
++_yum_list()
+ {
+- local IFS=$'\n'
- # TODO: add -d 0 when http://yum.baseurl.org/ticket/29 is fixed
- COMPREPLY=( $( compgen -W "$( ${yum:-yum} -C grouplist $1 "$2*" \
- 2>/dev/null | sed -ne 's/^[[:space:]]\{1,\}\(.\{1,\}\)/\1/p' )" \
-+ COMPREPLY=( $( compgen -W "$( ${yum:-yum} -d 0 -C grouplist $1 \
-+ 2>/dev/null | sed -e 's/[[:space:]]\{1,\}\[.*$//' \
-+ -ne 's/^[[:space:]]\{1,\}\(.\{1,\}\)/\1/p' )" \
- -- "$2" ) )
+- -- "$2" ) )
++ # Fail fast for things that look like paths.
++ [[ $2 == */* || $2 == [.~]* ]] && return
++ _yum_helper list "$@"
}
-@@ -56,7 +56,7 @@ _yum_grouplist()
+ # arguments:
+@@ -56,7 +20,7 @@ _yum_grouplist()
_yum_plugins()
{
local val
@@ -2328,7 +2559,7 @@ index f1e06e8..f6a0039 100644
COMPREPLY+=( $( compgen -W '$( command grep -il "^\s*enabled\s*=\s*$val" \
/etc/yum/pluginconf.d/*.conf 2>/dev/null \
| sed -ne "s|^.*/\([^/]\{1,\}\)\.conf$|\1|p" )' -- "$2" ) )
-@@ -75,7 +75,7 @@ _yum_baseopts()
+@@ -75,7 +39,7 @@ _yum_baseopts()
{
local opts='--help --tolerant --cacheonly --config --randomwait
--debuglevel --showduplicates --errorlevel --rpmverbosity --quiet
@@ -2337,14 +2568,14 @@ index f1e06e8..f6a0039 100644
--disablerepo --exclude --disableexcludes --obsoletes --noplugins
--nogpgcheck --skip-broken --color --releasever --setopt'
[[ $COMP_LINE == *--noplugins* ]] || \
-@@ -89,6 +89,16 @@ _yum_transactions()
+@@ -89,6 +53,16 @@ _yum_transactions()
sed -ne 's/^[[:space:]]*\([0-9]\{1,\}\).*/\1/p' )" -- "$cur" ) )
}
+_yum_atgroups()
+{
+ if [[ $1 == \@* ]]; then
-+ _yum_grouplist "" "${1:1}"
++ _yum_helper groups list all "${1:1}"
+ COMPREPLY=( "${COMPREPLY[@]/#/@}" )
+ return 0
+ fi
@@ -2354,18 +2585,56 @@ index f1e06e8..f6a0039 100644
# arguments:
# 1 = current word to be completed
# 2 = previous word
-@@ -184,8 +194,8 @@ _yum()
+@@ -119,17 +93,17 @@ _yum_complete_baseopts()
+ ;;
+
+ --enablerepo)
+- _yum_repolist disabled "$1"
++ _yum_helper repolist disabled "$1"
+ return 0
+ ;;
+
+ --disablerepo)
+- _yum_repolist enabled "$1"
++ _yum_helper repolist enabled "$1"
+ return 0
+ ;;
+
+ --disableexcludes)
+- _yum_repolist all "$1"
++ _yum_helper repolist all "$1"
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]} all main' -- "$1" ) )
+ return 0
+ ;;
+@@ -183,16 +157,16 @@ _yum()
+
# Commands offered as completions
local cmds=( check check-update clean deplist distro-sync downgrade
- groupinfo groupinstall grouplist groupremove help history info install
+- groupinfo groupinstall grouplist groupremove help history info install
- list makecache provides reinstall remove repolist resolvedep search
- shell update upgrade version )
-+ list makecache provides reinstall remove repolist search shell update
-+ upgrade version )
++ groups help history info install list makecache provides reinstall
++ remove repolist search shell update upgrade version )
local i c cmd subcmd
for (( i=1; i < ${#words[@]}-1; i++ )) ; do
-@@ -211,7 +221,7 @@ _yum()
+ [[ -n $cmd ]] && subcmd=${words[i]} && break
+ # Recognize additional commands and aliases
+ for c in ${cmds[@]} check-rpmdb distribution-synchronization erase \
+- groupupdate grouperase localinstall localupdate whatprovides ; do
++ group groupinfo groupinstall grouplist groupremove groupupdate \
++ grouperase localinstall localupdate whatprovides ; do
+ [[ ${words[i]} == $c ]] && cmd=$c && break
+ done
+ done
+@@ -205,13 +179,12 @@ _yum()
+ return 0
+ ;;
+
+- check-update|grouplist|makecache|provides|whatprovides|resolvedep|\
+- search)
++ check-update|makecache|provides|whatprovides|resolvedep|search)
+ return 0
;;
clean)
@@ -2374,7 +2643,7 @@ index f1e06e8..f6a0039 100644
COMPREPLY=( $( compgen -W 'expire-cache packages headers
metadata cache dbcache all' -- "$cur" ) )
return 0
-@@ -224,20 +234,22 @@ _yum()
+@@ -224,59 +197,83 @@ _yum()
;;
distro-sync|distribution-synchronization)
@@ -2401,7 +2670,15 @@ index f1e06e8..f6a0039 100644
return 0
;;
-@@ -247,36 +259,53 @@ _yum()
+ group*)
+- _yum_grouplist "" "$cur"
++ if [[ ($cmd == groups || $cmd == group) && $prev == $cmd ]] ; then
++ COMPREPLY=( $( compgen -W 'info install list remove summary' \
++ -- "$cur" ) )
++ else
++ _yum_helper groups list all "$cur"
++ fi
+ return 0
;;
help)
@@ -2466,7 +2743,7 @@ index f1e06e8..f6a0039 100644
;;
esac
return 0
-@@ -288,13 +317,15 @@ _yum()
+@@ -288,13 +285,15 @@ _yum()
;;
install)
@@ -2485,7 +2762,7 @@ index f1e06e8..f6a0039 100644
COMPREPLY=( $( compgen -W 'all available updates installed
extras obsoletes recent' -- "$cur" ) )
return 0
-@@ -306,24 +337,26 @@ _yum()
+@@ -306,24 +305,26 @@ _yum()
;;
repolist)
@@ -2517,7 +2794,7 @@ index f1e06e8..f6a0039 100644
COMPREPLY=( $( compgen -W 'all installed available nogroups
grouplist groupinfo' -- "$cur" ) )
return 0
-@@ -337,7 +370,11 @@ _yum()
+@@ -337,7 +338,11 @@ _yum()
$split && return 0
@@ -2531,7 +2808,7 @@ index f1e06e8..f6a0039 100644
complete -F _yum -o filenames yum yummain.py
diff --git a/output.py b/output.py
-index b6aa277..01f0c40 100755
+index b6aa277..f21b790 100755
--- a/output.py
+++ b/output.py
@@ -1,6 +1,6 @@
@@ -3037,7 +3314,75 @@ index b6aa277..01f0c40 100755
yui = (to_unicode(_('y')), to_unicode(_('yes')))
nui = (to_unicode(_('n')), to_unicode(_('no')))
aui = (yui[0], yui[1], nui[0], nui[1])
-@@ -774,6 +1052,10 @@ class YumOutput:
+@@ -739,27 +1017,58 @@ class YumOutput:
+ return ret
+
+ def _calcDataPkgColumns(self, data, pkg_names, pkg_names2pkgs,
+- indent=' '):
++ indent=' ', igroup_data=None):
+ for item in pkg_names:
+ if item not in pkg_names2pkgs:
+ continue
+ for (apkg, ipkg) in pkg_names2pkgs[item]:
+ pkg = ipkg or apkg
+ envra = utf8_width(str(pkg)) + utf8_width(indent)
++ if igroup_data:
++ envra += 1
+ rid = len(pkg.ui_from_repo)
+ for (d, v) in (('envra', envra), ('rid', rid)):
+ data[d].setdefault(v, 0)
+ data[d][v] += 1
+
+ def _displayPkgsFromNames(self, pkg_names, verbose, pkg_names2pkgs,
+- indent=' ', columns=None):
++ indent=' ', columns=None, igroup_data=None):
++
++ def _get_igrp_data(item, indent):
++ if not igroup_data:
++ return indent
++
++ assert item in igroup_data
++ if item not in igroup_data or igroup_data[item] == 'available':
++ indent += '+' # Group up/in will install i
++ elif igroup_data[item] == 'installed':
++ indent += '=' # Installed via. group
++ elif igroup_data[item] == 'blacklisted-installed':
++ if False: # Not sure it's worth listing these...
++ return None # On the other hand, there's mark-packages
++ indent += ' ' # Installed, not via. group
++ else:
++ assert igroup_data[item] == 'blacklisted-available'
++ if False: # Not sure it's worth listing these...
++ return None
++ indent += '-' # Not installed, and won't be
++ return indent
++
+ if not verbose:
+ for item in sorted(pkg_names):
+- print '%s%s' % (indent, item)
++ pindent = _get_igrp_data(item, indent)
++ if pindent is None:
++ continue
++
++ print '%s%s' % (pindent, item)
+ else:
+ for item in sorted(pkg_names):
++ pindent = _get_igrp_data(item, indent)
++ if pindent is None:
++ continue
++
+ if item not in pkg_names2pkgs:
+- print '%s%s' % (indent, item)
++ print '%s%s' % (pindent, item)
+ continue
+ for (apkg, ipkg) in sorted(pkg_names2pkgs[item],
+ key=lambda x: x[1] or x[0]):
+@@ -770,18 +1079,38 @@ class YumOutput:
+ else:
+ highlight = False
+ self.simpleEnvraList(ipkg or apkg, ui_overflow=True,
+- indent=indent, highlight=highlight,
++ indent=pindent, highlight=highlight,
columns=columns)
def displayPkgsInGroups(self, group):
@@ -3048,8 +3393,53 @@ index b6aa277..01f0c40 100755
print _('\nGroup: %s') % group.ui_name
verb = self.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
-@@ -807,8 +1089,11 @@ class YumOutput:
- columns=columns)
+ if verb:
+ print _(' Group-Id: %s') % to_unicode(group.groupid)
++
++ igroup_data = self._groupInstalledData(group)
++ igrp_only = set()
++ for pkg_name in igroup_data:
++ if igroup_data[pkg_name] == 'installed':
++ igrp_only.add(pkg_name)
++ igrp_only.difference_update(group.packages)
++ all_pkgs = group.packages + list(igrp_only)
++
+ pkg_names2pkgs = None
+ if verb:
+- pkg_names2pkgs = self._group_names2aipkgs(group.packages)
++ pkg_names2pkgs = self._group_names2aipkgs(all_pkgs)
++ else:
++ pkg_names2pkgs = {}
++ for ipkg in self.rpmdb.searchNames(all_pkgs):
++ if ipkg.name not in pkg_names2pkgs:
++ pkg_names2pkgs[ipkg.name] = []
++ pkg_names2pkgs[ipkg.name].append(ipkg)
++
+ if group.ui_description:
+ print _(' Description: %s') % to_unicode(group.ui_description)
+ if group.langonly:
+@@ -795,7 +1124,8 @@ class YumOutput:
+ if verb:
+ data = {'envra' : {}, 'rid' : {}}
+ for (section_name, pkg_names) in sections:
+- self._calcDataPkgColumns(data, pkg_names, pkg_names2pkgs)
++ self._calcDataPkgColumns(data, pkg_names, pkg_names2pkgs,
++ igroup_data=igroup_data)
+ data = [data['envra'], data['rid']]
+ columns = self.calcColumns(data)
+ columns = (-columns[0], -columns[1])
+@@ -804,11 +1134,20 @@ class YumOutput:
+ if len(pkg_names) > 0:
+ print section_name
+ self._displayPkgsFromNames(pkg_names, verb, pkg_names2pkgs,
+- columns=columns)
++ columns=columns,
++ igroup_data=igroup_data)
++ if igrp_only:
++ print _(' Installed Packages:')
++ self._displayPkgsFromNames(igrp_only, verb, pkg_names2pkgs,
++ columns=columns,
++ igroup_data=igroup_data)
def depListOutput(self, results):
- """take a list of findDeps results and 'pretty print' the output"""
@@ -3062,7 +3452,7 @@ index b6aa277..01f0c40 100755
verb = self.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
for pkg in sorted(results):
print _("package: %s") % pkg.compactPrint()
-@@ -832,7 +1117,18 @@ class YumOutput:
+@@ -832,7 +1171,18 @@ class YumOutput:
print " provider: %s" % po.compactPrint()
def format_number(self, number, SI=0, space=' '):
@@ -3082,7 +3472,7 @@ index b6aa277..01f0c40 100755
symbols = [ ' ', # (none)
'k', # kilo
'M', # mega
-@@ -870,16 +1166,31 @@ class YumOutput:
+@@ -870,16 +1220,31 @@ class YumOutput:
@staticmethod
def format_time(seconds, use_hours=0):
@@ -3120,7 +3510,7 @@ index b6aa277..01f0c40 100755
if self.conf.showdupesfromrepos:
msg = '%s : ' % po
else:
-@@ -935,10 +1246,23 @@ class YumOutput:
+@@ -935,10 +1300,23 @@ class YumOutput:
print '\n\n'
def matchcallback_verbose(self, po, values, matchfor=None):
@@ -3145,7 +3535,7 @@ index b6aa277..01f0c40 100755
totsize = 0
locsize = 0
insize = 0
-@@ -982,7 +1306,10 @@ class YumOutput:
+@@ -982,7 +1360,10 @@ class YumOutput:
self.format_number(insize))
def reportRemoveSize(self, packages):
@@ -3157,7 +3547,7 @@ index b6aa277..01f0c40 100755
totsize = 0
error = False
for pkg in packages:
-@@ -1002,8 +1329,9 @@ class YumOutput:
+@@ -1002,8 +1383,9 @@ class YumOutput:
self.format_number(totsize))
def listTransaction(self):
@@ -3169,7 +3559,7 @@ index b6aa277..01f0c40 100755
self.tsInfo.makelists(True, True)
pkglist_lines = []
data = {'n' : {}, 'v' : {}, 'r' : {}}
-@@ -1032,8 +1360,7 @@ class YumOutput:
+@@ -1032,8 +1414,7 @@ class YumOutput:
for (d, v) in (("n",len(n)), ("v",len(evr)), ("r",len(repoid))):
data[d].setdefault(v, 0)
data[d][v] += 1
@@ -3179,7 +3569,7 @@ index b6aa277..01f0c40 100755
return a_wid
for (action, pkglist) in [(_('Installing'), self.tsInfo.installed),
-@@ -1102,19 +1429,72 @@ class YumOutput:
+@@ -1102,19 +1483,72 @@ class YumOutput:
Transaction Summary
%s
""") % ('=' * self.term.columns))
@@ -3262,7 +3652,7 @@ index b6aa277..01f0c40 100755
out = ''
self.tsInfo.makelists()
-@@ -1179,9 +1559,9 @@ Transaction Summary
+@@ -1179,9 +1613,9 @@ Transaction Summary
return out
def setupProgressCallbacks(self):
@@ -3275,7 +3665,7 @@ index b6aa277..01f0c40 100755
# if we're below 2 on the debug level we don't need to be outputting
# progress bars - this is hacky - I'm open to other options
# One of these is a download
-@@ -1216,10 +1596,12 @@ Transaction Summary
+@@ -1216,10 +1650,12 @@ Transaction Summary
self.dsCallback = dscb
def setupProgessCallbacks(self):
@@ -3289,7 +3679,7 @@ index b6aa277..01f0c40 100755
confirm_func = self._cli_confirm_gpg_key_import
gpg_import_func = self.getKeyForRepo
gpgca_import_func = self.getCAKeyForRepo
-@@ -1233,14 +1615,12 @@ Transaction Summary
+@@ -1233,14 +1669,12 @@ Transaction Summary
self.repos.gpgca_import_func = gpgca_import_func
def interrupt_callback(self, cbobj):
@@ -3309,7 +3699,7 @@ index b6aa277..01f0c40 100755
'''
delta_exit_chk = 2.0 # Delta between C-c's so we treat as exit
delta_exit_str = _("two") # Human readable version of above
-@@ -1269,6 +1649,14 @@ to exit.
+@@ -1269,6 +1703,14 @@ to exit.
def download_callback_total_cb(self, remote_pkgs, remote_size,
download_start_timestamp):
@@ -3324,7 +3714,7 @@ index b6aa277..01f0c40 100755
if len(remote_pkgs) <= 1:
return
if not hasattr(urlgrabber.progress, 'TerminalLine'):
-@@ -1434,8 +1822,17 @@ to exit.
+@@ -1434,8 +1876,17 @@ to exit.
return tids, printall
def historyListCmd(self, extcmds):
@@ -3343,7 +3733,7 @@ index b6aa277..01f0c40 100755
tids, printall = self._history_list_transactions(extcmds)
if tids is None:
return 1, ['Failed history list']
-@@ -1564,6 +1961,16 @@ to exit.
+@@ -1564,6 +2015,16 @@ to exit.
return old[0]
def historyInfoCmd(self, extcmds):
@@ -3360,7 +3750,7 @@ index b6aa277..01f0c40 100755
def str2int(x):
try:
return int(x)
-@@ -1656,6 +2063,9 @@ to exit.
+@@ -1656,6 +2117,9 @@ to exit.
def _hpkg2from_repo(self, hpkg):
""" Given a pkg, find the ipkg.ui_from_repo ... if none, then
get an apkg. ... and put a ? in there. """
@@ -3370,7 +3760,7 @@ index b6aa277..01f0c40 100755
ipkgs = self.rpmdb.searchPkgTuple(hpkg.pkgtup)
if not ipkgs:
apkgs = self.pkgSack.searchPkgTuple(hpkg.pkgtup)
-@@ -1672,13 +2082,12 @@ to exit.
+@@ -1672,13 +2136,12 @@ to exit.
'o' : _('Updated'), 'n' : _('Downgraded')}
_pkg_states_available = {'i' : _('Installed'), 'e' : _('Not installed'),
'o' : _('Older'), 'n' : _('Newer')}
@@ -3387,7 +3777,7 @@ index b6aa277..01f0c40 100755
prefix = " " * prefix_len
if was_installed:
_pkg_states = _pkg_states_installed
-@@ -1702,9 +2111,11 @@ to exit.
+@@ -1702,9 +2165,11 @@ to exit.
else:
(hibeg, hiend) = self._highlight('normal')
state = utf8_width_fill(state, _pkg_states['maxlen'])
@@ -3401,7 +3791,7 @@ index b6aa277..01f0c40 100755
if type(old.tid) == type([]):
print _("Transaction ID :"), "%u..%u" % (old.tid[0], old.tid[-1])
-@@ -1778,8 +2189,8 @@ to exit.
+@@ -1778,8 +2243,8 @@ to exit.
default_addons = set(['config-main', 'config-repos', 'saved_tx'])
non_default = set(addon_info).difference(default_addons)
if len(non_default) > 0:
@@ -3412,7 +3802,7 @@ index b6aa277..01f0c40 100755
if old.trans_with:
# This is _possible_, but not common
-@@ -1794,7 +2205,9 @@ to exit.
+@@ -1794,7 +2259,9 @@ to exit.
print _("Packages Skipped:")
pkg_max_len = max((len(str(hpkg)) for hpkg in old.trans_skip))
for hpkg in old.trans_skip:
@@ -3423,7 +3813,7 @@ index b6aa277..01f0c40 100755
if old.rpmdb_problems:
print _("Rpmdb Problems:")
-@@ -1833,6 +2246,13 @@ to exit.
+@@ -1833,6 +2300,13 @@ to exit.
'Updated' : _('Updated'),
}
def historyInfoCmdPkgsAltered(self, old, pats=[]):
@@ -3437,7 +3827,7 @@ index b6aa277..01f0c40 100755
last = None
# Note that these don't use _simple_pkg() because we are showing what
# happened to them in the transaction ... not the difference between the
-@@ -1886,6 +2306,10 @@ to exit.
+@@ -1886,6 +2360,10 @@ to exit.
self._hpkg2from_repo(hpkg))
def historySummaryCmd(self, extcmds):
@@ -3448,7 +3838,7 @@ index b6aa277..01f0c40 100755
tids, printall = self._history_list_transactions(extcmds)
if tids is None:
return 1, ['Failed history info']
-@@ -1946,6 +2370,10 @@ to exit.
+@@ -1946,6 +2424,10 @@ to exit.
utf8_width_fill(uiacts, 16, 16), count)
def historyAddonInfoCmd(self, extcmds):
@@ -3459,7 +3849,7 @@ index b6aa277..01f0c40 100755
tid = None
if len(extcmds) > 1:
tid = extcmds[1]
-@@ -1983,16 +2411,19 @@ to exit.
+@@ -1983,16 +2465,19 @@ to exit.
for item in extcmds[2:]:
if item in addon_info:
@@ -3485,7 +3875,7 @@ index b6aa277..01f0c40 100755
tids = self.history.search(extcmds)
limit = None
if extcmds and not tids:
-@@ -2078,9 +2509,95 @@ to exit.
+@@ -2078,9 +2563,94 @@ to exit.
if lastdbv.end_rpmdbversion != rpmdbv:
self._rpmdb_warn_checks()
@@ -3508,7 +3898,6 @@ index b6aa277..01f0c40 100755
+ for old in self.history.old(tids, limit=limit):
+ if limit is not None and num and (num +len(old.trans_data)) > limit:
+ break
-+ last = None
+
+ for hpkg in old.trans_data: # Find a pkg to go with each cmd...
+ if limit is None:
@@ -3582,7 +3971,7 @@ index b6aa277..01f0c40 100755
def __init__(self, ayum=None):
"""requires yum-cli log and errorlog functions as arguments"""
-@@ -2089,6 +2606,25 @@ class DepSolveProgressCallBack:
+@@ -2089,6 +2659,25 @@ class DepSolveProgressCallBack:
self.ayum = ayum
def pkgAdded(self, pkgtup, mode):
@@ -3608,7 +3997,7 @@ index b6aa277..01f0c40 100755
modedict = { 'i': _('installed'),
'u': _('an update'),
'e': _('erased'),
-@@ -2104,43 +2640,85 @@ class DepSolveProgressCallBack:
+@@ -2104,43 +2693,85 @@ class DepSolveProgressCallBack:
modeterm)
def start(self):
@@ -3696,7 +4085,7 @@ index b6aa277..01f0c40 100755
needname, needflags, needversion = reqTup
yb = self.ayum
-@@ -2225,46 +2803,106 @@ class DepSolveProgressCallBack:
+@@ -2225,46 +2856,106 @@ class DepSolveProgressCallBack:
return msg
def procConflict(self, name, confname):
@@ -3808,7 +4197,7 @@ index b6aa277..01f0c40 100755
def _pkgname_ui(ayum, pkgname, ts_states=None):
""" Get more information on a simple pkgname, if we can. We need to search
-@@ -2316,10 +2954,7 @@ def _pkgname_ui(ayum, pkgname, ts_states=None):
+@@ -2316,10 +3007,7 @@ def _pkgname_ui(ayum, pkgname, ts_states=None):
return pkgname
class YumCliRPMCallBack(RPMBaseCallback):
@@ -3820,7 +4209,7 @@ index b6aa277..01f0c40 100755
width = property(lambda x: _term_width())
-@@ -2337,21 +2972,34 @@ class YumCliRPMCallBack(RPMBaseCallback):
+@@ -2337,21 +3025,34 @@ class YumCliRPMCallBack(RPMBaseCallback):
# Installing things have pkg objects passed to the events, so only need to
# lookup for erased/obsoleted.
def pkgname_ui(self, pkgname, ts_states=('e', 'od', 'ud', None)):
@@ -3865,7 +4254,7 @@ index b6aa277..01f0c40 100755
if type(package) not in types.StringTypes:
pkgname = str(package)
-@@ -2363,9 +3011,25 @@ class YumCliRPMCallBack(RPMBaseCallback):
+@@ -2363,9 +3064,25 @@ class YumCliRPMCallBack(RPMBaseCallback):
percent = 0
else:
percent = (te_current*100L)/te_total
@@ -3892,7 +4281,7 @@ index b6aa277..01f0c40 100755
pkgname=pkgname, wid1=wid1)
msg = fmt % (utf8_width_fill(process, wid1, wid1),
utf8_width_fill(pkgname, wid2, wid2))
-@@ -2377,6 +3041,11 @@ class YumCliRPMCallBack(RPMBaseCallback):
+@@ -2377,6 +3094,11 @@ class YumCliRPMCallBack(RPMBaseCallback):
print " "
def scriptout(self, package, msgs):
@@ -3904,7 +4293,7 @@ index b6aa277..01f0c40 100755
if msgs:
sys.stdout.write(to_unicode(msgs))
sys.stdout.flush()
-@@ -2429,8 +3098,30 @@ class YumCliRPMCallBack(RPMBaseCallback):
+@@ -2429,8 +3151,30 @@ class YumCliRPMCallBack(RPMBaseCallback):
wid2 = pnl
return fmt, wid1, wid2
@@ -146342,7 +146731,7 @@ index 1ce4720..25e3022
gobject.threads_init()
dbus.glib.threads_init()
diff --git a/yum.spec b/yum.spec
-index abd203f..b78a9f6 100644
+index abd203f..572112a 100644
--- a/yum.spec
+++ b/yum.spec
@@ -1,24 +1,51 @@
@@ -146527,7 +146916,7 @@ index abd203f..b78a9f6 100644
%post cron
-@@ -165,21 +237,29 @@ exit 0
+@@ -165,21 +237,30 @@ exit 0
%files -f %{name}.lang
@@ -146551,6 +146940,7 @@ index abd203f..b78a9f6 100644
%{_sysconfdir}/bash_completion.d
+%dir %{_datadir}/yum-cli
%{_datadir}/yum-cli/*
++%exclude %{_datadir}/yum-cli/completion-helper.py?
+%if %{yum_updatesd}
%exclude %{_datadir}/yum-cli/yumupd.py*
+%endif
@@ -146562,7 +146952,7 @@ index abd203f..b78a9f6 100644
%dir /var/cache/yum
%dir /var/lib/yum
%ghost /var/lib/yum/uuid
-@@ -188,20 +268,24 @@ exit 0
+@@ -188,20 +269,24 @@ exit 0
%ghost /var/lib/yum/yumdb
%{_mandir}/man*/yum.*
%{_mandir}/man*/yum-shell*
@@ -146594,7 +146984,7 @@ index abd203f..b78a9f6 100644
%files updatesd
%defattr(-, root, root)
%config(noreplace) %{_sysconfdir}/yum/yum-updatesd.conf
-@@ -210,8 +294,12 @@ exit 0
+@@ -210,8 +295,12 @@ exit 0
%{_datadir}/yum-cli/yumupd.py*
%{_sbindir}/yum-updatesd
%{_mandir}/man*/yum-updatesd*
@@ -146608,10 +146998,18 @@ index abd203f..b78a9f6 100644
- 3.4.1
- umask bug fix.
diff --git a/yum/__init__.py b/yum/__init__.py
-index 99039e0..9163ad0 100644
+index 99039e0..cc64a90 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
-@@ -82,7 +82,7 @@ from packages import YumAvailablePackage, YumLocalPackage, YumInstalledPackage
+@@ -73,6 +73,7 @@ import logginglevels
+ import yumRepo
+ import callbacks
+ import yum.history
++import yum.igroups
+
+ import warnings
+ warnings.simplefilter("ignore", Errors.YumFutureDeprecationWarning)
+@@ -82,7 +83,7 @@ from packages import YumAvailablePackage, YumLocalPackage, YumInstalledPackage
from packages import YumUrlPackage, YumNotFoundPackage
from constants import *
from yum.rpmtrans import RPMTransaction,SimpleCliCallBack
@@ -146620,7 +147018,7 @@ index 99039e0..9163ad0 100644
import string
import StringIO
-@@ -102,10 +102,12 @@ default_grabber.opts.user_agent += " yum/" + __version__
+@@ -102,10 +103,12 @@ default_grabber.opts.user_agent += " yum/" + __version__
class _YumPreBaseConf:
@@ -146637,7 +147035,7 @@ index 99039e0..9163ad0 100644
def __init__(self):
self.fn = '/etc/yum/yum.conf'
self.root = '/'
-@@ -125,10 +127,12 @@ class _YumPreBaseConf:
+@@ -125,10 +128,12 @@ class _YumPreBaseConf:
class _YumPreRepoConf:
@@ -146654,7 +147052,7 @@ index 99039e0..9163ad0 100644
def __init__(self):
self.progressbar = None
self.callback = None
-@@ -164,11 +168,11 @@ class _YumCostExclude:
+@@ -164,11 +169,11 @@ class _YumCostExclude:
return False
class YumBase(depsolve.Depsolve):
@@ -146671,7 +147069,15 @@ index 99039e0..9163ad0 100644
def __init__(self):
depsolve.Depsolve.__init__(self)
self._conf = None
-@@ -213,6 +217,8 @@ class YumBase(depsolve.Depsolve):
+@@ -177,6 +182,7 @@ class YumBase(depsolve.Depsolve):
+ self._up = None
+ self._comps = None
+ self._history = None
++ self._igroups = None
+ self._pkgSack = None
+ self._lockfile = None
+ self._tags = None
+@@ -213,10 +219,15 @@ class YumBase(depsolve.Depsolve):
for cb in self._cleanup: cb()
def close(self):
@@ -146680,7 +147086,14 @@ index 99039e0..9163ad0 100644
# We don't want to create the object, so we test if it's been created
if self._history is not None:
self.history.close()
-@@ -225,15 +231,33 @@ class YumBase(depsolve.Depsolve):
+
++ if self._igroups is not None:
++ self.igroups.close()
++
+ if self._repos:
+ self._repos.close()
+
+@@ -225,15 +236,33 @@ class YumBase(depsolve.Depsolve):
return transactioninfo.TransactionData()
def doGenericSetup(self, cache=0):
@@ -146716,7 +147129,7 @@ index 99039e0..9163ad0 100644
warnings.warn(_('doConfigSetup() will go away in a future version of Yum.\n'),
Errors.YumFutureDeprecationWarning, stacklevel=2)
-@@ -297,7 +321,7 @@ class YumBase(depsolve.Depsolve):
+@@ -297,7 +326,7 @@ class YumBase(depsolve.Depsolve):
# Try the old default
fn = '/etc/yum.conf'
@@ -146725,7 +147138,7 @@ index 99039e0..9163ad0 100644
startupconf.arch = arch
startupconf.basearch = self.arch.basearch
if uuid:
-@@ -367,22 +391,36 @@ class YumBase(depsolve.Depsolve):
+@@ -367,22 +396,36 @@ class YumBase(depsolve.Depsolve):
def doLoggingSetup(self, debuglevel, errorlevel,
syslog_ident=None, syslog_facility=None,
syslog_device='/dev/log'):
@@ -146769,7 +147182,7 @@ index 99039e0..9163ad0 100644
if repo_age is None:
repo_age = os.stat(repofn)[8]
-@@ -448,8 +486,11 @@ class YumBase(depsolve.Depsolve):
+@@ -448,8 +491,11 @@ class YumBase(depsolve.Depsolve):
self.logger.warning(e)
def getReposFromConfig(self):
@@ -146783,7 +147196,7 @@ index 99039e0..9163ad0 100644
# Read .repo files from directories specified by the reposdir option
# (typically /etc/yum/repos.d)
repo_config_age = self.conf.config_file_age
-@@ -472,12 +513,13 @@ class YumBase(depsolve.Depsolve):
+@@ -472,12 +518,13 @@ class YumBase(depsolve.Depsolve):
self.getReposFromConfigFile(repofn, repo_age=thisrepo_age)
def readRepoConfig(self, parser, section):
@@ -146802,7 +147215,7 @@ index 99039e0..9163ad0 100644
repo = yumRepo.YumRepository(section)
try:
repo.populate(parser, section, self.conf)
-@@ -500,31 +542,31 @@ class YumBase(depsolve.Depsolve):
+@@ -500,31 +547,31 @@ class YumBase(depsolve.Depsolve):
return repo
def disablePlugins(self):
@@ -146855,7 +147268,7 @@ index 99039e0..9163ad0 100644
if isinstance(self.plugins, plugins.YumPlugins):
raise RuntimeError(_("plugins already initialised"))
-@@ -533,6 +575,8 @@ class YumBase(depsolve.Depsolve):
+@@ -533,6 +580,8 @@ class YumBase(depsolve.Depsolve):
def doRpmDBSetup(self):
@@ -146864,7 +147277,7 @@ index 99039e0..9163ad0 100644
warnings.warn(_('doRpmDBSetup() will go away in a future version of Yum.\n'),
Errors.YumFutureDeprecationWarning, stacklevel=2)
-@@ -552,7 +596,8 @@ class YumBase(depsolve.Depsolve):
+@@ -552,7 +601,8 @@ class YumBase(depsolve.Depsolve):
return self._rpmdb
def closeRpmDB(self):
@@ -146874,7 +147287,7 @@ index 99039e0..9163ad0 100644
if self._rpmdb is not None:
self._rpmdb.ts = None
self._rpmdb.dropCachedData()
-@@ -567,6 +612,12 @@ class YumBase(depsolve.Depsolve):
+@@ -567,6 +617,12 @@ class YumBase(depsolve.Depsolve):
self._ts = None
def doRepoSetup(self, thisrepo=None):
@@ -146887,7 +147300,7 @@ index 99039e0..9163ad0 100644
warnings.warn(_('doRepoSetup() will go away in a future version of Yum.\n'),
Errors.YumFutureDeprecationWarning, stacklevel=2)
-@@ -630,6 +681,14 @@ class YumBase(depsolve.Depsolve):
+@@ -630,6 +686,14 @@ class YumBase(depsolve.Depsolve):
self._repos = RepoStorage(self)
def doSackSetup(self, archlist=None, thisrepo=None):
@@ -146902,7 +147315,7 @@ index 99039e0..9163ad0 100644
warnings.warn(_('doSackSetup() will go away in a future version of Yum.\n'),
Errors.YumFutureDeprecationWarning, stacklevel=2)
-@@ -711,6 +770,9 @@ class YumBase(depsolve.Depsolve):
+@@ -711,6 +775,9 @@ class YumBase(depsolve.Depsolve):
def doUpdateSetup(self):
@@ -146912,7 +147325,7 @@ index 99039e0..9163ad0 100644
warnings.warn(_('doUpdateSetup() will go away in a future version of Yum.\n'),
Errors.YumFutureDeprecationWarning, stacklevel=2)
-@@ -765,6 +827,8 @@ class YumBase(depsolve.Depsolve):
+@@ -765,6 +832,8 @@ class YumBase(depsolve.Depsolve):
return self._up
def doGroupSetup(self):
@@ -146921,7 +147334,7 @@ index 99039e0..9163ad0 100644
warnings.warn(_('doGroupSetup() will go away in a future version of Yum.\n'),
Errors.YumFutureDeprecationWarning, stacklevel=2)
-@@ -881,7 +945,8 @@ class YumBase(depsolve.Depsolve):
+@@ -881,9 +950,18 @@ class YumBase(depsolve.Depsolve):
if self._history is None:
pdb_path = self.conf.persistdir + "/history"
self._history = yum.history.YumHistory(root=self.conf.installroot,
@@ -146930,8 +147343,30 @@ index 99039e0..9163ad0 100644
+ releasever=self.conf.yumvar['releasever'])
return self._history
++ def _getIGroups(self):
++ """auto create the installed groups object that to access/change the
++ installed groups information. """
++ if self._igroups is None:
++ pdb_path = self.conf.persistdir + "/groups"
++ self._igroups = yum.igroups.InstalledGroups(db_path=pdb_path)
++ return self._igroups
++
# properties so they auto-create themselves with defaults
-@@ -928,9 +993,10 @@ class YumBase(depsolve.Depsolve):
+ repos = property(fget=lambda self: self._getRepos(),
+ fset=lambda self, value: setattr(self, "_repos", value),
+@@ -921,6 +999,11 @@ class YumBase(depsolve.Depsolve):
+ fdel=lambda self: setattr(self, "_history", None),
+ doc="Yum History Object")
+
++ igroups = property(fget=lambda self: self._getIGroups(),
++ fset=lambda self, value: setattr(self, "_igroups",value),
++ fdel=lambda self: setattr(self, "_igroups", None),
++ doc="Yum Installed Groups Object")
++
+ pkgtags = property(fget=lambda self: self._getTags(),
+ fset=lambda self, value: setattr(self, "_tags",value),
+ fdel=lambda self: setattr(self, "_tags", None),
+@@ -928,9 +1011,10 @@ class YumBase(depsolve.Depsolve):
def doSackFilelistPopulate(self):
@@ -146945,7 +147380,7 @@ index 99039e0..9163ad0 100644
necessary = False
# I can't think of a nice way of doing this, we have to have the sack here
-@@ -951,8 +1017,12 @@ class YumBase(depsolve.Depsolve):
+@@ -951,8 +1035,12 @@ class YumBase(depsolve.Depsolve):
self.repos.populateSack(mdtype='filelists')
def yumUtilsMsg(self, func, prog):
@@ -146960,7 +147395,7 @@ index 99039e0..9163ad0 100644
if self.rpmdb.contains(name="yum-utils"):
return
-@@ -964,8 +1034,17 @@ class YumBase(depsolve.Depsolve):
+@@ -964,8 +1052,17 @@ class YumBase(depsolve.Depsolve):
(hibeg, prog, hiend))
def buildTransaction(self, unfinished_transactions_check=True):
@@ -146980,7 +147415,7 @@ index 99039e0..9163ad0 100644
if (unfinished_transactions_check and
misc.find_unfinished_transactions(yumlibpath=self.conf.persistdir)):
msg = _('There are unfinished transactions remaining. You might ' \
-@@ -1242,13 +1321,15 @@ class YumBase(depsolve.Depsolve):
+@@ -1242,13 +1339,15 @@ class YumBase(depsolve.Depsolve):
if None in pkgtup:
return None
return pkgtup
@@ -147000,7 +147435,7 @@ index 99039e0..9163ad0 100644
if pkgtup is None:
return
self._not_found_i[pkgtup] = YumNotFoundPackage(pkgtup)
-@@ -1454,8 +1535,14 @@ class YumBase(depsolve.Depsolve):
+@@ -1454,8 +1553,14 @@ class YumBase(depsolve.Depsolve):
return probs
def runTransaction(self, cb):
@@ -147016,7 +147451,7 @@ index 99039e0..9163ad0 100644
self.plugins.run('pretrans')
# We may want to put this other places, eventually, but for now it's
-@@ -1516,10 +1603,23 @@ class YumBase(depsolve.Depsolve):
+@@ -1516,10 +1621,23 @@ class YumBase(depsolve.Depsolve):
pass
self._ts_save_file = None
@@ -147040,7 +147475,7 @@ index 99039e0..9163ad0 100644
# make resultobject - just a plain yumgenericholder object
resultobject = misc.GenericHolder()
-@@ -1567,13 +1667,22 @@ class YumBase(depsolve.Depsolve):
+@@ -1567,13 +1685,24 @@ class YumBase(depsolve.Depsolve):
self.plugins.run('posttrans')
# sync up what just happened versus what is in the rpmdb
if not self.ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST):
@@ -147049,6 +147484,8 @@ index 99039e0..9163ad0 100644
+ if hasattr(cb, 'verify_txmbr'):
+ vTcb = cb.verify_txmbr
+ self.verifyTransaction(resultobject, vTcb)
++ if self.conf.group_command == 'objects':
++ self.igroups.save()
return resultobject
- def verifyTransaction(self, resultobject=None):
@@ -147068,7 +147505,7 @@ index 99039e0..9163ad0 100644
# check to see that the rpmdb and the tsInfo roughly matches
# push package object metadata outside of rpmdb into yumdb
# delete old yumdb metadata entries
-@@ -1584,9 +1693,16 @@ class YumBase(depsolve.Depsolve):
+@@ -1584,9 +1713,16 @@ class YumBase(depsolve.Depsolve):
# that there is not also an install of this pkg in the tsInfo (reinstall)
# for any kind of install add from_repo to the yumdb, and the cmdline
# and the install reason
@@ -147085,7 +147522,7 @@ index 99039e0..9163ad0 100644
for txmbr in self.tsInfo:
if txmbr.output_state in TS_INSTALL_STATES:
if not self.rpmdb.contains(po=txmbr.po):
-@@ -1596,7 +1712,9 @@ class YumBase(depsolve.Depsolve):
+@@ -1596,7 +1732,9 @@ class YumBase(depsolve.Depsolve):
' but is not!' % txmbr.po))
# Note: Get Panu to do te.Failed() so we don't have to
txmbr.output_state = TS_FAILED
@@ -147095,7 +147532,25 @@ index 99039e0..9163ad0 100644
po = self.getInstalledPackageObject(txmbr.pkgtup)
rpo = txmbr.po
po.yumdb_info.from_repo = rpo.repoid
-@@ -1645,6 +1763,9 @@ class YumBase(depsolve.Depsolve):
+@@ -1630,6 +1768,10 @@ class YumBase(depsolve.Depsolve):
+ if md:
+ po.yumdb_info.from_repo_timestamp = str(md.timestamp)
+
++ if hasattr(txmbr, 'group_member'):
++ # FIXME:
++ po.yumdb_info.group_member = txmbr.group_member
++
+ loginuid = misc.getloginuid()
+ if txmbr.updates or txmbr.downgrades or txmbr.reinstall:
+ if txmbr.updates:
+@@ -1640,11 +1782,16 @@ class YumBase(depsolve.Depsolve):
+ opo = po
+ if 'installed_by' in opo.yumdb_info:
+ po.yumdb_info.installed_by = opo.yumdb_info.installed_by
++ if 'group_member' in opo.yumdb_info:
++ po.yumdb_info.group_member = opo.yumdb_info.group_member
+ if loginuid is not None:
+ po.yumdb_info.changed_by = str(loginuid)
elif loginuid is not None:
po.yumdb_info.installed_by = str(loginuid)
@@ -147105,7 +147560,7 @@ index 99039e0..9163ad0 100644
# Remove old ones after installing new ones, so we can copy values.
for txmbr in self.tsInfo:
if txmbr.output_state in TS_INSTALL_STATES:
-@@ -1662,10 +1783,13 @@ class YumBase(depsolve.Depsolve):
+@@ -1662,10 +1809,13 @@ class YumBase(depsolve.Depsolve):
' but is not!' % txmbr.po))
# Note: Get Panu to do te.Failed() so we don't have to
txmbr.output_state = TS_FAILED
@@ -147119,7 +147574,7 @@ index 99039e0..9163ad0 100644
self.verbose_logger.log(logginglevels.DEBUG_2, 'What is this? %s' % txmbr.po)
self.plugins.run('postverifytrans')
-@@ -1680,10 +1804,11 @@ class YumBase(depsolve.Depsolve):
+@@ -1680,10 +1830,11 @@ class YumBase(depsolve.Depsolve):
self.verbose_logger.debug('VerifyTransaction time: %0.3f' % (time.time() - vt_st))
def costExcludePackages(self):
@@ -147135,7 +147590,7 @@ index 99039e0..9163ad0 100644
# if all the repo.costs are equal then don't bother running things
costs = {}
for r in self.repos.listEnabled():
-@@ -1705,10 +1830,12 @@ class YumBase(depsolve.Depsolve):
+@@ -1705,10 +1856,12 @@ class YumBase(depsolve.Depsolve):
done = True
def excludePackages(self, repo=None):
@@ -147151,7 +147606,7 @@ index 99039e0..9163ad0 100644
if "all" in self.conf.disable_excludes:
return
-@@ -1735,9 +1862,11 @@ class YumBase(depsolve.Depsolve):
+@@ -1735,9 +1888,11 @@ class YumBase(depsolve.Depsolve):
self.pkgSack.addPackageExcluder(repoid, exid,'exclude.match', match)
def includePackages(self, repo):
@@ -147166,7 +147621,7 @@ index 99039e0..9163ad0 100644
includelist = repo.getIncludePkgList()
if len(includelist) == 0:
-@@ -1757,8 +1886,11 @@ class YumBase(depsolve.Depsolve):
+@@ -1757,8 +1912,11 @@ class YumBase(depsolve.Depsolve):
self.pkgSack.addPackageExcluder(repo.id, exid, 'exclude.marked')
def doLock(self, lockfile = YUM_PID_FILE):
@@ -147180,7 +147635,7 @@ index 99039e0..9163ad0 100644
if self.conf.uid != 0:
# If we are a user, assume we are using the root cache ... so don't
# bother locking.
-@@ -1774,38 +1906,26 @@ class YumBase(depsolve.Depsolve):
+@@ -1774,38 +1932,26 @@ class YumBase(depsolve.Depsolve):
mypid=str(os.getpid())
while not self._lock(lockfile, mypid, 0644):
@@ -147234,7 +147689,7 @@ index 99039e0..9163ad0 100644
# if we're not root then we don't lock - just return nicely
# Note that we can get here from __del__, so if we haven't created
# YumBase.conf we don't want to do so here as creating stuff inside
-@@ -1830,31 +1950,69 @@ class YumBase(depsolve.Depsolve):
+@@ -1830,31 +1976,69 @@ class YumBase(depsolve.Depsolve):
self._unlock(lockfile)
self._lockfile = None
@@ -147314,7 +147769,7 @@ index 99039e0..9163ad0 100644
failed = False
if type(fo) is types.InstanceType:
-@@ -1894,9 +2052,16 @@ class YumBase(depsolve.Depsolve):
+@@ -1894,9 +2078,16 @@ class YumBase(depsolve.Depsolve):
def verifyChecksum(self, fo, checksumType, csum):
@@ -147334,7 +147789,7 @@ index 99039e0..9163ad0 100644
try:
filesum = misc.checksum(checksumType, fo)
except Errors.MiscError, e:
-@@ -1908,6 +2073,17 @@ class YumBase(depsolve.Depsolve):
+@@ -1908,6 +2099,17 @@ class YumBase(depsolve.Depsolve):
return 0
def downloadPkgs(self, pkglist, callback=None, callback_total=None):
@@ -147352,7 +147807,7 @@ index 99039e0..9163ad0 100644
def mediasort(apo, bpo):
# FIXME: we should probably also use the mediaid; else we
# could conceivably ping-pong between different disc1's
-@@ -1998,16 +2174,6 @@ class YumBase(depsolve.Depsolve):
+@@ -1998,16 +2200,6 @@ class YumBase(depsolve.Depsolve):
os.unlink(local)
checkfunc = (self.verifyPkg, (po, 1), {})
@@ -147369,7 +147824,7 @@ index 99039e0..9163ad0 100644
try:
if i == 1 and not local_size and remote_size == po.size:
text = os.path.basename(po.relativepath)
-@@ -2032,7 +2198,7 @@ class YumBase(depsolve.Depsolve):
+@@ -2032,7 +2224,7 @@ class YumBase(depsolve.Depsolve):
done_repos.add(po.repoid)
except Errors.RepoError, e:
@@ -147378,7 +147833,7 @@ index 99039e0..9163ad0 100644
else:
po.localpath = mylocal
if po in errors:
-@@ -2052,7 +2218,22 @@ class YumBase(depsolve.Depsolve):
+@@ -2052,7 +2244,22 @@ class YumBase(depsolve.Depsolve):
return errors
def verifyHeader(self, fo, po, raiseError):
@@ -147402,7 +147857,7 @@ index 99039e0..9163ad0 100644
if type(fo) is types.InstanceType:
fo = fo.filename
-@@ -2076,9 +2257,12 @@ class YumBase(depsolve.Depsolve):
+@@ -2076,9 +2283,12 @@ class YumBase(depsolve.Depsolve):
return 1
def downloadHeader(self, po):
@@ -147417,7 +147872,7 @@ index 99039e0..9163ad0 100644
if hasattr(po, 'pkgtype') and po.pkgtype == 'local':
return
-@@ -2122,15 +2306,17 @@ class YumBase(depsolve.Depsolve):
+@@ -2122,15 +2332,17 @@ class YumBase(depsolve.Depsolve):
return
def sigCheckPkg(self, po):
@@ -147443,7 +147898,7 @@ index 99039e0..9163ad0 100644
if self._override_sigchecks:
check = False
hasgpgkey = 0
-@@ -2181,6 +2367,9 @@ class YumBase(depsolve.Depsolve):
+@@ -2181,6 +2393,9 @@ class YumBase(depsolve.Depsolve):
return result, msg
def cleanUsedHeadersPackages(self):
@@ -147453,7 +147908,7 @@ index 99039e0..9163ad0 100644
filelist = []
for txmbr in self.tsInfo:
if txmbr.po.state not in TS_INSTALL_STATES:
-@@ -2218,27 +2407,42 @@ class YumBase(depsolve.Depsolve):
+@@ -2218,27 +2433,42 @@ class YumBase(depsolve.Depsolve):
_('%s removed'), fn)
def cleanHeaders(self):
@@ -147498,7 +147953,7 @@ index 99039e0..9163ad0 100644
cachedir = self.conf.persistdir + "/rpmdb-indexes/"
if not os.path.exists(cachedir):
filelist = []
-@@ -2272,8 +2476,29 @@ class YumBase(depsolve.Depsolve):
+@@ -2272,8 +2502,29 @@ class YumBase(depsolve.Depsolve):
def doPackageLists(self, pkgnarrow='all', patterns=None, showdups=None,
ignore_case=False):
@@ -147530,7 +147985,7 @@ index 99039e0..9163ad0 100644
if showdups is None:
showdups = self.conf.showdupesfromrepos
ygh = misc.GenericHolder(iter=pkgnarrow)
-@@ -2461,14 +2686,13 @@ class YumBase(depsolve.Depsolve):
+@@ -2461,14 +2712,13 @@ class YumBase(depsolve.Depsolve):
def findDeps(self, pkgs):
@@ -147550,7 +148005,7 @@ index 99039e0..9163ad0 100644
results = {}
for pkg in pkgs:
-@@ -2495,10 +2719,22 @@ class YumBase(depsolve.Depsolve):
+@@ -2495,10 +2745,22 @@ class YumBase(depsolve.Depsolve):
# pre 3.2.10 API used to always showdups, so that's the default atm.
def searchGenerator(self, fields, criteria, showdups=True, keys=False,
searchtags=True, searchrpmdb=True):
@@ -147577,7 +148032,7 @@ index 99039e0..9163ad0 100644
sql_fields = []
for f in fields:
sql_fields.append(RPM_TO_SQLITE.get(f, f))
-@@ -2661,6 +2897,14 @@ class YumBase(depsolve.Depsolve):
+@@ -2661,6 +2923,14 @@ class YumBase(depsolve.Depsolve):
yield (po, vs)
def searchPackageTags(self, criteria):
@@ -147592,7 +148047,7 @@ index 99039e0..9163ad0 100644
results = {} # name = [(criteria, taglist)]
for c in criteria:
c = c.lower()
-@@ -2677,11 +2921,16 @@ class YumBase(depsolve.Depsolve):
+@@ -2677,11 +2947,16 @@ class YumBase(depsolve.Depsolve):
return results
def searchPackages(self, fields, criteria, callback=None):
@@ -147614,7 +148069,7 @@ index 99039e0..9163ad0 100644
warnings.warn(_('searchPackages() will go away in a future version of Yum.\
Use searchGenerator() instead. \n'),
Errors.YumFutureDeprecationWarning, stacklevel=2)
-@@ -2700,6 +2949,19 @@ class YumBase(depsolve.Depsolve):
+@@ -2700,6 +2975,19 @@ class YumBase(depsolve.Depsolve):
def searchPackageProvides(self, args, callback=None,
callback_has_matchfor=False):
@@ -147634,9 +148089,71 @@ index 99039e0..9163ad0 100644
def _arg_data(arg):
if not misc.re_glob(arg):
isglob = False
-@@ -2818,11 +3080,17 @@ class YumBase(depsolve.Depsolve):
+@@ -2723,7 +3011,7 @@ class YumBase(depsolve.Depsolve):
+ where = self.returnPackagesByDep(arg)
+ else:
+ usedDepString = False
+- where = self.pkgSack.searchAll(arg, False)
++ where = self.pkgSack.searchProvides(arg)
+ self.verbose_logger.log(logginglevels.DEBUG_1,
+ P_('Searching %d package', 'Searching %d packages', len(where)), len(where))
+
+@@ -2817,25 +3105,93 @@ class YumBase(depsolve.Depsolve):
+
return matches
++ def _groupInstalledData(self, group):
++ """ Return a dict of
++ pkg_name =>
++ (installed, available,
++ backlisted-installed, blacklisted-available). """
++ ret = {}
++ if not group or self.conf.group_command != 'objects':
++ return ret
++
++ pkg_names = {}
++ if group.groupid in self.igroups.groups:
++ pkg_names = self.igroups.groups[group.groupid].pkg_names
++
++ for pkg_name in set(group.packages + list(pkg_names)):
++ ipkgs = self.rpmdb.searchNames([pkg_name])
++ if pkg_name not in pkg_names and not ipkgs:
++ ret[pkg_name] = 'available'
++ continue
++
++ if not ipkgs:
++ ret[pkg_name] = 'blacklisted-available'
++ continue
++
++ for ipkg in ipkgs:
++ # Multiarch, if any are installed for the group we count "both"
++ if ipkg.yumdb_info.get('group_member', '') != group.groupid:
++ continue
++ ret[pkg_name] = 'installed'
++ break
++ else:
++ ret[pkg_name] = 'blacklisted-installed'
++
++ return ret
++
++ def _groupReturnGroups(self, patterns=None, ignore_case=True):
++ igrps = None
++ if patterns is None:
++ grps = self.comps.groups
++ if self.conf.group_command == 'objects':
++ igrps = self.igroups.groups.values()
++ return igrps, grps
++
++ pats = ",".join(patterns)
++ cs = not ignore_case
++ grps = self.comps.return_groups(pats, case_sensitive=cs)
++ # Because we want name matches too, and we don't store group names
++ # we need to add the groupid's we've found:
++ if self.conf.group_command == 'objects':
++ pats += "," + ",".join([grp.groupid for grp in grps])
++ igrps = self.igroups.return_groups(pats, case_sensitive=cs)
++ return igrps, grps
++
def doGroupLists(self, uservisible=0, patterns=None, ignore_case=True):
- """returns two lists of groups, installed groups and available groups
- optional 'uservisible' bool to tell it whether or not to return
@@ -147657,9 +148174,55 @@ index 99039e0..9163ad0 100644
installed = []
available = []
-@@ -2852,8 +3120,13 @@ class YumBase(depsolve.Depsolve):
-
+ if self.comps.compscount == 0:
+ raise Errors.GroupsError, _('No group data available for configured repositories')
+
+- if patterns is None:
+- grps = self.comps.groups
+- else:
+- grps = self.comps.return_groups(",".join(patterns),
+- case_sensitive=not ignore_case)
++ igrps, grps = self._groupReturnGroups(patterns, ignore_case)
++
++ if igrps is not None:
++ digrps = {}
++ for igrp in igrps:
++ digrps[igrp.gid] = igrp
++ igrps = digrps
++
+ for grp in grps:
+- if grp.installed:
++ if igrps is None:
++ grp_installed = grp.installed
++ else:
++ grp_installed = grp.groupid in igrps
++ if grp_installed:
++ del igrps[grp.groupid]
++
++ if grp_installed:
+ if uservisible:
+ if grp.user_visible:
+ installed.append(grp)
+@@ -2848,12 +3204,29 @@ class YumBase(depsolve.Depsolve):
+ else:
+ available.append(grp)
+
++ if igrps is None:
++ return sorted(installed), sorted(available)
++
++ for igrp in igrps.values():
++ # These are installed groups that aren't in comps anymore. so we
++ # create fake comps groups for them.
++ grp = comps.Group()
++ grp.installed = True
++ grp.name = grp.groupid
++ for pkg_name in igrp.pkg_names:
++ grp.mandatory_packages[pkg_name] = 1
++ installed.append(grp)
++
+ return sorted(installed), sorted(available)
+-
def groupRemove(self, grpid):
- """mark all the packages in this group to be removed"""
-
@@ -147673,7 +148236,25 @@ index 99039e0..9163ad0 100644
txmbrs_used = []
thesegroups = self.comps.return_groups(grpid)
-@@ -2872,9 +3145,10 @@ class YumBase(depsolve.Depsolve):
+@@ -2861,20 +3234,28 @@ class YumBase(depsolve.Depsolve):
+ raise Errors.GroupsError, _("No Group named %s exists") % to_unicode(grpid)
+
+ for thisgroup in thesegroups:
++ igroup_data = self._groupInstalledData(thisgroup)
++
+ thisgroup.toremove = True
+ pkgs = thisgroup.packages
+ for pkg in thisgroup.packages:
++ if pkg in igroup_data and igroup_data[pkg] != 'installed':
++ continue
++
+ txmbrs = self.remove(name=pkg, silence_warnings=True)
+ txmbrs_used.extend(txmbrs)
+ for txmbr in txmbrs:
+ txmbr.groups.append(thisgroup.groupid)
++ if igroup_data:
++ self.igroups.del_group(thisgroup.groupid)
+
return txmbrs_used
def groupUnremove(self, grpid):
@@ -147686,16 +148267,19 @@ index 99039e0..9163ad0 100644
thesegroups = self.comps.return_groups(grpid)
if not thesegroups:
raise Errors.GroupsError, _("No Group named %s exists") % to_unicode(grpid)
-@@ -2899,12 +3173,16 @@ class YumBase(depsolve.Depsolve):
+@@ -2898,13 +3279,18 @@ class YumBase(depsolve.Depsolve):
+ self.tsInfo.remove(txmbr.po.pkgtup)
- def selectGroup(self, grpid, group_package_types=[], enable_group_conditionals=None):
+- def selectGroup(self, grpid, group_package_types=[], enable_group_conditionals=None):
- """mark all the packages in the group to be installed
- returns a list of transaction members it added to the transaction
- set
- Optionally take:
- group_package_types=List - overrides self.conf.group_package_types
- enable_group_conditionals=Bool - overrides self.conf.enable_group_conditionals
++ def selectGroup(self, grpid, group_package_types=[],
++ enable_group_conditionals=None, upgrade=False):
+ """Mark all the packages in the given group to be installed.
+
+ :param grpid: the name of the group containing the packages to
@@ -147709,16 +148293,64 @@ index 99039e0..9163ad0 100644
"""
if not self.comps.has_group(grpid):
-@@ -2939,7 +3217,7 @@ class YumBase(depsolve.Depsolve):
+@@ -2934,12 +3320,47 @@ class YumBase(depsolve.Depsolve):
+ if 'optional' in package_types:
+ pkgs.extend(thisgroup.optional_packages)
+
++ igroup_data = self._groupInstalledData(thisgroup)
++ igrp = None
++ if igroup_data:
++ if thisgroup.groupid in self.igroups.groups:
++ igrp = self.igroups.groups[thisgroup.groupid]
++ else:
++ self.igroups.add_group(thisgroup.groupid,thisgroup.packages)
++ pkgs.extend(list(igroup_data.keys()))
++
+ old_txmbrs = len(txmbrs_used)
+ for pkg in pkgs:
++ if self.conf.group_command == 'objects':
++ assert pkg in igroup_data
++ if (pkg not in igroup_data or
++ igroup_data[pkg].startswith('blacklisted')):
++ # (upgrade and igroup_data[pkg] == 'available')):
++ msg = _('Skipping package %s from group %s'),
++ self.verbose_logger.log(logginglevels.DEBUG_2,
++ msg, pkg, thisgroup.groupid)
++ continue
++
self.verbose_logger.log(logginglevels.DEBUG_2,
_('Adding package %s from group %s'), pkg, thisgroup.groupid)
++
++ if igrp is not None:
++ igrp.pkg_names.add(pkg)
++ self.igroups.changed = True
++
++ txmbrs = []
try:
- txmbrs = self.install(name = pkg)
-+ txmbrs = self.install(name=pkg, pkg_warning_level='debug2')
++ if (upgrade and
++ (self.conf.group_command == 'simple' or
++ (igroup_data and igroup_data[pkg] == 'installed'))):
++ txmbrs = self.update(name = pkg)
++ elif igroup_data and igroup_data[pkg] == 'installed':
++ pass # Don't upgrade on install.
++ else:
++ txmbrs = self.install(name = pkg,
++ pkg_warning_level='debug2')
++ for txmbr in txmbrs:
++ txmbr.group_member = thisgroup.groupid
except Errors.InstallError, e:
self.verbose_logger.debug(_('No package named %s available to be installed'),
pkg)
-@@ -2997,10 +3275,14 @@ class YumBase(depsolve.Depsolve):
+@@ -2953,6 +3374,7 @@ class YumBase(depsolve.Depsolve):
+ group_conditionals = enable_group_conditionals
+
+ count_cond_test = 0
++ # FIXME: What do we do about group conditionals when group==objects
+ if group_conditionals:
+ for condreq, cond in thisgroup.conditional_packages.iteritems():
+ if self.isPackageInstalled(cond):
+@@ -2997,10 +3419,14 @@ class YumBase(depsolve.Depsolve):
return txmbrs_used
def deselectGroup(self, grpid, force=False):
@@ -147737,7 +148369,7 @@ index 99039e0..9163ad0 100644
if not self.comps.has_group(grpid):
raise Errors.GroupsError, _("No Group named %s exists") % to_unicode(grpid)
-@@ -3035,12 +3317,21 @@ class YumBase(depsolve.Depsolve):
+@@ -3035,12 +3461,21 @@ class YumBase(depsolve.Depsolve):
self.tsInfo.remove(pkg.pkgtup)
def getPackageObject(self, pkgtup, allow_missing=False):
@@ -147765,7 +148397,7 @@ index 99039e0..9163ad0 100644
# look it up in the self.localPackages first:
for po in self.localPackages:
if po.pkgtup == pkgtup:
-@@ -3049,7 +3340,7 @@ class YumBase(depsolve.Depsolve):
+@@ -3049,7 +3484,7 @@ class YumBase(depsolve.Depsolve):
pkgs = self.pkgSack.searchPkgTuple(pkgtup)
if len(pkgs) == 0:
@@ -147774,7 +148406,7 @@ index 99039e0..9163ad0 100644
if allow_missing: # This can happen due to excludes after .up has
return None # happened.
raise Errors.DepError, _('Package tuple %s could not be found in packagesack') % str(pkgtup)
-@@ -3065,13 +3356,21 @@ class YumBase(depsolve.Depsolve):
+@@ -3065,13 +3500,21 @@ class YumBase(depsolve.Depsolve):
return result
def getInstalledPackageObject(self, pkgtup):
@@ -147801,7 +148433,7 @@ index 99039e0..9163ad0 100644
raise Errors.RpmDBError, _('Package tuple %s could not be found in rpmdb') % str(pkgtup)
# Dito. FIXME from getPackageObject() for len() > 1 ... :)
-@@ -3079,9 +3378,11 @@ class YumBase(depsolve.Depsolve):
+@@ -3079,9 +3522,11 @@ class YumBase(depsolve.Depsolve):
return po
def gpgKeyCheck(self):
@@ -147815,7 +148447,7 @@ index 99039e0..9163ad0 100644
gpgkeyschecked = self.conf.cachedir + '/.gpgkeyschecked.yum'
if os.path.exists(gpgkeyschecked):
return 1
-@@ -3106,9 +3407,13 @@ class YumBase(depsolve.Depsolve):
+@@ -3106,9 +3551,13 @@ class YumBase(depsolve.Depsolve):
return 1
def returnPackagesByDep(self, depstring):
@@ -147831,7 +148463,7 @@ index 99039e0..9163ad0 100644
if not depstring:
return []
-@@ -3135,9 +3440,16 @@ class YumBase(depsolve.Depsolve):
+@@ -3135,9 +3584,16 @@ class YumBase(depsolve.Depsolve):
return self.pkgSack.getProvides(depname, depflags, depver).keys()
def returnPackageByDep(self, depstring):
@@ -147851,7 +148483,16 @@ index 99039e0..9163ad0 100644
# we get all sorts of randomness here
errstring = depstring
if type(depstring) not in types.StringTypes:
-@@ -3156,9 +3468,14 @@ class YumBase(depsolve.Depsolve):
+@@ -3149,16 +3605,22 @@ class YumBase(depsolve.Depsolve):
+ raise Errors.YumBaseError, _('No Package found for %s') % errstring
+
+ ps = ListPackageSack(pkglist)
+- result = self._bestPackageFromList(ps.returnNewestByNameArch())
++ result = self._bestPackageFromList(ps.returnNewestByNameArch(),
++ req=errstring)
+ if result is None:
+ raise Errors.YumBaseError, _('No Package found for %s') % errstring
+
return result
def returnInstalledPackagesByDep(self, depstring):
@@ -147869,10 +148510,11 @@ index 99039e0..9163ad0 100644
if not depstring:
return []
-@@ -3184,6 +3501,34 @@ class YumBase(depsolve.Depsolve):
+@@ -3184,12 +3646,47 @@ class YumBase(depsolve.Depsolve):
return self.rpmdb.getProvides(depname, depflags, depver).keys()
+- def _bestPackageFromList(self, pkglist):
+ def returnInstalledPackageByDep(self, depstring):
+ """Return the best, or first, installed package object that provides the
+ given dependencies.
@@ -147895,23 +148537,44 @@ index 99039e0..9163ad0 100644
+ raise Errors.YumBaseError, _('No Package found for %s') % errstring
+
+ ps = ListPackageSack(pkglist)
-+ result = self._bestPackageFromList(ps.returnNewestByNameArch())
++ result = self._bestPackageFromList(ps.returnNewestByNameArch(),
++ req=errstring)
+ if result is None:
+ raise Errors.YumBaseError, _('No Package found for %s') % errstring
+
+ return result
+
- def _bestPackageFromList(self, pkglist):
++ def _bestPackageFromList(self, pkglist, req=None):
"""take list of package objects and return the best package object.
If the list is empty, return None.
-@@ -3202,10 +3547,17 @@ class YumBase(depsolve.Depsolve):
+
+ Note: this is not aware of multilib so make sure you're only
+- passing it packages of a single arch group."""
++ passing it packages of a single arch group.
++
++ :param pkglist: the list of packages to return the best
++ packages from
++ :param req: the requirement from the user
++ :return: a list of the best packages from *pkglist*
++ """
+
+
+ if len(pkglist) == 0:
+@@ -3198,14 +3695,23 @@ class YumBase(depsolve.Depsolve):
+ if len(pkglist) == 1:
+ return pkglist[0]
+
+- bestlist = self._compare_providers(pkglist, None)
++ bestlist = self._compare_providers(pkglist, reqpo=None, req=req)
return bestlist[0][0]
- def bestPackagesFromList(self, pkglist, arch=None, single_name=False):
+- def bestPackagesFromList(self, pkglist, arch=None, single_name=False):
- """Takes a list of packages, returns the best packages.
- This function is multilib aware so that it will not compare
- multilib to singlelib packages"""
-
++ def bestPackagesFromList(self, pkglist, arch=None, single_name=False,
++ req=None):
+ """Return the best packages from a list of packages. This
+ function is multilib aware, so that it will not compare
+ multilib to singlelib packages.
@@ -147921,12 +148584,82 @@ index 99039e0..9163ad0 100644
+ :param arch: packages will be selected that are compatible
+ with the architecture specified by *arch*
+ :param single_name: whether to return a single package name
++ :param req: the requirement from the user
+ :return: a list of the best packages from *pkglist*
+ """
returnlist = []
compatArchList = self.arch.get_arch_list(arch)
multiLib = []
-@@ -3438,13 +3790,35 @@ class YumBase(depsolve.Depsolve):
+@@ -3222,9 +3728,9 @@ class YumBase(depsolve.Depsolve):
+ singleLib.append(po)
+
+ # we now have three lists. find the best package(s) of each
+- multi = self._bestPackageFromList(multiLib)
+- single = self._bestPackageFromList(singleLib)
+- no = self._bestPackageFromList(noarch)
++ multi = self._bestPackageFromList(multiLib, req=req)
++ single = self._bestPackageFromList(singleLib, req=req)
++ no = self._bestPackageFromList(noarch, req=req)
+
+ if single_name and multi and single and multi.name != single.name:
+ # Sinlge _must_ match multi, if we want a single package name
+@@ -3238,7 +3744,7 @@ class YumBase(depsolve.Depsolve):
+ # if there's a noarch and it's newer than the multilib, we want
+ # just the noarch. otherwise, we want multi + single
+ elif multi:
+- best = self._bestPackageFromList([multi,no])
++ best = self._bestPackageFromList([multi,no], req=req)
+ if best.arch == "noarch":
+ returnlist.append(no)
+ else:
+@@ -3246,7 +3752,7 @@ class YumBase(depsolve.Depsolve):
+ if single: returnlist.append(single)
+ # similar for the non-multilib case
+ elif single:
+- best = self._bestPackageFromList([single,no])
++ best = self._bestPackageFromList([single,no], req=req)
+ if best.arch == "noarch":
+ returnlist.append(no)
+ else:
+@@ -3353,20 +3859,24 @@ class YumBase(depsolve.Depsolve):
+ if next == slow:
+ return None
+
+- def _at_groupinstall(self, pattern):
+- " Do groupinstall via. leading @ on the cmd line, for install/update."
++ def _at_groupinstall(self, pattern, upgrade=False):
++ " Do groupinstall via. leading @ on the cmd line, for install."
+ assert pattern[0] == '@'
+ group_string = pattern[1:]
+ tx_return = []
+ for group in self.comps.return_groups(group_string):
+ try:
+- txmbrs = self.selectGroup(group.groupid)
++ 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)
+ continue
+ return tx_return
+-
++
++ def _at_groupupgrade(self, pattern):
++ " Do group upgrade via. leading @ on the cmd line, for update."
++ return self._at_groupinstall(pattern, upgrade=True)
++
+ def _at_groupremove(self, pattern):
+ " Do groupremove via. leading @ on the cmd line, for remove."
+ assert pattern[0] == '@'
+@@ -3398,7 +3908,7 @@ class YumBase(depsolve.Depsolve):
+ def _minus_deselect(self, pattern):
+ """ Remove things from the transaction, like kickstart. """
+ assert pattern[0] == '-'
+- pat = pattern[1:]
++ pat = pattern[1:].strip()
+
+ if pat and pat[0] == '@':
+ pat = pat[1:]
+@@ -3438,13 +3948,35 @@ class YumBase(depsolve.Depsolve):
self.tsInfo.probFilterFlags.append(flag)
def install(self, po=None, **kwargs):
@@ -147968,7 +148701,33 @@ index 99039e0..9163ad0 100644
pkgs = []
was_pattern = False
if po:
-@@ -3600,23 +3974,23 @@ class YumBase(depsolve.Depsolve):
+@@ -3477,20 +4009,12 @@ class YumBase(depsolve.Depsolve):
+ self.verbose_logger.debug(_('Checking for virtual provide or file-provide for %s'),
+ arg)
+
+- try:
+- mypkgs = self.returnPackagesByDep(arg)
+- except yum.Errors.YumBaseError, e:
+- self.logger.critical(_('No Match for argument: %s') % to_unicode(arg))
+- else:
+- # install MTA* == fail, because provides don't do globs
+- # install /usr/kerberos/bin/* == success (and we want
+- # all of the pkgs)
+- if mypkgs and not misc.re_glob(arg):
++ mypkgs = self.pkgSack.searchProvides(arg)
++ if not misc.re_glob(arg):
+ mypkgs = self.bestPackagesFromList(mypkgs,
+- single_name=True)
+- if mypkgs:
+- pkgs.extend(mypkgs)
+-
++ single_name=True,
++ req=arg)
++ pkgs.extend(mypkgs)
+ else:
+ nevra_dict = self._nevra_kwarg_parse(kwargs)
+
+@@ -3600,23 +4124,23 @@ class YumBase(depsolve.Depsolve):
already_obs = pkgs[0]
if already_obs:
@@ -147999,7 +148758,7 @@ index 99039e0..9163ad0 100644
continue
# make sure we don't have a name.arch of this already installed
-@@ -3630,7 +4004,7 @@ class YumBase(depsolve.Depsolve):
+@@ -3630,7 +4154,7 @@ class YumBase(depsolve.Depsolve):
found = True
break
if not found:
@@ -148008,7 +148767,7 @@ index 99039e0..9163ad0 100644
txmbrs = self.update(po=po)
tx_return.extend(txmbrs)
continue
-@@ -3719,14 +4093,33 @@ class YumBase(depsolve.Depsolve):
+@@ -3719,14 +4243,33 @@ class YumBase(depsolve.Depsolve):
return txmbr
def update(self, po=None, requiringPo=None, update_to=False, **kwargs):
@@ -148030,7 +148789,7 @@ index 99039e0..9163ad0 100644
+ be run if it will update the given package to the given
+ version. For example, if the package foo-1-2 is installed,::
+
-+ updatePkgs(["foo-1-2], update_to=False)
++ updatePkgs(["foo-1-2"], update_to=False)
+ will work identically to::
- returns the list of txmbr of the items it marked for update"""
@@ -148049,7 +148808,30 @@ index 99039e0..9163ad0 100644
# check for args - if no po nor kwargs, do them all
# if po, do it, ignore all else
# if no po do kwargs
-@@ -3985,11 +4378,18 @@ class YumBase(depsolve.Depsolve):
+@@ -3765,7 +4308,12 @@ class YumBase(depsolve.Depsolve):
+ if new is None:
+ continue
+ tx_return.extend(self.update(po=new))
+-
++
++ # Upgrade the installed groups, as part of generic "yum upgrade"
++ if self.conf.group_command == 'objects':
++ for igrp in self.igroups.groups:
++ tx_return.extend(self._at_groupupgrade(igrp))
++
+ return tx_return
+
+ # complications
+@@ -3787,7 +4335,7 @@ class YumBase(depsolve.Depsolve):
+ return self._minus_deselect(kwargs['pattern'])
+
+ if kwargs['pattern'] and kwargs['pattern'][0] == '@':
+- return self._at_groupinstall(kwargs['pattern'])
++ return self._at_groupupgrade(kwargs['pattern'])
+
+ arg = kwargs['pattern']
+ if not update_to:
+@@ -3985,11 +4533,18 @@ class YumBase(depsolve.Depsolve):
return tx_return
def remove(self, po=None, **kwargs):
@@ -148073,7 +148855,7 @@ index 99039e0..9163ad0 100644
if not po and not kwargs:
raise Errors.RemoveError, 'Nothing specified to remove'
-@@ -4055,17 +4455,19 @@ class YumBase(depsolve.Depsolve):
+@@ -4055,17 +4610,19 @@ class YumBase(depsolve.Depsolve):
return tx_return
def installLocal(self, pkg, po=None, updateonly=False):
@@ -148103,7 +148885,7 @@ index 99039e0..9163ad0 100644
# read in the package into a YumLocalPackage Object
# append it to self.localPackages
# check if it can be installed or updated based on nevra versus rpmdb
-@@ -4183,16 +4585,15 @@ class YumBase(depsolve.Depsolve):
+@@ -4183,16 +4740,15 @@ class YumBase(depsolve.Depsolve):
return tx_return
def reinstallLocal(self, pkg, po=None):
@@ -148128,7 +148910,7 @@ index 99039e0..9163ad0 100644
if not po:
try:
po = YumUrlPackage(self, ts=self.rpmdb.readOnlyTS(), url=pkg,
-@@ -4215,9 +4616,19 @@ class YumBase(depsolve.Depsolve):
+@@ -4215,9 +4771,19 @@ class YumBase(depsolve.Depsolve):
return self.reinstall(po=po)
def reinstall(self, po=None, **kwargs):
@@ -148151,7 +148933,7 @@ index 99039e0..9163ad0 100644
self._add_prob_flags(rpm.RPMPROB_FILTER_REPLACEPKG,
rpm.RPMPROB_FILTER_REPLACENEWFILES,
rpm.RPMPROB_FILTER_REPLACEOLDFILES)
-@@ -4259,16 +4670,15 @@ class YumBase(depsolve.Depsolve):
+@@ -4259,16 +4825,15 @@ class YumBase(depsolve.Depsolve):
return tx_mbrs
def downgradeLocal(self, pkg, po=None):
@@ -148176,7 +148958,7 @@ index 99039e0..9163ad0 100644
if not po:
try:
po = YumUrlPackage(self, ts=self.rpmdb.readOnlyTS(), url=pkg,
-@@ -4309,13 +4719,19 @@ class YumBase(depsolve.Depsolve):
+@@ -4309,13 +4874,19 @@ class YumBase(depsolve.Depsolve):
return False
def downgrade(self, po=None, **kwargs):
@@ -148203,7 +148985,7 @@ index 99039e0..9163ad0 100644
if not po and not kwargs:
raise Errors.DowngradeError, 'Nothing specified to downgrade'
-@@ -4457,7 +4873,7 @@ class YumBase(depsolve.Depsolve):
+@@ -4457,7 +5028,7 @@ class YumBase(depsolve.Depsolve):
if e and v and r:
evr = '%s:%s-%s' % (e, v, r)
elif v and r:
@@ -148212,7 +148994,7 @@ index 99039e0..9163ad0 100644
elif e and v:
evr = '%s:%s' % (e, v)
elif v: # e and r etc. is just too weird to print
-@@ -4500,12 +4916,24 @@ class YumBase(depsolve.Depsolve):
+@@ -4500,12 +5071,24 @@ class YumBase(depsolve.Depsolve):
return returndict
@@ -148240,7 +149022,7 @@ index 99039e0..9163ad0 100644
old_conf_obs = self.conf.obsoletes
self.conf.obsoletes = False
done = False
-@@ -4515,19 +4943,46 @@ class YumBase(depsolve.Depsolve):
+@@ -4515,19 +5098,46 @@ class YumBase(depsolve.Depsolve):
done = True
for pkg in transaction.trans_data:
if pkg.state == 'Downgrade':
@@ -148287,7 +149069,7 @@ index 99039e0..9163ad0 100644
if self.install(pkgtup=pkg.pkgtup):
done = True
for pkg in transaction.trans_data:
-@@ -4538,8 +4993,14 @@ class YumBase(depsolve.Depsolve):
+@@ -4538,8 +5148,14 @@ class YumBase(depsolve.Depsolve):
return done
def history_undo(self, transaction):
@@ -148304,7 +149086,7 @@ index 99039e0..9163ad0 100644
# NOTE: This is somewhat basic atm. ... for instance we don't check
# that we are going from the old new version. However it's still
# better than the RHN rollback code, and people pay for that :).
-@@ -4674,39 +5135,49 @@ class YumBase(depsolve.Depsolve):
+@@ -4674,39 +5290,49 @@ class YumBase(depsolve.Depsolve):
if pkgs:
pkgs = sorted(pkgs)[-1]
msg = (_('Importing %s key 0x%s:\n'
@@ -148372,7 +149154,7 @@ index 99039e0..9163ad0 100644
user_cb_fail = False
for keyurl in keyurls:
keys = self._retrievePublicKey(keyurl, repo)
-@@ -4725,7 +5196,9 @@ class YumBase(depsolve.Depsolve):
+@@ -4725,7 +5351,9 @@ class YumBase(depsolve.Depsolve):
# Try installing/updating GPG key
self._getKeyImportMessage(info, keyurl)
rc = False
@@ -148383,7 +149165,7 @@ index 99039e0..9163ad0 100644
rc = True
# grab the .sig/.asc for the keyurl, if it exists
-@@ -4751,8 +5224,8 @@ class YumBase(depsolve.Depsolve):
+@@ -4751,8 +5379,8 @@ class YumBase(depsolve.Depsolve):
ts = self.rpmdb.readOnlyTS()
result = ts.pgpImportPubkey(misc.procgpgkey(info['raw_key']))
if result != 0:
@@ -148394,7 +149176,7 @@ index 99039e0..9163ad0 100644
self.logger.info(_('Key imported successfully'))
key_installed = True
-@@ -4760,18 +5233,20 @@ class YumBase(depsolve.Depsolve):
+@@ -4760,18 +5388,20 @@ class YumBase(depsolve.Depsolve):
raise Errors.YumBaseError, _("Didn't install any keys")
if not key_installed:
@@ -148420,7 +149202,7 @@ index 99039e0..9163ad0 100644
def _getAnyKeyForRepo(self, repo, destdir, keyurl_list, is_cakey=False, callback=None):
"""
-@@ -4788,6 +5263,18 @@ class YumBase(depsolve.Depsolve):
+@@ -4788,6 +5418,18 @@ class YumBase(depsolve.Depsolve):
"""
key_installed = False
@@ -148439,7 +149221,7 @@ index 99039e0..9163ad0 100644
user_cb_fail = False
for keyurl in keyurl_list:
keys = self._retrievePublicKey(keyurl, repo, getSig=not is_cakey)
-@@ -4819,8 +5306,11 @@ class YumBase(depsolve.Depsolve):
+@@ -4819,8 +5461,11 @@ class YumBase(depsolve.Depsolve):
if not key_installed:
self._getKeyImportMessage(info, keyurl, keytype)
rc = False
@@ -148452,7 +149234,7 @@ index 99039e0..9163ad0 100644
elif callback:
rc = callback({"repo": repo, "userid": info['userid'],
"hexkeyid": info['hexkeyid'], "keyurl": keyurl,
-@@ -4835,7 +5325,8 @@ class YumBase(depsolve.Depsolve):
+@@ -4835,7 +5480,8 @@ class YumBase(depsolve.Depsolve):
# Import the key
result = misc.import_key_to_pubring(info['raw_key'], info['hexkeyid'], gpgdir=destdir)
if not result:
@@ -148462,7 +149244,7 @@ index 99039e0..9163ad0 100644
self.logger.info(_('Key imported successfully'))
key_installed = True
# write out the key id to imported_cakeys in the repos basedir
-@@ -4851,36 +5342,35 @@ class YumBase(depsolve.Depsolve):
+@@ -4851,36 +5497,35 @@ class YumBase(depsolve.Depsolve):
pass
if not key_installed and user_cb_fail:
@@ -148515,7 +149297,7 @@ index 99039e0..9163ad0 100644
self._getAnyKeyForRepo(repo, repo.gpgcadir, repo.gpgcakey, is_cakey=True, callback=callback)
def _limit_installonly_pkgs(self):
-@@ -4959,19 +5449,22 @@ class YumBase(depsolve.Depsolve):
+@@ -4959,19 +5604,22 @@ class YumBase(depsolve.Depsolve):
txmbr.depends_on.append(rel)
def processTransaction(self, callback=None,rpmTestDisplay=None, rpmDisplay=None):
@@ -148551,7 +149333,7 @@ index 99039e0..9163ad0 100644
if not callback:
callback = callbacks.ProcessTransNoOutputCallback()
-@@ -5114,13 +5607,19 @@ class YumBase(depsolve.Depsolve):
+@@ -5114,13 +5762,19 @@ class YumBase(depsolve.Depsolve):
return results
def add_enable_repo(self, repoid, baseurls=[], mirrorlist=None, **kwargs):
@@ -148578,7 +149360,7 @@ index 99039e0..9163ad0 100644
# out of place fixme - maybe we should make this the default repo addition
# routine and use it from getReposFromConfigFile(), etc.
newrepo = yumRepo.YumRepository(repoid)
-@@ -5167,9 +5666,15 @@ class YumBase(depsolve.Depsolve):
+@@ -5167,9 +5821,15 @@ class YumBase(depsolve.Depsolve):
def setCacheDir(self, force=False, tmpdir=None, reuse=True,
suffix='/$basearch/$releasever'):
@@ -148597,7 +149379,7 @@ index 99039e0..9163ad0 100644
if not force and os.geteuid() == 0:
return True # We are root, not forced, so happy with the global dir.
if tmpdir is None:
-@@ -5220,13 +5725,24 @@ class YumBase(depsolve.Depsolve):
+@@ -5220,13 +5880,24 @@ class YumBase(depsolve.Depsolve):
self.history.write_addon_data('config-repos', myrepos)
def verify_plugins_cb(self, verify_package):
@@ -148625,7 +149407,7 @@ index 99039e0..9163ad0 100644
if self.tsInfo._unresolvedMembers:
if auto:
self.logger.critical(_("Dependencies not solved. Will not save unresolved transaction."))
-@@ -5234,7 +5750,7 @@ class YumBase(depsolve.Depsolve):
+@@ -5234,7 +5905,7 @@ class YumBase(depsolve.Depsolve):
raise Errors.YumBaseError(_("Dependencies not solved. Will not save unresolved transaction."))
if not filename:
@@ -148634,7 +149416,7 @@ index 99039e0..9163ad0 100644
fd,filename = tempfile.mkstemp(suffix='.yumtx', prefix=prefix)
f = os.fdopen(fd, 'w')
else:
-@@ -5266,7 +5782,17 @@ class YumBase(depsolve.Depsolve):
+@@ -5266,7 +5937,17 @@ class YumBase(depsolve.Depsolve):
def load_ts(self, filename, ignorerpm=None, ignoremissing=None):
@@ -148653,7 +149435,7 @@ index 99039e0..9163ad0 100644
# check rpmversion - if not match throw a fit
# check repoversions (and repos)- if not match throw a fit
# load each txmbr - if pkgs being updated don't exist, bail w/error
-@@ -5292,6 +5818,16 @@ class YumBase(depsolve.Depsolve):
+@@ -5292,6 +5973,16 @@ class YumBase(depsolve.Depsolve):
# 3+numrepos = num pkgs
# 3+numrepos+1 -> EOF= txmembers
@@ -148670,7 +149452,7 @@ index 99039e0..9163ad0 100644
# rpm db ver
rpmv = data[0].strip()
if rpmv != str(self.rpmdb.simpleVersion(main_only=True)[0]):
-@@ -5329,6 +5865,7 @@ class YumBase(depsolve.Depsolve):
+@@ -5329,6 +6020,7 @@ class YumBase(depsolve.Depsolve):
pkgcount = 0
pkgprob = False
curpkg = None
@@ -148826,16 +149608,17 @@ index 7ad25ce..a9a8e53 100644
pass
diff --git a/yum/config.py b/yum/config.py
-index d09511f..6c09ee9 100644
+index d09511f..982c0c5 100644
--- a/yum/config.py
+++ b/yum/config.py
-@@ -45,15 +45,17 @@ from misc import get_uuid, read_in_items_from_dot_dir
+@@ -45,15 +45,18 @@ from misc import get_uuid, read_in_items_from_dot_dir
# Alter/patch these to change the default checking...
__pkgs_gpgcheck_default__ = False
__repo_gpgcheck_default__ = False
+__main_multilib_policy_default__ = 'all'
+__main_failovermethod_default__ = 'roundrobin'
+__main_installonly_limit_default__ = 0
++__group_command_default__ = 'compat'
class Option(object):
- '''
@@ -148851,7 +149634,7 @@ index d09511f..6c09ee9 100644
def __init__(self, default=None, parse_default=False):
self._setattrname()
-@@ -63,19 +65,19 @@ class Option(object):
+@@ -63,19 +66,19 @@ class Option(object):
self.default = default
def _setattrname(self):
@@ -148879,7 +149662,7 @@ index d09511f..6c09ee9 100644
# xemacs highlighting hack: '
if obj is None:
return self
-@@ -83,12 +85,11 @@ class Option(object):
+@@ -83,12 +86,11 @@ class Option(object):
return getattr(obj, self._attrname, None)
def __set__(self, obj, value):
@@ -148896,7 +149679,7 @@ index d09511f..6c09ee9 100644
# Only try to parse if it's a string
if isinstance(value, basestring):
try:
-@@ -100,62 +101,59 @@ class Option(object):
+@@ -100,62 +102,59 @@ class Option(object):
setattr(obj, self._attrname, value)
def setup(self, obj, name):
@@ -148985,7 +149768,7 @@ index d09511f..6c09ee9 100644
def __init__(self, default=None, parse_default=False):
if default is None:
-@@ -163,10 +161,12 @@ class ListOption(Option):
+@@ -163,10 +162,12 @@ class ListOption(Option):
super(ListOption, self).__init__(default, parse_default)
def parse(self, s):
@@ -149001,7 +149784,7 @@ index d09511f..6c09ee9 100644
"""
# we need to allow for the '\n[whitespace]' continuation - easier
# to sub the \n with a space and then read the lines
-@@ -183,12 +183,18 @@ class ListOption(Option):
+@@ -183,12 +184,18 @@ class ListOption(Option):
return results
def tostring(self, value):
@@ -149023,7 +149806,7 @@ index d09511f..6c09ee9 100644
def __init__(self, default=None, schemes=('http', 'ftp', 'file', 'https'),
allow_none=False):
-@@ -197,6 +203,13 @@ class UrlOption(Option):
+@@ -197,6 +204,13 @@ class UrlOption(Option):
self.allow_none = allow_none
def parse(self, url):
@@ -149037,7 +149820,7 @@ index d09511f..6c09ee9 100644
url = url.strip()
# Handle the "_none_" special case
-@@ -224,10 +237,9 @@ class UrlOption(Option):
+@@ -224,10 +238,9 @@ class UrlOption(Option):
return '%s or %s' % (', '.join(self.schemes[:-1]), self.schemes[-1])
class UrlListOption(ListOption):
@@ -149051,7 +149834,7 @@ index d09511f..6c09ee9 100644
def __init__(self, default=None, schemes=('http', 'ftp', 'file', 'https'),
parse_default=False):
super(UrlListOption, self).__init__(default, parse_default)
-@@ -236,6 +248,13 @@ class UrlListOption(ListOption):
+@@ -236,6 +249,13 @@ class UrlListOption(ListOption):
self._urloption = UrlOption(schemes=schemes)
def parse(self, s):
@@ -149065,7 +149848,7 @@ index d09511f..6c09ee9 100644
out = []
s = s.replace('\n', ' ')
s = s.replace(',', ' ')
-@@ -254,10 +273,7 @@ class UrlListOption(ListOption):
+@@ -254,10 +274,7 @@ class UrlListOption(ListOption):
class IntOption(Option):
@@ -149077,7 +149860,7 @@ index d09511f..6c09ee9 100644
def __init__(self, default=None, range_min=None, range_max=None):
super(IntOption, self).__init__(default)
-@@ -265,6 +281,13 @@ class IntOption(Option):
+@@ -265,6 +282,13 @@ class IntOption(Option):
self._range_max = range_max
def parse(self, s):
@@ -149091,7 +149874,7 @@ index d09511f..6c09ee9 100644
try:
val = int(s)
except (ValueError, TypeError), e:
-@@ -276,39 +299,56 @@ class IntOption(Option):
+@@ -276,39 +300,56 @@ class IntOption(Option):
return val
class PositiveIntOption(IntOption):
@@ -149162,7 +149945,7 @@ index d09511f..6c09ee9 100644
if len(s) < 1:
raise ValueError("no value specified")
-@@ -335,14 +375,20 @@ class SecondsOption(Option):
+@@ -335,14 +376,20 @@ class SecondsOption(Option):
return int(n * mult)
class BoolOption(Option):
@@ -149188,7 +149971,7 @@ index d09511f..6c09ee9 100644
s = s.lower()
if s in ('0', 'no', 'false'):
return False
-@@ -352,30 +398,49 @@ class BoolOption(Option):
+@@ -352,30 +399,49 @@ class BoolOption(Option):
raise ValueError('invalid boolean value')
def tostring(self, value):
@@ -149243,7 +150026,7 @@ index d09511f..6c09ee9 100644
if s in self._mapper:
s = self._mapper[s]
if s not in self._allowed:
-@@ -383,18 +448,21 @@ class SelectionOption(Option):
+@@ -383,18 +449,21 @@ class SelectionOption(Option):
return s
class CaselessSelectionOption(SelectionOption):
@@ -149273,7 +150056,7 @@ index d09511f..6c09ee9 100644
"""
# Multipliers for unit symbols
MULTS = {
-@@ -404,20 +472,18 @@ class BytesOption(Option):
+@@ -404,20 +473,18 @@ class BytesOption(Option):
}
def parse(self, s):
@@ -149304,7 +150087,7 @@ index d09511f..6c09ee9 100644
"""
if len(s) < 1:
raise ValueError("no value specified")
-@@ -443,25 +509,23 @@ class BytesOption(Option):
+@@ -443,25 +510,23 @@ class BytesOption(Option):
return int(n * mult)
class ThrottleOption(BytesOption):
@@ -149344,7 +150127,7 @@ index d09511f..6c09ee9 100644
"""
if len(s) < 1:
raise ValueError("no value specified")
-@@ -479,10 +543,9 @@ class ThrottleOption(BytesOption):
+@@ -479,10 +544,9 @@ class ThrottleOption(BytesOption):
return BytesOption.parse(self, s)
class BaseConfig(object):
@@ -149358,7 +150141,7 @@ index d09511f..6c09ee9 100644
def __init__(self):
self._section = None
-@@ -499,13 +562,14 @@ class BaseConfig(object):
+@@ -499,13 +563,14 @@ class BaseConfig(object):
return '\n'.join(out)
def populate(self, parser, section, parent=None):
@@ -149379,7 +150162,7 @@ index d09511f..6c09ee9 100644
self.cfg = parser
self._section = section
-@@ -527,8 +591,19 @@ class BaseConfig(object):
+@@ -527,8 +592,19 @@ class BaseConfig(object):
setattr(self, name, value)
def optionobj(cls, name, exceptions=True):
@@ -149401,7 +150184,7 @@ index d09511f..6c09ee9 100644
obj = getattr(cls, name, None)
if isinstance(obj, Option):
return obj
-@@ -539,37 +614,41 @@ class BaseConfig(object):
+@@ -539,37 +615,41 @@ class BaseConfig(object):
optionobj = classmethod(optionobj)
def isoption(cls, name):
@@ -149458,7 +150241,7 @@ index d09511f..6c09ee9 100644
# Write section heading
if section is None:
if self._section is None:
-@@ -586,6 +665,14 @@ class BaseConfig(object):
+@@ -586,6 +666,14 @@ class BaseConfig(object):
self.cfg.write(fileobj)
def getConfigOption(self, option, default=None):
@@ -149473,7 +150256,7 @@ index d09511f..6c09ee9 100644
warnings.warn('getConfigOption() will go away in a future version of Yum.\n'
'Please access option values as attributes or using getattr().',
DeprecationWarning)
-@@ -594,6 +681,12 @@ class BaseConfig(object):
+@@ -594,6 +682,12 @@ class BaseConfig(object):
return default
def setConfigOption(self, option, value):
@@ -149486,7 +150269,7 @@ index d09511f..6c09ee9 100644
warnings.warn('setConfigOption() will go away in a future version of Yum.\n'
'Please set option values as attributes or using setattr().',
DeprecationWarning)
-@@ -603,11 +696,10 @@ class BaseConfig(object):
+@@ -603,11 +697,10 @@ class BaseConfig(object):
raise Errors.ConfigError, 'No such option %s' % option
class StartupConf(BaseConfig):
@@ -149502,7 +150285,7 @@ index d09511f..6c09ee9 100644
# xemacs highlighting hack: '
debuglevel = IntOption(2, 0, 10)
errorlevel = IntOption(2, 0, 10)
-@@ -625,13 +717,13 @@ class StartupConf(BaseConfig):
+@@ -625,13 +718,13 @@ class StartupConf(BaseConfig):
persistdir = Option('/var/lib/yum')
class YumConf(StartupConf):
@@ -149520,7 +150303,7 @@ index d09511f..6c09ee9 100644
cachedir = Option('/var/cache/yum')
-@@ -641,7 +733,7 @@ class YumConf(StartupConf):
+@@ -641,7 +734,7 @@ class YumConf(StartupConf):
commands = ListOption()
exclude = ListOption()
@@ -149529,7 +150312,7 @@ index d09511f..6c09ee9 100644
proxy = UrlOption(schemes=('http', 'ftp', 'https'), allow_none=True)
proxy_username = Option()
proxy_password = Option()
-@@ -654,7 +746,8 @@ class YumConf(StartupConf):
+@@ -654,7 +747,8 @@ class YumConf(StartupConf):
# NOTE: If you set this to 2, then because it keeps the current kernel it
# means if you ever install an "old" kernel it'll get rid of the newest one
# so you probably want to use 3 as a minimum ... if you turn it on.
@@ -149539,7 +150322,7 @@ index d09511f..6c09ee9 100644
names_of_0=["0", "<off>"])
kernelpkgnames = ListOption(['kernel','kernel-smp', 'kernel-enterprise',
'kernel-bigmem', 'kernel-BOOT', 'kernel-PAE', 'kernel-PAE-debug'])
-@@ -664,6 +757,7 @@ class YumConf(StartupConf):
+@@ -664,6 +758,7 @@ class YumConf(StartupConf):
tsflags = ListOption()
assumeyes = BoolOption(False)
@@ -149547,7 +150330,14 @@ index d09511f..6c09ee9 100644
alwaysprompt = BoolOption(True)
exactarch = BoolOption(True)
tolerant = BoolOption(True)
-@@ -686,6 +780,9 @@ class YumConf(StartupConf):
+@@ -681,11 +776,16 @@ class YumConf(StartupConf):
+ enable_group_conditionals = BoolOption(True)
+ groupremove_leaf_only = BoolOption(False)
+ group_package_types = ListOption(['mandatory', 'default'])
++ group_command = SelectionOption(__group_command_default__,
++ ('compat', 'objects', 'simple'))
+
+ timeout = FloatOption(30.0) # FIXME: Should use variation of SecondsOption
bandwidth = BytesOption(0)
throttle = ThrottleOption(0)
@@ -149557,7 +150347,7 @@ index d09511f..6c09ee9 100644
http_caching = SelectionOption('all', ('none', 'packages', 'all'))
metadata_expire = SecondsOption(60 * 60 * 6) # Time in seconds (6h).
-@@ -698,12 +795,14 @@ class YumConf(StartupConf):
+@@ -698,12 +798,14 @@ class YumConf(StartupConf):
# Note that "instant" is the old behaviour, but group:primary is very
# similar but better :).
mdpolicy = ListOption(['group:primary'])
@@ -149574,7 +150364,7 @@ index d09511f..6c09ee9 100644
color = SelectionOption('auto', ('auto', 'never', 'always'),
mapper={'on' : 'always', 'yes' : 'always',
-@@ -747,6 +846,7 @@ class YumConf(StartupConf):
+@@ -747,6 +849,7 @@ class YumConf(StartupConf):
clean_requirements_on_remove = BoolOption(False)
@@ -149582,7 +150372,7 @@ index d09511f..6c09ee9 100644
history_list_view = SelectionOption('single-user-commands',
('single-user-commands', 'users',
-@@ -756,6 +856,12 @@ class YumConf(StartupConf):
+@@ -756,6 +859,12 @@ class YumConf(StartupConf):
_reposlist = []
def dump(self):
@@ -149595,7 +150385,7 @@ index d09511f..6c09ee9 100644
output = '[main]\n'
# we exclude all vars which start with _ or are in this list:
excluded_vars = ('cfg', 'uid', 'yumvar', 'progress_obj', 'failure_obj',
-@@ -778,14 +884,12 @@ class YumConf(StartupConf):
+@@ -778,14 +887,12 @@ class YumConf(StartupConf):
return output
class RepoConf(BaseConfig):
@@ -149613,7 +150403,7 @@ index d09511f..6c09ee9 100644
ck = self.__cached_keys
if not isinstance(self, RepoConf):
ck = set()
-@@ -823,12 +927,15 @@ class RepoConf(BaseConfig):
+@@ -823,12 +930,15 @@ class RepoConf(BaseConfig):
bandwidth = Inherit(YumConf.bandwidth)
throttle = Inherit(YumConf.throttle)
timeout = Inherit(YumConf.timeout)
@@ -149629,7 +150419,7 @@ index d09511f..6c09ee9 100644
cost = IntOption(1000)
sslcacert = Inherit(YumConf.sslcacert)
-@@ -839,23 +946,23 @@ class RepoConf(BaseConfig):
+@@ -839,23 +949,23 @@ class RepoConf(BaseConfig):
skip_if_unavailable = BoolOption(False)
class VersionGroupConf(BaseConfig):
@@ -149664,7 +150454,7 @@ index d09511f..6c09ee9 100644
# ' xemacs syntax hack
-@@ -876,20 +983,24 @@ def readStartupConfig(configfile, root):
+@@ -876,20 +986,24 @@ def readStartupConfig(configfile, root):
raise Errors.ConfigError("All plugin search paths must be absolute")
# Stuff this here to avoid later re-parsing
startupconf._parser = parser
@@ -149695,7 +150485,7 @@ index d09511f..6c09ee9 100644
# ' xemacs syntax hack
-@@ -956,6 +1067,12 @@ def readMainConfig(startupconf):
+@@ -956,6 +1070,12 @@ def readMainConfig(startupconf):
return yumconf
def readVersionGroupsConfig(configfile="/etc/yum/version-groups.conf"):
@@ -149708,7 +150498,7 @@ index d09511f..6c09ee9 100644
parser = ConfigParser()
confpp_obj = ConfigPreProcessor(configfile)
try:
-@@ -970,17 +1087,16 @@ def readVersionGroupsConfig(configfile="/etc/yum/version-groups.conf"):
+@@ -970,17 +1090,16 @@ def readVersionGroupsConfig(configfile="/etc/yum/version-groups.conf"):
def getOption(conf, section, name, option):
@@ -149736,7 +150526,7 @@ index d09511f..6c09ee9 100644
try:
val = conf.get(section, name)
except (NoSectionError, NoOptionError):
-@@ -1028,7 +1144,10 @@ def _getsysver(installroot, distroverpkg):
+@@ -1028,7 +1147,10 @@ def _getsysver(installroot, distroverpkg):
if idx.count() == 0:
releasever = '$releasever'
else:
@@ -149748,7 +150538,7 @@ index d09511f..6c09ee9 100644
releasever = hdr['version']
del hdr
del idx
-@@ -1036,13 +1155,12 @@ def _getsysver(installroot, distroverpkg):
+@@ -1036,13 +1158,12 @@ def _getsysver(installroot, distroverpkg):
return releasever
def writeRawRepoFile(repo,only=None):
@@ -149767,7 +150557,7 @@ index d09511f..6c09ee9 100644
if not _use_iniparse:
return
-@@ -1069,7 +1187,7 @@ def writeRawRepoFile(repo,only=None):
+@@ -1069,7 +1190,7 @@ def writeRawRepoFile(repo,only=None):
# If the value is the same, but just interpreted ... when we don't want
# to keep the interpreted values.
if (name in ini[section_id] and
@@ -149777,18 +150567,20 @@ index d09511f..6c09ee9 100644
if name not in cfgOptions and option.default == value:
diff --git a/yum/depsolve.py b/yum/depsolve.py
-index 6d744c0..720188c 100644
+index 6d744c0..de01582 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
-@@ -32,7 +32,6 @@ import rpm
+@@ -31,8 +31,8 @@ from transactioninfo import TransactionMember
+ import rpm
from packageSack import ListPackageSack
++from packages import PackageEVR
from constants import *
-import packages
import logginglevels
import Errors
import warnings
-@@ -58,12 +57,12 @@ flags = {"GT": rpm.RPMSENSE_GREATER,
+@@ -58,12 +58,12 @@ flags = {"GT": rpm.RPMSENSE_GREATER,
"LE": rpm.RPMSENSE_LESS | rpm.RPMSENSE_EQUAL,
"EQ": rpm.RPMSENSE_EQUAL,
None: 0 }
@@ -149805,7 +150597,7 @@ index 6d744c0..720188c 100644
def __init__(self):
self._ts = None
-@@ -81,6 +80,8 @@ class Depsolve(object):
+@@ -81,6 +81,8 @@ class Depsolve(object):
self.installedUnresolvedFileRequires = None
def doTsSetup(self):
@@ -149814,7 +150606,7 @@ index 6d744c0..720188c 100644
warnings.warn(_('doTsSetup() will go away in a future version of Yum.\n'),
Errors.YumFutureDeprecationWarning, stacklevel=2)
return self._getTs()
-@@ -131,7 +132,7 @@ class Depsolve(object):
+@@ -131,7 +133,7 @@ class Depsolve(object):
def initActionTs(self):
@@ -149823,7 +150615,7 @@ index 6d744c0..720188c 100644
self._ts = rpmUtils.transaction.TransactionWrapper(self.conf.installroot)
ts_flags_to_rpm = { 'noscripts': rpm.RPMTRANS_FLAG_NOSCRIPTS,
-@@ -158,19 +159,31 @@ class Depsolve(object):
+@@ -158,19 +160,31 @@ class Depsolve(object):
self._ts.setProbFilter(probfilter)
def whatProvides(self, name, flags, version):
@@ -149862,7 +150654,7 @@ index 6d744c0..720188c 100644
iopkgs = set(self.conf.installonlypkgs)
if po.name in iopkgs:
return True
-@@ -182,8 +195,11 @@ class Depsolve(object):
+@@ -182,8 +196,11 @@ class Depsolve(object):
return False
def populateTs(self, test=0, keepold=1):
@@ -149875,7 +150667,7 @@ index 6d744c0..720188c 100644
if self.dsCallback: self.dsCallback.transactionPopulation()
ts_elem = {}
-@@ -393,9 +409,27 @@ class Depsolve(object):
+@@ -393,9 +410,27 @@ class Depsolve(object):
self.conf.obsoletes = 0
txmbrs = self.update(po=requiringPo, requiringPo=requiringPo)
self.conf.obsoletes = origobs
@@ -149905,7 +150697,7 @@ index 6d744c0..720188c 100644
msg = self._err_missing_requires(requiringPo, requirement)
self.verbose_logger.log(logginglevels.DEBUG_2, _('No update paths found for %s. Failure!'), requiringPo)
return self._requiringFromTransaction(requiringPo, requirement, errorlist)
-@@ -696,6 +730,13 @@ class Depsolve(object):
+@@ -696,6 +731,13 @@ class Depsolve(object):
self.tsInfo.remove(txmbr.pkgtup)
def prof_resolveDeps(self):
@@ -149919,7 +150711,7 @@ index 6d744c0..720188c 100644
fn = "anaconda.prof.0"
import hotshot, hotshot.stats
prof = hotshot.Profile(fn)
-@@ -709,6 +750,13 @@ class Depsolve(object):
+@@ -709,6 +751,13 @@ class Depsolve(object):
return rc
def cprof_resolveDeps(self):
@@ -149933,7 +150725,7 @@ index 6d744c0..720188c 100644
import cProfile, pstats
prof = cProfile.Profile()
rc = prof.runcall(self.resolveDeps)
-@@ -722,7 +770,17 @@ class Depsolve(object):
+@@ -722,7 +771,17 @@ class Depsolve(object):
return rc
def resolveDeps(self, full_check=True, skipping_broken=False):
@@ -149952,7 +150744,7 @@ index 6d744c0..720188c 100644
if not len(self.tsInfo):
return (0, [_('Success - empty transaction')])
-@@ -778,6 +836,25 @@ class Depsolve(object):
+@@ -778,6 +837,25 @@ class Depsolve(object):
if checkdep:
break # The next conflict might be the same pkg
@@ -149978,7 +150770,7 @@ index 6d744c0..720188c 100644
if CheckDeps:
if self.dsCallback: self.dsCallback.restartLoop()
self.verbose_logger.log(logginglevels.DEBUG_1, _('Restarting Loop'))
-@@ -1150,6 +1227,11 @@ class Depsolve(object):
+@@ -1150,6 +1228,11 @@ class Depsolve(object):
return ret
def isPackageInstalled(self, pkgname):
@@ -149990,7 +150782,68 @@ index 6d744c0..720188c 100644
lst = self.tsInfo.matchNaevr(name = pkgname)
for txmbr in lst:
if txmbr.output_state in TS_INSTALL_STATES:
-@@ -1393,42 +1475,52 @@ class Depsolve(object):
+@@ -1166,7 +1249,7 @@ class Depsolve(object):
+ return True
+ _isPackageInstalled = isPackageInstalled
+
+- def _compare_providers(self, pkgs, reqpo):
++ def _compare_providers(self, pkgs, reqpo, req=None):
+ """take the list of pkgs and score them based on the requesting package
+ return a dictionary of po=score"""
+ self.verbose_logger.log(logginglevels.DEBUG_4,
+@@ -1210,6 +1293,24 @@ class Depsolve(object):
+ return None
+ return x
+
++ def _pkg2prov_version(pkg, provname):
++ ''' This converts a package into a specific version tuple for the
++ required provide. The provide _must_ be '=' and epoch=None and
++ release=None == '0'.
++ If there is 0 or 2+ matches, return None.
++ If the req does not == the provide name, return None. '''
++ ret = None
++ for prov in pkg.provides:
++ (n, f, (e, v, r)) = prov
++ if n != provname:
++ continue
++ if f != 'EQ':
++ continue
++ if ret is not None:
++ return None
++ ret = (e or '0', v, r or '0')
++ return ret
++
+ # Actual start of _compare_providers().
+
+ # Do a NameArch filtering, based on repo. __cmp__
+@@ -1332,6 +1433,26 @@ class Depsolve(object):
+ _('common prefix of %s between %s and %s' % (cpl, po, reqpo)))
+
+ pkgresults[po] += cpl*2
++
++ if req is not None:
++ bestnum = max(pkgresults.values())
++ prov_depsolve = {}
++ for po in pkgs:
++ if pkgresults[po] != bestnum:
++ continue
++ evr = _pkg2prov_version(po, req)
++ if evr is None:
++ prov_depsolve = {}
++ break
++ prov_depsolve[po] = evr
++ if len(prov_depsolve) > 1:
++ self.verbose_logger.log(logginglevels.DEBUG_4,
++ _('provides vercmp: %s') % str(req))
++ newest = sorted(prov_depsolve,
++ key = lambda x: PackageEVR(*prov_depsolve[x]))[-1]
++ self.verbose_logger.log(logginglevels.DEBUG_4,
++ _(' Winner: %s') % newest)
++ pkgresults[newest] += 1
+
+ # If we have more than one "best", see what would happen if we picked
+ # each package ... ie. what things do they require that _aren't_ already
+@@ -1393,42 +1514,52 @@ class Depsolve(object):
class DepCheck(object):
@@ -150047,12 +150900,12 @@ index 6d744c0..720188c 100644
class Conflicts(object):
-
-- """
-- A pure data class for holding a package and the list of things it
-- conflicts.
+ """A pure data class for holding a list packages and what the
+ conflict between them is.
"""
+- A pure data class for holding a package and the list of things it
+- conflicts.
+- """
-
def __init__(self, pkglist, conflict):
self.pkglist = pkglist # list of conflicting package objects
@@ -150710,6 +151563,153 @@ index 9889bf6..76a258d 100755
try:
'''
Setup the yum translation domain and make _() and P_() translation wrappers
+diff --git a/yum/igroups.py b/yum/igroups.py
+new file mode 100644
+index 0000000..625ee66
+--- /dev/null
++++ b/yum/igroups.py
+@@ -0,0 +1,141 @@
++#! /usr/bin/python -tt
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU Library General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++#
++# Copyright 2010 Red Hat
++#
++# James Antill <james at fedoraproject.org>
++
++import os
++import fnmatch
++import re
++
++class InstalledGroup(object):
++ def __init__(self, gid):
++ self.gid = gid
++ self.pkg_names = set()
++
++ def __cmp__(self, other):
++ if other is None:
++ return 1
++ return cmp(self.gid, other.gid)
++
++ def _additions(self, pkg_names):
++ pkg_names = set(pkg_names)
++ return sorted(pkg_names.difference(self.pkg_names))
++
++ def _removals(self, pkg_names):
++ pkg_names = set(pkg_names)
++ return sorted(pkg_names.difference(self.pkg_names))
++
++
++class InstalledGroups(object):
++ def __init__(self, db_path):
++ self.filename = db_path + "/installed"
++ self.groups = {}
++ self.changed = False
++
++ if not os.access(self.filename, os.R_OK):
++ return
++
++ def _read_str(fo):
++ return fo.readline()[:-1]
++
++ fo = open(self.filename)
++ ver = int(_read_str(fo))
++ if ver != 1:
++ return
++
++ groups_num = int(_read_str(fo))
++ while groups_num > 0:
++ groups_num -= 1
++
++ grp = InstalledGroup(_read_str(fo))
++ self.groups[grp.gid] = grp
++
++ num = int(_read_str(fo))
++ while num > 0:
++ num -= 1
++ grp.pkg_names.add(_read_str(fo))
++
++ def close(self):
++ pass
++
++ def save(self, force=False):
++ if not force and not self.changed:
++ return False
++
++ db_path = os.path.dirname(self.filename)
++ if not os.path.exists(db_path):
++ try:
++ os.makedirs(db_path)
++ except (IOError, OSError), e:
++ # some sort of useful thing here? A warning?
++ return False
++
++ if not os.access(db_path, os.W_OK):
++ return False
++
++ fo = open(self.filename + '.tmp', 'w')
++
++ fo.write("1\n") # version
++ fo.write("%u\n" % len(self.groups))
++ for grp in sorted(self.groups.values()):
++ fo.write("%s\n" % grp.gid)
++ fo.write("%u\n" % len(grp.pkg_names))
++ for pkgname in sorted(grp.pkg_names):
++ fo.write("%s\n" % pkgname)
++ fo.close()
++ os.rename(self.filename + '.tmp', self.filename)
++ self.changed = False
++
++ def add_group(self, groupid, pkg_names):
++ self.changed = True
++
++ if groupid not in self.groups:
++ self.groups[groupid] = InstalledGroup(groupid)
++ grp = self.groups[groupid]
++
++ for pkg_name in pkg_names:
++ grp.pkg_names.add(pkg_name)
++
++ def del_group(self, groupid):
++ self.changed = True
++
++ if groupid in self.groups:
++ del self.groups[groupid]
++
++ def return_groups(self, group_pattern, case_sensitive=False):
++ returns = {}
++
++ for item in group_pattern.split(','):
++ item = item.strip()
++ if item in self.groups:
++ thisgroup = self.groups[item]
++ returns[thisgroup.gid] = thisgroup
++ continue
++
++ if case_sensitive:
++ match = re.compile(fnmatch.translate(item)).match
++ else:
++ match = re.compile(fnmatch.translate(item), flags=re.I).match
++
++ done = False
++ for group in self.groups.values():
++ if match(group.gid):
++ done = True
++ returns[group.gid] = group
++ break
++
++ return returns.values()
diff --git a/yum/misc.py b/yum/misc.py
index 2f6ddfe..5321003 100644
--- a/yum/misc.py
@@ -150797,7 +151797,7 @@ index 4af563a..47832fc 100644
self.obsoletes = {} #obs[obsoletename] = [pkg1, pkg2, pkg3]
#the package lists are packages that obsolete the key name
diff --git a/yum/packages.py b/yum/packages.py
-index 5ef9951..15316c8 100644
+index 5ef9951..6bc909e 100644
--- a/yum/packages.py
+++ b/yum/packages.py
@@ -243,34 +243,87 @@ class PackageObject(object):
@@ -150908,7 +151908,31 @@ index 5ef9951..15316c8 100644
def __str__(self):
return self.ui_envra
-@@ -1083,7 +1136,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -481,15 +534,14 @@ class RpmBase(object):
+ if prcotuple in self._prco_lookup[prcotype]:
+ return 1
+
+- if True: # Keep indentation for patch smallness...
+- # make us look it up and compare
+- (reqn, reqf, (reqe, reqv ,reqr)) = prcotuple
+- if reqf is not None:
+- return self.inPrcoRange(prcotype, prcotuple)
+- else:
+- for (n, f, (e, v, r)) in self.returnPrco(prcotype):
+- if i18n.str_eq(reqn, n):
+- return 1
++ # make us look it up and compare
++ (reqn, reqf, (reqe, reqv ,reqr)) = prcotuple
++ if reqf is not None:
++ return self.inPrcoRange(prcotype, prcotuple)
++ else:
++ for (n, f, (e, v, r)) in self.returnPrco(prcotype):
++ if i18n.str_eq(reqn, n):
++ return 1
+
+ return 0
+
+@@ -1083,7 +1135,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
misc.to_unicode(misc.to_xml(self.summary)),
misc.to_unicode(misc.to_xml(self.description)),
packager, url, self.filetime,
@@ -150917,7 +151941,7 @@ index 5ef9951..15316c8 100644
msg += self._return_remote_location()
return msg
-@@ -1133,7 +1186,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1133,7 +1185,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
msg = ""
mylist = getattr(self, pcotype)
if mylist: msg = "\n <rpm:%s>\n" % pcotype
@@ -150926,7 +151950,7 @@ index 5ef9951..15316c8 100644
pcostring = ''' <rpm:entry name="%s"''' % misc.to_xml(name, attrib=True)
if flags:
pcostring += ''' flags="%s"''' % misc.to_xml(flags, attrib=True)
-@@ -1161,11 +1214,11 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1161,11 +1213,11 @@ class YumAvailablePackage(PackageObject, RpmBase):
dirs = self.returnFileEntries('dir', primary_only=True)
ghosts = self.returnFileEntries('ghost', primary_only=True)
@@ -150941,7 +151965,7 @@ index 5ef9951..15316c8 100644
msg += """ <file type="ghost">%s</file>\n""" % misc.to_xml(fn)
return msg
-@@ -1194,8 +1247,8 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1194,8 +1246,8 @@ class YumAvailablePackage(PackageObject, RpmBase):
continue
newlist.append(i)
mylist = newlist
@@ -150952,7 +151976,7 @@ index 5ef9951..15316c8 100644
if name.startswith('rpmlib('):
continue
# this drops out requires that the pkg provides for itself.
-@@ -1217,13 +1270,16 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1217,13 +1269,16 @@ class YumAvailablePackage(PackageObject, RpmBase):
prcostring += ''' ver="%s"''' % misc.to_xml(v, attrib=True)
if r:
prcostring += ''' rel="%s"''' % misc.to_xml(r, attrib=True)
@@ -150971,7 +151995,7 @@ index 5ef9951..15316c8 100644
return msg
def _dump_changelog(self, clog_limit):
-@@ -1299,7 +1355,8 @@ class YumHeaderPackage(YumAvailablePackage):
+@@ -1299,7 +1354,8 @@ class YumHeaderPackage(YumAvailablePackage):
self.pkgid = self.hdr[rpm.RPMTAG_SHA1HEADER]
if not self.pkgid:
self.pkgid = "%s.%s" %(self.hdr['name'], self.hdr['buildtime'])
@@ -151696,7 +152720,7 @@ index 9b265f9..24a1f9e 100644
+
+ self.display.verify_txmbr(self.base, txmbr, count)
diff --git a/yum/sqlitesack.py b/yum/sqlitesack.py
-index 8a6f6f3..19193ad 100644
+index 8a6f6f3..f6df93e 100644
--- a/yum/sqlitesack.py
+++ b/yum/sqlitesack.py
@@ -406,7 +406,7 @@ class YumAvailablePackageSqlite(YumAvailablePackage, PackageObject, RpmBase):
@@ -151708,11 +152732,26 @@ index 8a6f6f3..19193ad 100644
pre = "1"
prco_set = (_share_data(ob['name']), _share_data(ob['flags']),
(_share_data(ob['epoch']),
+@@ -917,8 +917,7 @@ class YumSqlitePackageSack(yumRepo.YumPackageSack):
+
+ # ultra simple optimization
+ if misc.re_primary_filename(name):
+- if not misc.re_glob(dirname): # is the dirname a glob?
+- return self._search_primary_files(name)
++ return self._search_primary_files(name)
+
+ if len(self.filelistsdb) == 0:
+ # grab repo object from primarydb and force filelists population in this sack using repo
diff --git a/yum/yumRepo.py b/yum/yumRepo.py
-index e5e9ece..f645a1a 100644
+index e5e9ece..62e53f8 100644
--- a/yum/yumRepo.py
+++ b/yum/yumRepo.py
-@@ -24,6 +24,7 @@ urlparse.uses_fragment.append("media")
+@@ -20,10 +20,12 @@ import time
+ import types
+ import urlparse
+ urlparse.uses_fragment.append("media")
++import urllib
+
import Errors
from urlgrabber.grabber import URLGrabber
from urlgrabber.grabber import default_grabber
@@ -151720,7 +152759,7 @@ index e5e9ece..f645a1a 100644
import urlgrabber.mirror
from urlgrabber.grabber import URLGrabError
import repoMDObject
-@@ -35,6 +36,7 @@ import sqlitesack
+@@ -35,6 +37,7 @@ import sqlitesack
from yum import config
from yum import misc
from yum import comps
@@ -151728,7 +152767,35 @@ index e5e9ece..f645a1a 100644
from constants import *
import metalink
-@@ -499,6 +501,7 @@ class YumRepository(Repository, config.RepoConf):
+@@ -434,22 +437,13 @@ class YumRepository(Repository, config.RepoConf):
+ if self.proxy not in empty:
+ proxy_string = '%s' % self.proxy
+ if self.proxy_username not in empty:
+- proxy_parsed = urlparse.urlsplit(self.proxy, allow_fragments=0)
+- proxy_proto = proxy_parsed[0]
+- proxy_host = proxy_parsed[1]
+- # http://foo:123 == ('http', 'foo:123', '', '', '')
+- # don't turn that into: http://foo:123? - bug#328121
+- if proxy_parsed[2] == '':
+- proxy_rest = ''
+- else:
+- proxy_rest = proxy_parsed[2] + '?' + proxy_parsed[3]
+- proxy_string = '%s://%s@%s%s' % (proxy_proto,
+- self.proxy_username, proxy_host, proxy_rest)
+
++ auth = urllib.quote(self.proxy_username)
+ if self.proxy_password not in empty:
+- proxy_string = '%s://%s:%s@%s%s' % (proxy_proto,
+- self.proxy_username, self.proxy_password,
+- proxy_host, proxy_rest)
++ auth += ':' + urllib.quote(self.proxy_password)
++
++ proto, rest = re.match('(\w+://)(.+)', proxy_string).groups()
++ proxy_string = '%s%s@%s' % (proto, auth, rest)
+
+ if proxy_string is not None:
+ self._proxy_dict['http'] = proxy_string
+@@ -499,6 +493,7 @@ class YumRepository(Repository, config.RepoConf):
'throttle': self.throttle,
'proxies': self.proxy_dict,
'timeout': self.timeout,
@@ -151736,7 +152803,7 @@ index e5e9ece..f645a1a 100644
'http_headers': tuple(self.__headersListFromDict(cache=cache)),
'ssl_verify_peer': self.sslverify,
'ssl_verify_host': self.sslverify,
-@@ -796,6 +799,16 @@ class YumRepository(Repository, config.RepoConf):
+@@ -796,6 +791,16 @@ class YumRepository(Repository, config.RepoConf):
except Errors.MediaError, e:
verbose_logger.log(logginglevels.DEBUG_2, "Error getting package from media; falling back to url %s" %(e,))
@@ -151753,7 +152820,7 @@ index e5e9ece..f645a1a 100644
if url and scheme != "media":
ugopts = self._default_grabopts(cache=cache)
ug = URLGrabber(progress_obj = self.callback,
-@@ -1020,7 +1033,7 @@ class YumRepository(Repository, config.RepoConf):
+@@ -1020,7 +1025,7 @@ class YumRepository(Repository, config.RepoConf):
if grab_can_fail:
return None
raise Errors.RepoError, 'Error downloading file %s: %s' % (local, e)
@@ -151762,7 +152829,7 @@ index e5e9ece..f645a1a 100644
misc.unlink_f(tfname)
if grab_can_fail:
return None
-@@ -1260,6 +1273,9 @@ class YumRepository(Repository, config.RepoConf):
+@@ -1260,6 +1265,9 @@ class YumRepository(Repository, config.RepoConf):
return True
def _check_db_version(self, mdtype, repoXML=None):
@@ -151772,7 +152839,21 @@ index e5e9ece..f645a1a 100644
if repoXML is None:
repoXML = self.repoXML
if mdtype in repoXML.repoData:
-@@ -1614,7 +1630,7 @@ class YumRepository(Repository, config.RepoConf):
+@@ -1451,12 +1459,7 @@ class YumRepository(Repository, config.RepoConf):
+ def _getRepoXML(self):
+ if self._repoXML:
+ return self._repoXML
+- try:
+- self._loadRepoXML(text=self)
+- except Errors.RepoError, e:
+- msg = ("Cannot retrieve repository metadata (repomd.xml) for repository: %s. "
+- "Please verify its path and try again" % self )
+- raise Errors.RepoError, msg
++ self._loadRepoXML(text=self)
+ return self._repoXML
+
+
+@@ -1614,7 +1617,7 @@ class YumRepository(Repository, config.RepoConf):
text=text,
cache=self.http_caching == 'all',
size=thisdata.size)
@@ -151782,7 +152863,7 @@ index e5e9ece..f645a1a 100644
return None
raise
diff --git a/yumcommands.py b/yumcommands.py
-index 4dcbea7..36b19b3 100644
+index 4dcbea7..31cb190 100644
--- a/yumcommands.py
+++ b/yumcommands.py
@@ -43,16 +43,24 @@ def _err_mini_usage(base, basecmd):
@@ -151828,7 +152909,7 @@ index 4dcbea7..36b19b3 100644
if len(extcmds) == 0:
base.logger.critical(
_('Error: Need to pass a list of pkgs to %s') % basecmd)
-@@ -82,18 +98,44 @@ def checkPackageArg(base, basecmd, extcmds):
+@@ -82,24 +98,51 @@ def checkPackageArg(base, basecmd, extcmds):
raise cli.CliError
def checkItemArg(base, basecmd, extcmds):
@@ -151873,7 +152954,14 @@ index 4dcbea7..36b19b3 100644
VALID_ARGS = ('headers', 'packages', 'metadata', 'dbcache', 'plugins',
'expire-cache', 'rpmdb', 'all')
-@@ -108,12 +150,14 @@ def checkCleanArg(base, basecmd, extcmds):
+ if len(extcmds) == 0:
+ base.logger.critical(_('Error: clean requires an option: %s') % (
+ ", ".join(VALID_ARGS)))
++ raise cli.CliError
+
+ for cmd in extcmds:
+ if cmd not in VALID_ARGS:
+@@ -108,12 +151,14 @@ def checkCleanArg(base, basecmd, extcmds):
raise cli.CliError
def checkShellArg(base, basecmd, extcmds):
@@ -151894,7 +152982,7 @@ index 4dcbea7..36b19b3 100644
"""
if len(extcmds) == 0:
base.verbose_logger.debug(_("No argument to shell"))
-@@ -133,10 +177,12 @@ def checkShellArg(base, basecmd, extcmds):
+@@ -133,10 +178,12 @@ def checkShellArg(base, basecmd, extcmds):
raise cli.CliError
def checkEnabledRepo(base, possible_local_files=[]):
@@ -151910,7 +152998,7 @@ index 4dcbea7..36b19b3 100644
"""
if base.repos.listEnabled():
return
-@@ -152,63 +198,145 @@ def checkEnabledRepo(base, possible_local_files=[]):
+@@ -152,63 +199,145 @@ def checkEnabledRepo(base, possible_local_files=[]):
raise cli.CliError
class YumCommand:
@@ -152066,7 +153154,7 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _("Setting up Install Process"))
try:
return base.installPkgs(extcmds)
-@@ -216,21 +344,60 @@ class InstallCommand(YumCommand):
+@@ -216,21 +345,60 @@ class InstallCommand(YumCommand):
return 1, [str(e)]
class UpdateCommand(YumCommand):
@@ -152127,7 +153215,7 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _("Setting up Update Process"))
try:
return base.updatePkgs(extcmds, update_to=(basecmd == 'update-to'))
-@@ -238,21 +405,59 @@ class UpdateCommand(YumCommand):
+@@ -238,21 +406,59 @@ class UpdateCommand(YumCommand):
return 1, [str(e)]
class DistroSyncCommand(YumCommand):
@@ -152187,12 +153275,12 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _("Setting up Distribution Synchronization Process"))
try:
base.conf.obsoletes = 1
-@@ -289,16 +494,46 @@ def _list_cmd_calc_columns(base, ypl):
+@@ -289,16 +495,46 @@ def _list_cmd_calc_columns(base, ypl):
return (-columns[0], -columns[1], -columns[2])
class InfoCommand(YumCommand):
+ """A class containing methods needed by the cli to execute the
-+ update command.
++ info command.
+ """
+
def getNames(self):
@@ -152234,7 +153322,7 @@ index 4dcbea7..36b19b3 100644
try:
highlight = base.term.MODE['bold']
ypl = base.returnPkgLists(extcmds, installed_available=highlight)
-@@ -389,35 +624,95 @@ class InfoCommand(YumCommand):
+@@ -389,35 +625,95 @@ class InfoCommand(YumCommand):
return 0, []
def needTs(self, base, basecmd, extcmds):
@@ -152330,7 +153418,7 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _("Setting up Remove Process"))
try:
return base.erasePkgs(extcmds)
-@@ -425,9 +720,25 @@ class EraseCommand(YumCommand):
+@@ -425,9 +721,25 @@ class EraseCommand(YumCommand):
return 1, [str(e)]
def needTs(self, base, basecmd, extcmds):
@@ -152356,7 +153444,7 @@ index 4dcbea7..36b19b3 100644
return True
-@@ -442,12 +753,25 @@ class GroupsCommand(YumCommand):
+@@ -442,12 +754,25 @@ class GroupsCommand(YumCommand):
'groupinfo' : 'info'}
def getNames(self):
@@ -152382,7 +153470,7 @@ index 4dcbea7..36b19b3 100644
return _("Display, or use, the groups information")
def _grp_setup_doCommand(self, base):
-@@ -479,6 +803,14 @@ class GroupsCommand(YumCommand):
+@@ -479,32 +804,68 @@ class GroupsCommand(YumCommand):
return cmd, extcmds
def doCheck(self, base, basecmd, extcmds):
@@ -152397,9 +153485,48 @@ index 4dcbea7..36b19b3 100644
cmd, extcmds = self._grp_cmd(basecmd, extcmds)
checkEnabledRepo(base)
-@@ -505,6 +837,19 @@ class GroupsCommand(YumCommand):
+
+ if cmd in ('install', 'remove',
+ 'mark-install', 'mark-remove',
+- 'mark-members', 'info', 'mark-members-sync'):
++ 'info',
++ 'mark-packages', 'mark-packages-force', 'unmark-packages',
++ 'mark-packages-sync', 'mark-packages-sync-force'):
+ checkGroupArg(base, cmd, extcmds)
+
+ if cmd in ('install', 'remove', 'upgrade',
+ 'mark-install', 'mark-remove',
+- 'mark-members', 'mark-members-sync'):
++ 'mark-packages', 'mark-packages-force', 'unmark-packages',
++ 'mark-packages-sync', 'mark-packages-sync-force'):
+ checkRootUID(base)
+
+ if cmd in ('install', 'upgrade'):
+ checkGPGKey(base)
+
+- cmds = ('list', 'info', 'remove', 'install', 'upgrade', 'summary',
+- 'mark-install', 'mark-remove',
+- 'mark-members', 'mark-members-sync')
++ cmds = set(('list', 'info', 'remove', 'install', 'upgrade', 'summary'))
++ if base.conf.group_command == 'objects':
++ ocmds = ('mark-install', 'mark-remove',
++ 'mark-packages', 'mark-packages-force', 'unmark-packages',
++ 'mark-packages-sync', 'mark-packages-sync-force')
++ cmds.update(ocmds)
++
+ if cmd not in cmds:
+ base.logger.critical(_('Invalid groups sub-command, use: %s.'),
+ ", ".join(cmds))
raise cli.CliError
++ if base.conf.group_command != 'objects':
++ pass
++ elif not os.path.exists(base.igroups.filename):
++ base.logger.critical(_("There is no installed groups file."))
++ 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
++
def doCommand(self, base, basecmd, extcmds):
+ """Execute this command.
+
@@ -152417,7 +153544,66 @@ index 4dcbea7..36b19b3 100644
cmd, extcmds = self._grp_cmd(basecmd, extcmds)
self._grp_setup_doCommand(base)
-@@ -529,6 +874,14 @@ class GroupsCommand(YumCommand):
+@@ -524,39 +885,147 @@ class GroupsCommand(YumCommand):
+ if cmd == 'remove':
+ return base.removeGroups(extcmds)
+
++ if cmd == 'mark-install':
++ for strng in extcmds:
++ for group in base.comps.return_groups(strng):
++ base.igroups.add_group(group.groupid, group.packages)
++ base.igroups.save()
++ return 0, ['Marked install: ' + ','.join(extcmds)]
++
++ if cmd in ('mark-packages', 'mark-packages-force'):
++ if len(extcmds) < 2:
++ return 1, ['No group or package given']
++ igrps, grps = base._groupReturnGroups([extcmds[0]],
++ ignore_case=False)
++ if igrps is not None and len(igrps) != 1:
++ return 1, ['No group matched']
++ grp = igrps[0]
++ force = cmd == 'mark-packages-force'
++ for pkg in base.rpmdb.returnPackages(patterns=extcmds[1:]):
++ if not force and 'group_member' in pkg.yumdb_info:
++ continue
++ pkg.yumdb_info.group_member = grp.gid
++ grp.pkg_names.add(pkg.name)
++ base.igroups.changed = True
++ base.igroups.save()
++ return 0, ['Marked packages: ' + ','.join(extcmds[1:])]
++
++ if cmd == 'unmark-packages':
++ for pkg in base.rpmdb.returnPackages(patterns=extcmds):
++ if 'group_member' in pkg.yumdb_info:
++ del pkg.yumdb_info.group_member
++ return 0, ['UnMarked packages: ' + ','.join(extcmds)]
++
++ if cmd in ('mark-packages-sync', 'mark-packages-sync-force'):
++ igrps, grps = base._groupReturnGroups(extcmds,ignore_case=False)
++ if not igrps:
++ return 1, ['No group matched']
++ force = cmd == 'mark-packages-sync-force'
++ for grp in igrps:
++ for pkg in base.rpmdb.searchNames(grp.pkg_names):
++ if not force and 'group_member' in pkg.yumdb_info:
++ continue
++ pkg.yumdb_info.group_member = grp.gid
++ if force:
++ return 0, ['Marked packages-sync-force: '+','.join(extcmds)]
++ else:
++ return 0, ['Marked packages-sync: ' + ','.join(extcmds)]
++
++ if cmd == 'mark-remove':
++ for strng in extcmds:
++ for group in base.comps.return_groups(strng):
++ base.igroups.del_group(group.groupid)
++ base.igroups.save()
++ return 0, ['Marked remove: ' + ','.join(extcmds)]
++
++
+ except yum.Errors.YumBaseError, e:
+ return 1, [str(e)]
def needTs(self, base, basecmd, extcmds):
@@ -152432,7 +153618,9 @@ index 4dcbea7..36b19b3 100644
cmd, extcmds = self._grp_cmd(basecmd, extcmds)
if cmd in ('list', 'info', 'remove', 'summary'):
-@@ -536,27 +889,71 @@ class GroupsCommand(YumCommand):
+ return False
++ if cmd.startswith('mark') or cmd.startswith('unmark'):
++ return False
return True
def needTsRemove(self, base, basecmd, extcmds):
@@ -152505,7 +153693,18 @@ index 4dcbea7..36b19b3 100644
base.logger.debug(_("Making cache files for all metadata files."))
base.logger.debug(_("This may take a while depending on the speed of this computer"))
try:
-@@ -582,44 +979,134 @@ class MakeCacheCommand(YumCommand):
+@@ -572,9 +1041,7 @@ class MakeCacheCommand(YumCommand):
+ # we can't remove them until *LoadRepo() can do:
+ # 1. Download a .sqlite.bz2 and convert to .sqlite
+ # 2. Download a .xml.gz and convert to .xml.gz.sqlite
+- base.repos.populateSack(mdtype='metadata', cacheonly=1)
+- base.repos.populateSack(mdtype='filelists', cacheonly=1)
+- base.repos.populateSack(mdtype='otherdata', cacheonly=1)
++ base.repos.populateSack(mdtype='all', cacheonly=1)
+
+
+ except yum.Errors.YumBaseError, e:
+@@ -582,44 +1049,134 @@ class MakeCacheCommand(YumCommand):
return 0, [_('Metadata Cache Created')]
def needTs(self, base, basecmd, extcmds):
@@ -152640,12 +153839,12 @@ index 4dcbea7..36b19b3 100644
base.logger.debug("Searching Packages: ")
try:
return base.provides(extcmds)
-@@ -627,19 +1114,56 @@ class ProvidesCommand(YumCommand):
+@@ -627,19 +1184,56 @@ class ProvidesCommand(YumCommand):
return 1, [str(e)]
class CheckUpdateCommand(YumCommand):
+ """A class containing methods needed by the cli to execute the
-+ update command.
++ check-update command.
+ """
+
def getNames(self):
@@ -152697,7 +153896,7 @@ index 4dcbea7..36b19b3 100644
obscmds = ['obsoletes'] + extcmds
base.extcmds.insert(0, 'updates')
result = 0
-@@ -681,19 +1205,56 @@ class CheckUpdateCommand(YumCommand):
+@@ -681,19 +1275,56 @@ class CheckUpdateCommand(YumCommand):
return result, []
class SearchCommand(YumCommand):
@@ -152754,7 +153953,7 @@ index 4dcbea7..36b19b3 100644
base.logger.debug(_("Searching Packages: "))
try:
return base.search(extcmds)
-@@ -701,24 +1262,70 @@ class SearchCommand(YumCommand):
+@@ -701,24 +1332,70 @@ class SearchCommand(YumCommand):
return 1, [str(e)]
def needTs(self, base, basecmd, extcmds):
@@ -152770,7 +153969,7 @@ index 4dcbea7..36b19b3 100644
class UpgradeCommand(YumCommand):
+ """A class containing methods needed by the cli to execute the
-+ update command.
++ upgrade command.
+ """
+
def getNames(self):
@@ -152825,7 +154024,7 @@ index 4dcbea7..36b19b3 100644
base.conf.obsoletes = 1
self.doneCommand(base, _("Setting up Upgrade Process"))
try:
-@@ -727,25 +1334,64 @@ class UpgradeCommand(YumCommand):
+@@ -727,25 +1404,64 @@ class UpgradeCommand(YumCommand):
return 1, [str(e)]
class LocalInstallCommand(YumCommand):
@@ -152890,7 +154089,7 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _("Setting up Local Package Process"))
updateonly = basecmd == 'localupdate'
-@@ -755,19 +1401,61 @@ class LocalInstallCommand(YumCommand):
+@@ -755,19 +1471,61 @@ class LocalInstallCommand(YumCommand):
return 1, [str(e)]
def needTs(self, base, basecmd, extcmds):
@@ -152953,7 +154152,7 @@ index 4dcbea7..36b19b3 100644
base.logger.debug(_("Searching Packages for Dependency:"))
try:
return base.resolveDepCli(extcmds)
-@@ -775,19 +1463,56 @@ class ResolveDepCommand(YumCommand):
+@@ -775,19 +1533,56 @@ class ResolveDepCommand(YumCommand):
return 1, [str(e)]
class ShellCommand(YumCommand):
@@ -153010,7 +154209,7 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _('Setting up Yum Shell'))
try:
return base.doShell()
-@@ -795,23 +1520,69 @@ class ShellCommand(YumCommand):
+@@ -795,23 +1590,69 @@ class ShellCommand(YumCommand):
return 1, [str(e)]
def needTs(self, base, basecmd, extcmds):
@@ -153080,7 +154279,7 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _("Finding dependencies: "))
try:
return base.deplist(extcmds)
-@@ -820,17 +1591,46 @@ class DepListCommand(YumCommand):
+@@ -820,17 +1661,46 @@ class DepListCommand(YumCommand):
class RepoListCommand(YumCommand):
@@ -153127,7 +154326,7 @@ index 4dcbea7..36b19b3 100644
def _repo_size(repo):
ret = 0
for pkg in repo.sack.returnPackages():
-@@ -866,6 +1666,13 @@ class RepoListCommand(YumCommand):
+@@ -866,6 +1736,13 @@ class RepoListCommand(YumCommand):
except yum.Errors.RepoError:
if verbose:
raise
@@ -153141,7 +154340,212 @@ index 4dcbea7..36b19b3 100644
repos = base.repos.repos.values()
repos.sort()
-@@ -1088,21 +1895,54 @@ class RepoListCommand(YumCommand):
+@@ -924,111 +1801,108 @@ class RepoListCommand(YumCommand):
+ ui_enabled = dhibeg + _('disabled') + hiend
+ ui_endis_wid = utf8_width(_('disabled'))
+
+- if True: # Here to make patch smaller, TODO: rm
+- if not verbose:
+- rid = str(repo)
+- if enabled and repo.metalink:
+- mdts = repo.metalink_data.repomd.timestamp
+- if mdts > repo.repoXML.timestamp:
+- rid = '*' + rid
+- cols.append((rid, repo.name,
+- (ui_enabled, ui_endis_wid), ui_num))
++ if not verbose:
++ rid = str(repo)
++ if enabled and repo.metalink:
++ mdts = repo.metalink_data.repomd.timestamp
++ if mdts > repo.repoXML.timestamp:
++ rid = '*' + rid
++ cols.append((rid, repo.name,
++ (ui_enabled, ui_endis_wid), ui_num))
++ else:
++ if enabled:
++ md = repo.repoXML
+ else:
++ md = None
++ out = [base.fmtKeyValFill(_("Repo-id : "), repo),
++ base.fmtKeyValFill(_("Repo-name : "), repo.name)]
++
++ if force_show or extcmds:
++ out += [base.fmtKeyValFill(_("Repo-status : "),
++ ui_enabled)]
++ if md and md.revision is not None:
++ out += [base.fmtKeyValFill(_("Repo-revision: "),
++ md.revision)]
++ if md and md.tags['content']:
++ tags = md.tags['content']
++ out += [base.fmtKeyValFill(_("Repo-tags : "),
++ ", ".join(sorted(tags)))]
++
++ if md and md.tags['distro']:
++ for distro in sorted(md.tags['distro']):
++ tags = md.tags['distro'][distro]
++ out += [base.fmtKeyValFill(_("Repo-distro-tags: "),
++ "[%s]: %s" % (distro,
++ ", ".join(sorted(tags))))]
++
++ if md:
++ out += [base.fmtKeyValFill(_("Repo-updated : "),
++ time.ctime(md.timestamp)),
++ base.fmtKeyValFill(_("Repo-pkgs : "),ui_num),
++ base.fmtKeyValFill(_("Repo-size : "),ui_size)]
++
++ if hasattr(repo, '_orig_baseurl'):
++ baseurls = repo._orig_baseurl
++ else:
++ baseurls = repo.baseurl
++ if baseurls:
++ out += [base.fmtKeyValFill(_("Repo-baseurl : "),
++ ", ".join(baseurls))]
++
++ if enabled:
++ # This needs to be here due to the mirrorlists are
++ # metalinks hack.
++ repo.urls
++ if repo.metalink:
++ out += [base.fmtKeyValFill(_("Repo-metalink: "),
++ repo.metalink)]
+ if enabled:
+- md = repo.repoXML
+- else:
+- md = None
+- out = [base.fmtKeyValFill(_("Repo-id : "), repo),
+- base.fmtKeyValFill(_("Repo-name : "), repo.name)]
+-
+- if force_show or extcmds:
+- out += [base.fmtKeyValFill(_("Repo-status : "),
+- ui_enabled)]
+- if md and md.revision is not None:
+- out += [base.fmtKeyValFill(_("Repo-revision: "),
+- md.revision)]
+- if md and md.tags['content']:
+- tags = md.tags['content']
+- out += [base.fmtKeyValFill(_("Repo-tags : "),
+- ", ".join(sorted(tags)))]
+-
+- if md and md.tags['distro']:
+- for distro in sorted(md.tags['distro']):
+- tags = md.tags['distro'][distro]
+- out += [base.fmtKeyValFill(_("Repo-distro-tags: "),
+- "[%s]: %s" % (distro,
+- ", ".join(sorted(tags))))]
+-
+- if md:
+- out += [base.fmtKeyValFill(_("Repo-updated : "),
+- time.ctime(md.timestamp)),
+- base.fmtKeyValFill(_("Repo-pkgs : "),ui_num),
+- base.fmtKeyValFill(_("Repo-size : "),ui_size)]
+-
+- if hasattr(repo, '_orig_baseurl'):
+- baseurls = repo._orig_baseurl
+- else:
+- baseurls = repo.baseurl
+- if baseurls:
+- out += [base.fmtKeyValFill(_("Repo-baseurl : "),
+- ", ".join(baseurls))]
+-
+- if enabled:
+- # This needs to be here due to the mirrorlists are
+- # metalinks hack.
+- repo.urls
+- if repo.metalink:
+- out += [base.fmtKeyValFill(_("Repo-metalink: "),
+- repo.metalink)]
+- if enabled:
+- ts = repo.metalink_data.repomd.timestamp
+- out += [base.fmtKeyValFill(_(" Updated : "),
+- time.ctime(ts))]
+- elif repo.mirrorlist:
+- out += [base.fmtKeyValFill(_("Repo-mirrors : "),
+- repo.mirrorlist)]
+- if enabled and repo.urls and not baseurls:
+- url = repo.urls[0]
+- if len(repo.urls) > 1:
+- url += ' (%d more)' % (len(repo.urls) - 1)
+- out += [base.fmtKeyValFill(_("Repo-baseurl : "),
+- url)]
+-
+- if not os.path.exists(repo.metadata_cookie):
+- last = _("Unknown")
+- else:
+- last = os.stat(repo.metadata_cookie).st_mtime
+- last = time.ctime(last)
++ ts = repo.metalink_data.repomd.timestamp
++ out += [base.fmtKeyValFill(_(" Updated : "),
++ time.ctime(ts))]
++ elif repo.mirrorlist:
++ out += [base.fmtKeyValFill(_("Repo-mirrors : "),
++ repo.mirrorlist)]
++ if enabled and repo.urls and not baseurls:
++ url = repo.urls[0]
++ if len(repo.urls) > 1:
++ url += ' (%d more)' % (len(repo.urls) - 1)
++ out += [base.fmtKeyValFill(_("Repo-baseurl : "), url)]
++
++ if not os.path.exists(repo.metadata_cookie):
++ last = _("Unknown")
++ else:
++ last = os.stat(repo.metadata_cookie).st_mtime
++ last = time.ctime(last)
+
+- if repo.metadata_expire <= -1:
+- num = _("Never (last: %s)") % last
+- elif not repo.metadata_expire:
+- num = _("Instant (last: %s)") % last
+- else:
+- num = _num2ui_num(repo.metadata_expire)
+- num = _("%s second(s) (last: %s)") % (num, last)
++ if repo.metadata_expire <= -1:
++ num = _("Never (last: %s)") % last
++ elif not repo.metadata_expire:
++ num = _("Instant (last: %s)") % last
++ else:
++ num = _num2ui_num(repo.metadata_expire)
++ num = _("%s second(s) (last: %s)") % (num, last)
+
+- out += [base.fmtKeyValFill(_("Repo-expire : "), num)]
++ out += [base.fmtKeyValFill(_("Repo-expire : "), num)]
+
+- if repo.exclude:
+- out += [base.fmtKeyValFill(_("Repo-exclude : "),
+- ", ".join(repo.exclude))]
++ if repo.exclude:
++ out += [base.fmtKeyValFill(_("Repo-exclude : "),
++ ", ".join(repo.exclude))]
+
+- if repo.includepkgs:
+- out += [base.fmtKeyValFill(_("Repo-include : "),
+- ", ".join(repo.includepkgs))]
++ if repo.includepkgs:
++ out += [base.fmtKeyValFill(_("Repo-include : "),
++ ", ".join(repo.includepkgs))]
+
+- if ui_excludes_num:
+- out += [base.fmtKeyValFill(_("Repo-excluded: "),
+- ui_excludes_num)]
++ if ui_excludes_num:
++ out += [base.fmtKeyValFill(_("Repo-excluded: "),
++ ui_excludes_num)]
+
+- if repo.repofile:
+- out += [base.fmtKeyValFill(_("Repo-filename: "),
+- repo.repofile)]
++ if repo.repofile:
++ out += [base.fmtKeyValFill(_("Repo-filename: "),
++ repo.repofile)]
+
+- base.verbose_logger.log(logginglevels.DEBUG_3,
+- "%s\n",
+- "\n".join(map(misc.to_unicode, out)))
++ base.verbose_logger.log(logginglevels.DEBUG_3, "%s\n",
++ "\n".join(map(misc.to_unicode, out)))
+
+ if not verbose and cols:
+ # Work out the first (id) and last (enabled/disalbed/count),
+@@ -1088,21 +1962,54 @@ class RepoListCommand(YumCommand):
return 0, ['repolist: ' +to_unicode(locale.format("%d", tot_num, True))]
def needTs(self, base, basecmd, extcmds):
@@ -153196,7 +154600,7 @@ index 4dcbea7..36b19b3 100644
if len(extcmds) == 0:
base.usage()
raise cli.CliError
-@@ -1147,28 +1987,85 @@ class HelpCommand(YumCommand):
+@@ -1147,28 +2054,85 @@ class HelpCommand(YumCommand):
return help_output
def doCommand(self, base, basecmd, extcmds):
@@ -153282,7 +154686,7 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _("Setting up Reinstall Process"))
try:
return base.reinstallPkgs(extcmds)
-@@ -1177,25 +2074,73 @@ class ReInstallCommand(YumCommand):
+@@ -1177,25 +2141,73 @@ class ReInstallCommand(YumCommand):
return 1, [to_unicode(e)]
def getSummary(self):
@@ -153356,7 +154760,7 @@ index 4dcbea7..36b19b3 100644
self.doneCommand(base, _("Setting up Downgrade Process"))
try:
return base.downgradePkgs(extcmds)
-@@ -1203,23 +2148,65 @@ class DowngradeCommand(YumCommand):
+@@ -1203,23 +2215,65 @@ class DowngradeCommand(YumCommand):
return 1, [str(e)]
def getSummary(self):
@@ -153422,7 +154826,7 @@ index 4dcbea7..36b19b3 100644
vcmd = 'installed'
if extcmds:
vcmd = extcmds[0]
-@@ -1344,6 +2331,14 @@ class VersionCommand(YumCommand):
+@@ -1344,6 +2398,14 @@ class VersionCommand(YumCommand):
return 0, ['version']
def needTs(self, base, basecmd, extcmds):
@@ -153437,7 +154841,7 @@ index 4dcbea7..36b19b3 100644
vcmd = 'installed'
if extcmds:
vcmd = extcmds[0]
-@@ -1354,23 +2349,62 @@ class VersionCommand(YumCommand):
+@@ -1354,23 +2416,62 @@ class VersionCommand(YumCommand):
class HistoryCommand(YumCommand):
@@ -153501,7 +154905,7 @@ index 4dcbea7..36b19b3 100644
return 2, ["Repeating transaction %u" % (old.tid,)]
def _hcmd_undo(self, base, extcmds):
-@@ -1426,12 +2460,54 @@ class HistoryCommand(YumCommand):
+@@ -1426,12 +2527,54 @@ class HistoryCommand(YumCommand):
def _hcmd_new(self, base, extcmds):
base.history._create_db_file()
@@ -153557,7 +154961,7 @@ index 4dcbea7..36b19b3 100644
if extcmds and extcmds[0] not in cmds:
base.logger.critical(_('Invalid history sub-command, use: %s.'),
", ".join(cmds))
-@@ -1444,6 +2520,19 @@ class HistoryCommand(YumCommand):
+@@ -1444,6 +2587,19 @@ class HistoryCommand(YumCommand):
raise cli.CliError
def doCommand(self, base, basecmd, extcmds):
@@ -153577,7 +154981,7 @@ index 4dcbea7..36b19b3 100644
vcmd = 'list'
if extcmds:
vcmd = extcmds[0]
-@@ -1468,12 +2557,26 @@ class HistoryCommand(YumCommand):
+@@ -1468,12 +2624,26 @@ class HistoryCommand(YumCommand):
ret = self._hcmd_rollback(base, extcmds)
elif vcmd == 'new':
ret = self._hcmd_new(base, extcmds)
@@ -153604,7 +155008,7 @@ index 4dcbea7..36b19b3 100644
vcmd = 'list'
if extcmds:
vcmd = extcmds[0]
-@@ -1481,16 +2584,46 @@ class HistoryCommand(YumCommand):
+@@ -1481,16 +2651,46 @@ class HistoryCommand(YumCommand):
class CheckRpmdbCommand(YumCommand):
@@ -153651,7 +155055,7 @@ index 4dcbea7..36b19b3 100644
chkcmd = 'all'
if extcmds:
chkcmd = extcmds
-@@ -1505,19 +2638,57 @@ class CheckRpmdbCommand(YumCommand):
+@@ -1505,19 +2705,57 @@ class CheckRpmdbCommand(YumCommand):
return rc, ['%s %s' % (basecmd, chkcmd)]
def needTs(self, base, basecmd, extcmds):
@@ -153709,7 +155113,7 @@ index 4dcbea7..36b19b3 100644
if not extcmds:
base.logger.critical(_("No saved transaction file specified."))
raise cli.CliError
-@@ -1533,5 +2704,13 @@ class LoadTransactionCommand(YumCommand):
+@@ -1533,5 +2771,13 @@ class LoadTransactionCommand(YumCommand):
def needTs(self, base, basecmd, extcmds):
@@ -153724,7 +155128,7 @@ index 4dcbea7..36b19b3 100644
return True
diff --git a/yummain.py b/yummain.py
-index 9f79f4f..12582d2 100755
+index 9f79f4f..e1a9702 100755
--- a/yummain.py
+++ b/yummain.py
@@ -29,13 +29,13 @@ from yum import Errors
@@ -153744,7 +155148,7 @@ index 9f79f4f..12582d2 100755
yum.misc.setup_locale(override_time=True)
-@@ -102,15 +102,15 @@ def main(args):
+@@ -102,15 +102,21 @@ def main(args):
return exFatal(e)
# Try to open the current directory to see if we have
@@ -153760,10 +155164,16 @@ index 9f79f4f..12582d2 100755
else:
- close(f)
+ f.close()
++ try:
++ os.getcwd()
++ except OSError, e:
++ if e.errno == errno.ENOENT:
++ logger.critical(_('No getcwd() access in current directory, moving to /'))
++ os.chdir("/")
lockerr = ""
while True:
-@@ -120,16 +120,16 @@ def main(args):
+@@ -120,16 +126,16 @@ def main(args):
if exception2msg(e) != lockerr:
lockerr = exception2msg(e)
logger.critical(lockerr)
@@ -153785,7 +155195,7 @@ index 9f79f4f..12582d2 100755
else:
logger.critical(_("Another app is currently holding the yum lock; exiting as configured by exit_on_lock"))
return 1
-@@ -238,9 +238,15 @@ def main(args):
+@@ -238,9 +244,15 @@ def main(args):
rpmdb_warn_checks()
return_code = result
if base._ts_save_file:
@@ -153802,7 +155212,7 @@ index 9f79f4f..12582d2 100755
else:
verbose_logger.log(logginglevels.INFO_2, _('Complete!'))
-@@ -248,6 +254,11 @@ def main(args):
+@@ -248,6 +260,11 @@ def main(args):
return return_code
def hotshot(func, *args, **kwargs):
@@ -153814,7 +155224,7 @@ index 9f79f4f..12582d2 100755
import hotshot.stats
fn = os.path.expanduser("~/yum.prof")
prof = hotshot.Profile(fn)
-@@ -257,6 +268,11 @@ def hotshot(func, *args, **kwargs):
+@@ -257,6 +274,11 @@ def hotshot(func, *args, **kwargs):
return rc
def cprof(func, *args, **kwargs):
@@ -153826,7 +155236,7 @@ index 9f79f4f..12582d2 100755
import cProfile, pstats
fn = os.path.expanduser("~/yum.prof")
prof = cProfile.Profile()
-@@ -266,6 +282,10 @@ def cprof(func, *args, **kwargs):
+@@ -266,6 +288,10 @@ def cprof(func, *args, **kwargs):
return rc
def print_stats(stats):
@@ -153837,7 +155247,7 @@ index 9f79f4f..12582d2 100755
stats.strip_dirs()
stats.sort_stats('time', 'calls')
stats.print_stats(20)
-@@ -273,7 +293,14 @@ def print_stats(stats):
+@@ -273,7 +299,14 @@ def print_stats(stats):
stats.print_stats(40)
def user_main(args, exit_code=False):
diff --git a/yum-distro-configs.patch b/yum-distro-configs.patch
index 28b7856..a4608a2 100644
--- a/yum-distro-configs.patch
+++ b/yum-distro-configs.patch
@@ -1,17 +1,19 @@
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,9 +45,9 @@
+@@ -45,10 +45,10 @@
# Alter/patch these to change the default checking...
__pkgs_gpgcheck_default__ = False
__repo_gpgcheck_default__ = False
-__main_multilib_policy_default__ = 'all'
-__main_failovermethod_default__ = 'roundrobin'
-__main_installonly_limit_default__ = 0
+-__group_command_default__ = 'compat'
+__main_multilib_policy_default__ = 'best'
+__main_failovermethod_default__ = 'priority'
+__main_installonly_limit_default__ = 3
-
++__group_command_default__ = 'objects'
+
class Option(object):
"""
Only in yum-3.4.3/yum: config.py~
diff --git a/yum.spec b/yum.spec
index abc7153..1e133e0 100644
--- a/yum.spec
+++ b/yum.spec
@@ -18,7 +18,7 @@
Summary: RPM package installer/updater/manager
Name: yum
Version: 3.4.3
-Release: 16%{?dist}
+Release: 17%{?dist}
License: GPLv2+
Group: System Environment/Base
Source0: http://yum.baseurl.org/download/3.4/%{name}-%{version}.tar.gz
@@ -311,6 +311,11 @@ exit 0
%endif
%changelog
+* Fri Jan 20 2012 James Antill <james at fedoraproject.org> - 3.4.3-17
+- update to latest HEAD
+- Added group_command, and changed to groups as objects by default.
+- Minor updates.
+
* Tue Dec 13 2011 James Antill <james at fedoraproject.org> - 3.4.3-16
- update to latest HEAD
- Have users always use their own dirs.
More information about the scm-commits
mailing list