Mercurial > public > mercurial-scm > hg
diff mercurial/hgweb/hgweb_mod.py @ 6393:894875eae49b
hgweb: refactor hgweb code
author | Dirkjan Ochtman <dirkjan@ochtman.nl> |
---|---|
date | Fri, 28 Mar 2008 19:40:44 +0100 |
parents | 2540521dc7c1 |
children | a63aed912e54 |
line wrap: on
line diff
--- a/mercurial/hgweb/hgweb_mod.py Fri Mar 28 19:37:28 2008 +0100 +++ b/mercurial/hgweb/hgweb_mod.py Fri Mar 28 19:40:44 2008 +0100 @@ -6,13 +6,12 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import os, mimetypes, re -from mercurial.node import hex, nullid, short +import os, mimetypes +from mercurial.node import hex, nullid from mercurial.repo import RepoError -from mercurial import mdiff, ui, hg, util, archival, patch, hook +from mercurial import mdiff, ui, hg, util, patch, hook from mercurial import revlog, templater, templatefilters, changegroup -from common import get_mtime, style_map, paritygen, countgen, get_contact -from common import ErrorResponse +from common import get_mtime, style_map, paritygen, countgen, ErrorResponse from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR from request import wsgirequest import webcommands, protocol, webutil @@ -32,54 +31,6 @@ 'static': [('cmd', ['static']), ('file', None)] } -def _up(p): - if p[0] != "/": - p = "/" + p - if p[-1] == "/": - p = p[:-1] - up = os.path.dirname(p) - if up == "/": - return "/" - return up + "/" - -def revnavgen(pos, pagelen, limit, nodefunc): - def seq(factor, limit=None): - if limit: - yield limit - if limit >= 20 and limit <= 40: - yield 50 - else: - yield 1 * factor - yield 3 * factor - for f in seq(factor * 10): - yield f - - def nav(**map): - l = [] - last = 0 - for f in seq(1, pagelen): - if f < pagelen or f <= last: - continue - if f > limit: - break - last = f - if pos + f < limit: - l.append(("+%d" % f, hex(nodefunc(pos + f).node()))) - if pos - f >= 0: - l.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node()))) - - try: - yield {"label": "(0)", "node": hex(nodefunc('0').node())} - - for label, node in l: - yield {"label": label, "node": node} - - yield {"label": "tip", "node": "tip"} - except RepoError: - pass - - return nav - class hgweb(object): def __init__(self, repo, name=None): if isinstance(repo, str): @@ -407,476 +358,12 @@ yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f, opts=diffopts), f, tn) - def changelog(self, tmpl, ctx, shortlog=False): - def changelist(limit=0,**map): - cl = self.repo.changelog - l = [] # build a list in forward order for efficiency - for i in xrange(start, end): - ctx = self.repo.changectx(i) - n = ctx.node() - showtags = webutil.showtag(self.repo, tmpl, 'changelogtag', n) - - l.insert(0, {"parity": parity.next(), - "author": ctx.user(), - "parent": webutil.siblings(ctx.parents(), i - 1), - "child": webutil.siblings(ctx.children(), i + 1), - "changelogtag": showtags, - "desc": ctx.description(), - "date": ctx.date(), - "files": self.listfilediffs(tmpl, ctx.files(), n), - "rev": i, - "node": hex(n), - "tags": webutil.nodetagsdict(self.repo, n), - "inbranch": webutil.nodeinbranch(self.repo, ctx), - "branches": webutil.nodebranchdict(self.repo, ctx) - }) - - if limit > 0: - l = l[:limit] - - for e in l: - yield e - - maxchanges = shortlog and self.maxshortchanges or self.maxchanges - cl = self.repo.changelog - count = cl.count() - pos = ctx.rev() - start = max(0, pos - maxchanges + 1) - end = min(count, start + maxchanges) - pos = end - 1 - parity = paritygen(self.stripecount, offset=start-end) - - changenav = revnavgen(pos, maxchanges, count, self.repo.changectx) - - return tmpl(shortlog and 'shortlog' or 'changelog', - changenav=changenav, - node=hex(cl.tip()), - rev=pos, changesets=count, - entries=lambda **x: changelist(limit=0,**x), - latestentry=lambda **x: changelist(limit=1,**x), - archives=self.archivelist("tip")) - - def search(self, tmpl, query): - - def changelist(**map): - cl = self.repo.changelog - count = 0 - qw = query.lower().split() - - def revgen(): - for i in xrange(cl.count() - 1, 0, -100): - l = [] - for j in xrange(max(0, i - 100), i + 1): - ctx = self.repo.changectx(j) - l.append(ctx) - l.reverse() - for e in l: - yield e - - for ctx in revgen(): - miss = 0 - for q in qw: - if not (q in ctx.user().lower() or - q in ctx.description().lower() or - q in " ".join(ctx.files()).lower()): - miss = 1 - break - if miss: - continue - - count += 1 - n = ctx.node() - showtags = webutil.showtag(self.repo, tmpl, 'changelogtag', n) - - yield tmpl('searchentry', - parity=parity.next(), - author=ctx.user(), - parent=webutil.siblings(ctx.parents()), - child=webutil.siblings(ctx.children()), - changelogtag=showtags, - desc=ctx.description(), - date=ctx.date(), - files=self.listfilediffs(tmpl, ctx.files(), n), - rev=ctx.rev(), - node=hex(n), - tags=webutil.nodetagsdict(self.repo, n), - inbranch=webutil.nodeinbranch(self.repo, ctx), - branches=webutil.nodebranchdict(self.repo, ctx)) - - if count >= self.maxchanges: - break - - cl = self.repo.changelog - parity = paritygen(self.stripecount) - - return tmpl('search', - query=query, - node=hex(cl.tip()), - entries=changelist, - archives=self.archivelist("tip")) - - def changeset(self, tmpl, ctx): - n = ctx.node() - showtags = webutil.showtag(self.repo, tmpl, 'changesettag', n) - parents = ctx.parents() - p1 = parents[0].node() - - files = [] - parity = paritygen(self.stripecount) - for f in ctx.files(): - files.append(tmpl("filenodelink", - node=hex(n), file=f, - parity=parity.next())) - - def diff(**map): - yield self.diff(tmpl, p1, n, None) - - return tmpl('changeset', - diff=diff, - rev=ctx.rev(), - node=hex(n), - parent=webutil.siblings(parents), - child=webutil.siblings(ctx.children()), - changesettag=showtags, - author=ctx.user(), - desc=ctx.description(), - date=ctx.date(), - files=files, - archives=self.archivelist(hex(n)), - tags=webutil.nodetagsdict(self.repo, n), - branch=webutil.nodebranchnodefault(ctx), - inbranch=webutil.nodeinbranch(self.repo, ctx), - branches=webutil.nodebranchdict(self.repo, ctx)) - - def filelog(self, tmpl, fctx): - f = fctx.path() - fl = fctx.filelog() - count = fl.count() - pagelen = self.maxshortchanges - pos = fctx.filerev() - start = max(0, pos - pagelen + 1) - end = min(count, start + pagelen) - pos = end - 1 - parity = paritygen(self.stripecount, offset=start-end) - - def entries(limit=0, **map): - l = [] - - for i in xrange(start, end): - ctx = fctx.filectx(i) - n = fl.node(i) - - l.insert(0, {"parity": parity.next(), - "filerev": i, - "file": f, - "node": hex(ctx.node()), - "author": ctx.user(), - "date": ctx.date(), - "rename": webutil.renamelink(fl, n), - "parent": webutil.siblings(fctx.parents()), - "child": webutil.siblings(fctx.children()), - "desc": ctx.description()}) - - if limit > 0: - l = l[:limit] - - for e in l: - yield e - - nodefunc = lambda x: fctx.filectx(fileid=x) - nav = revnavgen(pos, pagelen, count, nodefunc) - return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav, - entries=lambda **x: entries(limit=0, **x), - latestentry=lambda **x: entries(limit=1, **x)) - - def filerevision(self, tmpl, fctx): - f = fctx.path() - text = fctx.data() - fl = fctx.filelog() - n = fctx.filenode() - parity = paritygen(self.stripecount) - - if util.binary(text): - mt = mimetypes.guess_type(f)[0] or 'application/octet-stream' - text = '(binary:%s)' % mt - - def lines(): - for lineno, t in enumerate(text.splitlines(1)): - yield {"line": t, - "lineid": "l%d" % (lineno + 1), - "linenumber": "% 6d" % (lineno + 1), - "parity": parity.next()} - - return tmpl("filerevision", - file=f, - path=_up(f), - text=lines(), - rev=fctx.rev(), - node=hex(fctx.node()), - author=fctx.user(), - date=fctx.date(), - desc=fctx.description(), - branch=webutil.nodebranchnodefault(fctx), - parent=webutil.siblings(fctx.parents()), - child=webutil.siblings(fctx.children()), - rename=webutil.renamelink(fl, n), - permissions=fctx.manifest().flags(f)) - - def fileannotate(self, tmpl, fctx): - f = fctx.path() - n = fctx.filenode() - fl = fctx.filelog() - parity = paritygen(self.stripecount) - - def annotate(**map): - last = None - if util.binary(fctx.data()): - mt = (mimetypes.guess_type(fctx.path())[0] - or 'application/octet-stream') - lines = enumerate([((fctx.filectx(fctx.filerev()), 1), - '(binary:%s)' % mt)]) - else: - lines = enumerate(fctx.annotate(follow=True, linenumber=True)) - for lineno, ((f, targetline), l) in lines: - fnode = f.filenode() - name = self.repo.ui.shortuser(f.user()) - - if last != fnode: - last = fnode - - yield {"parity": parity.next(), - "node": hex(f.node()), - "rev": f.rev(), - "author": name, - "file": f.path(), - "targetline": targetline, - "line": l, - "lineid": "l%d" % (lineno + 1), - "linenumber": "% 6d" % (lineno + 1)} - - return tmpl("fileannotate", - file=f, - annotate=annotate, - path=_up(f), - rev=fctx.rev(), - node=hex(fctx.node()), - author=fctx.user(), - date=fctx.date(), - desc=fctx.description(), - rename=webutil.renamelink(fl, n), - branch=webutil.nodebranchnodefault(fctx), - parent=webutil.siblings(fctx.parents()), - child=webutil.siblings(fctx.children()), - permissions=fctx.manifest().flags(f)) - - def manifest(self, tmpl, ctx, path): - mf = ctx.manifest() - node = ctx.node() - - files = {} - parity = paritygen(self.stripecount) - - if path and path[-1] != "/": - path += "/" - l = len(path) - abspath = "/" + path - - for f, n in mf.items(): - if f[:l] != path: - continue - remain = f[l:] - if "/" in remain: - short = remain[:remain.index("/") + 1] # bleah - files[short] = (f, None) - else: - short = os.path.basename(remain) - files[short] = (f, n) - - if not files: - raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path) - - def filelist(**map): - fl = files.keys() - fl.sort() - for f in fl: - full, fnode = files[f] - if not fnode: - continue - - fctx = ctx.filectx(full) - yield {"file": full, - "parity": parity.next(), - "basename": f, - "date": fctx.changectx().date(), - "size": fctx.size(), - "permissions": mf.flags(full)} - - def dirlist(**map): - fl = files.keys() - fl.sort() - for f in fl: - full, fnode = files[f] - if fnode: - continue - - yield {"parity": parity.next(), - "path": "%s%s" % (abspath, f), - "basename": f[:-1]} - - return tmpl("manifest", - rev=ctx.rev(), - node=hex(node), - path=abspath, - up=_up(abspath), - upparity=parity.next(), - fentries=filelist, - dentries=dirlist, - archives=self.archivelist(hex(node)), - tags=webutil.nodetagsdict(self.repo, node), - inbranch=webutil.nodeinbranch(self.repo, ctx), - branches=webutil.nodebranchdict(self.repo, ctx)) - - def tags(self, tmpl): - i = self.repo.tagslist() - i.reverse() - parity = paritygen(self.stripecount) - - def entries(notip=False,limit=0, **map): - count = 0 - for k, n in i: - if notip and k == "tip": - continue - if limit > 0 and count >= limit: - continue - count = count + 1 - yield {"parity": parity.next(), - "tag": k, - "date": self.repo.changectx(n).date(), - "node": hex(n)} - - return tmpl("tags", - node=hex(self.repo.changelog.tip()), - entries=lambda **x: entries(False,0, **x), - entriesnotip=lambda **x: entries(True,0, **x), - latestentry=lambda **x: entries(True,1, **x)) - - def summary(self, tmpl): - i = self.repo.tagslist() - i.reverse() - - def tagentries(**map): - parity = paritygen(self.stripecount) - count = 0 - for k, n in i: - if k == "tip": # skip tip - continue; - - count += 1 - if count > 10: # limit to 10 tags - break; - - yield tmpl("tagentry", - parity=parity.next(), - tag=k, - node=hex(n), - date=self.repo.changectx(n).date()) - - - def branches(**map): - parity = paritygen(self.stripecount) - - b = self.repo.branchtags() - l = [(-self.repo.changelog.rev(n), n, t) for t, n in b.items()] - l.sort() - - for r,n,t in l: - ctx = self.repo.changectx(n) - - yield {'parity': parity.next(), - 'branch': t, - 'node': hex(n), - 'date': ctx.date()} - - def changelist(**map): - parity = paritygen(self.stripecount, offset=start-end) - l = [] # build a list in forward order for efficiency - for i in xrange(start, end): - ctx = self.repo.changectx(i) - n = ctx.node() - hn = hex(n) - - l.insert(0, tmpl( - 'shortlogentry', - parity=parity.next(), - author=ctx.user(), - desc=ctx.description(), - date=ctx.date(), - rev=i, - node=hn, - tags=webutil.nodetagsdict(self.repo, n), - inbranch=webutil.nodeinbranch(self.repo, ctx), - branches=webutil.nodebranchdict(self.repo, ctx))) - - yield l - - cl = self.repo.changelog - count = cl.count() - start = max(0, count - self.maxchanges) - end = min(count, start + self.maxchanges) - - return tmpl("summary", - desc=self.config("web", "description", "unknown"), - owner=get_contact(self.config) or "unknown", - lastchange=cl.read(cl.tip())[2], - tags=tagentries, - branches=branches, - shortlog=changelist, - node=hex(cl.tip()), - archives=self.archivelist("tip")) - - def filediff(self, tmpl, fctx): - n = fctx.node() - path = fctx.path() - parents = fctx.parents() - p1 = parents and parents[0].node() or nullid - - def diff(**map): - yield self.diff(tmpl, p1, n, [path]) - - return tmpl("filediff", - file=path, - node=hex(n), - rev=fctx.rev(), - branch=webutil.nodebranchnodefault(fctx), - parent=webutil.siblings(parents), - child=webutil.siblings(fctx.children()), - diff=diff) - archive_specs = { 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None), 'gz': ('application/x-tar', 'tgz', '.tar.gz', None), 'zip': ('application/zip', 'zip', '.zip', None), } - def archive(self, tmpl, req, key, type_): - reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame)) - cnode = self.repo.lookup(key) - arch_version = key - if cnode == key or key == 'tip': - arch_version = short(cnode) - name = "%s-%s" % (reponame, arch_version) - mimetype, artype, extension, encoding = self.archive_specs[type_] - headers = [ - ('Content-Type', mimetype), - ('Content-Disposition', 'attachment; filename=%s%s' % - (name, extension)) - ] - if encoding: - headers.append(('Content-Encoding', encoding)) - req.header(headers) - req.respond(HTTP_OK) - archival.archive(self.repo, req, cnode, artype, prefix=name) - def check_perm(self, req, op, default): '''check permission for operation based on user auth. return true if op allowed, else false.