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