##// END OF EJS Templates
webutil: move from dict() construction to {} literals...
Augie Fackler -
r20681:52e5aca1 default
parent child Browse files
Show More
@@ -1,408 +1,408 b''
1 # hgweb/webutil.py - utility library for the web interface.
1 # hgweb/webutil.py - utility library for the web interface.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import os, copy
9 import os, copy
10 from mercurial import match, patch, error, ui, util, pathutil
10 from mercurial import match, patch, error, ui, util, pathutil
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12 from mercurial.node import hex, nullid
12 from mercurial.node import hex, nullid
13 from common import ErrorResponse
13 from common import ErrorResponse
14 from common import HTTP_NOT_FOUND
14 from common import HTTP_NOT_FOUND
15 import difflib
15 import difflib
16
16
17 def up(p):
17 def up(p):
18 if p[0] != "/":
18 if p[0] != "/":
19 p = "/" + p
19 p = "/" + p
20 if p[-1] == "/":
20 if p[-1] == "/":
21 p = p[:-1]
21 p = p[:-1]
22 up = os.path.dirname(p)
22 up = os.path.dirname(p)
23 if up == "/":
23 if up == "/":
24 return "/"
24 return "/"
25 return up + "/"
25 return up + "/"
26
26
27 def _navseq(step, firststep=None):
27 def _navseq(step, firststep=None):
28 if firststep:
28 if firststep:
29 yield firststep
29 yield firststep
30 if firststep >= 20 and firststep <= 40:
30 if firststep >= 20 and firststep <= 40:
31 firststep = 50
31 firststep = 50
32 yield firststep
32 yield firststep
33 assert step > 0
33 assert step > 0
34 assert firststep > 0
34 assert firststep > 0
35 while step <= firststep:
35 while step <= firststep:
36 step *= 10
36 step *= 10
37 while True:
37 while True:
38 yield 1 * step
38 yield 1 * step
39 yield 3 * step
39 yield 3 * step
40 step *= 10
40 step *= 10
41
41
42 class revnav(object):
42 class revnav(object):
43
43
44 def __init__(self, repo):
44 def __init__(self, repo):
45 """Navigation generation object
45 """Navigation generation object
46
46
47 :repo: repo object we generate nav for
47 :repo: repo object we generate nav for
48 """
48 """
49 # used for hex generation
49 # used for hex generation
50 self._revlog = repo.changelog
50 self._revlog = repo.changelog
51
51
52 def __nonzero__(self):
52 def __nonzero__(self):
53 """return True if any revision to navigate over"""
53 """return True if any revision to navigate over"""
54 return self._first() is not None
54 return self._first() is not None
55
55
56 def _first(self):
56 def _first(self):
57 """return the minimum non-filtered changeset or None"""
57 """return the minimum non-filtered changeset or None"""
58 try:
58 try:
59 return iter(self._revlog).next()
59 return iter(self._revlog).next()
60 except StopIteration:
60 except StopIteration:
61 return None
61 return None
62
62
63 def hex(self, rev):
63 def hex(self, rev):
64 return hex(self._revlog.node(rev))
64 return hex(self._revlog.node(rev))
65
65
66 def gen(self, pos, pagelen, limit):
66 def gen(self, pos, pagelen, limit):
67 """computes label and revision id for navigation link
67 """computes label and revision id for navigation link
68
68
69 :pos: is the revision relative to which we generate navigation.
69 :pos: is the revision relative to which we generate navigation.
70 :pagelen: the size of each navigation page
70 :pagelen: the size of each navigation page
71 :limit: how far shall we link
71 :limit: how far shall we link
72
72
73 The return is:
73 The return is:
74 - a single element tuple
74 - a single element tuple
75 - containing a dictionary with a `before` and `after` key
75 - containing a dictionary with a `before` and `after` key
76 - values are generator functions taking arbitrary number of kwargs
76 - values are generator functions taking arbitrary number of kwargs
77 - yield items are dictionaries with `label` and `node` keys
77 - yield items are dictionaries with `label` and `node` keys
78 """
78 """
79 if not self:
79 if not self:
80 # empty repo
80 # empty repo
81 return ({'before': (), 'after': ()},)
81 return ({'before': (), 'after': ()},)
82
82
83 targets = []
83 targets = []
84 for f in _navseq(1, pagelen):
84 for f in _navseq(1, pagelen):
85 if f > limit:
85 if f > limit:
86 break
86 break
87 targets.append(pos + f)
87 targets.append(pos + f)
88 targets.append(pos - f)
88 targets.append(pos - f)
89 targets.sort()
89 targets.sort()
90
90
91 first = self._first()
91 first = self._first()
92 navbefore = [("(%i)" % first, self.hex(first))]
92 navbefore = [("(%i)" % first, self.hex(first))]
93 navafter = []
93 navafter = []
94 for rev in targets:
94 for rev in targets:
95 if rev not in self._revlog:
95 if rev not in self._revlog:
96 continue
96 continue
97 if pos < rev < limit:
97 if pos < rev < limit:
98 navafter.append(("+%d" % abs(rev - pos), self.hex(rev)))
98 navafter.append(("+%d" % abs(rev - pos), self.hex(rev)))
99 if 0 < rev < pos:
99 if 0 < rev < pos:
100 navbefore.append(("-%d" % abs(rev - pos), self.hex(rev)))
100 navbefore.append(("-%d" % abs(rev - pos), self.hex(rev)))
101
101
102
102
103 navafter.append(("tip", "tip"))
103 navafter.append(("tip", "tip"))
104
104
105 data = lambda i: {"label": i[0], "node": i[1]}
105 data = lambda i: {"label": i[0], "node": i[1]}
106 return ({'before': lambda **map: (data(i) for i in navbefore),
106 return ({'before': lambda **map: (data(i) for i in navbefore),
107 'after': lambda **map: (data(i) for i in navafter)},)
107 'after': lambda **map: (data(i) for i in navafter)},)
108
108
109 class filerevnav(revnav):
109 class filerevnav(revnav):
110
110
111 def __init__(self, repo, path):
111 def __init__(self, repo, path):
112 """Navigation generation object
112 """Navigation generation object
113
113
114 :repo: repo object we generate nav for
114 :repo: repo object we generate nav for
115 :path: path of the file we generate nav for
115 :path: path of the file we generate nav for
116 """
116 """
117 # used for iteration
117 # used for iteration
118 self._changelog = repo.unfiltered().changelog
118 self._changelog = repo.unfiltered().changelog
119 # used for hex generation
119 # used for hex generation
120 self._revlog = repo.file(path)
120 self._revlog = repo.file(path)
121
121
122 def hex(self, rev):
122 def hex(self, rev):
123 return hex(self._changelog.node(self._revlog.linkrev(rev)))
123 return hex(self._changelog.node(self._revlog.linkrev(rev)))
124
124
125
125
126 def _siblings(siblings=[], hiderev=None):
126 def _siblings(siblings=[], hiderev=None):
127 siblings = [s for s in siblings if s.node() != nullid]
127 siblings = [s for s in siblings if s.node() != nullid]
128 if len(siblings) == 1 and siblings[0].rev() == hiderev:
128 if len(siblings) == 1 and siblings[0].rev() == hiderev:
129 return
129 return
130 for s in siblings:
130 for s in siblings:
131 d = {'node': s.hex(), 'rev': s.rev()}
131 d = {'node': s.hex(), 'rev': s.rev()}
132 d['user'] = s.user()
132 d['user'] = s.user()
133 d['date'] = s.date()
133 d['date'] = s.date()
134 d['description'] = s.description()
134 d['description'] = s.description()
135 d['branch'] = s.branch()
135 d['branch'] = s.branch()
136 if util.safehasattr(s, 'path'):
136 if util.safehasattr(s, 'path'):
137 d['file'] = s.path()
137 d['file'] = s.path()
138 yield d
138 yield d
139
139
140 def parents(ctx, hide=None):
140 def parents(ctx, hide=None):
141 return _siblings(ctx.parents(), hide)
141 return _siblings(ctx.parents(), hide)
142
142
143 def children(ctx, hide=None):
143 def children(ctx, hide=None):
144 return _siblings(ctx.children(), hide)
144 return _siblings(ctx.children(), hide)
145
145
146 def renamelink(fctx):
146 def renamelink(fctx):
147 r = fctx.renamed()
147 r = fctx.renamed()
148 if r:
148 if r:
149 return [dict(file=r[0], node=hex(r[1]))]
149 return [{'file': r[0], 'node': hex(r[1])}]
150 return []
150 return []
151
151
152 def nodetagsdict(repo, node):
152 def nodetagsdict(repo, node):
153 return [{"name": i} for i in repo.nodetags(node)]
153 return [{"name": i} for i in repo.nodetags(node)]
154
154
155 def nodebookmarksdict(repo, node):
155 def nodebookmarksdict(repo, node):
156 return [{"name": i} for i in repo.nodebookmarks(node)]
156 return [{"name": i} for i in repo.nodebookmarks(node)]
157
157
158 def nodebranchdict(repo, ctx):
158 def nodebranchdict(repo, ctx):
159 branches = []
159 branches = []
160 branch = ctx.branch()
160 branch = ctx.branch()
161 # If this is an empty repo, ctx.node() == nullid,
161 # If this is an empty repo, ctx.node() == nullid,
162 # ctx.branch() == 'default'.
162 # ctx.branch() == 'default'.
163 try:
163 try:
164 branchnode = repo.branchtip(branch)
164 branchnode = repo.branchtip(branch)
165 except error.RepoLookupError:
165 except error.RepoLookupError:
166 branchnode = None
166 branchnode = None
167 if branchnode == ctx.node():
167 if branchnode == ctx.node():
168 branches.append({"name": branch})
168 branches.append({"name": branch})
169 return branches
169 return branches
170
170
171 def nodeinbranch(repo, ctx):
171 def nodeinbranch(repo, ctx):
172 branches = []
172 branches = []
173 branch = ctx.branch()
173 branch = ctx.branch()
174 try:
174 try:
175 branchnode = repo.branchtip(branch)
175 branchnode = repo.branchtip(branch)
176 except error.RepoLookupError:
176 except error.RepoLookupError:
177 branchnode = None
177 branchnode = None
178 if branch != 'default' and branchnode != ctx.node():
178 if branch != 'default' and branchnode != ctx.node():
179 branches.append({"name": branch})
179 branches.append({"name": branch})
180 return branches
180 return branches
181
181
182 def nodebranchnodefault(ctx):
182 def nodebranchnodefault(ctx):
183 branches = []
183 branches = []
184 branch = ctx.branch()
184 branch = ctx.branch()
185 if branch != 'default':
185 if branch != 'default':
186 branches.append({"name": branch})
186 branches.append({"name": branch})
187 return branches
187 return branches
188
188
189 def showtag(repo, tmpl, t1, node=nullid, **args):
189 def showtag(repo, tmpl, t1, node=nullid, **args):
190 for t in repo.nodetags(node):
190 for t in repo.nodetags(node):
191 yield tmpl(t1, tag=t, **args)
191 yield tmpl(t1, tag=t, **args)
192
192
193 def showbookmark(repo, tmpl, t1, node=nullid, **args):
193 def showbookmark(repo, tmpl, t1, node=nullid, **args):
194 for t in repo.nodebookmarks(node):
194 for t in repo.nodebookmarks(node):
195 yield tmpl(t1, bookmark=t, **args)
195 yield tmpl(t1, bookmark=t, **args)
196
196
197 def cleanpath(repo, path):
197 def cleanpath(repo, path):
198 path = path.lstrip('/')
198 path = path.lstrip('/')
199 return pathutil.canonpath(repo.root, '', path)
199 return pathutil.canonpath(repo.root, '', path)
200
200
201 def changeidctx (repo, changeid):
201 def changeidctx (repo, changeid):
202 try:
202 try:
203 ctx = repo[changeid]
203 ctx = repo[changeid]
204 except error.RepoError:
204 except error.RepoError:
205 man = repo.manifest
205 man = repo.manifest
206 ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
206 ctx = repo[man.linkrev(man.rev(man.lookup(changeid)))]
207
207
208 return ctx
208 return ctx
209
209
210 def changectx (repo, req):
210 def changectx (repo, req):
211 changeid = "tip"
211 changeid = "tip"
212 if 'node' in req.form:
212 if 'node' in req.form:
213 changeid = req.form['node'][0]
213 changeid = req.form['node'][0]
214 ipos=changeid.find(':')
214 ipos=changeid.find(':')
215 if ipos != -1:
215 if ipos != -1:
216 changeid = changeid[(ipos + 1):]
216 changeid = changeid[(ipos + 1):]
217 elif 'manifest' in req.form:
217 elif 'manifest' in req.form:
218 changeid = req.form['manifest'][0]
218 changeid = req.form['manifest'][0]
219
219
220 return changeidctx(repo, changeid)
220 return changeidctx(repo, changeid)
221
221
222 def basechangectx(repo, req):
222 def basechangectx(repo, req):
223 if 'node' in req.form:
223 if 'node' in req.form:
224 changeid = req.form['node'][0]
224 changeid = req.form['node'][0]
225 ipos=changeid.find(':')
225 ipos=changeid.find(':')
226 if ipos != -1:
226 if ipos != -1:
227 changeid = changeid[:ipos]
227 changeid = changeid[:ipos]
228 return changeidctx(repo, changeid)
228 return changeidctx(repo, changeid)
229
229
230 return None
230 return None
231
231
232 def filectx(repo, req):
232 def filectx(repo, req):
233 if 'file' not in req.form:
233 if 'file' not in req.form:
234 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
234 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
235 path = cleanpath(repo, req.form['file'][0])
235 path = cleanpath(repo, req.form['file'][0])
236 if 'node' in req.form:
236 if 'node' in req.form:
237 changeid = req.form['node'][0]
237 changeid = req.form['node'][0]
238 elif 'filenode' in req.form:
238 elif 'filenode' in req.form:
239 changeid = req.form['filenode'][0]
239 changeid = req.form['filenode'][0]
240 else:
240 else:
241 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given')
241 raise ErrorResponse(HTTP_NOT_FOUND, 'node or filenode not given')
242 try:
242 try:
243 fctx = repo[changeid][path]
243 fctx = repo[changeid][path]
244 except error.RepoError:
244 except error.RepoError:
245 fctx = repo.filectx(path, fileid=changeid)
245 fctx = repo.filectx(path, fileid=changeid)
246
246
247 return fctx
247 return fctx
248
248
249 def listfilediffs(tmpl, files, node, max):
249 def listfilediffs(tmpl, files, node, max):
250 for f in files[:max]:
250 for f in files[:max]:
251 yield tmpl('filedifflink', node=hex(node), file=f)
251 yield tmpl('filedifflink', node=hex(node), file=f)
252 if len(files) > max:
252 if len(files) > max:
253 yield tmpl('fileellipses')
253 yield tmpl('fileellipses')
254
254
255 def diffs(repo, tmpl, ctx, basectx, files, parity, style):
255 def diffs(repo, tmpl, ctx, basectx, files, parity, style):
256
256
257 def countgen():
257 def countgen():
258 start = 1
258 start = 1
259 while True:
259 while True:
260 yield start
260 yield start
261 start += 1
261 start += 1
262
262
263 blockcount = countgen()
263 blockcount = countgen()
264 def prettyprintlines(diff, blockno):
264 def prettyprintlines(diff, blockno):
265 for lineno, l in enumerate(diff.splitlines(True)):
265 for lineno, l in enumerate(diff.splitlines(True)):
266 lineno = "%d.%d" % (blockno, lineno + 1)
266 lineno = "%d.%d" % (blockno, lineno + 1)
267 if l.startswith('+'):
267 if l.startswith('+'):
268 ltype = "difflineplus"
268 ltype = "difflineplus"
269 elif l.startswith('-'):
269 elif l.startswith('-'):
270 ltype = "difflineminus"
270 ltype = "difflineminus"
271 elif l.startswith('@'):
271 elif l.startswith('@'):
272 ltype = "difflineat"
272 ltype = "difflineat"
273 else:
273 else:
274 ltype = "diffline"
274 ltype = "diffline"
275 yield tmpl(ltype,
275 yield tmpl(ltype,
276 line=l,
276 line=l,
277 lineid="l%s" % lineno,
277 lineid="l%s" % lineno,
278 linenumber="% 8s" % lineno)
278 linenumber="% 8s" % lineno)
279
279
280 if files:
280 if files:
281 m = match.exact(repo.root, repo.getcwd(), files)
281 m = match.exact(repo.root, repo.getcwd(), files)
282 else:
282 else:
283 m = match.always(repo.root, repo.getcwd())
283 m = match.always(repo.root, repo.getcwd())
284
284
285 diffopts = patch.diffopts(repo.ui, untrusted=True)
285 diffopts = patch.diffopts(repo.ui, untrusted=True)
286 if basectx is None:
286 if basectx is None:
287 parents = ctx.parents()
287 parents = ctx.parents()
288 node1 = parents and parents[0].node() or nullid
288 node1 = parents and parents[0].node() or nullid
289 else:
289 else:
290 node1 = basectx.node()
290 node1 = basectx.node()
291 node2 = ctx.node()
291 node2 = ctx.node()
292
292
293 block = []
293 block = []
294 for chunk in patch.diff(repo, node1, node2, m, opts=diffopts):
294 for chunk in patch.diff(repo, node1, node2, m, opts=diffopts):
295 if chunk.startswith('diff') and block:
295 if chunk.startswith('diff') and block:
296 blockno = blockcount.next()
296 blockno = blockcount.next()
297 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
297 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
298 lines=prettyprintlines(''.join(block), blockno))
298 lines=prettyprintlines(''.join(block), blockno))
299 block = []
299 block = []
300 if chunk.startswith('diff') and style != 'raw':
300 if chunk.startswith('diff') and style != 'raw':
301 chunk = ''.join(chunk.splitlines(True)[1:])
301 chunk = ''.join(chunk.splitlines(True)[1:])
302 block.append(chunk)
302 block.append(chunk)
303 blockno = blockcount.next()
303 blockno = blockcount.next()
304 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
304 yield tmpl('diffblock', parity=parity.next(), blockno=blockno,
305 lines=prettyprintlines(''.join(block), blockno))
305 lines=prettyprintlines(''.join(block), blockno))
306
306
307 def compare(tmpl, context, leftlines, rightlines):
307 def compare(tmpl, context, leftlines, rightlines):
308 '''Generator function that provides side-by-side comparison data.'''
308 '''Generator function that provides side-by-side comparison data.'''
309
309
310 def compline(type, leftlineno, leftline, rightlineno, rightline):
310 def compline(type, leftlineno, leftline, rightlineno, rightline):
311 lineid = leftlineno and ("l%s" % leftlineno) or ''
311 lineid = leftlineno and ("l%s" % leftlineno) or ''
312 lineid += rightlineno and ("r%s" % rightlineno) or ''
312 lineid += rightlineno and ("r%s" % rightlineno) or ''
313 return tmpl('comparisonline',
313 return tmpl('comparisonline',
314 type=type,
314 type=type,
315 lineid=lineid,
315 lineid=lineid,
316 leftlinenumber="% 6s" % (leftlineno or ''),
316 leftlinenumber="% 6s" % (leftlineno or ''),
317 leftline=leftline or '',
317 leftline=leftline or '',
318 rightlinenumber="% 6s" % (rightlineno or ''),
318 rightlinenumber="% 6s" % (rightlineno or ''),
319 rightline=rightline or '')
319 rightline=rightline or '')
320
320
321 def getblock(opcodes):
321 def getblock(opcodes):
322 for type, llo, lhi, rlo, rhi in opcodes:
322 for type, llo, lhi, rlo, rhi in opcodes:
323 len1 = lhi - llo
323 len1 = lhi - llo
324 len2 = rhi - rlo
324 len2 = rhi - rlo
325 count = min(len1, len2)
325 count = min(len1, len2)
326 for i in xrange(count):
326 for i in xrange(count):
327 yield compline(type=type,
327 yield compline(type=type,
328 leftlineno=llo + i + 1,
328 leftlineno=llo + i + 1,
329 leftline=leftlines[llo + i],
329 leftline=leftlines[llo + i],
330 rightlineno=rlo + i + 1,
330 rightlineno=rlo + i + 1,
331 rightline=rightlines[rlo + i])
331 rightline=rightlines[rlo + i])
332 if len1 > len2:
332 if len1 > len2:
333 for i in xrange(llo + count, lhi):
333 for i in xrange(llo + count, lhi):
334 yield compline(type=type,
334 yield compline(type=type,
335 leftlineno=i + 1,
335 leftlineno=i + 1,
336 leftline=leftlines[i],
336 leftline=leftlines[i],
337 rightlineno=None,
337 rightlineno=None,
338 rightline=None)
338 rightline=None)
339 elif len2 > len1:
339 elif len2 > len1:
340 for i in xrange(rlo + count, rhi):
340 for i in xrange(rlo + count, rhi):
341 yield compline(type=type,
341 yield compline(type=type,
342 leftlineno=None,
342 leftlineno=None,
343 leftline=None,
343 leftline=None,
344 rightlineno=i + 1,
344 rightlineno=i + 1,
345 rightline=rightlines[i])
345 rightline=rightlines[i])
346
346
347 s = difflib.SequenceMatcher(None, leftlines, rightlines)
347 s = difflib.SequenceMatcher(None, leftlines, rightlines)
348 if context < 0:
348 if context < 0:
349 yield tmpl('comparisonblock', lines=getblock(s.get_opcodes()))
349 yield tmpl('comparisonblock', lines=getblock(s.get_opcodes()))
350 else:
350 else:
351 for oc in s.get_grouped_opcodes(n=context):
351 for oc in s.get_grouped_opcodes(n=context):
352 yield tmpl('comparisonblock', lines=getblock(oc))
352 yield tmpl('comparisonblock', lines=getblock(oc))
353
353
354 def diffstatgen(ctx, basectx):
354 def diffstatgen(ctx, basectx):
355 '''Generator function that provides the diffstat data.'''
355 '''Generator function that provides the diffstat data.'''
356
356
357 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx)))
357 stats = patch.diffstatdata(util.iterlines(ctx.diff(basectx)))
358 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
358 maxname, maxtotal, addtotal, removetotal, binary = patch.diffstatsum(stats)
359 while True:
359 while True:
360 yield stats, maxname, maxtotal, addtotal, removetotal, binary
360 yield stats, maxname, maxtotal, addtotal, removetotal, binary
361
361
362 def diffsummary(statgen):
362 def diffsummary(statgen):
363 '''Return a short summary of the diff.'''
363 '''Return a short summary of the diff.'''
364
364
365 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
365 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
366 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
366 return _(' %d files changed, %d insertions(+), %d deletions(-)\n') % (
367 len(stats), addtotal, removetotal)
367 len(stats), addtotal, removetotal)
368
368
369 def diffstat(tmpl, ctx, statgen, parity):
369 def diffstat(tmpl, ctx, statgen, parity):
370 '''Return a diffstat template for each file in the diff.'''
370 '''Return a diffstat template for each file in the diff.'''
371
371
372 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
372 stats, maxname, maxtotal, addtotal, removetotal, binary = statgen.next()
373 files = ctx.files()
373 files = ctx.files()
374
374
375 def pct(i):
375 def pct(i):
376 if maxtotal == 0:
376 if maxtotal == 0:
377 return 0
377 return 0
378 return (float(i) / maxtotal) * 100
378 return (float(i) / maxtotal) * 100
379
379
380 fileno = 0
380 fileno = 0
381 for filename, adds, removes, isbinary in stats:
381 for filename, adds, removes, isbinary in stats:
382 template = filename in files and 'diffstatlink' or 'diffstatnolink'
382 template = filename in files and 'diffstatlink' or 'diffstatnolink'
383 total = adds + removes
383 total = adds + removes
384 fileno += 1
384 fileno += 1
385 yield tmpl(template, node=ctx.hex(), file=filename, fileno=fileno,
385 yield tmpl(template, node=ctx.hex(), file=filename, fileno=fileno,
386 total=total, addpct=pct(adds), removepct=pct(removes),
386 total=total, addpct=pct(adds), removepct=pct(removes),
387 parity=parity.next())
387 parity=parity.next())
388
388
389 class sessionvars(object):
389 class sessionvars(object):
390 def __init__(self, vars, start='?'):
390 def __init__(self, vars, start='?'):
391 self.start = start
391 self.start = start
392 self.vars = vars
392 self.vars = vars
393 def __getitem__(self, key):
393 def __getitem__(self, key):
394 return self.vars[key]
394 return self.vars[key]
395 def __setitem__(self, key, value):
395 def __setitem__(self, key, value):
396 self.vars[key] = value
396 self.vars[key] = value
397 def __copy__(self):
397 def __copy__(self):
398 return sessionvars(copy.copy(self.vars), self.start)
398 return sessionvars(copy.copy(self.vars), self.start)
399 def __iter__(self):
399 def __iter__(self):
400 separator = self.start
400 separator = self.start
401 for key, value in sorted(self.vars.iteritems()):
401 for key, value in sorted(self.vars.iteritems()):
402 yield {'name': key, 'value': str(value), 'separator': separator}
402 yield {'name': key, 'value': str(value), 'separator': separator}
403 separator = '&'
403 separator = '&'
404
404
405 class wsgiui(ui.ui):
405 class wsgiui(ui.ui):
406 # default termwidth breaks under mod_wsgi
406 # default termwidth breaks under mod_wsgi
407 def termwidth(self):
407 def termwidth(self):
408 return 80
408 return 80
General Comments 0
You need to be logged in to leave comments. Login now