diff options
Diffstat (limited to 'tools/pkgmgr_gen.py')
-rwxr-xr-x | tools/pkgmgr_gen.py | 254 |
1 files changed, 140 insertions, 114 deletions
diff --git a/tools/pkgmgr_gen.py b/tools/pkgmgr_gen.py index d318e46c0..03d36dfc0 100755 --- a/tools/pkgmgr_gen.py +++ b/tools/pkgmgr_gen.py @@ -1,40 +1,45 @@ #!/usr/bin/python -""" Program to generate a bcfg2 Pkgmgr configuration file from a list - of directories that contain RPMS. +"""Program to generate a bcfg2 Pkgmgr configuration file from a list + of directories that contain RPMS. - All versions or only the latest may be included in the output. - rpm.labelCompare is used to compare the package versions, so that - a proper rpm version comparison is done (epoch:version-release). + All versions or only the latest may be included in the output. + rpm.labelCompare is used to compare the package versions, so that + a proper rpm version comparison is done (epoch:version-release). - The output file may be formated for use with the RPM or Yum - bcfg2 client drivers. The output can also contain the PackageList - and nested group headers. + The output file may be formated for use with the RPM or Yum + bcfg2 client drivers. The output can also contain the PackageList + and nested group headers. """ __revision__ = '$Revision: $' -import sys -import os -import rpm -import optparse +import collections import datetime import glob -import urllib import gzip -import urlparse +import optparse +import os +import rpm +import sys from lxml.etree import parse import xml.sax from xml.sax.handler import ContentHandler +# Compatibility imports +from Bcfg2.Bcfg2Py3k import urljoin + + def info(object, spacing=10, collapse=1): """Print methods and doc strings. Takes module, class, list, dictionary, or string. """ methodList = [method for method in dir(object) - if callable(getattr(object, method))] + if isinstance(getattr(object, method), + collections.Callable)] processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s) - print "\n".join(["%s %s" % + print("\n".join(["%s %s" % (method.ljust(spacing), processFunc(str(getattr(object, method).__doc__))) - for method in methodList]) + for method in methodList])) + def readRpmHeader(ts, filename): """ @@ -43,19 +48,21 @@ def readRpmHeader(ts, filename): try: fd = os.open(filename, os.O_RDONLY) except: - print 'Failed to open RPM file %s' % filename + print("Failed to open RPM file %s" % filename) h = ts.hdrFromFdno(fd) os.close(fd) return h + def sortedDictValues(adict): """ Sort a dictionary by its keys and return the items in sorted key order. """ - keys = adict.keys() + keys = list(adict.keys()) keys.sort() - return map(adict.get, keys) + return list(map(adict.get, keys)) + def cmpRpmHeader(a, b): """ @@ -79,6 +86,7 @@ def cmpRpmHeader(a, b): ret = rpm.labelCompare((e1, v1, r1), (e2, v2, r2)) return ret + def loadRpms(dirs): """ dirs is a list of directories to search for rpms. @@ -114,18 +122,18 @@ def loadRpms(dirs): for dir in dirs: if options.verbose: - print 'Scanning directory: %s' % dir + print("Scanning directory: %s" % dir) for file in [files for files in os.listdir(dir) if files.endswith('.rpm')]: - filename = os.path.join( dir, file ) + filename = os.path.join(dir, file) # Get the mtime of the RPM file. file_mtime = datetime.date.fromtimestamp(os.stat(filename).st_mtime) # Get the RPM header - header = readRpmHeader( ts, filename ) + header = readRpmHeader(ts, filename) # Get what we are interesting in out of the header. name = header[rpm.RPMTAG_NAME] @@ -138,9 +146,13 @@ def loadRpms(dirs): if subarch in subarchs or 'all' in subarchs: # Store what we want in our structure. - packages.setdefault(name, []).append({'filename':file, 'mtime':file_mtime, 'name':name, \ - 'arch':subarch, 'epoch':epoch, 'version':version, \ - 'release':release}) + packages.setdefault(name, []).append({'filename': file, + 'mtime': file_mtime, + 'name': name, + 'arch': subarch, + 'epoch': epoch, + 'version': version, + 'release': release}) # Print '.' for each package. stdio is line buffered, so have to flush it. if options.verbose: @@ -151,6 +163,7 @@ def loadRpms(dirs): return packages + class pkgmgr_URLopener(urllib.FancyURLopener): """ Override default error handling so that we can see what the errors are. @@ -159,57 +172,62 @@ class pkgmgr_URLopener(urllib.FancyURLopener): """ Override default error handling so that we can see what the errors are. """ - print "ERROR %s: Unable to retrieve %s" % (errcode, url) + print("ERROR %s: Unable to retrieve %s" % (errcode, url)) + class PrimaryParser(ContentHandler): def __init__(self, packages): - self.inPackage = 0 - self.inName = 0 - self.inArch = 0 - self.packages = packages + self.inPackage = 0 + self.inName = 0 + self.inArch = 0 + self.packages = packages def startElement(self, name, attrs): - if name == "package": - self.package = {'file': None, 'name': '', 'subarch': '', - 'epoch': None, 'version': None, 'release': None} - self.inPackage = 1 - elif self.inPackage: - if name == "name": - self.inName = 1 - elif name == "arch": - self.inArch = 1 - elif name == "version": - self.package['epoch'] = attrs.getValue('epoch') - self.package['version'] = attrs.getValue('ver') - self.package['release'] = attrs.getValue('rel') - elif name == "location": - self.package['file'] = attrs.getValue('href') + if name == "package": + self.package = {'file': None, 'name': '', 'subarch': '', + 'epoch': None, 'version': None, 'release': None} + self.inPackage = 1 + elif self.inPackage: + if name == "name": + self.inName = 1 + elif name == "arch": + self.inArch = 1 + elif name == "version": + self.package['epoch'] = attrs.getValue('epoch') + self.package['version'] = attrs.getValue('ver') + self.package['release'] = attrs.getValue('rel') + elif name == "location": + self.package['file'] = attrs.getValue('href') def endElement(self, name): - if name == "package": - self.inPackage = 0 - # Only load RPMs with subarchitectures as calculated from the --archs option. - if self.package['subarch'] in subarchs or 'all' in subarchs: - self.packages.setdefault(self.package['name'], []).append( - {'filename':self.package['file'], 'name':self.package['name'], - 'arch':self.package['subarch'], 'epoch':self.package['epoch'], - 'version':self.package['version'], 'release':self.package['release']}) - # Print '.' for each package. stdio is line buffered, so have to flush it. - if options.verbose: - sys.stdout.write('.') - sys.stdout.flush() - elif self.inPackage: - if name == "name": - self.inName = 0 - elif name == "arch": - self.inArch = 0 + if name == "package": + self.inPackage = 0 + # Only load RPMs with subarchitectures as calculated from the --archs option. + if self.package['subarch'] in subarchs or 'all' in subarchs: + self.packages.setdefault(self.package['name'], []).append( + {'filename': self.package['file'], + 'name': self.package['name'], + 'arch': self.package['subarch'], + 'epoch': self.package['epoch'], + 'version': self.package['version'], + 'release': self.package['release']}) + # Print '.' for each package. stdio is line buffered, so have to flush it. + if options.verbose: + sys.stdout.write('.') + sys.stdout.flush() + elif self.inPackage: + if name == "name": + self.inName = 0 + elif name == "arch": + self.inArch = 0 def characters(self, content): - if self.inPackage: - if self.inName: - self.package['name'] += content - if self.inArch: - self.package['subarch'] += content + if self.inPackage: + if self.inName: + self.package['name'] += content + if self.inArch: + self.package['subarch'] += content + def loadRepos(repolist): ''' @@ -239,10 +257,10 @@ def loadRepos(repolist): ''' packages = {} for repo in repolist: - url = urlparse.urljoin(repo, './repodata/repomd.xml') + url = urljoin(repo, './repodata/repomd.xml') if options.verbose: - print 'Loading repo metadata : %s' % url + print("Loading repo metadata : %s" % url) try: opener = pkgmgr_URLopener() @@ -253,7 +271,7 @@ def loadRepos(repolist): try: tree = parse(file) except IOError: - print "ERROR: Unable to parse retrieved repomd.xml." + print("ERROR: Unable to parse retrieved repomd.xml.") sys.exit() repomd = tree.getroot() @@ -263,10 +281,10 @@ def loadRepos(repolist): if property.tag.endswith('location'): primaryhref = property.get('href') - url = urlparse.urljoin(repo, './' + primaryhref) + url = urljoin(repo, './' + primaryhref) if options.verbose: - print 'Loading : %s' % url + print("Loading : %s" % url) try: opener = pkgmgr_URLopener() @@ -277,7 +295,7 @@ def loadRepos(repolist): try: repo_file = gzip.open(file) except IOError: - print "ERROR: Unable to parse retrieved file." + print("ERROR: Unable to parse retrieved file.") sys.exit() parser = xml.sax.make_parser() @@ -289,6 +307,7 @@ def loadRepos(repolist): repo_file.close() return packages + def printInstance(instance, group_count): """ Print the details for a package instance with the appropriate indentation and @@ -303,16 +322,17 @@ def printInstance(instance, group_count): output_line = '' if options.format == 'rpm': - output_line = '%s<Instance simplefile=\'%s\' ' % ( indent * group_count , instance['filename']) + output_line = '%s<Instance simplefile=\'%s\' ' % (indent * group_count, instance['filename']) else: output_line = '%s<Instance ' % (indent * group_count) if epoch: output_line += 'epoch=\'%s\' ' % (epoch) - output_line += 'version=\'%s\' release=\'%s\' arch=\'%s\'/>\n' % ( version, release, arch) + output_line += 'version=\'%s\' release=\'%s\' arch=\'%s\'/>\n' % (version, release, arch) output.write(output_line) + def printPackage(entry, group_count): """ Print the details of a package with the appropriate indentation. @@ -321,7 +341,7 @@ def printPackage(entry, group_count): entry is a single package entry as created in loadRpms(). """ output.write('%s<Package name=\'%s\' type=\'%s\'>\n' \ - % ( group_count * indent, entry[0]['name'], options.format) ) + % (group_count * indent, entry[0]['name'], options.format)) subarch_dict = {} arch_dict = {} @@ -333,17 +353,17 @@ def printPackage(entry, group_count): if instance['arch'] in subarch_dict: subarch_dict[instance['arch']].append(instance) else: - subarch_dict[instance['arch']] = [ instance ] + subarch_dict[instance['arch']] = [instance] # Keep track of the subarchitectures we have found in each architecture. if subarch_mapping[instance['arch']] in arch_dict: if instance['arch'] not in arch_dict[subarch_mapping[instance['arch']]]: arch_dict[subarch_mapping[instance['arch']]].append(instance['arch']) else: - arch_dict[subarch_mapping[instance['arch']]] = [ instance['arch'] ] + arch_dict[subarch_mapping[instance['arch']]] = [instance['arch']] # Only keep the 'highest' subarchitecture in each architecture. - for arch in arch_dict.iterkeys(): + for arch in list(arch_dict.keys()): if len(arch_dict[arch]) > 1: arch_dict[arch].sort() for s in arch_dict[arch][:-1]: @@ -361,12 +381,13 @@ def printPackage(entry, group_count): # Output the latest printInstance(subarch_dict[arch][-1], group_count) - output.write('%s</Package>\n' % ( group_count * indent ) ) + output.write('%s</Package>\n' % (group_count * indent)) + def main(): if options.verbose: - print 'Loading package headers' + print("Loading package headers") if options.rpmdirs: package_dict = loadRpms(search_dirs) @@ -374,18 +395,18 @@ def main(): package_dict = loadRepos(repos) if options.verbose: - print 'Processing package headers' + print("Processing package headers") if options.pkgmgrhdr: if options.format == "rpm": - output.write("<PackageList uri='%s' priority='%s' type='rpm'>\n" % ( options.uri, options.priority )) + output.write("<PackageList uri='%s' priority='%s' type='rpm'>\n" % (options.uri, options.priority)) else: - output.write("<PackageList priority='%s' type='yum'>\n" %( options.priority )) + output.write("<PackageList priority='%s' type='yum'>\n" % (options.priority)) group_count = 1 if groups_list: for group in groups_list: - output.write("%s<Group name='%s'>\n" % ( indent * group_count , group ) ) + output.write("%s<Group name='%s'>\n" % (indent * group_count, group)) group_count = group_count + 1 # Process packages in name order @@ -395,14 +416,14 @@ def main(): if groups_list: group_count = group_count - 1 while group_count: - output.write( '%s</Group>\n' % ( indent * group_count ) ) + output.write('%s</Group>\n' % (indent * group_count)) group_count = group_count - 1 if options.pkgmgrhdr: - output.write( '</PackageList>\n' ) + output.write('</PackageList>\n') if options.verbose: - print '%i package instances were processed' % len(package_dict) + print("%i package instances were processed" % len(package_dict)) if __name__ == "__main__": @@ -434,7 +455,7 @@ if __name__ == "__main__": p.add_option('--format', '-f', action='store', \ default='yum', \ type='choice', \ - choices=('yum','rpm'), \ + choices=('yum', 'rpm'), \ help='''Format of the Output. Choices are yum or rpm. (Default: yum) ''') @@ -469,7 +490,7 @@ if __name__ == "__main__": p.add_option('--release', '-r', action='store', \ default='latest', \ type='choice', \ - choices=('all','latest'), \ + choices=('all', 'latest'), \ help='''Which releases to include in the output. Choices are all or latest. (Default: latest).''') @@ -492,11 +513,12 @@ if __name__ == "__main__": options, arguments = p.parse_args() if options.pkgmgrhdr and options.format == 'rpm' and not options.uri: - print "Option --uri must be specified to produce a PackageList Tag for rpm formatted files." + print("Option --uri must be specified to produce a PackageList Tag " + "for rpm formatted files.") sys.exit(1) if not options.rpmdirs and not options.yumrepos: - print "One of --rpmdirs and --yumrepos must be specified" + print("One of --rpmdirs and --yumrepos must be specified") sys.exit(1) # Set up list of directories to search @@ -505,9 +527,9 @@ if __name__ == "__main__": for d in options.rpmdirs.split(','): search_dirs += glob.glob(d) if options.verbose: - print 'The following directories will be scanned:' + print("The following directories will be scanned:") for d in search_dirs: - print ' %s' % d + print(" %s" % d) # Setup list of repos if options.yumrepos: @@ -515,26 +537,30 @@ if __name__ == "__main__": for r in options.yumrepos.split(','): repos.append(r) if options.verbose: - print 'The following repositories will be scanned:' + print("The following repositories will be scanned:") for d in repos: - print ' %s' % d + print(" %s" % d) # Set up list of architectures to include and some mappings # to use later. - arch_mapping = {'x86':['i686', 'i586', 'i486', 'i386', 'athlon'], - 'x86_64':['x86_64'], - 'ia64':['ia64'], - 'ppc':['ppc'], - 'ppc64':['ppc64'], - 'sparc':['sparc'], - 'noarch':['noarch']} - subarch_mapping = {'i686':'x86', 'i586':'x86', 'i486':'x86', 'i386':'x86', 'athlon':'x86', - 'x86_64':'x86_64', - 'ia64':'ia64', - 'ppc':'ppc', - 'ppc64':'ppc64', - 'sparc':'sparc', - 'noarch':'noarch' } + arch_mapping = {'x86': ['i686', 'i586', 'i486', 'i386', 'athlon'], + 'x86_64': ['x86_64'], + 'ia64': ['ia64'], + 'ppc': ['ppc'], + 'ppc64': ['ppc64'], + 'sparc': ['sparc'], + 'noarch': ['noarch']} + subarch_mapping = {'i686': 'x86', + 'i586': 'x86', + 'i486': 'x86', + 'i386': 'x86', + 'athlon': 'x86', + 'x86_64': 'x86_64', + 'ia64': 'ia64', + 'ppc': 'ppc', + 'ppc64': 'ppc64', + 'sparc': 'sparc', + 'noarch': 'noarch'} commandline_subarchs = options.archs.split(',') arch_list = [] subarchs = [] @@ -543,7 +569,7 @@ if __name__ == "__main__": else: for s in commandline_subarchs: if s not in subarch_mapping: - print 'Error: Invalid subarchitecture specified: ', s + print("Error: Invalid subarchitecture specified: ", s) sys.exit(1) # Only allow one subarchitecture per architecture to be specified. if s not in arch_list: @@ -556,7 +582,8 @@ if __name__ == "__main__": #if i != len(arch_mapping[subarch_mapping[s]]): subarchs += arch_mapping[subarch_mapping[s]][i:] else: - print 'Error: Multiple subarchitecutes of the same architecture specified.' + print("Error: Multiple subarchitecutes of the same " + "architecture specified.") sys.exit(1) indent = ' ' * options.indent @@ -572,4 +599,3 @@ if __name__ == "__main__": output = sys.stdout main() - |