##// END OF EJS Templates
service-endpoint: expose additional data of vcsserver via service-data endpoint....
marcink -
r173:d7a24340 default
parent child Browse files
Show More
@@ -1,408 +1,424 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):
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
159
158 locale = settings.get('locale', '') or 'en_US.UTF-8'
160 locale = settings.get('locale', '') or 'en_US.UTF-8'
159 vcs = VCS(locale=locale, cache_config=settings)
161 vcs = VCS(locale=locale, cache_config=settings)
160 self._remotes = {
162 self._remotes = {
161 'hg': vcs._hg_remote,
163 'hg': vcs._hg_remote,
162 'git': vcs._git_remote,
164 'git': vcs._git_remote,
163 'svn': vcs._svn_remote,
165 'svn': vcs._svn_remote,
164 'server': vcs._vcsserver,
166 'server': vcs._vcsserver,
165 }
167 }
166 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
168 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
167 self._use_echo_app = True
169 self._use_echo_app = True
168 log.warning("Using EchoApp for VCS operations.")
170 log.warning("Using EchoApp for VCS operations.")
169 self.remote_wsgi = remote_wsgi_stub
171 self.remote_wsgi = remote_wsgi_stub
170 self._configure_settings(settings)
172 self._configure_settings(settings)
171 self._configure()
173 self._configure()
172
174
173 def _configure_settings(self, app_settings):
175 def _configure_settings(self, app_settings):
174 """
176 """
175 Configure the settings module.
177 Configure the settings module.
176 """
178 """
177 git_path = app_settings.get('git_path', None)
179 git_path = app_settings.get('git_path', None)
178 if git_path:
180 if git_path:
179 settings.GIT_EXECUTABLE = git_path
181 settings.GIT_EXECUTABLE = git_path
180
182
181 def _configure(self):
183 def _configure(self):
182 self.config.add_renderer(
184 self.config.add_renderer(
183 name='msgpack',
185 name='msgpack',
184 factory=self._msgpack_renderer_factory)
186 factory=self._msgpack_renderer_factory)
185
187
186 self.config.add_route('service', '/_service')
188 self.config.add_route('service', '/_service')
187 self.config.add_route('status', '/status')
189 self.config.add_route('status', '/status')
188 self.config.add_route('hg_proxy', '/proxy/hg')
190 self.config.add_route('hg_proxy', '/proxy/hg')
189 self.config.add_route('git_proxy', '/proxy/git')
191 self.config.add_route('git_proxy', '/proxy/git')
190 self.config.add_route('vcs', '/{backend}')
192 self.config.add_route('vcs', '/{backend}')
191 self.config.add_route('stream_git', '/stream/git/*repo_name')
193 self.config.add_route('stream_git', '/stream/git/*repo_name')
192 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
194 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
193
195
194 self.config.add_view(
196 self.config.add_view(
195 self.status_view, route_name='status', renderer='json')
197 self.status_view, route_name='status', renderer='json')
196 self.config.add_view(
198 self.config.add_view(
197 self.service_view, route_name='service', renderer='msgpack')
199 self.service_view, route_name='service', renderer='msgpack')
198
200
199 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
201 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
200 self.config.add_view(self.git_proxy(), route_name='git_proxy')
202 self.config.add_view(self.git_proxy(), route_name='git_proxy')
201 self.config.add_view(
203 self.config.add_view(
202 self.vcs_view, route_name='vcs', renderer='msgpack',
204 self.vcs_view, route_name='vcs', renderer='msgpack',
203 custom_predicates=[self.is_vcs_view])
205 custom_predicates=[self.is_vcs_view])
204
206
205 self.config.add_view(self.hg_stream(), route_name='stream_hg')
207 self.config.add_view(self.hg_stream(), route_name='stream_hg')
206 self.config.add_view(self.git_stream(), route_name='stream_git')
208 self.config.add_view(self.git_stream(), route_name='stream_git')
207
209
208 def notfound(request):
210 def notfound(request):
209 return {'status': '404 NOT FOUND'}
211 return {'status': '404 NOT FOUND'}
210 self.config.add_notfound_view(notfound, renderer='json')
212 self.config.add_notfound_view(notfound, renderer='json')
211
213
212 self.config.add_view(
214 self.config.add_view(
213 self.handle_vcs_exception, context=Exception,
215 self.handle_vcs_exception, context=Exception,
214 custom_predicates=[self.is_vcs_exception])
216 custom_predicates=[self.is_vcs_exception])
215
217
216 self.config.add_view(
218 self.config.add_view(
217 self.general_error_handler, context=Exception)
219 self.general_error_handler, context=Exception)
218
220
219 self.config.add_tween(
221 self.config.add_tween(
220 'vcsserver.tweens.RequestWrapperTween',
222 'vcsserver.tweens.RequestWrapperTween',
221 )
223 )
222
224
223 def wsgi_app(self):
225 def wsgi_app(self):
224 return self.config.make_wsgi_app()
226 return self.config.make_wsgi_app()
225
227
226 def vcs_view(self, request):
228 def vcs_view(self, request):
227 remote = self._remotes[request.matchdict['backend']]
229 remote = self._remotes[request.matchdict['backend']]
228 payload = msgpack.unpackb(request.body, use_list=True)
230 payload = msgpack.unpackb(request.body, use_list=True)
229 method = payload.get('method')
231 method = payload.get('method')
230 params = payload.get('params')
232 params = payload.get('params')
231 wire = params.get('wire')
233 wire = params.get('wire')
232 args = params.get('args')
234 args = params.get('args')
233 kwargs = params.get('kwargs')
235 kwargs = params.get('kwargs')
234 if wire:
236 if wire:
235 try:
237 try:
236 wire['context'] = uuid.UUID(wire['context'])
238 wire['context'] = uuid.UUID(wire['context'])
237 except KeyError:
239 except KeyError:
238 pass
240 pass
239 args.insert(0, wire)
241 args.insert(0, wire)
240
242
241 log.debug('method called:%s with kwargs:%s', method, kwargs)
243 log.debug('method called:%s with kwargs:%s', method, kwargs)
242 try:
244 try:
243 resp = getattr(remote, method)(*args, **kwargs)
245 resp = getattr(remote, method)(*args, **kwargs)
244 except Exception as e:
246 except Exception as e:
245 tb_info = traceback.format_exc()
247 tb_info = traceback.format_exc()
246
248
247 type_ = e.__class__.__name__
249 type_ = e.__class__.__name__
248 if type_ not in self.ALLOWED_EXCEPTIONS:
250 if type_ not in self.ALLOWED_EXCEPTIONS:
249 type_ = None
251 type_ = None
250
252
251 resp = {
253 resp = {
252 'id': payload.get('id'),
254 'id': payload.get('id'),
253 'error': {
255 'error': {
254 'message': e.message,
256 'message': e.message,
255 'traceback': tb_info,
257 'traceback': tb_info,
256 'type': type_
258 'type': type_
257 }
259 }
258 }
260 }
259 try:
261 try:
260 resp['error']['_vcs_kind'] = e._vcs_kind
262 resp['error']['_vcs_kind'] = e._vcs_kind
261 except AttributeError:
263 except AttributeError:
262 pass
264 pass
263 else:
265 else:
264 resp = {
266 resp = {
265 'id': payload.get('id'),
267 'id': payload.get('id'),
266 'result': resp
268 'result': resp
267 }
269 }
268
270
269 return resp
271 return resp
270
272
271 def status_view(self, request):
273 def status_view(self, request):
272 return {'status': 'OK'}
274 return {'status': 'OK'}
273
275
274 def service_view(self, request):
276 def service_view(self, request):
275 import vcsserver
277 import vcsserver
278 import ConfigParser as configparser
279
276 payload = msgpack.unpackb(request.body, use_list=True)
280 payload = msgpack.unpackb(request.body, use_list=True)
281
282 try:
283 path = self.global_config['__file__']
284 config = configparser.ConfigParser()
285 config.read(path)
286 parsed_ini = config
287 if parsed_ini.has_section('server:main'):
288 parsed_ini = dict(parsed_ini.items('server:main'))
289 except Exception:
290 log.exception('Failed to read .ini file for display')
291 parsed_ini = {}
292
277 resp = {
293 resp = {
278 'id': payload.get('id'),
294 'id': payload.get('id'),
279 'result': dict(
295 'result': dict(
280 version=vcsserver.__version__,
296 version=vcsserver.__version__,
281 config={},
297 config=parsed_ini,
282 payload=payload,
298 payload=payload,
283 )
299 )
284 }
300 }
285 return resp
301 return resp
286
302
287 def _msgpack_renderer_factory(self, info):
303 def _msgpack_renderer_factory(self, info):
288 def _render(value, system):
304 def _render(value, system):
289 value = msgpack.packb(value)
305 value = msgpack.packb(value)
290 request = system.get('request')
306 request = system.get('request')
291 if request is not None:
307 if request is not None:
292 response = request.response
308 response = request.response
293 ct = response.content_type
309 ct = response.content_type
294 if ct == response.default_content_type:
310 if ct == response.default_content_type:
295 response.content_type = 'application/x-msgpack'
311 response.content_type = 'application/x-msgpack'
296 return value
312 return value
297 return _render
313 return _render
298
314
299 def hg_proxy(self):
315 def hg_proxy(self):
300 @wsgiapp
316 @wsgiapp
301 def _hg_proxy(environ, start_response):
317 def _hg_proxy(environ, start_response):
302 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
318 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
303 return app(environ, start_response)
319 return app(environ, start_response)
304 return _hg_proxy
320 return _hg_proxy
305
321
306 def git_proxy(self):
322 def git_proxy(self):
307 @wsgiapp
323 @wsgiapp
308 def _git_proxy(environ, start_response):
324 def _git_proxy(environ, start_response):
309 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
325 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
310 return app(environ, start_response)
326 return app(environ, start_response)
311 return _git_proxy
327 return _git_proxy
312
328
313 def hg_stream(self):
329 def hg_stream(self):
314 if self._use_echo_app:
330 if self._use_echo_app:
315 @wsgiapp
331 @wsgiapp
316 def _hg_stream(environ, start_response):
332 def _hg_stream(environ, start_response):
317 app = EchoApp('fake_path', 'fake_name', None)
333 app = EchoApp('fake_path', 'fake_name', None)
318 return app(environ, start_response)
334 return app(environ, start_response)
319 return _hg_stream
335 return _hg_stream
320 else:
336 else:
321 @wsgiapp
337 @wsgiapp
322 def _hg_stream(environ, start_response):
338 def _hg_stream(environ, start_response):
323 repo_path = environ['HTTP_X_RC_REPO_PATH']
339 repo_path = environ['HTTP_X_RC_REPO_PATH']
324 repo_name = environ['HTTP_X_RC_REPO_NAME']
340 repo_name = environ['HTTP_X_RC_REPO_NAME']
325 packed_config = base64.b64decode(
341 packed_config = base64.b64decode(
326 environ['HTTP_X_RC_REPO_CONFIG'])
342 environ['HTTP_X_RC_REPO_CONFIG'])
327 config = msgpack.unpackb(packed_config)
343 config = msgpack.unpackb(packed_config)
328 app = scm_app.create_hg_wsgi_app(
344 app = scm_app.create_hg_wsgi_app(
329 repo_path, repo_name, config)
345 repo_path, repo_name, config)
330
346
331 # Consitent path information for hgweb
347 # Consitent path information for hgweb
332 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
348 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
333 environ['REPO_NAME'] = repo_name
349 environ['REPO_NAME'] = repo_name
334 return app(environ, ResponseFilter(start_response))
350 return app(environ, ResponseFilter(start_response))
335 return _hg_stream
351 return _hg_stream
336
352
337 def git_stream(self):
353 def git_stream(self):
338 if self._use_echo_app:
354 if self._use_echo_app:
339 @wsgiapp
355 @wsgiapp
340 def _git_stream(environ, start_response):
356 def _git_stream(environ, start_response):
341 app = EchoApp('fake_path', 'fake_name', None)
357 app = EchoApp('fake_path', 'fake_name', None)
342 return app(environ, start_response)
358 return app(environ, start_response)
343 return _git_stream
359 return _git_stream
344 else:
360 else:
345 @wsgiapp
361 @wsgiapp
346 def _git_stream(environ, start_response):
362 def _git_stream(environ, start_response):
347 repo_path = environ['HTTP_X_RC_REPO_PATH']
363 repo_path = environ['HTTP_X_RC_REPO_PATH']
348 repo_name = environ['HTTP_X_RC_REPO_NAME']
364 repo_name = environ['HTTP_X_RC_REPO_NAME']
349 packed_config = base64.b64decode(
365 packed_config = base64.b64decode(
350 environ['HTTP_X_RC_REPO_CONFIG'])
366 environ['HTTP_X_RC_REPO_CONFIG'])
351 config = msgpack.unpackb(packed_config)
367 config = msgpack.unpackb(packed_config)
352
368
353 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
369 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
354 app = scm_app.create_git_wsgi_app(
370 app = scm_app.create_git_wsgi_app(
355 repo_path, repo_name, config)
371 repo_path, repo_name, config)
356 return app(environ, start_response)
372 return app(environ, start_response)
357 return _git_stream
373 return _git_stream
358
374
359 def is_vcs_view(self, context, request):
375 def is_vcs_view(self, context, request):
360 """
376 """
361 View predicate that returns true if given backend is supported by
377 View predicate that returns true if given backend is supported by
362 defined remotes.
378 defined remotes.
363 """
379 """
364 backend = request.matchdict.get('backend')
380 backend = request.matchdict.get('backend')
365 return backend in self._remotes
381 return backend in self._remotes
366
382
367 def is_vcs_exception(self, context, request):
383 def is_vcs_exception(self, context, request):
368 """
384 """
369 View predicate that returns true if the context object is a VCS
385 View predicate that returns true if the context object is a VCS
370 exception.
386 exception.
371 """
387 """
372 return hasattr(context, '_vcs_kind')
388 return hasattr(context, '_vcs_kind')
373
389
374 def handle_vcs_exception(self, exception, request):
390 def handle_vcs_exception(self, exception, request):
375 if exception._vcs_kind == 'repo_locked':
391 if exception._vcs_kind == 'repo_locked':
376 # Get custom repo-locked status code if present.
392 # Get custom repo-locked status code if present.
377 status_code = request.headers.get('X-RC-Locked-Status-Code')
393 status_code = request.headers.get('X-RC-Locked-Status-Code')
378 return HTTPRepoLocked(
394 return HTTPRepoLocked(
379 title=exception.message, status_code=status_code)
395 title=exception.message, status_code=status_code)
380
396
381 # Re-raise exception if we can not handle it.
397 # Re-raise exception if we can not handle it.
382 raise exception
398 raise exception
383
399
384 def general_error_handler(self, exception, request):
400 def general_error_handler(self, exception, request):
385 log.exception(
401 log.exception(
386 'error occurred handling this request for path: %s',
402 'error occurred handling this request for path: %s',
387 request.path)
403 request.path)
388 raise exception
404 raise exception
389
405
390
406
391 class ResponseFilter(object):
407 class ResponseFilter(object):
392
408
393 def __init__(self, start_response):
409 def __init__(self, start_response):
394 self._start_response = start_response
410 self._start_response = start_response
395
411
396 def __call__(self, status, response_headers, exc_info=None):
412 def __call__(self, status, response_headers, exc_info=None):
397 headers = tuple(
413 headers = tuple(
398 (h, v) for h, v in response_headers
414 (h, v) for h, v in response_headers
399 if not wsgiref.util.is_hop_by_hop(h))
415 if not wsgiref.util.is_hop_by_hop(h))
400 return self._start_response(status, headers, exc_info)
416 return self._start_response(status, headers, exc_info)
401
417
402
418
403 def main(global_config, **settings):
419 def main(global_config, **settings):
404 if MercurialFactory:
420 if MercurialFactory:
405 hgpatches.patch_largefiles_capabilities()
421 hgpatches.patch_largefiles_capabilities()
406 hgpatches.patch_subrepo_type_mapping()
422 hgpatches.patch_subrepo_type_mapping()
407 app = HTTPApplication(settings=settings)
423 app = HTTPApplication(settings=settings, global_config=global_config)
408 return app.wsgi_app()
424 return app.wsgi_app()
General Comments 0
You need to be logged in to leave comments. Login now