#!/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 2008 Red Hat, Inc written by Seth Vidal skvidal@fedoraproject.org import sys sys.path.insert(0,'/usr/share/yum-cli') import yum from yum.constants import * from cli import * from utils import YumUtilBase from urlparse import urljoin from urlgrabber.progress import TextMeter _requires_cache = {} ignore_list = ['glibc', 'bash', 'libgcc'] class YumRemoveWithLeaves(YumUtilBase): NAME = 'yum-remove-with-leaves' VERSION = '1.0' USAGE = '"usage: yum-remove-with-leaves [options] package1 [package2] [package..]' def __init__(self): YumUtilBase.__init__(self, YumRemoveWithLeaves.NAME, YumRemoveWithLeaves.VERSION, YumRemoveWithLeaves.USAGE) self.logger = logging.getLogger("yum.verbose.cli.yumbuilremovewithleaves") self.main() def main(self): # Add util commandline options to the yum-cli ones self.optparser = self.getOptionParser() # Parse the commandline option and setup the basics. try: opts = self.doUtilConfigSetup() except yum.Errors.RepoError, e: self.logger.error("Cannot handle specific enablerepo/disablerepo options.") sys.exit(50) # Check if there is anything to do. if len(self.cmds) < 1: self.optparser.print_help() sys.exit(0) if self.conf.uid != 0: self.logger.error("Error: You must be root to remove packages") sys.exit(1) # Setup yum (Ts, RPM db, Repo & Sack) self.doUtilYumSetup() # Do the real action # solve for each srpm and put the pkgs into a ts self.get_removed_pkgs() self.buildTransaction() if len(self.tsInfo) < 1: print 'Nothing to remove' sys.exit() self.doTransaction() def _requires_this_package(self, pkg): if _requires_cache.has_key(pkg): return _requires_cache[pkg] requirers = {} for prov in pkg.provides: for req_pkg in self.rpmdb.getRequires(prov[0], prov[1], prov[2]): if req_pkg == pkg: continue requirers[req_pkg.pkgtup] = 1 # do filelists, too :( for prov in pkg.filelist + pkg.dirlist + pkg.ghostlist: for req_pkg in self.rpmdb.getRequires(prov): if req_pkg == pkg: continue requirers[req_pkg.pkgtup] = 1 _requires_cache[pkg] = requirers.keys() return requirers.keys() def get_removed_pkgs(self): for pkg_patt in self.cmds: self.remove(pattern=pkg_patt) oldlen = 0 while oldlen != len(self.tsInfo): oldlen = len(self.tsInfo) for txmbr in self.tsInfo.getMembersWithState(output_states=TS_REMOVE_STATES): for req in txmbr.po.requires: if req[0].startswith('rpmlib('): continue for pkg in self.rpmdb.getProvides(req[0], req[1], req[2]): if pkg.pkgtup in [ txmbr.po.pkgtup for txmbr in self.tsInfo.getMembersWithState(output_states=TS_REMOVE_STATES) ]: continue # skip ones already marked for remove, kinda pointless if pkg.name in ignore_list: # there are some pkgs which are NEVER going to be leafremovals continue non_removed_requires = [] for req_pkgtup in self._requires_this_package(pkg): pkgtups = [ txmbr.po.pkgtup for txmbr in self.tsInfo.getMembersWithState(output_states=TS_REMOVE_STATES) ] if req_pkgtup not in pkgtups: non_removed_requires.append(req_pkgtup) if not non_removed_requires: self.verbose_logger.log(yum.logginglevels.INFO_2, 'removing %s. It is not required by anything else' % pkg) self.remove(pkg) if __name__ == '__main__': util = YumRemoveWithLeaves()