##// END OF EJS Templates
config: Use rhodecode aslist if commas included in list settings otherwise pyramids aslist.
Martin Bornhold -
r604:d8ead9a9 default
parent child Browse files
Show More
@@ -1,462 +1,465 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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 """
21 """
22 Pylons middleware initialization
22 Pylons middleware initialization
23 """
23 """
24 import logging
24 import logging
25 from collections import OrderedDict
25 from collections import OrderedDict
26
26
27 from paste.registry import RegistryManager
27 from paste.registry import RegistryManager
28 from paste.gzipper import make_gzip_middleware
28 from paste.gzipper import make_gzip_middleware
29 from pylons.wsgiapp import PylonsApp
29 from pylons.wsgiapp import PylonsApp
30 from pyramid.authorization import ACLAuthorizationPolicy
30 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.config import Configurator
31 from pyramid.config import Configurator
32 from pyramid.settings import asbool, aslist
32 from pyramid.settings import asbool, aslist
33 from pyramid.wsgi import wsgiapp
33 from pyramid.wsgi import wsgiapp
34 from pyramid.httpexceptions import HTTPError, HTTPInternalServerError
34 from pyramid.httpexceptions import HTTPError, HTTPInternalServerError
35 from pylons.controllers.util import redirect
35 from pylons.controllers.util import redirect
36 from pyramid.events import ApplicationCreated
36 from pyramid.events import ApplicationCreated
37 import pyramid.httpexceptions as httpexceptions
37 import pyramid.httpexceptions as httpexceptions
38 from pyramid.renderers import render_to_response
38 from pyramid.renderers import render_to_response
39 from routes.middleware import RoutesMiddleware
39 from routes.middleware import RoutesMiddleware
40 import routes.util
40 import routes.util
41
41
42 import rhodecode
42 import rhodecode
43 import rhodecode.integrations # do not remove this as it registers celery tasks
43 import rhodecode.integrations # do not remove this as it registers celery tasks
44 from rhodecode.config import patches
44 from rhodecode.config import patches
45 from rhodecode.config.routing import STATIC_FILE_PREFIX
45 from rhodecode.config.routing import STATIC_FILE_PREFIX
46 from rhodecode.config.environment import (
46 from rhodecode.config.environment import (
47 load_environment, load_pyramid_environment)
47 load_environment, load_pyramid_environment)
48 from rhodecode.lib.middleware import csrf
48 from rhodecode.lib.middleware import csrf
49 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
50 from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
50 from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
51 from rhodecode.lib.middleware.https_fixup import HttpsFixup
51 from rhodecode.lib.middleware.https_fixup import HttpsFixup
52 from rhodecode.lib.middleware.vcs import VCSMiddleware
52 from rhodecode.lib.middleware.vcs import VCSMiddleware
53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
54 from rhodecode.lib.utils2 import aslist as rhodecode_aslist
54 from rhodecode.subscribers import scan_repositories_if_enabled
55 from rhodecode.subscribers import scan_repositories_if_enabled
55
56
56
57
57 log = logging.getLogger(__name__)
58 log = logging.getLogger(__name__)
58
59
59
60
60 # this is used to avoid avoid the route lookup overhead in routesmiddleware
61 # this is used to avoid avoid the route lookup overhead in routesmiddleware
61 # for certain routes which won't go to pylons to - eg. static files, debugger
62 # for certain routes which won't go to pylons to - eg. static files, debugger
62 # it is only needed for the pylons migration and can be removed once complete
63 # it is only needed for the pylons migration and can be removed once complete
63 class SkippableRoutesMiddleware(RoutesMiddleware):
64 class SkippableRoutesMiddleware(RoutesMiddleware):
64 """ Routes middleware that allows you to skip prefixes """
65 """ Routes middleware that allows you to skip prefixes """
65
66
66 def __init__(self, *args, **kw):
67 def __init__(self, *args, **kw):
67 self.skip_prefixes = kw.pop('skip_prefixes', [])
68 self.skip_prefixes = kw.pop('skip_prefixes', [])
68 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
69 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
69
70
70 def __call__(self, environ, start_response):
71 def __call__(self, environ, start_response):
71 for prefix in self.skip_prefixes:
72 for prefix in self.skip_prefixes:
72 if environ['PATH_INFO'].startswith(prefix):
73 if environ['PATH_INFO'].startswith(prefix):
73 # added to avoid the case when a missing /_static route falls
74 # added to avoid the case when a missing /_static route falls
74 # through to pylons and causes an exception as pylons is
75 # through to pylons and causes an exception as pylons is
75 # expecting wsgiorg.routingargs to be set in the environ
76 # expecting wsgiorg.routingargs to be set in the environ
76 # by RoutesMiddleware.
77 # by RoutesMiddleware.
77 if 'wsgiorg.routing_args' not in environ:
78 if 'wsgiorg.routing_args' not in environ:
78 environ['wsgiorg.routing_args'] = (None, {})
79 environ['wsgiorg.routing_args'] = (None, {})
79 return self.app(environ, start_response)
80 return self.app(environ, start_response)
80
81
81 return super(SkippableRoutesMiddleware, self).__call__(
82 return super(SkippableRoutesMiddleware, self).__call__(
82 environ, start_response)
83 environ, start_response)
83
84
84
85
85 def make_app(global_conf, static_files=True, **app_conf):
86 def make_app(global_conf, static_files=True, **app_conf):
86 """Create a Pylons WSGI application and return it
87 """Create a Pylons WSGI application and return it
87
88
88 ``global_conf``
89 ``global_conf``
89 The inherited configuration for this application. Normally from
90 The inherited configuration for this application. Normally from
90 the [DEFAULT] section of the Paste ini file.
91 the [DEFAULT] section of the Paste ini file.
91
92
92 ``app_conf``
93 ``app_conf``
93 The application's local configuration. Normally specified in
94 The application's local configuration. Normally specified in
94 the [app:<name>] section of the Paste ini file (where <name>
95 the [app:<name>] section of the Paste ini file (where <name>
95 defaults to main).
96 defaults to main).
96
97
97 """
98 """
98 # Apply compatibility patches
99 # Apply compatibility patches
99 patches.kombu_1_5_1_python_2_7_11()
100 patches.kombu_1_5_1_python_2_7_11()
100 patches.inspect_getargspec()
101 patches.inspect_getargspec()
101
102
102 # Configure the Pylons environment
103 # Configure the Pylons environment
103 config = load_environment(global_conf, app_conf)
104 config = load_environment(global_conf, app_conf)
104
105
105 # The Pylons WSGI app
106 # The Pylons WSGI app
106 app = PylonsApp(config=config)
107 app = PylonsApp(config=config)
107 if rhodecode.is_test:
108 if rhodecode.is_test:
108 app = csrf.CSRFDetector(app)
109 app = csrf.CSRFDetector(app)
109
110
110 expected_origin = config.get('expected_origin')
111 expected_origin = config.get('expected_origin')
111 if expected_origin:
112 if expected_origin:
112 # The API can be accessed from other Origins.
113 # The API can be accessed from other Origins.
113 app = csrf.OriginChecker(app, expected_origin,
114 app = csrf.OriginChecker(app, expected_origin,
114 skip_urls=[routes.util.url_for('api')])
115 skip_urls=[routes.util.url_for('api')])
115
116
116 # Establish the Registry for this application
117 # Establish the Registry for this application
117 app = RegistryManager(app)
118 app = RegistryManager(app)
118
119
119 app.config = config
120 app.config = config
120
121
121 return app
122 return app
122
123
123
124
124 def make_pyramid_app(global_config, **settings):
125 def make_pyramid_app(global_config, **settings):
125 """
126 """
126 Constructs the WSGI application based on Pyramid and wraps the Pylons based
127 Constructs the WSGI application based on Pyramid and wraps the Pylons based
127 application.
128 application.
128
129
129 Specials:
130 Specials:
130
131
131 * We migrate from Pylons to Pyramid. While doing this, we keep both
132 * We migrate from Pylons to Pyramid. While doing this, we keep both
132 frameworks functional. This involves moving some WSGI middlewares around
133 frameworks functional. This involves moving some WSGI middlewares around
133 and providing access to some data internals, so that the old code is
134 and providing access to some data internals, so that the old code is
134 still functional.
135 still functional.
135
136
136 * The application can also be integrated like a plugin via the call to
137 * The application can also be integrated like a plugin via the call to
137 `includeme`. This is accompanied with the other utility functions which
138 `includeme`. This is accompanied with the other utility functions which
138 are called. Changing this should be done with great care to not break
139 are called. Changing this should be done with great care to not break
139 cases when these fragments are assembled from another place.
140 cases when these fragments are assembled from another place.
140
141
141 """
142 """
142 # The edition string should be available in pylons too, so we add it here
143 # The edition string should be available in pylons too, so we add it here
143 # before copying the settings.
144 # before copying the settings.
144 settings.setdefault('rhodecode.edition', 'Community Edition')
145 settings.setdefault('rhodecode.edition', 'Community Edition')
145
146
146 # As long as our Pylons application does expect "unprepared" settings, make
147 # As long as our Pylons application does expect "unprepared" settings, make
147 # sure that we keep an unmodified copy. This avoids unintentional change of
148 # sure that we keep an unmodified copy. This avoids unintentional change of
148 # behavior in the old application.
149 # behavior in the old application.
149 settings_pylons = settings.copy()
150 settings_pylons = settings.copy()
150
151
151 sanitize_settings_and_apply_defaults(settings)
152 sanitize_settings_and_apply_defaults(settings)
152 config = Configurator(settings=settings)
153 config = Configurator(settings=settings)
153 add_pylons_compat_data(config.registry, global_config, settings_pylons)
154 add_pylons_compat_data(config.registry, global_config, settings_pylons)
154
155
155 load_pyramid_environment(global_config, settings)
156 load_pyramid_environment(global_config, settings)
156
157
157 includeme_first(config)
158 includeme_first(config)
158 includeme(config)
159 includeme(config)
159 pyramid_app = config.make_wsgi_app()
160 pyramid_app = config.make_wsgi_app()
160 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
161 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
161 return pyramid_app
162 return pyramid_app
162
163
163
164
164 def make_not_found_view(config):
165 def make_not_found_view(config):
165 """
166 """
166 This creates the view which should be registered as not-found-view to
167 This creates the view which should be registered as not-found-view to
167 pyramid. Basically it contains of the old pylons app, converted to a view.
168 pyramid. Basically it contains of the old pylons app, converted to a view.
168 Additionally it is wrapped by some other middlewares.
169 Additionally it is wrapped by some other middlewares.
169 """
170 """
170 settings = config.registry.settings
171 settings = config.registry.settings
171 vcs_server_enabled = settings['vcs.server.enable']
172 vcs_server_enabled = settings['vcs.server.enable']
172
173
173 # Make pylons app from unprepared settings.
174 # Make pylons app from unprepared settings.
174 pylons_app = make_app(
175 pylons_app = make_app(
175 config.registry._pylons_compat_global_config,
176 config.registry._pylons_compat_global_config,
176 **config.registry._pylons_compat_settings)
177 **config.registry._pylons_compat_settings)
177 config.registry._pylons_compat_config = pylons_app.config
178 config.registry._pylons_compat_config = pylons_app.config
178
179
179 # Appenlight monitoring.
180 # Appenlight monitoring.
180 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
181 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
181 pylons_app, settings)
182 pylons_app, settings)
182
183
183 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find
184 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find
184 # a view to handle the request. Therefore we wrap it around the pylons app.
185 # a view to handle the request. Therefore we wrap it around the pylons app.
185 if vcs_server_enabled:
186 if vcs_server_enabled:
186 pylons_app = VCSMiddleware(
187 pylons_app = VCSMiddleware(
187 pylons_app, settings, appenlight_client, registry=config.registry)
188 pylons_app, settings, appenlight_client, registry=config.registry)
188
189
189 pylons_app_as_view = wsgiapp(pylons_app)
190 pylons_app_as_view = wsgiapp(pylons_app)
190
191
191 # Protect from VCS Server error related pages when server is not available
192 # Protect from VCS Server error related pages when server is not available
192 if not vcs_server_enabled:
193 if not vcs_server_enabled:
193 pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
194 pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
194
195
195 def pylons_app_with_error_handler(context, request):
196 def pylons_app_with_error_handler(context, request):
196 """
197 """
197 Handle exceptions from rc pylons app:
198 Handle exceptions from rc pylons app:
198
199
199 - old webob type exceptions get converted to pyramid exceptions
200 - old webob type exceptions get converted to pyramid exceptions
200 - pyramid exceptions are passed to the error handler view
201 - pyramid exceptions are passed to the error handler view
201 """
202 """
202 def is_vcs_response(request):
203 def is_vcs_response(request):
203 return True == request.environ.get(
204 return True == request.environ.get(
204 'rhodecode.vcs.skip_error_handling')
205 'rhodecode.vcs.skip_error_handling')
205
206
206 def is_webob_error(response):
207 def is_webob_error(response):
207 # webob type error responses
208 # webob type error responses
208 return (400 <= response.status_int <= 599)
209 return (400 <= response.status_int <= 599)
209
210
210 try:
211 try:
211 response = pylons_app_as_view(context, request)
212 response = pylons_app_as_view(context, request)
212 if is_webob_error(response) and not is_vcs_response(request):
213 if is_webob_error(response) and not is_vcs_response(request):
213 return error_handler(
214 return error_handler(
214 webob_to_pyramid_http_response(response), request)
215 webob_to_pyramid_http_response(response), request)
215 except HTTPError as e: # pyramid type exceptions
216 except HTTPError as e: # pyramid type exceptions
216 return error_handler(e, request)
217 return error_handler(e, request)
217 except Exception:
218 except Exception:
218 if settings.get('debugtoolbar.enabled', False):
219 if settings.get('debugtoolbar.enabled', False):
219 raise
220 raise
220 return error_handler(HTTPInternalServerError(), request)
221 return error_handler(HTTPInternalServerError(), request)
221 return response
222 return response
222
223
223 return pylons_app_with_error_handler
224 return pylons_app_with_error_handler
224
225
225
226
226 def add_pylons_compat_data(registry, global_config, settings):
227 def add_pylons_compat_data(registry, global_config, settings):
227 """
228 """
228 Attach data to the registry to support the Pylons integration.
229 Attach data to the registry to support the Pylons integration.
229 """
230 """
230 registry._pylons_compat_global_config = global_config
231 registry._pylons_compat_global_config = global_config
231 registry._pylons_compat_settings = settings
232 registry._pylons_compat_settings = settings
232
233
233
234
234 def webob_to_pyramid_http_response(webob_response):
235 def webob_to_pyramid_http_response(webob_response):
235 ResponseClass = httpexceptions.status_map[webob_response.status_int]
236 ResponseClass = httpexceptions.status_map[webob_response.status_int]
236 pyramid_response = ResponseClass(webob_response.status)
237 pyramid_response = ResponseClass(webob_response.status)
237 pyramid_response.status = webob_response.status
238 pyramid_response.status = webob_response.status
238 pyramid_response.headers.update(webob_response.headers)
239 pyramid_response.headers.update(webob_response.headers)
239 if pyramid_response.headers['content-type'] == 'text/html':
240 if pyramid_response.headers['content-type'] == 'text/html':
240 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
241 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
241 return pyramid_response
242 return pyramid_response
242
243
243
244
244 def error_handler(exception, request):
245 def error_handler(exception, request):
245 # TODO: dan: replace the old pylons error controller with this
246 # TODO: dan: replace the old pylons error controller with this
246 from rhodecode.model.settings import SettingsModel
247 from rhodecode.model.settings import SettingsModel
247 from rhodecode.lib.utils2 import AttributeDict
248 from rhodecode.lib.utils2 import AttributeDict
248
249
249 try:
250 try:
250 rc_config = SettingsModel().get_all_settings()
251 rc_config = SettingsModel().get_all_settings()
251 except Exception:
252 except Exception:
252 log.exception('failed to fetch settings')
253 log.exception('failed to fetch settings')
253 rc_config = {}
254 rc_config = {}
254
255
255 base_response = HTTPInternalServerError()
256 base_response = HTTPInternalServerError()
256 # prefer original exception for the response since it may have headers set
257 # prefer original exception for the response since it may have headers set
257 if isinstance(exception, HTTPError):
258 if isinstance(exception, HTTPError):
258 base_response = exception
259 base_response = exception
259
260
260 c = AttributeDict()
261 c = AttributeDict()
261 c.error_message = base_response.status
262 c.error_message = base_response.status
262 c.error_explanation = base_response.explanation or str(base_response)
263 c.error_explanation = base_response.explanation or str(base_response)
263 c.visual = AttributeDict()
264 c.visual = AttributeDict()
264
265
265 c.visual.rhodecode_support_url = (
266 c.visual.rhodecode_support_url = (
266 request.registry.settings.get('rhodecode_support_url') or
267 request.registry.settings.get('rhodecode_support_url') or
267 request.route_url('rhodecode_support')
268 request.route_url('rhodecode_support')
268 )
269 )
269 c.redirect_time = 0
270 c.redirect_time = 0
270 c.rhodecode_name = rc_config.get('rhodecode_title', '')
271 c.rhodecode_name = rc_config.get('rhodecode_title', '')
271 if not c.rhodecode_name:
272 if not c.rhodecode_name:
272 c.rhodecode_name = 'Rhodecode'
273 c.rhodecode_name = 'Rhodecode'
273
274
274 response = render_to_response(
275 response = render_to_response(
275 '/errors/error_document.html', {'c': c}, request=request,
276 '/errors/error_document.html', {'c': c}, request=request,
276 response=base_response)
277 response=base_response)
277
278
278 return response
279 return response
279
280
280
281
281 def includeme(config):
282 def includeme(config):
282 settings = config.registry.settings
283 settings = config.registry.settings
283
284
284 # plugin information
285 # plugin information
285 config.registry.rhodecode_plugins = OrderedDict()
286 config.registry.rhodecode_plugins = OrderedDict()
286
287
287 config.add_directive(
288 config.add_directive(
288 'register_rhodecode_plugin', register_rhodecode_plugin)
289 'register_rhodecode_plugin', register_rhodecode_plugin)
289
290
290 if asbool(settings.get('appenlight', 'false')):
291 if asbool(settings.get('appenlight', 'false')):
291 config.include('appenlight_client.ext.pyramid_tween')
292 config.include('appenlight_client.ext.pyramid_tween')
292
293
293 # Includes which are required. The application would fail without them.
294 # Includes which are required. The application would fail without them.
294 config.include('pyramid_mako')
295 config.include('pyramid_mako')
295 config.include('pyramid_beaker')
296 config.include('pyramid_beaker')
296 config.include('rhodecode.channelstream')
297 config.include('rhodecode.channelstream')
297 config.include('rhodecode.admin')
298 config.include('rhodecode.admin')
298 config.include('rhodecode.authentication')
299 config.include('rhodecode.authentication')
299 config.include('rhodecode.integrations')
300 config.include('rhodecode.integrations')
300 config.include('rhodecode.login')
301 config.include('rhodecode.login')
301 config.include('rhodecode.tweens')
302 config.include('rhodecode.tweens')
302 config.include('rhodecode.api')
303 config.include('rhodecode.api')
303 config.include('rhodecode.svn_support')
304 config.include('rhodecode.svn_support')
304 config.add_route(
305 config.add_route(
305 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
306 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
306
307
307 # Add subscribers.
308 # Add subscribers.
308 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
309 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
309
310
310 # Set the authorization policy.
311 # Set the authorization policy.
311 authz_policy = ACLAuthorizationPolicy()
312 authz_policy = ACLAuthorizationPolicy()
312 config.set_authorization_policy(authz_policy)
313 config.set_authorization_policy(authz_policy)
313
314
314 # Set the default renderer for HTML templates to mako.
315 # Set the default renderer for HTML templates to mako.
315 config.add_mako_renderer('.html')
316 config.add_mako_renderer('.html')
316
317
317 # include RhodeCode plugins
318 # include RhodeCode plugins
318 includes = aslist(settings.get('rhodecode.includes', []))
319 includes = aslist(settings.get('rhodecode.includes', []))
319 for inc in includes:
320 for inc in includes:
320 config.include(inc)
321 config.include(inc)
321
322
322 # This is the glue which allows us to migrate in chunks. By registering the
323 # This is the glue which allows us to migrate in chunks. By registering the
323 # pylons based application as the "Not Found" view in Pyramid, we will
324 # pylons based application as the "Not Found" view in Pyramid, we will
324 # fallback to the old application each time the new one does not yet know
325 # fallback to the old application each time the new one does not yet know
325 # how to handle a request.
326 # how to handle a request.
326 config.add_notfound_view(make_not_found_view(config))
327 config.add_notfound_view(make_not_found_view(config))
327
328
328 if not settings.get('debugtoolbar.enabled', False):
329 if not settings.get('debugtoolbar.enabled', False):
329 # if no toolbar, then any exception gets caught and rendered
330 # if no toolbar, then any exception gets caught and rendered
330 config.add_view(error_handler, context=Exception)
331 config.add_view(error_handler, context=Exception)
331
332
332 config.add_view(error_handler, context=HTTPError)
333 config.add_view(error_handler, context=HTTPError)
333
334
334
335
335 def includeme_first(config):
336 def includeme_first(config):
336 # redirect automatic browser favicon.ico requests to correct place
337 # redirect automatic browser favicon.ico requests to correct place
337 def favicon_redirect(context, request):
338 def favicon_redirect(context, request):
338 return redirect(
339 return redirect(
339 request.static_path('rhodecode:public/images/favicon.ico'))
340 request.static_path('rhodecode:public/images/favicon.ico'))
340
341
341 config.add_view(favicon_redirect, route_name='favicon')
342 config.add_view(favicon_redirect, route_name='favicon')
342 config.add_route('favicon', '/favicon.ico')
343 config.add_route('favicon', '/favicon.ico')
343
344
344 config.add_static_view(
345 config.add_static_view(
345 '_static/deform', 'deform:static')
346 '_static/deform', 'deform:static')
346 config.add_static_view(
347 config.add_static_view(
347 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
348 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
348
349
349
350
350 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
351 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
351 """
352 """
352 Apply outer WSGI middlewares around the application.
353 Apply outer WSGI middlewares around the application.
353
354
354 Part of this has been moved up from the Pylons layer, so that the
355 Part of this has been moved up from the Pylons layer, so that the
355 data is also available if old Pylons code is hit through an already ported
356 data is also available if old Pylons code is hit through an already ported
356 view.
357 view.
357 """
358 """
358 settings = config.registry.settings
359 settings = config.registry.settings
359
360
360 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
361 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
361 pyramid_app = HttpsFixup(pyramid_app, settings)
362 pyramid_app = HttpsFixup(pyramid_app, settings)
362
363
363 # Add RoutesMiddleware to support the pylons compatibility tween during
364 # Add RoutesMiddleware to support the pylons compatibility tween during
364 # migration to pyramid.
365 # migration to pyramid.
365 pyramid_app = SkippableRoutesMiddleware(
366 pyramid_app = SkippableRoutesMiddleware(
366 pyramid_app, config.registry._pylons_compat_config['routes.map'],
367 pyramid_app, config.registry._pylons_compat_config['routes.map'],
367 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
368 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
368
369
369 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
370 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
370
371
371 if settings['gzip_responses']:
372 if settings['gzip_responses']:
372 pyramid_app = make_gzip_middleware(
373 pyramid_app = make_gzip_middleware(
373 pyramid_app, settings, compress_level=1)
374 pyramid_app, settings, compress_level=1)
374
375
375 return pyramid_app
376 return pyramid_app
376
377
377
378
378 def sanitize_settings_and_apply_defaults(settings):
379 def sanitize_settings_and_apply_defaults(settings):
379 """
380 """
380 Applies settings defaults and does all type conversion.
381 Applies settings defaults and does all type conversion.
381
382
382 We would move all settings parsing and preparation into this place, so that
383 We would move all settings parsing and preparation into this place, so that
383 we have only one place left which deals with this part. The remaining parts
384 we have only one place left which deals with this part. The remaining parts
384 of the application would start to rely fully on well prepared settings.
385 of the application would start to rely fully on well prepared settings.
385
386
386 This piece would later be split up per topic to avoid a big fat monster
387 This piece would later be split up per topic to avoid a big fat monster
387 function.
388 function.
388 """
389 """
389
390
390 # Pyramid's mako renderer has to search in the templates folder so that the
391 # Pyramid's mako renderer has to search in the templates folder so that the
391 # old templates still work. Ported and new templates are expected to use
392 # old templates still work. Ported and new templates are expected to use
392 # real asset specifications for the includes.
393 # real asset specifications for the includes.
393 mako_directories = settings.setdefault('mako.directories', [
394 mako_directories = settings.setdefault('mako.directories', [
394 # Base templates of the original Pylons application
395 # Base templates of the original Pylons application
395 'rhodecode:templates',
396 'rhodecode:templates',
396 ])
397 ])
397 log.debug(
398 log.debug(
398 "Using the following Mako template directories: %s",
399 "Using the following Mako template directories: %s",
399 mako_directories)
400 mako_directories)
400
401
401 # Default includes, possible to change as a user
402 # Default includes, possible to change as a user
402 pyramid_includes = settings.setdefault('pyramid.includes', [
403 pyramid_includes = settings.setdefault('pyramid.includes', [
403 'rhodecode.lib.middleware.request_wrapper',
404 'rhodecode.lib.middleware.request_wrapper',
404 ])
405 ])
405 log.debug(
406 log.debug(
406 "Using the following pyramid.includes: %s",
407 "Using the following pyramid.includes: %s",
407 pyramid_includes)
408 pyramid_includes)
408
409
409 # TODO: johbo: Re-think this, usually the call to config.include
410 # TODO: johbo: Re-think this, usually the call to config.include
410 # should allow to pass in a prefix.
411 # should allow to pass in a prefix.
411 settings.setdefault('rhodecode.api.url', '/_admin/api')
412 settings.setdefault('rhodecode.api.url', '/_admin/api')
412
413
413 # Sanitize generic settings.
414 # Sanitize generic settings.
414 _list_setting(settings, 'default_encoding', 'UTF-8')
415 _list_setting(settings, 'default_encoding', 'UTF-8')
415 _bool_setting(settings, 'is_test', 'false')
416 _bool_setting(settings, 'is_test', 'false')
416 _bool_setting(settings, 'gzip_responses', 'false')
417 _bool_setting(settings, 'gzip_responses', 'false')
417
418
418 # Call split out functions that sanitize settings for each topic.
419 # Call split out functions that sanitize settings for each topic.
419 _sanitize_appenlight_settings(settings)
420 _sanitize_appenlight_settings(settings)
420 _sanitize_vcs_settings(settings)
421 _sanitize_vcs_settings(settings)
421
422
422 return settings
423 return settings
423
424
424
425
425 def _sanitize_appenlight_settings(settings):
426 def _sanitize_appenlight_settings(settings):
426 _bool_setting(settings, 'appenlight', 'false')
427 _bool_setting(settings, 'appenlight', 'false')
427
428
428
429
429 def _sanitize_vcs_settings(settings):
430 def _sanitize_vcs_settings(settings):
430 """
431 """
431 Applies settings defaults and does type conversion for all VCS related
432 Applies settings defaults and does type conversion for all VCS related
432 settings.
433 settings.
433 """
434 """
434 _string_setting(settings, 'vcs.svn.compatible_version', '')
435 _string_setting(settings, 'vcs.svn.compatible_version', '')
435 _string_setting(settings, 'git_rev_filter', '--all')
436 _string_setting(settings, 'git_rev_filter', '--all')
436 _string_setting(settings, 'vcs.hooks.protocol', 'pyro4')
437 _string_setting(settings, 'vcs.hooks.protocol', 'pyro4')
437 _string_setting(settings, 'vcs.server', '')
438 _string_setting(settings, 'vcs.server', '')
438 _string_setting(settings, 'vcs.server.log_level', 'debug')
439 _string_setting(settings, 'vcs.server.log_level', 'debug')
439 _string_setting(settings, 'vcs.server.protocol', 'pyro4')
440 _string_setting(settings, 'vcs.server.protocol', 'pyro4')
440 _bool_setting(settings, 'startup.import_repos', 'false')
441 _bool_setting(settings, 'startup.import_repos', 'false')
441 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
442 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
442 _bool_setting(settings, 'vcs.server.enable', 'true')
443 _bool_setting(settings, 'vcs.server.enable', 'true')
443 _bool_setting(settings, 'vcs.start_server', 'false')
444 _bool_setting(settings, 'vcs.start_server', 'false')
444 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
445 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
445
446
446
447
447 def _bool_setting(settings, name, default):
448 def _bool_setting(settings, name, default):
448 settings[name] = asbool(settings.get(name, default))
449 settings[name] = asbool(settings.get(name, default))
449
450
450
451
451 def _list_setting(settings, name, default):
452 def _list_setting(settings, name, default):
452 raw_value = settings.get(name, default)
453 raw_value = settings.get(name, default)
453
454
454 # Check if we get a setting with the old syntax (comma separated).
455 old_separator = ','
455 if ',' in raw_value:
456 if old_separator in raw_value:
456 raw_value = raw_value.replace(',', ' ')
457 # If we get a comma separated list, pass it to our own function.
457
458 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
458 settings[name] = aslist(raw_value)
459 else:
460 # Otherwise we assume it uses pyramids space/newline separation.
461 settings[name] = aslist(raw_value)
459
462
460
463
461 def _string_setting(settings, name, default):
464 def _string_setting(settings, name, default):
462 settings[name] = settings.get(name, default).lower()
465 settings[name] = settings.get(name, default).lower()
General Comments 0
You need to be logged in to leave comments. Login now