##// END OF EJS Templates
Fix memory leak when using hg commands over http repositories...
Fix memory leak when using hg commands over http repositories When using hg commands over an http repository in a long running process, a httphandler instance is leaked for each command, because of a loop handler.parent -> OpenerDirector and OpenerDirector.handlers -> handler which is not handled by Python's gc. Discussion on #mercurial concluded that removing the __del__ method solved the problem.

File last commit:

r10282:08a0f04b default
r12391:ca5fd84d stable
Show More
webutil.py
221 lines | 6.3 KiB | text/x-python | PythonLexer
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 # 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>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345 import os, copy
Matt Mackall
error: move repo errors...
r7637 from mercurial import match, patch, util, error
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 from mercurial.node import hex, nullid
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 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
Nicolas Dumazet
hgweb: changenav: separate pages before and after the current position...
r10254 navbefore = []
navafter = []
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Nicolas Dumazet
hgweb: changenav: separate pages before and after the current position...
r10254 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())))
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Nicolas Dumazet
hgweb: changenav: separate pages before and after the current position...
r10254 navafter.append(("tip", "tip"))
try:
navbefore.insert(0, ("(0)", hex(nodefunc('0').node())))
except error.RepoError:
pass
def gen(l):
def f(**map):
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 for label, node in l:
yield {"label": label, "node": node}
Nicolas Dumazet
hgweb: changenav: separate pages before and after the current position...
r10254 return f
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Matt Mackall
many, many trivial check-code fixups
r10282 return (dict(before=gen(navbefore), after=gen(navafter)),)
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393
Dirkjan Ochtman
hgweb: simplify parents/children generation code
r7671 def _siblings(siblings=[], hiderev=None):
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 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()}
Dirkjan Ochtman
hgweb: pass more information about parent/child csets to templates
r7294 d['user'] = s.user()
d['date'] = s.date()
d['description'] = s.description()
Dirkjan Ochtman
hgweb: expose sibling branches to templater
r7717 d['branch'] = s.branch()
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 if hasattr(s, 'path'):
d['file'] = s.path()
yield d
Dirkjan Ochtman
hgweb: simplify parents/children generation code
r7671 def parents(ctx, hide=None):
return _siblings(ctx.parents(), hide)
def children(ctx, hide=None):
return _siblings(ctx.children(), hide)
Matt Mackall
hgweb: minor improvements for new web style...
r6434 def renamelink(fctx):
Matt Mackall
hgweb: fix merge breakage
r6437 r = fctx.renamed()
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 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 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 cleanpath(repo, path):
path = path.lstrip('/')
return util.canonpath(repo.root, '', path)
def changectx(repo, req):
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 changeid = "tip"
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 if 'node' in req.form:
changeid = req.form['node'][0]
elif 'manifest' in req.form:
changeid = req.form['manifest'][0]
try:
Matt Mackall
use repo[changeid] to get a changectx
r6747 ctx = repo[changeid]
Matt Mackall
error: move repo errors...
r7637 except error.RepoError:
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 man = repo.manifest
Matt Mackall
linkrev: take a revision number rather than a hash
r7361 ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
Dirkjan Ochtman
hgweb: separate out utility functions
r6392
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:
Matt Mackall
use repo[changeid] to get a changectx
r6747 fctx = repo[changeid][path]
Matt Mackall
error: move repo errors...
r7637 except error.RepoError:
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 fctx = repo.filectx(path, fileid=changeid)
return fctx
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310
Dirkjan Ochtman
hgweb: move another utility function into the webutil module
r7311 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')
Dirkjan Ochtman
hgweb: show diff header line in raw diffs
r9402 def diffs(repo, tmpl, ctx, files, parity, style):
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310
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 = []
Dirkjan Ochtman
hgweb: show diff header line in raw diffs
r9402 if chunk.startswith('diff') and style != 'raw':
Dirkjan Ochtman
hgweb: move the diffs() generator into webutil
r7310 chunk = ''.join(chunk.splitlines(True)[1:])
block.append(chunk)
yield tmpl('diffblock', parity=parity.next(),
lines=prettyprintlines(''.join(block)))
Dirkjan Ochtman
hgweb: fix up the less/more links on the graph page...
r7345
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 = '&'