''' Script to find duplicate provides. Given a list of paths to built RPMs, extracts all Provides and filesystem path in their payload, and then looks then up in yum, reporting any duplicates found. ''' import os import sys import rpm def get_header_by_name(ts, pkgname): mi = ts.dbMatch(rpm.RPMTAG_NAME, pkgname) for h in mi: # only get the first one: return h def get_header_for_rpm_file(ts, path): fd = os.open(path, os.O_RDONLY) try: return ts.hdrFromFdno(fd) finally: os.close(fd) class HeaderSet: def __init__(self): # a list of (name, header) pairs self.headers = [] @classmethod def from_dir(self, path): '''Get all RPMs in directory (and below); use their headers''' result = HeaderSet() for rpmpath in get_rpm_files_in_dir(path): result.add_rpm_file(rpmpath) return result @classmethod def from_paths(self, paths): result = HeaderSet() for rpmpath in paths: result.add_rpm_file(rpmpath) return result def add_installed_rpm(self, pkgname): ts = rpm.TransactionSet() self.headers.append(get_header_by_name(ts, pkgname)) def add_rpm_file(self, path): ts = rpm.TransactionSet() ts.setVSFlags(-1) self.headers.append((path, get_header_for_rpm_file(ts, path))) def get_provides(self): result = [] for name, h in self.headers: for p in h[rpm.RPMTAG_PROVIDENAME]: result += [(name, p)] return result def get_owned_paths(self): result = [] for name, h in self.headers: for f in h[rpm.RPMTAG_FILENAMES]: result += [(name, f)] return result def get_rpm_files_in_dir(path): for dirpath, dirnames, filenames in os.walk(path): for filename in filenames: if filename.endswith('.rpm'): yield os.path.join(dirpath, filename) def get_collisions_against_yum(provisions): import yum my = yum.YumBase() my.setCacheDir() c = 0 for name, provision in provisions: for pkg, path in my.searchPackageProvides([provision]).iteritems(): print '%s from %s collides with %s from %s' % (provision, name, path, repr(pkg)) c += 1 return c def print_collisions(hs): num_collisions = 0 sys.stdout.write('Colliding "Provides" items:\n') num_collisions += get_collisions_against_yum(hs.get_provides()) sys.stdout.write('Colliding filesystem items:\n') num_collisions += get_collisions_against_yum(hs.get_owned_paths()) return num_collisions if __name__ == '__main__': hs = HeaderSet.from_paths(sys.argv[1:]) num_collisions = print_collisions(hs) sys.exit(num_collisions)