[PATCH] package-cleanup output formatting patch set

Ville Skyttä <[email protected]>
Newsgroups gmane.linux.rpm.yum
Message-ID <[email protected]>
Here's a patch set for package-cleanup whose combined result is sorted package 
list output and query formatting like rpm.

My primary use case for these changes is running 
package-cleanup --leaves --all before and after some package management 
operation as well as comparing its output between boxes, sorted output 
and --qf="%{NAME}" makes the output easier to diff.

The patches are 0002: ground work, 0003: sorting, 0004: query formatting.

_______________________________________________
Yum mailing list
[email protected]
http://lists.baseurl.org/mailman/listinfo/yum
0002-Operate-more-on-yum-package-objects-rather-than-tupl.patch (text/x-diff, 5.8 KB)
From 8f916d73c19958aa4a431d289185301e933f9171 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Ville=20Skytt=C3=A4?= <[email protected]>
Date: Wed, 25 Mar 2009 00:41:22 +0200
Subject: [PATCH] Operate more on yum package objects rather than tuples.

---
 package-cleanup.py |   60 ++++++++++++++++++++++++---------------------------
 1 files changed, 28 insertions(+), 32 deletions(-)

diff --git a/package-cleanup.py b/package-cleanup.py
index 11d8415..8c10b87 100755
--- a/package-cleanup.py
+++ b/package-cleanup.py
@@ -69,14 +69,13 @@ def getLocalRequires(my):
     """Get a list of all requirements in the local rpmdb"""
     pkgs = {}
     for po in my.rpmdb.returnPackages():
-        tup = po.pkgtup
         header = po.hdr
         requires = zip(
             header[rpm.RPMTAG_REQUIRENAME],
             header[rpm.RPMTAG_REQUIREFLAGS],
             header[rpm.RPMTAG_REQUIREVERSION],
         )
-        pkgs[tup] = requires
+        pkgs[po] = requires
     return pkgs
 
 def buildProviderList(my, pkgs, reportProblems):
@@ -87,7 +86,7 @@ def buildProviderList(my, pkgs, reportProblems):
     providers = {} # To speed depsolving, don't recheck deps that have 
                    # already been checked
     provsomething = {}
-    for (pkg,reqs) in pkgs.items():
+    for (po,reqs) in pkgs.items():
         for (req,flags,ver)  in reqs:
             if ver == '':
                 ver = None
@@ -102,13 +101,13 @@ def buildProviderList(my, pkgs, reportProblems):
                 if not errors:
                     print "Missing dependencies:"
                 errors = True
