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