##// END OF EJS Templates
hgweb: add less/more links for search logs (issue1972)
Dirkjan Ochtman -
r10247:e8c74103 default
parent child Browse files
Show More
@@ -1,715 +1,727 b''
1 #
1 #
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 import os, mimetypes, re, cgi, copy
8 import os, mimetypes, re, cgi, copy
9 import webutil
9 import webutil
10 from mercurial import error, archival, templater, templatefilters
10 from mercurial import error, archival, templater, templatefilters
11 from mercurial.node import short, hex
11 from mercurial.node import short, hex
12 from mercurial.util import binary
12 from mercurial.util import binary
13 from common import paritygen, staticfile, get_contact, ErrorResponse
13 from common import paritygen, staticfile, get_contact, ErrorResponse
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
15 from mercurial import graphmod
15 from mercurial import graphmod
16
16
17 # __all__ is populated with the allowed commands. Be sure to add to it if
17 # __all__ is populated with the allowed commands. Be sure to add to it if
18 # you're adding a new command, or the new command won't work.
18 # you're adding a new command, or the new command won't work.
19
19
20 __all__ = [
20 __all__ = [
21 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
21 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
22 'manifest', 'tags', 'branches', 'summary', 'filediff', 'diff', 'annotate',
22 'manifest', 'tags', 'branches', 'summary', 'filediff', 'diff', 'annotate',
23 'filelog', 'archive', 'static', 'graph',
23 'filelog', 'archive', 'static', 'graph',
24 ]
24 ]
25
25
26 def log(web, req, tmpl):
26 def log(web, req, tmpl):
27 if 'file' in req.form and req.form['file'][0]:
27 if 'file' in req.form and req.form['file'][0]:
28 return filelog(web, req, tmpl)
28 return filelog(web, req, tmpl)
29 else:
29 else:
30 return changelog(web, req, tmpl)
30 return changelog(web, req, tmpl)
31
31
32 def rawfile(web, req, tmpl):
32 def rawfile(web, req, tmpl):
33 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
33 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
34 if not path:
34 if not path:
35 content = manifest(web, req, tmpl)
35 content = manifest(web, req, tmpl)
36 req.respond(HTTP_OK, web.ctype)
36 req.respond(HTTP_OK, web.ctype)
37 return content
37 return content
38
38
39 try:
39 try:
40 fctx = webutil.filectx(web.repo, req)
40 fctx = webutil.filectx(web.repo, req)
41 except error.LookupError, inst:
41 except error.LookupError, inst:
42 try:
42 try:
43 content = manifest(web, req, tmpl)
43 content = manifest(web, req, tmpl)
44 req.respond(HTTP_OK, web.ctype)
44 req.respond(HTTP_OK, web.ctype)
45 return content
45 return content
46 except ErrorResponse:
46 except ErrorResponse:
47 raise inst
47 raise inst
48
48
49 path = fctx.path()
49 path = fctx.path()
50 text = fctx.data()
50 text = fctx.data()
51 mt = mimetypes.guess_type(path)[0]
51 mt = mimetypes.guess_type(path)[0]
52 if mt is None:
52 if mt is None:
53 mt = binary(text) and 'application/octet-stream' or 'text/plain'
53 mt = binary(text) and 'application/octet-stream' or 'text/plain'
54
54
55 req.respond(HTTP_OK, mt, path, len(text))
55 req.respond(HTTP_OK, mt, path, len(text))
56 return [text]
56 return [text]
57
57
58 def _filerevision(web, tmpl, fctx):
58 def _filerevision(web, tmpl, fctx):
59 f = fctx.path()
59 f = fctx.path()
60 text = fctx.data()
60 text = fctx.data()
61 parity = paritygen(web.stripecount)
61 parity = paritygen(web.stripecount)
62
62
63 if binary(text):
63 if binary(text):
64 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
64 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
65 text = '(binary:%s)' % mt
65 text = '(binary:%s)' % mt
66
66
67 def lines():
67 def lines():
68 for lineno, t in enumerate(text.splitlines(True)):
68 for lineno, t in enumerate(text.splitlines(True)):
69 yield {"line": t,
69 yield {"line": t,
70 "lineid": "l%d" % (lineno + 1),
70 "lineid": "l%d" % (lineno + 1),
71 "linenumber": "% 6d" % (lineno + 1),
71 "linenumber": "% 6d" % (lineno + 1),
72 "parity": parity.next()}
72 "parity": parity.next()}
73
73
74 return tmpl("filerevision",
74 return tmpl("filerevision",
75 file=f,
75 file=f,
76 path=webutil.up(f),
76 path=webutil.up(f),
77 text=lines(),
77 text=lines(),
78 rev=fctx.rev(),
78 rev=fctx.rev(),
79 node=hex(fctx.node()),
79 node=hex(fctx.node()),
80 author=fctx.user(),
80 author=fctx.user(),
81 date=fctx.date(),
81 date=fctx.date(),
82 desc=fctx.description(),
82 desc=fctx.description(),
83 branch=webutil.nodebranchnodefault(fctx),
83 branch=webutil.nodebranchnodefault(fctx),
84 parent=webutil.parents(fctx),
84 parent=webutil.parents(fctx),
85 child=webutil.children(fctx),
85 child=webutil.children(fctx),
86 rename=webutil.renamelink(fctx),
86 rename=webutil.renamelink(fctx),
87 permissions=fctx.manifest().flags(f))
87 permissions=fctx.manifest().flags(f))
88
88
89 def file(web, req, tmpl):
89 def file(web, req, tmpl):
90 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
90 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
91 if not path:
91 if not path:
92 return manifest(web, req, tmpl)
92 return manifest(web, req, tmpl)
93 try:
93 try:
94 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
94 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
95 except error.LookupError, inst:
95 except error.LookupError, inst:
96 try:
96 try:
97 return manifest(web, req, tmpl)
97 return manifest(web, req, tmpl)
98 except ErrorResponse:
98 except ErrorResponse:
99 raise inst
99 raise inst
100
100
101 def _search(web, tmpl, query):
101 def _search(web, req, tmpl):
102
103 query = req.form['rev'][0]
104 revcount = web.maxchanges
105 if 'revcount' in req.form:
106 revcount = int(req.form.get('revcount', [revcount])[0])
107 tmpl.defaults['sessionvars']['revcount'] = revcount
108
109 lessvars = copy.copy(tmpl.defaults['sessionvars'])
110 lessvars['revcount'] = revcount / 2
111 lessvars['rev'] = query
112 morevars = copy.copy(tmpl.defaults['sessionvars'])
113 morevars['revcount'] = revcount * 2
114 morevars['rev'] = query
102
115
103 def changelist(**map):
116 def changelist(**map):
104 cl = web.repo.changelog
117 cl = web.repo.changelog
105 count = 0
118 count = 0
106 qw = query.lower().split()
119 qw = query.lower().split()
107
120
108 def revgen():
121 def revgen():
109 for i in xrange(len(cl) - 1, 0, -100):
122 for i in xrange(len(cl) - 1, 0, -100):
110 l = []
123 l = []
111 for j in xrange(max(0, i - 100), i + 1):
124 for j in xrange(max(0, i - 100), i + 1):
112 ctx = web.repo[j]
125 ctx = web.repo[j]
113 l.append(ctx)
126 l.append(ctx)
114 l.reverse()
127 l.reverse()
115 for e in l:
128 for e in l:
116 yield e
129 yield e
117
130
118 for ctx in revgen():
131 for ctx in revgen():
119 miss = 0
132 miss = 0
120 for q in qw:
133 for q in qw:
121 if not (q in ctx.user().lower() or
134 if not (q in ctx.user().lower() or
122 q in ctx.description().lower() or
135 q in ctx.description().lower() or
123 q in " ".join(ctx.files()).lower()):
136 q in " ".join(ctx.files()).lower()):
124 miss = 1
137 miss = 1
125 break
138 break
126 if miss:
139 if miss:
127 continue
140 continue
128
141
129 count += 1
142 count += 1
130 n = ctx.node()
143 n = ctx.node()
131 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
144 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
132 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
145 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
133
146
134 yield tmpl('searchentry',
147 yield tmpl('searchentry',
135 parity=parity.next(),
148 parity=parity.next(),
136 author=ctx.user(),
149 author=ctx.user(),
137 parent=webutil.parents(ctx),
150 parent=webutil.parents(ctx),
138 child=webutil.children(ctx),
151 child=webutil.children(ctx),
139 changelogtag=showtags,
152 changelogtag=showtags,
140 desc=ctx.description(),
153 desc=ctx.description(),
141 date=ctx.date(),
154 date=ctx.date(),
142 files=files,
155 files=files,
143 rev=ctx.rev(),
156 rev=ctx.rev(),
144 node=hex(n),
157 node=hex(n),
145 tags=webutil.nodetagsdict(web.repo, n),
158 tags=webutil.nodetagsdict(web.repo, n),
146 inbranch=webutil.nodeinbranch(web.repo, ctx),
159 inbranch=webutil.nodeinbranch(web.repo, ctx),
147 branches=webutil.nodebranchdict(web.repo, ctx))
160 branches=webutil.nodebranchdict(web.repo, ctx))
148
161
149 if count >= web.maxchanges:
162 if count >= revcount:
150 break
163 break
151
164
152 cl = web.repo.changelog
165 cl = web.repo.changelog
153 parity = paritygen(web.stripecount)
166 parity = paritygen(web.stripecount)
154
167
155 return tmpl('search',
168 return tmpl('search', query=query, node=hex(cl.tip()),
156 query=query,
169 entries=changelist, archives=web.archivelist("tip"),
157 node=hex(cl.tip()),
170 morevars=morevars, lessvars=lessvars)
158 entries=changelist,
159 archives=web.archivelist("tip"))
160
171
161 def changelog(web, req, tmpl, shortlog = False):
172 def changelog(web, req, tmpl, shortlog=False):
173
162 if 'node' in req.form:
174 if 'node' in req.form:
163 ctx = webutil.changectx(web.repo, req)
175 ctx = webutil.changectx(web.repo, req)
164 else:
176 else:
165 if 'rev' in req.form:
177 if 'rev' in req.form:
166 hi = req.form['rev'][0]
178 hi = req.form['rev'][0]
167 else:
179 else:
168 hi = len(web.repo) - 1
180 hi = len(web.repo) - 1
169 try:
181 try:
170 ctx = web.repo[hi]
182 ctx = web.repo[hi]
171 except error.RepoError:
183 except error.RepoError:
172 return _search(web, tmpl, hi) # XXX redirect to 404 page?
184 return _search(web, req, tmpl) # XXX redirect to 404 page?
173
185
174 def changelist(limit=0, **map):
186 def changelist(limit=0, **map):
175 l = [] # build a list in forward order for efficiency
187 l = [] # build a list in forward order for efficiency
176 for i in xrange(start, end):
188 for i in xrange(start, end):
177 ctx = web.repo[i]
189 ctx = web.repo[i]
178 n = ctx.node()
190 n = ctx.node()
179 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
191 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
180 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
192 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
181
193
182 l.insert(0, {"parity": parity.next(),
194 l.insert(0, {"parity": parity.next(),
183 "author": ctx.user(),
195 "author": ctx.user(),
184 "parent": webutil.parents(ctx, i - 1),
196 "parent": webutil.parents(ctx, i - 1),
185 "child": webutil.children(ctx, i + 1),
197 "child": webutil.children(ctx, i + 1),
186 "changelogtag": showtags,
198 "changelogtag": showtags,
187 "desc": ctx.description(),
199 "desc": ctx.description(),
188 "date": ctx.date(),
200 "date": ctx.date(),
189 "files": files,
201 "files": files,
190 "rev": i,
202 "rev": i,
191 "node": hex(n),
203 "node": hex(n),
192 "tags": webutil.nodetagsdict(web.repo, n),
204 "tags": webutil.nodetagsdict(web.repo, n),
193 "inbranch": webutil.nodeinbranch(web.repo, ctx),
205 "inbranch": webutil.nodeinbranch(web.repo, ctx),
194 "branches": webutil.nodebranchdict(web.repo, ctx)
206 "branches": webutil.nodebranchdict(web.repo, ctx)
195 })
207 })
196
208
197 if limit > 0:
209 if limit > 0:
198 l = l[:limit]
210 l = l[:limit]
199
211
200 for e in l:
212 for e in l:
201 yield e
213 yield e
202
214
203 revcount = shortlog and web.maxshortchanges or web.maxchanges
215 revcount = shortlog and web.maxshortchanges or web.maxchanges
204 if 'revcount' in req.form:
216 if 'revcount' in req.form:
205 revcount = int(req.form.get('revcount', [revcount])[0])
217 revcount = int(req.form.get('revcount', [revcount])[0])
206 tmpl.defaults['sessionvars']['revcount'] = revcount
218 tmpl.defaults['sessionvars']['revcount'] = revcount
207
219
208 lessvars = copy.copy(tmpl.defaults['sessionvars'])
220 lessvars = copy.copy(tmpl.defaults['sessionvars'])
209 lessvars['revcount'] = revcount / 2
221 lessvars['revcount'] = revcount / 2
210 morevars = copy.copy(tmpl.defaults['sessionvars'])
222 morevars = copy.copy(tmpl.defaults['sessionvars'])
211 morevars['revcount'] = revcount * 2
223 morevars['revcount'] = revcount * 2
212
224
213 cl = web.repo.changelog
225 cl = web.repo.changelog
214 count = len(cl)
226 count = len(cl)
215 pos = ctx.rev()
227 pos = ctx.rev()
216 start = max(0, pos - revcount + 1)
228 start = max(0, pos - revcount + 1)
217 end = min(count, start + revcount)
229 end = min(count, start + revcount)
218 pos = end - 1
230 pos = end - 1
219 parity = paritygen(web.stripecount, offset=start-end)
231 parity = paritygen(web.stripecount, offset=start-end)
220
232
221 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
233 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
222
234
223 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
235 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
224 node=hex(ctx.node()), rev=pos, changesets=count,
236 node=hex(ctx.node()), rev=pos, changesets=count,
225 entries=lambda **x: changelist(limit=0,**x),
237 entries=lambda **x: changelist(limit=0,**x),
226 latestentry=lambda **x: changelist(limit=1,**x),
238 latestentry=lambda **x: changelist(limit=1,**x),
227 archives=web.archivelist("tip"), revcount=revcount,
239 archives=web.archivelist("tip"), revcount=revcount,
228 morevars=morevars, lessvars=lessvars)
240 morevars=morevars, lessvars=lessvars)
229
241
230 def shortlog(web, req, tmpl):
242 def shortlog(web, req, tmpl):
231 return changelog(web, req, tmpl, shortlog = True)
243 return changelog(web, req, tmpl, shortlog = True)
232
244
233 def changeset(web, req, tmpl):
245 def changeset(web, req, tmpl):
234 ctx = webutil.changectx(web.repo, req)
246 ctx = webutil.changectx(web.repo, req)
235 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
247 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
236 showbranch = webutil.nodebranchnodefault(ctx)
248 showbranch = webutil.nodebranchnodefault(ctx)
237
249
238 files = []
250 files = []
239 parity = paritygen(web.stripecount)
251 parity = paritygen(web.stripecount)
240 for f in ctx.files():
252 for f in ctx.files():
241 template = f in ctx and 'filenodelink' or 'filenolink'
253 template = f in ctx and 'filenodelink' or 'filenolink'
242 files.append(tmpl(template,
254 files.append(tmpl(template,
243 node=ctx.hex(), file=f,
255 node=ctx.hex(), file=f,
244 parity=parity.next()))
256 parity=parity.next()))
245
257
246 parity = paritygen(web.stripecount)
258 parity = paritygen(web.stripecount)
247 style = web.config('web', 'style', 'paper')
259 style = web.config('web', 'style', 'paper')
248 if 'style' in req.form:
260 if 'style' in req.form:
249 style = req.form['style'][0]
261 style = req.form['style'][0]
250
262
251 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity, style)
263 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity, style)
252 return tmpl('changeset',
264 return tmpl('changeset',
253 diff=diffs,
265 diff=diffs,
254 rev=ctx.rev(),
266 rev=ctx.rev(),
255 node=ctx.hex(),
267 node=ctx.hex(),
256 parent=webutil.parents(ctx),
268 parent=webutil.parents(ctx),
257 child=webutil.children(ctx),
269 child=webutil.children(ctx),
258 changesettag=showtags,
270 changesettag=showtags,
259 changesetbranch=showbranch,
271 changesetbranch=showbranch,
260 author=ctx.user(),
272 author=ctx.user(),
261 desc=ctx.description(),
273 desc=ctx.description(),
262 date=ctx.date(),
274 date=ctx.date(),
263 files=files,
275 files=files,
264 archives=web.archivelist(ctx.hex()),
276 archives=web.archivelist(ctx.hex()),
265 tags=webutil.nodetagsdict(web.repo, ctx.node()),
277 tags=webutil.nodetagsdict(web.repo, ctx.node()),
266 branch=webutil.nodebranchnodefault(ctx),
278 branch=webutil.nodebranchnodefault(ctx),
267 inbranch=webutil.nodeinbranch(web.repo, ctx),
279 inbranch=webutil.nodeinbranch(web.repo, ctx),
268 branches=webutil.nodebranchdict(web.repo, ctx))
280 branches=webutil.nodebranchdict(web.repo, ctx))
269
281
270 rev = changeset
282 rev = changeset
271
283
272 def manifest(web, req, tmpl):
284 def manifest(web, req, tmpl):
273 ctx = webutil.changectx(web.repo, req)
285 ctx = webutil.changectx(web.repo, req)
274 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
286 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
275 mf = ctx.manifest()
287 mf = ctx.manifest()
276 node = ctx.node()
288 node = ctx.node()
277
289
278 files = {}
290 files = {}
279 dirs = {}
291 dirs = {}
280 parity = paritygen(web.stripecount)
292 parity = paritygen(web.stripecount)
281
293
282 if path and path[-1] != "/":
294 if path and path[-1] != "/":
283 path += "/"
295 path += "/"
284 l = len(path)
296 l = len(path)
285 abspath = "/" + path
297 abspath = "/" + path
286
298
287 for f, n in mf.iteritems():
299 for f, n in mf.iteritems():
288 if f[:l] != path:
300 if f[:l] != path:
289 continue
301 continue
290 remain = f[l:]
302 remain = f[l:]
291 elements = remain.split('/')
303 elements = remain.split('/')
292 if len(elements) == 1:
304 if len(elements) == 1:
293 files[remain] = f
305 files[remain] = f
294 else:
306 else:
295 h = dirs # need to retain ref to dirs (root)
307 h = dirs # need to retain ref to dirs (root)
296 for elem in elements[0:-1]:
308 for elem in elements[0:-1]:
297 if elem not in h:
309 if elem not in h:
298 h[elem] = {}
310 h[elem] = {}
299 h = h[elem]
311 h = h[elem]
300 if len(h) > 1:
312 if len(h) > 1:
301 break
313 break
302 h[None] = None # denotes files present
314 h[None] = None # denotes files present
303
315
304 if mf and not files and not dirs:
316 if mf and not files and not dirs:
305 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
317 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
306
318
307 def filelist(**map):
319 def filelist(**map):
308 for f in sorted(files):
320 for f in sorted(files):
309 full = files[f]
321 full = files[f]
310
322
311 fctx = ctx.filectx(full)
323 fctx = ctx.filectx(full)
312 yield {"file": full,
324 yield {"file": full,
313 "parity": parity.next(),
325 "parity": parity.next(),
314 "basename": f,
326 "basename": f,
315 "date": fctx.date(),
327 "date": fctx.date(),
316 "size": fctx.size(),
328 "size": fctx.size(),
317 "permissions": mf.flags(full)}
329 "permissions": mf.flags(full)}
318
330
319 def dirlist(**map):
331 def dirlist(**map):
320 for d in sorted(dirs):
332 for d in sorted(dirs):
321
333
322 emptydirs = []
334 emptydirs = []
323 h = dirs[d]
335 h = dirs[d]
324 while isinstance(h, dict) and len(h) == 1:
336 while isinstance(h, dict) and len(h) == 1:
325 k,v = h.items()[0]
337 k,v = h.items()[0]
326 if v:
338 if v:
327 emptydirs.append(k)
339 emptydirs.append(k)
328 h = v
340 h = v
329
341
330 path = "%s%s" % (abspath, d)
342 path = "%s%s" % (abspath, d)
331 yield {"parity": parity.next(),
343 yield {"parity": parity.next(),
332 "path": path,
344 "path": path,
333 "emptydirs": "/".join(emptydirs),
345 "emptydirs": "/".join(emptydirs),
334 "basename": d}
346 "basename": d}
335
347
336 return tmpl("manifest",
348 return tmpl("manifest",
337 rev=ctx.rev(),
349 rev=ctx.rev(),
338 node=hex(node),
350 node=hex(node),
339 path=abspath,
351 path=abspath,
340 up=webutil.up(abspath),
352 up=webutil.up(abspath),
341 upparity=parity.next(),
353 upparity=parity.next(),
342 fentries=filelist,
354 fentries=filelist,
343 dentries=dirlist,
355 dentries=dirlist,
344 archives=web.archivelist(hex(node)),
356 archives=web.archivelist(hex(node)),
345 tags=webutil.nodetagsdict(web.repo, node),
357 tags=webutil.nodetagsdict(web.repo, node),
346 inbranch=webutil.nodeinbranch(web.repo, ctx),
358 inbranch=webutil.nodeinbranch(web.repo, ctx),
347 branches=webutil.nodebranchdict(web.repo, ctx))
359 branches=webutil.nodebranchdict(web.repo, ctx))
348
360
349 def tags(web, req, tmpl):
361 def tags(web, req, tmpl):
350 i = web.repo.tagslist()
362 i = web.repo.tagslist()
351 i.reverse()
363 i.reverse()
352 parity = paritygen(web.stripecount)
364 parity = paritygen(web.stripecount)
353
365
354 def entries(notip=False, limit=0, **map):
366 def entries(notip=False, limit=0, **map):
355 count = 0
367 count = 0
356 for k, n in i:
368 for k, n in i:
357 if notip and k == "tip":
369 if notip and k == "tip":
358 continue
370 continue
359 if limit > 0 and count >= limit:
371 if limit > 0 and count >= limit:
360 continue
372 continue
361 count = count + 1
373 count = count + 1
362 yield {"parity": parity.next(),
374 yield {"parity": parity.next(),
363 "tag": k,
375 "tag": k,
364 "date": web.repo[n].date(),
376 "date": web.repo[n].date(),
365 "node": hex(n)}
377 "node": hex(n)}
366
378
367 return tmpl("tags",
379 return tmpl("tags",
368 node=hex(web.repo.changelog.tip()),
380 node=hex(web.repo.changelog.tip()),
369 entries=lambda **x: entries(False,0, **x),
381 entries=lambda **x: entries(False,0, **x),
370 entriesnotip=lambda **x: entries(True,0, **x),
382 entriesnotip=lambda **x: entries(True,0, **x),
371 latestentry=lambda **x: entries(True,1, **x))
383 latestentry=lambda **x: entries(True,1, **x))
372
384
373 def branches(web, req, tmpl):
385 def branches(web, req, tmpl):
374 b = web.repo.branchtags()
386 b = web.repo.branchtags()
375 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
387 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
376 heads = web.repo.heads()
388 heads = web.repo.heads()
377 parity = paritygen(web.stripecount)
389 parity = paritygen(web.stripecount)
378 sortkey = lambda ctx: ('close' not in ctx.extra(), ctx.rev())
390 sortkey = lambda ctx: ('close' not in ctx.extra(), ctx.rev())
379
391
380 def entries(limit, **map):
392 def entries(limit, **map):
381 count = 0
393 count = 0
382 for ctx in sorted(tips, key=sortkey, reverse=True):
394 for ctx in sorted(tips, key=sortkey, reverse=True):
383 if limit > 0 and count >= limit:
395 if limit > 0 and count >= limit:
384 return
396 return
385 count += 1
397 count += 1
386 if ctx.node() not in heads:
398 if ctx.node() not in heads:
387 status = 'inactive'
399 status = 'inactive'
388 elif not web.repo.branchheads(ctx.branch()):
400 elif not web.repo.branchheads(ctx.branch()):
389 status = 'closed'
401 status = 'closed'
390 else:
402 else:
391 status = 'open'
403 status = 'open'
392 yield {'parity': parity.next(),
404 yield {'parity': parity.next(),
393 'branch': ctx.branch(),
405 'branch': ctx.branch(),
394 'status': status,
406 'status': status,
395 'node': ctx.hex(),
407 'node': ctx.hex(),
396 'date': ctx.date()}
408 'date': ctx.date()}
397
409
398 return tmpl('branches', node=hex(web.repo.changelog.tip()),
410 return tmpl('branches', node=hex(web.repo.changelog.tip()),
399 entries=lambda **x: entries(0, **x),
411 entries=lambda **x: entries(0, **x),
400 latestentry=lambda **x: entries(1, **x))
412 latestentry=lambda **x: entries(1, **x))
401
413
402 def summary(web, req, tmpl):
414 def summary(web, req, tmpl):
403 i = web.repo.tagslist()
415 i = web.repo.tagslist()
404 i.reverse()
416 i.reverse()
405
417
406 def tagentries(**map):
418 def tagentries(**map):
407 parity = paritygen(web.stripecount)
419 parity = paritygen(web.stripecount)
408 count = 0
420 count = 0
409 for k, n in i:
421 for k, n in i:
410 if k == "tip": # skip tip
422 if k == "tip": # skip tip
411 continue
423 continue
412
424
413 count += 1
425 count += 1
414 if count > 10: # limit to 10 tags
426 if count > 10: # limit to 10 tags
415 break
427 break
416
428
417 yield tmpl("tagentry",
429 yield tmpl("tagentry",
418 parity=parity.next(),
430 parity=parity.next(),
419 tag=k,
431 tag=k,
420 node=hex(n),
432 node=hex(n),
421 date=web.repo[n].date())
433 date=web.repo[n].date())
422
434
423 def branches(**map):
435 def branches(**map):
424 parity = paritygen(web.stripecount)
436 parity = paritygen(web.stripecount)
425
437
426 b = web.repo.branchtags()
438 b = web.repo.branchtags()
427 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
439 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
428 for r,n,t in sorted(l):
440 for r,n,t in sorted(l):
429 yield {'parity': parity.next(),
441 yield {'parity': parity.next(),
430 'branch': t,
442 'branch': t,
431 'node': hex(n),
443 'node': hex(n),
432 'date': web.repo[n].date()}
444 'date': web.repo[n].date()}
433
445
434 def changelist(**map):
446 def changelist(**map):
435 parity = paritygen(web.stripecount, offset=start-end)
447 parity = paritygen(web.stripecount, offset=start-end)
436 l = [] # build a list in forward order for efficiency
448 l = [] # build a list in forward order for efficiency
437 for i in xrange(start, end):
449 for i in xrange(start, end):
438 ctx = web.repo[i]
450 ctx = web.repo[i]
439 n = ctx.node()
451 n = ctx.node()
440 hn = hex(n)
452 hn = hex(n)
441
453
442 l.insert(0, tmpl(
454 l.insert(0, tmpl(
443 'shortlogentry',
455 'shortlogentry',
444 parity=parity.next(),
456 parity=parity.next(),
445 author=ctx.user(),
457 author=ctx.user(),
446 desc=ctx.description(),
458 desc=ctx.description(),
447 date=ctx.date(),
459 date=ctx.date(),
448 rev=i,
460 rev=i,
449 node=hn,
461 node=hn,
450 tags=webutil.nodetagsdict(web.repo, n),
462 tags=webutil.nodetagsdict(web.repo, n),
451 inbranch=webutil.nodeinbranch(web.repo, ctx),
463 inbranch=webutil.nodeinbranch(web.repo, ctx),
452 branches=webutil.nodebranchdict(web.repo, ctx)))
464 branches=webutil.nodebranchdict(web.repo, ctx)))
453
465
454 yield l
466 yield l
455
467
456 cl = web.repo.changelog
468 cl = web.repo.changelog
457 count = len(cl)
469 count = len(cl)
458 start = max(0, count - web.maxchanges)
470 start = max(0, count - web.maxchanges)
459 end = min(count, start + web.maxchanges)
471 end = min(count, start + web.maxchanges)
460
472
461 return tmpl("summary",
473 return tmpl("summary",
462 desc=web.config("web", "description", "unknown"),
474 desc=web.config("web", "description", "unknown"),
463 owner=get_contact(web.config) or "unknown",
475 owner=get_contact(web.config) or "unknown",
464 lastchange=cl.read(cl.tip())[2],
476 lastchange=cl.read(cl.tip())[2],
465 tags=tagentries,
477 tags=tagentries,
466 branches=branches,
478 branches=branches,
467 shortlog=changelist,
479 shortlog=changelist,
468 node=hex(cl.tip()),
480 node=hex(cl.tip()),
469 archives=web.archivelist("tip"))
481 archives=web.archivelist("tip"))
470
482
471 def filediff(web, req, tmpl):
483 def filediff(web, req, tmpl):
472 fctx, ctx = None, None
484 fctx, ctx = None, None
473 try:
485 try:
474 fctx = webutil.filectx(web.repo, req)
486 fctx = webutil.filectx(web.repo, req)
475 except LookupError:
487 except LookupError:
476 ctx = webutil.changectx(web.repo, req)
488 ctx = webutil.changectx(web.repo, req)
477 path = webutil.cleanpath(web.repo, req.form['file'][0])
489 path = webutil.cleanpath(web.repo, req.form['file'][0])
478 if path not in ctx.files():
490 if path not in ctx.files():
479 raise
491 raise
480
492
481 if fctx is not None:
493 if fctx is not None:
482 n = fctx.node()
494 n = fctx.node()
483 path = fctx.path()
495 path = fctx.path()
484 else:
496 else:
485 n = ctx.node()
497 n = ctx.node()
486 # path already defined in except clause
498 # path already defined in except clause
487
499
488 parity = paritygen(web.stripecount)
500 parity = paritygen(web.stripecount)
489 style = web.config('web', 'style', 'paper')
501 style = web.config('web', 'style', 'paper')
490 if 'style' in req.form:
502 if 'style' in req.form:
491 style = req.form['style'][0]
503 style = req.form['style'][0]
492
504
493 diffs = webutil.diffs(web.repo, tmpl, fctx or ctx, [path], parity, style)
505 diffs = webutil.diffs(web.repo, tmpl, fctx or ctx, [path], parity, style)
494 rename = fctx and webutil.renamelink(fctx) or []
506 rename = fctx and webutil.renamelink(fctx) or []
495 ctx = fctx and fctx or ctx
507 ctx = fctx and fctx or ctx
496 return tmpl("filediff",
508 return tmpl("filediff",
497 file=path,
509 file=path,
498 node=hex(n),
510 node=hex(n),
499 rev=ctx.rev(),
511 rev=ctx.rev(),
500 date=ctx.date(),
512 date=ctx.date(),
501 desc=ctx.description(),
513 desc=ctx.description(),
502 author=ctx.user(),
514 author=ctx.user(),
503 rename=rename,
515 rename=rename,
504 branch=webutil.nodebranchnodefault(ctx),
516 branch=webutil.nodebranchnodefault(ctx),
505 parent=webutil.parents(ctx),
517 parent=webutil.parents(ctx),
506 child=webutil.children(ctx),
518 child=webutil.children(ctx),
507 diff=diffs)
519 diff=diffs)
508
520
509 diff = filediff
521 diff = filediff
510
522
511 def annotate(web, req, tmpl):
523 def annotate(web, req, tmpl):
512 fctx = webutil.filectx(web.repo, req)
524 fctx = webutil.filectx(web.repo, req)
513 f = fctx.path()
525 f = fctx.path()
514 parity = paritygen(web.stripecount)
526 parity = paritygen(web.stripecount)
515
527
516 def annotate(**map):
528 def annotate(**map):
517 last = None
529 last = None
518 if binary(fctx.data()):
530 if binary(fctx.data()):
519 mt = (mimetypes.guess_type(fctx.path())[0]
531 mt = (mimetypes.guess_type(fctx.path())[0]
520 or 'application/octet-stream')
532 or 'application/octet-stream')
521 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
533 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
522 '(binary:%s)' % mt)])
534 '(binary:%s)' % mt)])
523 else:
535 else:
524 lines = enumerate(fctx.annotate(follow=True, linenumber=True))
536 lines = enumerate(fctx.annotate(follow=True, linenumber=True))
525 for lineno, ((f, targetline), l) in lines:
537 for lineno, ((f, targetline), l) in lines:
526 fnode = f.filenode()
538 fnode = f.filenode()
527
539
528 if last != fnode:
540 if last != fnode:
529 last = fnode
541 last = fnode
530
542
531 yield {"parity": parity.next(),
543 yield {"parity": parity.next(),
532 "node": hex(f.node()),
544 "node": hex(f.node()),
533 "rev": f.rev(),
545 "rev": f.rev(),
534 "author": f.user(),
546 "author": f.user(),
535 "desc": f.description(),
547 "desc": f.description(),
536 "file": f.path(),
548 "file": f.path(),
537 "targetline": targetline,
549 "targetline": targetline,
538 "line": l,
550 "line": l,
539 "lineid": "l%d" % (lineno + 1),
551 "lineid": "l%d" % (lineno + 1),
540 "linenumber": "% 6d" % (lineno + 1)}
552 "linenumber": "% 6d" % (lineno + 1)}
541
553
542 return tmpl("fileannotate",
554 return tmpl("fileannotate",
543 file=f,
555 file=f,
544 annotate=annotate,
556 annotate=annotate,
545 path=webutil.up(f),
557 path=webutil.up(f),
546 rev=fctx.rev(),
558 rev=fctx.rev(),
547 node=hex(fctx.node()),
559 node=hex(fctx.node()),
548 author=fctx.user(),
560 author=fctx.user(),
549 date=fctx.date(),
561 date=fctx.date(),
550 desc=fctx.description(),
562 desc=fctx.description(),
551 rename=webutil.renamelink(fctx),
563 rename=webutil.renamelink(fctx),
552 branch=webutil.nodebranchnodefault(fctx),
564 branch=webutil.nodebranchnodefault(fctx),
553 parent=webutil.parents(fctx),
565 parent=webutil.parents(fctx),
554 child=webutil.children(fctx),
566 child=webutil.children(fctx),
555 permissions=fctx.manifest().flags(f))
567 permissions=fctx.manifest().flags(f))
556
568
557 def filelog(web, req, tmpl):
569 def filelog(web, req, tmpl):
558
570
559 try:
571 try:
560 fctx = webutil.filectx(web.repo, req)
572 fctx = webutil.filectx(web.repo, req)
561 f = fctx.path()
573 f = fctx.path()
562 fl = fctx.filelog()
574 fl = fctx.filelog()
563 except error.LookupError:
575 except error.LookupError:
564 f = webutil.cleanpath(web.repo, req.form['file'][0])
576 f = webutil.cleanpath(web.repo, req.form['file'][0])
565 fl = web.repo.file(f)
577 fl = web.repo.file(f)
566 numrevs = len(fl)
578 numrevs = len(fl)
567 if not numrevs: # file doesn't exist at all
579 if not numrevs: # file doesn't exist at all
568 raise
580 raise
569 rev = webutil.changectx(web.repo, req).rev()
581 rev = webutil.changectx(web.repo, req).rev()
570 first = fl.linkrev(0)
582 first = fl.linkrev(0)
571 if rev < first: # current rev is from before file existed
583 if rev < first: # current rev is from before file existed
572 raise
584 raise
573 frev = numrevs - 1
585 frev = numrevs - 1
574 while fl.linkrev(frev) > rev:
586 while fl.linkrev(frev) > rev:
575 frev -= 1
587 frev -= 1
576 fctx = web.repo.filectx(f, fl.linkrev(frev))
588 fctx = web.repo.filectx(f, fl.linkrev(frev))
577
589
578 revcount = web.maxshortchanges
590 revcount = web.maxshortchanges
579 if 'revcount' in req.form:
591 if 'revcount' in req.form:
580 revcount = int(req.form.get('revcount', [revcount])[0])
592 revcount = int(req.form.get('revcount', [revcount])[0])
581 tmpl.defaults['sessionvars']['revcount'] = revcount
593 tmpl.defaults['sessionvars']['revcount'] = revcount
582
594
583 lessvars = copy.copy(tmpl.defaults['sessionvars'])
595 lessvars = copy.copy(tmpl.defaults['sessionvars'])
584 lessvars['revcount'] = revcount / 2
596 lessvars['revcount'] = revcount / 2
585 morevars = copy.copy(tmpl.defaults['sessionvars'])
597 morevars = copy.copy(tmpl.defaults['sessionvars'])
586 morevars['revcount'] = revcount * 2
598 morevars['revcount'] = revcount * 2
587
599
588 count = fctx.filerev() + 1
600 count = fctx.filerev() + 1
589 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
601 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
590 end = min(count, start + revcount) # last rev on this page
602 end = min(count, start + revcount) # last rev on this page
591 parity = paritygen(web.stripecount, offset=start-end)
603 parity = paritygen(web.stripecount, offset=start-end)
592
604
593 def entries(limit=0, **map):
605 def entries(limit=0, **map):
594 l = []
606 l = []
595
607
596 repo = web.repo
608 repo = web.repo
597 for i in xrange(start, end):
609 for i in xrange(start, end):
598 iterfctx = fctx.filectx(i)
610 iterfctx = fctx.filectx(i)
599
611
600 l.insert(0, {"parity": parity.next(),
612 l.insert(0, {"parity": parity.next(),
601 "filerev": i,
613 "filerev": i,
602 "file": f,
614 "file": f,
603 "node": hex(iterfctx.node()),
615 "node": hex(iterfctx.node()),
604 "author": iterfctx.user(),
616 "author": iterfctx.user(),
605 "date": iterfctx.date(),
617 "date": iterfctx.date(),
606 "rename": webutil.renamelink(iterfctx),
618 "rename": webutil.renamelink(iterfctx),
607 "parent": webutil.parents(iterfctx),
619 "parent": webutil.parents(iterfctx),
608 "child": webutil.children(iterfctx),
620 "child": webutil.children(iterfctx),
609 "desc": iterfctx.description(),
621 "desc": iterfctx.description(),
610 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
622 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
611 "branch": webutil.nodebranchnodefault(iterfctx),
623 "branch": webutil.nodebranchnodefault(iterfctx),
612 "inbranch": webutil.nodeinbranch(repo, iterfctx),
624 "inbranch": webutil.nodeinbranch(repo, iterfctx),
613 "branches": webutil.nodebranchdict(repo, iterfctx)})
625 "branches": webutil.nodebranchdict(repo, iterfctx)})
614
626
615 if limit > 0:
627 if limit > 0:
616 l = l[:limit]
628 l = l[:limit]
617
629
618 for e in l:
630 for e in l:
619 yield e
631 yield e
620
632
621 nodefunc = lambda x: fctx.filectx(fileid=x)
633 nodefunc = lambda x: fctx.filectx(fileid=x)
622 nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
634 nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
623 return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
635 return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
624 entries=lambda **x: entries(limit=0, **x),
636 entries=lambda **x: entries(limit=0, **x),
625 latestentry=lambda **x: entries(limit=1, **x),
637 latestentry=lambda **x: entries(limit=1, **x),
626 revcount=revcount, morevars=morevars, lessvars=lessvars)
638 revcount=revcount, morevars=morevars, lessvars=lessvars)
627
639
628 def archive(web, req, tmpl):
640 def archive(web, req, tmpl):
629 type_ = req.form.get('type', [None])[0]
641 type_ = req.form.get('type', [None])[0]
630 allowed = web.configlist("web", "allow_archive")
642 allowed = web.configlist("web", "allow_archive")
631 key = req.form['node'][0]
643 key = req.form['node'][0]
632
644
633 if type_ not in web.archives:
645 if type_ not in web.archives:
634 msg = 'Unsupported archive type: %s' % type_
646 msg = 'Unsupported archive type: %s' % type_
635 raise ErrorResponse(HTTP_NOT_FOUND, msg)
647 raise ErrorResponse(HTTP_NOT_FOUND, msg)
636
648
637 if not ((type_ in allowed or
649 if not ((type_ in allowed or
638 web.configbool("web", "allow" + type_, False))):
650 web.configbool("web", "allow" + type_, False))):
639 msg = 'Archive type not allowed: %s' % type_
651 msg = 'Archive type not allowed: %s' % type_
640 raise ErrorResponse(HTTP_FORBIDDEN, msg)
652 raise ErrorResponse(HTTP_FORBIDDEN, msg)
641
653
642 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
654 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
643 cnode = web.repo.lookup(key)
655 cnode = web.repo.lookup(key)
644 arch_version = key
656 arch_version = key
645 if cnode == key or key == 'tip':
657 if cnode == key or key == 'tip':
646 arch_version = short(cnode)
658 arch_version = short(cnode)
647 name = "%s-%s" % (reponame, arch_version)
659 name = "%s-%s" % (reponame, arch_version)
648 mimetype, artype, extension, encoding = web.archive_specs[type_]
660 mimetype, artype, extension, encoding = web.archive_specs[type_]
649 headers = [
661 headers = [
650 ('Content-Type', mimetype),
662 ('Content-Type', mimetype),
651 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
663 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
652 ]
664 ]
653 if encoding:
665 if encoding:
654 headers.append(('Content-Encoding', encoding))
666 headers.append(('Content-Encoding', encoding))
655 req.header(headers)
667 req.header(headers)
656 req.respond(HTTP_OK)
668 req.respond(HTTP_OK)
657 archival.archive(web.repo, req, cnode, artype, prefix=name)
669 archival.archive(web.repo, req, cnode, artype, prefix=name)
658 return []
670 return []
659
671
660
672
661 def static(web, req, tmpl):
673 def static(web, req, tmpl):
662 fname = req.form['file'][0]
674 fname = req.form['file'][0]
663 # a repo owner may set web.static in .hg/hgrc to get any file
675 # a repo owner may set web.static in .hg/hgrc to get any file
664 # readable by the user running the CGI script
676 # readable by the user running the CGI script
665 static = web.config("web", "static", None, untrusted=False)
677 static = web.config("web", "static", None, untrusted=False)
666 if not static:
678 if not static:
667 tp = web.templatepath or templater.templatepath()
679 tp = web.templatepath or templater.templatepath()
668 if isinstance(tp, str):
680 if isinstance(tp, str):
669 tp = [tp]
681 tp = [tp]
670 static = [os.path.join(p, 'static') for p in tp]
682 static = [os.path.join(p, 'static') for p in tp]
671 return [staticfile(static, fname, req)]
683 return [staticfile(static, fname, req)]
672
684
673 def graph(web, req, tmpl):
685 def graph(web, req, tmpl):
674
686
675 rev = webutil.changectx(web.repo, req).rev()
687 rev = webutil.changectx(web.repo, req).rev()
676 bg_height = 39
688 bg_height = 39
677 revcount = web.maxshortchanges
689 revcount = web.maxshortchanges
678 if 'revcount' in req.form:
690 if 'revcount' in req.form:
679 revcount = int(req.form.get('revcount', [revcount])[0])
691 revcount = int(req.form.get('revcount', [revcount])[0])
680 tmpl.defaults['sessionvars']['revcount'] = revcount
692 tmpl.defaults['sessionvars']['revcount'] = revcount
681
693
682 lessvars = copy.copy(tmpl.defaults['sessionvars'])
694 lessvars = copy.copy(tmpl.defaults['sessionvars'])
683 lessvars['revcount'] = revcount / 2
695 lessvars['revcount'] = revcount / 2
684 morevars = copy.copy(tmpl.defaults['sessionvars'])
696 morevars = copy.copy(tmpl.defaults['sessionvars'])
685 morevars['revcount'] = revcount * 2
697 morevars['revcount'] = revcount * 2
686
698
687 max_rev = len(web.repo) - 1
699 max_rev = len(web.repo) - 1
688 revcount = min(max_rev, revcount)
700 revcount = min(max_rev, revcount)
689 revnode = web.repo.changelog.node(rev)
701 revnode = web.repo.changelog.node(rev)
690 revnode_hex = hex(revnode)
702 revnode_hex = hex(revnode)
691 uprev = min(max_rev, rev + revcount)
703 uprev = min(max_rev, rev + revcount)
692 downrev = max(0, rev - revcount)
704 downrev = max(0, rev - revcount)
693 count = len(web.repo)
705 count = len(web.repo)
694 changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
706 changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
695
707
696 dag = graphmod.revisions(web.repo, rev, downrev)
708 dag = graphmod.revisions(web.repo, rev, downrev)
697 tree = list(graphmod.colored(dag))
709 tree = list(graphmod.colored(dag))
698 canvasheight = (len(tree) + 1) * bg_height - 27;
710 canvasheight = (len(tree) + 1) * bg_height - 27;
699 data = []
711 data = []
700 for (id, type, ctx, vtx, edges) in tree:
712 for (id, type, ctx, vtx, edges) in tree:
701 if type != graphmod.CHANGESET:
713 if type != graphmod.CHANGESET:
702 continue
714 continue
703 node = short(ctx.node())
715 node = short(ctx.node())
704 age = templatefilters.age(ctx.date())
716 age = templatefilters.age(ctx.date())
705 desc = templatefilters.firstline(ctx.description())
717 desc = templatefilters.firstline(ctx.description())
706 desc = cgi.escape(templatefilters.nonempty(desc))
718 desc = cgi.escape(templatefilters.nonempty(desc))
707 user = cgi.escape(templatefilters.person(ctx.user()))
719 user = cgi.escape(templatefilters.person(ctx.user()))
708 branch = ctx.branch()
720 branch = ctx.branch()
709 branch = branch, web.repo.branchtags().get(branch) == ctx.node()
721 branch = branch, web.repo.branchtags().get(branch) == ctx.node()
710 data.append((node, vtx, edges, desc, user, age, branch, ctx.tags()))
722 data.append((node, vtx, edges, desc, user, age, branch, ctx.tags()))
711
723
712 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
724 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
713 lessvars=lessvars, morevars=morevars, downrev=downrev,
725 lessvars=lessvars, morevars=morevars, downrev=downrev,
714 canvasheight=canvasheight, jsdata=data, bg_height=bg_height,
726 canvasheight=canvasheight, jsdata=data, bg_height=bg_height,
715 node=revnode_hex, changenav=changenav)
727 node=revnode_hex, changenav=changenav)
@@ -1,43 +1,53 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="container">
6 <div class="container">
7 <div class="menu">
7 <div class="menu">
8 <div class="logo">
8 <div class="logo">
9 <a href="http://mercurial.selenic.com/">
9 <a href="http://mercurial.selenic.com/">
10 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
10 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
11 </div>
11 </div>
12 <ul>
12 <ul>
13 <li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
13 <li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
14 <li><a href="{url}graph{sessionvars%urlparameter}">graph</a></li>
14 <li><a href="{url}graph{sessionvars%urlparameter}">graph</a></li>
15 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
15 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
16 <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
16 <li><a href="{url}branches{sessionvars%urlparameter}">branches</a></li>
17 </ul>
17 </ul>
18 </div>
18 </div>
19
19
20 <div class="main">
20 <div class="main">
21 <h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
21 <h2><a href="{url}{sessionvars%urlparameter}">{repo|escape}</a></h2>
22 <h3>searching for '{query|escape}'</h3>
22 <h3>searching for '{query|escape}'</h3>
23
23
24 <form class="search" action="{url}log">
24 <form class="search" action="{url}log">
25 {sessionvars%hiddenformentry}
25 {sessionvars%hiddenformentry}
26 <p><input name="rev" id="search1" type="text" size="30"></p>
26 <p><input name="rev" id="search1" type="text" size="30"></p>
27 <div id="hint">find changesets by author, revision,
27 <div id="hint">find changesets by author, revision,
28 files, or words in the commit message</div>
28 files, or words in the commit message</div>
29 </form>
29 </form>
30
30
31 <div class="navigate">
32 <a href="{url}search/{lessvars%urlparameter}">less</a>
33 <a href="{url}search/{morevars%urlparameter}">more</a>
34 </div>
35
31 <table class="bigtable">
36 <table class="bigtable">
32 <tr>
37 <tr>
33 <th class="age">age</th>
38 <th class="age">age</th>
34 <th class="author">author</th>
39 <th class="author">author</th>
35 <th class="description">description</th>
40 <th class="description">description</th>
36 </tr>
41 </tr>
37 {entries}
42 {entries}
38 </table>
43 </table>
39
44
45 <div class="navigate">
46 <a href="{url}search/{lessvars%urlparameter}">less</a>
47 <a href="{url}search/{morevars%urlparameter}">more</a>
48 </div>
49
40 </div>
50 </div>
41 </div>
51 </div>
42
52
43 {footer}
53 {footer}
General Comments 0
You need to be logged in to leave comments. Login now