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