##// END OF EJS Templates
patch.diff: avoid calling workingctx().manifest()...
patch.diff: avoid calling workingctx().manifest() Right now, to generate the manifest of the working dir, we have to perform a full walk of the working dir, which will be very slow, especially if we're interested in only a small part of it. Since we use the manifest only to find out the mode of files for git patches, manually build an execf function to do it. This should fix issue567.

File last commit:

r4469:8af65bc0 default
r4496:b79cdb7f default
Show More
hgweb_mod.py
1158 lines | 40.6 KiB | text/x-python | PythonLexer
Eric Hopper
Fixing up comment headers for split up code.
r2391 # hgweb/hgweb_mod.py - Web interface for a repository.
Eric Hopper
Final stage of the hgweb split up....
r2356 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
Vadim Gelfer
update copyrights.
r2859 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
Eric Hopper
Final stage of the hgweb split up....
r2356 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Benoit Boissinot
hgweb: fix unused import
r3974 import os, mimetypes, re, zlib, mimetools, cStringIO, sys
Matt Mackall
Replace demandload with new demandimport
r3877 import tempfile, urllib, bz2
Eric Hopper
Final stage of the hgweb split up....
r2356 from mercurial.node import *
from mercurial.i18n import gettext as _
Matt Mackall
Replace demandload with new demandimport
r3877 from mercurial import mdiff, ui, hg, util, archival, streamclone, patch
from mercurial import revlog, templater
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 from common import get_mtime, staticfile, style_map, paritygen
Eric Hopper
Final stage of the hgweb split up....
r2356
def _up(p):
if p[0] != "/":
p = "/" + p
if p[-1] == "/":
p = p[:-1]
up = os.path.dirname(p)
if up == "/":
return "/"
return up + "/"
Brendan Cully
Convert changenav bar from revisions to hashes (closes issue189)
r3422 def revnavgen(pos, pagelen, limit, nodefunc):
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407 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:
Brendan Cully
Convert changenav bar from revisions to hashes (closes issue189)
r3422 l.append(("+%d" % f, hex(nodefunc(pos + f).node())))
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407 if pos - f >= 0:
Brendan Cully
Convert changenav bar from revisions to hashes (closes issue189)
r3422 l.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node())))
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407
Brendan Cully
Fix test-oldcgi after navbar update
r3424 try:
yield {"label": "(0)", "node": hex(nodefunc('0').node())}
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407
Brendan Cully
Fix test-oldcgi after navbar update
r3424 for label, node in l:
yield {"label": label, "node": node}
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407
Thomas Arendsen Hein
Explicitly use "tip" in revision navigation....
r3427 yield {"label": "tip", "node": "tip"}
Brendan Cully
Fix test-oldcgi after navbar update
r3424 except hg.RepoError:
pass
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407
return nav
Eric Hopper
Final stage of the hgweb split up....
r2356 class hgweb(object):
def __init__(self, repo, name=None):
if type(repo) == type(""):
Thomas Arendsen Hein
Turn of "Not trusting file" logging when running hgweb and hgwebdir...
r3557 self.repo = hg.repository(ui.ui(report_untrusted=False), repo)
Eric Hopper
Final stage of the hgweb split up....
r2356 else:
self.repo = repo
self.mtime = -1
self.reponame = name
self.archives = 'zip', 'gz', 'bz2'
Frank Kingswood
hgweb: Configurable zebra stripes...
r2666 self.stripecount = 1
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 # a repo owner may set web.templates in .hg/hgrc to get any file
# readable by the user running the CGI script
self.templatepath = self.config("web", "templates",
templater.templatepath(),
untrusted=False)
# The CGI scripts are often run by a user different from the repo owner.
# Trust the settings from the .hg/hgrc files by default.
def config(self, section, name, default=None, untrusted=True):
return self.repo.ui.config(section, name, default,
untrusted=untrusted)
def configbool(self, section, name, default=False, untrusted=True):
return self.repo.ui.configbool(section, name, default,
untrusted=untrusted)
def configlist(self, section, name, default=None, untrusted=True):
return self.repo.ui.configlist(section, name, default,
untrusted=untrusted)
Eric Hopper
Final stage of the hgweb split up....
r2356
def refresh(self):
mtime = get_mtime(self.repo.root)
if mtime != self.mtime:
self.mtime = mtime
self.repo = hg.repository(self.repo.ui, self.repo.root)
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 self.maxchanges = int(self.config("web", "maxchanges", 10))
self.stripecount = int(self.config("web", "stripes", 1))
self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
self.maxfiles = int(self.config("web", "maxfiles", 10))
self.allowpull = self.configbool("web", "allowpull", True)
Eric Hopper
Final stage of the hgweb split up....
r2356
def archivelist(self, nodeid):
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 allowed = self.configlist("web", "allow_archive")
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 for i, spec in self.archive_specs.iteritems():
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 if i in allowed or self.configbool("web", "allow" + i):
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 yield {"type" : i, "extension" : spec[2], "node" : nodeid}
Eric Hopper
Final stage of the hgweb split up....
r2356
def listfilediffs(self, files, changeset):
for f in files[:self.maxfiles]:
yield self.t("filedifflink", node=hex(changeset), file=f)
if len(files) > self.maxfiles:
yield self.t("fileellipses")
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 def siblings(self, siblings=[], hiderev=None, **args):
siblings = [s for s in siblings if s.node() != nullid]
if len(siblings) == 1 and siblings[0].rev() == hiderev:
Eric Hopper
Final stage of the hgweb split up....
r2356 return
for s in siblings:
Brendan Cully
hgweb: fix parent/child links across renames
r3392 d = {'node': hex(s.node()), 'rev': s.rev()}
Brendan Cully
hgweb: really fix parent/child rename links
r3394 if hasattr(s, 'path'):
d['file'] = s.path()
Brendan Cully
hgweb: fix parent/child links across renames
r3392 d.update(args)
yield d
Eric Hopper
Final stage of the hgweb split up....
r2356
def renamelink(self, fl, node):
r = fl.renamed(node)
if r:
return [dict(file=r[0], node=hex(r[1]))]
return []
def showtag(self, t1, node=nullid, **args):
for t in self.repo.nodetags(node):
Thomas Arendsen Hein
white space and line break cleanups
r3673 yield self.t(t1, tag=t, **args)
Eric Hopper
Final stage of the hgweb split up....
r2356
def diff(self, node1, node2, files):
def filterfiles(filters, files):
l = [x for x in files if x in filters]
for t in filters:
if t and t[-1] != os.sep:
t += os.sep
l += [x for x in files if x.startswith(t)]
return l
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Eric Hopper
Final stage of the hgweb split up....
r2356 def diffblock(diff, f, fn):
yield self.t("diffblock",
lines=prettyprintlines(diff),
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity=parity.next(),
Eric Hopper
Final stage of the hgweb split up....
r2356 file=f,
filenode=hex(fn or nullid))
def prettyprintlines(diff):
for l in diff.splitlines(1):
if l.startswith('+'):
yield self.t("difflineplus", line=l)
elif l.startswith('-'):
yield self.t("difflineminus", line=l)
elif l.startswith('@'):
yield self.t("difflineat", line=l)
else:
yield self.t("diffline", line=l)
r = self.repo
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 c1 = r.changectx(node1)
c2 = r.changectx(node2)
date1 = util.datestr(c1.date())
date2 = util.datestr(c2.date())
Eric Hopper
Final stage of the hgweb split up....
r2356
Giorgos Keramidas
hgweb: repo.changes() is now called repo.status()
r2876 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
Eric Hopper
Final stage of the hgweb split up....
r2356 if files:
modified, added, removed = map(lambda x: filterfiles(files, x),
(modified, added, removed))
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 diffopts = patch.diffopts(self.repo.ui, untrusted=True)
Eric Hopper
Final stage of the hgweb split up....
r2356 for f in modified:
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 to = c1.filectx(f).data()
tn = c2.filectx(f).data()
Eric Hopper
Final stage of the hgweb split up....
r2356 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
Vadim Gelfer
refactor text diff/patch code....
r2874 opts=diffopts), f, tn)
Eric Hopper
Final stage of the hgweb split up....
r2356 for f in added:
to = None
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 tn = c2.filectx(f).data()
Eric Hopper
Final stage of the hgweb split up....
r2356 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
Vadim Gelfer
refactor text diff/patch code....
r2874 opts=diffopts), f, tn)
Eric Hopper
Final stage of the hgweb split up....
r2356 for f in removed:
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 to = c1.filectx(f).data()
Eric Hopper
Final stage of the hgweb split up....
r2356 tn = None
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
Vadim Gelfer
refactor text diff/patch code....
r2874 opts=diffopts), f, tn)
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
hgweb: use contexts in more handlers
r3220 def changelog(self, ctx, shortlog=False):
Eric Hopper
Final stage of the hgweb split up....
r2356 def changelist(**map):
cl = self.repo.changelog
l = [] # build a list in forward order for efficiency
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(start, end):
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 ctx = self.repo.changectx(i)
n = ctx.node()
Eric Hopper
Final stage of the hgweb split up....
r2356
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 l.insert(0, {"parity": parity.next(),
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 "author": ctx.user(),
"parent": self.siblings(ctx.parents(), i - 1),
"child": self.siblings(ctx.children(), i + 1),
Eric Hopper
Final stage of the hgweb split up....
r2356 "changelogtag": self.showtag("changelogtag",n),
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 "desc": ctx.description(),
"date": ctx.date(),
"files": self.listfilediffs(ctx.files(), n),
Eric Hopper
Final stage of the hgweb split up....
r2356 "rev": i,
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 "node": hex(n)})
Eric Hopper
Final stage of the hgweb split up....
r2356
for e in l:
yield e
Josef "Jeff" Sipek
[hgweb] Implemented shortlog (gitweb templates only)
r2684 maxchanges = shortlog and self.maxshortchanges or self.maxchanges
Eric Hopper
Final stage of the hgweb split up....
r2356 cl = self.repo.changelog
count = cl.count()
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407 pos = ctx.rev()
Josef "Jeff" Sipek
[hgweb] Implemented shortlog (gitweb templates only)
r2684 start = max(0, pos - maxchanges + 1)
end = min(count, start + maxchanges)
Eric Hopper
Final stage of the hgweb split up....
r2356 pos = end - 1
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount, offset=start-end)
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
Convert changenav bar from revisions to hashes (closes issue189)
r3422 changenav = revnavgen(pos, maxchanges, count, self.repo.changectx)
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407
Josef "Jeff" Sipek
[hgweb] Implemented shortlog (gitweb templates only)
r2684 yield self.t(shortlog and 'shortlog' or 'changelog',
Eric Hopper
Final stage of the hgweb split up....
r2356 changenav=changenav,
Brendan Cully
hgweb: kill #manifest#
r3205 node=hex(cl.tip()),
Eric Hopper
Final stage of the hgweb split up....
r2356 rev=pos, changesets=count, entries=changelist,
archives=self.archivelist("tip"))
def search(self, query):
def changelist(**map):
cl = self.repo.changelog
count = 0
qw = query.lower().split()
def revgen():
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(cl.count() - 1, 0, -100):
Eric Hopper
Final stage of the hgweb split up....
r2356 l = []
Benoit Boissinot
use xrange instead of range
r3473 for j in xrange(max(0, i - 100), i):
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 ctx = self.repo.changectx(j)
l.append(ctx)
Eric Hopper
Final stage of the hgweb split up....
r2356 l.reverse()
for e in l:
yield e
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 for ctx in revgen():
Eric Hopper
Final stage of the hgweb split up....
r2356 miss = 0
for q in qw:
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 if not (q in ctx.user().lower() or
q in ctx.description().lower() or
TK Soh
hgweb: expand keyword search to full list of files
r4323 q in " ".join(ctx.files()).lower()):
Eric Hopper
Final stage of the hgweb split up....
r2356 miss = 1
break
if miss:
continue
count += 1
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 n = ctx.node()
Eric Hopper
Final stage of the hgweb split up....
r2356
yield self.t('searchentry',
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity=parity.next(),
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 author=ctx.user(),
parent=self.siblings(ctx.parents()),
child=self.siblings(ctx.children()),
Eric Hopper
Final stage of the hgweb split up....
r2356 changelogtag=self.showtag("changelogtag",n),
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 desc=ctx.description(),
date=ctx.date(),
files=self.listfilediffs(ctx.files(), n),
rev=ctx.rev(),
node=hex(n))
Eric Hopper
Final stage of the hgweb split up....
r2356
if count >= self.maxchanges:
break
cl = self.repo.changelog
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Eric Hopper
Final stage of the hgweb split up....
r2356
yield self.t('search',
query=query,
Brendan Cully
hgweb: kill #manifest#
r3205 node=hex(cl.tip()),
Josef "Jeff" Sipek
gitweb: Fixed-up search template...
r4469 entries=changelist,
archives=self.archivelist("tip"))
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
hgweb: use contexts in more handlers
r3220 def changeset(self, ctx):
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 n = ctx.node()
parents = ctx.parents()
p1 = parents[0].node()
Eric Hopper
Final stage of the hgweb split up....
r2356
files = []
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 for f in ctx.files():
Eric Hopper
Final stage of the hgweb split up....
r2356 files.append(self.t("filenodelink",
Brendan Cully
hgweb: kill off #filenode#
r3206 node=hex(n), file=f,
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity=parity.next()))
Eric Hopper
Final stage of the hgweb split up....
r2356
def diff(**map):
yield self.diff(p1, n, None)
yield self.t('changeset',
diff=diff,
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 rev=ctx.rev(),
node=hex(n),
parent=self.siblings(parents),
child=self.siblings(ctx.children()),
Eric Hopper
Final stage of the hgweb split up....
r2356 changesettag=self.showtag("changesettag",n),
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 author=ctx.user(),
desc=ctx.description(),
date=ctx.date(),
Eric Hopper
Final stage of the hgweb split up....
r2356 files=files,
Brendan Cully
hgweb: use contexts in more handlers
r3220 archives=self.archivelist(hex(n)))
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
hgweb: kill off #filenode#
r3206 def filelog(self, fctx):
f = fctx.path()
fl = fctx.filelog()
Eric Hopper
Final stage of the hgweb split up....
r2356 count = fl.count()
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407 pagelen = self.maxshortchanges
Thomas Arendsen Hein
Fixed page overlap for file revision links in hgweb....
r3409 pos = fctx.filerev()
Thomas Arendsen Hein
white space and line break cleanups
r3673 start = max(0, pos - pagelen + 1)
Thomas Arendsen Hein
Fixed page overlap for file revision links in hgweb....
r3409 end = min(count, start + pagelen)
pos = end - 1
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount, offset=start-end)
Eric Hopper
Final stage of the hgweb split up....
r2356
def entries(**map):
l = []
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(start, end):
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 ctx = fctx.filectx(i)
Eric Hopper
Final stage of the hgweb split up....
r2356 n = fl.node(i)
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 l.insert(0, {"parity": parity.next(),
Eric Hopper
Final stage of the hgweb split up....
r2356 "filerev": i,
"file": f,
Brendan Cully
hgweb: kill off #filenode#
r3206 "node": hex(ctx.node()),
"author": ctx.user(),
"date": ctx.date(),
Eric Hopper
Final stage of the hgweb split up....
r2356 "rename": self.renamelink(fl, n),
Brendan Cully
hgweb: fix parent/child links across renames
r3392 "parent": self.siblings(fctx.parents()),
"child": self.siblings(fctx.children()),
Brendan Cully
hgweb: kill off #filenode#
r3206 "desc": ctx.description()})
Eric Hopper
Final stage of the hgweb split up....
r2356
for e in l:
yield e
Brendan Cully
Convert changenav bar from revisions to hashes (closes issue189)
r3422 nodefunc = lambda x: fctx.filectx(fileid=x)
nav = revnavgen(pos, pagelen, count, nodefunc)
Brendan Cully
hgweb: hoist changenav up, and use it in the filelog
r3407 yield self.t("filelog", file=f, node=hex(fctx.node()), nav=nav,
entries=entries)
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
hgweb: kill off #filenode#
r3206 def filerevision(self, fctx):
f = fctx.path()
text = fctx.data()
fl = fctx.filelog()
n = fctx.filenode()
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Eric Hopper
Final stage of the hgweb split up....
r2356
mt = mimetypes.guess_type(f)[0]
rawtext = text
if util.binary(text):
mt = mt or 'application/octet-stream'
text = "(binary:%s)" % mt
mt = mt or 'text/plain'
def lines():
for l, t in enumerate(text.splitlines(1)):
yield {"line": t,
"linenumber": "% 6d" % (l + 1),
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 "parity": parity.next()}
Eric Hopper
Final stage of the hgweb split up....
r2356
yield self.t("filerevision",
file=f,
path=_up(f),
text=lines(),
raw=rawtext,
mimetype=mt,
Brendan Cully
hgweb: kill off #filenode#
r3206 rev=fctx.rev(),
node=hex(fctx.node()),
author=fctx.user(),
date=fctx.date(),
Brendan Cully
hgweb: add changeset description to file revision page
r3395 desc=fctx.description(),
Brendan Cully
hgweb: fix parent/child links across renames
r3392 parent=self.siblings(fctx.parents()),
child=self.siblings(fctx.children()),
Eric Hopper
Final stage of the hgweb split up....
r2356 rename=self.renamelink(fl, n),
Brendan Cully
hgweb: kill off #filenode#
r3206 permissions=fctx.manifest().execf(f))
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
hgweb: kill off #filenode#
r3206 def fileannotate(self, fctx):
f = fctx.path()
Brendan Cully
hgweb: use filectx.annotate instead of filelog
r3173 n = fctx.filenode()
fl = fctx.filelog()
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Eric Hopper
Final stage of the hgweb split up....
r2356
def annotate(**map):
last = None
Brendan Cully
hgweb: make annotate line revisions point to annotation for that rev
r3175 for f, l in fctx.annotate(follow=True):
fnode = f.filenode()
Brendan Cully
hgweb: use filectx.annotate instead of filelog
r3173 name = self.repo.ui.shortuser(f.user())
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
hgweb: make annotate line revisions point to annotation for that rev
r3175 if last != fnode:
last = fnode
Eric Hopper
Final stage of the hgweb split up....
r2356
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 yield {"parity": parity.next(),
Brendan Cully
hgweb: yield filenode as well as node in annotate, use filenode in annotateline
r3178 "node": hex(f.node()),
Brendan Cully
Back out d8eba1c3ce9b and a004164dbeef
r3403 "rev": f.rev(),
Eric Hopper
Final stage of the hgweb split up....
r2356 "author": name,
Brendan Cully
hgweb: use filectx.annotate instead of filelog
r3173 "file": f.path(),
Eric Hopper
Final stage of the hgweb split up....
r2356 "line": l}
yield self.t("fileannotate",
file=f,
annotate=annotate,
path=_up(f),
Brendan Cully
hgweb: use filectx.annotate instead of filelog
r3173 rev=fctx.rev(),
Brendan Cully
hgweb: fix changeset link in annotate view.
r3177 node=hex(fctx.node()),
Brendan Cully
hgweb: use filectx.annotate instead of filelog
r3173 author=fctx.user(),
date=fctx.date(),
Brendan Cully
hgweb: add changeset description to annotate page
r3391 desc=fctx.description(),
Eric Hopper
Final stage of the hgweb split up....
r2356 rename=self.renamelink(fl, n),
Brendan Cully
hgweb: fix parent/child links across renames
r3392 parent=self.siblings(fctx.parents()),
child=self.siblings(fctx.children()),
Brendan Cully
hgweb: use filectx.annotate instead of filelog
r3173 permissions=fctx.manifest().execf(f))
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
hgweb: kill #manifest#
r3205 def manifest(self, ctx, path):
mf = ctx.manifest()
node = ctx.node()
Eric Hopper
Final stage of the hgweb split up....
r2356
files = {}
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Eric Hopper
Final stage of the hgweb split up....
r2356
Benoit Boissinot
hgweb: fix handling of path for old style template...
r3595 if path and path[-1] != "/":
path += "/"
l = len(path)
abspath = "/" + path
Eric Hopper
Final stage of the hgweb split up....
r2356
Thomas Arendsen Hein
white space and line break cleanups
r3673 for f, n in mf.items():
Benoit Boissinot
hgweb: fix handling of path for old style template...
r3595 if f[:l] != path:
Eric Hopper
Final stage of the hgweb split up....
r2356 continue
remain = f[l:]
if "/" in remain:
Benoit Boissinot
use __contains__, index or split instead of str.find...
r2579 short = remain[:remain.index("/") + 1] # bleah
Eric Hopper
Final stage of the hgweb split up....
r2356 files[short] = (f, None)
else:
short = os.path.basename(remain)
files[short] = (f, n)
def filelist(**map):
fl = files.keys()
fl.sort()
for f in fl:
full, fnode = files[f]
if not fnode:
continue
yield {"file": full,
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 "parity": parity.next(),
Eric Hopper
Final stage of the hgweb split up....
r2356 "basename": f,
Matt Mackall
hgweb: add file sizes to manifest browsing
r3305 "size": ctx.filectx(full).size(),
Alexis S. L. Carvalho
Fix some bugs introduced during the manifest refactoring
r2857 "permissions": mf.execf(full)}
Eric Hopper
Final stage of the hgweb split up....
r2356
def dirlist(**map):
fl = files.keys()
fl.sort()
for f in fl:
full, fnode = files[f]
if fnode:
continue
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 yield {"parity": parity.next(),
Benoit Boissinot
hgweb: fix handling of path for old style template...
r3595 "path": os.path.join(abspath, f),
Eric Hopper
Final stage of the hgweb split up....
r2356 "basename": f[:-1]}
yield self.t("manifest",
Brendan Cully
hgweb: kill #manifest#
r3205 rev=ctx.rev(),
Eric Hopper
Final stage of the hgweb split up....
r2356 node=hex(node),
Benoit Boissinot
hgweb: fix handling of path for old style template...
r3595 path=abspath,
up=_up(abspath),
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 upparity=parity.next(),
Eric Hopper
Final stage of the hgweb split up....
r2356 fentries=filelist,
dentries=dirlist,
archives=self.archivelist(hex(node)))
def tags(self):
i = self.repo.tagslist()
i.reverse()
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Eric Hopper
Final stage of the hgweb split up....
r2356
def entries(notip=False, **map):
Thomas Arendsen Hein
white space and line break cleanups
r3673 for k, n in i:
if notip and k == "tip":
continue
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 yield {"parity": parity.next(),
Eric Hopper
Final stage of the hgweb split up....
r2356 "tag": k,
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 "date": self.repo.changectx(n).date(),
Eric Hopper
Final stage of the hgweb split up....
r2356 "node": hex(n)}
yield self.t("tags",
Brendan Cully
hgweb: kill #manifest#
r3205 node=hex(self.repo.changelog.tip()),
Eric Hopper
Final stage of the hgweb split up....
r2356 entries=lambda **x: entries(False, **x),
entriesnotip=lambda **x: entries(True, **x))
def summary(self):
i = self.repo.tagslist()
i.reverse()
def tagentries(**map):
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Eric Hopper
Final stage of the hgweb split up....
r2356 count = 0
Thomas Arendsen Hein
white space and line break cleanups
r3673 for k, n in i:
Eric Hopper
Final stage of the hgweb split up....
r2356 if k == "tip": # skip tip
continue;
count += 1
if count > 10: # limit to 10 tags
break;
yield self.t("tagentry",
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity=parity.next(),
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 tag=k,
node=hex(n),
date=self.repo.changectx(n).date())
Eric Hopper
Final stage of the hgweb split up....
r2356
greg@maptuit.com
hgweb: display named branches in gitweb-style summary page
r4300
def branches(**map):
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Brendan Cully
hgweb: add heads to gitweb summary
r3499
greg@maptuit.com
hgweb: display named branches in gitweb-style summary page
r4300 b = self.repo.branchtags()
l = [(-self.repo.changelog.rev(n), n, t) for t, n in b.items()]
l.sort()
Brendan Cully
hgweb: add heads to gitweb summary
r3499
greg@maptuit.com
hgweb: display named branches in gitweb-style summary page
r4300 for r,n,t in l:
ctx = self.repo.changectx(n)
Brendan Cully
hgweb: add heads to gitweb summary
r3499
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 yield {'parity': parity.next(),
greg@maptuit.com
hgweb: display named branches in gitweb-style summary page
r4300 'branch': t,
'node': hex(n),
Brendan Cully
hgweb: add heads to gitweb summary
r3499 'date': ctx.date()}
Eric Hopper
Final stage of the hgweb split up....
r2356 def changelist(**map):
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount, offset=start-end)
Eric Hopper
Final stage of the hgweb split up....
r2356 l = [] # build a list in forward order for efficiency
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(start, end):
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 ctx = self.repo.changectx(i)
hn = hex(ctx.node())
Eric Hopper
Final stage of the hgweb split up....
r2356
l.insert(0, self.t(
'shortlogentry',
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity=parity.next(),
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 author=ctx.user(),
desc=ctx.description(),
date=ctx.date(),
rev=i,
node=hn))
Eric Hopper
Final stage of the hgweb split up....
r2356
yield l
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 cl = self.repo.changelog
Eric Hopper
Final stage of the hgweb split up....
r2356 count = cl.count()
start = max(0, count - self.maxchanges)
end = min(count, start + self.maxchanges)
yield self.t("summary",
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 desc=self.config("web", "description", "unknown"),
owner=(self.config("ui", "username") or # preferred
self.config("web", "contact") or # deprecated
self.config("web", "author", "unknown")), # also
lastchange=cl.read(cl.tip())[2],
tags=tagentries,
greg@maptuit.com
hgweb: display named branches in gitweb-style summary page
r4300 branches=branches,
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 shortlog=changelist,
node=hex(cl.tip()),
Josef "Jeff" Sipek
[hgweb] Fixed up gitweb templates...
r2683 archives=self.archivelist("tip"))
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
hgweb: use contexts in more handlers
r3220 def filediff(self, fctx):
n = fctx.node()
path = fctx.path()
Brendan Cully
hgweb: link to file parents in filediff, rather than changeset parents
r3406 parents = fctx.parents()
p1 = parents and parents[0].node() or nullid
Eric Hopper
Final stage of the hgweb split up....
r2356
def diff(**map):
Brendan Cully
hgweb: use contexts in more handlers
r3220 yield self.diff(p1, n, [path])
Eric Hopper
Final stage of the hgweb split up....
r2356
yield self.t("filediff",
Brendan Cully
hgweb: use contexts in more handlers
r3220 file=path,
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 node=hex(n),
Brendan Cully
hgweb: use contexts in more handlers
r3220 rev=fctx.rev(),
Brendan Cully
hgweb: teach siblings and callers to use contexts
r3208 parent=self.siblings(parents),
Brendan Cully
hgweb: use contexts in more handlers
r3220 child=self.siblings(fctx.children()),
Eric Hopper
Final stage of the hgweb split up....
r2356 diff=diff)
archive_specs = {
Thomas Arendsen Hein
Fix automatic decompression of tarballs with Firefox....
r2361 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
Eric Hopper
Final stage of the hgweb split up....
r2356 'zip': ('application/zip', 'zip', '.zip', None),
}
Michael Gebetsroither
hgweb: use the given revision in the name of the archive...
r4164 def archive(self, req, id, type_):
Eric Hopper
Final stage of the hgweb split up....
r2356 reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame))
Michael Gebetsroither
hgweb: use the given revision in the name of the archive...
r4164 cnode = self.repo.lookup(id)
arch_version = id
Christian Ebert
hgweb: short hash for tip archive name
r4282 if cnode == id or id == 'tip':
Michael Gebetsroither
hgweb: use the given revision in the name of the archive...
r4164 arch_version = short(cnode)
name = "%s-%s" % (reponame, arch_version)
Benoit Boissinot
hgweb: fix errors and warnings found by pychecker...
r2394 mimetype, artype, extension, encoding = self.archive_specs[type_]
Eric Hopper
Final stage of the hgweb split up....
r2356 headers = [('Content-type', mimetype),
('Content-disposition', 'attachment; filename=%s%s' %
(name, extension))]
if encoding:
headers.append(('Content-encoding', encoding))
req.header(headers)
archival.archive(self.repo, req.out, cnode, artype, prefix=name)
# add tags to things
# tags -> list of changesets corresponding to tags
# find tag, changeset, file
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436 def cleanpath(self, path):
Benoit Boissinot
hgweb: fix handling of path for old style template...
r3595 path = path.lstrip('/')
Benoit Boissinot
hgweb: fix path cleaning
r3382 return util.canonpath(self.repo.root, '', path)
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535 def run(self):
Eric Hopper
Cleanup hgweb and hgwebdir's run method a bit.
r2538 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535 raise RuntimeError("This function is only intended to be called while running as a CGI script.")
import mercurial.hgweb.wsgicgi as wsgicgi
from request import wsgiapplication
def make_web_app():
Eric Hopper
Cleanup hgweb and hgwebdir's run method a bit.
r2538 return self
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535 wsgicgi.launch(wsgiapplication(make_web_app))
def run_wsgi(self, req):
Eric Hopper
Final stage of the hgweb split up....
r2356 def header(**map):
Matt Mackall
hgweb: report detected character set...
r3781 header_file = cStringIO.StringIO(
Thomas Arendsen Hein
Set charset encoding for hgwebdir, too....
r3882 ''.join(self.t("header", encoding=util._encoding, **map)))
Eric Hopper
Really fix http headers for web UI and issue 254....
r2514 msg = mimetools.Message(header_file, 0)
req.header(msg.items())
yield header_file.read()
Eric Hopper
Final stage of the hgweb split up....
r2356
Eric Hopper
Fix raw files in the web UI.
r2534 def rawfileheader(**map):
req.header([('Content-type', map['mimetype']),
('Content-disposition', 'filename=%s' % map['file']),
('Content-length', str(len(map['raw'])))])
yield ''
Eric Hopper
Final stage of the hgweb split up....
r2356 def footer(**map):
Alexis S. L. Carvalho
hgweb: make #motd# available for all templates
r3488 yield self.t("footer", **map)
def motd(**map):
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 yield self.config("web", "motd", "")
Eric Hopper
Final stage of the hgweb split up....
r2356
def expand_form(form):
shortcuts = {
'cl': [('cmd', ['changelog']), ('rev', None)],
Josef "Jeff" Sipek
[hgweb] Implemented shortlog (gitweb templates only)
r2684 'sl': [('cmd', ['shortlog']), ('rev', None)],
Eric Hopper
Final stage of the hgweb split up....
r2356 'cs': [('cmd', ['changeset']), ('node', None)],
'f': [('cmd', ['file']), ('filenode', None)],
'fl': [('cmd', ['filelog']), ('filenode', None)],
'fd': [('cmd', ['filediff']), ('node', None)],
'fa': [('cmd', ['annotate']), ('filenode', None)],
'mf': [('cmd', ['manifest']), ('manifest', None)],
'ca': [('cmd', ['archive']), ('node', None)],
'tags': [('cmd', ['tags'])],
'tip': [('cmd', ['changeset']), ('node', ['tip'])],
'static': [('cmd', ['static']), ('file', None)]
}
for k in shortcuts.iterkeys():
if form.has_key(k):
for name, value in shortcuts[k]:
if value is None:
value = form[k]
form[name] = value
del form[k]
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 def rewrite_request(req):
'''translate new web interface to traditional format'''
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 def spliturl(req):
def firstitem(query):
return query.split('&', 1)[0].split(';', 1)[0]
Brendan Cully
NWI base URL detection fixes
r3327 def normurl(url):
inner = '/'.join([x for x in url.split('/') if x])
tl = len(url) > 1 and url.endswith('/') and '/' or ''
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263
Brendan Cully
NWI base URL detection fixes
r3327 return '%s%s%s' % (url.startswith('/') and '/' or '',
inner, tl)
Brendan Cully
hgweb: split URLs containing spaces or other escaped characters correctly
r3606 root = normurl(urllib.unquote(req.env.get('REQUEST_URI', '').split('?', 1)[0]))
Brendan Cully
NWI base URL detection fixes
r3327 pi = normurl(req.env.get('PATH_INFO', ''))
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 if pi:
Brendan Cully
NWI base URL detection fixes
r3327 # strip leading /
pi = pi[1:]
if pi:
Matt Mackall
hgweb: fix rfind bug in PATH_INFO handling
r4348 root = root[:root.rfind(pi)]
Brendan Cully
NWI base URL detection fixes
r3327 if req.env.has_key('REPO_NAME'):
rn = req.env['REPO_NAME'] + '/'
root += rn
query = pi[len(rn):]
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 else:
Brendan Cully
NWI base URL detection fixes
r3327 query = pi
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 else:
Brendan Cully
NWI base URL detection fixes
r3327 root += '?'
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 query = firstitem(req.env['QUERY_STRING'])
Brendan Cully
NWI base URL detection fixes
r3327 return (root, query)
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263
req.url, query = spliturl(req)
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 if req.form.has_key('cmd'):
# old style
return
args = query.split('/', 2)
if not args or not args[0]:
return
cmd = args.pop(0)
Brendan Cully
hgweb: extract raw prefix from NWI commands
r3261 style = cmd.rfind('-')
if style != -1:
req.form['style'] = [cmd[:style]]
cmd = cmd[style+1:]
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 # avoid accepting e.g. style parameter as command
if hasattr(self, 'do_' + cmd):
req.form['cmd'] = [cmd]
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260
if args and args[0]:
node = args.pop(0)
req.form['node'] = [node]
if args:
req.form['file'] = args
if cmd == 'static':
req.form['file'] = req.form['node']
elif cmd == 'archive':
fn = req.form['node'][0]
for type_, spec in self.archive_specs.iteritems():
ext = spec[2]
if fn.endswith(ext):
req.form['node'] = [fn[:-len(ext)]]
req.form['type'] = [type_]
Thomas Arendsen Hein
hgweb: Keep session variables (currently only style) in HTML forms, too....
r3362 def sessionvars(**map):
fields = []
if req.form.has_key('style'):
style = req.form['style'][0]
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 if style != self.config('web', 'style', ''):
Thomas Arendsen Hein
hgweb: Keep session variables (currently only style) in HTML forms, too....
r3362 fields.append(('style', style))
Thomas Arendsen Hein
hgweb: Apply the new method of passing session variables to links.
r3363 separator = req.url[-1] == '?' and ';' or '?'
Thomas Arendsen Hein
hgweb: Keep session variables (currently only style) in HTML forms, too....
r3362 for name, value in fields:
Thomas Arendsen Hein
hgweb: Apply the new method of passing session variables to links.
r3363 yield dict(name=name, value=value, separator=separator)
separator = ';'
Brendan Cully
hgweb: provide means for handling query parameters
r3270
Eric Hopper
Final stage of the hgweb split up....
r2356 self.refresh()
expand_form(req.form)
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 rewrite_request(req)
Eric Hopper
Final stage of the hgweb split up....
r2356
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 style = self.config("web", "style", "")
Eric Hopper
Final stage of the hgweb split up....
r2356 if req.form.has_key('style'):
style = req.form['style'][0]
Thomas Arendsen Hein
hgweb: Search templates in templatepath/style/map, too, using a common function....
r3276 mapfile = style_map(self.templatepath, style)
Eric Hopper
Final stage of the hgweb split up....
r2356
Brendan Cully
Fix RSS URLs (closes issue396)
r3423 port = req.env["SERVER_PORT"]
port = port != "80" and (":" + port) or ""
urlbase = 'http://%s%s' % (req.env['SERVER_NAME'], port)
Alexis S. L. Carvalho
hgweb: allow static files to be served directly by the HTTP server
r4084 staticurl = self.config("web", "staticurl") or req.url + 'static/'
if not staticurl.endswith('/'):
staticurl += '/'
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263
Eric Hopper
Final stage of the hgweb split up....
r2356 if not self.reponame:
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 self.reponame = (self.config("web", "name")
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 or req.env.get('REPO_NAME')
or req.url.strip('/') or self.repo.root)
Eric Hopper
Final stage of the hgweb split up....
r2356
Thomas Arendsen Hein
hgweb: Search templates in templatepath/style/map, too, using a common function....
r3276 self.t = templater.templater(mapfile, templater.common_filters,
Brendan Cully
hgweb: support for generating and parsing NWI URLs
r3263 defaults={"url": req.url,
Alexis S. L. Carvalho
hgweb: allow static files to be served directly by the HTTP server
r4084 "staticurl": staticurl,
Brendan Cully
Fix RSS URLs (closes issue396)
r3423 "urlbase": urlbase,
Eric Hopper
Final stage of the hgweb split up....
r2356 "repo": self.reponame,
"header": header,
"footer": footer,
Alexis S. L. Carvalho
hgweb: make #motd# available for all templates
r3488 "motd": motd,
Eric Hopper
Fix raw files in the web UI.
r2534 "rawfileheader": rawfileheader,
Thomas Arendsen Hein
hgweb: Apply the new method of passing session variables to links.
r3363 "sessionvars": sessionvars
Eric Hopper
Final stage of the hgweb split up....
r2356 })
Alexis S. L. Carvalho
hgweb: break templater -> templater circular reference...
r4243 try:
if not req.form.has_key('cmd'):
req.form['cmd'] = [self.t.cache['default']]
Eric Hopper
Final stage of the hgweb split up....
r2356
Alexis S. L. Carvalho
hgweb: break templater -> templater circular reference...
r4243 cmd = req.form['cmd'][0]
Eric Hopper
Final stage of the hgweb split up....
r2356
Alexis S. L. Carvalho
hgweb: break templater -> templater circular reference...
r4243 method = getattr(self, 'do_' + cmd, None)
if method:
try:
method(req)
except (hg.RepoError, revlog.RevlogError), inst:
req.write(self.t("error", error=str(inst)))
else:
req.write(self.t("error", error='No such method: ' + cmd))
finally:
self.t = None
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436
Brendan Cully
hgweb: add methods to get contexts from request
r3226 def changectx(self, req):
if req.form.has_key('node'):
changeid = req.form['node'][0]
Brendan Cully
hgweb: globally default to tip if no revision is specified
r3333 elif req.form.has_key('manifest'):
changeid = req.form['manifest'][0]
Brendan Cully
hgweb: add methods to get contexts from request
r3226 else:
Brendan Cully
hgweb: globally default to tip if no revision is specified
r3333 changeid = self.repo.changelog.count() - 1
Brendan Cully
hgweb: add methods to get contexts from request
r3226 try:
ctx = self.repo.changectx(changeid)
except hg.RepoError:
man = self.repo.manifest
mn = man.lookup(changeid)
ctx = self.repo.changectx(man.linkrev(mn))
return ctx
def filectx(self, req):
path = self.cleanpath(req.form['file'][0])
if req.form.has_key('node'):
changeid = req.form['node'][0]
else:
changeid = req.form['filenode'][0]
try:
ctx = self.repo.changectx(changeid)
fctx = ctx.filectx(path)
except hg.RepoError:
fctx = self.repo.filectx(path, fileid=changeid)
return fctx
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 def do_log(self, req):
if req.form.has_key('file') and req.form['file'][0]:
self.do_filelog(req)
else:
self.do_changelog(req)
def do_rev(self, req):
self.do_changeset(req)
def do_file(self, req):
Benoit Boissinot
hgweb: fix handling of path for old style template...
r3595 path = self.cleanpath(req.form.get('file', [''])[0])
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 if path:
try:
req.write(self.filerevision(self.filectx(req)))
return
Brendan Cully
Teach hgweb about revlog.LookupError
r3936 except revlog.LookupError:
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 pass
Benoit Boissinot
hgweb: fix handling of path for old style template...
r3595 req.write(self.manifest(self.changectx(req), path))
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260
def do_diff(self, req):
self.do_filediff(req)
Brendan Cully
hgweb: add methods to get contexts from request
r3226 def do_changelog(self, req, shortlog = False):
if req.form.has_key('node'):
ctx = self.changectx(req)
Brendan Cully
hgweb: use contexts in more handlers
r3220 else:
Brendan Cully
hgweb: add methods to get contexts from request
r3226 if req.form.has_key('rev'):
hi = req.form['rev'][0]
else:
hi = self.repo.changelog.count() - 1
try:
ctx = self.repo.changectx(hi)
except hg.RepoError:
req.write(self.search(hi)) # XXX redirect to 404 page?
return
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436
Brendan Cully
hgweb: add methods to get contexts from request
r3226 req.write(self.changelog(ctx, shortlog = shortlog))
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436
Josef "Jeff" Sipek
[hgweb] Implemented shortlog (gitweb templates only)
r2684 def do_shortlog(self, req):
Brendan Cully
hgweb: add methods to get contexts from request
r3226 self.do_changelog(req, shortlog = True)
Josef "Jeff" Sipek
[hgweb] Implemented shortlog (gitweb templates only)
r2684
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436 def do_changeset(self, req):
Brendan Cully
hgweb: globally default to tip if no revision is specified
r3333 req.write(self.changeset(self.changectx(req)))
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436
def do_manifest(self, req):
Brendan Cully
hgweb: add methods to get contexts from request
r3226 req.write(self.manifest(self.changectx(req),
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436 self.cleanpath(req.form['path'][0])))
def do_tags(self, req):
req.write(self.tags())
def do_summary(self, req):
req.write(self.summary())
def do_filediff(self, req):
Brendan Cully
hgweb: add methods to get contexts from request
r3226 req.write(self.filediff(self.filectx(req)))
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436
def do_annotate(self, req):
Brendan Cully
hgweb: add methods to get contexts from request
r3226 req.write(self.fileannotate(self.filectx(req)))
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436
def do_filelog(self, req):
Brendan Cully
hgweb: add methods to get contexts from request
r3226 req.write(self.filelog(self.filectx(req)))
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436
Eric Hopper
Adding changegroupsubset and lookup to web protocol so pull -r and...
r3444 def do_lookup(self, req):
Matt Mackall
httprepo: add support for passing lookup exception data
r3445 try:
r = hex(self.repo.lookup(req.form['key'][0]))
success = 1
except Exception,inst:
r = str(inst)
success = 0
resp = "%s %s\n" % (success, r)
Eric Hopper
Adding changegroupsubset and lookup to web protocol so pull -r and...
r3444 req.httphdr("application/mercurial-0.1", length=len(resp))
req.write(resp)
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436 def do_heads(self, req):
resp = " ".join(map(hex, self.repo.heads())) + "\n"
req.httphdr("application/mercurial-0.1", length=len(resp))
req.write(resp)
def do_branches(self, req):
nodes = []
if req.form.has_key('nodes'):
nodes = map(bin, req.form['nodes'][0].split(" "))
resp = cStringIO.StringIO()
for b in self.repo.branches(nodes):
resp.write(" ".join(map(hex, b)) + "\n")
resp = resp.getvalue()
req.httphdr("application/mercurial-0.1", length=len(resp))
req.write(resp)
def do_between(self, req):
if req.form.has_key('pairs'):
pairs = [map(bin, p.split("-"))
for p in req.form['pairs'][0].split(" ")]
resp = cStringIO.StringIO()
for b in self.repo.between(pairs):
resp.write(" ".join(map(hex, b)) + "\n")
resp = resp.getvalue()
req.httphdr("application/mercurial-0.1", length=len(resp))
req.write(resp)
def do_changegroup(self, req):
req.httphdr("application/mercurial-0.1")
nodes = []
if not self.allowpull:
return
if req.form.has_key('roots'):
nodes = map(bin, req.form['roots'][0].split(" "))
z = zlib.compressobj()
f = self.repo.changegroup(nodes, 'serve')
while 1:
chunk = f.read(4096)
if not chunk:
break
req.write(z.compress(chunk))
req.write(z.flush())
Eric Hopper
Adding changegroupsubset and lookup to web protocol so pull -r and...
r3444 def do_changegroupsubset(self, req):
req.httphdr("application/mercurial-0.1")
bases = []
heads = []
if not self.allowpull:
return
if req.form.has_key('bases'):
bases = [bin(x) for x in req.form['bases'][0].split(' ')]
if req.form.has_key('heads'):
heads = [bin(x) for x in req.form['heads'][0].split(' ')]
z = zlib.compressobj()
f = self.repo.changegroupsubset(bases, heads, 'serve')
while 1:
chunk = f.read(4096)
if not chunk:
break
req.write(z.compress(chunk))
req.write(z.flush())
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436 def do_archive(self, req):
type_ = req.form['type'][0]
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 allowed = self.configlist("web", "allow_archive")
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436 if (type_ in self.archives and (type_ in allowed or
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 self.configbool("web", "allow" + type_, False))):
Michael Gebetsroither
hgweb: use the given revision in the name of the archive...
r4164 self.archive(req, req.form['node'][0], type_)
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436 return
req.write(self.t("error"))
def do_static(self, req):
fname = req.form['file'][0]
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 # a repo owner may set web.static in .hg/hgrc to get any file
# readable by the user running the CGI script
static = self.config("web", "static",
os.path.join(self.templatepath, "static"),
untrusted=False)
Eric Hopper
Really fix http headers for web UI and issue 254....
r2514 req.write(staticfile(static, fname, req)
Vadim Gelfer
hgweb: split "verbs" into methods.
r2436 or self.t("error", error="%r not found" % fname))
Vadim Gelfer
http: query server for capabilities
r2442
def do_capabilities(self, req):
Thomas Arendsen Hein
Add allowed bundle types as argument to hgweb unbundle capability....
r3612 caps = ['lookup', 'changegroupsubset']
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 if self.configbool('server', 'uncompressed'):
Matt Mackall
revlog: simplify revlog version handling...
r4258 caps.append('stream=%d' % self.repo.changelog.version)
Thomas Arendsen Hein
Add allowed bundle types as argument to hgweb unbundle capability....
r3612 # XXX: make configurable and/or share code with do_unbundle:
unbundleversions = ['HG10GZ', 'HG10BZ', 'HG10UN']
if unbundleversions:
caps.append('unbundle=%s' % ','.join(unbundleversions))
Vadim Gelfer
clone: disable stream support on server side by default....
r2621 resp = ' '.join(caps)
Vadim Gelfer
http: query server for capabilities
r2442 req.httphdr("application/mercurial-0.1", length=len(resp))
req.write(resp)
Vadim Gelfer
push over http: server side authorization support....
r2466 def check_perm(self, req, op, default):
'''check permission for operation based on user auth.
return true if op allowed, else false.
default is policy to use if no config given.'''
user = req.env.get('REMOTE_USER')
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 deny = self.configlist('web', 'deny_' + op)
Vadim Gelfer
push over http: server side authorization support....
r2466 if deny and (not user or deny == ['*'] or user in deny):
return False
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 allow = self.configlist('web', 'allow_' + op)
Vadim Gelfer
push over http: server side authorization support....
r2466 return (allow and (allow == ['*'] or user in allow)) or default
Vadim Gelfer
push over http: server support....
r2464 def do_unbundle(self, req):
Vadim Gelfer
push over http: server side authorization support....
r2466 def bail(response, headers={}):
length = int(req.env['CONTENT_LENGTH'])
for s in util.filechunkiter(req, limit=length):
# drain incoming bundle, else client will not see
# response when run outside cgi script
pass
req.httphdr("application/mercurial-0.1", headers=headers)
req.write('0\n')
req.write(response)
# require ssl by default, auth info cannot be sniffed and
# replayed
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 ssl_req = self.configbool('web', 'push_ssl', True)
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 if ssl_req:
if not req.env.get('HTTPS'):
bail(_('ssl required\n'))
return
proto = 'https'
else:
proto = 'http'
Vadim Gelfer
push over http: server side authorization support....
r2466
# do not allow push unless explicitly allowed
if not self.check_perm(req, 'push', False):
bail(_('push not authorized\n'),
headers={'status': '401 Unauthorized'})
return
Vadim Gelfer
push over http: server support....
r2464 their_heads = req.form['heads'][0].split(' ')
def check_heads():
heads = map(hex, self.repo.heads())
return their_heads == [hex('force')] or their_heads == heads
# fail early if possible
if not check_heads():
Vadim Gelfer
push over http: server side authorization support....
r2466 bail(_('unsynced changes\n'))
Vadim Gelfer
push over http: server support....
r2464 return
Alexis S. L. Carvalho
hgweb.unbundle: call req.httphdr only after the last possible call to bail
r4227 req.httphdr("application/mercurial-0.1")
Vadim Gelfer
push over http: server support....
r2464 # do not lock repo until all changegroup data is
# streamed. save to temporary file.
fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
fp = os.fdopen(fd, 'wb+')
try:
length = int(req.env['CONTENT_LENGTH'])
for s in util.filechunkiter(req, limit=length):
fp.write(s)
try:
Alexis S. L. Carvalho
hgweb: handle IOErrors and OSErrors during unbundle...
r4228 lock = self.repo.lock()
try:
if not check_heads():
req.write('0\n')
req.write(_('unsynced changes\n'))
return
Vadim Gelfer
push over http: server support....
r2464
Alexis S. L. Carvalho
hgweb: handle IOErrors and OSErrors during unbundle...
r4228 fp.seek(0)
header = fp.read(6)
if not header.startswith("HG"):
# old client with uncompressed bundle
def generator(f):
yield header
for chunk in f:
yield chunk
elif not header.startswith("HG10"):
req.write("0\n")
req.write(_("unknown bundle version\n"))
return
elif header == "HG10GZ":
def generator(f):
zd = zlib.decompressobj()
for chunk in f:
yield zd.decompress(chunk)
elif header == "HG10BZ":
def generator(f):
zd = bz2.BZ2Decompressor()
zd.decompress("BZ")
for chunk in f:
yield zd.decompress(chunk)
elif header == "HG10UN":
def generator(f):
for chunk in f:
yield chunk
else:
req.write("0\n")
req.write(_("unknown bundle compression type\n"))
return
gen = generator(util.filechunkiter(fp, 4096))
# send addchangegroup output to client
old_stdout = sys.stdout
sys.stdout = cStringIO.StringIO()
try:
url = 'remote:%s:%s' % (proto,
req.env.get('REMOTE_HOST', ''))
try:
ret = self.repo.addchangegroup(
util.chunkbuffer(gen), 'serve', url)
except util.Abort, inst:
sys.stdout.write("abort: %s\n" % inst)
ret = 0
finally:
val = sys.stdout.getvalue()
sys.stdout = old_stdout
req.write('%d\n' % ret)
req.write(val)
finally:
lock.release()
except (OSError, IOError), inst:
req.write('0\n')
filename = getattr(inst, 'filename', '')
# Don't send our filesystem layout to the client
if filename.startswith(self.repo.root):
filename = filename[len(self.repo.root)+1:]
Benoit Boissinot
hgweb: introduce a new capability for sending a compressed bundle...
r3610 else:
Alexis S. L. Carvalho
hgweb: handle IOErrors and OSErrors during unbundle...
r4228 filename = ''
error = getattr(inst, 'strerror', 'Unknown error')
req.write('%s: %s\n' % (error, filename))
Vadim Gelfer
push over http: server support....
r2464 finally:
fp.close()
os.unlink(tempname)
Vadim Gelfer
add support for streaming clone....
r2612
def do_stream_out(self, req):
req.httphdr("application/mercurial-0.1")
streamclone.stream_out(self.repo, req)