commit 05c9c11fbfff0e9b6f6743d6167840b15ec74ea2 Author: James Antill Date: Tue Dec 21 12:31:49 2010 -0500 Add first attempt of the installed groups module. 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 + +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/cli.py b/cli.py index 06bfb68..b00e130 100644 --- a/cli.py +++ b/cli.py @@ -78,11 +78,14 @@ class YumBaseCli(yum.YumBase, output.YumOutput): self.registerCommand(yumcommands.InfoCommand()) self.registerCommand(yumcommands.ListCommand()) self.registerCommand(yumcommands.EraseCommand()) - self.registerCommand(yumcommands.GroupCommand()) - self.registerCommand(yumcommands.GroupListCommand()) - self.registerCommand(yumcommands.GroupInstallCommand()) - self.registerCommand(yumcommands.GroupRemoveCommand()) - self.registerCommand(yumcommands.GroupInfoCommand()) + if True: + self.registerCommand(yumcommands.GroupsCommand()) + else: + self.registerCommand(yumcommands.GroupCommand()) + self.registerCommand(yumcommands.GroupListCommand()) + self.registerCommand(yumcommands.GroupInstallCommand()) + self.registerCommand(yumcommands.GroupRemoveCommand()) + self.registerCommand(yumcommands.GroupInfoCommand()) self.registerCommand(yumcommands.MakeCacheCommand()) self.registerCommand(yumcommands.CleanCommand()) self.registerCommand(yumcommands.ProvidesCommand()) @@ -1207,6 +1210,50 @@ class YumBaseCli(yum.YumBase, output.YumOutput): return 0, [_('Done')] + def returnGroupSummary(self, userlist): + + uservisible=1 + + if len(userlist) > 0: + if userlist[0] == 'hidden': + uservisible=0 + userlist.pop(0) + if not userlist: + userlist = None # Match everything... + + installed, available = self.doGroupLists(uservisible=uservisible, + patterns=userlist) + + def _out_grp(sect, num): + if not num: + return + self.verbose_logger.log(yum.logginglevels.INFO_2, '%s %u', sect,num) + done = 0 + for group in installed: + if group.langonly: continue + done += 1 + _out_grp(_('Installed Groups:'), done) + + done = 0 + for group in installed: + if not group.langonly: continue + done += 1 + _out_grp(_('Installed Language Groups:'), done) + + done = False + for group in available: + if group.langonly: continue + done += 1 + _out_grp(_('Available Groups:'), done) + + done = False + for group in available: + if not group.langonly: continue + done += 1 + _out_grp(_('Available Language Groups:'), done) + + return 0, [_('Done')] + def returnGroupInfo(self, userlist): """returns complete information on a list of groups""" for strng in userlist: @@ -1220,7 +1267,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput): return 0, [] - def installGroups(self, grouplist): + def installGroups(self, grouplist, upgrade=False): """for each group requested do 'selectGroup' on them.""" pkgs_used = [] @@ -1232,7 +1279,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 diff --git a/output.py b/output.py index a8bf1cc..d68f090 100755 --- a/output.py +++ b/output.py @@ -752,10 +752,28 @@ class YumOutput: data[d][v] += 1 def _displayPkgsFromNames(self, pkg_names, verbose, pkg_names2pkgs, - indent=' ', columns=None): + indent=' ', columns=None, igroup_data=None): if not verbose: for item in sorted(pkg_names): - print '%s%s' % (indent, item) + if not igroup_data: + print '%s%s' % (indent, item) + continue + + assert item in igroup_data + if item not in igroup_data or igroup_data[item] == 'available': + print '%s+%s' % (indent, item) # Group up/in will install it + elif igroup_data[item] == 'installed': + print '%s=%s' % (indent, item) # Installed via. group + elif igroup_data[item] == 'blacklisted-installed': + if False: # Not sure it's worth listing these... + continue # On the other hand, there's mark-packages + + print '%s %s' % (indent, item) # Installed, not via. group + else: + assert igroup_data[item] == 'blacklisted-available' + if False: # Not sure it's worth listing these... + continue + print '%s-%s' % (indent, item) # Not installed, and won't be else: for item in sorted(pkg_names): if item not in pkg_names2pkgs: @@ -779,9 +797,25 @@ class YumOutput: verb = self.verbose_logger.isEnabledFor(logginglevels.DEBUG_3) 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: @@ -804,7 +838,13 @@ 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""" diff --git a/yum/__init__.py b/yum/__init__.py index eb34a19..cdd19cd 100644 --- a/yum/__init__.py +++ b/yum/__init__.py @@ -73,6 +73,7 @@ import logginglevels import yumRepo import callbacks import yum.history +import yum.igroups import warnings warnings.simplefilter("ignore", Errors.YumFutureDeprecationWarning) @@ -175,6 +176,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 @@ -210,6 +212,9 @@ class YumBase(depsolve.Depsolve): if self._history is not None: self.history.close() + if self._igroups is not None: + self.igroups.close() + if self._repos: self._repos.close() @@ -842,6 +847,14 @@ class YumBase(depsolve.Depsolve): db_path=pdb_path) 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 repos = property(fget=lambda self: self._getRepos(), fset=lambda self, value: setattr(self, "_repos", value), @@ -878,12 +891,16 @@ class YumBase(depsolve.Depsolve): fset=lambda self, value: setattr(self, "_history",value), fdel=lambda self: setattr(self, "_history", None), doc="Yum History Object") - pkgtags = property(fget=lambda self: self._getTags(), fset=lambda self, value: setattr(self, "_tags",value), fdel=lambda self: setattr(self, "_tags", None), doc="Yum Package Tags 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") + def doSackFilelistPopulate(self): """convenience function to populate the repos with the filelist metadata @@ -1477,6 +1494,8 @@ class YumBase(depsolve.Depsolve): # sync up what just happened versus what is in the rpmdb if not self.ts.isTsFlagSet(rpm.RPMTRANS_FLAG_TEST): self.verifyTransaction(resultobject) + if self.conf.groups_are_real: + self.igroups.save() return resultobject def verifyTransaction(self, resultobject=None): @@ -1537,6 +1556,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: @@ -1547,6 +1570,8 @@ 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: @@ -2669,6 +2694,58 @@ 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 not self.conf.groups_are_real: + 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.groups_are_real: + 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.groups_are_real: + 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 @@ -2680,14 +2757,24 @@ 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) @@ -2699,7 +2786,17 @@ class YumBase(depsolve.Depsolve): available.append(grp) else: available.append(grp) - + + 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) @@ -2713,13 +2810,19 @@ class YumBase(depsolve.Depsolve): raise Errors.GroupsError, _("No Group named %s exists") % 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 @@ -2750,7 +2853,7 @@ 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, upgrade=False): """mark all the packages in the group to be installed returns a list of transaction members it added to the transaction set @@ -2760,13 +2863,13 @@ class YumBase(depsolve.Depsolve): """ if not self.comps.has_group(grpid): - raise Errors.GroupsError, _("No Group named %s exists") % grpid + raise Errors.GroupsError, _("No Group named %s exists in the repos.") % grpid txmbrs_used = [] thesegroups = self.comps.return_groups(grpid) - + if not thesegroups: - raise Errors.GroupsError, _("No Group named %s exists") % grpid + raise Errors.GroupsError, _("No Group named %s exists in the repos.") % grpid package_types = self.conf.group_package_types if group_package_types: @@ -2789,11 +2892,39 @@ class YumBase(depsolve.Depsolve): if not pkgs: self.logger.critical(_('Warning: Group %s does not have any packages.'), thisgroup.groupid) + 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())) for pkg in pkgs: + + 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 + try: - txmbrs = self.install(name = pkg) + if igroup_data[pkg] == 'installed': + txmbrs = self.update(name = pkg) + else: + txmbrs = self.install(name = pkg) + 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) @@ -2806,6 +2937,7 @@ class YumBase(depsolve.Depsolve): if enable_group_conditionals is not None: # has to be this way so we can set it to False group_conditionals = enable_group_conditionals + # FIXME: What do we do about group conditionals and groups_are_real? if group_conditionals: for condreq, cond in thisgroup.conditional_packages.iteritems(): if self.isPackageInstalled(cond): @@ -3164,20 +3296,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] == '@' @@ -3563,7 +3699,11 @@ class YumBase(depsolve.Depsolve): if new is None: continue tx_return.extend(self.update(po=new)) - + + if self.conf.groups_are_real: + for igrp in self.igroups.groups: + tx_return.extend(self._at_groupupgrade(igrp)) + return tx_return # complications @@ -3585,7 +3725,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']) (e, m, u) = self.rpmdb.matchPackageNames([kwargs['pattern']]) instpkgs.extend(e) diff --git a/yum/config.py b/yum/config.py index 14eb992..3f1abbf 100644 --- a/yum/config.py +++ b/yum/config.py @@ -745,6 +745,9 @@ class YumConf(StartupConf): loadts_ignorerpm = BoolOption(False) clean_requirements_on_remove = BoolOption(False) + + groups_are_real = BoolOption(True) + _reposlist = [] def dump(self): diff --git a/yumcommands.py b/yumcommands.py index ecce347..c136b2e 100644 --- a/yumcommands.py +++ b/yumcommands.py @@ -432,6 +432,164 @@ class GroupCommand(YumCommand): except yum.Errors.YumBaseError, e: return 1, [str(e)] +class GroupsCommand(YumCommand): + """ Single sub-command interface for most groups interaction. """ + + direct_commands = {'grouplist' : 'list', + 'groupinstall' : 'install', + 'groupupdate' : 'install', + 'groupremove' : 'remove', + 'grouperase' : 'remove', + 'groupinfo' : 'info'} + + def getNames(self): + return ['groups', 'group'] + self.direct_commands.keys() + + def getUsage(self): + return "[list|info|summary|install|upgrade|remove|mark] [GROUP]" + + def getSummary(self): + return _("Display, or use, the groups information") + + def _grp_setup_doCommand(self, base): + self.doneCommand(base, _("Setting up Group Process")) + + base.doRepoSetup(dosack=0) + try: + base.doGroupSetup() + except yum.Errors.GroupsError: + return 1, [_('No Groups on which to run command')] + except yum.Errors.YumBaseError, e: + return 1, [str(e)] + + def _grp_cmd(self, basecmd, extcmds): + if basecmd in self.direct_commands: + cmd = self.direct_commands[basecmd] + elif extcmds: + cmd = extcmds[0] + extcmds = extcmds[1:] + else: + cmd = 'summary' + + remap = {'update' : 'upgrade', + 'erase' : 'remove', + 'mark-erase' : 'mark-remove', + } + cmd = remap.get(cmd, cmd) + + return cmd, extcmds + + def doCheck(self, base, basecmd, extcmds): + cmd, extcmds = self._grp_cmd(basecmd, extcmds) + + checkEnabledRepo(base) + + if cmd in ('install', 'remove', + 'mark-install', 'mark-remove', + 'mark-members', 'info', 'mark-members-sync'): + checkGroupArg(base, cmd, extcmds) + + if cmd in ('install', 'remove', 'upgrade', + 'mark-install', 'mark-remove', + 'mark-members', 'mark-members-sync'): + 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') + if cmd not in cmds: + base.logger.critical(_('Invalid groups sub-command, use: %s.'), + ", ".join(cmds)) + raise cli.CliError + + if 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 history DB.")) + raise cli.CliError + + def doCommand(self, base, basecmd, extcmds): + cmd, extcmds = self._grp_cmd(basecmd, extcmds) + + self._grp_setup_doCommand(base) + if cmd == 'summary': + return base.returnGroupSummary(extcmds) + + if cmd == 'list': + return base.returnGroupLists(extcmds) + + try: + if cmd == 'info': + return base.returnGroupInfo(extcmds) + if cmd == 'install': + return base.installGroups(extcmds) + if cmd == 'upgrade': + return base.installGroups(extcmds, upgrade=True) + 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 == 'mark-members': + if len(extcmds) < 2: + return 1, ['No group or package given'] + igrps, grps = base._groupReturnGroups([extcmds[0]], + ignore_case=False) + if len(igrps) != 1: + return 1, ['No group matched'] + grp = igrps[0] + for pkg in base.rpmdb.returnPackages(patterns=extcmds[1:]): + pkg.yumdb_info.group_member = grp.gid + grp.pkg_names.add(pkg.name) + base.igroups.save() + return 0, ['Marked members: ' + ','.join(extcmds)] + + if cmd == 'mark-members-sync': + igrps, grps = base._groupReturnGroups(extcmds,ignore_case=False) + if not igrps: + return 1, ['No group matched'] + for grp in igrps: + for pkg in base.rpmdb.searchNames(grp.pkg_names): + pkg.yumdb_info.group_member = grp.gid + return 0, ['Marked members-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): + cmd, extcmds = self._grp_cmd(basecmd, extcmds) + + if cmd in ('list', 'info', 'remove', 'summary'): + return False + if cmd.startswith('mark'): + return False + + return True + + def needTsRemove(self, base, basecmd, extcmds): + cmd, extcmds = self._grp_cmd(basecmd, extcmds) + + if cmd in ('remove',): + return True + return False + class GroupListCommand(GroupCommand): def getNames(self):