##// END OF EJS Templates
add tracking of execute permissions...
add tracking of execute permissions -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 add tracking of execute permissions Changes to executable permissions are now tracked. We only track one bit here as the others tends to be problematic. "hg manifest" now shows file permissions. manifest hash: b76b85d12a9550fdc9fbc4f9446a812f3a2bbe88 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCpzYBywK+sNU5EO8RAgkMAJ48l2ac12E20EFS24/i8ScwOtG4HwCgkbaE ue6l1RJroqzNA7vNeqwCwK4= =sEmJ -----END PGP SIGNATURE-----

File last commit:

r271:35acefbf default
r276:10e325db default
Show More
hgweb.py
721 lines | 23.6 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>
# 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.
# useful for debugging
import cgitb
cgitb.enable()
import os, cgi, time, re, difflib, 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
Revamped templated hgweb
r138 return ''.join([ '&#%d' % ord(c) for c in text ])
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):
print 'Content-type: %s\n' % type
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
hgweb: add template filters, template style maps, and raw pages...
r201 def template(tmpl, filters = {}, **map):
mpm@selenic.com
Revamped templated hgweb
r138 while tmpl:
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 m = re.search(r"#([a-zA-Z0-9]+)((\|[a-zA-Z0-9]+)*)#", tmpl)
mpm@selenic.com
Revamped templated hgweb
r138 if m:
yield tmpl[:m.start(0)]
v = map.get(m.group(1), "")
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 v = callable(v) and v() or v
fl = m.group(2)
if fl:
for f in fl.split("|")[1:]:
v = filters[f](v)
yield v
mpm@selenic.com
Revamped templated hgweb
r138 tmpl = tmpl[m.end(0):]
else:
yield tmpl
return
class templater:
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 def __init__(self, mapfile, filters = {}):
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
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):
try:
tmpl = self.cache[t]
except KeyError:
tmpl = self.cache[t] = file(self.map[t]).read()
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 return template(tmpl, self.filters, **map)
mpm@selenic.com
Revamped templated hgweb
r138
class hgweb:
mpm@selenic.com
hgweb: shrink the default changelog list to 10...
r269 maxchanges = 10
mpm@selenic.com
Revamped templated hgweb
r138 maxfiles = 10
jake@edge2.net
added template support for some hgweb output, also, template files for...
r133
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 def __init__(self, path, name, templates = ""):
self.templates = templates or templatepath()
mpm@selenic.com
Revamped templated hgweb
r138 self.reponame = name
mpm@selenic.com
hgweb: watch changelog for changes...
r258 self.path = path
self.mtime = -1
mpm@selenic.com
hgweb: add view-only support...
r197 self.viewonly = 0
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 self.filters = {
"escape": cgi.escape,
"age": age,
"date": (lambda x: time.asctime(time.gmtime(x))),
"addbreaks": nl2br,
"obfuscate": obfuscate,
"firstline": (lambda x: x.splitlines(1)[0]),
}
mpm@selenic.com
hgweb: watch changelog for changes...
r258 def refresh(self):
s = os.stat(os.path.join(self.path, ".hg", "00changelog.i"))
if s.st_mtime != self.mtime:
self.repo = repository(ui(), self.path)
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
Fix some broken parent links in hgweb
r156 def parent(self, t1, node=nullid, rev=-1, **args):
mpm@selenic.com
Prettify the web interface...
r142 if node != hex(nullid):
mpm@selenic.com
Fix some broken parent links in hgweb
r156 yield self.t(t1, node = node, rev = rev, **args)
mpm@selenic.com
Prettify the web interface...
r142
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 ]
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,
filenode = hex(fn))
parity[0] = 1 - parity[0]
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
Revamped templated hgweb
r138 c, a, d = r.diffrevs(node1, node2)
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
Prettify the web interface...
r142 def header(self):
yield self.t("header", repo = self.reponame)
def footer(self):
yield self.t("footer", repo = self.reponame)
mpm@selenic.com
hgweb: Fix navigate to 0 bug
r180 def changelog(self, pos):
mpm@selenic.com
Revamped templated hgweb
r138 def changenav():
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
if pos + f < count - (f/2): l.append(("+" + r, pos + f))
if pos - f >= 0 + (f/2): l.insert(0, ("-" + r, pos - f))
yield self.t("naventry", rev = 0, label="(0)")
mpm@selenic.com
Revamped templated hgweb
r138
mpm@selenic.com
hgweb: make navigation of changesets a bit nicer
r173 for label, rev in l:
yield self.t("naventry", label = label, rev = rev)
mpm@selenic.com
hgweb: fix tip so that it doesn't need refreshing...
r198 yield self.t("naventry", label="tip")
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 def changelist():
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
for i in range(start, end + 1):
n = cl.node(i)
changes = cl.read(n)
hn = hex(n)
p1, p2 = cl.parents(n)
t = float(changes[2].split(' ')[0])
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 l.insert(0, self.t(
'changelogentry',
mpm@selenic.com
Prettify the web interface...
r142 parity = parity,
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 author = changes[1],
mpm@selenic.com
Prettify the web interface...
r142 parent1 = self.parent("changelogparent",
hex(p1), cl.rev(p1)),
parent2 = self.parent("changelogparent",
hex(p2), cl.rev(p2)),
mpm@selenic.com
Revamped templated hgweb
r138 p1 = hex(p1), p2 = hex(p2),
p1rev = cl.rev(p1), p2rev = cl.rev(p2),
manifest = hex(changes[0]),
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 desc = changes[4],
date = t,
mpm@selenic.com
Revamped templated hgweb
r138 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
yield l
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
Revamped templated hgweb
r138 end = min(pos, count - 1)
start = max(0, pos - self.maxchanges)
end = min(count - 1, start + self.maxchanges)
mpm@selenic.com
Prettify the web interface...
r142 yield self.t('changelog',
header = self.header(),
footer = self.footer(),
repo = self.reponame,
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
Revamped templated hgweb
r138 def changeset(self, nodeid):
n = bin(nodeid)
cl = self.repo.changelog
changes = cl.read(n)
p1, p2 = cl.parents(n)
p1rev, p2rev = cl.rev(p1), cl.rev(p2)
t = float(changes[2].split(' ')[0])
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",
filenode = hex(mf[f]), file = f))
def diff():
yield self.diff(p1, n, changes[3])
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 yield self.t('changeset',
mpm@selenic.com
Prettify the web interface...
r142 header = self.header(),
footer = self.footer(),
repo = self.reponame,
mpm@selenic.com
Revamped templated hgweb
r138 diff = diff,
rev = cl.rev(n),
node = nodeid,
mpm@selenic.com
Prettify the web interface...
r142 parent1 = self.parent("changesetparent",
hex(p1), cl.rev(p1)),
parent2 = self.parent("changesetparent",
hex(p2), cl.rev(p2)),
mpm@selenic.com
Revamped templated hgweb
r138 p1 = hex(p1), p2 = hex(p2),
p1rev = cl.rev(p1), p2rev = cl.rev(p2),
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()
def entries():
l = []
mpm@selenic.com
Prettify the web interface...
r142 parity = (count - 1) & 1
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))
p1, p2 = fl.parents(n)
t = float(cs[2].split(' ')[0])
jake@edge2.net
added template support for some hgweb output, also, template files for...
r133
mpm@selenic.com
Revamped templated hgweb
r138 l.insert(0, self.t("filelogentry",
mpm@selenic.com
Prettify the web interface...
r142 parity = parity,
mpm@selenic.com
Revamped templated hgweb
r138 filenode = hex(n),
filerev = i,
file = f,
node = hex(cn),
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 author = cs[1],
date = t,
desc = cs[4],
mpm@selenic.com
Revamped templated hgweb
r138 p1 = hex(p1), p2 = hex(p2),
p1rev = fl.rev(p1), p2rev = fl.rev(p2)))
mpm@selenic.com
Prettify the web interface...
r142 parity = 1 - parity
mpm@selenic.com
Revamped templated hgweb
r138
yield l
yield self.t("filelog",
mpm@selenic.com
Prettify the web interface...
r142 header = self.header(),
footer = self.footer(),
repo = self.reponame,
mpm@selenic.com
Revamped templated hgweb
r138 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)
p1, p2 = fl.parents(n)
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)):
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 yield self.t("fileline", line = t,
mpm@selenic.com
Prettify the web interface...
r142 linenumber = "% 6d" % (l + 1),
parity = l & 1)
mpm@selenic.com
Revamped templated hgweb
r138
yield self.t("filerevision", file = f,
mpm@selenic.com
Prettify the web interface...
r142 header = self.header(),
footer = self.footer(),
repo = self.reponame,
mpm@selenic.com
Revamped templated hgweb
r138 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
Prettify the web interface...
r142 parent1 = self.parent("filerevparent",
mpm@selenic.com
Fix some broken parent links in hgweb
r156 hex(p1), fl.rev(p1), file=f),
mpm@selenic.com
Prettify the web interface...
r142 parent2 = self.parent("filerevparent",
mpm@selenic.com
Fix some broken parent links in hgweb
r156 hex(p2), fl.rev(p2), file=f),
mpm@selenic.com
Revamped templated hgweb
r138 p1 = hex(p1), p2 = hex(p2),
p1rev = fl.rev(p1), p2rev = fl.rev(p2))
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)
p1, p2 = fl.parents(n)
t = float(cs[2].split(' ')[0])
mfn = cs[0]
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 def annotate():
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)
try:
name = bcache[r]
except KeyError:
cl = self.repo.changelog.read(cnode)
name = cl[1]
f = name.find('@')
if f >= 0:
name = name[:f]
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
mpm@selenic.com
Revamped templated hgweb
r138 yield self.t("annotateline",
mpm@selenic.com
Prettify the web interface...
r142 parity = parity,
mpm@selenic.com
Revamped templated hgweb
r138 node = hex(cnode),
rev = r,
author = name,
file = f,
mpm@selenic.com
hgweb: add template filters, template style maps, and raw pages...
r201 line = l)
mpm@selenic.com
Revamped templated hgweb
r138
yield self.t("fileannotate",
mpm@selenic.com
Prettify the web interface...
r142 header = self.header(),
footer = self.footer(),
repo = self.reponame,
mpm@selenic.com
Revamped templated hgweb
r138 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
Fix some broken parent links in hgweb
r156 parent1 = self.parent("fileannotateparent",
hex(p1), fl.rev(p1), file=f),
parent2 = self.parent("fileannotateparent",
hex(p2), fl.rev(p2), file=f),
mpm@selenic.com
Revamped templated hgweb
r138 p1 = hex(p1), p2 = hex(p2),
p1rev = fl.rev(p1), p2rev = fl.rev(p2))
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)
files = {}
mpm@selenic.com
Prettify the web interface...
r142
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
mpm@selenic.com
Revamped templated hgweb
r138 def filelist():
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]
mpm@selenic.com
Prettify the web interface...
r142 if fnode:
yield self.t("manifestfileentry",
file = full,
manifest = mnode,
filenode = hex(fnode),
parity = parity,
basename = f)
else:
yield self.t("manifestdirentry",
parity = parity,
path = os.path.join(path, f),
manifest = mnode, basename = f[:-1])
parity = 1 - parity
mpm@selenic.com
Revamped templated hgweb
r138
yield self.t("manifest",
mpm@selenic.com
Prettify the web interface...
r142 header = self.header(),
footer = self.footer(),
repo = self.reponame,
mpm@selenic.com
Revamped templated hgweb
r138 manifest = mnode,
rev = rev,
node = hex(node),
path = path,
up = up(path),
mpm@selenic.com
Prettify the web interface...
r142 entries = filelist)
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]
self.repo.lookup(0) # prime the cache
i = self.repo.tags.items()
mpm@selenic.com
hgweb: Sort tags by revision number
r183 n = [ (cl.rev(e[1]), e) for e in i ] # sort by revision
n.sort()
n.reverse()
i = [ e[1] for e in n ]
mpm@selenic.com
hgweb: add tags links and manifest links...
r168
def entries():
parity = 0
for k,n in i:
yield self.t("tagentry",
parity = parity,
tag = k,
node = hex(n))
parity = 1 - parity
yield self.t("tags",
header = self.header(),
footer = self.footer(),
repo = self.reponame,
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])
def diff():
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",
mpm@selenic.com
Prettify the web interface...
r142 header = self.header(),
footer = self.footer(),
repo = self.reponame,
mpm@selenic.com
Revamped templated hgweb
r138 file = file,
filenode = hex(mf[file]),
node = changeset,
rev = self.repo.changelog.rev(n),
p1 = hex(p1),
p1rev = self.repo.changelog.rev(p1),
diff = diff)
# 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):
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: add template filters, template style maps, and raw pages...
r201 m = os.path.join(self.templates, "map")
if args.has_key('style'):
b = os.path.basename("map-" + args['style'][0])
p = os.path.join(self.templates, b)
if os.path.isfile(p): m = p
self.t = templater(m, self.filters)
mpm@selenic.com
Revamped templated hgweb
r138 if not args.has_key('cmd') or args['cmd'][0] == 'changelog':
hi = self.repo.changelog.count()
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))
except KeyError:
hi = self.repo.changelog.count()
jake@edge2.net
moving hgweb to mercurial subdir
r131
mpm@selenic.com
Revamped templated hgweb
r138 write(self.changelog(hi))
jake@edge2.net
making hgweb class
r132
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':
httphdr("text/plain")
h = self.repo.heads()
sys.stdout.write(" ".join(map(hex, h)) + "\n")
jake@edge2.net
making hgweb class
r132 elif args['cmd'][0] == 'branches':
httphdr("text/plain")
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':
httphdr("text/plain")
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':
httphdr("application/hg-changegroup")
nodes = []
mpm@selenic.com
hgweb: add view-only support...
r197 if self.viewonly:
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()
mpm@selenic.com
Revamped templated hgweb
r138 for chunk in self.repo.changegroup(nodes):
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
Add 'hg serve' command for stand-alone server...
r158 def server(path, name, templates, address, port):
import BaseHTTPServer
import sys, os
class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler):
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('+', ' ')
env = {}
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
env['REQUEST_METHOD'] = self.command
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
hg = hgweb(path, name, templates)
httpd = BaseHTTPServer.HTTPServer((address, port), hgwebhandler)
httpd.serve_forever()