# -*- coding: utf-8 -*- import cgi import os import sys import patchtracker.Conf as Conf from patchtracker.Templates import ErrorTemplate, PatchTemplate, PackageVersTemplate, LetterTocTemplate, FrontPageTemplate, SearchResultsTemplate from patchtracker.DiffGzHandler import DiffGzHandler, DiffGzException from patchtracker.DebTarHandler import DebTarHandler from patchtracker.CacheObject import CacheObject, CacheMissException import patchtracker.DB as DB from patchtracker.DB import PatchTrackerDB, PackageWithoutDiffException import pygments from pygments.lexers import DiffLexer from pygments.formatters import HtmlFormatter import patchtracker.SourceArchive as SourceArchive class ReqHandlerException(Exception): def __init__(self, msg, code="500 Oh noes"): Exception.__init__(self, msg) self.status=code class Cmd: def __init__(self): self.content_type = 'text/html' self.status = "200 OK" class ErrorCmd(Cmd): def __init__(self, msg, code="500 Oh noes"): Cmd.__init__(self) self.status = code self.msg = msg def output(self): return str(ErrorTemplate(self.msg)) class PatchCmd(Cmd): def __init__(self, args): Cmd.__init__(self) self.db = PatchTrackerDB() self.patchtype,mode,pkgname,version = args[0:4] self.parsemode(mode) try: dh = self.db.makeDiffHandler(pkgname,version) except PackageWithoutDiffException, e: raise ReqHandlerException(str(e)) if self.patchtype == "series": self.patchname = os.sep.join(args[4:]) self.content = dh.series().fetch(self.patchname) elif self.patchtype == "debianonly": self.patchname = "debian-dir only changes" self.content = dh.debiandir() elif self.patchtype == "nondebian": self.patchname = "direct (non packaging) changes" self.content = dh.nondebiandir() elif self.patchtype == "misc": self.patchname = os.sep.join(args[4:]) self.content = dh.filterdiff(include=self.patchname) else: raise ReqHandlerException("unhandled patch type '%s'"%(self.patchtype)) self.pkgname = pkgname self.version = version def parsemode(self, mode): if mode == "view" or mode == "dl": self.mode = mode else: raise ReqHandlerException("unhandled display mode '%s'"%(mode)) if mode == "dl": self.content_type = "text/x-diff" def output(self): if self.mode == "dl": return str(self.content) else: return str(PatchTemplate(pkg=self.pkgname,vers=self.version, patch=self.content,name=self.patchname, patchtype=self.patchtype)) class PackageCmd(Cmd): def __init__(self, args): Cmd.__init__(self) db = PatchTrackerDB() self.name = args[0] if len(args) > 1: version = args[1] else: version = None self.toc = db.findCollection(package=self.name, version=version) # if there's no match, try with a wildcard match if not self.toc.size(): # ... but don't allow pathologically short names if len(self.name) < 3: raise ReqHandlerException("search terms must be 3 or more letters...") else: self.toc = db.findCollection(package="%"+self.name+"%", version=version) plist = self.toc.getletter(self.name) if not plist or len(plist) == 0: raise ReqHandlerException("can't find any package named or containing '%s'"%self.name, code="404 ENOPKG kthxbye") def output(self): p = self.toc.getpackage(self.name) # if there is no match, or if multiple versions were returned if not p or len(set(map(lambda x: x.version, p.values()))) > 1: querydesc = "package name contains" return str(SearchResultsTemplate(self.name, querydesc, self.toc)) else: return str(PackageVersTemplate(p.popitem()[1])) class IndexCmd(Cmd): def __init__(self, args): Cmd.__init__(self) if len(args) < 1 or not len(args[0]): raise ReqHandlerException("please provide a letter on which to index") else: self.db = PatchTrackerDB() self.letter = args[0] self.toc = self.db.findLetterToc(self.letter) def output(self): return str(LetterTocTemplate(self.letter, self.toc)) class MaintCmd(Cmd): def __init__(self, args): Cmd.__init__(self) if len(args) < 1 or not len(args[0]): raise ReqHandlerException("please provide a email address on which to index") else: self.db = PatchTrackerDB() self.email = args[0] self.toc = self.db.findCollection(email=self.email) def output(self): return str(SearchResultsTemplate(self.email, "maintainer email", self.toc)) class JumpCmd(Cmd): def __init__(self, env): Cmd.__init__(self) form = cgi.FieldStorage(fp=env['wsgi.input'],environ=env) self.name = form.getfirst("package") self.uri = "%s/package/%s"%(Conf.root_url, self.name) self.status = "302 Try this other place kthx" def output(self): return "" class FrontPageCmd(Cmd): def __init__(self): Cmd.__init__(self) self.db = PatchTrackerDB() self.index = self.db.findIndices() def output(self): return str(FrontPageTemplate(self.index)) class CmdHandler: def __init__(self, env): self.headers = [] uri = Conf.root_url+env['PATH_INFO'] self.cacheobj = None #print "Accept:",env['HTTP_ACCEPT'] args = uri[len(Conf.root_url)+1:].split("/") cmdarg = args[0] cacheable = False if cmdarg == "patch": self.cmd = PatchCmd(args[1:]) cacheable = True elif cmdarg == "package": self.cmd = PackageCmd(args[1:]) if len(args[1:]) > 1: cacheable = True elif cmdarg == "index": self.cmd = IndexCmd(args[1:]) elif cmdarg == "jump": self.cmd = JumpCmd(env) self.headers.append( ('Location', self.cmd.uri) ) elif cmdarg == "email": self.cmd = MaintCmd(args[1:]) elif not len(cmdarg): self.cmd = FrontPageCmd() else: self.cmd = ErrorCmd("invalid command/location '%s'"%(cmdarg), "404 Not found") if Conf.caching and cacheable: self.cacheobj = CacheObject(key=uri) self.headers.append( ('Content-type', self.cmd.content_type) ) self.status = self.cmd.status def output(self): result = None try: if self.cacheobj: result = self.cacheobj.get() else: result = self.cmd.output() except CacheMissException: result = self.cmd.output() self.cacheobj.put(result) except DiffGzException, e: return ErrorCmd(str(e), "500 Oh Noez!!1!").output() return result if __name__ == '__main__': fake_env = { 'PATH_INFO': sys.argv[1] } cmdh = CmdHandler(fake_env) print "Status: %s\nHeaders: %s"%(cmdh.status, cmdh.headers) print cmdh.output()