##// END OF EJS Templates
exceptions: use only one exception handler to track errors with nicer...
marcink -
r178:f5cbb023 default
parent child Browse files
Show More
@@ -1,424 +1,409 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2017 RodeCode GmbH
2 # Copyright (C) 2014-2017 RodeCode GmbH
3 #
3 #
4 # This program is free software; you can redistribute it and/or modify
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
7 # (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import base64
18 import base64
19 import locale
19 import locale
20 import logging
20 import logging
21 import uuid
21 import uuid
22 import wsgiref.util
22 import wsgiref.util
23 import traceback
23 import traceback
24 from itertools import chain
24 from itertools import chain
25
25
26 import msgpack
26 import msgpack
27 from beaker.cache import CacheManager
27 from beaker.cache import CacheManager
28 from beaker.util import parse_cache_config_options
28 from beaker.util import parse_cache_config_options
29 from pyramid.config import Configurator
29 from pyramid.config import Configurator
30 from pyramid.wsgi import wsgiapp
30 from pyramid.wsgi import wsgiapp
31
31
32 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
32 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
33 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
33 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
34 from vcsserver.echo_stub.echo_app import EchoApp
34 from vcsserver.echo_stub.echo_app import EchoApp
35 from vcsserver.exceptions import HTTPRepoLocked
35 from vcsserver.exceptions import HTTPRepoLocked
36 from vcsserver.server import VcsServer
36 from vcsserver.server import VcsServer
37
37
38 try:
38 try:
39 from vcsserver.git import GitFactory, GitRemote
39 from vcsserver.git import GitFactory, GitRemote
40 except ImportError:
40 except ImportError:
41 GitFactory = None
41 GitFactory = None
42 GitRemote = None
42 GitRemote = None
43 try:
43 try:
44 from vcsserver.hg import MercurialFactory, HgRemote
44 from vcsserver.hg import MercurialFactory, HgRemote
45 except ImportError:
45 except ImportError:
46 MercurialFactory = None
46 MercurialFactory = None
47 HgRemote = None
47 HgRemote = None
48 try:
48 try:
49 from vcsserver.svn import SubversionFactory, SvnRemote
49 from vcsserver.svn import SubversionFactory, SvnRemote
50 except ImportError:
50 except ImportError:
51 SubversionFactory = None
51 SubversionFactory = None
52 SvnRemote = None
52 SvnRemote = None
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56
56
57 class VCS(object):
57 class VCS(object):
58 def __init__(self, locale=None, cache_config=None):
58 def __init__(self, locale=None, cache_config=None):
59 self.locale = locale
59 self.locale = locale
60 self.cache_config = cache_config
60 self.cache_config = cache_config
61 self._configure_locale()
61 self._configure_locale()
62 self._initialize_cache()
62 self._initialize_cache()
63
63
64 if GitFactory and GitRemote:
64 if GitFactory and GitRemote:
65 git_repo_cache = self.cache.get_cache_region(
65 git_repo_cache = self.cache.get_cache_region(
66 'git', region='repo_object')
66 'git', region='repo_object')
67 git_factory = GitFactory(git_repo_cache)
67 git_factory = GitFactory(git_repo_cache)
68 self._git_remote = GitRemote(git_factory)
68 self._git_remote = GitRemote(git_factory)
69 else:
69 else:
70 log.info("Git client import failed")
70 log.info("Git client import failed")
71
71
72 if MercurialFactory and HgRemote:
72 if MercurialFactory and HgRemote:
73 hg_repo_cache = self.cache.get_cache_region(
73 hg_repo_cache = self.cache.get_cache_region(
74 'hg', region='repo_object')
74 'hg', region='repo_object')
75 hg_factory = MercurialFactory(hg_repo_cache)
75 hg_factory = MercurialFactory(hg_repo_cache)
76 self._hg_remote = HgRemote(hg_factory)
76 self._hg_remote = HgRemote(hg_factory)
77 else:
77 else:
78 log.info("Mercurial client import failed")
78 log.info("Mercurial client import failed")
79
79
80 if SubversionFactory and SvnRemote:
80 if SubversionFactory and SvnRemote:
81 svn_repo_cache = self.cache.get_cache_region(
81 svn_repo_cache = self.cache.get_cache_region(
82 'svn', region='repo_object')
82 'svn', region='repo_object')
83 svn_factory = SubversionFactory(svn_repo_cache)
83 svn_factory = SubversionFactory(svn_repo_cache)
84 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
84 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
85 else:
85 else:
86 log.info("Subversion client import failed")
86 log.info("Subversion client import failed")
87
87
88 self._vcsserver = VcsServer()
88 self._vcsserver = VcsServer()
89
89
90 def _initialize_cache(self):
90 def _initialize_cache(self):
91 cache_config = parse_cache_config_options(self.cache_config)
91 cache_config = parse_cache_config_options(self.cache_config)
92 log.info('Initializing beaker cache: %s' % cache_config)
92 log.info('Initializing beaker cache: %s' % cache_config)
93 self.cache = CacheManager(**cache_config)
93 self.cache = CacheManager(**cache_config)
94
94
95 def _configure_locale(self):
95 def _configure_locale(self):
96 if self.locale:
96 if self.locale:
97 log.info('Settings locale: `LC_ALL` to %s' % self.locale)
97 log.info('Settings locale: `LC_ALL` to %s' % self.locale)
98 else:
98 else:
99 log.info(
99 log.info(
100 'Configuring locale subsystem based on environment variables')
100 'Configuring locale subsystem based on environment variables')
101 try:
101 try:
102 # If self.locale is the empty string, then the locale
102 # If self.locale is the empty string, then the locale
103 # module will use the environment variables. See the
103 # module will use the environment variables. See the
104 # documentation of the package `locale`.
104 # documentation of the package `locale`.
105 locale.setlocale(locale.LC_ALL, self.locale)
105 locale.setlocale(locale.LC_ALL, self.locale)
106
106
107 language_code, encoding = locale.getlocale()
107 language_code, encoding = locale.getlocale()
108 log.info(
108 log.info(
109 'Locale set to language code "%s" with encoding "%s".',
109 'Locale set to language code "%s" with encoding "%s".',
110 language_code, encoding)
110 language_code, encoding)
111 except locale.Error:
111 except locale.Error:
112 log.exception(
112 log.exception(
113 'Cannot set locale, not configuring the locale system')
113 'Cannot set locale, not configuring the locale system')
114
114
115
115
116 class WsgiProxy(object):
116 class WsgiProxy(object):
117 def __init__(self, wsgi):
117 def __init__(self, wsgi):
118 self.wsgi = wsgi
118 self.wsgi = wsgi
119
119
120 def __call__(self, environ, start_response):
120 def __call__(self, environ, start_response):
121 input_data = environ['wsgi.input'].read()
121 input_data = environ['wsgi.input'].read()
122 input_data = msgpack.unpackb(input_data)
122 input_data = msgpack.unpackb(input_data)
123
123
124 error = None
124 error = None
125 try:
125 try:
126 data, status, headers = self.wsgi.handle(
126 data, status, headers = self.wsgi.handle(
127 input_data['environment'], input_data['input_data'],
127 input_data['environment'], input_data['input_data'],
128 *input_data['args'], **input_data['kwargs'])
128 *input_data['args'], **input_data['kwargs'])
129 except Exception as e:
129 except Exception as e:
130 data, status, headers = [], None, None
130 data, status, headers = [], None, None
131 error = {
131 error = {
132 'message': str(e),
132 'message': str(e),
133 '_vcs_kind': getattr(e, '_vcs_kind', None)
133 '_vcs_kind': getattr(e, '_vcs_kind', None)
134 }
134 }
135
135
136 start_response(200, {})
136 start_response(200, {})
137 return self._iterator(error, status, headers, data)
137 return self._iterator(error, status, headers, data)
138
138
139 def _iterator(self, error, status, headers, data):
139 def _iterator(self, error, status, headers, data):
140 initial_data = [
140 initial_data = [
141 error,
141 error,
142 status,
142 status,
143 headers,
143 headers,
144 ]
144 ]
145
145
146 for d in chain(initial_data, data):
146 for d in chain(initial_data, data):
147 yield msgpack.packb(d)
147 yield msgpack.packb(d)
148
148
149
149
150 class HTTPApplication(object):
150 class HTTPApplication(object):
151 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
151 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
152
152
153 remote_wsgi = remote_wsgi
153 remote_wsgi = remote_wsgi
154 _use_echo_app = False
154 _use_echo_app = False
155
155
156 def __init__(self, settings=None, global_config=None):
156 def __init__(self, settings=None, global_config=None):
157 self.config = Configurator(settings=settings)
157 self.config = Configurator(settings=settings)
158 self.global_config = global_config
158 self.global_config = global_config
159
159
160 locale = settings.get('locale', '') or 'en_US.UTF-8'
160 locale = settings.get('locale', '') or 'en_US.UTF-8'
161 vcs = VCS(locale=locale, cache_config=settings)
161 vcs = VCS(locale=locale, cache_config=settings)
162 self._remotes = {
162 self._remotes = {
163 'hg': vcs._hg_remote,
163 'hg': vcs._hg_remote,
164 'git': vcs._git_remote,
164 'git': vcs._git_remote,
165 'svn': vcs._svn_remote,
165 'svn': vcs._svn_remote,
166 'server': vcs._vcsserver,
166 'server': vcs._vcsserver,
167 }
167 }
168 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
168 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
169 self._use_echo_app = True
169 self._use_echo_app = True
170 log.warning("Using EchoApp for VCS operations.")
170 log.warning("Using EchoApp for VCS operations.")
171 self.remote_wsgi = remote_wsgi_stub
171 self.remote_wsgi = remote_wsgi_stub
172 self._configure_settings(settings)
172 self._configure_settings(settings)
173 self._configure()
173 self._configure()
174
174
175 def _configure_settings(self, app_settings):
175 def _configure_settings(self, app_settings):
176 """
176 """
177 Configure the settings module.
177 Configure the settings module.
178 """
178 """
179 git_path = app_settings.get('git_path', None)
179 git_path = app_settings.get('git_path', None)
180 if git_path:
180 if git_path:
181 settings.GIT_EXECUTABLE = git_path
181 settings.GIT_EXECUTABLE = git_path
182
182
183 def _configure(self):
183 def _configure(self):
184 self.config.add_renderer(
184 self.config.add_renderer(
185 name='msgpack',
185 name='msgpack',
186 factory=self._msgpack_renderer_factory)
186 factory=self._msgpack_renderer_factory)
187
187
188 self.config.add_route('service', '/_service')
188 self.config.add_route('service', '/_service')
189 self.config.add_route('status', '/status')
189 self.config.add_route('status', '/status')
190 self.config.add_route('hg_proxy', '/proxy/hg')
190 self.config.add_route('hg_proxy', '/proxy/hg')
191 self.config.add_route('git_proxy', '/proxy/git')
191 self.config.add_route('git_proxy', '/proxy/git')
192 self.config.add_route('vcs', '/{backend}')
192 self.config.add_route('vcs', '/{backend}')
193 self.config.add_route('stream_git', '/stream/git/*repo_name')
193 self.config.add_route('stream_git', '/stream/git/*repo_name')
194 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
194 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
195
195
196 self.config.add_view(
196 self.config.add_view(
197 self.status_view, route_name='status', renderer='json')
197 self.status_view, route_name='status', renderer='json')
198 self.config.add_view(
198 self.config.add_view(
199 self.service_view, route_name='service', renderer='msgpack')
199 self.service_view, route_name='service', renderer='msgpack')
200
200
201 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
201 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
202 self.config.add_view(self.git_proxy(), route_name='git_proxy')
202 self.config.add_view(self.git_proxy(), route_name='git_proxy')
203 self.config.add_view(
203 self.config.add_view(
204 self.vcs_view, route_name='vcs', renderer='msgpack',
204 self.vcs_view, route_name='vcs', renderer='msgpack',
205 custom_predicates=[self.is_vcs_view])
205 custom_predicates=[self.is_vcs_view])
206
206
207 self.config.add_view(self.hg_stream(), route_name='stream_hg')
207 self.config.add_view(self.hg_stream(), route_name='stream_hg')
208 self.config.add_view(self.git_stream(), route_name='stream_git')
208 self.config.add_view(self.git_stream(), route_name='stream_git')
209
209
210 def notfound(request):
210 def notfound(request):
211 return {'status': '404 NOT FOUND'}
211 return {'status': '404 NOT FOUND'}
212 self.config.add_notfound_view(notfound, renderer='json')
212 self.config.add_notfound_view(notfound, renderer='json')
213
213
214 self.config.add_view(
214 self.config.add_view(self.handle_vcs_exception, context=Exception)
215 self.handle_vcs_exception, context=Exception,
216 custom_predicates=[self.is_vcs_exception])
217
218 self.config.add_view(
219 self.general_error_handler, context=Exception)
220
215
221 self.config.add_tween(
216 self.config.add_tween(
222 'vcsserver.tweens.RequestWrapperTween',
217 'vcsserver.tweens.RequestWrapperTween',
223 )
218 )
224
219
225 def wsgi_app(self):
220 def wsgi_app(self):
226 return self.config.make_wsgi_app()
221 return self.config.make_wsgi_app()
227
222
228 def vcs_view(self, request):
223 def vcs_view(self, request):
229 remote = self._remotes[request.matchdict['backend']]
224 remote = self._remotes[request.matchdict['backend']]
230 payload = msgpack.unpackb(request.body, use_list=True)
225 payload = msgpack.unpackb(request.body, use_list=True)
231 method = payload.get('method')
226 method = payload.get('method')
232 params = payload.get('params')
227 params = payload.get('params')
233 wire = params.get('wire')
228 wire = params.get('wire')
234 args = params.get('args')
229 args = params.get('args')
235 kwargs = params.get('kwargs')
230 kwargs = params.get('kwargs')
236 if wire:
231 if wire:
237 try:
232 try:
238 wire['context'] = uuid.UUID(wire['context'])
233 wire['context'] = uuid.UUID(wire['context'])
239 except KeyError:
234 except KeyError:
240 pass
235 pass
241 args.insert(0, wire)
236 args.insert(0, wire)
242
237
243 log.debug('method called:%s with kwargs:%s', method, kwargs)
238 log.debug('method called:%s with kwargs:%s', method, kwargs)
244 try:
239 try:
245 resp = getattr(remote, method)(*args, **kwargs)
240 resp = getattr(remote, method)(*args, **kwargs)
246 except Exception as e:
241 except Exception as e:
247 tb_info = traceback.format_exc()
242 tb_info = traceback.format_exc()
248
243
249 type_ = e.__class__.__name__
244 type_ = e.__class__.__name__
250 if type_ not in self.ALLOWED_EXCEPTIONS:
245 if type_ not in self.ALLOWED_EXCEPTIONS:
251 type_ = None
246 type_ = None
252
247
253 resp = {
248 resp = {
254 'id': payload.get('id'),
249 'id': payload.get('id'),
255 'error': {
250 'error': {
256 'message': e.message,
251 'message': e.message,
257 'traceback': tb_info,
252 'traceback': tb_info,
258 'type': type_
253 'type': type_
259 }
254 }
260 }
255 }
261 try:
256 try:
262 resp['error']['_vcs_kind'] = e._vcs_kind
257 resp['error']['_vcs_kind'] = e._vcs_kind
263 except AttributeError:
258 except AttributeError:
264 pass
259 pass
265 else:
260 else:
266 resp = {
261 resp = {
267 'id': payload.get('id'),
262 'id': payload.get('id'),
268 'result': resp
263 'result': resp
269 }
264 }
270
265
271 return resp
266 return resp
272
267
273 def status_view(self, request):
268 def status_view(self, request):
274 return {'status': 'OK'}
269 return {'status': 'OK'}
275
270
276 def service_view(self, request):
271 def service_view(self, request):
277 import vcsserver
272 import vcsserver
278 import ConfigParser as configparser
273 import ConfigParser as configparser
279
274
280 payload = msgpack.unpackb(request.body, use_list=True)
275 payload = msgpack.unpackb(request.body, use_list=True)
281
276
282 try:
277 try:
283 path = self.global_config['__file__']
278 path = self.global_config['__file__']
284 config = configparser.ConfigParser()
279 config = configparser.ConfigParser()
285 config.read(path)
280 config.read(path)
286 parsed_ini = config
281 parsed_ini = config
287 if parsed_ini.has_section('server:main'):
282 if parsed_ini.has_section('server:main'):
288 parsed_ini = dict(parsed_ini.items('server:main'))
283 parsed_ini = dict(parsed_ini.items('server:main'))
289 except Exception:
284 except Exception:
290 log.exception('Failed to read .ini file for display')
285 log.exception('Failed to read .ini file for display')
291 parsed_ini = {}
286 parsed_ini = {}
292
287
293 resp = {
288 resp = {
294 'id': payload.get('id'),
289 'id': payload.get('id'),
295 'result': dict(
290 'result': dict(
296 version=vcsserver.__version__,
291 version=vcsserver.__version__,
297 config=parsed_ini,
292 config=parsed_ini,
298 payload=payload,
293 payload=payload,
299 )
294 )
300 }
295 }
301 return resp
296 return resp
302
297
303 def _msgpack_renderer_factory(self, info):
298 def _msgpack_renderer_factory(self, info):
304 def _render(value, system):
299 def _render(value, system):
305 value = msgpack.packb(value)
300 value = msgpack.packb(value)
306 request = system.get('request')
301 request = system.get('request')
307 if request is not None:
302 if request is not None:
308 response = request.response
303 response = request.response
309 ct = response.content_type
304 ct = response.content_type
310 if ct == response.default_content_type:
305 if ct == response.default_content_type:
311 response.content_type = 'application/x-msgpack'
306 response.content_type = 'application/x-msgpack'
312 return value
307 return value
313 return _render
308 return _render
314
309
315 def hg_proxy(self):
310 def hg_proxy(self):
316 @wsgiapp
311 @wsgiapp
317 def _hg_proxy(environ, start_response):
312 def _hg_proxy(environ, start_response):
318 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
313 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
319 return app(environ, start_response)
314 return app(environ, start_response)
320 return _hg_proxy
315 return _hg_proxy
321
316
322 def git_proxy(self):
317 def git_proxy(self):
323 @wsgiapp
318 @wsgiapp
324 def _git_proxy(environ, start_response):
319 def _git_proxy(environ, start_response):
325 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
320 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
326 return app(environ, start_response)
321 return app(environ, start_response)
327 return _git_proxy
322 return _git_proxy
328
323
329 def hg_stream(self):
324 def hg_stream(self):
330 if self._use_echo_app:
325 if self._use_echo_app:
331 @wsgiapp
326 @wsgiapp
332 def _hg_stream(environ, start_response):
327 def _hg_stream(environ, start_response):
333 app = EchoApp('fake_path', 'fake_name', None)
328 app = EchoApp('fake_path', 'fake_name', None)
334 return app(environ, start_response)
329 return app(environ, start_response)
335 return _hg_stream
330 return _hg_stream
336 else:
331 else:
337 @wsgiapp
332 @wsgiapp
338 def _hg_stream(environ, start_response):
333 def _hg_stream(environ, start_response):
339 repo_path = environ['HTTP_X_RC_REPO_PATH']
334 repo_path = environ['HTTP_X_RC_REPO_PATH']
340 repo_name = environ['HTTP_X_RC_REPO_NAME']
335 repo_name = environ['HTTP_X_RC_REPO_NAME']
341 packed_config = base64.b64decode(
336 packed_config = base64.b64decode(
342 environ['HTTP_X_RC_REPO_CONFIG'])
337 environ['HTTP_X_RC_REPO_CONFIG'])
343 config = msgpack.unpackb(packed_config)
338 config = msgpack.unpackb(packed_config)
344 app = scm_app.create_hg_wsgi_app(
339 app = scm_app.create_hg_wsgi_app(
345 repo_path, repo_name, config)
340 repo_path, repo_name, config)
346
341
347 # Consitent path information for hgweb
342 # Consitent path information for hgweb
348 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
343 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
349 environ['REPO_NAME'] = repo_name
344 environ['REPO_NAME'] = repo_name
350 return app(environ, ResponseFilter(start_response))
345 return app(environ, ResponseFilter(start_response))
351 return _hg_stream
346 return _hg_stream
352
347
353 def git_stream(self):
348 def git_stream(self):
354 if self._use_echo_app:
349 if self._use_echo_app:
355 @wsgiapp
350 @wsgiapp
356 def _git_stream(environ, start_response):
351 def _git_stream(environ, start_response):
357 app = EchoApp('fake_path', 'fake_name', None)
352 app = EchoApp('fake_path', 'fake_name', None)
358 return app(environ, start_response)
353 return app(environ, start_response)
359 return _git_stream
354 return _git_stream
360 else:
355 else:
361 @wsgiapp
356 @wsgiapp
362 def _git_stream(environ, start_response):
357 def _git_stream(environ, start_response):
363 repo_path = environ['HTTP_X_RC_REPO_PATH']
358 repo_path = environ['HTTP_X_RC_REPO_PATH']
364 repo_name = environ['HTTP_X_RC_REPO_NAME']
359 repo_name = environ['HTTP_X_RC_REPO_NAME']
365 packed_config = base64.b64decode(
360 packed_config = base64.b64decode(
366 environ['HTTP_X_RC_REPO_CONFIG'])
361 environ['HTTP_X_RC_REPO_CONFIG'])
367 config = msgpack.unpackb(packed_config)
362 config = msgpack.unpackb(packed_config)
368
363
369 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
364 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
370 app = scm_app.create_git_wsgi_app(
365 app = scm_app.create_git_wsgi_app(
371 repo_path, repo_name, config)
366 repo_path, repo_name, config)
372 return app(environ, start_response)
367 return app(environ, start_response)
373 return _git_stream
368 return _git_stream
374
369
375 def is_vcs_view(self, context, request):
370 def is_vcs_view(self, context, request):
376 """
371 """
377 View predicate that returns true if given backend is supported by
372 View predicate that returns true if given backend is supported by
378 defined remotes.
373 defined remotes.
379 """
374 """
380 backend = request.matchdict.get('backend')
375 backend = request.matchdict.get('backend')
381 return backend in self._remotes
376 return backend in self._remotes
382
377
383 def is_vcs_exception(self, context, request):
384 """
385 View predicate that returns true if the context object is a VCS
386 exception.
387 """
388 return hasattr(context, '_vcs_kind')
389
390 def handle_vcs_exception(self, exception, request):
378 def handle_vcs_exception(self, exception, request):
391 if exception._vcs_kind == 'repo_locked':
379 _vcs_kind = getattr(exception, '_vcs_kind', '')
380 if _vcs_kind == 'repo_locked':
392 # Get custom repo-locked status code if present.
381 # Get custom repo-locked status code if present.
393 status_code = request.headers.get('X-RC-Locked-Status-Code')
382 status_code = request.headers.get('X-RC-Locked-Status-Code')
394 return HTTPRepoLocked(
383 return HTTPRepoLocked(
395 title=exception.message, status_code=status_code)
384 title=exception.message, status_code=status_code)
396
385
397 # Re-raise exception if we can not handle it.
386 # Re-raise exception if we can not handle it.
398 raise exception
399
400 def general_error_handler(self, exception, request):
401 log.exception(
387 log.exception(
402 'error occurred handling this request for path: %s',
388 'error occurred handling this request for path: %s', request.path)
403 request.path)
404 raise exception
389 raise exception
405
390
406
391
407 class ResponseFilter(object):
392 class ResponseFilter(object):
408
393
409 def __init__(self, start_response):
394 def __init__(self, start_response):
410 self._start_response = start_response
395 self._start_response = start_response
411
396
412 def __call__(self, status, response_headers, exc_info=None):
397 def __call__(self, status, response_headers, exc_info=None):
413 headers = tuple(
398 headers = tuple(
414 (h, v) for h, v in response_headers
399 (h, v) for h, v in response_headers
415 if not wsgiref.util.is_hop_by_hop(h))
400 if not wsgiref.util.is_hop_by_hop(h))
416 return self._start_response(status, headers, exc_info)
401 return self._start_response(status, headers, exc_info)
417
402
418
403
419 def main(global_config, **settings):
404 def main(global_config, **settings):
420 if MercurialFactory:
405 if MercurialFactory:
421 hgpatches.patch_largefiles_capabilities()
406 hgpatches.patch_largefiles_capabilities()
422 hgpatches.patch_subrepo_type_mapping()
407 hgpatches.patch_subrepo_type_mapping()
423 app = HTTPApplication(settings=settings, global_config=global_config)
408 app = HTTPApplication(settings=settings, global_config=global_config)
424 return app.wsgi_app()
409 return app.wsgi_app()
General Comments 0
You need to be logged in to leave comments. Login now