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