##// END OF EJS Templates
ssh: skip loading parts for SSH to make execution of ssh commands faster.
marcink -
r3910:def4f469 default
parent child Browse files
Show More
@@ -1,750 +1,755 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 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 collections
24 import collections
25 import tempfile
25 import tempfile
26 import time
26 import time
27
27
28 from paste.gzipper import make_gzip_middleware
28 from paste.gzipper import make_gzip_middleware
29 import pyramid.events
29 import pyramid.events
30 from pyramid.wsgi import wsgiapp
30 from pyramid.wsgi import wsgiapp
31 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.authorization import ACLAuthorizationPolicy
32 from pyramid.config import Configurator
32 from pyramid.config import Configurator
33 from pyramid.settings import asbool, aslist
33 from pyramid.settings import asbool, aslist
34 from pyramid.httpexceptions import (
34 from pyramid.httpexceptions import (
35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
36 from pyramid.renderers import render_to_response
36 from pyramid.renderers import render_to_response
37
37
38 from rhodecode.model import meta
38 from rhodecode.model import meta
39 from rhodecode.config import patches
39 from rhodecode.config import patches
40 from rhodecode.config import utils as config_utils
40 from rhodecode.config import utils as config_utils
41 from rhodecode.config.environment import load_pyramid_environment
41 from rhodecode.config.environment import load_pyramid_environment
42
42
43 import rhodecode.events
43 import rhodecode.events
44 from rhodecode.lib.middleware.vcs import VCSMiddleware
44 from rhodecode.lib.middleware.vcs import VCSMiddleware
45 from rhodecode.lib.request import Request
45 from rhodecode.lib.request import Request
46 from rhodecode.lib.vcs import VCSCommunicationError
46 from rhodecode.lib.vcs import VCSCommunicationError
47 from rhodecode.lib.exceptions import VCSServerUnavailable
47 from rhodecode.lib.exceptions import VCSServerUnavailable
48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 from rhodecode.lib.middleware.https_fixup import HttpsFixup
49 from rhodecode.lib.middleware.https_fixup import HttpsFixup
50 from rhodecode.lib.celerylib.loader import configure_celery
50 from rhodecode.lib.celerylib.loader import configure_celery
51 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
51 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
52 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
52 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
53 from rhodecode.lib.exc_tracking import store_exception
53 from rhodecode.lib.exc_tracking import store_exception
54 from rhodecode.subscribers import (
54 from rhodecode.subscribers import (
55 scan_repositories_if_enabled, write_js_routes_if_enabled,
55 scan_repositories_if_enabled, write_js_routes_if_enabled,
56 write_metadata_if_needed, inject_app_settings)
56 write_metadata_if_needed, inject_app_settings)
57
57
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 def is_http_error(response):
62 def is_http_error(response):
63 # error which should have traceback
63 # error which should have traceback
64 return response.status_code > 499
64 return response.status_code > 499
65
65
66
66
67 def should_load_all():
67 def should_load_all():
68 """
68 """
69 Returns if all application components should be loaded. In some cases it's
69 Returns if all application components should be loaded. In some cases it's
70 desired to skip apps loading for faster shell script execution
70 desired to skip apps loading for faster shell script execution
71 """
71 """
72 ssh_cmd = os.environ.get('RC_CMD_SSH_WRAPPER')
73 if ssh_cmd:
74 return False
75
72 return True
76 return True
73
77
74
78
75 def make_pyramid_app(global_config, **settings):
79 def make_pyramid_app(global_config, **settings):
76 """
80 """
77 Constructs the WSGI application based on Pyramid.
81 Constructs the WSGI application based on Pyramid.
78
82
79 Specials:
83 Specials:
80
84
81 * The application can also be integrated like a plugin via the call to
85 * The application can also be integrated like a plugin via the call to
82 `includeme`. This is accompanied with the other utility functions which
86 `includeme`. This is accompanied with the other utility functions which
83 are called. Changing this should be done with great care to not break
87 are called. Changing this should be done with great care to not break
84 cases when these fragments are assembled from another place.
88 cases when these fragments are assembled from another place.
85
89
86 """
90 """
87
91
88 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
92 # Allows to use format style "{ENV_NAME}" placeholders in the configuration. It
89 # will be replaced by the value of the environment variable "NAME" in this case.
93 # will be replaced by the value of the environment variable "NAME" in this case.
90 start_time = time.time()
94 start_time = time.time()
91
95
92 debug = asbool(global_config.get('debug'))
96 debug = asbool(global_config.get('debug'))
93 if debug:
97 if debug:
94 enable_debug()
98 enable_debug()
95
99
96 environ = {'ENV_{}'.format(key): value for key, value in os.environ.items()}
100 environ = {'ENV_{}'.format(key): value for key, value in os.environ.items()}
97
101
98 global_config = _substitute_values(global_config, environ)
102 global_config = _substitute_values(global_config, environ)
99 settings = _substitute_values(settings, environ)
103 settings = _substitute_values(settings, environ)
100
104
101 sanitize_settings_and_apply_defaults(global_config, settings)
105 sanitize_settings_and_apply_defaults(global_config, settings)
102
106
103 config = Configurator(settings=settings)
107 config = Configurator(settings=settings)
104
108
105 # Apply compatibility patches
109 # Apply compatibility patches
106 patches.inspect_getargspec()
110 patches.inspect_getargspec()
107
111
108 load_pyramid_environment(global_config, settings)
112 load_pyramid_environment(global_config, settings)
109
113
110 # Static file view comes first
114 # Static file view comes first
111 includeme_first(config)
115 includeme_first(config)
112
116
113 includeme(config)
117 includeme(config)
114
118
115 pyramid_app = config.make_wsgi_app()
119 pyramid_app = config.make_wsgi_app()
116 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
120 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
117 pyramid_app.config = config
121 pyramid_app.config = config
118
122
119 config.configure_celery(global_config['__file__'])
123 config.configure_celery(global_config['__file__'])
120 # creating the app uses a connection - return it after we are done
124 # creating the app uses a connection - return it after we are done
121 meta.Session.remove()
125 meta.Session.remove()
122 total_time = time.time() - start_time
126 total_time = time.time() - start_time
123 log.info('Pyramid app `%s` created and configured in %.2fs',
127 log.info('Pyramid app `%s` created and configured in %.2fs',
124 pyramid_app.func_name, total_time)
128 pyramid_app.func_name, total_time)
125
129
126 return pyramid_app
130 return pyramid_app
127
131
128
132
129 def not_found_view(request):
133 def not_found_view(request):
130 """
134 """
131 This creates the view which should be registered as not-found-view to
135 This creates the view which should be registered as not-found-view to
132 pyramid.
136 pyramid.
133 """
137 """
134
138
135 if not getattr(request, 'vcs_call', None):
139 if not getattr(request, 'vcs_call', None):
136 # handle like regular case with our error_handler
140 # handle like regular case with our error_handler
137 return error_handler(HTTPNotFound(), request)
141 return error_handler(HTTPNotFound(), request)
138
142
139 # handle not found view as a vcs call
143 # handle not found view as a vcs call
140 settings = request.registry.settings
144 settings = request.registry.settings
141 ae_client = getattr(request, 'ae_client', None)
145 ae_client = getattr(request, 'ae_client', None)
142 vcs_app = VCSMiddleware(
146 vcs_app = VCSMiddleware(
143 HTTPNotFound(), request.registry, settings,
147 HTTPNotFound(), request.registry, settings,
144 appenlight_client=ae_client)
148 appenlight_client=ae_client)
145
149
146 return wsgiapp(vcs_app)(None, request)
150 return wsgiapp(vcs_app)(None, request)
147
151
148
152
149 def error_handler(exception, request):
153 def error_handler(exception, request):
150 import rhodecode
154 import rhodecode
151 from rhodecode.lib import helpers
155 from rhodecode.lib import helpers
152
156
153 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
157 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
154
158
155 base_response = HTTPInternalServerError()
159 base_response = HTTPInternalServerError()
156 # prefer original exception for the response since it may have headers set
160 # prefer original exception for the response since it may have headers set
157 if isinstance(exception, HTTPException):
161 if isinstance(exception, HTTPException):
158 base_response = exception
162 base_response = exception
159 elif isinstance(exception, VCSCommunicationError):
163 elif isinstance(exception, VCSCommunicationError):
160 base_response = VCSServerUnavailable()
164 base_response = VCSServerUnavailable()
161
165
162 if is_http_error(base_response):
166 if is_http_error(base_response):
163 log.exception(
167 log.exception(
164 'error occurred handling this request for path: %s', request.path)
168 'error occurred handling this request for path: %s', request.path)
165
169
166 error_explanation = base_response.explanation or str(base_response)
170 error_explanation = base_response.explanation or str(base_response)
167 if base_response.status_code == 404:
171 if base_response.status_code == 404:
168 error_explanation += " Optionally you don't have permission to access this page."
172 error_explanation += " Optionally you don't have permission to access this page."
169 c = AttributeDict()
173 c = AttributeDict()
170 c.error_message = base_response.status
174 c.error_message = base_response.status
171 c.error_explanation = error_explanation
175 c.error_explanation = error_explanation
172 c.visual = AttributeDict()
176 c.visual = AttributeDict()
173
177
174 c.visual.rhodecode_support_url = (
178 c.visual.rhodecode_support_url = (
175 request.registry.settings.get('rhodecode_support_url') or
179 request.registry.settings.get('rhodecode_support_url') or
176 request.route_url('rhodecode_support')
180 request.route_url('rhodecode_support')
177 )
181 )
178 c.redirect_time = 0
182 c.redirect_time = 0
179 c.rhodecode_name = rhodecode_title
183 c.rhodecode_name = rhodecode_title
180 if not c.rhodecode_name:
184 if not c.rhodecode_name:
181 c.rhodecode_name = 'Rhodecode'
185 c.rhodecode_name = 'Rhodecode'
182
186
183 c.causes = []
187 c.causes = []
184 if is_http_error(base_response):
188 if is_http_error(base_response):
185 c.causes.append('Server is overloaded.')
189 c.causes.append('Server is overloaded.')
186 c.causes.append('Server database connection is lost.')
190 c.causes.append('Server database connection is lost.')
187 c.causes.append('Server expected unhandled error.')
191 c.causes.append('Server expected unhandled error.')
188
192
189 if hasattr(base_response, 'causes'):
193 if hasattr(base_response, 'causes'):
190 c.causes = base_response.causes
194 c.causes = base_response.causes
191
195
192 c.messages = helpers.flash.pop_messages(request=request)
196 c.messages = helpers.flash.pop_messages(request=request)
193
197
194 exc_info = sys.exc_info()
198 exc_info = sys.exc_info()
195 c.exception_id = id(exc_info)
199 c.exception_id = id(exc_info)
196 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
200 c.show_exception_id = isinstance(base_response, VCSServerUnavailable) \
197 or base_response.status_code > 499
201 or base_response.status_code > 499
198 c.exception_id_url = request.route_url(
202 c.exception_id_url = request.route_url(
199 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
203 'admin_settings_exception_tracker_show', exception_id=c.exception_id)
200
204
201 if c.show_exception_id:
205 if c.show_exception_id:
202 store_exception(c.exception_id, exc_info)
206 store_exception(c.exception_id, exc_info)
203
207
204 response = render_to_response(
208 response = render_to_response(
205 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
209 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
206 response=base_response)
210 response=base_response)
207
211
208 return response
212 return response
209
213
210
214
211 def includeme_first(config):
215 def includeme_first(config):
212 # redirect automatic browser favicon.ico requests to correct place
216 # redirect automatic browser favicon.ico requests to correct place
213 def favicon_redirect(context, request):
217 def favicon_redirect(context, request):
214 return HTTPFound(
218 return HTTPFound(
215 request.static_path('rhodecode:public/images/favicon.ico'))
219 request.static_path('rhodecode:public/images/favicon.ico'))
216
220
217 config.add_view(favicon_redirect, route_name='favicon')
221 config.add_view(favicon_redirect, route_name='favicon')
218 config.add_route('favicon', '/favicon.ico')
222 config.add_route('favicon', '/favicon.ico')
219
223
220 def robots_redirect(context, request):
224 def robots_redirect(context, request):
221 return HTTPFound(
225 return HTTPFound(
222 request.static_path('rhodecode:public/robots.txt'))
226 request.static_path('rhodecode:public/robots.txt'))
223
227
224 config.add_view(robots_redirect, route_name='robots')
228 config.add_view(robots_redirect, route_name='robots')
225 config.add_route('robots', '/robots.txt')
229 config.add_route('robots', '/robots.txt')
226
230
227 config.add_static_view(
231 config.add_static_view(
228 '_static/deform', 'deform:static')
232 '_static/deform', 'deform:static')
229 config.add_static_view(
233 config.add_static_view(
230 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
234 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
231
235
232
236
233 def includeme(config):
237 def includeme(config):
234 log.debug('Initializing main includeme from %s', os.path.basename(__file__))
238 log.debug('Initializing main includeme from %s', os.path.basename(__file__))
235 settings = config.registry.settings
239 settings = config.registry.settings
236 config.set_request_factory(Request)
240 config.set_request_factory(Request)
237
241
238 # plugin information
242 # plugin information
239 config.registry.rhodecode_plugins = collections.OrderedDict()
243 config.registry.rhodecode_plugins = collections.OrderedDict()
240
244
241 config.add_directive(
245 config.add_directive(
242 'register_rhodecode_plugin', register_rhodecode_plugin)
246 'register_rhodecode_plugin', register_rhodecode_plugin)
243
247
244 config.add_directive('configure_celery', configure_celery)
248 config.add_directive('configure_celery', configure_celery)
245
249
246 if asbool(settings.get('appenlight', 'false')):
250 if asbool(settings.get('appenlight', 'false')):
247 config.include('appenlight_client.ext.pyramid_tween')
251 config.include('appenlight_client.ext.pyramid_tween')
248
252
249 load_all = should_load_all()
253 load_all = should_load_all()
250
254
251 # Includes which are required. The application would fail without them.
255 # Includes which are required. The application would fail without them.
252 config.include('pyramid_mako')
256 config.include('pyramid_mako')
253 config.include('rhodecode.lib.rc_beaker')
257 config.include('rhodecode.lib.rc_beaker')
254 config.include('rhodecode.lib.rc_cache')
258 config.include('rhodecode.lib.rc_cache')
255
259
256 config.include('rhodecode.apps._base.navigation')
260 config.include('rhodecode.apps._base.navigation')
257 config.include('rhodecode.apps._base.subscribers')
261 config.include('rhodecode.apps._base.subscribers')
258 config.include('rhodecode.tweens')
262 config.include('rhodecode.tweens')
263 config.include('rhodecode.authentication')
259
264
265 if load_all:
260 config.include('rhodecode.integrations')
266 config.include('rhodecode.integrations')
261 config.include('rhodecode.authentication')
262
267
263 if load_all:
268 if load_all:
264 from rhodecode.authentication import discover_legacy_plugins
269 from rhodecode.authentication import discover_legacy_plugins
265 # load CE authentication plugins
270 # load CE authentication plugins
266 config.include('rhodecode.authentication.plugins.auth_crowd')
271 config.include('rhodecode.authentication.plugins.auth_crowd')
267 config.include('rhodecode.authentication.plugins.auth_headers')
272 config.include('rhodecode.authentication.plugins.auth_headers')
268 config.include('rhodecode.authentication.plugins.auth_jasig_cas')
273 config.include('rhodecode.authentication.plugins.auth_jasig_cas')
269 config.include('rhodecode.authentication.plugins.auth_ldap')
274 config.include('rhodecode.authentication.plugins.auth_ldap')
270 config.include('rhodecode.authentication.plugins.auth_pam')
275 config.include('rhodecode.authentication.plugins.auth_pam')
271 config.include('rhodecode.authentication.plugins.auth_rhodecode')
276 config.include('rhodecode.authentication.plugins.auth_rhodecode')
272 config.include('rhodecode.authentication.plugins.auth_token')
277 config.include('rhodecode.authentication.plugins.auth_token')
273
278
274 # Auto discover authentication plugins and include their configuration.
279 # Auto discover authentication plugins and include their configuration.
275 discover_legacy_plugins(config)
280 discover_legacy_plugins(config)
276
281
277 # apps
282 # apps
283 if load_all:
278 config.include('rhodecode.apps._base')
284 config.include('rhodecode.apps._base')
279
280 if load_all:
281 config.include('rhodecode.apps.ops')
285 config.include('rhodecode.apps.ops')
282 config.include('rhodecode.apps.admin')
286 config.include('rhodecode.apps.admin')
283 config.include('rhodecode.apps.channelstream')
287 config.include('rhodecode.apps.channelstream')
284 config.include('rhodecode.apps.file_store')
288 config.include('rhodecode.apps.file_store')
285 config.include('rhodecode.apps.login')
289 config.include('rhodecode.apps.login')
286 config.include('rhodecode.apps.home')
290 config.include('rhodecode.apps.home')
287 config.include('rhodecode.apps.journal')
291 config.include('rhodecode.apps.journal')
288 config.include('rhodecode.apps.repository')
292 config.include('rhodecode.apps.repository')
289 config.include('rhodecode.apps.repo_group')
293 config.include('rhodecode.apps.repo_group')
290 config.include('rhodecode.apps.user_group')
294 config.include('rhodecode.apps.user_group')
291 config.include('rhodecode.apps.search')
295 config.include('rhodecode.apps.search')
292 config.include('rhodecode.apps.user_profile')
296 config.include('rhodecode.apps.user_profile')
293 config.include('rhodecode.apps.user_group_profile')
297 config.include('rhodecode.apps.user_group_profile')
294 config.include('rhodecode.apps.my_account')
298 config.include('rhodecode.apps.my_account')
295 config.include('rhodecode.apps.svn_support')
299 config.include('rhodecode.apps.svn_support')
296 config.include('rhodecode.apps.ssh_support')
300 config.include('rhodecode.apps.ssh_support')
297 config.include('rhodecode.apps.gist')
301 config.include('rhodecode.apps.gist')
298 config.include('rhodecode.apps.debug_style')
302 config.include('rhodecode.apps.debug_style')
299 config.include('rhodecode.api')
303 config.include('rhodecode.api')
300
304
301 config.add_route('rhodecode_support', 'https://rhodecode.com/help/', static=True)
305 config.add_route('rhodecode_support', 'https://rhodecode.com/help/', static=True)
302 config.add_translation_dirs('rhodecode:i18n/')
306 config.add_translation_dirs('rhodecode:i18n/')
303 settings['default_locale_name'] = settings.get('lang', 'en')
307 settings['default_locale_name'] = settings.get('lang', 'en')
304
308
305 # Add subscribers.
309 # Add subscribers.
310 if load_all:
306 config.add_subscriber(inject_app_settings,
311 config.add_subscriber(inject_app_settings,
307 pyramid.events.ApplicationCreated)
312 pyramid.events.ApplicationCreated)
308 config.add_subscriber(scan_repositories_if_enabled,
313 config.add_subscriber(scan_repositories_if_enabled,
309 pyramid.events.ApplicationCreated)
314 pyramid.events.ApplicationCreated)
310 config.add_subscriber(write_metadata_if_needed,
315 config.add_subscriber(write_metadata_if_needed,
311 pyramid.events.ApplicationCreated)
316 pyramid.events.ApplicationCreated)
312 config.add_subscriber(write_js_routes_if_enabled,
317 config.add_subscriber(write_js_routes_if_enabled,
313 pyramid.events.ApplicationCreated)
318 pyramid.events.ApplicationCreated)
314
319
315 # request custom methods
320 # request custom methods
316 config.add_request_method(
321 config.add_request_method(
317 'rhodecode.lib.partial_renderer.get_partial_renderer',
322 'rhodecode.lib.partial_renderer.get_partial_renderer',
318 'get_partial_renderer')
323 'get_partial_renderer')
319
324
320 config.add_request_method(
325 config.add_request_method(
321 'rhodecode.lib.request_counter.get_request_counter',
326 'rhodecode.lib.request_counter.get_request_counter',
322 'request_count')
327 'request_count')
323
328
324 # Set the authorization policy.
329 # Set the authorization policy.
325 authz_policy = ACLAuthorizationPolicy()
330 authz_policy = ACLAuthorizationPolicy()
326 config.set_authorization_policy(authz_policy)
331 config.set_authorization_policy(authz_policy)
327
332
328 # Set the default renderer for HTML templates to mako.
333 # Set the default renderer for HTML templates to mako.
329 config.add_mako_renderer('.html')
334 config.add_mako_renderer('.html')
330
335
331 config.add_renderer(
336 config.add_renderer(
332 name='json_ext',
337 name='json_ext',
333 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
338 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
334
339
335 # include RhodeCode plugins
340 # include RhodeCode plugins
336 includes = aslist(settings.get('rhodecode.includes', []))
341 includes = aslist(settings.get('rhodecode.includes', []))
337 for inc in includes:
342 for inc in includes:
338 config.include(inc)
343 config.include(inc)
339
344
340 # custom not found view, if our pyramid app doesn't know how to handle
345 # custom not found view, if our pyramid app doesn't know how to handle
341 # the request pass it to potential VCS handling ap
346 # the request pass it to potential VCS handling ap
342 config.add_notfound_view(not_found_view)
347 config.add_notfound_view(not_found_view)
343 if not settings.get('debugtoolbar.enabled', False):
348 if not settings.get('debugtoolbar.enabled', False):
344 # disabled debugtoolbar handle all exceptions via the error_handlers
349 # disabled debugtoolbar handle all exceptions via the error_handlers
345 config.add_view(error_handler, context=Exception)
350 config.add_view(error_handler, context=Exception)
346
351
347 # all errors including 403/404/50X
352 # all errors including 403/404/50X
348 config.add_view(error_handler, context=HTTPError)
353 config.add_view(error_handler, context=HTTPError)
349
354
350
355
351 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
356 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
352 """
357 """
353 Apply outer WSGI middlewares around the application.
358 Apply outer WSGI middlewares around the application.
354 """
359 """
355 registry = config.registry
360 registry = config.registry
356 settings = registry.settings
361 settings = registry.settings
357
362
358 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
363 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
359 pyramid_app = HttpsFixup(pyramid_app, settings)
364 pyramid_app = HttpsFixup(pyramid_app, settings)
360
365
361 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
366 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
362 pyramid_app, settings)
367 pyramid_app, settings)
363 registry.ae_client = _ae_client
368 registry.ae_client = _ae_client
364
369
365 if settings['gzip_responses']:
370 if settings['gzip_responses']:
366 pyramid_app = make_gzip_middleware(
371 pyramid_app = make_gzip_middleware(
367 pyramid_app, settings, compress_level=1)
372 pyramid_app, settings, compress_level=1)
368
373
369 # this should be the outer most middleware in the wsgi stack since
374 # this should be the outer most middleware in the wsgi stack since
370 # middleware like Routes make database calls
375 # middleware like Routes make database calls
371 def pyramid_app_with_cleanup(environ, start_response):
376 def pyramid_app_with_cleanup(environ, start_response):
372 try:
377 try:
373 return pyramid_app(environ, start_response)
378 return pyramid_app(environ, start_response)
374 finally:
379 finally:
375 # Dispose current database session and rollback uncommitted
380 # Dispose current database session and rollback uncommitted
376 # transactions.
381 # transactions.
377 meta.Session.remove()
382 meta.Session.remove()
378
383
379 # In a single threaded mode server, on non sqlite db we should have
384 # In a single threaded mode server, on non sqlite db we should have
380 # '0 Current Checked out connections' at the end of a request,
385 # '0 Current Checked out connections' at the end of a request,
381 # if not, then something, somewhere is leaving a connection open
386 # if not, then something, somewhere is leaving a connection open
382 pool = meta.Base.metadata.bind.engine.pool
387 pool = meta.Base.metadata.bind.engine.pool
383 log.debug('sa pool status: %s', pool.status())
388 log.debug('sa pool status: %s', pool.status())
384 log.debug('Request processing finalized')
389 log.debug('Request processing finalized')
385
390
386 return pyramid_app_with_cleanup
391 return pyramid_app_with_cleanup
387
392
388
393
389 def sanitize_settings_and_apply_defaults(global_config, settings):
394 def sanitize_settings_and_apply_defaults(global_config, settings):
390 """
395 """
391 Applies settings defaults and does all type conversion.
396 Applies settings defaults and does all type conversion.
392
397
393 We would move all settings parsing and preparation into this place, so that
398 We would move all settings parsing and preparation into this place, so that
394 we have only one place left which deals with this part. The remaining parts
399 we have only one place left which deals with this part. The remaining parts
395 of the application would start to rely fully on well prepared settings.
400 of the application would start to rely fully on well prepared settings.
396
401
397 This piece would later be split up per topic to avoid a big fat monster
402 This piece would later be split up per topic to avoid a big fat monster
398 function.
403 function.
399 """
404 """
400
405
401 settings.setdefault('rhodecode.edition', 'Community Edition')
406 settings.setdefault('rhodecode.edition', 'Community Edition')
402
407
403 if 'mako.default_filters' not in settings:
408 if 'mako.default_filters' not in settings:
404 # set custom default filters if we don't have it defined
409 # set custom default filters if we don't have it defined
405 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
410 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
406 settings['mako.default_filters'] = 'h_filter'
411 settings['mako.default_filters'] = 'h_filter'
407
412
408 if 'mako.directories' not in settings:
413 if 'mako.directories' not in settings:
409 mako_directories = settings.setdefault('mako.directories', [
414 mako_directories = settings.setdefault('mako.directories', [
410 # Base templates of the original application
415 # Base templates of the original application
411 'rhodecode:templates',
416 'rhodecode:templates',
412 ])
417 ])
413 log.debug(
418 log.debug(
414 "Using the following Mako template directories: %s",
419 "Using the following Mako template directories: %s",
415 mako_directories)
420 mako_directories)
416
421
417 # NOTE(marcink): fix redis requirement for schema of connection since 3.X
422 # NOTE(marcink): fix redis requirement for schema of connection since 3.X
418 if 'beaker.session.type' in settings and settings['beaker.session.type'] == 'ext:redis':
423 if 'beaker.session.type' in settings and settings['beaker.session.type'] == 'ext:redis':
419 raw_url = settings['beaker.session.url']
424 raw_url = settings['beaker.session.url']
420 if not raw_url.startswith(('redis://', 'rediss://', 'unix://')):
425 if not raw_url.startswith(('redis://', 'rediss://', 'unix://')):
421 settings['beaker.session.url'] = 'redis://' + raw_url
426 settings['beaker.session.url'] = 'redis://' + raw_url
422
427
423 # Default includes, possible to change as a user
428 # Default includes, possible to change as a user
424 pyramid_includes = settings.setdefault('pyramid.includes', [
429 pyramid_includes = settings.setdefault('pyramid.includes', [
425 'rhodecode.lib.middleware.request_wrapper',
430 'rhodecode.lib.middleware.request_wrapper',
426 ])
431 ])
427 log.debug(
432 log.debug(
428 "Using the following pyramid.includes: %s",
433 "Using the following pyramid.includes: %s",
429 pyramid_includes)
434 pyramid_includes)
430
435
431 # TODO: johbo: Re-think this, usually the call to config.include
436 # TODO: johbo: Re-think this, usually the call to config.include
432 # should allow to pass in a prefix.
437 # should allow to pass in a prefix.
433 settings.setdefault('rhodecode.api.url', '/_admin/api')
438 settings.setdefault('rhodecode.api.url', '/_admin/api')
434 settings.setdefault('__file__', global_config.get('__file__'))
439 settings.setdefault('__file__', global_config.get('__file__'))
435
440
436 # Sanitize generic settings.
441 # Sanitize generic settings.
437 _list_setting(settings, 'default_encoding', 'UTF-8')
442 _list_setting(settings, 'default_encoding', 'UTF-8')
438 _bool_setting(settings, 'is_test', 'false')
443 _bool_setting(settings, 'is_test', 'false')
439 _bool_setting(settings, 'gzip_responses', 'false')
444 _bool_setting(settings, 'gzip_responses', 'false')
440
445
441 # Call split out functions that sanitize settings for each topic.
446 # Call split out functions that sanitize settings for each topic.
442 _sanitize_appenlight_settings(settings)
447 _sanitize_appenlight_settings(settings)
443 _sanitize_vcs_settings(settings)
448 _sanitize_vcs_settings(settings)
444 _sanitize_cache_settings(settings)
449 _sanitize_cache_settings(settings)
445
450
446 # configure instance id
451 # configure instance id
447 config_utils.set_instance_id(settings)
452 config_utils.set_instance_id(settings)
448
453
449 return settings
454 return settings
450
455
451
456
452 def enable_debug():
457 def enable_debug():
453 """
458 """
454 Helper to enable debug on running instance
459 Helper to enable debug on running instance
455 :return:
460 :return:
456 """
461 """
457 import tempfile
462 import tempfile
458 import textwrap
463 import textwrap
459 import logging.config
464 import logging.config
460
465
461 ini_template = textwrap.dedent("""
466 ini_template = textwrap.dedent("""
462 #####################################
467 #####################################
463 ### DEBUG LOGGING CONFIGURATION ####
468 ### DEBUG LOGGING CONFIGURATION ####
464 #####################################
469 #####################################
465 [loggers]
470 [loggers]
466 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
471 keys = root, sqlalchemy, beaker, celery, rhodecode, ssh_wrapper
467
472
468 [handlers]
473 [handlers]
469 keys = console, console_sql
474 keys = console, console_sql
470
475
471 [formatters]
476 [formatters]
472 keys = generic, color_formatter, color_formatter_sql
477 keys = generic, color_formatter, color_formatter_sql
473
478
474 #############
479 #############
475 ## LOGGERS ##
480 ## LOGGERS ##
476 #############
481 #############
477 [logger_root]
482 [logger_root]
478 level = NOTSET
483 level = NOTSET
479 handlers = console
484 handlers = console
480
485
481 [logger_sqlalchemy]
486 [logger_sqlalchemy]
482 level = INFO
487 level = INFO
483 handlers = console_sql
488 handlers = console_sql
484 qualname = sqlalchemy.engine
489 qualname = sqlalchemy.engine
485 propagate = 0
490 propagate = 0
486
491
487 [logger_beaker]
492 [logger_beaker]
488 level = DEBUG
493 level = DEBUG
489 handlers =
494 handlers =
490 qualname = beaker.container
495 qualname = beaker.container
491 propagate = 1
496 propagate = 1
492
497
493 [logger_rhodecode]
498 [logger_rhodecode]
494 level = DEBUG
499 level = DEBUG
495 handlers =
500 handlers =
496 qualname = rhodecode
501 qualname = rhodecode
497 propagate = 1
502 propagate = 1
498
503
499 [logger_ssh_wrapper]
504 [logger_ssh_wrapper]
500 level = DEBUG
505 level = DEBUG
501 handlers =
506 handlers =
502 qualname = ssh_wrapper
507 qualname = ssh_wrapper
503 propagate = 1
508 propagate = 1
504
509
505 [logger_celery]
510 [logger_celery]
506 level = DEBUG
511 level = DEBUG
507 handlers =
512 handlers =
508 qualname = celery
513 qualname = celery
509
514
510
515
511 ##############
516 ##############
512 ## HANDLERS ##
517 ## HANDLERS ##
513 ##############
518 ##############
514
519
515 [handler_console]
520 [handler_console]
516 class = StreamHandler
521 class = StreamHandler
517 args = (sys.stderr, )
522 args = (sys.stderr, )
518 level = DEBUG
523 level = DEBUG
519 formatter = color_formatter
524 formatter = color_formatter
520
525
521 [handler_console_sql]
526 [handler_console_sql]
522 # "level = DEBUG" logs SQL queries and results.
527 # "level = DEBUG" logs SQL queries and results.
523 # "level = INFO" logs SQL queries.
528 # "level = INFO" logs SQL queries.
524 # "level = WARN" logs neither. (Recommended for production systems.)
529 # "level = WARN" logs neither. (Recommended for production systems.)
525 class = StreamHandler
530 class = StreamHandler
526 args = (sys.stderr, )
531 args = (sys.stderr, )
527 level = WARN
532 level = WARN
528 formatter = color_formatter_sql
533 formatter = color_formatter_sql
529
534
530 ################
535 ################
531 ## FORMATTERS ##
536 ## FORMATTERS ##
532 ################
537 ################
533
538
534 [formatter_generic]
539 [formatter_generic]
535 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
540 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
536 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
541 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
537 datefmt = %Y-%m-%d %H:%M:%S
542 datefmt = %Y-%m-%d %H:%M:%S
538
543
539 [formatter_color_formatter]
544 [formatter_color_formatter]
540 class = rhodecode.lib.logging_formatter.ColorRequestTrackingFormatter
545 class = rhodecode.lib.logging_formatter.ColorRequestTrackingFormatter
541 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
546 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s | %(req_id)s
542 datefmt = %Y-%m-%d %H:%M:%S
547 datefmt = %Y-%m-%d %H:%M:%S
543
548
544 [formatter_color_formatter_sql]
549 [formatter_color_formatter_sql]
545 class = rhodecode.lib.logging_formatter.ColorFormatterSql
550 class = rhodecode.lib.logging_formatter.ColorFormatterSql
546 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
551 format = %(asctime)s.%(msecs)03d [%(process)d] %(levelname)-5.5s [%(name)s] %(message)s
547 datefmt = %Y-%m-%d %H:%M:%S
552 datefmt = %Y-%m-%d %H:%M:%S
548 """)
553 """)
549
554
550 with tempfile.NamedTemporaryFile(prefix='rc_debug_logging_', suffix='.ini',
555 with tempfile.NamedTemporaryFile(prefix='rc_debug_logging_', suffix='.ini',
551 delete=False) as f:
556 delete=False) as f:
552 log.info('Saved Temporary DEBUG config at %s', f.name)
557 log.info('Saved Temporary DEBUG config at %s', f.name)
553 f.write(ini_template)
558 f.write(ini_template)
554
559
555 logging.config.fileConfig(f.name)
560 logging.config.fileConfig(f.name)
556 log.debug('DEBUG MODE ON')
561 log.debug('DEBUG MODE ON')
557 os.remove(f.name)
562 os.remove(f.name)
558
563
559
564
560 def _sanitize_appenlight_settings(settings):
565 def _sanitize_appenlight_settings(settings):
561 _bool_setting(settings, 'appenlight', 'false')
566 _bool_setting(settings, 'appenlight', 'false')
562
567
563
568
564 def _sanitize_vcs_settings(settings):
569 def _sanitize_vcs_settings(settings):
565 """
570 """
566 Applies settings defaults and does type conversion for all VCS related
571 Applies settings defaults and does type conversion for all VCS related
567 settings.
572 settings.
568 """
573 """
569 _string_setting(settings, 'vcs.svn.compatible_version', '')
574 _string_setting(settings, 'vcs.svn.compatible_version', '')
570 _string_setting(settings, 'git_rev_filter', '--all')
575 _string_setting(settings, 'git_rev_filter', '--all')
571 _string_setting(settings, 'vcs.hooks.protocol', 'http')
576 _string_setting(settings, 'vcs.hooks.protocol', 'http')
572 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
577 _string_setting(settings, 'vcs.hooks.host', '127.0.0.1')
573 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
578 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
574 _string_setting(settings, 'vcs.server', '')
579 _string_setting(settings, 'vcs.server', '')
575 _string_setting(settings, 'vcs.server.log_level', 'debug')
580 _string_setting(settings, 'vcs.server.log_level', 'debug')
576 _string_setting(settings, 'vcs.server.protocol', 'http')
581 _string_setting(settings, 'vcs.server.protocol', 'http')
577 _bool_setting(settings, 'startup.import_repos', 'false')
582 _bool_setting(settings, 'startup.import_repos', 'false')
578 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
583 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
579 _bool_setting(settings, 'vcs.server.enable', 'true')
584 _bool_setting(settings, 'vcs.server.enable', 'true')
580 _bool_setting(settings, 'vcs.start_server', 'false')
585 _bool_setting(settings, 'vcs.start_server', 'false')
581 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
586 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
582 _int_setting(settings, 'vcs.connection_timeout', 3600)
587 _int_setting(settings, 'vcs.connection_timeout', 3600)
583
588
584 # Support legacy values of vcs.scm_app_implementation. Legacy
589 # Support legacy values of vcs.scm_app_implementation. Legacy
585 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
590 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http', or
586 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
591 # disabled since 4.13 'vcsserver.scm_app' which is now mapped to 'http'.
587 scm_app_impl = settings['vcs.scm_app_implementation']
592 scm_app_impl = settings['vcs.scm_app_implementation']
588 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
593 if scm_app_impl in ['rhodecode.lib.middleware.utils.scm_app_http', 'vcsserver.scm_app']:
589 settings['vcs.scm_app_implementation'] = 'http'
594 settings['vcs.scm_app_implementation'] = 'http'
590
595
591
596
592 def _sanitize_cache_settings(settings):
597 def _sanitize_cache_settings(settings):
593 temp_store = tempfile.gettempdir()
598 temp_store = tempfile.gettempdir()
594 default_cache_dir = os.path.join(temp_store, 'rc_cache')
599 default_cache_dir = os.path.join(temp_store, 'rc_cache')
595
600
596 # save default, cache dir, and use it for all backends later.
601 # save default, cache dir, and use it for all backends later.
597 default_cache_dir = _string_setting(
602 default_cache_dir = _string_setting(
598 settings,
603 settings,
599 'cache_dir',
604 'cache_dir',
600 default_cache_dir, lower=False, default_when_empty=True)
605 default_cache_dir, lower=False, default_when_empty=True)
601
606
602 # ensure we have our dir created
607 # ensure we have our dir created
603 if not os.path.isdir(default_cache_dir):
608 if not os.path.isdir(default_cache_dir):
604 os.makedirs(default_cache_dir, mode=0o755)
609 os.makedirs(default_cache_dir, mode=0o755)
605
610
606 # exception store cache
611 # exception store cache
607 _string_setting(
612 _string_setting(
608 settings,
613 settings,
609 'exception_tracker.store_path',
614 'exception_tracker.store_path',
610 temp_store, lower=False, default_when_empty=True)
615 temp_store, lower=False, default_when_empty=True)
611
616
612 # cache_perms
617 # cache_perms
613 _string_setting(
618 _string_setting(
614 settings,
619 settings,
615 'rc_cache.cache_perms.backend',
620 'rc_cache.cache_perms.backend',
616 'dogpile.cache.rc.file_namespace', lower=False)
621 'dogpile.cache.rc.file_namespace', lower=False)
617 _int_setting(
622 _int_setting(
618 settings,
623 settings,
619 'rc_cache.cache_perms.expiration_time',
624 'rc_cache.cache_perms.expiration_time',
620 60)
625 60)
621 _string_setting(
626 _string_setting(
622 settings,
627 settings,
623 'rc_cache.cache_perms.arguments.filename',
628 'rc_cache.cache_perms.arguments.filename',
624 os.path.join(default_cache_dir, 'rc_cache_1'), lower=False)
629 os.path.join(default_cache_dir, 'rc_cache_1'), lower=False)
625
630
626 # cache_repo
631 # cache_repo
627 _string_setting(
632 _string_setting(
628 settings,
633 settings,
629 'rc_cache.cache_repo.backend',
634 'rc_cache.cache_repo.backend',
630 'dogpile.cache.rc.file_namespace', lower=False)
635 'dogpile.cache.rc.file_namespace', lower=False)
631 _int_setting(
636 _int_setting(
632 settings,
637 settings,
633 'rc_cache.cache_repo.expiration_time',
638 'rc_cache.cache_repo.expiration_time',
634 60)
639 60)
635 _string_setting(
640 _string_setting(
636 settings,
641 settings,
637 'rc_cache.cache_repo.arguments.filename',
642 'rc_cache.cache_repo.arguments.filename',
638 os.path.join(default_cache_dir, 'rc_cache_2'), lower=False)
643 os.path.join(default_cache_dir, 'rc_cache_2'), lower=False)
639
644
640 # cache_license
645 # cache_license
641 _string_setting(
646 _string_setting(
642 settings,
647 settings,
643 'rc_cache.cache_license.backend',
648 'rc_cache.cache_license.backend',
644 'dogpile.cache.rc.file_namespace', lower=False)
649 'dogpile.cache.rc.file_namespace', lower=False)
645 _int_setting(
650 _int_setting(
646 settings,
651 settings,
647 'rc_cache.cache_license.expiration_time',
652 'rc_cache.cache_license.expiration_time',
648 5*60)
653 5*60)
649 _string_setting(
654 _string_setting(
650 settings,
655 settings,
651 'rc_cache.cache_license.arguments.filename',
656 'rc_cache.cache_license.arguments.filename',
652 os.path.join(default_cache_dir, 'rc_cache_3'), lower=False)
657 os.path.join(default_cache_dir, 'rc_cache_3'), lower=False)
653
658
654 # cache_repo_longterm memory, 96H
659 # cache_repo_longterm memory, 96H
655 _string_setting(
660 _string_setting(
656 settings,
661 settings,
657 'rc_cache.cache_repo_longterm.backend',
662 'rc_cache.cache_repo_longterm.backend',
658 'dogpile.cache.rc.memory_lru', lower=False)
663 'dogpile.cache.rc.memory_lru', lower=False)
659 _int_setting(
664 _int_setting(
660 settings,
665 settings,
661 'rc_cache.cache_repo_longterm.expiration_time',
666 'rc_cache.cache_repo_longterm.expiration_time',
662 345600)
667 345600)
663 _int_setting(
668 _int_setting(
664 settings,
669 settings,
665 'rc_cache.cache_repo_longterm.max_size',
670 'rc_cache.cache_repo_longterm.max_size',
666 10000)
671 10000)
667
672
668 # sql_cache_short
673 # sql_cache_short
669 _string_setting(
674 _string_setting(
670 settings,
675 settings,
671 'rc_cache.sql_cache_short.backend',
676 'rc_cache.sql_cache_short.backend',
672 'dogpile.cache.rc.memory_lru', lower=False)
677 'dogpile.cache.rc.memory_lru', lower=False)
673 _int_setting(
678 _int_setting(
674 settings,
679 settings,
675 'rc_cache.sql_cache_short.expiration_time',
680 'rc_cache.sql_cache_short.expiration_time',
676 30)
681 30)
677 _int_setting(
682 _int_setting(
678 settings,
683 settings,
679 'rc_cache.sql_cache_short.max_size',
684 'rc_cache.sql_cache_short.max_size',
680 10000)
685 10000)
681
686
682
687
683 def _int_setting(settings, name, default):
688 def _int_setting(settings, name, default):
684 settings[name] = int(settings.get(name, default))
689 settings[name] = int(settings.get(name, default))
685 return settings[name]
690 return settings[name]
686
691
687
692
688 def _bool_setting(settings, name, default):
693 def _bool_setting(settings, name, default):
689 input_val = settings.get(name, default)
694 input_val = settings.get(name, default)
690 if isinstance(input_val, unicode):
695 if isinstance(input_val, unicode):
691 input_val = input_val.encode('utf8')
696 input_val = input_val.encode('utf8')
692 settings[name] = asbool(input_val)
697 settings[name] = asbool(input_val)
693 return settings[name]
698 return settings[name]
694
699
695
700
696 def _list_setting(settings, name, default):
701 def _list_setting(settings, name, default):
697 raw_value = settings.get(name, default)
702 raw_value = settings.get(name, default)
698
703
699 old_separator = ','
704 old_separator = ','
700 if old_separator in raw_value:
705 if old_separator in raw_value:
701 # If we get a comma separated list, pass it to our own function.
706 # If we get a comma separated list, pass it to our own function.
702 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
707 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
703 else:
708 else:
704 # Otherwise we assume it uses pyramids space/newline separation.
709 # Otherwise we assume it uses pyramids space/newline separation.
705 settings[name] = aslist(raw_value)
710 settings[name] = aslist(raw_value)
706 return settings[name]
711 return settings[name]
707
712
708
713
709 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
714 def _string_setting(settings, name, default, lower=True, default_when_empty=False):
710 value = settings.get(name, default)
715 value = settings.get(name, default)
711
716
712 if default_when_empty and not value:
717 if default_when_empty and not value:
713 # use default value when value is empty
718 # use default value when value is empty
714 value = default
719 value = default
715
720
716 if lower:
721 if lower:
717 value = value.lower()
722 value = value.lower()
718 settings[name] = value
723 settings[name] = value
719 return settings[name]
724 return settings[name]
720
725
721
726
722 def _substitute_values(mapping, substitutions):
727 def _substitute_values(mapping, substitutions):
723 result = {}
728 result = {}
724
729
725 try:
730 try:
726 for key, value in mapping.items():
731 for key, value in mapping.items():
727 # initialize without substitution first
732 # initialize without substitution first
728 result[key] = value
733 result[key] = value
729
734
730 # Note: Cannot use regular replacements, since they would clash
735 # Note: Cannot use regular replacements, since they would clash
731 # with the implementation of ConfigParser. Using "format" instead.
736 # with the implementation of ConfigParser. Using "format" instead.
732 try:
737 try:
733 result[key] = value.format(**substitutions)
738 result[key] = value.format(**substitutions)
734 except KeyError as e:
739 except KeyError as e:
735 env_var = '{}'.format(e.args[0])
740 env_var = '{}'.format(e.args[0])
736
741
737 msg = 'Failed to substitute: `{key}={{{var}}}` with environment entry. ' \
742 msg = 'Failed to substitute: `{key}={{{var}}}` with environment entry. ' \
738 'Make sure your environment has {var} set, or remove this ' \
743 'Make sure your environment has {var} set, or remove this ' \
739 'variable from config file'.format(key=key, var=env_var)
744 'variable from config file'.format(key=key, var=env_var)
740
745
741 if env_var.startswith('ENV_'):
746 if env_var.startswith('ENV_'):
742 raise ValueError(msg)
747 raise ValueError(msg)
743 else:
748 else:
744 log.warning(msg)
749 log.warning(msg)
745
750
746 except ValueError as e:
751 except ValueError as e:
747 log.warning('Failed to substitute ENV variable: %s', e)
752 log.warning('Failed to substitute ENV variable: %s', e)
748 result = mapping
753 result = mapping
749
754
750 return result
755 return result
@@ -1,40 +1,45 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2015-2019 RhodeCode GmbH
3 # Copyright (C) 2015-2019 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 atexit
22 import atexit
22 import logging
23 import logging
23
24
24 log = logging.getLogger(__name__)
25 log = logging.getLogger(__name__)
25
26
26 cache_keys_by_pid = []
27 cache_keys_by_pid = []
27
28
28
29
29 @atexit.register
30 @atexit.register
30 def free_cache_keys():
31 def free_cache_keys():
32 ssh_cmd = os.environ.get('RC_CMD_SSH_WRAPPER')
33 if ssh_cmd:
34 return
35
31 from rhodecode.model.db import Session, CacheKey
36 from rhodecode.model.db import Session, CacheKey
32 log.info('Clearing %s cache keys', len(cache_keys_by_pid))
37 log.info('Clearing %s cache keys', len(cache_keys_by_pid))
33
38
34 if cache_keys_by_pid:
39 if cache_keys_by_pid:
35 try:
40 try:
36 for cache_key in cache_keys_by_pid:
41 for cache_key in cache_keys_by_pid:
37 CacheKey.query().filter(CacheKey.cache_key == cache_key).delete()
42 CacheKey.query().filter(CacheKey.cache_key == cache_key).delete()
38 Session().commit()
43 Session().commit()
39 except Exception:
44 except Exception:
40 log.warn('Failed to clear keys, exiting gracefully')
45 log.warn('Failed to clear keys, exiting gracefully')
General Comments 0
You need to be logged in to leave comments. Login now