##// END OF EJS Templates
Minor hgwebdir tweaks...
Minor hgwebdir tweaks - ignore / for PATH_INFO - fix // in URLs

File last commit:

r1022:31dcaf91 default
r1022:31dcaf91 default
Show More
hgweb.py
891 lines | 28.8 KiB | text/x-python | PythonLexer
mpm@selenic.com
hgweb.py: kill #! line, clean up copyright notice...
r238 # hgweb.py - web interface to a mercurial repository
jake@edge2.net
moving hgweb to mercurial subdir
r131 #
mpm@selenic.com
hgweb.py: kill #! line, clean up copyright notice...
r238 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
mpm@selenic.com
More whitespace cleanups...
r575 # Copyright 2005 Matt Mackall <mpm@selenic.com>
jake@edge2.net
moving hgweb to mercurial subdir
r131 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Samuel Tardieu
Add an option to hg serve to serve file using IPv6
r825 import os, cgi, time, re, difflib, socket, sys, zlib
mpm@selenic.com
Revamped templated hgweb
r138 from mercurial.hg import *
mpm@selenic.com
hgweb: import ui...
r215 from mercurial.ui import *
mpm@selenic.com
Revamped templated hgweb
r138
mpm@selenic.com
Install the templates where they can be found by hgweb.py...
r157 def templatepath():
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 for f in "templates", "../templates":
mpm@selenic.com
Install the templates where they can be found by hgweb.py...
r157 p = os.path.join(os.path.dirname(__file__), f)
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 if os.path.isdir(p): return p
mpm@selenic.com
Install the templates where they can be found by hgweb.py...
r157
mpm@selenic.com
Revamped templated hgweb
r138 def age(t):
def plural(t, c):
if c == 1: return t
return t + "s"
def fmt(t, c):
return "%d %s" % (c, plural(t, c))
now = time.time()
delta = max(1, int(now - t))
scales = [["second", 1],
["minute", 60],
["hour", 3600],
["day", 3600 * 24],
["week", 3600 * 24 * 7],
["month", 3600 * 24 * 30],
["year", 3600 * 24 * 365]]
scales.reverse()
for t, s in scales:
n = delta / s
mpm@selenic.com
hgweb: make age() smarter...
r195 if n >= 2 or s == 1: return fmt(t, n)
jake@edge2.net
moving hgweb to mercurial subdir
r131
def nl2br(text):
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 return text.replace('\n', '<br/>\n')
jake@edge2.net
moving hgweb to mercurial subdir
r131
def obfuscate(text):
mpm@selenic.com
[PATCH] Generate correctly XML entities for obfuscated user...
r533 return ''.join([ '&#%d;' % ord(c) for c in text ])
mpm@selenic.com
Revamped templated hgweb
r138
def up(p):
if p[0] != "/": p = "/" + p
if p[-1] == "/": p = p[:-1]
up = os.path.dirname(p)
if up == "/":
return "/"
return up + "/"
jake@edge2.net
moving hgweb to mercurial subdir
r131
def httphdr(type):
mpm@selenic.com
Remove all remaining print statements...
r582 sys.stdout.write('Content-type: %s\n\n' % type)
jake@edge2.net
moving hgweb to mercurial subdir
r131
jake@edge2.net
change template to a generator...
r135 def write(*things):
for thing in things:
if hasattr(thing, "__iter__"):
for part in thing:
write(part)
else:
sys.stdout.write(str(thing))
mpm@selenic.com
Revamped templated hgweb
r138 class templater:
mpm@selenic.com
Add globals to templater/fixup RSS...
r601 def __init__(self, mapfile, filters = {}, defaults = {}):
mpm@selenic.com
Revamped templated hgweb
r138 self.cache = {}
self.map = {}
self.base = os.path.dirname(mapfile)
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 self.filters = filters
mpm@selenic.com
Add globals to templater/fixup RSS...
r601 self.defaults = defaults
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Revamped templated hgweb
r138 for l in file(mapfile):
m = re.match(r'(\S+)\s*=\s*"(.*)"$', l)
jake@edge2.net
added template support for some hgweb output, also, template files for...
r133 if m:
mpm@selenic.com
Revamped templated hgweb
r138 self.cache[m.group(1)] = m.group(2)
else:
m = re.match(r'(\S+)\s*=\s*(\S+)', l)
if m:
self.map[m.group(1)] = os.path.join(self.base, m.group(2))
jake@edge2.net
added template support for some hgweb output, also, template files for...
r133 else:
mpm@selenic.com
Revamped templated hgweb
r138 raise "unknown map entry '%s'" % l
jake@edge2.net
added template support for some hgweb output, also, template files for...
r133
mpm@selenic.com
Revamped templated hgweb
r138 def __call__(self, t, **map):
mpm@selenic.com
Add globals to templater/fixup RSS...
r601 m = self.defaults.copy()
m.update(map)
mpm@selenic.com
Revamped templated hgweb
r138 try:
tmpl = self.cache[t]
except KeyError:
tmpl = self.cache[t] = file(self.map[t]).read()
Josef "Jeff" Sipek
Added support for #foo%bar# syntax...
r974 return self.template(tmpl, self.filters, **m)
def template(self, tmpl, filters = {}, **map):
while tmpl:
m = re.search(r"#([a-zA-Z0-9]+)((%[a-zA-Z0-9]+)*)((\|[a-zA-Z0-9]+)*)#", tmpl)
if m:
yield tmpl[:m.start(0)]
v = map.get(m.group(1), "")
v = callable(v) and v(**map) or v
format = m.group(2)
fl = m.group(4)
if format:
q = v.__iter__
for i in q():
lm = map.copy()
lm.update(i)
yield self(format[1:], **lm)
v = ""
elif fl:
for f in fl.split("|")[1:]:
v = filters[f](v)
yield v
tmpl = tmpl[m.end(0):]
else:
yield tmpl
return
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
[PATCH] Add RSS support to hgweb...
r599 def rfc822date(x):
mpm@selenic.com
Add globals to templater/fixup RSS...
r601 return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(x))
mpm@selenic.com
[PATCH] Add RSS support to hgweb...
r599
mpm@selenic.com
Add a multi-repository server...
r941 common_filters = {
"escape": cgi.escape,
"age": age,
"date": (lambda x: time.asctime(time.gmtime(x))),
"addbreaks": nl2br,
"obfuscate": obfuscate,
"short": (lambda x: x[:12]),
"firstline": (lambda x: x.splitlines(1)[0]),
"permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
"rfc822date": rfc822date,
}
mpm@selenic.com
Revamped templated hgweb
r138 class hgweb:
mpm@selenic.com
hgweb: change startup argument processing...
r987 def __init__(self, repo, name=None):
if type(repo) == type(""):
self.repo = repository(ui(), repo)
else:
self.repo = repo
jake@edge2.net
added template support for some hgweb output, also, template files for...
r133
mpm@selenic.com
hgweb: watch changelog for changes...
r258 self.mtime = -1
mpm@selenic.com
hgweb: change startup argument processing...
r987 self.reponame = name or self.repo.ui.config("web", "name",
self.repo.root)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
hgweb: watch changelog for changes...
r258 def refresh(self):
mpm@selenic.com
hgweb: change startup argument processing...
r987 s = os.stat(os.path.join(self.repo.root, ".hg", "00changelog.i"))
mpm@selenic.com
hgweb: watch changelog for changes...
r258 if s.st_mtime != self.mtime:
mpm@selenic.com
hgweb: Fix reloading of index...
r322 self.mtime = s.st_mtime
mpm@selenic.com
hgweb: change startup argument processing...
r987 self.repo = repository(self.repo.ui, self.repo.root)
mpm@selenic.com
hgweb: Make maxfiles, maxchanges, and allowpull proper config options
r964 self.maxchanges = self.repo.ui.config("web", "maxchanges", 10)
self.maxfiles = self.repo.ui.config("web", "maxchanges", 10)
self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
mpm@selenic.com
hgweb: watch changelog for changes...
r258
mpm@selenic.com
Revamped templated hgweb
r138 def date(self, cs):
return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
def listfiles(self, files, mf):
for f in files[:self.maxfiles]:
yield self.t("filenodelink", node = hex(mf[f]), file = f)
if len(files) > self.maxfiles:
yield self.t("fileellipses")
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")
mpm@selenic.com
[PATCH 1/5]: cleaning the template parent management in hgweb...
r569 def parents(self, t1, nodes=[], rev=None,**args):
if not rev: rev = lambda x: ""
for node in nodes:
if node != nullid:
yield self.t(t1, node = hex(node), rev = rev(node), **args)
mpm@selenic.com
[PATCH] Add tags to hgweb...
r568 def showtag(self, t1, node=nullid, **args):
for t in self.repo.nodetags(node):
yield self.t(t1, tag = t, **args)
mpm@selenic.com
Revamped templated hgweb
r138 def diff(self, node1, node2, files):
def filterfiles(list, files):
l = [ x for x in list if x in files ]
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Revamped templated hgweb
r138 for f in files:
if f[-1] != os.sep: f += os.sep
l += [ x for x in list if x.startswith(f) ]
return l
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
hgweb: alternating colors for multifile diffs
r172 parity = [0]
def diffblock(diff, f, fn):
yield self.t("diffblock",
lines = prettyprintlines(diff),
parity = parity[0],
file = f,
mpm@selenic.com
hgweb: fix deleted file in changeset key error...
r369 filenode = hex(fn or nullid))
mpm@selenic.com
hgweb: alternating colors for multifile diffs
r172 parity[0] = 1 - parity[0]
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
hgweb: alternating colors for multifile diffs
r172 def prettyprintlines(diff):
mpm@selenic.com
Revamped templated hgweb
r138 for l in diff.splitlines(1):
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 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)
mpm@selenic.com
Revamped templated hgweb
r138 else:
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 yield self.t("diffline", line = l)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 r = self.repo
cl = r.changelog
mf = r.manifest
change1 = cl.read(node1)
change2 = cl.read(node2)
mmap1 = mf.read(change1[0])
mmap2 = mf.read(change2[0])
date1 = self.date(change1)
date2 = self.date(change2)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Minor hgweb fixup for new diff code...
r539 c, a, d, u = r.changes(node1, node2)
kreijack@inwind.REMOVEME.it
this patch permits hgweb to show the deleted files in the changeset diff...
r645 if files:
c, a, d = map(lambda x: filterfiles(x, files), (c, a, d))
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 for f in c:
to = r.file(f).read(mmap1[f])
tn = r.file(f).read(mmap2[f])
mpm@selenic.com
hgweb: alternating colors for multifile diffs
r172 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
mpm@selenic.com
Revamped templated hgweb
r138 for f in a:
mpm@selenic.com
hgweb: fix non-existent source or destination for diff...
r265 to = None
mpm@selenic.com
Revamped templated hgweb
r138 tn = r.file(f).read(mmap2[f])
mpm@selenic.com
hgweb: alternating colors for multifile diffs
r172 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
mpm@selenic.com
Revamped templated hgweb
r138 for f in d:
to = r.file(f).read(mmap1[f])
mpm@selenic.com
hgweb: fix non-existent source or destination for diff...
r265 tn = None
mpm@selenic.com
hgweb: alternating colors for multifile diffs
r172 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f), f, tn)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
hgweb: Fix navigate to 0 bug
r180 def changelog(self, pos):
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def changenav(**map):
mpm@selenic.com
Revamped templated hgweb
r138 def seq(factor = 1):
yield 1 * factor
mpm@selenic.com
hgweb: make navigation of changesets a bit nicer
r173 yield 3 * factor
#yield 5 * factor
mpm@selenic.com
Revamped templated hgweb
r138 for f in seq(factor * 10):
yield f
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
hgweb: make navigation of changesets a bit nicer
r173 l = []
for f in seq():
if f < self.maxchanges / 2: continue
if f > count: break
r = "%d" % f
mpm@selenic.com
hgweb: change number navigation tidy up...
r351 if pos + f < count: l.append(("+" + r, pos + f))
if pos - f >= 0: l.insert(0, ("-" + r, pos - f))
mpm@selenic.com
hgweb: make navigation of changesets a bit nicer
r173
Josef "Jeff" Sipek
hgweb: Changed changelog page to list format syntax
r975 yield {"rev": 0, "label": "(0)"}
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
hgweb: make navigation of changesets a bit nicer
r173 for label, rev in l:
Josef "Jeff" Sipek
hgweb: Changed changelog page to list format syntax
r975 yield {"label": label, "rev": rev}
mpm@selenic.com
hgweb: make navigation of changesets a bit nicer
r173
Josef "Jeff" Sipek
hgweb: Changed changelog page to list format syntax
r975 yield {"label": "tip", "rev": ""}
jake@edge2.net
moving hgweb to mercurial subdir
r131
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def changelist(**map):
mpm@selenic.com
Prettify the web interface...
r142 parity = (start - end) & 1
mpm@selenic.com
Revamped templated hgweb
r138 cl = self.repo.changelog
l = [] # build a list in forward order for efficiency
mpm@selenic.com
hgweb: change number navigation tidy up...
r351 for i in range(start, end):
mpm@selenic.com
Revamped templated hgweb
r138 n = cl.node(i)
changes = cl.read(n)
hn = hex(n)
t = float(changes[2].split(' ')[0])
jake@edge2.net
moving hgweb to mercurial subdir
r131
Josef "Jeff" Sipek
hgweb: Changed changelog page to list format syntax
r975 l.insert(0, {
"parity": parity,
"author": changes[1],
"parent": self.parents("changelogparent",
mpm@selenic.com
[PATCH 1/5]: cleaning the template parent management in hgweb...
r569 cl.parents(n), cl.rev),
Josef "Jeff" Sipek
hgweb: Changed changelog page to list format syntax
r975 "changelogtag": self.showtag("changelogtag",n),
"manifest": hex(changes[0]),
"desc": changes[4],
"date": t,
"files": self.listfilediffs(changes[3], n),
"rev": i,
"node": hn})
mpm@selenic.com
Prettify the web interface...
r142 parity = 1 - parity
mpm@selenic.com
Revamped templated hgweb
r138
Josef "Jeff" Sipek
hgweb: Changed changelog page to list format syntax
r975 for e in l: yield e
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
hgweb: add tags links and manifest links...
r168 cl = self.repo.changelog
mf = cl.read(cl.tip())[0]
count = cl.count()
mpm@selenic.com
hgweb: change number navigation tidy up...
r351 start = max(0, pos - self.maxchanges + 1)
end = min(count, start + self.maxchanges)
pos = end - 1
mpm@selenic.com
Revamped templated hgweb
r138
mpm@selenic.com
Prettify the web interface...
r142 yield self.t('changelog',
changenav = changenav,
mpm@selenic.com
hgweb: add tags links and manifest links...
r168 manifest = hex(mf),
mpm@selenic.com
Prettify the web interface...
r142 rev = pos, changesets = count, entries = changelist)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Add multiple keyword search to hgweb...
r538 def search(self, query):
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def changelist(**map):
mpm@selenic.com
Add multiple keyword search to hgweb...
r538 cl = self.repo.changelog
count = 0
qw = query.lower().split()
def revgen():
for i in range(cl.count() - 1, 0, -100):
l = []
for j in range(max(0, i - 100), i):
n = cl.node(j)
changes = cl.read(n)
l.insert(0, (n, j, changes))
for e in l:
yield e
for n, i, changes in revgen():
miss = 0
for q in qw:
if not (q in changes[1].lower() or
q in changes[4].lower() or
q in " ".join(changes[3][:20]).lower()):
miss = 1
break
if miss: continue
count += 1
hn = hex(n)
t = float(changes[2].split(' ')[0])
yield self.t(
'searchentry',
parity = count & 1,
author = changes[1],
mpm@selenic.com
[PATCH 2/5]: cleaning the template parent management in hgweb...
r570 parent = self.parents("changelogparent",
mpm@selenic.com
[PATCH 1/5]: cleaning the template parent management in hgweb...
r569 cl.parents(n), cl.rev),
mpm@selenic.com
[PATCH] Add tags to hgweb...
r568 changelogtag = self.showtag("changelogtag",n),
mpm@selenic.com
Add multiple keyword search to hgweb...
r538 manifest = hex(changes[0]),
desc = changes[4],
date = t,
files = self.listfilediffs(changes[3], n),
rev = i,
node = hn)
if count >= self.maxchanges: break
cl = self.repo.changelog
mf = cl.read(cl.tip())[0]
yield self.t('search',
query = query,
manifest = hex(mf),
entries = changelist)
mpm@selenic.com
Revamped templated hgweb
r138 def changeset(self, nodeid):
n = bin(nodeid)
cl = self.repo.changelog
changes = cl.read(n)
mpm@selenic.com
[PATCH 4/5]: cleaning the template parent management in hgweb...
r598 p1 = cl.parents(n)[0]
mpm@selenic.com
Revamped templated hgweb
r138 t = float(changes[2].split(' ')[0])
mpm@selenic.com
Whitespace cleanups...
r515
jake@edge2.net
added template support for some hgweb output, also, template files for...
r133 files = []
mpm@selenic.com
Revamped templated hgweb
r138 mf = self.repo.manifest.read(changes[0])
jake@edge2.net
moving hgweb to mercurial subdir
r131 for f in changes[3]:
mpm@selenic.com
Revamped templated hgweb
r138 files.append(self.t("filenodelink",
mpm@selenic.com
hgweb: fix deleted file in changeset key error...
r369 filenode = hex(mf.get(f, nullid)), file = f))
mpm@selenic.com
Revamped templated hgweb
r138
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def diff(**map):
kreijack@inwind.REMOVEME.it
this patch permits hgweb to show the deleted files in the changeset diff...
r645 yield self.diff(p1, n, None)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 yield self.t('changeset',
diff = diff,
rev = cl.rev(n),
node = nodeid,
mpm@selenic.com
[PATCH 2/5]: cleaning the template parent management in hgweb...
r570 parent = self.parents("changesetparent",
mpm@selenic.com
[PATCH 1/5]: cleaning the template parent management in hgweb...
r569 cl.parents(n), cl.rev),
mpm@selenic.com
[PATCH] Add tags to hgweb...
r568 changesettag = self.showtag("changesettag",n),
mpm@selenic.com
Revamped templated hgweb
r138 manifest = hex(changes[0]),
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 author = changes[1],
desc = changes[4],
date = t,
mpm@selenic.com
Revamped templated hgweb
r138 files = files)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 def filelog(self, f, filenode):
cl = self.repo.changelog
fl = self.repo.file(f)
count = fl.count()
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def entries(**map):
mpm@selenic.com
Revamped templated hgweb
r138 l = []
mpm@selenic.com
Prettify the web interface...
r142 parity = (count - 1) & 1
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Revamped templated hgweb
r138 for i in range(count):
n = fl.node(i)
lr = fl.linkrev(n)
cn = cl.node(lr)
cs = cl.read(cl.node(lr))
t = float(cs[2].split(' ')[0])
jake@edge2.net
added template support for some hgweb output, also, template files for...
r133
Josef "Jeff" Sipek
hgweb: Changed file revision page to list format syntax
r978 l.insert(0, {"parity": parity,
"filenode": hex(n),
"filerev": i,
"file": f,
"node": hex(cn),
"author": cs[1],
"date": t,
"parent": self.parents("filelogparent",
mpm@selenic.com
[PATCH 4/5]: cleaning the template parent management in hgweb...
r598 fl.parents(n), fl.rev, file=f),
Josef "Jeff" Sipek
hgweb: Changed file revision page to list format syntax
r978 "desc": cs[4]})
mpm@selenic.com
Prettify the web interface...
r142 parity = 1 - parity
mpm@selenic.com
Revamped templated hgweb
r138
Josef "Jeff" Sipek
hgweb: Changed file revision page to list format syntax
r978 for e in l: yield e
mpm@selenic.com
Revamped templated hgweb
r138
yield self.t("filelog",
file = f,
filenode = filenode,
entries = entries)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 def filerevision(self, f, node):
fl = self.repo.file(f)
n = bin(node)
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 text = fl.read(n)
mpm@selenic.com
Revamped templated hgweb
r138 changerev = fl.linkrev(n)
cl = self.repo.changelog
cn = cl.node(changerev)
cs = cl.read(cn)
t = float(cs[2].split(' ')[0])
mfn = cs[0]
mpm@selenic.com
Prettify the web interface...
r142
def lines():
for l, t in enumerate(text.splitlines(1)):
Josef "Jeff" Sipek
hgweb: Changed file page to list format syntax
r976 yield {"line": t,
"linenumber": "% 6d" % (l + 1),
"parity": l & 1}
mpm@selenic.com
hgweb: add file permissions...
r359
mpm@selenic.com
Revamped templated hgweb
r138 yield self.t("filerevision", file = f,
filenode = node,
path = up(f),
mpm@selenic.com
Prettify the web interface...
r142 text = lines(),
mpm@selenic.com
Revamped templated hgweb
r138 rev = changerev,
node = hex(cn),
manifest = hex(mfn),
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 author = cs[1],
date = t,
mpm@selenic.com
[PATCH 2/5]: cleaning the template parent management in hgweb...
r570 parent = self.parents("filerevparent",
mpm@selenic.com
[PATCH 1/5]: cleaning the template parent management in hgweb...
r569 fl.parents(n), fl.rev, file=f),
mpm@selenic.com
[PATCH 4/5]: cleaning the template parent management in hgweb...
r598 permissions = self.repo.manifest.readflags(mfn)[f])
mpm@selenic.com
Revamped templated hgweb
r138
def fileannotate(self, f, node):
bcache = {}
ncache = {}
fl = self.repo.file(f)
n = bin(node)
changerev = fl.linkrev(n)
cl = self.repo.changelog
cn = cl.node(changerev)
cs = cl.read(cn)
t = float(cs[2].split(' ')[0])
mfn = cs[0]
jake@edge2.net
moving hgweb to mercurial subdir
r131
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def annotate(**map):
mpm@selenic.com
Prettify the web interface...
r142 parity = 1
last = None
mpm@selenic.com
Revamped templated hgweb
r138 for r, l in fl.annotate(n):
try:
cnode = ncache[r]
except KeyError:
cnode = ncache[r] = self.repo.changelog.node(r)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Revamped templated hgweb
r138 try:
name = bcache[r]
except KeyError:
cl = self.repo.changelog.read(cnode)
name = cl[1]
f = name.find('@')
if f >= 0:
name = name[:f]
mpm@selenic.com
[PATCH] Handle 'name firstname <email@server>' correctly in annotate...
r534 f = name.find('<')
if f >= 0:
name = name[f+1:]
mpm@selenic.com
Revamped templated hgweb
r138 bcache[r] = name
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Prettify the web interface...
r142 if last != cnode:
parity = 1 - parity
last = cnode
Josef "Jeff" Sipek
hgweb: Changed annotate page to list format syntax
r977 yield {"parity": parity,
"node": hex(cnode),
"rev": r,
"author": name,
"file": f,
"line": l}
mpm@selenic.com
Revamped templated hgweb
r138
yield self.t("fileannotate",
file = f,
filenode = node,
annotate = annotate,
path = up(f),
rev = changerev,
node = hex(cn),
manifest = hex(mfn),
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 author = cs[1],
date = t,
mpm@selenic.com
[PATCH 2/5]: cleaning the template parent management in hgweb...
r570 parent = self.parents("fileannotateparent",
mpm@selenic.com
[PATCH 1/5]: cleaning the template parent management in hgweb...
r569 fl.parents(n), fl.rev, file=f),
mpm@selenic.com
[PATCH 4/5]: cleaning the template parent management in hgweb...
r598 permissions = self.repo.manifest.readflags(mfn)[f])
jake@edge2.net
added annotate...
r136
mpm@selenic.com
Revamped templated hgweb
r138 def manifest(self, mnode, path):
mf = self.repo.manifest.read(bin(mnode))
rev = self.repo.manifest.rev(bin(mnode))
node = self.repo.changelog.node(rev)
mpm@selenic.com
hgweb: add file permissions...
r359 mff=self.repo.manifest.readflags(bin(mnode))
mpm@selenic.com
Revamped templated hgweb
r138
files = {}
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Revamped templated hgweb
r138 p = path[1:]
l = len(p)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 for f,n in mf.items():
if f[:l] != p:
continue
remain = f[l:]
if "/" in remain:
short = remain[:remain.find("/") + 1] # bleah
mpm@selenic.com
Prettify the web interface...
r142 files[short] = (f, None)
mpm@selenic.com
Revamped templated hgweb
r138 else:
short = os.path.basename(remain)
files[short] = (f, n)
jake@edge2.net
moving hgweb to mercurial subdir
r131
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def filelist(**map):
mpm@selenic.com
Prettify the web interface...
r142 parity = 0
mpm@selenic.com
Revamped templated hgweb
r138 fl = files.keys()
fl.sort()
for f in fl:
full, fnode = files[f]
Josef "Jeff" Sipek
hgweb: Changed manifest page to list format syntax
r979 if not fnode:
continue
yield {"file": full,
"manifest": mnode,
"filenode": hex(fnode),
"parity": parity,
"basename": f,
"permissions": mff[full]}
mpm@selenic.com
Prettify the web interface...
r142 parity = 1 - parity
mpm@selenic.com
Revamped templated hgweb
r138
Josef "Jeff" Sipek
hgweb: Changed manifest page to list format syntax
r979 def dirlist(**map):
parity = 0
fl = files.keys()
fl.sort()
for f in fl:
full, fnode = files[f]
if fnode:
continue
yield {"parity": parity,
"path": os.path.join(path, f),
"manifest": mnode,
Josef "Jeff" Sipek
Merge with MPM
r980 "basename": f[:-1]}
Josef "Jeff" Sipek
hgweb: Changed manifest page to list format syntax
r979 parity = 1 - parity
mpm@selenic.com
hgweb: convert index entries to list expansion style
r982
mpm@selenic.com
Revamped templated hgweb
r138 yield self.t("manifest",
manifest = mnode,
rev = rev,
node = hex(node),
path = path,
up = up(path),
Josef "Jeff" Sipek
hgweb: Changed manifest page to list format syntax
r979 fentries = filelist,
dentries = dirlist)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
hgweb: add tags links and manifest links...
r168 def tags(self):
cl = self.repo.changelog
mf = cl.read(cl.tip())[0]
mpm@selenic.com
rework all code using tags...
r343 i = self.repo.tagslist()
i.reverse()
mpm@selenic.com
hgweb: add tags links and manifest links...
r168
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def entries(**map):
mpm@selenic.com
hgweb: add tags links and manifest links...
r168 parity = 0
for k,n in i:
Josef "Jeff" Sipek
Added support for #foo%bar# syntax...
r974 yield {"parity": parity,
"tag": k,
"node": hex(n)}
mpm@selenic.com
hgweb: add tags links and manifest links...
r168 parity = 1 - parity
yield self.t("tags",
manifest = hex(mf),
entries = entries)
mpm@selenic.com
Revamped templated hgweb
r138 def filediff(self, file, changeset):
n = bin(changeset)
cl = self.repo.changelog
p1 = cl.parents(n)[0]
cs = cl.read(n)
mf = self.repo.manifest.read(cs[0])
mpm@selenic.com
Whitespace cleanups...
r515
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def diff(**map):
mpm@selenic.com
Revamped templated hgweb
r138 yield self.diff(p1, n, file)
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 yield self.t("filediff",
file = file,
Thomas Arendsen Hein
hgweb: fix deleted file in filediff key error...
r376 filenode = hex(mf.get(file, nullid)),
mpm@selenic.com
Revamped templated hgweb
r138 node = changeset,
rev = self.repo.changelog.rev(n),
mpm@selenic.com
[PATCH 3/5]: cleaning the template parent management in hgweb...
r571 parent = self.parents("filediffparent",
cl.parents(n), cl.rev),
mpm@selenic.com
Revamped templated hgweb
r138 diff = diff)
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Revamped templated hgweb
r138 # add tags to things
# tags -> list of changesets corresponding to tags
# find tag, changeset, file
jake@edge2.net
moving hgweb to mercurial subdir
r131
jake@edge2.net
making hgweb class
r132 def run(self):
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 def header(**map):
yield self.t("header", **map)
def footer(**map):
yield self.t("footer", **map)
mpm@selenic.com
hgweb: watch changelog for changes...
r258 self.refresh()
jake@edge2.net
making hgweb class
r132 args = cgi.parse()
mpm@selenic.com
hgweb: change startup argument processing...
r987 t = self.repo.ui.config("web", "templates", templatepath())
mpm@selenic.com
hgweb: add [web] section to hgrc...
r938 m = os.path.join(t, "map")
mpm@selenic.com
Add web:style option
r986 style = self.repo.ui.config("web", "style", "")
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 if args.has_key('style'):
mpm@selenic.com
Add web:style option
r986 style = args['style'][0]
if style:
b = os.path.basename("map-" + style)
mpm@selenic.com
Fix RSS feeds
r983 p = os.path.join(t, b)
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 if os.path.isfile(p): m = p
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Add globals to templater/fixup RSS...
r601 port = os.environ["SERVER_PORT"]
port = port != "80" and (":" + port) or ""
Matt Mackall
Attempt to handle RSS URIs properly...
r620 uri = os.environ["REQUEST_URI"]
if "?" in uri: uri = uri.split("?")[0]
url = "http://%s%s%s" % (os.environ["SERVER_NAME"], port, uri)
mpm@selenic.com
Add globals to templater/fixup RSS...
r601
mpm@selenic.com
Add a multi-repository server...
r941 self.t = templater(m, common_filters,
mpm@selenic.com
Add globals to templater/fixup RSS...
r601 {"url":url,
mpm@selenic.com
hgweb: change startup argument processing...
r987 "repo":self.reponame,
Jeff Sipek
[PATCH] Propagate the template map though recursively...
r857 "header":header,
"footer":footer,
mpm@selenic.com
Add globals to templater/fixup RSS...
r601 })
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201
Jeff Sipek
[PATCH] Move default page name into map file...
r858 if not args.has_key('cmd'):
args['cmd'] = [self.t.cache['default'],]
mpm@selenic.com
Whitespace
r937
Jeff Sipek
[PATCH] Move default page name into map file...
r858 if args['cmd'][0] == 'changelog':
mpm@selenic.com
Add multiple keyword search to hgweb...
r538 c = self.repo.changelog.count() - 1
hi = c
jake@edge2.net
changed pos to rev for changelog cmd, changed & to ;
r153 if args.has_key('rev'):
mpm@selenic.com
Add tag/rev/node search to hgweb
r165 hi = args['rev'][0]
mpm@selenic.com
hgweb: don't blow up on search for unknown keys
r166 try:
hi = self.repo.changelog.rev(self.repo.lookup(hi))
mpm@selenic.com
Repair the hgweb search interface...
r688 except RepoError:
mpm@selenic.com
Add multiple keyword search to hgweb...
r538 write(self.search(hi))
return
mpm@selenic.com
More whitespace cleanups...
r575
mpm@selenic.com
Revamped templated hgweb
r138 write(self.changelog(hi))
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Revamped templated hgweb
r138 elif args['cmd'][0] == 'changeset':
write(self.changeset(args['node'][0]))
elif args['cmd'][0] == 'manifest':
write(self.manifest(args['manifest'][0], args['path'][0]))
mpm@selenic.com
hgweb: add tags links and manifest links...
r168 elif args['cmd'][0] == 'tags':
write(self.tags())
mpm@selenic.com
Revamped templated hgweb
r138 elif args['cmd'][0] == 'filediff':
write(self.filediff(args['file'][0], args['node'][0]))
jake@edge2.net
moving hgweb to mercurial subdir
r131
jake@edge2.net
making hgweb class
r132 elif args['cmd'][0] == 'file':
mpm@selenic.com
Revamped templated hgweb
r138 write(self.filerevision(args['file'][0], args['filenode'][0]))
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 elif args['cmd'][0] == 'annotate':
write(self.fileannotate(args['file'][0], args['filenode'][0]))
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 elif args['cmd'][0] == 'filelog':
write(self.filelog(args['file'][0], args['filenode'][0]))
jake@edge2.net
added annotate...
r136
mpm@selenic.com
make pull work for multiple heads...
r222 elif args['cmd'][0] == 'heads':
Muli Ben-Yehuda
When pulling from a non hg repository URL (e.g. http://www.kernel.org/hg)...
r751 httphdr("application/mercurial-0.1")
mpm@selenic.com
make pull work for multiple heads...
r222 h = self.repo.heads()
sys.stdout.write(" ".join(map(hex, h)) + "\n")
jake@edge2.net
making hgweb class
r132 elif args['cmd'][0] == 'branches':
Muli Ben-Yehuda
When pulling from a non hg repository URL (e.g. http://www.kernel.org/hg)...
r751 httphdr("application/mercurial-0.1")
jake@edge2.net
making hgweb class
r132 nodes = []
if args.has_key('nodes'):
mpm@selenic.com
Revamped templated hgweb
r138 nodes = map(bin, args['nodes'][0].split(" "))
for b in self.repo.branches(nodes):
sys.stdout.write(" ".join(map(hex, b)) + "\n")
jake@edge2.net
moving hgweb to mercurial subdir
r131
jake@edge2.net
making hgweb class
r132 elif args['cmd'][0] == 'between':
mpm@selenic.com
Check protocol versions...
r753 httphdr("application/mercurial-0.1")
jake@edge2.net
making hgweb class
r132 nodes = []
if args.has_key('pairs'):
mpm@selenic.com
Revamped templated hgweb
r138 pairs = [ map(bin, p.split("-"))
jake@edge2.net
making hgweb class
r132 for p in args['pairs'][0].split(" ") ]
mpm@selenic.com
Revamped templated hgweb
r138 for b in self.repo.between(pairs):
sys.stdout.write(" ".join(map(hex, b)) + "\n")
jake@edge2.net
making hgweb class
r132
elif args['cmd'][0] == 'changegroup':
Muli Ben-Yehuda
When pulling from a non hg repository URL (e.g. http://www.kernel.org/hg)...
r751 httphdr("application/mercurial-0.1")
jake@edge2.net
making hgweb class
r132 nodes = []
mpm@selenic.com
hgweb: Make maxfiles, maxchanges, and allowpull proper config options
r964 if not self.allowpull:
mpm@selenic.com
hgweb: add view-only support...
r197 return
jake@edge2.net
making hgweb class
r132 if args.has_key('roots'):
mpm@selenic.com
Revamped templated hgweb
r138 nodes = map(bin, args['roots'][0].split(" "))
jake@edge2.net
moving hgweb to mercurial subdir
r131
jake@edge2.net
making hgweb class
r132 z = zlib.compressobj()
Matt Mackall
Protocol switch from using generators to stream-like objects....
r635 f = self.repo.changegroup(nodes)
while 1:
chunk = f.read(4096)
if not chunk: break
jake@edge2.net
making hgweb class
r132 sys.stdout.write(z.compress(chunk))
sys.stdout.write(z.flush())
jake@edge2.net
moving hgweb to mercurial subdir
r131
jake@edge2.net
making hgweb class
r132 else:
mpm@selenic.com
Revamped templated hgweb
r138 write(self.t("error"))
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
hgweb: change startup argument processing...
r987 def create_server(repo):
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158
mpm@selenic.com
hgweb: add [web] section to hgrc...
r938 def openlog(opt, default):
if opt and opt != '-':
return open(opt, 'w')
return default
mpm@selenic.com
hgweb: change startup argument processing...
r987 address = repo.ui.config("web", "address", "")
port = int(repo.ui.config("web", "port", 8000))
use_ipv6 = repo.ui.configbool("web", "ipv6")
accesslog = openlog(repo.ui.config("web", "accesslog", "-"), sys.stdout)
errorlog = openlog(repo.ui.config("web", "errorlog", "-"), sys.stderr)
mpm@selenic.com
hgweb: add [web] section to hgrc...
r938
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158 import BaseHTTPServer
Samuel Tardieu
Add an option to hg serve to serve file using IPv6
r825 class IPv6HTTPServer(BaseHTTPServer.HTTPServer):
Bryan O'Sullivan
Fix problem with "hg serve" on systems not providing IPv6.
r881 address_family = getattr(socket, 'AF_INET6', None)
def __init__(self, *args, **kwargs):
if self.address_family is None:
raise RepoError('IPv6 not available on this system')
BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
Samuel Tardieu
Add an option to hg serve to serve file using IPv6
r825
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158 class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
mpm@selenic.com
[PATCH] Get "hg serve" to optionally log accesses and errors to files...
r605 def log_error(self, format, *args):
errorlog.write("%s - - [%s] %s\n" % (self.address_string(),
self.log_date_time_string(),
format % args))
mpm@selenic.com
Whitespace
r937
mpm@selenic.com
[PATCH] Get "hg serve" to optionally log accesses and errors to files...
r605 def log_message(self, format, *args):
accesslog.write("%s - - [%s] %s\n" % (self.address_string(),
self.log_date_time_string(),
format % args))
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158 def do_POST(self):
mpm@selenic.com
hgweb: ignore pipe errors...
r271 try:
self.do_hgweb()
except socket.error, inst:
if inst.args[0] != 32: raise
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158
def do_GET(self):
mpm@selenic.com
hgweb: ignore pipe errors...
r271 self.do_POST()
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158
def do_hgweb(self):
query = ""
p = self.path.find("?")
if p:
query = self.path[p + 1:]
query = query.replace('+', ' ')
mpm@selenic.com
Whitespace cleanups...
r515
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158 env = {}
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
env['REQUEST_METHOD'] = self.command
mpm@selenic.com
[PATCH] Add RSS support to hgweb...
r599 env['SERVER_NAME'] = self.server.server_name
env['SERVER_PORT'] = str(self.server.server_port)
env['REQUEST_URI'] = "/"
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158 if query:
env['QUERY_STRING'] = query
host = self.address_string()
if host != self.client_address[0]:
env['REMOTE_HOST'] = host
env['REMOTE_ADDR'] = self.client_address[0]
if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
else:
env['CONTENT_TYPE'] = self.headers.typeheader
length = self.headers.getheader('content-length')
if length:
env['CONTENT_LENGTH'] = length
accept = []
for line in self.headers.getallmatchingheaders('accept'):
if line[:1] in "\t\n\r ":
accept.append(line.strip())
else:
accept = accept + line[7:].split(',')
env['HTTP_ACCEPT'] = ','.join(accept)
os.environ.update(env)
save = sys.argv, sys.stdin, sys.stdout, sys.stderr
try:
sys.stdin = self.rfile
sys.stdout = self.wfile
sys.argv = ["hgweb.py"]
if '=' not in query:
sys.argv.append(query)
self.send_response(200, "Script output follows")
hg.run()
finally:
sys.argv, sys.stdin, sys.stdout, sys.stderr = save
mpm@selenic.com
hgweb: change startup argument processing...
r987 hg = hgweb(repo)
Samuel Tardieu
Add an option to hg serve to serve file using IPv6
r825 if use_ipv6:
return IPv6HTTPServer((address, port), hgwebhandler)
else:
return BaseHTTPServer.HTTPServer((address, port), hgwebhandler)
mpm@selenic.com
[PATCH] Get "hg serve" to print the URL being served...
r603
Samuel Tardieu
Add an option to hg serve to serve file using IPv6
r825 def server(path, name, templates, address, port, use_ipv6 = False,
mpm@selenic.com
[PATCH] Get "hg serve" to optionally log accesses and errors to files...
r605 accesslog = sys.stdout, errorlog = sys.stderr):
Samuel Tardieu
Add an option to hg serve to serve file using IPv6
r825 httpd = create_server(path, name, templates, address, port, use_ipv6,
mpm@selenic.com
[PATCH] Get "hg serve" to optionally log accesses and errors to files...
r605 accesslog, errorlog)
mpm@selenic.com
Add 'hg serve' command for stand-alone server...
r158 httpd.serve_forever()
mpm@selenic.com
Add a multi-repository server...
r941
# This is a stopgap
class hgwebdir:
def __init__(self, config):
self.cp = ConfigParser.SafeConfigParser()
self.cp.read(config)
def run(self):
try:
virtual = os.environ["PATH_INFO"]
except:
virtual = ""
mpm@selenic.com
Minor hgwebdir tweaks...
r1022 if virtual[1:]:
mpm@selenic.com
Add a multi-repository server...
r941 real = self.cp.get("paths", virtual[1:])
mpm@selenic.com
Fix hgwebdir virtual start-up
r956 h = hgweb(real)
mpm@selenic.com
Add a multi-repository server...
r941 h.run()
return
def header(**map):
yield tmpl("header", **map)
def footer(**map):
yield tmpl("footer", **map)
templates = templatepath()
m = os.path.join(templates, "map")
tmpl = templater(m, common_filters,
{"header": header, "footer": footer})
def entries(**map):
parity = 0
mpm@selenic.com
hgweb: sort repository list
r957 l = self.cp.items("paths")
l.sort()
for v,r in l:
mpm@selenic.com
Add a multi-repository server...
r941 cp2 = ConfigParser.SafeConfigParser()
cp2.read(os.path.join(r, ".hg", "hgrc"))
def get(sec, val, default):
try:
return cp2.get(sec, val)
except:
return default
mpm@selenic.com
Minor hgwebdir tweaks...
r1022 url = os.environ["REQUEST_URI"] + "/" + v
url = url.replace("//", "/")
mpm@selenic.com
hgweb: convert index entries to list expansion style
r982 yield dict(author = get("web", "author", "unknown"),
mpm@selenic.com
Add a multi-repository server...
r941 name = get("web", "name", v),
mpm@selenic.com
Minor hgwebdir tweaks...
r1022 url = url,
mpm@selenic.com
Add a multi-repository server...
r941 parity = parity,
shortdesc = get("web", "description", "unknown"),
lastupdate = os.stat(os.path.join(r, ".hg",
"00changelog.d")).st_mtime)
parity = 1 - parity
write(tmpl("index", entries = entries))