comparison upmana/mercurial/hgweb/webcommands.py @ 121:496dbf12a6cb alpha

Traipse Alpha 'OpenRPG' {091030-00} Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to offer more advanced features and enhance the productivity of the user. Update Summary (Cleaning up for Beta): Adds Bookmarks (Alpha) with cool Smiley Star and Plus Symbol images! Changes made to the map for increased portability. SnowDog has changes planned in Core, though. Added an initial push to the BCG. Not much to see, just shows off how it is re-writing Main code. Fix to remote admin commands Minor fix to texted based server, works in /System/ folder Some Core changes to gametree to correctly disply Pretty Print, thanks David! Fix to Splitter Nodes not being created. Added images to Plugin Control panel for Autostart feature Fix to massive amounts of images loading; from Core fix to gsclient so with_statement imports Added 'boot' command to remote admin Prep work in Pass tool for remote admin rankings and different passwords, ei, Server, Admin, Moderator, etc. Remote Admin Commands more organized, more prep work. Added Confirmation window for sent nodes. Minor changes to allow for portability to an OpenSUSE linux OS (hopefully without breaking) {091028} Made changes to gametree to start working with Element Tree, mostly from Core Minor changes to Map to start working with Element Tree, from Core Preliminary changes to map efficiency, from FlexiRPG Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG Changes to main.py to start working with Element Tree {091029} Changes made to server to start working with Element Tree. Changes made to Meta Server Lib. Prepping test work for a multi meta network page. Minor bug fixed with mini to gametree Zoom Mouse plugin added. {091030} Getting ready for Beta. Server needs debugging so Alpha remains bugged. Plugin UI code cleaned. Auto start works with a graphic, pop-up asks to enable or disable plugin. Update Manager now has a partially working Status Bar. Status Bar captures terminal text, so Merc out put is visible. Manifest.xml file, will be renamed, is now much cleaner. Debug Console has a clear button and a Report Bug button. Prep work for a Term2Win class in Debug Console. Known: Current Alpha fails in Windows.
author sirebral
date Fri, 30 Oct 2009 22:21:40 -0500
parents
children 36919b8a3ef9
comparison
equal deleted inserted replaced
120:d86e762a994f 121:496dbf12a6cb
1 #
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
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.
7
8 import os, mimetypes, re, cgi, copy
9 import webutil
10 from mercurial import error, archival, templater, templatefilters
11 from mercurial.node import short, hex
12 from mercurial.util import binary
13 from common import paritygen, staticfile, get_contact, ErrorResponse
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
15 from mercurial import graphmod
16
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.
19
20 __all__ = [
21 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
22 'manifest', 'tags', 'branches', 'summary', 'filediff', 'diff', 'annotate',
23 'filelog', 'archive', 'static', 'graph',
24 ]
25
26 def log(web, req, tmpl):
27 if 'file' in req.form and req.form['file'][0]:
28 return filelog(web, req, tmpl)
29 else:
30 return changelog(web, req, tmpl)
31
32 def rawfile(web, req, tmpl):
33 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
34 if not path:
35 content = manifest(web, req, tmpl)
36 req.respond(HTTP_OK, web.ctype)
37 return content
38
39 try:
40 fctx = webutil.filectx(web.repo, req)
41 except error.LookupError, inst:
42 try:
43 content = manifest(web, req, tmpl)
44 req.respond(HTTP_OK, web.ctype)
45 return content
46 except ErrorResponse:
47 raise inst
48
49 path = fctx.path()
50 text = fctx.data()
51 mt = mimetypes.guess_type(path)[0]
52 if mt is None:
53 mt = binary(text) and 'application/octet-stream' or 'text/plain'
54
55 req.respond(HTTP_OK, mt, path, len(text))
56 return [text]
57
58 def _filerevision(web, tmpl, fctx):
59 f = fctx.path()
60 text = fctx.data()
61 parity = paritygen(web.stripecount)
62
63 if binary(text):
64 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
65 text = '(binary:%s)' % mt
66
67 def lines():
68 for lineno, t in enumerate(text.splitlines(1)):
69 yield {"line": t,
70 "lineid": "l%d" % (lineno + 1),
71 "linenumber": "% 6d" % (lineno + 1),
72 "parity": parity.next()}
73
74 return tmpl("filerevision",
75 file=f,
76 path=webutil.up(f),
77 text=lines(),
78 rev=fctx.rev(),
79 node=hex(fctx.node()),
80 author=fctx.user(),
81 date=fctx.date(),
82 desc=fctx.description(),
83 branch=webutil.nodebranchnodefault(fctx),
84 parent=webutil.parents(fctx),
85 child=webutil.children(fctx),
86 rename=webutil.renamelink(fctx),
87 permissions=fctx.manifest().flags(f))
88
89 def file(web, req, tmpl):
90 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
91 if not path:
92 return manifest(web, req, tmpl)
93 try:
94 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
95 except error.LookupError, inst:
96 try:
97 return manifest(web, req, tmpl)
98 except ErrorResponse:
99 raise inst
100
101 def _search(web, tmpl, query):
102
103 def changelist(**map):
104 cl = web.repo.changelog
105 count = 0
106 qw = query.lower().split()
107
108 def revgen():
109 for i in xrange(len(cl) - 1, 0, -100):
110 l = []
111 for j in xrange(max(0, i - 100), i + 1):
112 ctx = web.repo[j]
113 l.append(ctx)
114 l.reverse()
115 for e in l:
116 yield e
117
118 for ctx in revgen():
119 miss = 0
120 for q in qw:
121 if not (q in ctx.user().lower() or
122 q in ctx.description().lower() or
123 q in " ".join(ctx.files()).lower()):
124 miss = 1
125 break
126 if miss:
127 continue
128
129 count += 1
130 n = ctx.node()
131 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
132 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
133
134 yield tmpl('searchentry',
135 parity=parity.next(),
136 author=ctx.user(),
137 parent=webutil.parents(ctx),
138 child=webutil.children(ctx),
139 changelogtag=showtags,
140 desc=ctx.description(),
141 date=ctx.date(),
142 files=files,
143 rev=ctx.rev(),
144 node=hex(n),
145 tags=webutil.nodetagsdict(web.repo, n),
146 inbranch=webutil.nodeinbranch(web.repo, ctx),
147 branches=webutil.nodebranchdict(web.repo, ctx))
148
149 if count >= web.maxchanges:
150 break
151
152 cl = web.repo.changelog
153 parity = paritygen(web.stripecount)
154
155 return tmpl('search',
156 query=query,
157 node=hex(cl.tip()),
158 entries=changelist,
159 archives=web.archivelist("tip"))
160
161 def changelog(web, req, tmpl, shortlog = False):
162 if 'node' in req.form:
163 ctx = webutil.changectx(web.repo, req)
164 else:
165 if 'rev' in req.form:
166 hi = req.form['rev'][0]
167 else:
168 hi = len(web.repo) - 1
169 try:
170 ctx = web.repo[hi]
171 except error.RepoError:
172 return _search(web, tmpl, hi) # XXX redirect to 404 page?
173
174 def changelist(limit=0, **map):
175 l = [] # build a list in forward order for efficiency
176 for i in xrange(start, end):
177 ctx = web.repo[i]
178 n = ctx.node()
179 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
180 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
181
182 l.insert(0, {"parity": parity.next(),
183 "author": ctx.user(),
184 "parent": webutil.parents(ctx, i - 1),
185 "child": webutil.children(ctx, i + 1),
186 "changelogtag": showtags,
187 "desc": ctx.description(),
188 "date": ctx.date(),
189 "files": files,
190 "rev": i,
191 "node": hex(n),
192 "tags": webutil.nodetagsdict(web.repo, n),
193 "inbranch": webutil.nodeinbranch(web.repo, ctx),
194 "branches": webutil.nodebranchdict(web.repo, ctx)
195 })
196
197 if limit > 0:
198 l = l[:limit]
199
200 for e in l:
201 yield e
202
203 maxchanges = shortlog and web.maxshortchanges or web.maxchanges
204 cl = web.repo.changelog
205 count = len(cl)
206 pos = ctx.rev()
207 start = max(0, pos - maxchanges + 1)
208 end = min(count, start + maxchanges)
209 pos = end - 1
210 parity = paritygen(web.stripecount, offset=start-end)
211
212 changenav = webutil.revnavgen(pos, maxchanges, count, web.repo.changectx)
213
214 return tmpl(shortlog and 'shortlog' or 'changelog',
215 changenav=changenav,
216 node=hex(ctx.node()),
217 rev=pos, changesets=count,
218 entries=lambda **x: changelist(limit=0,**x),
219 latestentry=lambda **x: changelist(limit=1,**x),
220 archives=web.archivelist("tip"))
221
222 def shortlog(web, req, tmpl):
223 return changelog(web, req, tmpl, shortlog = True)
224
225 def changeset(web, req, tmpl):
226 ctx = webutil.changectx(web.repo, req)
227 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
228 showbranch = webutil.nodebranchnodefault(ctx)
229
230 files = []
231 parity = paritygen(web.stripecount)
232 for f in ctx.files():
233 template = f in ctx and 'filenodelink' or 'filenolink'
234 files.append(tmpl(template,
235 node=ctx.hex(), file=f,
236 parity=parity.next()))
237
238 parity = paritygen(web.stripecount)
239 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity)
240 return tmpl('changeset',
241 diff=diffs,
242 rev=ctx.rev(),
243 node=ctx.hex(),
244 parent=webutil.parents(ctx),
245 child=webutil.children(ctx),
246 changesettag=showtags,
247 changesetbranch=showbranch,
248 author=ctx.user(),
249 desc=ctx.description(),
250 date=ctx.date(),
251 files=files,
252 archives=web.archivelist(ctx.hex()),
253 tags=webutil.nodetagsdict(web.repo, ctx.node()),
254 branch=webutil.nodebranchnodefault(ctx),
255 inbranch=webutil.nodeinbranch(web.repo, ctx),
256 branches=webutil.nodebranchdict(web.repo, ctx))
257
258 rev = changeset
259
260 def manifest(web, req, tmpl):
261 ctx = webutil.changectx(web.repo, req)
262 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
263 mf = ctx.manifest()
264 node = ctx.node()
265
266 files = {}
267 dirs = {}
268 parity = paritygen(web.stripecount)
269
270 if path and path[-1] != "/":
271 path += "/"
272 l = len(path)
273 abspath = "/" + path
274
275 for f, n in mf.iteritems():
276 if f[:l] != path:
277 continue
278 remain = f[l:]
279 elements = remain.split('/')
280 if len(elements) == 1:
281 files[remain] = f
282 else:
283 h = dirs # need to retain ref to dirs (root)
284 for elem in elements[0:-1]:
285 if elem not in h:
286 h[elem] = {}
287 h = h[elem]
288 if len(h) > 1:
289 break
290 h[None] = None # denotes files present
291
292 if mf and not files and not dirs:
293 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
294
295 def filelist(**map):
296 for f in sorted(files):
297 full = files[f]
298
299 fctx = ctx.filectx(full)
300 yield {"file": full,
301 "parity": parity.next(),
302 "basename": f,
303 "date": fctx.date(),
304 "size": fctx.size(),
305 "permissions": mf.flags(full)}
306
307 def dirlist(**map):
308 for d in sorted(dirs):
309
310 emptydirs = []
311 h = dirs[d]
312 while isinstance(h, dict) and len(h) == 1:
313 k,v = h.items()[0]
314 if v:
315 emptydirs.append(k)
316 h = v
317
318 path = "%s%s" % (abspath, d)
319 yield {"parity": parity.next(),
320 "path": path,
321 "emptydirs": "/".join(emptydirs),
322 "basename": d}
323
324 return tmpl("manifest",
325 rev=ctx.rev(),
326 node=hex(node),
327 path=abspath,
328 up=webutil.up(abspath),
329 upparity=parity.next(),
330 fentries=filelist,
331 dentries=dirlist,
332 archives=web.archivelist(hex(node)),
333 tags=webutil.nodetagsdict(web.repo, node),
334 inbranch=webutil.nodeinbranch(web.repo, ctx),
335 branches=webutil.nodebranchdict(web.repo, ctx))
336
337 def tags(web, req, tmpl):
338 i = web.repo.tagslist()
339 i.reverse()
340 parity = paritygen(web.stripecount)
341
342 def entries(notip=False,limit=0, **map):
343 count = 0
344 for k, n in i:
345 if notip and k == "tip":
346 continue
347 if limit > 0 and count >= limit:
348 continue
349 count = count + 1
350 yield {"parity": parity.next(),
351 "tag": k,
352 "date": web.repo[n].date(),
353 "node": hex(n)}
354
355 return tmpl("tags",
356 node=hex(web.repo.changelog.tip()),
357 entries=lambda **x: entries(False,0, **x),
358 entriesnotip=lambda **x: entries(True,0, **x),
359 latestentry=lambda **x: entries(True,1, **x))
360
361 def branches(web, req, tmpl):
362 b = web.repo.branchtags()
363 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
364 heads = web.repo.heads()
365 parity = paritygen(web.stripecount)
366 sortkey = lambda ctx: ('close' not in ctx.extra(), ctx.rev())
367
368 def entries(limit, **map):
369 count = 0
370 for ctx in sorted(tips, key=sortkey, reverse=True):
371 if limit > 0 and count >= limit:
372 return
373 count += 1
374 if ctx.node() not in heads:
375 status = 'inactive'
376 elif not web.repo.branchheads(ctx.branch()):
377 status = 'closed'
378 else:
379 status = 'open'
380 yield {'parity': parity.next(),
381 'branch': ctx.branch(),
382 'status': status,
383 'node': ctx.hex(),
384 'date': ctx.date()}
385
386 return tmpl('branches', node=hex(web.repo.changelog.tip()),
387 entries=lambda **x: entries(0, **x),
388 latestentry=lambda **x: entries(1, **x))
389
390 def summary(web, req, tmpl):
391 i = web.repo.tagslist()
392 i.reverse()
393
394 def tagentries(**map):
395 parity = paritygen(web.stripecount)
396 count = 0
397 for k, n in i:
398 if k == "tip": # skip tip
399 continue
400
401 count += 1
402 if count > 10: # limit to 10 tags
403 break
404
405 yield tmpl("tagentry",
406 parity=parity.next(),
407 tag=k,
408 node=hex(n),
409 date=web.repo[n].date())
410
411 def branches(**map):
412 parity = paritygen(web.stripecount)
413
414 b = web.repo.branchtags()
415 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
416 for r,n,t in sorted(l):
417 yield {'parity': parity.next(),
418 'branch': t,
419 'node': hex(n),
420 'date': web.repo[n].date()}
421
422 def changelist(**map):
423 parity = paritygen(web.stripecount, offset=start-end)
424 l = [] # build a list in forward order for efficiency
425 for i in xrange(start, end):
426 ctx = web.repo[i]
427 n = ctx.node()
428 hn = hex(n)
429
430 l.insert(0, tmpl(
431 'shortlogentry',
432 parity=parity.next(),
433 author=ctx.user(),
434 desc=ctx.description(),
435 date=ctx.date(),
436 rev=i,
437 node=hn,
438 tags=webutil.nodetagsdict(web.repo, n),
439 inbranch=webutil.nodeinbranch(web.repo, ctx),
440 branches=webutil.nodebranchdict(web.repo, ctx)))
441
442 yield l
443
444 cl = web.repo.changelog
445 count = len(cl)
446 start = max(0, count - web.maxchanges)
447 end = min(count, start + web.maxchanges)
448
449 return tmpl("summary",
450 desc=web.config("web", "description", "unknown"),
451 owner=get_contact(web.config) or "unknown",
452 lastchange=cl.read(cl.tip())[2],
453 tags=tagentries,
454 branches=branches,
455 shortlog=changelist,
456 node=hex(cl.tip()),
457 archives=web.archivelist("tip"))
458
459 def filediff(web, req, tmpl):
460 fctx, ctx = None, None
461 try:
462 fctx = webutil.filectx(web.repo, req)
463 except LookupError:
464 ctx = webutil.changectx(web.repo, req)
465 path = webutil.cleanpath(web.repo, req.form['file'][0])
466 if path not in ctx.files():
467 raise
468
469 if fctx is not None:
470 n = fctx.node()
471 path = fctx.path()
472 else:
473 n = ctx.node()
474 # path already defined in except clause
475
476 parity = paritygen(web.stripecount)
477 diffs = webutil.diffs(web.repo, tmpl, fctx or ctx, [path], parity)
478 rename = fctx and webutil.renamelink(fctx) or []
479 ctx = fctx and fctx or ctx
480 return tmpl("filediff",
481 file=path,
482 node=hex(n),
483 rev=ctx.rev(),
484 date=ctx.date(),
485 desc=ctx.description(),
486 author=ctx.user(),
487 rename=rename,
488 branch=webutil.nodebranchnodefault(ctx),
489 parent=webutil.parents(ctx),
490 child=webutil.children(ctx),
491 diff=diffs)
492
493 diff = filediff
494
495 def annotate(web, req, tmpl):
496 fctx = webutil.filectx(web.repo, req)
497 f = fctx.path()
498 parity = paritygen(web.stripecount)
499
500 def annotate(**map):
501 last = None
502 if binary(fctx.data()):
503 mt = (mimetypes.guess_type(fctx.path())[0]
504 or 'application/octet-stream')
505 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
506 '(binary:%s)' % mt)])
507 else:
508 lines = enumerate(fctx.annotate(follow=True, linenumber=True))
509 for lineno, ((f, targetline), l) in lines:
510 fnode = f.filenode()
511
512 if last != fnode:
513 last = fnode
514
515 yield {"parity": parity.next(),
516 "node": hex(f.node()),
517 "rev": f.rev(),
518 "author": f.user(),
519 "desc": f.description(),
520 "file": f.path(),
521 "targetline": targetline,
522 "line": l,
523 "lineid": "l%d" % (lineno + 1),
524 "linenumber": "% 6d" % (lineno + 1)}
525
526 return tmpl("fileannotate",
527 file=f,
528 annotate=annotate,
529 path=webutil.up(f),
530 rev=fctx.rev(),
531 node=hex(fctx.node()),
532 author=fctx.user(),
533 date=fctx.date(),
534 desc=fctx.description(),
535 rename=webutil.renamelink(fctx),
536 branch=webutil.nodebranchnodefault(fctx),
537 parent=webutil.parents(fctx),
538 child=webutil.children(fctx),
539 permissions=fctx.manifest().flags(f))
540
541 def filelog(web, req, tmpl):
542
543 try:
544 fctx = webutil.filectx(web.repo, req)
545 f = fctx.path()
546 fl = fctx.filelog()
547 except error.LookupError:
548 f = webutil.cleanpath(web.repo, req.form['file'][0])
549 fl = web.repo.file(f)
550 numrevs = len(fl)
551 if not numrevs: # file doesn't exist at all
552 raise
553 rev = webutil.changectx(web.repo, req).rev()
554 first = fl.linkrev(0)
555 if rev < first: # current rev is from before file existed
556 raise
557 frev = numrevs - 1
558 while fl.linkrev(frev) > rev:
559 frev -= 1
560 fctx = web.repo.filectx(f, fl.linkrev(frev))
561
562 count = fctx.filerev() + 1
563 pagelen = web.maxshortchanges
564 start = max(0, fctx.filerev() - pagelen + 1) # first rev on this page
565 end = min(count, start + pagelen) # last rev on this page
566 parity = paritygen(web.stripecount, offset=start-end)
567
568 def entries(limit=0, **map):
569 l = []
570
571 repo = web.repo
572 for i in xrange(start, end):
573 iterfctx = fctx.filectx(i)
574
575 l.insert(0, {"parity": parity.next(),
576 "filerev": i,
577 "file": f,
578 "node": hex(iterfctx.node()),
579 "author": iterfctx.user(),
580 "date": iterfctx.date(),
581 "rename": webutil.renamelink(iterfctx),
582 "parent": webutil.parents(iterfctx),
583 "child": webutil.children(iterfctx),
584 "desc": iterfctx.description(),
585 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
586 "branch": webutil.nodebranchnodefault(iterfctx),
587 "inbranch": webutil.nodeinbranch(repo, iterfctx),
588 "branches": webutil.nodebranchdict(repo, iterfctx)})
589
590 if limit > 0:
591 l = l[:limit]
592
593 for e in l:
594 yield e
595
596 nodefunc = lambda x: fctx.filectx(fileid=x)
597 nav = webutil.revnavgen(end - 1, pagelen, count, nodefunc)
598 return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
599 entries=lambda **x: entries(limit=0, **x),
600 latestentry=lambda **x: entries(limit=1, **x))
601
602
603 def archive(web, req, tmpl):
604 type_ = req.form.get('type', [None])[0]
605 allowed = web.configlist("web", "allow_archive")
606 key = req.form['node'][0]
607
608 if type_ not in web.archives:
609 msg = 'Unsupported archive type: %s' % type_
610 raise ErrorResponse(HTTP_NOT_FOUND, msg)
611
612 if not ((type_ in allowed or
613 web.configbool("web", "allow" + type_, False))):
614 msg = 'Archive type not allowed: %s' % type_
615 raise ErrorResponse(HTTP_FORBIDDEN, msg)
616
617 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
618 cnode = web.repo.lookup(key)
619 arch_version = key
620 if cnode == key or key == 'tip':
621 arch_version = short(cnode)
622 name = "%s-%s" % (reponame, arch_version)
623 mimetype, artype, extension, encoding = web.archive_specs[type_]
624 headers = [
625 ('Content-Type', mimetype),
626 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
627 ]
628 if encoding:
629 headers.append(('Content-Encoding', encoding))
630 req.header(headers)
631 req.respond(HTTP_OK)
632 archival.archive(web.repo, req, cnode, artype, prefix=name)
633 return []
634
635
636 def static(web, req, tmpl):
637 fname = req.form['file'][0]
638 # a repo owner may set web.static in .hg/hgrc to get any file
639 # readable by the user running the CGI script
640 static = web.config("web", "static", None, untrusted=False)
641 if not static:
642 tp = web.templatepath or templater.templatepath()
643 if isinstance(tp, str):
644 tp = [tp]
645 static = [os.path.join(p, 'static') for p in tp]
646 return [staticfile(static, fname, req)]
647
648 def graph(web, req, tmpl):
649 rev = webutil.changectx(web.repo, req).rev()
650 bg_height = 39
651
652 revcount = 25
653 if 'revcount' in req.form:
654 revcount = int(req.form.get('revcount', [revcount])[0])
655 tmpl.defaults['sessionvars']['revcount'] = revcount
656
657 lessvars = copy.copy(tmpl.defaults['sessionvars'])
658 lessvars['revcount'] = revcount / 2
659 morevars = copy.copy(tmpl.defaults['sessionvars'])
660 morevars['revcount'] = revcount * 2
661
662 max_rev = len(web.repo) - 1
663 revcount = min(max_rev, revcount)
664 revnode = web.repo.changelog.node(rev)
665 revnode_hex = hex(revnode)
666 uprev = min(max_rev, rev + revcount)
667 downrev = max(0, rev - revcount)
668 count = len(web.repo)
669 changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
670
671 dag = graphmod.revisions(web.repo, rev, downrev)
672 tree = list(graphmod.colored(dag))
673 canvasheight = (len(tree) + 1) * bg_height - 27;
674 data = []
675 for (id, type, ctx, vtx, edges) in tree:
676 if type != graphmod.CHANGESET:
677 continue
678 node = short(ctx.node())
679 age = templatefilters.age(ctx.date())
680 desc = templatefilters.firstline(ctx.description())
681 desc = cgi.escape(templatefilters.nonempty(desc))
682 user = cgi.escape(templatefilters.person(ctx.user()))
683 branch = ctx.branch()
684 branch = branch, web.repo.branchtags().get(branch) == ctx.node()
685 data.append((node, vtx, edges, desc, user, age, branch, ctx.tags()))
686
687 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
688 lessvars=lessvars, morevars=morevars, downrev=downrev,
689 canvasheight=canvasheight, jsdata=data, bg_height=bg_height,
690 node=revnode_hex, changenav=changenav)