##// END OF EJS Templates
middleware: use finalizing log to inidicate we finished ALL operations.
marcink -
r2922:40395251 default
parent child Browse files
Show More
@@ -1,518 +1,518 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
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 Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import sys
22 import sys
23 import logging
23 import logging
24 import traceback
25 import collections
24 import collections
26 import tempfile
25 import tempfile
27
26
28 from paste.gzipper import make_gzip_middleware
27 from paste.gzipper import make_gzip_middleware
29 from pyramid.wsgi import wsgiapp
28 from pyramid.wsgi import wsgiapp
30 from pyramid.authorization import ACLAuthorizationPolicy
29 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.config import Configurator
30 from pyramid.config import Configurator
32 from pyramid.settings import asbool, aslist
31 from pyramid.settings import asbool, aslist
33 from pyramid.httpexceptions import (
32 from pyramid.httpexceptions import (
34 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
33 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
35 from pyramid.events import ApplicationCreated
34 from pyramid.events import ApplicationCreated
36 from pyramid.renderers import render_to_response
35 from pyramid.renderers import render_to_response
37
36
38 from rhodecode.model import meta
37 from rhodecode.model import meta
39 from rhodecode.config import patches
38 from rhodecode.config import patches
40 from rhodecode.config import utils as config_utils
39 from rhodecode.config import utils as config_utils
41 from rhodecode.config.environment import load_pyramid_environment
40 from rhodecode.config.environment import load_pyramid_environment
42
41
43 from rhodecode.lib.middleware.vcs import VCSMiddleware
42 from rhodecode.lib.middleware.vcs import VCSMiddleware
44 from rhodecode.lib.request import Request
43 from rhodecode.lib.request import Request
45 from rhodecode.lib.vcs import VCSCommunicationError
44 from rhodecode.lib.vcs import VCSCommunicationError
46 from rhodecode.lib.exceptions import VCSServerUnavailable
45 from rhodecode.lib.exceptions import VCSServerUnavailable
47 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
46 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
48 from rhodecode.lib.middleware.https_fixup import HttpsFixup
47 from rhodecode.lib.middleware.https_fixup import HttpsFixup
49 from rhodecode.lib.celerylib.loader import configure_celery
48 from rhodecode.lib.celerylib.loader import configure_celery
50 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
49 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
51 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
50 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
52 from rhodecode.lib.exc_tracking import store_exception
51 from rhodecode.lib.exc_tracking import store_exception
53 from rhodecode.subscribers import (
52 from rhodecode.subscribers import (
54 scan_repositories_if_enabled, write_js_routes_if_enabled,
53 scan_repositories_if_enabled, write_js_routes_if_enabled,
55 write_metadata_if_needed, inject_app_settings)
54 write_metadata_if_needed, inject_app_settings)
56
55
57
56
58 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
59
58
60
59
61 def is_http_error(response):
60 def is_http_error(response):
62 # error which should have traceback
61 # error which should have traceback
63 return response.status_code > 499
62 return response.status_code > 499
64
63
65
64
66 def make_pyramid_app(global_config, **settings):
65 def make_pyramid_app(global_config, **settings):
67 """
66 """
68 Constructs the WSGI application based on Pyramid.
67 Constructs the WSGI application based on Pyramid.
69
68
70 Specials:
69 Specials:
71
70
72 * The application can also be integrated like a plugin via the call to
71 * The application can also be integrated like a plugin via the call to
73 `includeme`. This is accompanied with the other utility functions which
72 `includeme`. This is accompanied with the other utility functions which
74 are called. Changing this should be done with great care to not break
73 are called. Changing this should be done with great care to not break
75 cases when these fragments are assembled from another place.
74 cases when these fragments are assembled from another place.
76
75
77 """
76 """
78
77
79 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
78 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
80 # will be replaced by the value of the environment variable "NAME" in this case.
79 # will be replaced by the value of the environment variable "NAME" in this case.
81 environ = {
80 environ = {
82 'ENV_{}'.format(key): value for key, value in os.environ.items()}
81 'ENV_{}'.format(key): value for key, value in os.environ.items()}
83
82
84 global_config = _substitute_values(global_config, environ)
83 global_config = _substitute_values(global_config, environ)
85 settings = _substitute_values(settings, environ)
84 settings = _substitute_values(settings, environ)
86
85
87 sanitize_settings_and_apply_defaults(settings)
86 sanitize_settings_and_apply_defaults(settings)
88
87
89 config = Configurator(settings=settings)
88 config = Configurator(settings=settings)
90
89
91 # Apply compatibility patches
90 # Apply compatibility patches
92 patches.inspect_getargspec()
91 patches.inspect_getargspec()
93
92
94 load_pyramid_environment(global_config, settings)
93 load_pyramid_environment(global_config, settings)
95
94
96 # Static file view comes first
95 # Static file view comes first
97 includeme_first(config)
96 includeme_first(config)
98
97
99 includeme(config)
98 includeme(config)
100
99
101 pyramid_app = config.make_wsgi_app()
100 pyramid_app = config.make_wsgi_app()
102 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
101 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
103 pyramid_app.config = config
102 pyramid_app.config = config
104
103
105 config.configure_celery(global_config['__file__'])
104 config.configure_celery(global_config['__file__'])
106 # creating the app uses a connection - return it after we are done
105 # creating the app uses a connection - return it after we are done
107 meta.Session.remove()
106 meta.Session.remove()
108
107
109 log.info('Pyramid app %s created and configured.', pyramid_app)
108 log.info('Pyramid app %s created and configured.', pyramid_app)
110 return pyramid_app
109 return pyramid_app
111
110
112
111
113 def not_found_view(request):
112 def not_found_view(request):
114 """
113 """
115 This creates the view which should be registered as not-found-view to
114 This creates the view which should be registered as not-found-view to
116 pyramid.
115 pyramid.
117 """
116 """
118
117
119 if not getattr(request, 'vcs_call', None):
118 if not getattr(request, 'vcs_call', None):
120 # handle like regular case with our error_handler
119 # handle like regular case with our error_handler
121 return error_handler(HTTPNotFound(), request)
120 return error_handler(HTTPNotFound(), request)
122
121
123 # handle not found view as a vcs call
122 # handle not found view as a vcs call
124 settings = request.registry.settings
123 settings = request.registry.settings
125 ae_client = getattr(request, 'ae_client', None)
124 ae_client = getattr(request, 'ae_client', None)
126 vcs_app = VCSMiddleware(
125 vcs_app = VCSMiddleware(
127 HTTPNotFound(), request.registry, settings,
126 HTTPNotFound(), request.registry, settings,
128 appenlight_client=ae_client)
127 appenlight_client=ae_client)
129
128
130 return wsgiapp(vcs_app)(None, request)
129 return wsgiapp(vcs_app)(None, request)
131
130
132
131
133 def error_handler(exception, request):
132 def error_handler(exception, request):
134 import rhodecode
133 import rhodecode
135 from rhodecode.lib import helpers
134 from rhodecode.lib import helpers
136
135
137 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
136 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
138
137
139 base_response = HTTPInternalServerError()
138 base_response = HTTPInternalServerError()
140 # prefer original exception for the response since it may have headers set
139 # prefer original exception for the response since it may have headers set
141 if isinstance(exception, HTTPException):
140 if isinstance(exception, HTTPException):
142 base_response = exception
141 base_response = exception
143 elif isinstance(exception, VCSCommunicationError):
142 elif isinstance(exception, VCSCommunicationError):
144 base_response = VCSServerUnavailable()
143 base_response = VCSServerUnavailable()
145
144
146 if is_http_error(base_response):
145 if is_http_error(base_response):
147 log.exception(
146 log.exception(
148 'error occurred handling this request for path: %s', request.path)
147 'error occurred handling this request for path: %s', request.path)
149
148
150 error_explanation = base_response.explanation or str(base_response)
149 error_explanation = base_response.explanation or str(base_response)
151 if base_response.status_code == 404:
150 if base_response.status_code == 404:
152 error_explanation += " Or you don't have permission to access it."
151 error_explanation += " Or you don't have permission to access it."
153 c = AttributeDict()
152 c = AttributeDict()
154 c.error_message = base_response.status
153 c.error_message = base_response.status
155 c.error_explanation = error_explanation
154 c.error_explanation = error_explanation
156 c.visual = AttributeDict()
155 c.visual = AttributeDict()
157
156
158 c.visual.rhodecode_support_url = (
157 c.visual.rhodecode_support_url = (
159 request.registry.settings.get('rhodecode_support_url') or
158 request.registry.settings.get('rhodecode_support_url') or
160 request.route_url('rhodecode_support')
159 request.route_url('rhodecode_support')
161 )
160 )
162 c.redirect_time = 0
161 c.redirect_time = 0
163 c.rhodecode_name = rhodecode_title
162 c.rhodecode_name = rhodecode_title
164 if not c.rhodecode_name:
163 if not c.rhodecode_name:
165 c.rhodecode_name = 'Rhodecode'
164 c.rhodecode_name = 'Rhodecode'
166
165
167 c.causes = []
166 c.causes = []
168 if is_http_error(base_response):
167 if is_http_error(base_response):
169 c.causes.append('Server is overloaded.')
168 c.causes.append('Server is overloaded.')
170 c.causes.append('Server database connection is lost.')
169 c.causes.append('Server database connection is lost.')
171 c.causes.append('Server expected unhandled error.')
170 c.causes.append('Server expected unhandled error.')
172
171
173 if hasattr(base_response, 'causes'):
172 if hasattr(base_response, 'causes'):
174 c.causes = base_response.causes
173 c.causes = base_response.causes
175
174
176 c.messages = helpers.flash.pop_messages(request=request)
175 c.messages = helpers.flash.pop_messages(request=request)
177
176
178 exc_info = sys.exc_info()
177 exc_info = sys.exc_info()
179 c.exception_id = id(exc_info)
178 c.exception_id = id(exc_info)
180 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
179 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
181 or base_response.status_code > 499
180 or base_response.status_code > 499
182 c.exception_id_url = request.route_url(
181 c.exception_id_url = request.route_url(
183 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
182 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
184
183
185 if c.show_exception_id:
184 if c.show_exception_id:
186 store_exception(c.exception_id, exc_info)
185 store_exception(c.exception_id, exc_info)
187
186
188 response = render_to_response(
187 response = render_to_response(
189 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
188 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
190 response=base_response)
189 response=base_response)
191
190
192 return response
191 return response
193
192
194
193
195 def includeme_first(config):
194 def includeme_first(config):
196 # redirect automatic browser favicon.ico requests to correct place
195 # redirect automatic browser favicon.ico requests to correct place
197 def favicon_redirect(context, request):
196 def favicon_redirect(context, request):
198 return HTTPFound(
197 return HTTPFound(
199 request.static_path('rhodecode:public/images/favicon.ico'))
198 request.static_path('rhodecode:public/images/favicon.ico'))
200
199
201 config.add_view(favicon_redirect, route_name='favicon')
200 config.add_view(favicon_redirect, route_name='favicon')
202 config.add_route('favicon', '/favicon.ico')
201 config.add_route('favicon', '/favicon.ico')
203
202
204 def robots_redirect(context, request):
203 def robots_redirect(context, request):
205 return HTTPFound(
204 return HTTPFound(
206 request.static_path('rhodecode:public/robots.txt'))
205 request.static_path('rhodecode:public/robots.txt'))
207
206
208 config.add_view(robots_redirect, route_name='robots')
207 config.add_view(robots_redirect, route_name='robots')
209 config.add_route('robots', '/robots.txt')
208 config.add_route('robots', '/robots.txt')
210
209
211 config.add_static_view(
210 config.add_static_view(
212 '_static/deform', 'deform:static')
211 '_static/deform', 'deform:static')
213 config.add_static_view(
212 config.add_static_view(
214 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
213 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
215
214
216
215
217 def includeme(config):
216 def includeme(config):
218 settings = config.registry.settings
217 settings = config.registry.settings
219 config.set_request_factory(Request)
218 config.set_request_factory(Request)
220
219
221 # plugin information
220 # plugin information
222 config.registry.rhodecode_plugins = collections.OrderedDict()
221 config.registry.rhodecode_plugins = collections.OrderedDict()
223
222
224 config.add_directive(
223 config.add_directive(
225 'register_rhodecode_plugin', register_rhodecode_plugin)
224 'register_rhodecode_plugin', register_rhodecode_plugin)
226
225
227 config.add_directive('configure_celery', configure_celery)
226 config.add_directive('configure_celery', configure_celery)
228
227
229 if asbool(settings.get('appenlight', 'false')):
228 if asbool(settings.get('appenlight', 'false')):
230 config.include('appenlight_client.ext.pyramid_tween')
229 config.include('appenlight_client.ext.pyramid_tween')
231
230
232 # Includes which are required. The application would fail without them.
231 # Includes which are required. The application would fail without them.
233 config.include('pyramid_mako')
232 config.include('pyramid_mako')
234 config.include('pyramid_beaker')
233 config.include('pyramid_beaker')
235 config.include('rhodecode.lib.caches')
234 config.include('rhodecode.lib.caches')
236 config.include('rhodecode.lib.rc_cache')
235 config.include('rhodecode.lib.rc_cache')
237
236
238 config.include('rhodecode.authentication')
237 config.include('rhodecode.authentication')
239 config.include('rhodecode.integrations')
238 config.include('rhodecode.integrations')
240
239
241 # apps
240 # apps
242 config.include('rhodecode.apps._base')
241 config.include('rhodecode.apps._base')
243 config.include('rhodecode.apps.ops')
242 config.include('rhodecode.apps.ops')
244
243
245 config.include('rhodecode.apps.admin')
244 config.include('rhodecode.apps.admin')
246 config.include('rhodecode.apps.channelstream')
245 config.include('rhodecode.apps.channelstream')
247 config.include('rhodecode.apps.login')
246 config.include('rhodecode.apps.login')
248 config.include('rhodecode.apps.home')
247 config.include('rhodecode.apps.home')
249 config.include('rhodecode.apps.journal')
248 config.include('rhodecode.apps.journal')
250 config.include('rhodecode.apps.repository')
249 config.include('rhodecode.apps.repository')
251 config.include('rhodecode.apps.repo_group')
250 config.include('rhodecode.apps.repo_group')
252 config.include('rhodecode.apps.user_group')
251 config.include('rhodecode.apps.user_group')
253 config.include('rhodecode.apps.search')
252 config.include('rhodecode.apps.search')
254 config.include('rhodecode.apps.user_profile')
253 config.include('rhodecode.apps.user_profile')
255 config.include('rhodecode.apps.user_group_profile')
254 config.include('rhodecode.apps.user_group_profile')
256 config.include('rhodecode.apps.my_account')
255 config.include('rhodecode.apps.my_account')
257 config.include('rhodecode.apps.svn_support')
256 config.include('rhodecode.apps.svn_support')
258 config.include('rhodecode.apps.ssh_support')
257 config.include('rhodecode.apps.ssh_support')
259 config.include('rhodecode.apps.gist')
258 config.include('rhodecode.apps.gist')
260
259
261 config.include('rhodecode.apps.debug_style')
260 config.include('rhodecode.apps.debug_style')
262 config.include('rhodecode.tweens')
261 config.include('rhodecode.tweens')
263 config.include('rhodecode.api')
262 config.include('rhodecode.api')
264
263
265 config.add_route(
264 config.add_route(
266 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
265 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
267
266
268 config.add_translation_dirs('rhodecode:i18n/')
267 config.add_translation_dirs('rhodecode:i18n/')
269 settings['default_locale_name'] = settings.get('lang', 'en')
268 settings['default_locale_name'] = settings.get('lang', 'en')
270
269
271 # Add subscribers.
270 # Add subscribers.
272 config.add_subscriber(inject_app_settings, ApplicationCreated)
271 config.add_subscriber(inject_app_settings, ApplicationCreated)
273 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
272 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
274 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
273 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
275 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
274 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
276
275
277
276
278 # request custom methods
277 # request custom methods
279 config.add_request_method(
278 config.add_request_method(
280 'rhodecode.lib.partial_renderer.get_partial_renderer',
279 'rhodecode.lib.partial_renderer.get_partial_renderer',
281 'get_partial_renderer')
280 'get_partial_renderer')
282
281
283 # Set the authorization policy.
282 # Set the authorization policy.
284 authz_policy = ACLAuthorizationPolicy()
283 authz_policy = ACLAuthorizationPolicy()
285 config.set_authorization_policy(authz_policy)
284 config.set_authorization_policy(authz_policy)
286
285
287 # Set the default renderer for HTML templates to mako.
286 # Set the default renderer for HTML templates to mako.
288 config.add_mako_renderer('.html')
287 config.add_mako_renderer('.html')
289
288
290 config.add_renderer(
289 config.add_renderer(
291 name='json_ext',
290 name='json_ext',
292 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
291 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
293
292
294 # include RhodeCode plugins
293 # include RhodeCode plugins
295 includes = aslist(settings.get('rhodecode.includes', []))
294 includes = aslist(settings.get('rhodecode.includes', []))
296 for inc in includes:
295 for inc in includes:
297 config.include(inc)
296 config.include(inc)
298
297
299 # custom not found view, if our pyramid app doesn't know how to handle
298 # custom not found view, if our pyramid app doesn't know how to handle
300 # the request pass it to potential VCS handling ap
299 # the request pass it to potential VCS handling ap
301 config.add_notfound_view(not_found_view)
300 config.add_notfound_view(not_found_view)
302 if not settings.get('debugtoolbar.enabled', False):
301 if not settings.get('debugtoolbar.enabled', False):
303 # disabled debugtoolbar handle all exceptions via the error_handlers
302 # disabled debugtoolbar handle all exceptions via the error_handlers
304 config.add_view(error_handler, context=Exception)
303 config.add_view(error_handler, context=Exception)
305
304
306 # all errors including 403/404/50X
305 # all errors including 403/404/50X
307 config.add_view(error_handler, context=HTTPError)
306 config.add_view(error_handler, context=HTTPError)
308
307
309
308
310 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
309 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
311 """
310 """
312 Apply outer WSGI middlewares around the application.
311 Apply outer WSGI middlewares around the application.
313 """
312 """
314 registry = config.registry
313 registry = config.registry
315 settings = registry.settings
314 settings = registry.settings
316
315
317 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
316 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
318 pyramid_app = HttpsFixup(pyramid_app, settings)
317 pyramid_app = HttpsFixup(pyramid_app, settings)
319
318
320 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
319 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
321 pyramid_app, settings)
320 pyramid_app, settings)
322 registry.ae_client = _ae_client
321 registry.ae_client = _ae_client
323
322
324 if settings['gzip_responses']:
323 if settings['gzip_responses']:
325 pyramid_app = make_gzip_middleware(
324 pyramid_app = make_gzip_middleware(
326 pyramid_app, settings, compress_level=1)
325 pyramid_app, settings, compress_level=1)
327
326
328 # this should be the outer most middleware in the wsgi stack since
327 # this should be the outer most middleware in the wsgi stack since
329 # middleware like Routes make database calls
328 # middleware like Routes make database calls
330 def pyramid_app_with_cleanup(environ, start_response):
329 def pyramid_app_with_cleanup(environ, start_response):
331 try:
330 try:
332 return pyramid_app(environ, start_response)
331 return pyramid_app(environ, start_response)
333 finally:
332 finally:
334 # Dispose current database session and rollback uncommitted
333 # Dispose current database session and rollback uncommitted
335 # transactions.
334 # transactions.
336 meta.Session.remove()
335 meta.Session.remove()
337
336
338 # In a single threaded mode server, on non sqlite db we should have
337 # In a single threaded mode server, on non sqlite db we should have
339 # '0 Current Checked out connections' at the end of a request,
338 # '0 Current Checked out connections' at the end of a request,
340 # if not, then something, somewhere is leaving a connection open
339 # if not, then something, somewhere is leaving a connection open
341 pool = meta.Base.metadata.bind.engine.pool
340 pool = meta.Base.metadata.bind.engine.pool
342 log.debug('sa pool status: %s', pool.status())
341 log.debug('sa pool status: %s', pool.status())
342 log.debug('Request processing finalized')
343
343
344 return pyramid_app_with_cleanup
344 return pyramid_app_with_cleanup
345
345
346
346
347 def sanitize_settings_and_apply_defaults(settings):
347 def sanitize_settings_and_apply_defaults(settings):
348 """
348 """
349 Applies settings defaults and does all type conversion.
349 Applies settings defaults and does all type conversion.
350
350
351 We would move all settings parsing and preparation into this place, so that
351 We would move all settings parsing and preparation into this place, so that
352 we have only one place left which deals with this part. The remaining parts
352 we have only one place left which deals with this part. The remaining parts
353 of the application would start to rely fully on well prepared settings.
353 of the application would start to rely fully on well prepared settings.
354
354
355 This piece would later be split up per topic to avoid a big fat monster
355 This piece would later be split up per topic to avoid a big fat monster
356 function.
356 function.
357 """
357 """
358
358
359 settings.setdefault('rhodecode.edition', 'Community Edition')
359 settings.setdefault('rhodecode.edition', 'Community Edition')
360
360
361 if 'mako.default_filters' not in settings:
361 if 'mako.default_filters' not in settings:
362 # set custom default filters if we don't have it defined
362 # set custom default filters if we don't have it defined
363 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
363 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
364 settings['mako.default_filters'] = 'h_filter'
364 settings['mako.default_filters'] = 'h_filter'
365
365
366 if 'mako.directories' not in settings:
366 if 'mako.directories' not in settings:
367 mako_directories = settings.setdefault('mako.directories', [
367 mako_directories = settings.setdefault('mako.directories', [
368 # Base templates of the original application
368 # Base templates of the original application
369 'rhodecode:templates',
369 'rhodecode:templates',
370 ])
370 ])
371 log.debug(
371 log.debug(
372 "Using the following Mako template directories: %s",
372 "Using the following Mako template directories: %s",
373 mako_directories)
373 mako_directories)
374
374
375 # Default includes, possible to change as a user
375 # Default includes, possible to change as a user
376 pyramid_includes = settings.setdefault('pyramid.includes', [
376 pyramid_includes = settings.setdefault('pyramid.includes', [
377 'rhodecode.lib.middleware.request_wrapper',
377 'rhodecode.lib.middleware.request_wrapper',
378 ])
378 ])
379 log.debug(
379 log.debug(
380 "Using the following pyramid.includes: %s",
380 "Using the following pyramid.includes: %s",
381 pyramid_includes)
381 pyramid_includes)
382
382
383 # TODO: johbo: Re-think this, usually the call to config.include
383 # TODO: johbo: Re-think this, usually the call to config.include
384 # should allow to pass in a prefix.
384 # should allow to pass in a prefix.
385 settings.setdefault('rhodecode.api.url', '/_admin/api')
385 settings.setdefault('rhodecode.api.url', '/_admin/api')
386
386
387 # Sanitize generic settings.
387 # Sanitize generic settings.
388 _list_setting(settings, 'default_encoding', 'UTF-8')
388 _list_setting(settings, 'default_encoding', 'UTF-8')
389 _bool_setting(settings, 'is_test', 'false')
389 _bool_setting(settings, 'is_test', 'false')
390 _bool_setting(settings, 'gzip_responses', 'false')
390 _bool_setting(settings, 'gzip_responses', 'false')
391
391
392 # Call split out functions that sanitize settings for each topic.
392 # Call split out functions that sanitize settings for each topic.
393 _sanitize_appenlight_settings(settings)
393 _sanitize_appenlight_settings(settings)
394 _sanitize_vcs_settings(settings)
394 _sanitize_vcs_settings(settings)
395 _sanitize_cache_settings(settings)
395 _sanitize_cache_settings(settings)
396
396
397 # configure instance id
397 # configure instance id
398 config_utils.set_instance_id(settings)
398 config_utils.set_instance_id(settings)
399
399
400 return settings
400 return settings
401
401
402
402
403 def _sanitize_appenlight_settings(settings):
403 def _sanitize_appenlight_settings(settings):
404 _bool_setting(settings, 'appenlight', 'false')
404 _bool_setting(settings, 'appenlight', 'false')
405
405
406
406
407 def _sanitize_vcs_settings(settings):
407 def _sanitize_vcs_settings(settings):
408 """
408 """
409 Applies settings defaults and does type conversion for all VCS related
409 Applies settings defaults and does type conversion for all VCS related
410 settings.
410 settings.
411 """
411 """
412 _string_setting(settings, 'vcs.svn.compatible_version', '')
412 _string_setting(settings, 'vcs.svn.compatible_version', '')
413 _string_setting(settings, 'git_rev_filter', '--all')
413 _string_setting(settings, 'git_rev_filter', '--all')
414 _string_setting(settings, 'vcs.hooks.protocol', 'http')
414 _string_setting(settings, 'vcs.hooks.protocol', 'http')
415 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
415 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
416 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
416 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
417 _string_setting(settings, 'vcs.server', '')
417 _string_setting(settings, 'vcs.server', '')
418 _string_setting(settings, 'vcs.server.log_level', 'debug')
418 _string_setting(settings, 'vcs.server.log_level', 'debug')
419 _string_setting(settings, 'vcs.server.protocol', 'http')
419 _string_setting(settings, 'vcs.server.protocol', 'http')
420 _bool_setting(settings, 'startup.import_repos', 'false')
420 _bool_setting(settings, 'startup.import_repos', 'false')
421 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
421 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
422 _bool_setting(settings, 'vcs.server.enable', 'true')
422 _bool_setting(settings, 'vcs.server.enable', 'true')
423 _bool_setting(settings, 'vcs.start_server', 'false')
423 _bool_setting(settings, 'vcs.start_server', 'false')
424 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
424 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
425 _int_setting(settings, 'vcs.connection_timeout', 3600)
425 _int_setting(settings, 'vcs.connection_timeout', 3600)
426
426
427 # Support legacy values of vcs.scm_app_implementation. Legacy
427 # Support legacy values of vcs.scm_app_implementation. Legacy
428 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
428 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
429 # which is now mapped to 'http'.
429 # which is now mapped to 'http'.
430 scm_app_impl = settings['vcs.scm_app_implementation']
430 scm_app_impl = settings['vcs.scm_app_implementation']
431 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
431 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
432 settings['vcs.scm_app_implementation'] = 'http'
432 settings['vcs.scm_app_implementation'] = 'http'
433
433
434
434
435 def _sanitize_cache_settings(settings):
435 def _sanitize_cache_settings(settings):
436 _string_setting(settings, 'cache_dir',
436 _string_setting(settings, 'cache_dir',
437 os.path.join(tempfile.gettempdir(), 'rc_cache'))
437 os.path.join(tempfile.gettempdir(), 'rc_cache'))
438 # cache_perms
438 # cache_perms
439 _string_setting(
439 _string_setting(
440 settings,
440 settings,
441 'rc_cache.cache_perms.backend',
441 'rc_cache.cache_perms.backend',
442 'dogpile.cache.rc.file_namespace')
442 'dogpile.cache.rc.file_namespace')
443 _int_setting(
443 _int_setting(
444 settings,
444 settings,
445 'rc_cache.cache_perms.expiration_time',
445 'rc_cache.cache_perms.expiration_time',
446 60)
446 60)
447 _string_setting(
447 _string_setting(
448 settings,
448 settings,
449 'rc_cache.cache_perms.arguments.filename',
449 'rc_cache.cache_perms.arguments.filename',
450 os.path.join(tempfile.gettempdir(), 'rc_cache_1'))
450 os.path.join(tempfile.gettempdir(), 'rc_cache_1'))
451
451
452 # cache_repo
452 # cache_repo
453 _string_setting(
453 _string_setting(
454 settings,
454 settings,
455 'rc_cache.cache_repo.backend',
455 'rc_cache.cache_repo.backend',
456 'dogpile.cache.rc.file_namespace')
456 'dogpile.cache.rc.file_namespace')
457 _int_setting(
457 _int_setting(
458 settings,
458 settings,
459 'rc_cache.cache_repo.expiration_time',
459 'rc_cache.cache_repo.expiration_time',
460 60)
460 60)
461 _string_setting(
461 _string_setting(
462 settings,
462 settings,
463 'rc_cache.cache_repo.arguments.filename',
463 'rc_cache.cache_repo.arguments.filename',
464 os.path.join(tempfile.gettempdir(), 'rc_cache_2'))
464 os.path.join(tempfile.gettempdir(), 'rc_cache_2'))
465
465
466 # sql_cache_short
466 # sql_cache_short
467 _string_setting(
467 _string_setting(
468 settings,
468 settings,
469 'rc_cache.sql_cache_short.backend',
469 'rc_cache.sql_cache_short.backend',
470 'dogpile.cache.rc.memory_lru')
470 'dogpile.cache.rc.memory_lru')
471 _int_setting(
471 _int_setting(
472 settings,
472 settings,
473 'rc_cache.sql_cache_short.expiration_time',
473 'rc_cache.sql_cache_short.expiration_time',
474 30)
474 30)
475 _int_setting(
475 _int_setting(
476 settings,
476 settings,
477 'rc_cache.sql_cache_short.max_size',
477 'rc_cache.sql_cache_short.max_size',
478 10000)
478 10000)
479
479
480
480
481 def _int_setting(settings, name, default):
481 def _int_setting(settings, name, default):
482 settings[name] = int(settings.get(name, default))
482 settings[name] = int(settings.get(name, default))
483
483
484
484
485 def _bool_setting(settings, name, default):
485 def _bool_setting(settings, name, default):
486 input_val = settings.get(name, default)
486 input_val = settings.get(name, default)
487 if isinstance(input_val, unicode):
487 if isinstance(input_val, unicode):
488 input_val = input_val.encode('utf8')
488 input_val = input_val.encode('utf8')
489 settings[name] = asbool(input_val)
489 settings[name] = asbool(input_val)
490
490
491
491
492 def _list_setting(settings, name, default):
492 def _list_setting(settings, name, default):
493 raw_value = settings.get(name, default)
493 raw_value = settings.get(name, default)
494
494
495 old_separator = ','
495 old_separator = ','
496 if old_separator in raw_value:
496 if old_separator in raw_value:
497 # If we get a comma separated list, pass it to our own function.
497 # If we get a comma separated list, pass it to our own function.
498 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
498 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
499 else:
499 else:
500 # Otherwise we assume it uses pyramids space/newline separation.
500 # Otherwise we assume it uses pyramids space/newline separation.
501 settings[name] = aslist(raw_value)
501 settings[name] = aslist(raw_value)
502
502
503
503
504 def _string_setting(settings, name, default, lower=True):
504 def _string_setting(settings, name, default, lower=True):
505 value = settings.get(name, default)
505 value = settings.get(name, default)
506 if lower:
506 if lower:
507 value = value.lower()
507 value = value.lower()
508 settings[name] = value
508 settings[name] = value
509
509
510
510
511 def _substitute_values(mapping, substitutions):
511 def _substitute_values(mapping, substitutions):
512 result = {
512 result = {
513 # Note: Cannot use regular replacements, since they would clash
513 # Note: Cannot use regular replacements, since they would clash
514 # with the implementation of ConfigParser. Using "format" instead.
514 # with the implementation of ConfigParser. Using "format" instead.
515 key: value.format(**substitutions)
515 key: value.format(**substitutions)
516 for key, value in mapping.items()
516 for key, value in mapping.items()
517 }
517 }
518 return result
518 return result
General Comments 0
You need to be logged in to leave comments. Login now