##// END OF EJS Templates
core: added supports of repo based views via pyramid.
marcink -
r1554:8ba8e355 default
parent child Browse files
Show More
@@ -1,112 +1,163 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 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 time
22 22 import logging
23 23 from pylons import tmpl_context as c
24 24 from pyramid.httpexceptions import HTTPFound
25 25
26 26 from rhodecode.lib import helpers as h
27 27 from rhodecode.lib.utils2 import StrictAttributeDict, safe_int
28 from rhodecode.model import repo
28 29 from rhodecode.model.db import User
30 from rhodecode.model.scm import ScmModel
29 31
30 32 log = logging.getLogger(__name__)
31 33
32 34
33 35 ADMIN_PREFIX = '/_admin'
34 36 STATIC_FILE_PREFIX = '/_static'
35 37
36 38
37 39 class TemplateArgs(StrictAttributeDict):
38 40 pass
39 41
40 42
41 43 class BaseAppView(object):
42 44
43 45 def __init__(self, context, request):
44 46 self.request = request
45 47 self.context = context
46 48 self.session = request.session
47 49 self._rhodecode_user = request.user # auth user
48 50 self._rhodecode_db_user = self._rhodecode_user.get_instance()
49 51 self._maybe_needs_password_change(
50 52 request.matched_route.name, self._rhodecode_db_user)
51 53
52 54 def _maybe_needs_password_change(self, view_name, user_obj):
53 55 log.debug('Checking if user %s needs password change on view %s',
54 56 user_obj, view_name)
55 57 skip_user_views = [
56 58 'logout', 'login',
57 59 'my_account_password', 'my_account_password_update'
58 60 ]
59 61
60 62 if not user_obj:
61 63 return
62 64
63 65 if user_obj.username == User.DEFAULT_USER:
64 66 return
65 67
66 68 now = time.time()
67 69 should_change = user_obj.user_data.get('force_password_change')
68 70 change_after = safe_int(should_change) or 0
69 71 if should_change and now > change_after:
70 72 log.debug('User %s requires password change', user_obj)
71 73 h.flash('You are required to change your password', 'warning',
72 74 ignore_duplicate=True)
73 75
74 76 if view_name not in skip_user_views:
75 77 raise HTTPFound(
76 78 self.request.route_path('my_account_password'))
77 79
78 80 def _get_local_tmpl_context(self):
79 81 c = TemplateArgs()
80 82 c.auth_user = self.request.user
81 83 return c
82 84
83 85 def _register_global_c(self, tmpl_args):
84 86 """
85 87 Registers attributes to pylons global `c`
86 88 """
87 89 # TODO(marcink): remove once pyramid migration is finished
88 90 for k, v in tmpl_args.items():
89 91 setattr(c, k, v)
90 92
91 93 def _get_template_context(self, tmpl_args):
92 94 self._register_global_c(tmpl_args)
93 95
94 96 local_tmpl_args = {
95 97 'defaults': {},
96 98 'errors': {},
97 99 }
98 100 local_tmpl_args.update(tmpl_args)
99 101 return local_tmpl_args
100 102
101 103 def load_default_context(self):
102 104 """
103 105 example:
104 106
105 107 def load_default_context(self):
106 108 c = self._get_local_tmpl_context()
107 109 c.custom_var = 'foobar'
108 110 self._register_global_c(c)
109 111 return c
110 112 """
111 113 raise NotImplementedError('Needs implementation in view class')
112 114
115
116 class RepoAppView(BaseAppView):
117
118 def __init__(self, context, request):
119 super(RepoAppView, self).__init__(context, request)
120 self.db_repo = request.db_repo
121 self.db_repo_name = self.db_repo.repo_name
122 self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
123
124 def _get_local_tmpl_context(self):
125 c = super(RepoAppView, self)._get_local_tmpl_context()
126 # register common vars for this type of view
127 c.rhodecode_db_repo = self.db_repo
128 c.repo_name = self.db_repo_name
129 c.repository_pull_requests = self.db_repo_pull_requests
130 return c
131
132
133 class RepoRoutePredicate(object):
134 def __init__(self, val, config):
135 self.val = val
136
137 def text(self):
138 return 'repo_route = %s' % self.val
139
140 phash = text
141
142 def __call__(self, info, request):
143 repo_name = info['match']['repo_name']
144 repo_model = repo.RepoModel()
145 by_name_match = repo_model.get_by_repo_name(repo_name, cache=True)
146 # if we match quickly from database, short circuit the operation,
147 # and validate repo based on the type.
148 if by_name_match:
149 # register this as request object we can re-use later
150 request.db_repo = by_name_match
151 return True
152
153 by_id_match = repo_model.get_repo_by_id(repo_name)
154 if by_id_match:
155 request.db_repo = by_id_match
156 return True
157
158 return False
159
160
161 def includeme(config):
162 config.add_route_predicate(
163 'repo_route', RepoRoutePredicate)
@@ -1,504 +1,506 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 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 """
22 22 Pylons middleware initialization
23 23 """
24 24 import logging
25 25 from collections import OrderedDict
26 26
27 27 from paste.registry import RegistryManager
28 28 from paste.gzipper import make_gzip_middleware
29 29 from pylons.wsgiapp import PylonsApp
30 30 from pyramid.authorization import ACLAuthorizationPolicy
31 31 from pyramid.config import Configurator
32 32 from pyramid.settings import asbool, aslist
33 33 from pyramid.wsgi import wsgiapp
34 34 from pyramid.httpexceptions import (
35 35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
36 36 from pyramid.events import ApplicationCreated
37 37 from pyramid.renderers import render_to_response
38 38 from routes.middleware import RoutesMiddleware
39 39 import routes.util
40 40
41 41 import rhodecode
42 42 from rhodecode.model import meta
43 43 from rhodecode.config import patches
44 44 from rhodecode.config.routing import STATIC_FILE_PREFIX
45 45 from rhodecode.config.environment import (
46 46 load_environment, load_pyramid_environment)
47 47 from rhodecode.lib.middleware import csrf
48 48 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 49 from rhodecode.lib.middleware.error_handling import (
50 50 PylonsErrorHandlingMiddleware)
51 51 from rhodecode.lib.middleware.https_fixup import HttpsFixup
52 52 from rhodecode.lib.middleware.vcs import VCSMiddleware
53 53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
54 54 from rhodecode.lib.utils2 import aslist as rhodecode_aslist
55 55 from rhodecode.subscribers import (
56 56 scan_repositories_if_enabled, write_metadata_if_needed,
57 57 write_js_routes_if_enabled)
58 58
59 59
60 60 log = logging.getLogger(__name__)
61 61
62 62
63 63 # this is used to avoid avoid the route lookup overhead in routesmiddleware
64 64 # for certain routes which won't go to pylons to - eg. static files, debugger
65 65 # it is only needed for the pylons migration and can be removed once complete
66 66 class SkippableRoutesMiddleware(RoutesMiddleware):
67 67 """ Routes middleware that allows you to skip prefixes """
68 68
69 69 def __init__(self, *args, **kw):
70 70 self.skip_prefixes = kw.pop('skip_prefixes', [])
71 71 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
72 72
73 73 def __call__(self, environ, start_response):
74 74 for prefix in self.skip_prefixes:
75 75 if environ['PATH_INFO'].startswith(prefix):
76 76 # added to avoid the case when a missing /_static route falls
77 77 # through to pylons and causes an exception as pylons is
78 78 # expecting wsgiorg.routingargs to be set in the environ
79 79 # by RoutesMiddleware.
80 80 if 'wsgiorg.routing_args' not in environ:
81 81 environ['wsgiorg.routing_args'] = (None, {})
82 82 return self.app(environ, start_response)
83 83
84 84 return super(SkippableRoutesMiddleware, self).__call__(
85 85 environ, start_response)
86 86
87 87
88 88 def make_app(global_conf, static_files=True, **app_conf):
89 89 """Create a Pylons WSGI application and return it
90 90
91 91 ``global_conf``
92 92 The inherited configuration for this application. Normally from
93 93 the [DEFAULT] section of the Paste ini file.
94 94
95 95 ``app_conf``
96 96 The application's local configuration. Normally specified in
97 97 the [app:<name>] section of the Paste ini file (where <name>
98 98 defaults to main).
99 99
100 100 """
101 101 # Apply compatibility patches
102 102 patches.kombu_1_5_1_python_2_7_11()
103 103 patches.inspect_getargspec()
104 104
105 105 # Configure the Pylons environment
106 106 config = load_environment(global_conf, app_conf)
107 107
108 108 # The Pylons WSGI app
109 109 app = PylonsApp(config=config)
110 110 if rhodecode.is_test:
111 111 app = csrf.CSRFDetector(app)
112 112
113 113 expected_origin = config.get('expected_origin')
114 114 if expected_origin:
115 115 # The API can be accessed from other Origins.
116 116 app = csrf.OriginChecker(app, expected_origin,
117 117 skip_urls=[routes.util.url_for('api')])
118 118
119 119 # Establish the Registry for this application
120 120 app = RegistryManager(app)
121 121
122 122 app.config = config
123 123
124 124 return app
125 125
126 126
127 127 def make_pyramid_app(global_config, **settings):
128 128 """
129 129 Constructs the WSGI application based on Pyramid and wraps the Pylons based
130 130 application.
131 131
132 132 Specials:
133 133
134 134 * We migrate from Pylons to Pyramid. While doing this, we keep both
135 135 frameworks functional. This involves moving some WSGI middlewares around
136 136 and providing access to some data internals, so that the old code is
137 137 still functional.
138 138
139 139 * The application can also be integrated like a plugin via the call to
140 140 `includeme`. This is accompanied with the other utility functions which
141 141 are called. Changing this should be done with great care to not break
142 142 cases when these fragments are assembled from another place.
143 143
144 144 """
145 145 # The edition string should be available in pylons too, so we add it here
146 146 # before copying the settings.
147 147 settings.setdefault('rhodecode.edition', 'Community Edition')
148 148
149 149 # As long as our Pylons application does expect "unprepared" settings, make
150 150 # sure that we keep an unmodified copy. This avoids unintentional change of
151 151 # behavior in the old application.
152 152 settings_pylons = settings.copy()
153 153
154 154 sanitize_settings_and_apply_defaults(settings)
155 155 config = Configurator(settings=settings)
156 156 add_pylons_compat_data(config.registry, global_config, settings_pylons)
157 157
158 158 load_pyramid_environment(global_config, settings)
159 159
160 160 includeme_first(config)
161 161 includeme(config)
162 162 pyramid_app = config.make_wsgi_app()
163 163 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
164 164 pyramid_app.config = config
165 165
166 166 # creating the app uses a connection - return it after we are done
167 167 meta.Session.remove()
168 168
169 169 return pyramid_app
170 170
171 171
172 172 def make_not_found_view(config):
173 173 """
174 174 This creates the view which should be registered as not-found-view to
175 175 pyramid. Basically it contains of the old pylons app, converted to a view.
176 176 Additionally it is wrapped by some other middlewares.
177 177 """
178 178 settings = config.registry.settings
179 179 vcs_server_enabled = settings['vcs.server.enable']
180 180
181 181 # Make pylons app from unprepared settings.
182 182 pylons_app = make_app(
183 183 config.registry._pylons_compat_global_config,
184 184 **config.registry._pylons_compat_settings)
185 185 config.registry._pylons_compat_config = pylons_app.config
186 186
187 187 # Appenlight monitoring.
188 188 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
189 189 pylons_app, settings)
190 190
191 191 # The pylons app is executed inside of the pyramid 404 exception handler.
192 192 # Exceptions which are raised inside of it are not handled by pyramid
193 193 # again. Therefore we add a middleware that invokes the error handler in
194 194 # case of an exception or error response. This way we return proper error
195 195 # HTML pages in case of an error.
196 196 reraise = (settings.get('debugtoolbar.enabled', False) or
197 197 rhodecode.disable_error_handler)
198 198 pylons_app = PylonsErrorHandlingMiddleware(
199 199 pylons_app, error_handler, reraise)
200 200
201 201 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
202 202 # view to handle the request. Therefore it is wrapped around the pylons
203 203 # app. It has to be outside of the error handling otherwise error responses
204 204 # from the vcsserver are converted to HTML error pages. This confuses the
205 205 # command line tools and the user won't get a meaningful error message.
206 206 if vcs_server_enabled:
207 207 pylons_app = VCSMiddleware(
208 208 pylons_app, settings, appenlight_client, registry=config.registry)
209 209
210 210 # Convert WSGI app to pyramid view and return it.
211 211 return wsgiapp(pylons_app)
212 212
213 213
214 214 def add_pylons_compat_data(registry, global_config, settings):
215 215 """
216 216 Attach data to the registry to support the Pylons integration.
217 217 """
218 218 registry._pylons_compat_global_config = global_config
219 219 registry._pylons_compat_settings = settings
220 220
221 221
222 222 def error_handler(exception, request):
223 223 import rhodecode
224 224 from rhodecode.lib.utils2 import AttributeDict
225 225
226 226 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
227 227
228 228 base_response = HTTPInternalServerError()
229 229 # prefer original exception for the response since it may have headers set
230 230 if isinstance(exception, HTTPException):
231 231 base_response = exception
232 232
233 233 def is_http_error(response):
234 234 # error which should have traceback
235 235 return response.status_code > 499
236 236
237 237 if is_http_error(base_response):
238 238 log.exception(
239 239 'error occurred handling this request for path: %s', request.path)
240 240
241 241 c = AttributeDict()
242 242 c.error_message = base_response.status
243 243 c.error_explanation = base_response.explanation or str(base_response)
244 244 c.visual = AttributeDict()
245 245
246 246 c.visual.rhodecode_support_url = (
247 247 request.registry.settings.get('rhodecode_support_url') or
248 248 request.route_url('rhodecode_support')
249 249 )
250 250 c.redirect_time = 0
251 251 c.rhodecode_name = rhodecode_title
252 252 if not c.rhodecode_name:
253 253 c.rhodecode_name = 'Rhodecode'
254 254
255 255 c.causes = []
256 256 if hasattr(base_response, 'causes'):
257 257 c.causes = base_response.causes
258 258
259 259 response = render_to_response(
260 260 '/errors/error_document.mako', {'c': c}, request=request,
261 261 response=base_response)
262 262
263 263 return response
264 264
265 265
266 266 def includeme(config):
267 267 settings = config.registry.settings
268 268
269 269 # plugin information
270 270 config.registry.rhodecode_plugins = OrderedDict()
271 271
272 272 config.add_directive(
273 273 'register_rhodecode_plugin', register_rhodecode_plugin)
274 274
275 275 if asbool(settings.get('appenlight', 'false')):
276 276 config.include('appenlight_client.ext.pyramid_tween')
277 277
278 278 # Includes which are required. The application would fail without them.
279 279 config.include('pyramid_mako')
280 280 config.include('pyramid_beaker')
281 281
282 282 config.include('rhodecode.authentication')
283 283 config.include('rhodecode.integrations')
284 284
285 285 # apps
286 config.include('rhodecode.apps._base')
287
286 288 config.include('rhodecode.apps.admin')
287 289 config.include('rhodecode.apps.channelstream')
288 290 config.include('rhodecode.apps.login')
289 291 config.include('rhodecode.apps.user_profile')
290 292 config.include('rhodecode.apps.my_account')
291 293 config.include('rhodecode.apps.svn_support')
292 294
293 295 config.include('rhodecode.tweens')
294 296 config.include('rhodecode.api')
295 297
296 298 config.add_route(
297 299 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
298 300
299 301 config.add_translation_dirs('rhodecode:i18n/')
300 302 settings['default_locale_name'] = settings.get('lang', 'en')
301 303
302 304 # Add subscribers.
303 305 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
304 306 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
305 307 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
306 308
307 309 # Set the authorization policy.
308 310 authz_policy = ACLAuthorizationPolicy()
309 311 config.set_authorization_policy(authz_policy)
310 312
311 313 # Set the default renderer for HTML templates to mako.
312 314 config.add_mako_renderer('.html')
313 315
314 316 # include RhodeCode plugins
315 317 includes = aslist(settings.get('rhodecode.includes', []))
316 318 for inc in includes:
317 319 config.include(inc)
318 320
319 321 # This is the glue which allows us to migrate in chunks. By registering the
320 322 # pylons based application as the "Not Found" view in Pyramid, we will
321 323 # fallback to the old application each time the new one does not yet know
322 324 # how to handle a request.
323 325 config.add_notfound_view(make_not_found_view(config))
324 326
325 327 if not settings.get('debugtoolbar.enabled', False):
326 328 # if no toolbar, then any exception gets caught and rendered
327 329 config.add_view(error_handler, context=Exception)
328 330
329 331 config.add_view(error_handler, context=HTTPError)
330 332
331 333
332 334 def includeme_first(config):
333 335 # redirect automatic browser favicon.ico requests to correct place
334 336 def favicon_redirect(context, request):
335 337 return HTTPFound(
336 338 request.static_path('rhodecode:public/images/favicon.ico'))
337 339
338 340 config.add_view(favicon_redirect, route_name='favicon')
339 341 config.add_route('favicon', '/favicon.ico')
340 342
341 343 def robots_redirect(context, request):
342 344 return HTTPFound(
343 345 request.static_path('rhodecode:public/robots.txt'))
344 346
345 347 config.add_view(robots_redirect, route_name='robots')
346 348 config.add_route('robots', '/robots.txt')
347 349
348 350 config.add_static_view(
349 351 '_static/deform', 'deform:static')
350 352 config.add_static_view(
351 353 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
352 354
353 355
354 356 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
355 357 """
356 358 Apply outer WSGI middlewares around the application.
357 359
358 360 Part of this has been moved up from the Pylons layer, so that the
359 361 data is also available if old Pylons code is hit through an already ported
360 362 view.
361 363 """
362 364 settings = config.registry.settings
363 365
364 366 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
365 367 pyramid_app = HttpsFixup(pyramid_app, settings)
366 368
367 369 # Add RoutesMiddleware to support the pylons compatibility tween during
368 370 # migration to pyramid.
369 371 pyramid_app = SkippableRoutesMiddleware(
370 372 pyramid_app, config.registry._pylons_compat_config['routes.map'],
371 373 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
372 374
373 375 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
374 376
375 377 if settings['gzip_responses']:
376 378 pyramid_app = make_gzip_middleware(
377 379 pyramid_app, settings, compress_level=1)
378 380
379 381 # this should be the outer most middleware in the wsgi stack since
380 382 # middleware like Routes make database calls
381 383 def pyramid_app_with_cleanup(environ, start_response):
382 384 try:
383 385 return pyramid_app(environ, start_response)
384 386 finally:
385 387 # Dispose current database session and rollback uncommitted
386 388 # transactions.
387 389 meta.Session.remove()
388 390
389 391 # In a single threaded mode server, on non sqlite db we should have
390 392 # '0 Current Checked out connections' at the end of a request,
391 393 # if not, then something, somewhere is leaving a connection open
392 394 pool = meta.Base.metadata.bind.engine.pool
393 395 log.debug('sa pool status: %s', pool.status())
394 396
395 397
396 398 return pyramid_app_with_cleanup
397 399
398 400
399 401 def sanitize_settings_and_apply_defaults(settings):
400 402 """
401 403 Applies settings defaults and does all type conversion.
402 404
403 405 We would move all settings parsing and preparation into this place, so that
404 406 we have only one place left which deals with this part. The remaining parts
405 407 of the application would start to rely fully on well prepared settings.
406 408
407 409 This piece would later be split up per topic to avoid a big fat monster
408 410 function.
409 411 """
410 412
411 413 # Pyramid's mako renderer has to search in the templates folder so that the
412 414 # old templates still work. Ported and new templates are expected to use
413 415 # real asset specifications for the includes.
414 416 mako_directories = settings.setdefault('mako.directories', [
415 417 # Base templates of the original Pylons application
416 418 'rhodecode:templates',
417 419 ])
418 420 log.debug(
419 421 "Using the following Mako template directories: %s",
420 422 mako_directories)
421 423
422 424 # Default includes, possible to change as a user
423 425 pyramid_includes = settings.setdefault('pyramid.includes', [
424 426 'rhodecode.lib.middleware.request_wrapper',
425 427 ])
426 428 log.debug(
427 429 "Using the following pyramid.includes: %s",
428 430 pyramid_includes)
429 431
430 432 # TODO: johbo: Re-think this, usually the call to config.include
431 433 # should allow to pass in a prefix.
432 434 settings.setdefault('rhodecode.api.url', '/_admin/api')
433 435
434 436 # Sanitize generic settings.
435 437 _list_setting(settings, 'default_encoding', 'UTF-8')
436 438 _bool_setting(settings, 'is_test', 'false')
437 439 _bool_setting(settings, 'gzip_responses', 'false')
438 440
439 441 # Call split out functions that sanitize settings for each topic.
440 442 _sanitize_appenlight_settings(settings)
441 443 _sanitize_vcs_settings(settings)
442 444
443 445 return settings
444 446
445 447
446 448 def _sanitize_appenlight_settings(settings):
447 449 _bool_setting(settings, 'appenlight', 'false')
448 450
449 451
450 452 def _sanitize_vcs_settings(settings):
451 453 """
452 454 Applies settings defaults and does type conversion for all VCS related
453 455 settings.
454 456 """
455 457 _string_setting(settings, 'vcs.svn.compatible_version', '')
456 458 _string_setting(settings, 'git_rev_filter', '--all')
457 459 _string_setting(settings, 'vcs.hooks.protocol', 'http')
458 460 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
459 461 _string_setting(settings, 'vcs.server', '')
460 462 _string_setting(settings, 'vcs.server.log_level', 'debug')
461 463 _string_setting(settings, 'vcs.server.protocol', 'http')
462 464 _bool_setting(settings, 'startup.import_repos', 'false')
463 465 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
464 466 _bool_setting(settings, 'vcs.server.enable', 'true')
465 467 _bool_setting(settings, 'vcs.start_server', 'false')
466 468 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
467 469 _int_setting(settings, 'vcs.connection_timeout', 3600)
468 470
469 471 # Support legacy values of vcs.scm_app_implementation. Legacy
470 472 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
471 473 # which is now mapped to 'http'.
472 474 scm_app_impl = settings['vcs.scm_app_implementation']
473 475 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
474 476 settings['vcs.scm_app_implementation'] = 'http'
475 477
476 478
477 479 def _int_setting(settings, name, default):
478 480 settings[name] = int(settings.get(name, default))
479 481
480 482
481 483 def _bool_setting(settings, name, default):
482 484 input = settings.get(name, default)
483 485 if isinstance(input, unicode):
484 486 input = input.encode('utf8')
485 487 settings[name] = asbool(input)
486 488
487 489
488 490 def _list_setting(settings, name, default):
489 491 raw_value = settings.get(name, default)
490 492
491 493 old_separator = ','
492 494 if old_separator in raw_value:
493 495 # If we get a comma separated list, pass it to our own function.
494 496 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
495 497 else:
496 498 # Otherwise we assume it uses pyramids space/newline separation.
497 499 settings[name] = aslist(raw_value)
498 500
499 501
500 502 def _string_setting(settings, name, default, lower=True):
501 503 value = settings.get(name, default)
502 504 if lower:
503 505 value = value.lower()
504 506 settings[name] = value
General Comments 0
You need to be logged in to leave comments. Login now