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