Mercurial > public > mercurial-scm > hg-stable
view mercurial/hgweb/webutil.py @ 13741:b51bf961b3cb
wireproto: add getbundle() function
getbundle(common, heads) -> bundle
Returns the changegroup for all ancestors of heads which are not ancestors of common. For both
sets, the heads are included in the set.
Intended to eventually supercede changegroupsubset and changegroup. Uses heads of common region
to exclude unwanted changesets instead of bases of desired region, which is more useful and
easier to implement.
Designed to be extensible with new optional arguments (which will have to be guarded by
corresponding capabilities).
author | Peter Arrenbrecht <peter.arrenbrecht@gmail.com> |
---|---|
date | Wed, 23 Mar 2011 16:02:11 +0100 |
parents | 270f57d35525 |
children | bfeaa88b875d |
line wrap: on
line source
# hgweb/webutil.py - utility library for the web interface. # # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net> # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. import os, copy from mercurial import match, patch, util, error, ui from mercurial.node import hex, nullid 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 navbefore = [] navafter = [] 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: navafter.append(("+%d" % f, hex(nodefunc(pos + f).node()))) if pos - f >= 0: navbefore.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node()))) navafter.append(("tip", "tip")) try: navbefore.insert(0, ("(0)", hex(nodefunc('0').node()))) except error.RepoError: pass def gen(l): def f(**map): for label, node in l: yield {"label": label, "node": node} return f return (dict(before=gen(navbefore), after=gen(navafter)),) def _siblings(siblings=[], hiderev=None): siblings = [s for s in siblings if s.node() != nullid] if len(siblings) == 1 and siblings[0].rev() == hiderev: return for s in siblings: d = {'node': hex(s.node()), 'rev': s.rev()} d['user'] = s.user() d['date'] = s.date() d['description'] = s.description() d['branch'] = s.branch() if hasattr(s, 'path'): d['file'] = s.path() yield d def parents(ctx, hide=None): return _siblings(ctx.parents(), hide) def children(ctx, hide=None): return _siblings(ctx.children(), hide) def renamelink(fctx): r = fctx.renamed() if r: return [dict(file=r[0], node=hex(r[1]))] return [] def nodetagsdict(repo, node): return [{"name": i} for i in repo.nodetags(node)] def nodebookmarksdict(repo, node): return [{"name": i} for i in repo.nodebookmarks(node)] def nodebranchdict(repo, ctx): branches = [] branch = ctx.branch() # If this is an empty repo, ctx.node() == nullid, # ctx.branch() == 'default', but branchtags() is # an empty dict. Using dict.get avoids a traceback. if repo.branchtags().get(branch) == ctx.node(): branches.append({"name": branch}) return branches def nodeinbranch(repo, ctx): branches = [] branch = ctx.branch() if branch != 'default' and repo.branchtags().get(branch) != ctx.node(): branches.append({"name": branch}) return branches def nodebranchnodefault(ctx): branches = [] branch = ctx.branch() if branch != 'default': branches.append({"name": branch}) return branches def showtag(repo, tmpl, t1, node=nullid, **args): for t in repo.nodetags(node): yield tmpl(t1, tag=t, **args) def showbookmark(repo, tmpl, t1, node=nullid, **args): for t in repo.nodebookmarks(node): yield tmpl(t1, bookmark=t, **args) def cleanpath(repo, path): path = path.lstrip('/') return util.canonpath(repo.root, '', path) def changectx(repo, req): changeid = "tip" if 'node' in req.form: changeid = req.form['node'][0] elif 'manifest' in req.form: changeid = req.form['manifest'][0] try: ctx = repo[changeid] except error.RepoError: man = repo.manifest ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))] return ctx def filectx(repo, req): path = cleanpath(repo, req.form['file'][0]) if 'node' in req.form: changeid = req.form['node'][0] else: changeid = req.form['filenode'][0] try: fctx = repo[changeid][path] except error.RepoError: fctx = repo.filectx(path, fileid=changeid) return fctx def listfilediffs(tmpl, files, node, max): for f in files[:max]: yield tmpl('filedifflink', node=hex(node), file=f) if len(files) > max: yield tmpl('fileellipses') def diffs(repo, tmpl, ctx, files, parity, style): def countgen(): start = 1 while True: yield start start += 1 blockcount = countgen() def prettyprintlines(diff): blockno = blockcount.next() for lineno, l in enumerate(diff.splitlines(True)): lineno = "%d.%d" % (blockno, lineno + 1) if l.startswith('+'): ltype = "difflineplus" elif l.startswith('-'): ltype = "difflineminus" elif l.startswith('@'): ltype = "difflineat" else: ltype = "diffline" yield tmpl(ltype, line=l, lineid="l%s" % lineno, linenumber="% 8s" % lineno) if files: m = match.exact(repo.root, repo.getcwd(), files) else: m = match.always(repo.root, repo.getcwd()) diffopts = patch.diffopts(repo.ui, untrusted=True) parents = ctx.parents() node1 = parents and parents[0].node() or nullid node2 = ctx.node() block = [] for chunk in patch.diff(repo, node1, node2, m, opts=diffopts): if chunk.startswith('diff') and block: yield tmpl('diffblock', parity=parity.next(), lines=prettyprintlines(''.join(block))) block = [] if chunk.startswith('diff') and style != 'raw': chunk = ''.join(chunk.splitlines(True)[1:]) block.append(chunk) yield tmpl('diffblock', parity=parity.next(), lines=prettyprintlines(''.join(block))) class sessionvars(object): def __init__(self, vars, start='?'): self.start = start self.vars = vars def __getitem__(self, key): return self.vars[key] def __setitem__(self, key, value): self.vars[key] = value def __copy__(self): return sessionvars(copy.copy(self.vars), self.start) def __iter__(self): separator = self.start for key, value in self.vars.iteritems(): yield {'name': key, 'value': str(value), 'separator': separator} separator = '&' class wsgiui(ui.ui): # default termwidth breaks under mod_wsgi def termwidth(self): return 80