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