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