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