##// END OF EJS Templates
hgweb: Keep session variables (currently only style) in HTML forms, too....
Thomas Arendsen Hein -
r3362:887da224 default
parent child Browse files
Show More
@@ -1,1047 +1,1058 b''
1 # hgweb/hgweb_mod.py - Web interface for a repository.
1 # hgweb/hgweb_mod.py - Web interface for a repository.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 import os
9 import os
10 import os.path
10 import os.path
11 import mimetypes
11 import mimetypes
12 from mercurial.demandload import demandload
12 from mercurial.demandload import demandload
13 demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
13 demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
14 demandload(globals(), 'urllib')
14 demandload(globals(), 'urllib')
15 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
15 demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
16 demandload(globals(), "mercurial:revlog,templater")
16 demandload(globals(), "mercurial:revlog,templater")
17 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
17 demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile,style_map")
18 from mercurial.node import *
18 from mercurial.node import *
19 from mercurial.i18n import gettext as _
19 from mercurial.i18n import gettext as _
20
20
21 def _up(p):
21 def _up(p):
22 if p[0] != "/":
22 if p[0] != "/":
23 p = "/" + p
23 p = "/" + p
24 if p[-1] == "/":
24 if p[-1] == "/":
25 p = p[:-1]
25 p = p[:-1]
26 up = os.path.dirname(p)
26 up = os.path.dirname(p)
27 if up == "/":
27 if up == "/":
28 return "/"
28 return "/"
29 return up + "/"
29 return up + "/"
30
30
31 class hgweb(object):
31 class hgweb(object):
32 def __init__(self, repo, name=None):
32 def __init__(self, repo, name=None):
33 if type(repo) == type(""):
33 if type(repo) == type(""):
34 self.repo = hg.repository(ui.ui(), repo)
34 self.repo = hg.repository(ui.ui(), repo)
35 else:
35 else:
36 self.repo = repo
36 self.repo = repo
37
37
38 self.mtime = -1
38 self.mtime = -1
39 self.reponame = name
39 self.reponame = name
40 self.archives = 'zip', 'gz', 'bz2'
40 self.archives = 'zip', 'gz', 'bz2'
41 self.stripecount = 1
41 self.stripecount = 1
42 self.templatepath = self.repo.ui.config("web", "templates",
42 self.templatepath = self.repo.ui.config("web", "templates",
43 templater.templatepath())
43 templater.templatepath())
44
44
45 def refresh(self):
45 def refresh(self):
46 mtime = get_mtime(self.repo.root)
46 mtime = get_mtime(self.repo.root)
47 if mtime != self.mtime:
47 if mtime != self.mtime:
48 self.mtime = mtime
48 self.mtime = mtime
49 self.repo = hg.repository(self.repo.ui, self.repo.root)
49 self.repo = hg.repository(self.repo.ui, self.repo.root)
50 self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10))
50 self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10))
51 self.stripecount = int(self.repo.ui.config("web", "stripes", 1))
51 self.stripecount = int(self.repo.ui.config("web", "stripes", 1))
52 self.maxshortchanges = int(self.repo.ui.config("web", "maxshortchanges", 60))
52 self.maxshortchanges = int(self.repo.ui.config("web", "maxshortchanges", 60))
53 self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10))
53 self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10))
54 self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
54 self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
55
55
56 def archivelist(self, nodeid):
56 def archivelist(self, nodeid):
57 allowed = self.repo.ui.configlist("web", "allow_archive")
57 allowed = self.repo.ui.configlist("web", "allow_archive")
58 for i, spec in self.archive_specs.iteritems():
58 for i, spec in self.archive_specs.iteritems():
59 if i in allowed or self.repo.ui.configbool("web", "allow" + i):
59 if i in allowed or self.repo.ui.configbool("web", "allow" + i):
60 yield {"type" : i, "extension" : spec[2], "node" : nodeid}
60 yield {"type" : i, "extension" : spec[2], "node" : nodeid}
61
61
62 def listfilediffs(self, files, changeset):
62 def listfilediffs(self, files, changeset):
63 for f in files[:self.maxfiles]:
63 for f in files[:self.maxfiles]:
64 yield self.t("filedifflink", node=hex(changeset), file=f)
64 yield self.t("filedifflink", node=hex(changeset), file=f)
65 if len(files) > self.maxfiles:
65 if len(files) > self.maxfiles:
66 yield self.t("fileellipses")
66 yield self.t("fileellipses")
67
67
68 def siblings(self, siblings=[], hiderev=None, **args):
68 def siblings(self, siblings=[], hiderev=None, **args):
69 siblings = [s for s in siblings if s.node() != nullid]
69 siblings = [s for s in siblings if s.node() != nullid]
70 if len(siblings) == 1 and siblings[0].rev() == hiderev:
70 if len(siblings) == 1 and siblings[0].rev() == hiderev:
71 return
71 return
72 for s in siblings:
72 for s in siblings:
73 yield dict(node=hex(s.node()), rev=s.rev(), **args)
73 yield dict(node=hex(s.node()), rev=s.rev(), **args)
74
74
75 def renamelink(self, fl, node):
75 def renamelink(self, fl, node):
76 r = fl.renamed(node)
76 r = fl.renamed(node)
77 if r:
77 if r:
78 return [dict(file=r[0], node=hex(r[1]))]
78 return [dict(file=r[0], node=hex(r[1]))]
79 return []
79 return []
80
80
81 def showtag(self, t1, node=nullid, **args):
81 def showtag(self, t1, node=nullid, **args):
82 for t in self.repo.nodetags(node):
82 for t in self.repo.nodetags(node):
83 yield self.t(t1, tag=t, **args)
83 yield self.t(t1, tag=t, **args)
84
84
85 def diff(self, node1, node2, files):
85 def diff(self, node1, node2, files):
86 def filterfiles(filters, files):
86 def filterfiles(filters, files):
87 l = [x for x in files if x in filters]
87 l = [x for x in files if x in filters]
88
88
89 for t in filters:
89 for t in filters:
90 if t and t[-1] != os.sep:
90 if t and t[-1] != os.sep:
91 t += os.sep
91 t += os.sep
92 l += [x for x in files if x.startswith(t)]
92 l += [x for x in files if x.startswith(t)]
93 return l
93 return l
94
94
95 parity = [0]
95 parity = [0]
96 def diffblock(diff, f, fn):
96 def diffblock(diff, f, fn):
97 yield self.t("diffblock",
97 yield self.t("diffblock",
98 lines=prettyprintlines(diff),
98 lines=prettyprintlines(diff),
99 parity=parity[0],
99 parity=parity[0],
100 file=f,
100 file=f,
101 filenode=hex(fn or nullid))
101 filenode=hex(fn or nullid))
102 parity[0] = 1 - parity[0]
102 parity[0] = 1 - parity[0]
103
103
104 def prettyprintlines(diff):
104 def prettyprintlines(diff):
105 for l in diff.splitlines(1):
105 for l in diff.splitlines(1):
106 if l.startswith('+'):
106 if l.startswith('+'):
107 yield self.t("difflineplus", line=l)
107 yield self.t("difflineplus", line=l)
108 elif l.startswith('-'):
108 elif l.startswith('-'):
109 yield self.t("difflineminus", line=l)
109 yield self.t("difflineminus", line=l)
110 elif l.startswith('@'):
110 elif l.startswith('@'):
111 yield self.t("difflineat", line=l)
111 yield self.t("difflineat", line=l)
112 else:
112 else:
113 yield self.t("diffline", line=l)
113 yield self.t("diffline", line=l)
114
114
115 r = self.repo
115 r = self.repo
116 cl = r.changelog
116 cl = r.changelog
117 mf = r.manifest
117 mf = r.manifest
118 change1 = cl.read(node1)
118 change1 = cl.read(node1)
119 change2 = cl.read(node2)
119 change2 = cl.read(node2)
120 mmap1 = mf.read(change1[0])
120 mmap1 = mf.read(change1[0])
121 mmap2 = mf.read(change2[0])
121 mmap2 = mf.read(change2[0])
122 date1 = util.datestr(change1[2])
122 date1 = util.datestr(change1[2])
123 date2 = util.datestr(change2[2])
123 date2 = util.datestr(change2[2])
124
124
125 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
125 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
126 if files:
126 if files:
127 modified, added, removed = map(lambda x: filterfiles(files, x),
127 modified, added, removed = map(lambda x: filterfiles(files, x),
128 (modified, added, removed))
128 (modified, added, removed))
129
129
130 diffopts = patch.diffopts(self.repo.ui)
130 diffopts = patch.diffopts(self.repo.ui)
131 for f in modified:
131 for f in modified:
132 to = r.file(f).read(mmap1[f])
132 to = r.file(f).read(mmap1[f])
133 tn = r.file(f).read(mmap2[f])
133 tn = r.file(f).read(mmap2[f])
134 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
134 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
135 opts=diffopts), f, tn)
135 opts=diffopts), f, tn)
136 for f in added:
136 for f in added:
137 to = None
137 to = None
138 tn = r.file(f).read(mmap2[f])
138 tn = r.file(f).read(mmap2[f])
139 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
139 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
140 opts=diffopts), f, tn)
140 opts=diffopts), f, tn)
141 for f in removed:
141 for f in removed:
142 to = r.file(f).read(mmap1[f])
142 to = r.file(f).read(mmap1[f])
143 tn = None
143 tn = None
144 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
144 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
145 opts=diffopts), f, tn)
145 opts=diffopts), f, tn)
146
146
147 def changelog(self, ctx, shortlog=False):
147 def changelog(self, ctx, shortlog=False):
148 pos = ctx.rev()
148 pos = ctx.rev()
149 def changenav(**map):
149 def changenav(**map):
150 def seq(factor, maxchanges=None):
150 def seq(factor, maxchanges=None):
151 if maxchanges:
151 if maxchanges:
152 yield maxchanges
152 yield maxchanges
153 if maxchanges >= 20 and maxchanges <= 40:
153 if maxchanges >= 20 and maxchanges <= 40:
154 yield 50
154 yield 50
155 else:
155 else:
156 yield 1 * factor
156 yield 1 * factor
157 yield 3 * factor
157 yield 3 * factor
158 for f in seq(factor * 10):
158 for f in seq(factor * 10):
159 yield f
159 yield f
160
160
161 l = []
161 l = []
162 last = 0
162 last = 0
163 maxchanges = shortlog and self.maxshortchanges or self.maxchanges
163 maxchanges = shortlog and self.maxshortchanges or self.maxchanges
164 for f in seq(1, maxchanges):
164 for f in seq(1, maxchanges):
165 if f < maxchanges or f <= last:
165 if f < maxchanges or f <= last:
166 continue
166 continue
167 if f > count:
167 if f > count:
168 break
168 break
169 last = f
169 last = f
170 r = "%d" % f
170 r = "%d" % f
171 if pos + f < count:
171 if pos + f < count:
172 l.append(("+" + r, pos + f))
172 l.append(("+" + r, pos + f))
173 if pos - f >= 0:
173 if pos - f >= 0:
174 l.insert(0, ("-" + r, pos - f))
174 l.insert(0, ("-" + r, pos - f))
175
175
176 yield {"rev": 0, "label": "(0)"}
176 yield {"rev": 0, "label": "(0)"}
177
177
178 for label, rev in l:
178 for label, rev in l:
179 yield {"label": label, "rev": rev}
179 yield {"label": label, "rev": rev}
180
180
181 yield {"label": "tip", "rev": "tip"}
181 yield {"label": "tip", "rev": "tip"}
182
182
183 def changelist(**map):
183 def changelist(**map):
184 parity = (start - end) & 1
184 parity = (start - end) & 1
185 cl = self.repo.changelog
185 cl = self.repo.changelog
186 l = [] # build a list in forward order for efficiency
186 l = [] # build a list in forward order for efficiency
187 for i in range(start, end):
187 for i in range(start, end):
188 ctx = self.repo.changectx(i)
188 ctx = self.repo.changectx(i)
189 n = ctx.node()
189 n = ctx.node()
190
190
191 l.insert(0, {"parity": parity,
191 l.insert(0, {"parity": parity,
192 "author": ctx.user(),
192 "author": ctx.user(),
193 "parent": self.siblings(ctx.parents(), i - 1),
193 "parent": self.siblings(ctx.parents(), i - 1),
194 "child": self.siblings(ctx.children(), i + 1),
194 "child": self.siblings(ctx.children(), i + 1),
195 "changelogtag": self.showtag("changelogtag",n),
195 "changelogtag": self.showtag("changelogtag",n),
196 "desc": ctx.description(),
196 "desc": ctx.description(),
197 "date": ctx.date(),
197 "date": ctx.date(),
198 "files": self.listfilediffs(ctx.files(), n),
198 "files": self.listfilediffs(ctx.files(), n),
199 "rev": i,
199 "rev": i,
200 "node": hex(n)})
200 "node": hex(n)})
201 parity = 1 - parity
201 parity = 1 - parity
202
202
203 for e in l:
203 for e in l:
204 yield e
204 yield e
205
205
206 maxchanges = shortlog and self.maxshortchanges or self.maxchanges
206 maxchanges = shortlog and self.maxshortchanges or self.maxchanges
207 cl = self.repo.changelog
207 cl = self.repo.changelog
208 count = cl.count()
208 count = cl.count()
209 start = max(0, pos - maxchanges + 1)
209 start = max(0, pos - maxchanges + 1)
210 end = min(count, start + maxchanges)
210 end = min(count, start + maxchanges)
211 pos = end - 1
211 pos = end - 1
212
212
213 yield self.t(shortlog and 'shortlog' or 'changelog',
213 yield self.t(shortlog and 'shortlog' or 'changelog',
214 changenav=changenav,
214 changenav=changenav,
215 node=hex(cl.tip()),
215 node=hex(cl.tip()),
216 rev=pos, changesets=count, entries=changelist,
216 rev=pos, changesets=count, entries=changelist,
217 archives=self.archivelist("tip"))
217 archives=self.archivelist("tip"))
218
218
219 def search(self, query):
219 def search(self, query):
220
220
221 def changelist(**map):
221 def changelist(**map):
222 cl = self.repo.changelog
222 cl = self.repo.changelog
223 count = 0
223 count = 0
224 qw = query.lower().split()
224 qw = query.lower().split()
225
225
226 def revgen():
226 def revgen():
227 for i in range(cl.count() - 1, 0, -100):
227 for i in range(cl.count() - 1, 0, -100):
228 l = []
228 l = []
229 for j in range(max(0, i - 100), i):
229 for j in range(max(0, i - 100), i):
230 ctx = self.repo.changectx(j)
230 ctx = self.repo.changectx(j)
231 l.append(ctx)
231 l.append(ctx)
232 l.reverse()
232 l.reverse()
233 for e in l:
233 for e in l:
234 yield e
234 yield e
235
235
236 for ctx in revgen():
236 for ctx in revgen():
237 miss = 0
237 miss = 0
238 for q in qw:
238 for q in qw:
239 if not (q in ctx.user().lower() or
239 if not (q in ctx.user().lower() or
240 q in ctx.description().lower() or
240 q in ctx.description().lower() or
241 q in " ".join(ctx.files()[:20]).lower()):
241 q in " ".join(ctx.files()[:20]).lower()):
242 miss = 1
242 miss = 1
243 break
243 break
244 if miss:
244 if miss:
245 continue
245 continue
246
246
247 count += 1
247 count += 1
248 n = ctx.node()
248 n = ctx.node()
249
249
250 yield self.t('searchentry',
250 yield self.t('searchentry',
251 parity=self.stripes(count),
251 parity=self.stripes(count),
252 author=ctx.user(),
252 author=ctx.user(),
253 parent=self.siblings(ctx.parents()),
253 parent=self.siblings(ctx.parents()),
254 child=self.siblings(ctx.children()),
254 child=self.siblings(ctx.children()),
255 changelogtag=self.showtag("changelogtag",n),
255 changelogtag=self.showtag("changelogtag",n),
256 desc=ctx.description(),
256 desc=ctx.description(),
257 date=ctx.date(),
257 date=ctx.date(),
258 files=self.listfilediffs(ctx.files(), n),
258 files=self.listfilediffs(ctx.files(), n),
259 rev=ctx.rev(),
259 rev=ctx.rev(),
260 node=hex(n))
260 node=hex(n))
261
261
262 if count >= self.maxchanges:
262 if count >= self.maxchanges:
263 break
263 break
264
264
265 cl = self.repo.changelog
265 cl = self.repo.changelog
266
266
267 yield self.t('search',
267 yield self.t('search',
268 query=query,
268 query=query,
269 node=hex(cl.tip()),
269 node=hex(cl.tip()),
270 entries=changelist)
270 entries=changelist)
271
271
272 def changeset(self, ctx):
272 def changeset(self, ctx):
273 n = ctx.node()
273 n = ctx.node()
274 parents = ctx.parents()
274 parents = ctx.parents()
275 p1 = parents[0].node()
275 p1 = parents[0].node()
276
276
277 files = []
277 files = []
278 parity = 0
278 parity = 0
279 for f in ctx.files():
279 for f in ctx.files():
280 files.append(self.t("filenodelink",
280 files.append(self.t("filenodelink",
281 node=hex(n), file=f,
281 node=hex(n), file=f,
282 parity=parity))
282 parity=parity))
283 parity = 1 - parity
283 parity = 1 - parity
284
284
285 def diff(**map):
285 def diff(**map):
286 yield self.diff(p1, n, None)
286 yield self.diff(p1, n, None)
287
287
288 yield self.t('changeset',
288 yield self.t('changeset',
289 diff=diff,
289 diff=diff,
290 rev=ctx.rev(),
290 rev=ctx.rev(),
291 node=hex(n),
291 node=hex(n),
292 parent=self.siblings(parents),
292 parent=self.siblings(parents),
293 child=self.siblings(ctx.children()),
293 child=self.siblings(ctx.children()),
294 changesettag=self.showtag("changesettag",n),
294 changesettag=self.showtag("changesettag",n),
295 author=ctx.user(),
295 author=ctx.user(),
296 desc=ctx.description(),
296 desc=ctx.description(),
297 date=ctx.date(),
297 date=ctx.date(),
298 files=files,
298 files=files,
299 archives=self.archivelist(hex(n)))
299 archives=self.archivelist(hex(n)))
300
300
301 def filelog(self, fctx):
301 def filelog(self, fctx):
302 f = fctx.path()
302 f = fctx.path()
303 fl = fctx.filelog()
303 fl = fctx.filelog()
304 count = fl.count()
304 count = fl.count()
305
305
306 def entries(**map):
306 def entries(**map):
307 l = []
307 l = []
308 parity = (count - 1) & 1
308 parity = (count - 1) & 1
309
309
310 for i in range(count):
310 for i in range(count):
311 ctx = fctx.filectx(i)
311 ctx = fctx.filectx(i)
312 n = fl.node(i)
312 n = fl.node(i)
313
313
314 l.insert(0, {"parity": parity,
314 l.insert(0, {"parity": parity,
315 "filerev": i,
315 "filerev": i,
316 "file": f,
316 "file": f,
317 "node": hex(ctx.node()),
317 "node": hex(ctx.node()),
318 "author": ctx.user(),
318 "author": ctx.user(),
319 "date": ctx.date(),
319 "date": ctx.date(),
320 "rename": self.renamelink(fl, n),
320 "rename": self.renamelink(fl, n),
321 "parent": self.siblings(fctx.parents(), file=f),
321 "parent": self.siblings(fctx.parents(), file=f),
322 "child": self.siblings(fctx.children(), file=f),
322 "child": self.siblings(fctx.children(), file=f),
323 "desc": ctx.description()})
323 "desc": ctx.description()})
324 parity = 1 - parity
324 parity = 1 - parity
325
325
326 for e in l:
326 for e in l:
327 yield e
327 yield e
328
328
329 yield self.t("filelog", file=f, node=hex(fctx.node()), entries=entries)
329 yield self.t("filelog", file=f, node=hex(fctx.node()), entries=entries)
330
330
331 def filerevision(self, fctx):
331 def filerevision(self, fctx):
332 f = fctx.path()
332 f = fctx.path()
333 text = fctx.data()
333 text = fctx.data()
334 fl = fctx.filelog()
334 fl = fctx.filelog()
335 n = fctx.filenode()
335 n = fctx.filenode()
336
336
337 mt = mimetypes.guess_type(f)[0]
337 mt = mimetypes.guess_type(f)[0]
338 rawtext = text
338 rawtext = text
339 if util.binary(text):
339 if util.binary(text):
340 mt = mt or 'application/octet-stream'
340 mt = mt or 'application/octet-stream'
341 text = "(binary:%s)" % mt
341 text = "(binary:%s)" % mt
342 mt = mt or 'text/plain'
342 mt = mt or 'text/plain'
343
343
344 def lines():
344 def lines():
345 for l, t in enumerate(text.splitlines(1)):
345 for l, t in enumerate(text.splitlines(1)):
346 yield {"line": t,
346 yield {"line": t,
347 "linenumber": "% 6d" % (l + 1),
347 "linenumber": "% 6d" % (l + 1),
348 "parity": self.stripes(l)}
348 "parity": self.stripes(l)}
349
349
350 yield self.t("filerevision",
350 yield self.t("filerevision",
351 file=f,
351 file=f,
352 path=_up(f),
352 path=_up(f),
353 text=lines(),
353 text=lines(),
354 raw=rawtext,
354 raw=rawtext,
355 mimetype=mt,
355 mimetype=mt,
356 rev=fctx.rev(),
356 rev=fctx.rev(),
357 node=hex(fctx.node()),
357 node=hex(fctx.node()),
358 author=fctx.user(),
358 author=fctx.user(),
359 date=fctx.date(),
359 date=fctx.date(),
360 parent=self.siblings(fctx.parents(), file=f),
360 parent=self.siblings(fctx.parents(), file=f),
361 child=self.siblings(fctx.children(), file=f),
361 child=self.siblings(fctx.children(), file=f),
362 rename=self.renamelink(fl, n),
362 rename=self.renamelink(fl, n),
363 permissions=fctx.manifest().execf(f))
363 permissions=fctx.manifest().execf(f))
364
364
365 def fileannotate(self, fctx):
365 def fileannotate(self, fctx):
366 f = fctx.path()
366 f = fctx.path()
367 n = fctx.filenode()
367 n = fctx.filenode()
368 fl = fctx.filelog()
368 fl = fctx.filelog()
369
369
370 def annotate(**map):
370 def annotate(**map):
371 parity = 0
371 parity = 0
372 last = None
372 last = None
373 for f, l in fctx.annotate(follow=True):
373 for f, l in fctx.annotate(follow=True):
374 fnode = f.filenode()
374 fnode = f.filenode()
375 name = self.repo.ui.shortuser(f.user())
375 name = self.repo.ui.shortuser(f.user())
376
376
377 if last != fnode:
377 if last != fnode:
378 parity = 1 - parity
378 parity = 1 - parity
379 last = fnode
379 last = fnode
380
380
381 yield {"parity": parity,
381 yield {"parity": parity,
382 "node": hex(f.node()),
382 "node": hex(f.node()),
383 "rev": f.rev(),
383 "rev": f.rev(),
384 "author": name,
384 "author": name,
385 "file": f.path(),
385 "file": f.path(),
386 "line": l}
386 "line": l}
387
387
388 yield self.t("fileannotate",
388 yield self.t("fileannotate",
389 file=f,
389 file=f,
390 annotate=annotate,
390 annotate=annotate,
391 path=_up(f),
391 path=_up(f),
392 rev=fctx.rev(),
392 rev=fctx.rev(),
393 node=hex(fctx.node()),
393 node=hex(fctx.node()),
394 author=fctx.user(),
394 author=fctx.user(),
395 date=fctx.date(),
395 date=fctx.date(),
396 rename=self.renamelink(fl, n),
396 rename=self.renamelink(fl, n),
397 parent=self.siblings(fctx.parents(), file=f),
397 parent=self.siblings(fctx.parents(), file=f),
398 child=self.siblings(fctx.children(), file=f),
398 child=self.siblings(fctx.children(), file=f),
399 permissions=fctx.manifest().execf(f))
399 permissions=fctx.manifest().execf(f))
400
400
401 def manifest(self, ctx, path):
401 def manifest(self, ctx, path):
402 mf = ctx.manifest()
402 mf = ctx.manifest()
403 node = ctx.node()
403 node = ctx.node()
404
404
405 files = {}
405 files = {}
406
406
407 p = path[1:]
407 p = path[1:]
408 if p and p[-1] != "/":
408 if p and p[-1] != "/":
409 p += "/"
409 p += "/"
410 l = len(p)
410 l = len(p)
411
411
412 for f,n in mf.items():
412 for f,n in mf.items():
413 if f[:l] != p:
413 if f[:l] != p:
414 continue
414 continue
415 remain = f[l:]
415 remain = f[l:]
416 if "/" in remain:
416 if "/" in remain:
417 short = remain[:remain.index("/") + 1] # bleah
417 short = remain[:remain.index("/") + 1] # bleah
418 files[short] = (f, None)
418 files[short] = (f, None)
419 else:
419 else:
420 short = os.path.basename(remain)
420 short = os.path.basename(remain)
421 files[short] = (f, n)
421 files[short] = (f, n)
422
422
423 def filelist(**map):
423 def filelist(**map):
424 parity = 0
424 parity = 0
425 fl = files.keys()
425 fl = files.keys()
426 fl.sort()
426 fl.sort()
427 for f in fl:
427 for f in fl:
428 full, fnode = files[f]
428 full, fnode = files[f]
429 if not fnode:
429 if not fnode:
430 continue
430 continue
431
431
432 yield {"file": full,
432 yield {"file": full,
433 "parity": self.stripes(parity),
433 "parity": self.stripes(parity),
434 "basename": f,
434 "basename": f,
435 "size": ctx.filectx(full).size(),
435 "size": ctx.filectx(full).size(),
436 "permissions": mf.execf(full)}
436 "permissions": mf.execf(full)}
437 parity += 1
437 parity += 1
438
438
439 def dirlist(**map):
439 def dirlist(**map):
440 parity = 0
440 parity = 0
441 fl = files.keys()
441 fl = files.keys()
442 fl.sort()
442 fl.sort()
443 for f in fl:
443 for f in fl:
444 full, fnode = files[f]
444 full, fnode = files[f]
445 if fnode:
445 if fnode:
446 continue
446 continue
447
447
448 yield {"parity": self.stripes(parity),
448 yield {"parity": self.stripes(parity),
449 "path": os.path.join(path, f),
449 "path": os.path.join(path, f),
450 "basename": f[:-1]}
450 "basename": f[:-1]}
451 parity += 1
451 parity += 1
452
452
453 yield self.t("manifest",
453 yield self.t("manifest",
454 rev=ctx.rev(),
454 rev=ctx.rev(),
455 node=hex(node),
455 node=hex(node),
456 path=path,
456 path=path,
457 up=_up(path),
457 up=_up(path),
458 fentries=filelist,
458 fentries=filelist,
459 dentries=dirlist,
459 dentries=dirlist,
460 archives=self.archivelist(hex(node)))
460 archives=self.archivelist(hex(node)))
461
461
462 def tags(self):
462 def tags(self):
463 cl = self.repo.changelog
463 cl = self.repo.changelog
464
464
465 i = self.repo.tagslist()
465 i = self.repo.tagslist()
466 i.reverse()
466 i.reverse()
467
467
468 def entries(notip=False, **map):
468 def entries(notip=False, **map):
469 parity = 0
469 parity = 0
470 for k,n in i:
470 for k,n in i:
471 if notip and k == "tip": continue
471 if notip and k == "tip": continue
472 yield {"parity": self.stripes(parity),
472 yield {"parity": self.stripes(parity),
473 "tag": k,
473 "tag": k,
474 "date": cl.read(n)[2],
474 "date": cl.read(n)[2],
475 "node": hex(n)}
475 "node": hex(n)}
476 parity += 1
476 parity += 1
477
477
478 yield self.t("tags",
478 yield self.t("tags",
479 node=hex(self.repo.changelog.tip()),
479 node=hex(self.repo.changelog.tip()),
480 entries=lambda **x: entries(False, **x),
480 entries=lambda **x: entries(False, **x),
481 entriesnotip=lambda **x: entries(True, **x))
481 entriesnotip=lambda **x: entries(True, **x))
482
482
483 def summary(self):
483 def summary(self):
484 cl = self.repo.changelog
484 cl = self.repo.changelog
485
485
486 i = self.repo.tagslist()
486 i = self.repo.tagslist()
487 i.reverse()
487 i.reverse()
488
488
489 def tagentries(**map):
489 def tagentries(**map):
490 parity = 0
490 parity = 0
491 count = 0
491 count = 0
492 for k,n in i:
492 for k,n in i:
493 if k == "tip": # skip tip
493 if k == "tip": # skip tip
494 continue;
494 continue;
495
495
496 count += 1
496 count += 1
497 if count > 10: # limit to 10 tags
497 if count > 10: # limit to 10 tags
498 break;
498 break;
499
499
500 c = cl.read(n)
500 c = cl.read(n)
501 t = c[2]
501 t = c[2]
502
502
503 yield self.t("tagentry",
503 yield self.t("tagentry",
504 parity = self.stripes(parity),
504 parity = self.stripes(parity),
505 tag = k,
505 tag = k,
506 node = hex(n),
506 node = hex(n),
507 date = t)
507 date = t)
508 parity += 1
508 parity += 1
509
509
510 def changelist(**map):
510 def changelist(**map):
511 parity = 0
511 parity = 0
512 cl = self.repo.changelog
512 cl = self.repo.changelog
513 l = [] # build a list in forward order for efficiency
513 l = [] # build a list in forward order for efficiency
514 for i in range(start, end):
514 for i in range(start, end):
515 n = cl.node(i)
515 n = cl.node(i)
516 changes = cl.read(n)
516 changes = cl.read(n)
517 hn = hex(n)
517 hn = hex(n)
518 t = changes[2]
518 t = changes[2]
519
519
520 l.insert(0, self.t(
520 l.insert(0, self.t(
521 'shortlogentry',
521 'shortlogentry',
522 parity = parity,
522 parity = parity,
523 author = changes[1],
523 author = changes[1],
524 desc = changes[4],
524 desc = changes[4],
525 date = t,
525 date = t,
526 rev = i,
526 rev = i,
527 node = hn))
527 node = hn))
528 parity = 1 - parity
528 parity = 1 - parity
529
529
530 yield l
530 yield l
531
531
532 count = cl.count()
532 count = cl.count()
533 start = max(0, count - self.maxchanges)
533 start = max(0, count - self.maxchanges)
534 end = min(count, start + self.maxchanges)
534 end = min(count, start + self.maxchanges)
535
535
536 yield self.t("summary",
536 yield self.t("summary",
537 desc = self.repo.ui.config("web", "description", "unknown"),
537 desc = self.repo.ui.config("web", "description", "unknown"),
538 owner = (self.repo.ui.config("ui", "username") or # preferred
538 owner = (self.repo.ui.config("ui", "username") or # preferred
539 self.repo.ui.config("web", "contact") or # deprecated
539 self.repo.ui.config("web", "contact") or # deprecated
540 self.repo.ui.config("web", "author", "unknown")), # also
540 self.repo.ui.config("web", "author", "unknown")), # also
541 lastchange = cl.read(cl.tip())[2],
541 lastchange = cl.read(cl.tip())[2],
542 tags = tagentries,
542 tags = tagentries,
543 shortlog = changelist,
543 shortlog = changelist,
544 node = hex(cl.tip()),
544 node = hex(cl.tip()),
545 archives=self.archivelist("tip"))
545 archives=self.archivelist("tip"))
546
546
547 def filediff(self, fctx):
547 def filediff(self, fctx):
548 n = fctx.node()
548 n = fctx.node()
549 path = fctx.path()
549 path = fctx.path()
550 parents = fctx.changectx().parents()
550 parents = fctx.changectx().parents()
551 p1 = parents[0].node()
551 p1 = parents[0].node()
552
552
553 def diff(**map):
553 def diff(**map):
554 yield self.diff(p1, n, [path])
554 yield self.diff(p1, n, [path])
555
555
556 yield self.t("filediff",
556 yield self.t("filediff",
557 file=path,
557 file=path,
558 node=hex(n),
558 node=hex(n),
559 rev=fctx.rev(),
559 rev=fctx.rev(),
560 parent=self.siblings(parents),
560 parent=self.siblings(parents),
561 child=self.siblings(fctx.children()),
561 child=self.siblings(fctx.children()),
562 diff=diff)
562 diff=diff)
563
563
564 archive_specs = {
564 archive_specs = {
565 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
565 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
566 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
566 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
567 'zip': ('application/zip', 'zip', '.zip', None),
567 'zip': ('application/zip', 'zip', '.zip', None),
568 }
568 }
569
569
570 def archive(self, req, cnode, type_):
570 def archive(self, req, cnode, type_):
571 reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame))
571 reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame))
572 name = "%s-%s" % (reponame, short(cnode))
572 name = "%s-%s" % (reponame, short(cnode))
573 mimetype, artype, extension, encoding = self.archive_specs[type_]
573 mimetype, artype, extension, encoding = self.archive_specs[type_]
574 headers = [('Content-type', mimetype),
574 headers = [('Content-type', mimetype),
575 ('Content-disposition', 'attachment; filename=%s%s' %
575 ('Content-disposition', 'attachment; filename=%s%s' %
576 (name, extension))]
576 (name, extension))]
577 if encoding:
577 if encoding:
578 headers.append(('Content-encoding', encoding))
578 headers.append(('Content-encoding', encoding))
579 req.header(headers)
579 req.header(headers)
580 archival.archive(self.repo, req.out, cnode, artype, prefix=name)
580 archival.archive(self.repo, req.out, cnode, artype, prefix=name)
581
581
582 # add tags to things
582 # add tags to things
583 # tags -> list of changesets corresponding to tags
583 # tags -> list of changesets corresponding to tags
584 # find tag, changeset, file
584 # find tag, changeset, file
585
585
586 def cleanpath(self, path):
586 def cleanpath(self, path):
587 p = util.normpath(path)
587 p = util.normpath(path)
588 if p[:2] == "..":
588 if p[:2] == "..":
589 raise Exception("suspicious path")
589 raise Exception("suspicious path")
590 return p
590 return p
591
591
592 def run(self):
592 def run(self):
593 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
593 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
594 raise RuntimeError("This function is only intended to be called while running as a CGI script.")
594 raise RuntimeError("This function is only intended to be called while running as a CGI script.")
595 import mercurial.hgweb.wsgicgi as wsgicgi
595 import mercurial.hgweb.wsgicgi as wsgicgi
596 from request import wsgiapplication
596 from request import wsgiapplication
597 def make_web_app():
597 def make_web_app():
598 return self
598 return self
599 wsgicgi.launch(wsgiapplication(make_web_app))
599 wsgicgi.launch(wsgiapplication(make_web_app))
600
600
601 def run_wsgi(self, req):
601 def run_wsgi(self, req):
602 def header(**map):
602 def header(**map):
603 header_file = cStringIO.StringIO(''.join(self.t("header", **map)))
603 header_file = cStringIO.StringIO(''.join(self.t("header", **map)))
604 msg = mimetools.Message(header_file, 0)
604 msg = mimetools.Message(header_file, 0)
605 req.header(msg.items())
605 req.header(msg.items())
606 yield header_file.read()
606 yield header_file.read()
607
607
608 def rawfileheader(**map):
608 def rawfileheader(**map):
609 req.header([('Content-type', map['mimetype']),
609 req.header([('Content-type', map['mimetype']),
610 ('Content-disposition', 'filename=%s' % map['file']),
610 ('Content-disposition', 'filename=%s' % map['file']),
611 ('Content-length', str(len(map['raw'])))])
611 ('Content-length', str(len(map['raw'])))])
612 yield ''
612 yield ''
613
613
614 def footer(**map):
614 def footer(**map):
615 yield self.t("footer",
615 yield self.t("footer",
616 motd=self.repo.ui.config("web", "motd", ""),
616 motd=self.repo.ui.config("web", "motd", ""),
617 **map)
617 **map)
618
618
619 def expand_form(form):
619 def expand_form(form):
620 shortcuts = {
620 shortcuts = {
621 'cl': [('cmd', ['changelog']), ('rev', None)],
621 'cl': [('cmd', ['changelog']), ('rev', None)],
622 'sl': [('cmd', ['shortlog']), ('rev', None)],
622 'sl': [('cmd', ['shortlog']), ('rev', None)],
623 'cs': [('cmd', ['changeset']), ('node', None)],
623 'cs': [('cmd', ['changeset']), ('node', None)],
624 'f': [('cmd', ['file']), ('filenode', None)],
624 'f': [('cmd', ['file']), ('filenode', None)],
625 'fl': [('cmd', ['filelog']), ('filenode', None)],
625 'fl': [('cmd', ['filelog']), ('filenode', None)],
626 'fd': [('cmd', ['filediff']), ('node', None)],
626 'fd': [('cmd', ['filediff']), ('node', None)],
627 'fa': [('cmd', ['annotate']), ('filenode', None)],
627 'fa': [('cmd', ['annotate']), ('filenode', None)],
628 'mf': [('cmd', ['manifest']), ('manifest', None)],
628 'mf': [('cmd', ['manifest']), ('manifest', None)],
629 'ca': [('cmd', ['archive']), ('node', None)],
629 'ca': [('cmd', ['archive']), ('node', None)],
630 'tags': [('cmd', ['tags'])],
630 'tags': [('cmd', ['tags'])],
631 'tip': [('cmd', ['changeset']), ('node', ['tip'])],
631 'tip': [('cmd', ['changeset']), ('node', ['tip'])],
632 'static': [('cmd', ['static']), ('file', None)]
632 'static': [('cmd', ['static']), ('file', None)]
633 }
633 }
634
634
635 for k in shortcuts.iterkeys():
635 for k in shortcuts.iterkeys():
636 if form.has_key(k):
636 if form.has_key(k):
637 for name, value in shortcuts[k]:
637 for name, value in shortcuts[k]:
638 if value is None:
638 if value is None:
639 value = form[k]
639 value = form[k]
640 form[name] = value
640 form[name] = value
641 del form[k]
641 del form[k]
642
642
643 def rewrite_request(req):
643 def rewrite_request(req):
644 '''translate new web interface to traditional format'''
644 '''translate new web interface to traditional format'''
645
645
646 def spliturl(req):
646 def spliturl(req):
647 def firstitem(query):
647 def firstitem(query):
648 return query.split('&', 1)[0].split(';', 1)[0]
648 return query.split('&', 1)[0].split(';', 1)[0]
649
649
650 def normurl(url):
650 def normurl(url):
651 inner = '/'.join([x for x in url.split('/') if x])
651 inner = '/'.join([x for x in url.split('/') if x])
652 tl = len(url) > 1 and url.endswith('/') and '/' or ''
652 tl = len(url) > 1 and url.endswith('/') and '/' or ''
653
653
654 return '%s%s%s' % (url.startswith('/') and '/' or '',
654 return '%s%s%s' % (url.startswith('/') and '/' or '',
655 inner, tl)
655 inner, tl)
656
656
657 root = normurl(req.env.get('REQUEST_URI', '').split('?', 1)[0])
657 root = normurl(req.env.get('REQUEST_URI', '').split('?', 1)[0])
658 pi = normurl(req.env.get('PATH_INFO', ''))
658 pi = normurl(req.env.get('PATH_INFO', ''))
659 if pi:
659 if pi:
660 # strip leading /
660 # strip leading /
661 pi = pi[1:]
661 pi = pi[1:]
662 if pi:
662 if pi:
663 root = root[:-len(pi)]
663 root = root[:-len(pi)]
664 if req.env.has_key('REPO_NAME'):
664 if req.env.has_key('REPO_NAME'):
665 rn = req.env['REPO_NAME'] + '/'
665 rn = req.env['REPO_NAME'] + '/'
666 root += rn
666 root += rn
667 query = pi[len(rn):]
667 query = pi[len(rn):]
668 else:
668 else:
669 query = pi
669 query = pi
670 else:
670 else:
671 root += '?'
671 root += '?'
672 query = firstitem(req.env['QUERY_STRING'])
672 query = firstitem(req.env['QUERY_STRING'])
673
673
674 return (root, query)
674 return (root, query)
675
675
676 req.url, query = spliturl(req)
676 req.url, query = spliturl(req)
677
677
678 if req.form.has_key('cmd'):
678 if req.form.has_key('cmd'):
679 # old style
679 # old style
680 return
680 return
681
681
682 args = query.split('/', 2)
682 args = query.split('/', 2)
683 if not args or not args[0]:
683 if not args or not args[0]:
684 return
684 return
685
685
686 cmd = args.pop(0)
686 cmd = args.pop(0)
687 style = cmd.rfind('-')
687 style = cmd.rfind('-')
688 if style != -1:
688 if style != -1:
689 req.form['style'] = [cmd[:style]]
689 req.form['style'] = [cmd[:style]]
690 cmd = cmd[style+1:]
690 cmd = cmd[style+1:]
691 # avoid accepting e.g. style parameter as command
691 # avoid accepting e.g. style parameter as command
692 if hasattr(self, 'do_' + cmd):
692 if hasattr(self, 'do_' + cmd):
693 req.form['cmd'] = [cmd]
693 req.form['cmd'] = [cmd]
694
694
695 if args and args[0]:
695 if args and args[0]:
696 node = args.pop(0)
696 node = args.pop(0)
697 req.form['node'] = [node]
697 req.form['node'] = [node]
698 if args:
698 if args:
699 req.form['file'] = args
699 req.form['file'] = args
700
700
701 if cmd == 'static':
701 if cmd == 'static':
702 req.form['file'] = req.form['node']
702 req.form['file'] = req.form['node']
703 elif cmd == 'archive':
703 elif cmd == 'archive':
704 fn = req.form['node'][0]
704 fn = req.form['node'][0]
705 for type_, spec in self.archive_specs.iteritems():
705 for type_, spec in self.archive_specs.iteritems():
706 ext = spec[2]
706 ext = spec[2]
707 if fn.endswith(ext):
707 if fn.endswith(ext):
708 req.form['node'] = [fn[:-len(ext)]]
708 req.form['node'] = [fn[:-len(ext)]]
709 req.form['type'] = [type_]
709 req.form['type'] = [type_]
710
710
711 def sessionvars(**map):
712 fields = []
713 if req.form.has_key('style'):
714 style = req.form['style'][0]
715 if style != self.repo.ui.config('web', 'style', ''):
716 fields.append(('style', style))
717
718 for name, value in fields:
719 yield dict(name=name, value=value)
720
711 def queryprefix(**map):
721 def queryprefix(**map):
712 return req.url[-1] == '?' and ';' or '?'
722 return req.url[-1] == '?' and ';' or '?'
713
723
714 def getentries(**map):
724 def getentries(**map):
715 fields = {}
725 fields = {}
716 if req.form.has_key('style'):
726 if req.form.has_key('style'):
717 style = req.form['style'][0]
727 style = req.form['style'][0]
718 if style != self.repo.ui.config('web', 'style', ''):
728 if style != self.repo.ui.config('web', 'style', ''):
719 fields['style'] = style
729 fields['style'] = style
720
730
721 if fields:
731 if fields:
722 fields = ['%s=%s' % (k, urllib.quote(v))
732 fields = ['%s=%s' % (k, urllib.quote(v))
723 for k, v in fields.iteritems()]
733 for k, v in fields.iteritems()]
724 yield '%s%s' % (queryprefix(), ';'.join(fields))
734 yield '%s%s' % (queryprefix(), ';'.join(fields))
725 else:
735 else:
726 yield ''
736 yield ''
727
737
728 self.refresh()
738 self.refresh()
729
739
730 expand_form(req.form)
740 expand_form(req.form)
731 rewrite_request(req)
741 rewrite_request(req)
732
742
733 style = self.repo.ui.config("web", "style", "")
743 style = self.repo.ui.config("web", "style", "")
734 if req.form.has_key('style'):
744 if req.form.has_key('style'):
735 style = req.form['style'][0]
745 style = req.form['style'][0]
736 mapfile = style_map(self.templatepath, style)
746 mapfile = style_map(self.templatepath, style)
737
747
738 if not req.url:
748 if not req.url:
739 port = req.env["SERVER_PORT"]
749 port = req.env["SERVER_PORT"]
740 port = port != "80" and (":" + port) or ""
750 port = port != "80" and (":" + port) or ""
741 uri = req.env["REQUEST_URI"]
751 uri = req.env["REQUEST_URI"]
742 if "?" in uri:
752 if "?" in uri:
743 uri = uri.split("?")[0]
753 uri = uri.split("?")[0]
744 req.url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri)
754 req.url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri)
745
755
746 if not self.reponame:
756 if not self.reponame:
747 self.reponame = (self.repo.ui.config("web", "name")
757 self.reponame = (self.repo.ui.config("web", "name")
748 or req.env.get('REPO_NAME')
758 or req.env.get('REPO_NAME')
749 or req.url.strip('/') or self.repo.root)
759 or req.url.strip('/') or self.repo.root)
750
760
751 self.t = templater.templater(mapfile, templater.common_filters,
761 self.t = templater.templater(mapfile, templater.common_filters,
752 defaults={"url": req.url,
762 defaults={"url": req.url,
753 "repo": self.reponame,
763 "repo": self.reponame,
754 "header": header,
764 "header": header,
755 "footer": footer,
765 "footer": footer,
756 "rawfileheader": rawfileheader,
766 "rawfileheader": rawfileheader,
767 "sessionvars": sessionvars,
757 "queryprefix": queryprefix,
768 "queryprefix": queryprefix,
758 "getentries": getentries
769 "getentries": getentries
759 })
770 })
760
771
761 if not req.form.has_key('cmd'):
772 if not req.form.has_key('cmd'):
762 req.form['cmd'] = [self.t.cache['default'],]
773 req.form['cmd'] = [self.t.cache['default'],]
763
774
764 cmd = req.form['cmd'][0]
775 cmd = req.form['cmd'][0]
765
776
766 method = getattr(self, 'do_' + cmd, None)
777 method = getattr(self, 'do_' + cmd, None)
767 if method:
778 if method:
768 try:
779 try:
769 method(req)
780 method(req)
770 except (hg.RepoError, revlog.RevlogError), inst:
781 except (hg.RepoError, revlog.RevlogError), inst:
771 req.write(self.t("error", error=str(inst)))
782 req.write(self.t("error", error=str(inst)))
772 else:
783 else:
773 req.write(self.t("error", error='No such method: ' + cmd))
784 req.write(self.t("error", error='No such method: ' + cmd))
774
785
775 def changectx(self, req):
786 def changectx(self, req):
776 if req.form.has_key('node'):
787 if req.form.has_key('node'):
777 changeid = req.form['node'][0]
788 changeid = req.form['node'][0]
778 elif req.form.has_key('manifest'):
789 elif req.form.has_key('manifest'):
779 changeid = req.form['manifest'][0]
790 changeid = req.form['manifest'][0]
780 else:
791 else:
781 changeid = self.repo.changelog.count() - 1
792 changeid = self.repo.changelog.count() - 1
782
793
783 try:
794 try:
784 ctx = self.repo.changectx(changeid)
795 ctx = self.repo.changectx(changeid)
785 except hg.RepoError:
796 except hg.RepoError:
786 man = self.repo.manifest
797 man = self.repo.manifest
787 mn = man.lookup(changeid)
798 mn = man.lookup(changeid)
788 ctx = self.repo.changectx(man.linkrev(mn))
799 ctx = self.repo.changectx(man.linkrev(mn))
789
800
790 return ctx
801 return ctx
791
802
792 def filectx(self, req):
803 def filectx(self, req):
793 path = self.cleanpath(req.form['file'][0])
804 path = self.cleanpath(req.form['file'][0])
794 if req.form.has_key('node'):
805 if req.form.has_key('node'):
795 changeid = req.form['node'][0]
806 changeid = req.form['node'][0]
796 else:
807 else:
797 changeid = req.form['filenode'][0]
808 changeid = req.form['filenode'][0]
798 try:
809 try:
799 ctx = self.repo.changectx(changeid)
810 ctx = self.repo.changectx(changeid)
800 fctx = ctx.filectx(path)
811 fctx = ctx.filectx(path)
801 except hg.RepoError:
812 except hg.RepoError:
802 fctx = self.repo.filectx(path, fileid=changeid)
813 fctx = self.repo.filectx(path, fileid=changeid)
803
814
804 return fctx
815 return fctx
805
816
806 def stripes(self, parity):
817 def stripes(self, parity):
807 "make horizontal stripes for easier reading"
818 "make horizontal stripes for easier reading"
808 if self.stripecount:
819 if self.stripecount:
809 return (1 + parity / self.stripecount) & 1
820 return (1 + parity / self.stripecount) & 1
810 else:
821 else:
811 return 0
822 return 0
812
823
813 def do_log(self, req):
824 def do_log(self, req):
814 if req.form.has_key('file') and req.form['file'][0]:
825 if req.form.has_key('file') and req.form['file'][0]:
815 self.do_filelog(req)
826 self.do_filelog(req)
816 else:
827 else:
817 self.do_changelog(req)
828 self.do_changelog(req)
818
829
819 def do_rev(self, req):
830 def do_rev(self, req):
820 self.do_changeset(req)
831 self.do_changeset(req)
821
832
822 def do_file(self, req):
833 def do_file(self, req):
823 path = req.form.get('file', [''])[0]
834 path = req.form.get('file', [''])[0]
824 if path:
835 if path:
825 try:
836 try:
826 req.write(self.filerevision(self.filectx(req)))
837 req.write(self.filerevision(self.filectx(req)))
827 return
838 return
828 except hg.RepoError:
839 except hg.RepoError:
829 pass
840 pass
830 path = self.cleanpath(path)
841 path = self.cleanpath(path)
831
842
832 req.write(self.manifest(self.changectx(req), '/' + path))
843 req.write(self.manifest(self.changectx(req), '/' + path))
833
844
834 def do_diff(self, req):
845 def do_diff(self, req):
835 self.do_filediff(req)
846 self.do_filediff(req)
836
847
837 def do_changelog(self, req, shortlog = False):
848 def do_changelog(self, req, shortlog = False):
838 if req.form.has_key('node'):
849 if req.form.has_key('node'):
839 ctx = self.changectx(req)
850 ctx = self.changectx(req)
840 else:
851 else:
841 if req.form.has_key('rev'):
852 if req.form.has_key('rev'):
842 hi = req.form['rev'][0]
853 hi = req.form['rev'][0]
843 else:
854 else:
844 hi = self.repo.changelog.count() - 1
855 hi = self.repo.changelog.count() - 1
845 try:
856 try:
846 ctx = self.repo.changectx(hi)
857 ctx = self.repo.changectx(hi)
847 except hg.RepoError:
858 except hg.RepoError:
848 req.write(self.search(hi)) # XXX redirect to 404 page?
859 req.write(self.search(hi)) # XXX redirect to 404 page?
849 return
860 return
850
861
851 req.write(self.changelog(ctx, shortlog = shortlog))
862 req.write(self.changelog(ctx, shortlog = shortlog))
852
863
853 def do_shortlog(self, req):
864 def do_shortlog(self, req):
854 self.do_changelog(req, shortlog = True)
865 self.do_changelog(req, shortlog = True)
855
866
856 def do_changeset(self, req):
867 def do_changeset(self, req):
857 req.write(self.changeset(self.changectx(req)))
868 req.write(self.changeset(self.changectx(req)))
858
869
859 def do_manifest(self, req):
870 def do_manifest(self, req):
860 req.write(self.manifest(self.changectx(req),
871 req.write(self.manifest(self.changectx(req),
861 self.cleanpath(req.form['path'][0])))
872 self.cleanpath(req.form['path'][0])))
862
873
863 def do_tags(self, req):
874 def do_tags(self, req):
864 req.write(self.tags())
875 req.write(self.tags())
865
876
866 def do_summary(self, req):
877 def do_summary(self, req):
867 req.write(self.summary())
878 req.write(self.summary())
868
879
869 def do_filediff(self, req):
880 def do_filediff(self, req):
870 req.write(self.filediff(self.filectx(req)))
881 req.write(self.filediff(self.filectx(req)))
871
882
872 def do_annotate(self, req):
883 def do_annotate(self, req):
873 req.write(self.fileannotate(self.filectx(req)))
884 req.write(self.fileannotate(self.filectx(req)))
874
885
875 def do_filelog(self, req):
886 def do_filelog(self, req):
876 req.write(self.filelog(self.filectx(req)))
887 req.write(self.filelog(self.filectx(req)))
877
888
878 def do_heads(self, req):
889 def do_heads(self, req):
879 resp = " ".join(map(hex, self.repo.heads())) + "\n"
890 resp = " ".join(map(hex, self.repo.heads())) + "\n"
880 req.httphdr("application/mercurial-0.1", length=len(resp))
891 req.httphdr("application/mercurial-0.1", length=len(resp))
881 req.write(resp)
892 req.write(resp)
882
893
883 def do_branches(self, req):
894 def do_branches(self, req):
884 nodes = []
895 nodes = []
885 if req.form.has_key('nodes'):
896 if req.form.has_key('nodes'):
886 nodes = map(bin, req.form['nodes'][0].split(" "))
897 nodes = map(bin, req.form['nodes'][0].split(" "))
887 resp = cStringIO.StringIO()
898 resp = cStringIO.StringIO()
888 for b in self.repo.branches(nodes):
899 for b in self.repo.branches(nodes):
889 resp.write(" ".join(map(hex, b)) + "\n")
900 resp.write(" ".join(map(hex, b)) + "\n")
890 resp = resp.getvalue()
901 resp = resp.getvalue()
891 req.httphdr("application/mercurial-0.1", length=len(resp))
902 req.httphdr("application/mercurial-0.1", length=len(resp))
892 req.write(resp)
903 req.write(resp)
893
904
894 def do_between(self, req):
905 def do_between(self, req):
895 if req.form.has_key('pairs'):
906 if req.form.has_key('pairs'):
896 pairs = [map(bin, p.split("-"))
907 pairs = [map(bin, p.split("-"))
897 for p in req.form['pairs'][0].split(" ")]
908 for p in req.form['pairs'][0].split(" ")]
898 resp = cStringIO.StringIO()
909 resp = cStringIO.StringIO()
899 for b in self.repo.between(pairs):
910 for b in self.repo.between(pairs):
900 resp.write(" ".join(map(hex, b)) + "\n")
911 resp.write(" ".join(map(hex, b)) + "\n")
901 resp = resp.getvalue()
912 resp = resp.getvalue()
902 req.httphdr("application/mercurial-0.1", length=len(resp))
913 req.httphdr("application/mercurial-0.1", length=len(resp))
903 req.write(resp)
914 req.write(resp)
904
915
905 def do_changegroup(self, req):
916 def do_changegroup(self, req):
906 req.httphdr("application/mercurial-0.1")
917 req.httphdr("application/mercurial-0.1")
907 nodes = []
918 nodes = []
908 if not self.allowpull:
919 if not self.allowpull:
909 return
920 return
910
921
911 if req.form.has_key('roots'):
922 if req.form.has_key('roots'):
912 nodes = map(bin, req.form['roots'][0].split(" "))
923 nodes = map(bin, req.form['roots'][0].split(" "))
913
924
914 z = zlib.compressobj()
925 z = zlib.compressobj()
915 f = self.repo.changegroup(nodes, 'serve')
926 f = self.repo.changegroup(nodes, 'serve')
916 while 1:
927 while 1:
917 chunk = f.read(4096)
928 chunk = f.read(4096)
918 if not chunk:
929 if not chunk:
919 break
930 break
920 req.write(z.compress(chunk))
931 req.write(z.compress(chunk))
921
932
922 req.write(z.flush())
933 req.write(z.flush())
923
934
924 def do_archive(self, req):
935 def do_archive(self, req):
925 changeset = self.repo.lookup(req.form['node'][0])
936 changeset = self.repo.lookup(req.form['node'][0])
926 type_ = req.form['type'][0]
937 type_ = req.form['type'][0]
927 allowed = self.repo.ui.configlist("web", "allow_archive")
938 allowed = self.repo.ui.configlist("web", "allow_archive")
928 if (type_ in self.archives and (type_ in allowed or
939 if (type_ in self.archives and (type_ in allowed or
929 self.repo.ui.configbool("web", "allow" + type_, False))):
940 self.repo.ui.configbool("web", "allow" + type_, False))):
930 self.archive(req, changeset, type_)
941 self.archive(req, changeset, type_)
931 return
942 return
932
943
933 req.write(self.t("error"))
944 req.write(self.t("error"))
934
945
935 def do_static(self, req):
946 def do_static(self, req):
936 fname = req.form['file'][0]
947 fname = req.form['file'][0]
937 static = self.repo.ui.config("web", "static",
948 static = self.repo.ui.config("web", "static",
938 os.path.join(self.templatepath,
949 os.path.join(self.templatepath,
939 "static"))
950 "static"))
940 req.write(staticfile(static, fname, req)
951 req.write(staticfile(static, fname, req)
941 or self.t("error", error="%r not found" % fname))
952 or self.t("error", error="%r not found" % fname))
942
953
943 def do_capabilities(self, req):
954 def do_capabilities(self, req):
944 caps = ['unbundle']
955 caps = ['unbundle']
945 if self.repo.ui.configbool('server', 'uncompressed'):
956 if self.repo.ui.configbool('server', 'uncompressed'):
946 caps.append('stream=%d' % self.repo.revlogversion)
957 caps.append('stream=%d' % self.repo.revlogversion)
947 resp = ' '.join(caps)
958 resp = ' '.join(caps)
948 req.httphdr("application/mercurial-0.1", length=len(resp))
959 req.httphdr("application/mercurial-0.1", length=len(resp))
949 req.write(resp)
960 req.write(resp)
950
961
951 def check_perm(self, req, op, default):
962 def check_perm(self, req, op, default):
952 '''check permission for operation based on user auth.
963 '''check permission for operation based on user auth.
953 return true if op allowed, else false.
964 return true if op allowed, else false.
954 default is policy to use if no config given.'''
965 default is policy to use if no config given.'''
955
966
956 user = req.env.get('REMOTE_USER')
967 user = req.env.get('REMOTE_USER')
957
968
958 deny = self.repo.ui.configlist('web', 'deny_' + op)
969 deny = self.repo.ui.configlist('web', 'deny_' + op)
959 if deny and (not user or deny == ['*'] or user in deny):
970 if deny and (not user or deny == ['*'] or user in deny):
960 return False
971 return False
961
972
962 allow = self.repo.ui.configlist('web', 'allow_' + op)
973 allow = self.repo.ui.configlist('web', 'allow_' + op)
963 return (allow and (allow == ['*'] or user in allow)) or default
974 return (allow and (allow == ['*'] or user in allow)) or default
964
975
965 def do_unbundle(self, req):
976 def do_unbundle(self, req):
966 def bail(response, headers={}):
977 def bail(response, headers={}):
967 length = int(req.env['CONTENT_LENGTH'])
978 length = int(req.env['CONTENT_LENGTH'])
968 for s in util.filechunkiter(req, limit=length):
979 for s in util.filechunkiter(req, limit=length):
969 # drain incoming bundle, else client will not see
980 # drain incoming bundle, else client will not see
970 # response when run outside cgi script
981 # response when run outside cgi script
971 pass
982 pass
972 req.httphdr("application/mercurial-0.1", headers=headers)
983 req.httphdr("application/mercurial-0.1", headers=headers)
973 req.write('0\n')
984 req.write('0\n')
974 req.write(response)
985 req.write(response)
975
986
976 # require ssl by default, auth info cannot be sniffed and
987 # require ssl by default, auth info cannot be sniffed and
977 # replayed
988 # replayed
978 ssl_req = self.repo.ui.configbool('web', 'push_ssl', True)
989 ssl_req = self.repo.ui.configbool('web', 'push_ssl', True)
979 if ssl_req:
990 if ssl_req:
980 if not req.env.get('HTTPS'):
991 if not req.env.get('HTTPS'):
981 bail(_('ssl required\n'))
992 bail(_('ssl required\n'))
982 return
993 return
983 proto = 'https'
994 proto = 'https'
984 else:
995 else:
985 proto = 'http'
996 proto = 'http'
986
997
987 # do not allow push unless explicitly allowed
998 # do not allow push unless explicitly allowed
988 if not self.check_perm(req, 'push', False):
999 if not self.check_perm(req, 'push', False):
989 bail(_('push not authorized\n'),
1000 bail(_('push not authorized\n'),
990 headers={'status': '401 Unauthorized'})
1001 headers={'status': '401 Unauthorized'})
991 return
1002 return
992
1003
993 req.httphdr("application/mercurial-0.1")
1004 req.httphdr("application/mercurial-0.1")
994
1005
995 their_heads = req.form['heads'][0].split(' ')
1006 their_heads = req.form['heads'][0].split(' ')
996
1007
997 def check_heads():
1008 def check_heads():
998 heads = map(hex, self.repo.heads())
1009 heads = map(hex, self.repo.heads())
999 return their_heads == [hex('force')] or their_heads == heads
1010 return their_heads == [hex('force')] or their_heads == heads
1000
1011
1001 # fail early if possible
1012 # fail early if possible
1002 if not check_heads():
1013 if not check_heads():
1003 bail(_('unsynced changes\n'))
1014 bail(_('unsynced changes\n'))
1004 return
1015 return
1005
1016
1006 # do not lock repo until all changegroup data is
1017 # do not lock repo until all changegroup data is
1007 # streamed. save to temporary file.
1018 # streamed. save to temporary file.
1008
1019
1009 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
1020 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
1010 fp = os.fdopen(fd, 'wb+')
1021 fp = os.fdopen(fd, 'wb+')
1011 try:
1022 try:
1012 length = int(req.env['CONTENT_LENGTH'])
1023 length = int(req.env['CONTENT_LENGTH'])
1013 for s in util.filechunkiter(req, limit=length):
1024 for s in util.filechunkiter(req, limit=length):
1014 fp.write(s)
1025 fp.write(s)
1015
1026
1016 lock = self.repo.lock()
1027 lock = self.repo.lock()
1017 try:
1028 try:
1018 if not check_heads():
1029 if not check_heads():
1019 req.write('0\n')
1030 req.write('0\n')
1020 req.write(_('unsynced changes\n'))
1031 req.write(_('unsynced changes\n'))
1021 return
1032 return
1022
1033
1023 fp.seek(0)
1034 fp.seek(0)
1024
1035
1025 # send addchangegroup output to client
1036 # send addchangegroup output to client
1026
1037
1027 old_stdout = sys.stdout
1038 old_stdout = sys.stdout
1028 sys.stdout = cStringIO.StringIO()
1039 sys.stdout = cStringIO.StringIO()
1029
1040
1030 try:
1041 try:
1031 url = 'remote:%s:%s' % (proto,
1042 url = 'remote:%s:%s' % (proto,
1032 req.env.get('REMOTE_HOST', ''))
1043 req.env.get('REMOTE_HOST', ''))
1033 ret = self.repo.addchangegroup(fp, 'serve', url)
1044 ret = self.repo.addchangegroup(fp, 'serve', url)
1034 finally:
1045 finally:
1035 val = sys.stdout.getvalue()
1046 val = sys.stdout.getvalue()
1036 sys.stdout = old_stdout
1047 sys.stdout = old_stdout
1037 req.write('%d\n' % ret)
1048 req.write('%d\n' % ret)
1038 req.write(val)
1049 req.write(val)
1039 finally:
1050 finally:
1040 lock.release()
1051 lock.release()
1041 finally:
1052 finally:
1042 fp.close()
1053 fp.close()
1043 os.unlink(tempname)
1054 os.unlink(tempname)
1044
1055
1045 def do_stream_out(self, req):
1056 def do_stream_out(self, req):
1046 req.httphdr("application/mercurial-0.1")
1057 req.httphdr("application/mercurial-0.1")
1047 streamclone.stream_out(self.repo, req)
1058 streamclone.stream_out(self.repo, req)
@@ -1,36 +1,38 b''
1 #header#
1 #header#
2 <title>#repo|escape#: changelog</title>
2 <title>#repo|escape#: changelog</title>
3 <link rel="alternate" type="application/rss+xml"
3 <link rel="alternate" type="application/rss+xml"
4 href="#url#rss-log" title="RSS feed for #repo|escape#">
4 href="#url#rss-log" title="RSS feed for #repo|escape#">
5 </head>
5 </head>
6 <body>
6 <body>
7
7
8 <div class="buttons">
8 <div class="buttons">
9 <a href="#url#shortlog/#rev#{getentries}">shortlog</a>
9 <a href="#url#shortlog/#rev#{getentries}">shortlog</a>
10 <a href="#url#tags{getentries}">tags</a>
10 <a href="#url#tags{getentries}">tags</a>
11 <a href="#url#file/#node|short#{getentries}">manifest</a>
11 <a href="#url#file/#node|short#{getentries}">manifest</a>
12 #archives%archiveentry#
12 #archives%archiveentry#
13 <a type="application/rss+xml" href="#url#rss-log">rss</a>
13 <a type="application/rss+xml" href="#url#rss-log">rss</a>
14 </div>
14 </div>
15
15
16 <h2>changelog for #repo|escape#</h2>
16 <h2>changelog for #repo|escape#</h2>
17
17
18 <form action="#url#log">
18 <form action="#url#log">
19 {sessionvars%hiddenformentry}
19 <p>
20 <p>
20 <label for="search1">search:</label>
21 <label for="search1">search:</label>
21 <input name="rev" id="search1" type="text" size="30">
22 <input name="rev" id="search1" type="text" size="30">
22 navigate: <small class="navigate">#changenav%naventry#</small>
23 navigate: <small class="navigate">#changenav%naventry#</small>
23 </p>
24 </p>
24 </form>
25 </form>
25
26
26 #entries%changelogentry#
27 #entries%changelogentry#
27
28
28 <form action="#url#log">
29 <form action="#url#log">
30 {sessionvars%hiddenformentry}
29 <p>
31 <p>
30 <label for="search2">search:</label>
32 <label for="search2">search:</label>
31 <input name="rev" id="search2" type="text" size="30">
33 <input name="rev" id="search2" type="text" size="30">
32 navigate: <small class="navigate">#changenav%naventry#</small>
34 navigate: <small class="navigate">#changenav%naventry#</small>
33 </p>
35 </p>
34 </form>
36 </form>
35
37
36 #footer#
38 #footer#
@@ -1,32 +1,32 b''
1 #header#
1 #header#
2 <title>#repo|escape#: Changelog</title>
2 <title>#repo|escape#: Changelog</title>
3 <link rel="alternate" type="application/rss+xml"
3 <link rel="alternate" type="application/rss+xml"
4 href="{url}rss-log" title="RSS feed for #repo|escape#">
4 href="{url}rss-log" title="RSS feed for #repo|escape#">
5 </head>
5 </head>
6 <body>
6 <body>
7
7
8 <div class="page_header">
8 <div class="page_header">
9 <a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{getentries}">#repo|escape#</a> / changelog
9 <a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{getentries}">#repo|escape#</a> / changelog
10 </div>
10 </div>
11
11
12 <form action="{url}log">
12 <form action="{url}log">
13 {sessionvars%hiddenformentry}
13 <div class="search">
14 <div class="search">
14 <input type="hidden" name="style" value="gitweb" />
15 <input type="text" name="rev" />
15 <input type="text" name="rev" />
16 </div>
16 </div>
17 </form>
17 </form>
18 </div>
18 </div>
19
19
20 <div class="page_nav">
20 <div class="page_nav">
21 <a href="{url}summary{getentries}">summary</a> | <a href="{url}shortlog/#rev#{getentries}">shortlog</a> | changelog | <a href="{url}tags{getentries}">tags</a> | <a href="{url}file/#node|short#{getentries}">manifest</a>#archives%archiveentry#<br/>
21 <a href="{url}summary{getentries}">summary</a> | <a href="{url}shortlog/#rev#{getentries}">shortlog</a> | changelog | <a href="{url}tags{getentries}">tags</a> | <a href="{url}file/#node|short#{getentries}">manifest</a>#archives%archiveentry#<br/>
22 <br/>
22 <br/>
23 #changenav%naventry#<br/>
23 #changenav%naventry#<br/>
24 </div>
24 </div>
25
25
26 #entries%changelogentry#
26 #entries%changelogentry#
27
27
28 <div class="page_nav">
28 <div class="page_nav">
29 #changenav%naventry#<br/>
29 #changenav%naventry#<br/>
30 </div>
30 </div>
31
31
32 #footer#
32 #footer#
@@ -1,53 +1,54 b''
1 default = 'summary'
1 default = 'summary'
2 header = header.tmpl
2 header = header.tmpl
3 footer = footer.tmpl
3 footer = footer.tmpl
4 search = search.tmpl
4 search = search.tmpl
5 changelog = changelog.tmpl
5 changelog = changelog.tmpl
6 summary = summary.tmpl
6 summary = summary.tmpl
7 error = error.tmpl
7 error = error.tmpl
8 naventry = '<a href="#url#log/#rev#{getentries}">#label|escape#</a> '
8 naventry = '<a href="#url#log/#rev#{getentries}">#label|escape#</a> '
9 navshortentry = '<a href="#url#shortlog/#rev#{getentries}">#label|escape#</a> '
9 navshortentry = '<a href="#url#shortlog/#rev#{getentries}">#label|escape#</a> '
10 filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{getentries}">#file|escape#</a> '
10 filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{getentries}">#file|escape#</a> '
11 filenodelink = '<tr class="parity#parity#"><td><a class="list" href="{url}diff/{node|short}/{file|urlescape}{getentries}">#file|escape#</a></td><td></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{getentries}">file</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">annotate</a> | <a href="#url#diff/#node|short#/#file|urlescape#{getentries}">diff</a> | <a href="#url#log/#node|short#/#file|urlescape#{getentries}">revisions</a></td></tr>'
11 filenodelink = '<tr class="parity#parity#"><td><a class="list" href="{url}diff/{node|short}/{file|urlescape}{getentries}">#file|escape#</a></td><td></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{getentries}">file</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">annotate</a> | <a href="#url#diff/#node|short#/#file|urlescape#{getentries}">diff</a> | <a href="#url#log/#node|short#/#file|urlescape#{getentries}">revisions</a></td></tr>'
12 fileellipses = '...'
12 fileellipses = '...'
13 changelogentry = changelogentry.tmpl
13 changelogentry = changelogentry.tmpl
14 searchentry = changelogentry.tmpl
14 searchentry = changelogentry.tmpl
15 changeset = changeset.tmpl
15 changeset = changeset.tmpl
16 manifest = manifest.tmpl
16 manifest = manifest.tmpl
17 manifestdirentry = '<tr class="parity#parity#"><td style="font-family:monospace">drwxr-xr-x</td><td style="font-family:monospace"></td><td><a href="#url#file/#node|short##path|urlescape#{getentries}">#basename|escape#/</a></td><td class="link"><a href="#url#file/#node|short##path|urlescape#{getentries}">manifest</a></td></tr>'
17 manifestdirentry = '<tr class="parity#parity#"><td style="font-family:monospace">drwxr-xr-x</td><td style="font-family:monospace"></td><td><a href="#url#file/#node|short##path|urlescape#{getentries}">#basename|escape#/</a></td><td class="link"><a href="#url#file/#node|short##path|urlescape#{getentries}">manifest</a></td></tr>'
18 manifestfileentry = '<tr class="parity#parity#"><td style="font-family:monospace">#permissions|permissions#</td><td style="font-family:monospace" align=right>#size#</td><td class="list"><a class="list" href="#url#file/#node|short#/#file|urlescape#{getentries}">#basename|escape#</a></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{getentries}">file</a> | <a href="#url#log/#node|short#/#file|urlescape#{getentries}">revisions</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">annotate</a></td></tr>'
18 manifestfileentry = '<tr class="parity#parity#"><td style="font-family:monospace">#permissions|permissions#</td><td style="font-family:monospace" align=right>#size#</td><td class="list"><a class="list" href="#url#file/#node|short#/#file|urlescape#{getentries}">#basename|escape#</a></td><td class="link"><a href="#url#file/#node|short#/#file|urlescape#{getentries}">file</a> | <a href="#url#log/#node|short#/#file|urlescape#{getentries}">revisions</a> | <a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">annotate</a></td></tr>'
19 filerevision = filerevision.tmpl
19 filerevision = filerevision.tmpl
20 fileannotate = fileannotate.tmpl
20 fileannotate = fileannotate.tmpl
21 filediff = filediff.tmpl
21 filediff = filediff.tmpl
22 filelog = filelog.tmpl
22 filelog = filelog.tmpl
23 fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><span class="linenr"> #linenumber#</span> #line|escape#</pre></div>'
23 fileline = '<div style="font-family:monospace" class="parity#parity#"><pre><span class="linenr"> #linenumber#</span> #line|escape#</pre></div>'
24 annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
24 annotateline = '<tr style="font-family:monospace" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
25 difflineplus = '<div style="color:#008800;">#line|escape#</div>'
25 difflineplus = '<div style="color:#008800;">#line|escape#</div>'
26 difflineminus = '<div style="color:#cc0000;">#line|escape#</div>'
26 difflineminus = '<div style="color:#cc0000;">#line|escape#</div>'
27 difflineat = '<div style="color:#990099;">#line|escape#</div>'
27 difflineat = '<div style="color:#990099;">#line|escape#</div>'
28 diffline = '<div>#line|escape#</div>'
28 diffline = '<div>#line|escape#</div>'
29 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
29 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
30 changesetparent = '<tr><td>parent</td><td style="font-family:monospace"><a class="list" href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
30 changesetparent = '<tr><td>parent</td><td style="font-family:monospace"><a class="list" href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
31 filerevparent = '<tr><td class="metatag">parent:</td><td><a href="{url}file/{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
31 filerevparent = '<tr><td class="metatag">parent:</td><td><a href="{url}file/{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
32 filerename = '<tr><td class="metatag">parent:</td><td><a href="{url}file/#node|short#/#file|urlescape#{getentries}">#file|escape#@#node|short#</a></td></tr>'
32 filerename = '<tr><td class="metatag">parent:</td><td><a href="{url}file/#node|short#/#file|urlescape#{getentries}">#file|escape#@#node|short#</a></td></tr>'
33 filelogrename = '| <a href="{url}file/#node|short#/#file|urlescape#{getentries}">base</a>'
33 filelogrename = '| <a href="{url}file/#node|short#/#file|urlescape#{getentries}">base</a>'
34 fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="{url}annotate/{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
34 fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="{url}annotate/{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
35 changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{getentries}">#node|short#</a></td></tr>'
35 changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{getentries}">#node|short#</a></td></tr>'
36 changesetchild = '<tr><td>child</td><td style="font-family:monospace"><a class="list" href="{url}rev/#node|short#{getentries}">#node|short#</a></td></tr>'
36 changesetchild = '<tr><td>child</td><td style="font-family:monospace"><a class="list" href="{url}rev/#node|short#{getentries}">#node|short#</a></td></tr>'
37 filerevchild = '<tr><td class="metatag">child:</td><td><a href="{url}file/{node|short}#file|urlescape#{getentries}">#node|short#</a></td></tr>'
37 filerevchild = '<tr><td class="metatag">child:</td><td><a href="{url}file/{node|short}#file|urlescape#{getentries}">#node|short#</a></td></tr>'
38 fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="{url}annotate/{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
38 fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="{url}annotate/{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
39 tags = tags.tmpl
39 tags = tags.tmpl
40 tagentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/{node|short}{getentries}"><b>#tag|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{getentries}">changeset</a> | <a href="{url}log/#node|short#{getentries}">changelog</a> | <a href="{url}file/#node|short#{getentries}">manifest</a></td></tr>'
40 tagentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/{node|short}{getentries}"><b>#tag|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{getentries}">changeset</a> | <a href="{url}log/#node|short#{getentries}">changelog</a> | <a href="{url}file/#node|short#{getentries}">manifest</a></td></tr>'
41 diffblock = '<pre>#lines#</pre>'
41 diffblock = '<pre>#lines#</pre>'
42 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
42 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
43 changesettag = '<tr><td>tag</td><td>#tag|escape#</td></tr>'
43 changesettag = '<tr><td>tag</td><td>#tag|escape#</td></tr>'
44 filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="{url}rev/#node|short#{getentries}">#node|short#</a></td></tr>'
44 filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="{url}rev/#node|short#{getentries}">#node|short#</a></td></tr>'
45 filelogparent = '<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="{url}file/{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
45 filelogparent = '<tr><td align="right">parent #rev#:&nbsp;</td><td><a href="{url}file/{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
46 filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{getentries}">#node|short#</a></td></tr>'
46 filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="{url}rev/#node|short#{getentries}">#node|short#</a></td></tr>'
47 filelogchild = '<tr><td align="right">child #rev#:&nbsp;</td><td><a href="{url}file{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
47 filelogchild = '<tr><td align="right">child #rev#:&nbsp;</td><td><a href="{url}file{node|short}/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
48 shortlog = shortlog.tmpl
48 shortlog = shortlog.tmpl
49 shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{getentries}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{getentries}">changeset</a> | <a href="{url}file/#node|short#{getentries}">manifest</a></td></tr>'
49 shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{getentries}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}rev/#node|short#{getentries}">changeset</a> | <a href="{url}file/#node|short#{getentries}">manifest</a></td></tr>'
50 filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{getentries}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{getentries}">file</a> | <!-- FIXME: <a href="{url}diff/#node|short#/#file|urlescape#{getentries}">diff</a> | --> <a href="{url}annotate/#node|short#/#file|urlescape#{getentries}">annotate</a> #rename%filelogrename#</td></tr>'
50 filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{getentries}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{getentries}">file</a> | <!-- FIXME: <a href="{url}diff/#node|short#/#file|urlescape#{getentries}">diff</a> | --> <a href="{url}annotate/#node|short#/#file|urlescape#{getentries}">annotate</a> #rename%filelogrename#</td></tr>'
51 archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
51 archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
52 indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
52 indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
53 index = index.tmpl
53 index = index.tmpl
54 hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
@@ -1,26 +1,27 b''
1 #header#
1 #header#
2 <div class="page_nav">
2 <div class="page_nav">
3 <a href="{url}summary{getentries}">summary</a> |
3 <a href="{url}summary{getentries}">summary</a> |
4 <a href="{url}shortlog{getentries}">shortlog</a> |
4 <a href="{url}shortlog{getentries}">shortlog</a> |
5 <a href="{url}log{getentries}">changelog</a> |
5 <a href="{url}log{getentries}">changelog</a> |
6 <a href="{url}tags{getentries}">tags</a> |
6 <a href="{url}tags{getentries}">tags</a> |
7 <a href="{url}file/#node|short#{getentries}">manifest</a><br/>
7 <a href="{url}file/#node|short#{getentries}">manifest</a><br/>
8 </div>
8 </div>
9
9
10 <h2>searching for #query|escape#</h2>
10 <h2>searching for #query|escape#</h2>
11
11
12 <form action="{url}log">
12 <form action="{url}log">
13 {sessionvars%hiddenformentry}
13 search:
14 search:
14 <input type="hidden" name="style" value="gitweb">
15 <input name="rev" type="text" width="30" value="#query|escape#">
15 <input name="rev" type="text" width="30" value="#query|escape#">
16 </form>
16 </form>
17
17
18 #entries#
18 #entries#
19
19
20 <form action="{url}log">
20 <form action="{url}log">
21 {sessionvars%hiddenformentry}
21 search:
22 search:
22 <input type="hidden" name="style" value="gitweb">
23 <input type="hidden" name="style" value="gitweb">
23 <input name="rev" type="text" width="30">
24 <input name="rev" type="text" width="30">
24 </form>
25 </form>
25
26
26 #footer#
27 #footer#
@@ -1,34 +1,34 b''
1 #header#
1 #header#
2 <title>#repo|escape#: Shortlog</title>
2 <title>#repo|escape#: Shortlog</title>
3 <link rel="alternate" type="application/rss+xml"
3 <link rel="alternate" type="application/rss+xml"
4 href="{url}rss-log" title="RSS feed for #repo|escape#">
4 href="{url}rss-log" title="RSS feed for #repo|escape#">
5 </head>
5 </head>
6 <body>
6 <body>
7
7
8 <div class="page_header">
8 <div class="page_header">
9 <a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{getentries}">#repo|escape#</a> / shortlog
9 <a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="{url}summary{getentries}">#repo|escape#</a> / shortlog
10 </div>
10 </div>
11
11
12 <form action="{url}log">
12 <form action="{url}log">
13 {sessionvars%hiddenformentry}
13 <div class="search">
14 <div class="search">
14 <input type="hidden" name="style" value="gitweb" />
15 <input type="text" name="rev" />
15 <input type="text" name="rev" />
16 </div>
16 </div>
17 </form>
17 </form>
18 </div>
18 </div>
19 <div class="page_nav">
19 <div class="page_nav">
20 <a href="{url}summary{getentries}">summary</a> |
20 <a href="{url}summary{getentries}">summary</a> |
21 shortlog |
21 shortlog |
22 <a href="{url}log/#rev#{getentries}">changelog</a> |
22 <a href="{url}log/#rev#{getentries}">changelog</a> |
23 <a href="{url}tags{getentries}">tags</a> |
23 <a href="{url}tags{getentries}">tags</a> |
24 <a href="{url}file/#node|short#{getentries}">manifest</a>#archives%archiveentry#<br/>
24 <a href="{url}file/#node|short#{getentries}">manifest</a>#archives%archiveentry#<br/>
25 <br/>
25 <br/>
26
26
27 #changenav%navshortentry#<br/>
27 #changenav%navshortentry#<br/>
28 </div>
28 </div>
29
29
30 <table cellspacing="0">
30 <table cellspacing="0">
31 #entries%shortlogentry#
31 #entries%shortlogentry#
32 </table>
32 </table>
33
33
34 #footer#
34 #footer#
@@ -1,53 +1,54 b''
1 default = 'changelog'
1 default = 'changelog'
2 header = header.tmpl
2 header = header.tmpl
3 footer = footer.tmpl
3 footer = footer.tmpl
4 search = search.tmpl
4 search = search.tmpl
5 changelog = changelog.tmpl
5 changelog = changelog.tmpl
6 shortlog = shortlog.tmpl
6 shortlog = shortlog.tmpl
7 shortlogentry = shortlogentry.tmpl
7 shortlogentry = shortlogentry.tmpl
8 naventry = '<a href="#url#log/#rev#{getentries}">#label|escape#</a> '
8 naventry = '<a href="#url#log/#rev#{getentries}">#label|escape#</a> '
9 navshortentry = '<a href="#url#shortlog/#rev#{getentries}">#label|escape#</a> '
9 navshortentry = '<a href="#url#shortlog/#rev#{getentries}">#label|escape#</a> '
10 filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{getentries}">#file|escape#</a> '
10 filedifflink = '<a href="#url#diff/#node|short#/#file|urlescape#{getentries}">#file|escape#</a> '
11 filenodelink = '<a href="#url#file/#node|short#/#file|urlescape#{getentries}">#file|escape#</a> '
11 filenodelink = '<a href="#url#file/#node|short#/#file|urlescape#{getentries}">#file|escape#</a> '
12 fileellipses = '...'
12 fileellipses = '...'
13 changelogentry = changelogentry.tmpl
13 changelogentry = changelogentry.tmpl
14 searchentry = changelogentry.tmpl
14 searchentry = changelogentry.tmpl
15 changeset = changeset.tmpl
15 changeset = changeset.tmpl
16 manifest = manifest.tmpl
16 manifest = manifest.tmpl
17 manifestdirentry = '<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td>&nbsp;<td><a href="#url#file/#node|short##path|urlescape#{getentries}">#basename|escape#/</a>'
17 manifestdirentry = '<tr class="parity#parity#"><td><tt>drwxr-xr-x</tt>&nbsp;<td>&nbsp;<td><a href="#url#file/#node|short##path|urlescape#{getentries}">#basename|escape#/</a>'
18 manifestfileentry = '<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td align=right><tt>#size#</tt>&nbsp;<td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#basename|escape#</a>'
18 manifestfileentry = '<tr class="parity#parity#"><td><tt>#permissions|permissions#</tt>&nbsp;<td align=right><tt>#size#</tt>&nbsp;<td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#basename|escape#</a>'
19 filerevision = filerevision.tmpl
19 filerevision = filerevision.tmpl
20 fileannotate = fileannotate.tmpl
20 fileannotate = fileannotate.tmpl
21 filediff = filediff.tmpl
21 filediff = filediff.tmpl
22 filelog = filelog.tmpl
22 filelog = filelog.tmpl
23 fileline = '<div class="parity#parity#"><span class="lineno">#linenumber#</span>#line|escape#</div>'
23 fileline = '<div class="parity#parity#"><span class="lineno">#linenumber#</span>#line|escape#</div>'
24 filelogentry = filelogentry.tmpl
24 filelogentry = filelogentry.tmpl
25 annotateline = '<tr class="parity#parity#"><td class="annotate"><a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
25 annotateline = '<tr class="parity#parity#"><td class="annotate"><a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">#author|obfuscate#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>'
26 difflineplus = '<span class="plusline">#line|escape#</span>'
26 difflineplus = '<span class="plusline">#line|escape#</span>'
27 difflineminus = '<span class="minusline">#line|escape#</span>'
27 difflineminus = '<span class="minusline">#line|escape#</span>'
28 difflineat = '<span class="atline">#line|escape#</span>'
28 difflineat = '<span class="atline">#line|escape#</span>'
29 diffline = '#line|escape#'
29 diffline = '#line|escape#'
30 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
30 changelogparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
31 changesetparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
31 changesetparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
32 filerevparent = '<tr><td class="metatag">parent:</td><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
32 filerevparent = '<tr><td class="metatag">parent:</td><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
33 filerename = '<tr><td class="metatag">parent:</td><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#file|escape#@#node|short#</a></td></tr>'
33 filerename = '<tr><td class="metatag">parent:</td><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#file|escape#@#node|short#</a></td></tr>'
34 filelogrename = '<tr><th>base:</th><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#file|escape#@#node|short#</a></td></tr>'
34 filelogrename = '<tr><th>base:</th><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#file|escape#@#node|short#</a></td></tr>'
35 fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
35 fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
36 changesetchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
36 changesetchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
37 changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
37 changelogchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
38 filerevchild = '<tr><td class="metatag">child:</td><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
38 filerevchild = '<tr><td class="metatag">child:</td><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
39 fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
39 fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="#url#annotate/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
40 tags = tags.tmpl
40 tags = tags.tmpl
41 tagentry = '<li class="tagEntry parity#parity#"><tt class="node">#node#</tt> <a href="#url#rev/#node|short#{getentries}">#tag|escape#</a></li>'
41 tagentry = '<li class="tagEntry parity#parity#"><tt class="node">#node#</tt> <a href="#url#rev/#node|short#{getentries}">#tag|escape#</a></li>'
42 diffblock = '<pre class="parity#parity#">#lines#</pre>'
42 diffblock = '<pre class="parity#parity#">#lines#</pre>'
43 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
43 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
44 changesettag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
44 changesettag = '<tr><th class="tag">tag:</th><td class="tag">#tag|escape#</td></tr>'
45 filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
45 filediffparent = '<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
46 filelogparent = '<tr><th>parent #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
46 filelogparent = '<tr><th>parent #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
47 filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
47 filediffchild = '<tr><th class="child">child #rev#:</th><td class="child"><a href="#url#rev/#node|short#{getentries}">#node|short#</a></td></tr>'
48 filelogchild = '<tr><th>child #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
48 filelogchild = '<tr><th>child #rev#:</th><td><a href="#url#file/#node|short#/#file|urlescape#{getentries}">#node|short#</a></td></tr>'
49 indexentry = '<tr class="parity#parity#"><td><a href="#url#">#name|escape#</a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
49 indexentry = '<tr class="parity#parity#"><td><a href="#url#">#name|escape#</a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
50 index = index.tmpl
50 index = index.tmpl
51 archiveentry = '<a href="#url#archive/#node|short##extension|urlescape#">#type|escape#</a> '
51 archiveentry = '<a href="#url#archive/#node|short##extension|urlescape#">#type|escape#</a> '
52 notfound = notfound.tmpl
52 notfound = notfound.tmpl
53 error = error.tmpl
53 error = error.tmpl
54 hiddenformentry = '<input type="hidden" name="#name#" value="#value|escape#" />'
@@ -1,31 +1,33 b''
1 #header#
1 #header#
2 <title>#repo|escape#: searching for #query|escape#</title>
2 <title>#repo|escape#: searching for #query|escape#</title>
3 </head>
3 </head>
4 <body>
4 <body>
5
5
6 <div class="buttons">
6 <div class="buttons">
7 <a href="#url#log{getentries}">changelog</a>
7 <a href="#url#log{getentries}">changelog</a>
8 <a href="#url#shortlog{getentries}">shortlog</a>
8 <a href="#url#shortlog{getentries}">shortlog</a>
9 <a href="#url#tags{getentries}">tags</a>
9 <a href="#url#tags{getentries}">tags</a>
10 <a href="#url#file/#node|short#{getentries}">manifest</a>
10 <a href="#url#file/#node|short#{getentries}">manifest</a>
11 </div>
11 </div>
12
12
13 <h2>searching for #query|escape#</h2>
13 <h2>searching for #query|escape#</h2>
14
14
15 <form>
15 <form>
16 {sessionvars%hiddenformentry}
16 <p>
17 <p>
17 search:
18 search:
18 <input name="rev" type="text" width="30" value="#query|escape#">
19 <input name="rev" type="text" width="30" value="#query|escape#">
19 </p>
20 </p>
20 </form>
21 </form>
21
22
22 #entries#
23 #entries#
23
24
24 <form>
25 <form>
26 {sessionvars%hiddenformentry}
25 <p>
27 <p>
26 search:
28 search:
27 <input name="rev" type="text" width="30" value="#query|escape#">
29 <input name="rev" type="text" width="30" value="#query|escape#">
28 </p>
30 </p>
29 </form>
31 </form>
30
32
31 #footer#
33 #footer#
@@ -1,36 +1,38 b''
1 #header#
1 #header#
2 <title>#repo|escape#: shortlog</title>
2 <title>#repo|escape#: shortlog</title>
3 <link rel="alternate" type="application/rss+xml"
3 <link rel="alternate" type="application/rss+xml"
4 href="#url#rss-log" title="RSS feed for #repo|escape#">
4 href="#url#rss-log" title="RSS feed for #repo|escape#">
5 </head>
5 </head>
6 <body>
6 <body>
7
7
8 <div class="buttons">
8 <div class="buttons">
9 <a href="#url#log/#rev#{getentries}">changelog</a>
9 <a href="#url#log/#rev#{getentries}">changelog</a>
10 <a href="#url#tags{getentries}">tags</a>
10 <a href="#url#tags{getentries}">tags</a>
11 <a href="#url#file/#node|short#/{getentries}">manifest</a>
11 <a href="#url#file/#node|short#/{getentries}">manifest</a>
12 #archives%archiveentry#
12 #archives%archiveentry#
13 <a type="application/rss+xml" href="#url#rss-log">rss</a>
13 <a type="application/rss+xml" href="#url#rss-log">rss</a>
14 </div>
14 </div>
15
15
16 <h2>shortlog for #repo|escape#</h2>
16 <h2>shortlog for #repo|escape#</h2>
17
17
18 <form action="#url#log">
18 <form action="#url#log">
19 {sessionvars%hiddenformentry}
19 <p>
20 <p>
20 <label for="search1">search:</label>
21 <label for="search1">search:</label>
21 <input name="rev" id="search1" type="text" size="30">
22 <input name="rev" id="search1" type="text" size="30">
22 navigate: <small class="navigate">#changenav%navshortentry#</small>
23 navigate: <small class="navigate">#changenav%navshortentry#</small>
23 </p>
24 </p>
24 </form>
25 </form>
25
26
26 #entries%shortlogentry#
27 #entries%shortlogentry#
27
28
28 <form action="#url#log">
29 <form action="#url#log">
30 {sessionvars%hiddenformentry}
29 <p>
31 <p>
30 <label for="search2">search:</label>
32 <label for="search2">search:</label>
31 <input name="rev" id="search2" type="text" size="30">
33 <input name="rev" id="search2" type="text" size="30">
32 navigate: <small class="navigate">#changenav%navshortentry#</small>
34 navigate: <small class="navigate">#changenav%navshortentry#</small>
33 </p>
35 </p>
34 </form>
36 </form>
35
37
36 #footer#
38 #footer#
General Comments 0
You need to be logged in to leave comments. Login now