import os import errno from fnmatch import fnmatch from gzip import GzipFile from debian_bundle import deb822 import difflib from patchtracker import Conf class Archive: def __init__(self, dir, suitefilter=None, pkgfilter=None): self.root = None self.distsdir = None self.pkgs = {} self.root = dir self.distsdir = os.sep.join([dir, "dists"]) for s in self.parsesuites(filter=suitefilter): self.addsuite(s) for c in self.parsecomponents(s): self.addcomponent(s,c) for p in self.parsesourcepackages(s,c,filter=pkgfilter): self.addsourcepackage(s,c,p) def addsuite(self, suite): self.pkgs[suite] = {} def suites(self, filter=None): return sorted(self.pkgs.iterkeys()) def parsesuites(self, filter=None): slist = os.listdir(self.distsdir) if Conf.suites: slist = set(Conf.suites).intersection(set(slist)) if filter: slist = set(filter).intersection(set(slist)) for s in sorted(slist): yield s def addcomponent(self, suite, component): self.pkgs[suite][component] = {} def components(self, suite): return sorted(self.pkgs[suite].iterkeys()) def parsecomponents(self, suite): f = file(self.distsdir + os.sep + os.sep.join([suite, "Release"])) rel = deb822.Release(f) for comp in rel['Components'].split(' '): yield comp def addsourcepackage(self, suite, component, package): self.pkgs[suite][component][package.name] = package def sourcepackages(self, suite, component, filter=None, namesonly=False): if not namesonly: return sorted(self.pkgs[suite][component].itervalues()) else: namer = lambda x: x.name return sorted(map(namer, self.pkgs[suite][component].itervalues())) def parsesourcepackages(self, suite, component, filter=None): sfile=os.sep.join([self.distsdir,suite,component,"/source/Sources.gz"]) fdict = {} if filter: for name in filter: fdict[name] = True for ent in deb822.Sources.iter_paragraphs(GzipFile(sfile)): if filter and not fdict.has_key(ent['Package']): continue else: yield SourcePackage(ent) def __str__(self): return "Archive rooted at "+self.root class ArchiveDiffer: def diffsuites(self,a,b): return difflib.ndiff(a.suites(), b.suites()) def diffcomponents(self,a,b, suite): return difflib.ndiff(a.components(suite), b.components(suite)) def diffsourcepackages(self,a,b, suite, component): return difflib.ndiff(a.sourcepackages(suite, component, namesonly=True), b.sourcepackages(suite, component, namesonly=True)) # XXX maybe there's a better place/way for this def getidx(letter): name = str(letter) if len(name) < 4 or name[0:3] != "lib": return name[0] else: return name[0:4] class SourcePackage: def __init__(self, info): # attributes for debian .diff.gz source packages self.diffgz_name = None self.diffgz_size = None self.diffgz_md5sum = None self.diffgz = None # attributes for debian .debian.tar.gz source packages self.debtar_name = None self.debtar_size = None self.debtar_md5sum = None self.debtar = None # some other defaults self.type = "Native" self.name = info['Package'] self.format = info['Format'] self.loc = info['Directory'] self.version = info['Version'] self.uploaders = None try: self.maintainers = unicode(info['Maintainer']) except UnicodeDecodeError: self.maintainers = unicode(info['Maintainer'], 'latin-1') if info.has_key('Uploaders'): try: self.uploaders = unicode(info['Uploaders']) except UnicodeDecodeError: self.uploaders = unicode(info['Uploaders'], 'latin-1') self.idx = getidx(self) for f in info['Files']: if fnmatch(f['name'], '*.diff.gz'): self.diffgz_name=f['name'] self.diffgz_size=f['size'] self.diffgz_md5sum=f['md5sum'] self.type = "Debian-diff" elif fnmatch(f['name'], '*.debian.tar.*'): self.debtar_name=f['name'] self.debtar_size=f['size'] self.debtar_md5sum=f['md5sum'] self.type = "Debian-diff" def __str__(self): return self.name class SourcePackageIndex: def __init__(self): self.pkgs = {} def ins(self, srcpkg, rel): if not self.pkgs.has_key(srcpkg.idx): self.pkgs[srcpkg.idx] = {} if not self.pkgs[srcpkg.idx].has_key(srcpkg.name): self.pkgs[srcpkg.idx][srcpkg.name] = {} if not self.pkgs[srcpkg.idx][srcpkg.name].has_key(rel): self.pkgs[srcpkg.idx][srcpkg.name][rel] = srcpkg def size(self): return sum([len(self.pkgs[i]) for i in self.pkgs.iterkeys()]) def getpackage(self, name): try: return self.getletter(name)[name] except KeyError: return None def getletter(self, letter): try: return self.pkgs[getidx(letter)] except KeyError: return None def indices(self): return sorted(self.pkgs.iterkeys()) class ReleaseList: def __init__(self, project): self.project = project self.relorder = {} if Conf.suites: self.relorder["debian"] = Conf.suites else: self.relorder["debian"] = ["lenny", "squeeze", "wheezy", "sid", "experimental"] def __iter__(self): for r in self.relorder[self.project]: yield r # basic module tests if __name__ == "__main__": import Conf import sys import copy a = Archive(sys.argv[1], suitefilter=["lenny"]) b = copy.deepcopy(a) b.addsuite("lenny") b.addcomponent("lenny", "something") class x: def __init__(self,name): self.name=name b.addsourcepackage("lenny","main",x("foo")) print "suite diff" print "\n".join( ArchiveDiffer().diffsuites(a,b) ) print "component diff" print "\n".join( ArchiveDiffer().diffcomponents(a,b,"lenny") ) print "package diff" print "\n".join( ArchiveDiffer().diffsourcepackages(a,b,"lenny","main") )