##// END OF EJS Templates
hgweb: avoid initialization race (issue3953)
Matt Mackall -
r20168:d4be314b stable
parent child Browse files
Show More
@@ -1,391 +1,393
1 # hgweb/hgweb_mod.py - Web interface for a repository.
1 # hgweb/hgweb_mod.py - Web interface for a repository.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import os
9 import os
10 from mercurial import ui, hg, hook, error, encoding, templater, util, repoview
10 from mercurial import ui, hg, hook, error, encoding, templater, util, repoview
11 from mercurial.templatefilters import websub
11 from mercurial.templatefilters import websub
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13 from common import get_stat, ErrorResponse, permhooks, caching
13 from common import get_stat, ErrorResponse, permhooks, caching
14 from common import HTTP_OK, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST
14 from common import HTTP_OK, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST
15 from common import HTTP_NOT_FOUND, HTTP_SERVER_ERROR
15 from common import HTTP_NOT_FOUND, HTTP_SERVER_ERROR
16 from request import wsgirequest
16 from request import wsgirequest
17 import webcommands, protocol, webutil, re
17 import webcommands, protocol, webutil, re
18
18
19 perms = {
19 perms = {
20 'changegroup': 'pull',
20 'changegroup': 'pull',
21 'changegroupsubset': 'pull',
21 'changegroupsubset': 'pull',
22 'getbundle': 'pull',
22 'getbundle': 'pull',
23 'stream_out': 'pull',
23 'stream_out': 'pull',
24 'listkeys': 'pull',
24 'listkeys': 'pull',
25 'unbundle': 'push',
25 'unbundle': 'push',
26 'pushkey': 'push',
26 'pushkey': 'push',
27 }
27 }
28
28
29 def makebreadcrumb(url, prefix=''):
29 def makebreadcrumb(url, prefix=''):
30 '''Return a 'URL breadcrumb' list
30 '''Return a 'URL breadcrumb' list
31
31
32 A 'URL breadcrumb' is a list of URL-name pairs,
32 A 'URL breadcrumb' is a list of URL-name pairs,
33 corresponding to each of the path items on a URL.
33 corresponding to each of the path items on a URL.
34 This can be used to create path navigation entries.
34 This can be used to create path navigation entries.
35 '''
35 '''
36 if url.endswith('/'):
36 if url.endswith('/'):
37 url = url[:-1]
37 url = url[:-1]
38 if prefix:
38 if prefix:
39 url = '/' + prefix + url
39 url = '/' + prefix + url
40 relpath = url
40 relpath = url
41 if relpath.startswith('/'):
41 if relpath.startswith('/'):
42 relpath = relpath[1:]
42 relpath = relpath[1:]
43
43
44 breadcrumb = []
44 breadcrumb = []
45 urlel = url
45 urlel = url
46 pathitems = [''] + relpath.split('/')
46 pathitems = [''] + relpath.split('/')
47 for pathel in reversed(pathitems):
47 for pathel in reversed(pathitems):
48 if not pathel or not urlel:
48 if not pathel or not urlel:
49 break
49 break
50 breadcrumb.append({'url': urlel, 'name': pathel})
50 breadcrumb.append({'url': urlel, 'name': pathel})
51 urlel = os.path.dirname(urlel)
51 urlel = os.path.dirname(urlel)
52 return reversed(breadcrumb)
52 return reversed(breadcrumb)
53
53
54
54
55 class hgweb(object):
55 class hgweb(object):
56 def __init__(self, repo, name=None, baseui=None):
56 def __init__(self, repo, name=None, baseui=None):
57 if isinstance(repo, str):
57 if isinstance(repo, str):
58 if baseui:
58 if baseui:
59 u = baseui.copy()
59 u = baseui.copy()
60 else:
60 else:
61 u = ui.ui()
61 u = ui.ui()
62 self.repo = hg.repository(u, repo)
62 r = hg.repository(u, repo)
63 else:
63 else:
64 self.repo = repo
64 r = repo
65
65
66 self.repo = self._getview(self.repo)
66 r = self._getview(r)
67 self.repo.ui.setconfig('ui', 'report_untrusted', 'off')
67 r.ui.setconfig('ui', 'report_untrusted', 'off')
68 self.repo.baseui.setconfig('ui', 'report_untrusted', 'off')
68 r.baseui.setconfig('ui', 'report_untrusted', 'off')
69 self.repo.ui.setconfig('ui', 'nontty', 'true')
69 r.ui.setconfig('ui', 'nontty', 'true')
70 self.repo.baseui.setconfig('ui', 'nontty', 'true')
70 r.baseui.setconfig('ui', 'nontty', 'true')
71 self.repo = r
71 hook.redirect(True)
72 hook.redirect(True)
72 self.mtime = -1
73 self.mtime = -1
73 self.size = -1
74 self.size = -1
74 self.reponame = name
75 self.reponame = name
75 self.archives = 'zip', 'gz', 'bz2'
76 self.archives = 'zip', 'gz', 'bz2'
76 self.stripecount = 1
77 self.stripecount = 1
77 # a repo owner may set web.templates in .hg/hgrc to get any file
78 # a repo owner may set web.templates in .hg/hgrc to get any file
78 # readable by the user running the CGI script
79 # readable by the user running the CGI script
79 self.templatepath = self.config('web', 'templates')
80 self.templatepath = self.config('web', 'templates')
80 self.websubtable = self.loadwebsub()
81 self.websubtable = self.loadwebsub()
81
82
82 # The CGI scripts are often run by a user different from the repo owner.
83 # The CGI scripts are often run by a user different from the repo owner.
83 # Trust the settings from the .hg/hgrc files by default.
84 # Trust the settings from the .hg/hgrc files by default.
84 def config(self, section, name, default=None, untrusted=True):
85 def config(self, section, name, default=None, untrusted=True):
85 return self.repo.ui.config(section, name, default,
86 return self.repo.ui.config(section, name, default,
86 untrusted=untrusted)
87 untrusted=untrusted)
87
88
88 def configbool(self, section, name, default=False, untrusted=True):
89 def configbool(self, section, name, default=False, untrusted=True):
89 return self.repo.ui.configbool(section, name, default,
90 return self.repo.ui.configbool(section, name, default,
90 untrusted=untrusted)
91 untrusted=untrusted)
91
92
92 def configlist(self, section, name, default=None, untrusted=True):
93 def configlist(self, section, name, default=None, untrusted=True):
93 return self.repo.ui.configlist(section, name, default,
94 return self.repo.ui.configlist(section, name, default,
94 untrusted=untrusted)
95 untrusted=untrusted)
95
96
96 def _getview(self, repo):
97 def _getview(self, repo):
97 viewconfig = self.config('web', 'view', 'served')
98 viewconfig = repo.ui.config('web', 'view', 'served',
99 untrusted=True)
98 if viewconfig == 'all':
100 if viewconfig == 'all':
99 return repo.unfiltered()
101 return repo.unfiltered()
100 elif viewconfig in repoview.filtertable:
102 elif viewconfig in repoview.filtertable:
101 return repo.filtered(viewconfig)
103 return repo.filtered(viewconfig)
102 else:
104 else:
103 return repo.filtered('served')
105 return repo.filtered('served')
104
106
105 def refresh(self, request=None):
107 def refresh(self, request=None):
106 st = get_stat(self.repo.spath)
108 st = get_stat(self.repo.spath)
107 # compare changelog size in addition to mtime to catch
109 # compare changelog size in addition to mtime to catch
108 # rollbacks made less than a second ago
110 # rollbacks made less than a second ago
109 if st.st_mtime != self.mtime or st.st_size != self.size:
111 if st.st_mtime != self.mtime or st.st_size != self.size:
110 self.mtime = st.st_mtime
112 self.mtime = st.st_mtime
111 self.size = st.st_size
113 self.size = st.st_size
112 r = hg.repository(self.repo.baseui, self.repo.root)
114 r = hg.repository(self.repo.baseui, self.repo.root)
113 self.repo = self._getview(r)
115 self.repo = self._getview(r)
114 self.maxchanges = int(self.config("web", "maxchanges", 10))
116 self.maxchanges = int(self.config("web", "maxchanges", 10))
115 self.stripecount = int(self.config("web", "stripes", 1))
117 self.stripecount = int(self.config("web", "stripes", 1))
116 self.maxshortchanges = int(self.config("web", "maxshortchanges",
118 self.maxshortchanges = int(self.config("web", "maxshortchanges",
117 60))
119 60))
118 self.maxfiles = int(self.config("web", "maxfiles", 10))
120 self.maxfiles = int(self.config("web", "maxfiles", 10))
119 self.allowpull = self.configbool("web", "allowpull", True)
121 self.allowpull = self.configbool("web", "allowpull", True)
120 encoding.encoding = self.config("web", "encoding",
122 encoding.encoding = self.config("web", "encoding",
121 encoding.encoding)
123 encoding.encoding)
122 if request:
124 if request:
123 self.repo.ui.environ = request.env
125 self.repo.ui.environ = request.env
124
126
125 def run(self):
127 def run(self):
126 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
128 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
127 raise RuntimeError("This function is only intended to be "
129 raise RuntimeError("This function is only intended to be "
128 "called while running as a CGI script.")
130 "called while running as a CGI script.")
129 import mercurial.hgweb.wsgicgi as wsgicgi
131 import mercurial.hgweb.wsgicgi as wsgicgi
130 wsgicgi.launch(self)
132 wsgicgi.launch(self)
131
133
132 def __call__(self, env, respond):
134 def __call__(self, env, respond):
133 req = wsgirequest(env, respond)
135 req = wsgirequest(env, respond)
134 return self.run_wsgi(req)
136 return self.run_wsgi(req)
135
137
136 def run_wsgi(self, req):
138 def run_wsgi(self, req):
137
139
138 self.refresh(req)
140 self.refresh(req)
139
141
140 # work with CGI variables to create coherent structure
142 # work with CGI variables to create coherent structure
141 # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
143 # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
142
144
143 req.url = req.env['SCRIPT_NAME']
145 req.url = req.env['SCRIPT_NAME']
144 if not req.url.endswith('/'):
146 if not req.url.endswith('/'):
145 req.url += '/'
147 req.url += '/'
146 if 'REPO_NAME' in req.env:
148 if 'REPO_NAME' in req.env:
147 req.url += req.env['REPO_NAME'] + '/'
149 req.url += req.env['REPO_NAME'] + '/'
148
150
149 if 'PATH_INFO' in req.env:
151 if 'PATH_INFO' in req.env:
150 parts = req.env['PATH_INFO'].strip('/').split('/')
152 parts = req.env['PATH_INFO'].strip('/').split('/')
151 repo_parts = req.env.get('REPO_NAME', '').split('/')
153 repo_parts = req.env.get('REPO_NAME', '').split('/')
152 if parts[:len(repo_parts)] == repo_parts:
154 if parts[:len(repo_parts)] == repo_parts:
153 parts = parts[len(repo_parts):]
155 parts = parts[len(repo_parts):]
154 query = '/'.join(parts)
156 query = '/'.join(parts)
155 else:
157 else:
156 query = req.env['QUERY_STRING'].split('&', 1)[0]
158 query = req.env['QUERY_STRING'].split('&', 1)[0]
157 query = query.split(';', 1)[0]
159 query = query.split(';', 1)[0]
158
160
159 # process this if it's a protocol request
161 # process this if it's a protocol request
160 # protocol bits don't need to create any URLs
162 # protocol bits don't need to create any URLs
161 # and the clients always use the old URL structure
163 # and the clients always use the old URL structure
162
164
163 cmd = req.form.get('cmd', [''])[0]
165 cmd = req.form.get('cmd', [''])[0]
164 if protocol.iscmd(cmd):
166 if protocol.iscmd(cmd):
165 try:
167 try:
166 if query:
168 if query:
167 raise ErrorResponse(HTTP_NOT_FOUND)
169 raise ErrorResponse(HTTP_NOT_FOUND)
168 if cmd in perms:
170 if cmd in perms:
169 self.check_perm(req, perms[cmd])
171 self.check_perm(req, perms[cmd])
170 return protocol.call(self.repo, req, cmd)
172 return protocol.call(self.repo, req, cmd)
171 except ErrorResponse, inst:
173 except ErrorResponse, inst:
172 # A client that sends unbundle without 100-continue will
174 # A client that sends unbundle without 100-continue will
173 # break if we respond early.
175 # break if we respond early.
174 if (cmd == 'unbundle' and
176 if (cmd == 'unbundle' and
175 (req.env.get('HTTP_EXPECT',
177 (req.env.get('HTTP_EXPECT',
176 '').lower() != '100-continue') or
178 '').lower() != '100-continue') or
177 req.env.get('X-HgHttp2', '')):
179 req.env.get('X-HgHttp2', '')):
178 req.drain()
180 req.drain()
179 else:
181 else:
180 req.headers.append(('Connection', 'Close'))
182 req.headers.append(('Connection', 'Close'))
181 req.respond(inst, protocol.HGTYPE,
183 req.respond(inst, protocol.HGTYPE,
182 body='0\n%s\n' % inst.message)
184 body='0\n%s\n' % inst.message)
183 return ''
185 return ''
184
186
185 # translate user-visible url structure to internal structure
187 # translate user-visible url structure to internal structure
186
188
187 args = query.split('/', 2)
189 args = query.split('/', 2)
188 if 'cmd' not in req.form and args and args[0]:
190 if 'cmd' not in req.form and args and args[0]:
189
191
190 cmd = args.pop(0)
192 cmd = args.pop(0)
191 style = cmd.rfind('-')
193 style = cmd.rfind('-')
192 if style != -1:
194 if style != -1:
193 req.form['style'] = [cmd[:style]]
195 req.form['style'] = [cmd[:style]]
194 cmd = cmd[style + 1:]
196 cmd = cmd[style + 1:]
195
197
196 # avoid accepting e.g. style parameter as command
198 # avoid accepting e.g. style parameter as command
197 if util.safehasattr(webcommands, cmd):
199 if util.safehasattr(webcommands, cmd):
198 req.form['cmd'] = [cmd]
200 req.form['cmd'] = [cmd]
199 else:
201 else:
200 cmd = ''
202 cmd = ''
201
203
202 if cmd == 'static':
204 if cmd == 'static':
203 req.form['file'] = ['/'.join(args)]
205 req.form['file'] = ['/'.join(args)]
204 else:
206 else:
205 if args and args[0]:
207 if args and args[0]:
206 node = args.pop(0)
208 node = args.pop(0)
207 req.form['node'] = [node]
209 req.form['node'] = [node]
208 if args:
210 if args:
209 req.form['file'] = args
211 req.form['file'] = args
210
212
211 ua = req.env.get('HTTP_USER_AGENT', '')
213 ua = req.env.get('HTTP_USER_AGENT', '')
212 if cmd == 'rev' and 'mercurial' in ua:
214 if cmd == 'rev' and 'mercurial' in ua:
213 req.form['style'] = ['raw']
215 req.form['style'] = ['raw']
214
216
215 if cmd == 'archive':
217 if cmd == 'archive':
216 fn = req.form['node'][0]
218 fn = req.form['node'][0]
217 for type_, spec in self.archive_specs.iteritems():
219 for type_, spec in self.archive_specs.iteritems():
218 ext = spec[2]
220 ext = spec[2]
219 if fn.endswith(ext):
221 if fn.endswith(ext):
220 req.form['node'] = [fn[:-len(ext)]]
222 req.form['node'] = [fn[:-len(ext)]]
221 req.form['type'] = [type_]
223 req.form['type'] = [type_]
222
224
223 # process the web interface request
225 # process the web interface request
224
226
225 try:
227 try:
226 tmpl = self.templater(req)
228 tmpl = self.templater(req)
227 ctype = tmpl('mimetype', encoding=encoding.encoding)
229 ctype = tmpl('mimetype', encoding=encoding.encoding)
228 ctype = templater.stringify(ctype)
230 ctype = templater.stringify(ctype)
229
231
230 # check read permissions non-static content
232 # check read permissions non-static content
231 if cmd != 'static':
233 if cmd != 'static':
232 self.check_perm(req, None)
234 self.check_perm(req, None)
233
235
234 if cmd == '':
236 if cmd == '':
235 req.form['cmd'] = [tmpl.cache['default']]
237 req.form['cmd'] = [tmpl.cache['default']]
236 cmd = req.form['cmd'][0]
238 cmd = req.form['cmd'][0]
237
239
238 if self.configbool('web', 'cache', True):
240 if self.configbool('web', 'cache', True):
239 caching(self, req) # sets ETag header or raises NOT_MODIFIED
241 caching(self, req) # sets ETag header or raises NOT_MODIFIED
240 if cmd not in webcommands.__all__:
242 if cmd not in webcommands.__all__:
241 msg = 'no such method: %s' % cmd
243 msg = 'no such method: %s' % cmd
242 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
244 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
243 elif cmd == 'file' and 'raw' in req.form.get('style', []):
245 elif cmd == 'file' and 'raw' in req.form.get('style', []):
244 self.ctype = ctype
246 self.ctype = ctype
245 content = webcommands.rawfile(self, req, tmpl)
247 content = webcommands.rawfile(self, req, tmpl)
246 else:
248 else:
247 content = getattr(webcommands, cmd)(self, req, tmpl)
249 content = getattr(webcommands, cmd)(self, req, tmpl)
248 req.respond(HTTP_OK, ctype)
250 req.respond(HTTP_OK, ctype)
249
251
250 return content
252 return content
251
253
252 except (error.LookupError, error.RepoLookupError), err:
254 except (error.LookupError, error.RepoLookupError), err:
253 req.respond(HTTP_NOT_FOUND, ctype)
255 req.respond(HTTP_NOT_FOUND, ctype)
254 msg = str(err)
256 msg = str(err)
255 if (util.safehasattr(err, 'name') and
257 if (util.safehasattr(err, 'name') and
256 not isinstance(err, error.ManifestLookupError)):
258 not isinstance(err, error.ManifestLookupError)):
257 msg = 'revision not found: %s' % err.name
259 msg = 'revision not found: %s' % err.name
258 return tmpl('error', error=msg)
260 return tmpl('error', error=msg)
259 except (error.RepoError, error.RevlogError), inst:
261 except (error.RepoError, error.RevlogError), inst:
260 req.respond(HTTP_SERVER_ERROR, ctype)
262 req.respond(HTTP_SERVER_ERROR, ctype)
261 return tmpl('error', error=str(inst))
263 return tmpl('error', error=str(inst))
262 except ErrorResponse, inst:
264 except ErrorResponse, inst:
263 req.respond(inst, ctype)
265 req.respond(inst, ctype)
264 if inst.code == HTTP_NOT_MODIFIED:
266 if inst.code == HTTP_NOT_MODIFIED:
265 # Not allowed to return a body on a 304
267 # Not allowed to return a body on a 304
266 return ['']
268 return ['']
267 return tmpl('error', error=inst.message)
269 return tmpl('error', error=inst.message)
268
270
269 def loadwebsub(self):
271 def loadwebsub(self):
270 websubtable = []
272 websubtable = []
271 websubdefs = self.repo.ui.configitems('websub')
273 websubdefs = self.repo.ui.configitems('websub')
272 # we must maintain interhg backwards compatibility
274 # we must maintain interhg backwards compatibility
273 websubdefs += self.repo.ui.configitems('interhg')
275 websubdefs += self.repo.ui.configitems('interhg')
274 for key, pattern in websubdefs:
276 for key, pattern in websubdefs:
275 # grab the delimiter from the character after the "s"
277 # grab the delimiter from the character after the "s"
276 unesc = pattern[1]
278 unesc = pattern[1]
277 delim = re.escape(unesc)
279 delim = re.escape(unesc)
278
280
279 # identify portions of the pattern, taking care to avoid escaped
281 # identify portions of the pattern, taking care to avoid escaped
280 # delimiters. the replace format and flags are optional, but
282 # delimiters. the replace format and flags are optional, but
281 # delimiters are required.
283 # delimiters are required.
282 match = re.match(
284 match = re.match(
283 r'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
285 r'^s%s(.+)(?:(?<=\\\\)|(?<!\\))%s(.*)%s([ilmsux])*$'
284 % (delim, delim, delim), pattern)
286 % (delim, delim, delim), pattern)
285 if not match:
287 if not match:
286 self.repo.ui.warn(_("websub: invalid pattern for %s: %s\n")
288 self.repo.ui.warn(_("websub: invalid pattern for %s: %s\n")
287 % (key, pattern))
289 % (key, pattern))
288 continue
290 continue
289
291
290 # we need to unescape the delimiter for regexp and format
292 # we need to unescape the delimiter for regexp and format
291 delim_re = re.compile(r'(?<!\\)\\%s' % delim)
293 delim_re = re.compile(r'(?<!\\)\\%s' % delim)
292 regexp = delim_re.sub(unesc, match.group(1))
294 regexp = delim_re.sub(unesc, match.group(1))
293 format = delim_re.sub(unesc, match.group(2))
295 format = delim_re.sub(unesc, match.group(2))
294
296
295 # the pattern allows for 6 regexp flags, so set them if necessary
297 # the pattern allows for 6 regexp flags, so set them if necessary
296 flagin = match.group(3)
298 flagin = match.group(3)
297 flags = 0
299 flags = 0
298 if flagin:
300 if flagin:
299 for flag in flagin.upper():
301 for flag in flagin.upper():
300 flags |= re.__dict__[flag]
302 flags |= re.__dict__[flag]
301
303
302 try:
304 try:
303 regexp = re.compile(regexp, flags)
305 regexp = re.compile(regexp, flags)
304 websubtable.append((regexp, format))
306 websubtable.append((regexp, format))
305 except re.error:
307 except re.error:
306 self.repo.ui.warn(_("websub: invalid regexp for %s: %s\n")
308 self.repo.ui.warn(_("websub: invalid regexp for %s: %s\n")
307 % (key, regexp))
309 % (key, regexp))
308 return websubtable
310 return websubtable
309
311
310 def templater(self, req):
312 def templater(self, req):
311
313
312 # determine scheme, port and server name
314 # determine scheme, port and server name
313 # this is needed to create absolute urls
315 # this is needed to create absolute urls
314
316
315 proto = req.env.get('wsgi.url_scheme')
317 proto = req.env.get('wsgi.url_scheme')
316 if proto == 'https':
318 if proto == 'https':
317 proto = 'https'
319 proto = 'https'
318 default_port = "443"
320 default_port = "443"
319 else:
321 else:
320 proto = 'http'
322 proto = 'http'
321 default_port = "80"
323 default_port = "80"
322
324
323 port = req.env["SERVER_PORT"]
325 port = req.env["SERVER_PORT"]
324 port = port != default_port and (":" + port) or ""
326 port = port != default_port and (":" + port) or ""
325 urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
327 urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
326 logourl = self.config("web", "logourl", "http://mercurial.selenic.com/")
328 logourl = self.config("web", "logourl", "http://mercurial.selenic.com/")
327 logoimg = self.config("web", "logoimg", "hglogo.png")
329 logoimg = self.config("web", "logoimg", "hglogo.png")
328 staticurl = self.config("web", "staticurl") or req.url + 'static/'
330 staticurl = self.config("web", "staticurl") or req.url + 'static/'
329 if not staticurl.endswith('/'):
331 if not staticurl.endswith('/'):
330 staticurl += '/'
332 staticurl += '/'
331
333
332 # some functions for the templater
334 # some functions for the templater
333
335
334 def motd(**map):
336 def motd(**map):
335 yield self.config("web", "motd", "")
337 yield self.config("web", "motd", "")
336
338
337 # figure out which style to use
339 # figure out which style to use
338
340
339 vars = {}
341 vars = {}
340 styles = (
342 styles = (
341 req.form.get('style', [None])[0],
343 req.form.get('style', [None])[0],
342 self.config('web', 'style'),
344 self.config('web', 'style'),
343 'paper',
345 'paper',
344 )
346 )
345 style, mapfile = templater.stylemap(styles, self.templatepath)
347 style, mapfile = templater.stylemap(styles, self.templatepath)
346 if style == styles[0]:
348 if style == styles[0]:
347 vars['style'] = style
349 vars['style'] = style
348
350
349 start = req.url[-1] == '?' and '&' or '?'
351 start = req.url[-1] == '?' and '&' or '?'
350 sessionvars = webutil.sessionvars(vars, start)
352 sessionvars = webutil.sessionvars(vars, start)
351
353
352 if not self.reponame:
354 if not self.reponame:
353 self.reponame = (self.config("web", "name")
355 self.reponame = (self.config("web", "name")
354 or req.env.get('REPO_NAME')
356 or req.env.get('REPO_NAME')
355 or req.url.strip('/') or self.repo.root)
357 or req.url.strip('/') or self.repo.root)
356
358
357 def websubfilter(text):
359 def websubfilter(text):
358 return websub(text, self.websubtable)
360 return websub(text, self.websubtable)
359
361
360 # create the templater
362 # create the templater
361
363
362 tmpl = templater.templater(mapfile,
364 tmpl = templater.templater(mapfile,
363 filters={"websub": websubfilter},
365 filters={"websub": websubfilter},
364 defaults={"url": req.url,
366 defaults={"url": req.url,
365 "logourl": logourl,
367 "logourl": logourl,
366 "logoimg": logoimg,
368 "logoimg": logoimg,
367 "staticurl": staticurl,
369 "staticurl": staticurl,
368 "urlbase": urlbase,
370 "urlbase": urlbase,
369 "repo": self.reponame,
371 "repo": self.reponame,
370 "encoding": encoding.encoding,
372 "encoding": encoding.encoding,
371 "motd": motd,
373 "motd": motd,
372 "sessionvars": sessionvars,
374 "sessionvars": sessionvars,
373 "pathdef": makebreadcrumb(req.url),
375 "pathdef": makebreadcrumb(req.url),
374 })
376 })
375 return tmpl
377 return tmpl
376
378
377 def archivelist(self, nodeid):
379 def archivelist(self, nodeid):
378 allowed = self.configlist("web", "allow_archive")
380 allowed = self.configlist("web", "allow_archive")
379 for i, spec in self.archive_specs.iteritems():
381 for i, spec in self.archive_specs.iteritems():
380 if i in allowed or self.configbool("web", "allow" + i):
382 if i in allowed or self.configbool("web", "allow" + i):
381 yield {"type" : i, "extension" : spec[2], "node" : nodeid}
383 yield {"type" : i, "extension" : spec[2], "node" : nodeid}
382
384
383 archive_specs = {
385 archive_specs = {
384 'bz2': ('application/x-bzip2', 'tbz2', '.tar.bz2', None),
386 'bz2': ('application/x-bzip2', 'tbz2', '.tar.bz2', None),
385 'gz': ('application/x-gzip', 'tgz', '.tar.gz', None),
387 'gz': ('application/x-gzip', 'tgz', '.tar.gz', None),
386 'zip': ('application/zip', 'zip', '.zip', None),
388 'zip': ('application/zip', 'zip', '.zip', None),
387 }
389 }
388
390
389 def check_perm(self, req, op):
391 def check_perm(self, req, op):
390 for hook in permhooks:
392 for hook in permhooks:
391 hook(self, req, op)
393 hook(self, req, op)
General Comments 0
You need to be logged in to leave comments. Login now