Compare RPM Packages using Python
Question: I'm trying to compare a csv file containing required Linux packages with the
current installed packages. The comparison should output any packages not
installed or newer than the current installed packages.

The problem is that I'm unable to loop through the list of installed packages
and show all hits, for instance packages with the same name and version, but
different architecture should be shown twice(for instance compat-
libstdc++-33), but I only getting the first hit with the script below.

    
    
    #!/usr/bin/python
    
    import rpm
    import csv
    import sys
    import os
    
    '''
    Script to check installed rpms against a csv file containing the package name and version similar to the list below:
    atk,1.12.2
    libart_lgpl,2.3
    info,4.9
    libsepol,1.15.2
    libusb,0.1.12
    libfontenc,1.4.2
    
    '''
    
    if len(sys.argv) !=2:
            print ''
            print 'Usage: ', sys.argv[0], '/path/to/csv_input_file'
            print ''
            sys.exit(1)
    
    if not os.path.isfile(sys.argv[1]):
            print ''
            print sys.argv[1], 'not found!'
            print ''
            sys.exit(1)
    
    else:
            input_csv = sys.argv[1]
    
    pkgRequired = csv.reader(open(input_csv),delimiter=',')
    
    pkgInstalledName = []
    pkgInstalledVersion = []
    pkgInstalledArch = []
    
    ts = rpm.TransactionSet()
    mi = ts.dbMatch()
    
    for h in mi:
            pkgInstalledName.append((h['name']))
            pkgInstalledVersion.append((h['version']))
            pkgInstalledArch.append((h['arch']))
    
    for row in pkgRequired:
            pkgRequiredName = row[0]
            pkgRequiredVersion = row[1]
            #pkgRequiredArch = row[2]
    
            if pkgRequiredName in pkgInstalledName:
    
                    if pkgInstalledVersion[pkgInstalledName.index(pkgRequiredName)] >= pkgRequiredVersion:
                            pass
                    else:
                            print '\nInstalled:  ',pkgInstalledName[pkgInstalledName.index(pkgRequiredName)], pkgInstalledVersion[pkgInstalledName.index(pkgRequiredName)], pkgInstalledArch[pkgInstalledName.index(pkgRequiredName)], ' \nRequired: ', ' ', pkgRequiredName,pkgRequiredVersion
    


Answer: Assuming that there's no problem with the way that you're reading the list of
installed packages (I'm not familiar with the rpm module), then your only
problem is with using the index() function. This function return the first
occurrence of an item with the specified value - and it isn't what you want.

A correct implementation (which is also much more efficient) would be:

    
    
    installedPackages = {} #create a hash table, mapping package names to LISTS of installed package versions and architectures
    for h in mi: 
      l = installedPackages.get(h['name'], list()) #return either the existing list, or a new one if this is the first time that the name appears.
      l.append( (h['version'], h['arch']) )
    
    ...
    if requiredPackageName in installedPackages:
      for ver, arch in installedPackages[requiredPackageName]: print ...
    