-                print "Package %s requires %s" % (pkg[0],
+                print "Package %s requires %s" % (po,
                   miscutils.formatRequire(req,ver,rflags))
             else:
                 for rpkg in resolve_sack:
                     # Skip packages that provide something for themselves
                     # as these can still be leaves
-                    if rpkg != pkg:
+                    if rpkg != po.pkgtup:
                         provsomething[rpkg] = 1
                 # Store the resolve_sack so that we can re-use it if another
                 # package has the same requirement
@@ -191,11 +190,8 @@ def printDupes(my):
                 continue
             dupes.append(po)
 
-    for pkg in dupes:
-        if pkg.epoch != '0':
-            print '%s:%s-%s-%s.%s' % (pkg.epoch, pkg.name, pkg.ver, pkg.rel, pkg.arch)
-        else:
-            print '%s-%s-%s.%s' % (pkg.name, pkg.ver, pkg.rel, pkg.arch)
+    for po in dupes:
+        print "%s" % po
 
 def cleanOldDupes(my, confirmed):
     """remove all the older duplicates"""
@@ -238,19 +234,14 @@ def cleanOldDupes(my, confirmed):
                  
 
 
-def _shouldShowLeaf(my, pkg, leaf_regex, exclude_devel, exclude_bin):
+def _shouldShowLeaf(my, po, leaf_regex, exclude_devel, exclude_bin):
     """
     Determine if the given pkg should be displayed as a leaf or not.
 
     Return True if the pkg should be shown, False if not.
     """
-    if pkg[0] == 'gpg-pubkey':
+    if po.name == 'gpg-pubkey':
         return False
-    pos = my.rpmdb.searchNevra(name=pkg[0], epoch=str(pkg[2]), ver=pkg[3],
-            rel=pkg[4], arch=pkg[1])
-    # This should give us an exact match
-    assert len(pos) == 1
-    po = pos[0]
     name = po.name
     if exclude_devel and name.endswith('devel'):
         return False
@@ -263,27 +254,32 @@ def _shouldShowLeaf(my, pkg, leaf_regex, exclude_devel, exclude_bin):
     return False
 
 def listLeaves(my, all_nodes, leaf_regex, exclude_devel, exclude_bin):
-    """return a packagtuple of any installed packages that
-       are not required by any other package on the system"""
+    """Print packages that are not required by any other package
+       on the system"""
+
+    # Could use my.rpmdb.returnLeafNodes() directly but it's slow
     ts = transaction.initReadOnlyTransaction()
-    leaves = ts.returnLeafNodes()
-    for pkg in leaves:
-        name = pkg[0]
-        if all_nodes or _shouldShowLeaf(my, pkg, leaf_regex, exclude_devel,
+    leaves = [list(x) for x in ts.returnLeafNodes()]
+    # Epoch can be a number, stringify to work with getInstalledPackageObject
+    for lst in leaves:
+        lst[2] = str(lst[2])
+    leaves = (my.getInstalledPackageObject(x) for x in leaves)
+
+    for po in leaves:
+        if all_nodes or _shouldShowLeaf(my, po, leaf_regex, exclude_devel,
                 exclude_bin):
-            print "%s-%s-%s.%s" % (pkg[0],pkg[3],pkg[4],pkg[1])
+            print "%s" % po
 
 def listOrphans(my):
     """ This is "yum list extras". """
     avail = my.pkgSack.simplePkgList()
     avail = set(avail)
     for po in sorted(my.rpmdb.returnPackages()):
-        (n,a,e,v,r) = po.pkgtup
-        if n == "gpg-pubkey": # Not needed as of at least 3.2.19, but meh
+        if po.name == "gpg-pubkey": # Not needed as of at least 3.2.19, but meh
             continue
 
         if po.pkgtup not in avail:
-            print "%s-%s-%s.%s" % (n, v, r, a)
+            print "%s" % po
 
 def getKernels(my):
     """return a list of all installed kernels, sorted newest to oldest"""
@@ -384,17 +380,17 @@ def removeKernels(my, count, confirmed, keepdevel):
         print "No kernel related packages to remove"
         return
 
+    toremove = [my.getInstalledPackageObject(x) for x in toremove]
+
     print "I will remove the following %s kernel related packages:" % len(toremove)
-    for kernel in toremove:
-        (n,a,e,v,r) = kernel
-        print "%s-%s-%s" % (n,v,r) 
+    for po in toremove:
+        print "%s" % po
 
     if not confirmed:
         if not userconfirm():
             sys.exit(0)
 
-    for kernel in toremove:
-        po = my.rpmdb.searchPkgTuple(kernel)[0]
+    for po in toremove:
         my.tsInfo.addErase(po)
 
     # Now perform the action transaction
-- 
1.6.0.6
0003-Sort-package-list-output.patch (text/x-diff, 1.8 KB)
From 9a361719192aa601615446f43a160c7be2e7200d Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Ville=20Skytt=C3=A4?= <[email protected]>
Date: Wed, 25 Mar 2009 00:54:59 +0200
Subject: [PATCH] Sort package list output.

---
 package-cleanup.py |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/package-cleanup.py b/package-cleanup.py
index 8c10b87..236590f 100755
--- a/package-cleanup.py
+++ b/package-cleanup.py
@@ -190,7 +190,7 @@ def printDupes(my):
                 continue
             dupes.append(po)
 
-    for po in dupes:
+    for po in sorted(dupes):
         print "%s" % po
 
 def cleanOldDupes(my, confirmed):
@@ -214,9 +214,9 @@ def cleanOldDupes(my, confirmed):
     if len(removedupes) == 0:
         print "No dupes to clean"
         sys.exit(0)
-        
+
     print "I will remove the following old duplicate packages:"
-    for po in removedupes:
+    for po in sorted(removedupes):
         print "%s" % po
 
     if not confirmed:
@@ -263,7 +263,7 @@ def listLeaves(my, all_nodes, leaf_regex, exclude_devel, exclude_bin):
     # Epoch can be a number, stringify to work with getInstalledPackageObject
     for lst in leaves:
         lst[2] = str(lst[2])
-    leaves = (my.getInstalledPackageObject(x) for x in leaves)
+    leaves = sorted((my.getInstalledPackageObject(x) for x in leaves))
 
     for po in leaves:
         if all_nodes or _shouldShowLeaf(my, po, leaf_regex, exclude_devel,
@@ -380,7 +380,7 @@ def removeKernels(my, count, confirmed, keepdevel):
         print "No kernel related packages to remove"
         return
 
-    toremove = [my.getInstalledPackageObject(x) for x in toremove]
+    toremove = sorted((my.getInstalledPackageObject(x) for x in toremove))
 
     print "I will remove the following %s kernel related packages:" % len(toremove)
     for po in toremove:
-- 
1.6.0.6
0004-Add-query-formatting.patch (text/x-diff, 5.7 KB)
From d04e1ba0b7e8918634c66ffa321906a0685d3441 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Ville=20Skytt=C3=A4?= <[email protected]>
Date: Wed, 25 Mar 2009 01:01:25 +0200
Subject: [PATCH] Add query formatting.

---
 package-cleanup.py |   40 ++++++++++++++++++++++------------------
 1 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/package-cleanup.py b/package-cleanup.py
index 236590f..7f9c878 100755
--- a/package-cleanup.py
+++ b/package-cleanup.py
@@ -78,7 +78,7 @@ def getLocalRequires(my):
         pkgs[po] = requires
     return pkgs
 
-def buildProviderList(my, pkgs, reportProblems):
+def buildProviderList(my, pkgs, reportProblems, qf):
     """Resolve all dependencies in pkgs and build a dictionary of packages
      that provide something for a package other than itself"""
 
@@ -101,7 +101,7 @@ def buildProviderList(my, pkgs, reportProblems):
                 if not errors:
                     print "Missing dependencies:"
                 errors = True
-                print "Package %s requires %s" % (po,
+                print "Package %s requires %s" % (po.hdr.sprintf(qf),
                   miscutils.formatRequire(req,ver,rflags))
             else:
                 for rpkg in resolve_sack:
@@ -177,7 +177,7 @@ def findDupes(my):
     
     return refined
     
-def printDupes(my):
+def printDupes(my, qf):
     """print out the dupe listing"""
     dupedict = findDupes(my)
     dupes = []    
@@ -191,9 +191,9 @@ def printDupes(my):
             dupes.append(po)
 
     for po in sorted(dupes):
-        print "%s" % po
+        print po.hdr.sprintf(qf)
 
-def cleanOldDupes(my, confirmed):
+def cleanOldDupes(my, confirmed, qf):
     """remove all the older duplicates"""
     dupedict = findDupes(my)
     removedupes = []
@@ -217,7 +217,7 @@ def cleanOldDupes(my, confirmed):
 
     print "I will remove the following old duplicate packages:"
     for po in sorted(removedupes):
-        print "%s" % po
+        print po.hdr.sprintf(qf)
 
     if not confirmed:
         if not userconfirm():
@@ -253,7 +253,7 @@ def _shouldShowLeaf(my, po, leaf_regex, exclude_devel, exclude_bin):
         return True
     return False
 
-def listLeaves(my, all_nodes, leaf_regex, exclude_devel, exclude_bin):
+def listLeaves(my, all_nodes, leaf_regex, exclude_devel, exclude_bin, qf):
     """Print packages that are not required by any other package
        on the system"""
 
@@ -268,9 +268,9 @@ def listLeaves(my, all_nodes, leaf_regex, exclude_devel, exclude_bin):
     for po in leaves:
         if all_nodes or _shouldShowLeaf(my, po, leaf_regex, exclude_devel,
                 exclude_bin):
-            print "%s" % po
+            print po.hdr.sprintf(qf)
 
-def listOrphans(my):
+def listOrphans(my, qf):
     """ This is "yum list extras". """
     avail = my.pkgSack.simplePkgList()
     avail = set(avail)
@@ -279,7 +279,7 @@ def listOrphans(my):
             continue
 
         if po.pkgtup not in avail:
-            print "%s" % po
+            print po.hdr.sprintf(qf)
 
 def getKernels(my):
     """return a list of all installed kernels, sorted newest to oldest"""
@@ -333,7 +333,7 @@ def userconfirm():
     else:            
         return True
     
-def removeKernels(my, count, confirmed, keepdevel):
+def removeKernels(my, count, confirmed, keepdevel, qf):
     """Remove old kernels, keep at most count kernels (and always keep the running
      kernel"""
 
@@ -384,7 +384,7 @@ def removeKernels(my, count, confirmed, keepdevel):
 
     print "I will remove the following %s kernel related packages:" % len(toremove)
     for po in toremove:
-        print "%s" % po
+        print po.hdr.sprintf(qf)
 
     if not confirmed:
         if not userconfirm():
@@ -442,6 +442,9 @@ def parseArgs():
       help="Do not remove kernel-devel packages when removing kernels")
     parser.add_option("-c", dest="conffile", action="store",
                 default='/etc/yum.conf', help="config file location")
+    parser.add_option("--qf", "--queryformat", dest="qf", action="store",
+                      default='%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}',
+                      help="Query format to use for output.")
 
     (opts, args) = parser.parse_args()
     if not exactlyOne((opts.problems,opts.leaves,opts.kernels,opts.orphans, opts.dupes, opts.cleandupes)): 
@@ -460,20 +463,21 @@ def main():
         if os.geteuid() != 0:
             print "Error: Cannot remove kernels as a user, must be root"
             sys.exit(1)
-        removeKernels(my, opts.kernelcount, opts.confirmed, opts.keepdevel)
+        removeKernels(my, opts.kernelcount, opts.confirmed, opts.keepdevel,
+                      opts.qf)
         sys.exit(0)
     
     if (opts.leaves):
         listLeaves(my, opts.all_nodes, re.compile(opts.leaf_regex, re.IGNORECASE),
-                opts.exclude_devel, opts.exclude_bin)
+                opts.exclude_devel, opts.exclude_bin, opts.qf)
         sys.exit(0)
 
     if (opts.orphans):
-        listOrphans(my)
+        listOrphans(my, opts.qf)
         sys.exit(0)
 
     if opts.dupes:
-        printDupes(my)
+        printDupes(my, opts.qf)
         sys.exit(0)
 
     if opts.cleandupes:
@@ -481,7 +485,7 @@ def main():
             print "Error: Cannot remove packages as a user, must be root"
             sys.exit(1)
     
-        cleanOldDupes(my, opts.confirmed)
+        cleanOldDupes(my, opts.confirmed, opts.qf)
         sys.exit(0)
             
     if not opts.quiet:
@@ -489,7 +493,7 @@ def main():
     pkgs = getLocalRequires(my)
     if not opts.quiet:
         print "Processing all local requires"
-    provsomething = buildProviderList(my,pkgs,opts.problems)
+    provsomething = buildProviderList(my,pkgs,opts.problems,opts.qf)
     
 if __name__ == '__main__':
     main()
-- 
1.6.0.6
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.