##// END OF EJS Templates
core: code refactor and cleanups for easier pylons porting.
marcink -
r2321:a29db630 default
parent child Browse files
Show More
@@ -1,182 +1,177 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Pylons environment configuration
22 Pylons environment configuration
23 """
23 """
24
24
25 import os
25 import os
26 import logging
26 import logging
27 import rhodecode
27 import rhodecode
28 import platform
29 import re
30 import io
31
28
32 from mako.lookup import TemplateLookup
29 from mako.lookup import TemplateLookup
33 from pylons.configuration import PylonsConfig
34 from pylons.error import handle_mako_error
35 from pyramid.settings import asbool
30 from pyramid.settings import asbool
36
31
37 # ------------------------------------------------------------------------------
32 # ------------------------------------------------------------------------------
38 # CELERY magic until refactor - issue #4163 - import order matters here:
33 # CELERY magic until refactor - issue #4163 - import order matters here:
39 from rhodecode.lib import celerypylons # this must be first, celerypylons
34 from rhodecode.lib import celerypylons # this must be first, celerypylons
40 # sets config settings upon import
35 # sets config settings upon import
41
36
42 import rhodecode.integrations # any modules using celery task
37 import rhodecode.integrations # any modules using celery task
43 # decorators should be added afterwards:
38 # decorators should be added afterwards:
44 # ------------------------------------------------------------------------------
39 # ------------------------------------------------------------------------------
45
40
46 from rhodecode.lib import app_globals
41 from rhodecode.lib import app_globals
47 from rhodecode.config import utils
42 from rhodecode.config import utils
48 from rhodecode.config.routing import make_map
43 from rhodecode.config.routing import make_map
49 from rhodecode.config.jsroutes import generate_jsroutes_content
50
44
51 from rhodecode.lib import helpers
45 from rhodecode.lib import helpers
52 from rhodecode.lib.auth import set_available_permissions
53 from rhodecode.lib.utils import (
46 from rhodecode.lib.utils import (
54 repo2db_mapper, make_db_config, set_rhodecode_config,
47 make_db_config, set_rhodecode_config, load_rcextensions)
55 load_rcextensions)
56 from rhodecode.lib.utils2 import str2bool, aslist
48 from rhodecode.lib.utils2 import str2bool, aslist
57 from rhodecode.lib.vcs import connect_vcs, start_vcs_server
49 from rhodecode.lib.vcs import connect_vcs, start_vcs_server
58 from rhodecode.model.scm import ScmModel
59
50
60 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
61
52
53
62 def load_environment(global_conf, app_conf, initial=False,
54 def load_environment(global_conf, app_conf, initial=False,
63 test_env=None, test_index=None):
55 test_env=None, test_index=None):
64 """
56 """
65 Configure the Pylons environment via the ``pylons.config``
57 Configure the Pylons environment via the ``pylons.config``
66 object
58 object
67 """
59 """
60 from pylons.configuration import PylonsConfig
61 from pylons.error import handle_mako_error
62
68 config = PylonsConfig()
63 config = PylonsConfig()
69
64
70
65
71 # Pylons paths
66 # Pylons paths
72 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
67 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
73 paths = {
68 paths = {
74 'root': root,
69 'root': root,
75 'controllers': os.path.join(root, 'controllers'),
70 'controllers': os.path.join(root, 'controllers'),
76 'static_files': os.path.join(root, 'public'),
71 'static_files': os.path.join(root, 'public'),
77 'templates': [os.path.join(root, 'templates')],
72 'templates': [os.path.join(root, 'templates')],
78 }
73 }
79
74
80 # Initialize config with the basic options
75 # Initialize config with the basic options
81 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
76 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
82
77
83 # store some globals into rhodecode
78 # store some globals into rhodecode
84 rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery'))
79 rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery'))
85 rhodecode.CELERY_EAGER = str2bool(
80 rhodecode.CELERY_EAGER = str2bool(
86 config['app_conf'].get('celery.always.eager'))
81 config['app_conf'].get('celery.always.eager'))
87
82
88 config['routes.map'] = make_map(config)
83 config['routes.map'] = make_map(config)
89
84
90 config['pylons.app_globals'] = app_globals.Globals(config)
85 config['pylons.app_globals'] = app_globals.Globals(config)
91 config['pylons.h'] = helpers
86 config['pylons.h'] = helpers
92 rhodecode.CONFIG = config
87 rhodecode.CONFIG = config
93
88
94 load_rcextensions(root_path=config['here'])
89 load_rcextensions(root_path=config['here'])
95
90
96 # Setup cache object as early as possible
91 # Setup cache object as early as possible
97 import pylons
92 import pylons
98 pylons.cache._push_object(config['pylons.app_globals'].cache)
93 pylons.cache._push_object(config['pylons.app_globals'].cache)
99
94
100 # Create the Mako TemplateLookup, with the default auto-escaping
95 # Create the Mako TemplateLookup, with the default auto-escaping
101 config['pylons.app_globals'].mako_lookup = TemplateLookup(
96 config['pylons.app_globals'].mako_lookup = TemplateLookup(
102 directories=paths['templates'],
97 directories=paths['templates'],
103 error_handler=handle_mako_error,
98 error_handler=handle_mako_error,
104 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
99 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
105 input_encoding='utf-8', default_filters=['escape'],
100 input_encoding='utf-8', default_filters=['escape'],
106 imports=['from webhelpers.html import escape'])
101 imports=['from webhelpers.html import escape'])
107
102
108 # sets the c attribute access when don't existing attribute are accessed
103 # sets the c attribute access when don't existing attribute are accessed
109 config['pylons.strict_tmpl_context'] = True
104 config['pylons.strict_tmpl_context'] = True
110
105
111 # configure channelstream
106 # configure channelstream
112 config['channelstream_config'] = {
107 config['channelstream_config'] = {
113 'enabled': asbool(config.get('channelstream.enabled', False)),
108 'enabled': asbool(config.get('channelstream.enabled', False)),
114 'server': config.get('channelstream.server'),
109 'server': config.get('channelstream.server'),
115 'secret': config.get('channelstream.secret')
110 'secret': config.get('channelstream.secret')
116 }
111 }
117
112
118 db_cfg = make_db_config(clear_session=True)
113 db_cfg = make_db_config(clear_session=True)
119
114
120 repos_path = list(db_cfg.items('paths'))[0][1]
115 repos_path = list(db_cfg.items('paths'))[0][1]
121 config['base_path'] = repos_path
116 config['base_path'] = repos_path
122
117
123 # store db config also in main global CONFIG
118 # store db config also in main global CONFIG
124 set_rhodecode_config(config)
119 set_rhodecode_config(config)
125
120
126 # configure instance id
121 # configure instance id
127 utils.set_instance_id(config)
122 utils.set_instance_id(config)
128
123
129 # CONFIGURATION OPTIONS HERE (note: all config options will override
124 # CONFIGURATION OPTIONS HERE (note: all config options will override
130 # any Pylons config options)
125 # any Pylons config options)
131
126
132 # store config reference into our module to skip import magic of pylons
127 # store config reference into our module to skip import magic of pylons
133 rhodecode.CONFIG.update(config)
128 rhodecode.CONFIG.update(config)
134
129
135 return config
130 return config
136
131
137
132
138 def load_pyramid_environment(global_config, settings):
133 def load_pyramid_environment(global_config, settings):
139 # Some parts of the code expect a merge of global and app settings.
134 # Some parts of the code expect a merge of global and app settings.
140 settings_merged = global_config.copy()
135 settings_merged = global_config.copy()
141 settings_merged.update(settings)
136 settings_merged.update(settings)
142
137
143 # Store the settings to make them available to other modules.
138 # Store the settings to make them available to other modules.
144 rhodecode.PYRAMID_SETTINGS = settings_merged
139 rhodecode.PYRAMID_SETTINGS = settings_merged
145 # NOTE(marcink): needs to be enabled after full port to pyramid
140 # NOTE(marcink): needs to be enabled after full port to pyramid
146 # rhodecode.CONFIG = config
141 # rhodecode.CONFIG = config
147
142
148 # If this is a test run we prepare the test environment like
143 # If this is a test run we prepare the test environment like
149 # creating a test database, test search index and test repositories.
144 # creating a test database, test search index and test repositories.
150 # This has to be done before the database connection is initialized.
145 # This has to be done before the database connection is initialized.
151 if settings['is_test']:
146 if settings['is_test']:
152 rhodecode.is_test = True
147 rhodecode.is_test = True
153 rhodecode.disable_error_handler = True
148 rhodecode.disable_error_handler = True
154
149
155 utils.initialize_test_environment(settings_merged)
150 utils.initialize_test_environment(settings_merged)
156
151
157 # Initialize the database connection.
152 # Initialize the database connection.
158 utils.initialize_database(settings_merged)
153 utils.initialize_database(settings_merged)
159
154
160 # Limit backends to `vcs.backends` from configuration
155 # Limit backends to `vcs.backends` from configuration
161 for alias in rhodecode.BACKENDS.keys():
156 for alias in rhodecode.BACKENDS.keys():
162 if alias not in settings['vcs.backends']:
157 if alias not in settings['vcs.backends']:
163 del rhodecode.BACKENDS[alias]
158 del rhodecode.BACKENDS[alias]
164 log.info('Enabled VCS backends: %s', rhodecode.BACKENDS.keys())
159 log.info('Enabled VCS backends: %s', rhodecode.BACKENDS.keys())
165
160
166 # initialize vcs client and optionally run the server if enabled
161 # initialize vcs client and optionally run the server if enabled
167 vcs_server_uri = settings['vcs.server']
162 vcs_server_uri = settings['vcs.server']
168 vcs_server_enabled = settings['vcs.server.enable']
163 vcs_server_enabled = settings['vcs.server.enable']
169 start_server = (
164 start_server = (
170 settings['vcs.start_server'] and
165 settings['vcs.start_server'] and
171 not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0')))
166 not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0')))
172
167
173 if vcs_server_enabled and start_server:
168 if vcs_server_enabled and start_server:
174 log.info("Starting vcsserver")
169 log.info("Starting vcsserver")
175 start_vcs_server(server_and_port=vcs_server_uri,
170 start_vcs_server(server_and_port=vcs_server_uri,
176 protocol=utils.get_vcs_server_protocol(settings),
171 protocol=utils.get_vcs_server_protocol(settings),
177 log_level=settings['vcs.server.log_level'])
172 log_level=settings['vcs.server.log_level'])
178
173
179 utils.configure_vcs(settings)
174 utils.configure_vcs(settings)
180
175
181 if vcs_server_enabled:
176 if vcs_server_enabled:
182 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
177 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
@@ -1,542 +1,543 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Pylons middleware initialization
22 Pylons middleware initialization
23 """
23 """
24 import logging
24 import logging
25 import traceback
25 import traceback
26 from collections import OrderedDict
26 import collections
27
27
28 from paste.registry import RegistryManager
28 from paste.registry import RegistryManager
29 from paste.gzipper import make_gzip_middleware
29 from paste.gzipper import make_gzip_middleware
30 from pylons.wsgiapp import PylonsApp
31 from pyramid.authorization import ACLAuthorizationPolicy
30 from pyramid.authorization import ACLAuthorizationPolicy
32 from pyramid.config import Configurator
31 from pyramid.config import Configurator
33 from pyramid.settings import asbool, aslist
32 from pyramid.settings import asbool, aslist
34 from pyramid.wsgi import wsgiapp
33 from pyramid.wsgi import wsgiapp
35 from pyramid.httpexceptions import (
34 from pyramid.httpexceptions import (
36 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
35 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
37 from pyramid.events import ApplicationCreated
36 from pyramid.events import ApplicationCreated
38 from pyramid.renderers import render_to_response
37 from pyramid.renderers import render_to_response
39 from routes.middleware import RoutesMiddleware
38 from routes.middleware import RoutesMiddleware
40 import rhodecode
39 import rhodecode
41
40
42 from rhodecode.model import meta
41 from rhodecode.model import meta
43 from rhodecode.config import patches
42 from rhodecode.config import patches
44 from rhodecode.config import utils as config_utils
43 from rhodecode.config import utils as config_utils
45 from rhodecode.config.routing import STATIC_FILE_PREFIX
44 from rhodecode.config.routing import STATIC_FILE_PREFIX
46 from rhodecode.config.environment import (
45 from rhodecode.config.environment import (
47 load_environment, load_pyramid_environment)
46 load_environment, load_pyramid_environment)
48
47
49 from rhodecode.lib.vcs import VCSCommunicationError
48 from rhodecode.lib.vcs import VCSCommunicationError
50 from rhodecode.lib.exceptions import VCSServerUnavailable
49 from rhodecode.lib.exceptions import VCSServerUnavailable
51 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
50 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
52 from rhodecode.lib.middleware.error_handling import (
51 from rhodecode.lib.middleware.error_handling import (
53 PylonsErrorHandlingMiddleware)
52 PylonsErrorHandlingMiddleware)
54 from rhodecode.lib.middleware.https_fixup import HttpsFixup
53 from rhodecode.lib.middleware.https_fixup import HttpsFixup
55 from rhodecode.lib.middleware.vcs import VCSMiddleware
54 from rhodecode.lib.middleware.vcs import VCSMiddleware
56 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
55 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
57 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
56 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
58 from rhodecode.subscribers import (
57 from rhodecode.subscribers import (
59 scan_repositories_if_enabled, write_js_routes_if_enabled,
58 scan_repositories_if_enabled, write_js_routes_if_enabled,
60 write_metadata_if_needed, inject_app_settings)
59 write_metadata_if_needed, inject_app_settings)
61
60
62
61
63 log = logging.getLogger(__name__)
62 log = logging.getLogger(__name__)
64
63
65
64
66 # this is used to avoid avoid the route lookup overhead in routesmiddleware
65 # this is used to avoid avoid the route lookup overhead in routesmiddleware
67 # for certain routes which won't go to pylons to - eg. static files, debugger
66 # for certain routes which won't go to pylons to - eg. static files, debugger
68 # it is only needed for the pylons migration and can be removed once complete
67 # it is only needed for the pylons migration and can be removed once complete
69 class SkippableRoutesMiddleware(RoutesMiddleware):
68 class SkippableRoutesMiddleware(RoutesMiddleware):
70 """ Routes middleware that allows you to skip prefixes """
69 """ Routes middleware that allows you to skip prefixes """
71
70
72 def __init__(self, *args, **kw):
71 def __init__(self, *args, **kw):
73 self.skip_prefixes = kw.pop('skip_prefixes', [])
72 self.skip_prefixes = kw.pop('skip_prefixes', [])
74 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
73 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
75
74
76 def __call__(self, environ, start_response):
75 def __call__(self, environ, start_response):
77 for prefix in self.skip_prefixes:
76 for prefix in self.skip_prefixes:
78 if environ['PATH_INFO'].startswith(prefix):
77 if environ['PATH_INFO'].startswith(prefix):
79 # added to avoid the case when a missing /_static route falls
78 # added to avoid the case when a missing /_static route falls
80 # through to pylons and causes an exception as pylons is
79 # through to pylons and causes an exception as pylons is
81 # expecting wsgiorg.routingargs to be set in the environ
80 # expecting wsgiorg.routingargs to be set in the environ
82 # by RoutesMiddleware.
81 # by RoutesMiddleware.
83 if 'wsgiorg.routing_args' not in environ:
82 if 'wsgiorg.routing_args' not in environ:
84 environ['wsgiorg.routing_args'] = (None, {})
83 environ['wsgiorg.routing_args'] = (None, {})
85 return self.app(environ, start_response)
84 return self.app(environ, start_response)
86
85
87 return super(SkippableRoutesMiddleware, self).__call__(
86 return super(SkippableRoutesMiddleware, self).__call__(
88 environ, start_response)
87 environ, start_response)
89
88
90
89
91 def make_app(global_conf, static_files=True, **app_conf):
90 def make_app(global_conf, static_files=True, **app_conf):
92 """Create a Pylons WSGI application and return it
91 """Create a Pylons WSGI application and return it
93
92
94 ``global_conf``
93 ``global_conf``
95 The inherited configuration for this application. Normally from
94 The inherited configuration for this application. Normally from
96 the [DEFAULT] section of the Paste ini file.
95 the [DEFAULT] section of the Paste ini file.
97
96
98 ``app_conf``
97 ``app_conf``
99 The application's local configuration. Normally specified in
98 The application's local configuration. Normally specified in
100 the [app:<name>] section of the Paste ini file (where <name>
99 the [app:<name>] section of the Paste ini file (where <name>
101 defaults to main).
100 defaults to main).
102
101
103 """
102 """
103 from pylons.wsgiapp import PylonsApp
104
104 # Apply compatibility patches
105 # Apply compatibility patches
105 patches.kombu_1_5_1_python_2_7_11()
106 patches.kombu_1_5_1_python_2_7_11()
106 patches.inspect_getargspec()
107 patches.inspect_getargspec()
107
108
108 # Configure the Pylons environment
109 # Configure the Pylons environment
109 config = load_environment(global_conf, app_conf)
110 config = load_environment(global_conf, app_conf)
110
111
111 # The Pylons WSGI app
112 # The Pylons WSGI app
112 app = PylonsApp(config=config)
113 app = PylonsApp(config=config)
113
114
114 # Establish the Registry for this application
115 # Establish the Registry for this application
115 app = RegistryManager(app)
116 app = RegistryManager(app)
116
117
117 app.config = config
118 app.config = config
118
119
119 return app
120 return app
120
121
121
122
122 def make_pyramid_app(global_config, **settings):
123 def make_pyramid_app(global_config, **settings):
123 """
124 """
124 Constructs the WSGI application based on Pyramid and wraps the Pylons based
125 Constructs the WSGI application based on Pyramid and wraps the Pylons based
125 application.
126 application.
126
127
127 Specials:
128 Specials:
128
129
129 * We migrate from Pylons to Pyramid. While doing this, we keep both
130 * We migrate from Pylons to Pyramid. While doing this, we keep both
130 frameworks functional. This involves moving some WSGI middlewares around
131 frameworks functional. This involves moving some WSGI middlewares around
131 and providing access to some data internals, so that the old code is
132 and providing access to some data internals, so that the old code is
132 still functional.
133 still functional.
133
134
134 * The application can also be integrated like a plugin via the call to
135 * The application can also be integrated like a plugin via the call to
135 `includeme`. This is accompanied with the other utility functions which
136 `includeme`. This is accompanied with the other utility functions which
136 are called. Changing this should be done with great care to not break
137 are called. Changing this should be done with great care to not break
137 cases when these fragments are assembled from another place.
138 cases when these fragments are assembled from another place.
138
139
139 """
140 """
140 sanitize_settings_and_apply_defaults(settings)
141 sanitize_settings_and_apply_defaults(settings)
141
142
142 config = Configurator(settings=settings)
143 config = Configurator(settings=settings)
143 load_pyramid_environment(global_config, settings)
144 load_pyramid_environment(global_config, settings)
144
145
145 add_pylons_compat_data(config.registry, global_config, settings.copy())
146 add_pylons_compat_data(config.registry, global_config, settings.copy())
146
147
147 includeme_first(config)
148 includeme_first(config)
148 includeme(config)
149 includeme(config)
149
150
150 pyramid_app = config.make_wsgi_app()
151 pyramid_app = config.make_wsgi_app()
151 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
152 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
152 pyramid_app.config = config
153 pyramid_app.config = config
153
154
154 # creating the app uses a connection - return it after we are done
155 # creating the app uses a connection - return it after we are done
155 meta.Session.remove()
156 meta.Session.remove()
156
157
157 return pyramid_app
158 return pyramid_app
158
159
159
160
160 def make_not_found_view(config):
161 def make_not_found_view(config):
161 """
162 """
162 This creates the view which should be registered as not-found-view to
163 This creates the view which should be registered as not-found-view to
163 pyramid. Basically it contains of the old pylons app, converted to a view.
164 pyramid. Basically it contains of the old pylons app, converted to a view.
164 Additionally it is wrapped by some other middlewares.
165 Additionally it is wrapped by some other middlewares.
165 """
166 """
166 settings = config.registry.settings
167 settings = config.registry.settings
167 vcs_server_enabled = settings['vcs.server.enable']
168 vcs_server_enabled = settings['vcs.server.enable']
168
169
169 # Make pylons app from unprepared settings.
170 # Make pylons app from unprepared settings.
170 pylons_app = make_app(
171 pylons_app = make_app(
171 config.registry._pylons_compat_global_config,
172 config.registry._pylons_compat_global_config,
172 **config.registry._pylons_compat_settings)
173 **config.registry._pylons_compat_settings)
173 config.registry._pylons_compat_config = pylons_app.config
174 config.registry._pylons_compat_config = pylons_app.config
174
175
175 # Appenlight monitoring.
176 # Appenlight monitoring.
176 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
177 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
177 pylons_app, settings)
178 pylons_app, settings)
178
179
179 # The pylons app is executed inside of the pyramid 404 exception handler.
180 # The pylons app is executed inside of the pyramid 404 exception handler.
180 # Exceptions which are raised inside of it are not handled by pyramid
181 # Exceptions which are raised inside of it are not handled by pyramid
181 # again. Therefore we add a middleware that invokes the error handler in
182 # again. Therefore we add a middleware that invokes the error handler in
182 # case of an exception or error response. This way we return proper error
183 # case of an exception or error response. This way we return proper error
183 # HTML pages in case of an error.
184 # HTML pages in case of an error.
184 reraise = (settings.get('debugtoolbar.enabled', False) or
185 reraise = (settings.get('debugtoolbar.enabled', False) or
185 rhodecode.disable_error_handler)
186 rhodecode.disable_error_handler)
186 pylons_app = PylonsErrorHandlingMiddleware(
187 pylons_app = PylonsErrorHandlingMiddleware(
187 pylons_app, error_handler, reraise)
188 pylons_app, error_handler, reraise)
188
189
189 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
190 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
190 # view to handle the request. Therefore it is wrapped around the pylons
191 # view to handle the request. Therefore it is wrapped around the pylons
191 # app. It has to be outside of the error handling otherwise error responses
192 # app. It has to be outside of the error handling otherwise error responses
192 # from the vcsserver are converted to HTML error pages. This confuses the
193 # from the vcsserver are converted to HTML error pages. This confuses the
193 # command line tools and the user won't get a meaningful error message.
194 # command line tools and the user won't get a meaningful error message.
194 if vcs_server_enabled:
195 if vcs_server_enabled:
195 pylons_app = VCSMiddleware(
196 pylons_app = VCSMiddleware(
196 pylons_app, settings, appenlight_client, registry=config.registry)
197 pylons_app, settings, appenlight_client, registry=config.registry)
197
198
198 # Convert WSGI app to pyramid view and return it.
199 # Convert WSGI app to pyramid view and return it.
199 return wsgiapp(pylons_app)
200 return wsgiapp(pylons_app)
200
201
201
202
202 def add_pylons_compat_data(registry, global_config, settings):
203 def add_pylons_compat_data(registry, global_config, settings):
203 """
204 """
204 Attach data to the registry to support the Pylons integration.
205 Attach data to the registry to support the Pylons integration.
205 """
206 """
206 registry._pylons_compat_global_config = global_config
207 registry._pylons_compat_global_config = global_config
207 registry._pylons_compat_settings = settings
208 registry._pylons_compat_settings = settings
208
209
209
210
210 def error_handler(exception, request):
211 def error_handler(exception, request):
211 import rhodecode
212 import rhodecode
212 from rhodecode.lib import helpers
213 from rhodecode.lib import helpers
213
214
214 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
215 rhodecode_title = rhodecode.CONFIG.get('rhodecode_title') or 'RhodeCode'
215
216
216 base_response = HTTPInternalServerError()
217 base_response = HTTPInternalServerError()
217 # prefer original exception for the response since it may have headers set
218 # prefer original exception for the response since it may have headers set
218 if isinstance(exception, HTTPException):
219 if isinstance(exception, HTTPException):
219 base_response = exception
220 base_response = exception
220 elif isinstance(exception, VCSCommunicationError):
221 elif isinstance(exception, VCSCommunicationError):
221 base_response = VCSServerUnavailable()
222 base_response = VCSServerUnavailable()
222
223
223 def is_http_error(response):
224 def is_http_error(response):
224 # error which should have traceback
225 # error which should have traceback
225 return response.status_code > 499
226 return response.status_code > 499
226
227
227 if is_http_error(base_response):
228 if is_http_error(base_response):
228 log.exception(
229 log.exception(
229 'error occurred handling this request for path: %s', request.path)
230 'error occurred handling this request for path: %s', request.path)
230
231
231 error_explanation = base_response.explanation or str(base_response)
232 error_explanation = base_response.explanation or str(base_response)
232 if base_response.status_code == 404:
233 if base_response.status_code == 404:
233 error_explanation += " Or you don't have permission to access it."
234 error_explanation += " Or you don't have permission to access it."
234 c = AttributeDict()
235 c = AttributeDict()
235 c.error_message = base_response.status
236 c.error_message = base_response.status
236 c.error_explanation = error_explanation
237 c.error_explanation = error_explanation
237 c.visual = AttributeDict()
238 c.visual = AttributeDict()
238
239
239 c.visual.rhodecode_support_url = (
240 c.visual.rhodecode_support_url = (
240 request.registry.settings.get('rhodecode_support_url') or
241 request.registry.settings.get('rhodecode_support_url') or
241 request.route_url('rhodecode_support')
242 request.route_url('rhodecode_support')
242 )
243 )
243 c.redirect_time = 0
244 c.redirect_time = 0
244 c.rhodecode_name = rhodecode_title
245 c.rhodecode_name = rhodecode_title
245 if not c.rhodecode_name:
246 if not c.rhodecode_name:
246 c.rhodecode_name = 'Rhodecode'
247 c.rhodecode_name = 'Rhodecode'
247
248
248 c.causes = []
249 c.causes = []
249 if is_http_error(base_response):
250 if is_http_error(base_response):
250 c.causes.append('Server is overloaded.')
251 c.causes.append('Server is overloaded.')
251 c.causes.append('Server database connection is lost.')
252 c.causes.append('Server database connection is lost.')
252 c.causes.append('Server expected unhandled error.')
253 c.causes.append('Server expected unhandled error.')
253
254
254 if hasattr(base_response, 'causes'):
255 if hasattr(base_response, 'causes'):
255 c.causes = base_response.causes
256 c.causes = base_response.causes
256
257
257 c.messages = helpers.flash.pop_messages(request=request)
258 c.messages = helpers.flash.pop_messages(request=request)
258 c.traceback = traceback.format_exc()
259 c.traceback = traceback.format_exc()
259 response = render_to_response(
260 response = render_to_response(
260 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
261 '/errors/error_document.mako', {'c': c, 'h': helpers}, request=request,
261 response=base_response)
262 response=base_response)
262
263
263 return response
264 return response
264
265
265
266
266 def includeme(config):
267 def includeme(config):
267 settings = config.registry.settings
268 settings = config.registry.settings
268
269
269 # plugin information
270 # plugin information
270 config.registry.rhodecode_plugins = OrderedDict()
271 config.registry.rhodecode_plugins = collections.OrderedDict()
271
272
272 config.add_directive(
273 config.add_directive(
273 'register_rhodecode_plugin', register_rhodecode_plugin)
274 'register_rhodecode_plugin', register_rhodecode_plugin)
274
275
275 if asbool(settings.get('appenlight', 'false')):
276 if asbool(settings.get('appenlight', 'false')):
276 config.include('appenlight_client.ext.pyramid_tween')
277 config.include('appenlight_client.ext.pyramid_tween')
277
278
278 # Includes which are required. The application would fail without them.
279 # Includes which are required. The application would fail without them.
279 config.include('pyramid_mako')
280 config.include('pyramid_mako')
280 config.include('pyramid_beaker')
281 config.include('pyramid_beaker')
281
282
282 config.include('rhodecode.authentication')
283 config.include('rhodecode.authentication')
283 config.include('rhodecode.integrations')
284 config.include('rhodecode.integrations')
284
285
285 # apps
286 # apps
286 config.include('rhodecode.apps._base')
287 config.include('rhodecode.apps._base')
287 config.include('rhodecode.apps.ops')
288 config.include('rhodecode.apps.ops')
288
289
289 config.include('rhodecode.apps.admin')
290 config.include('rhodecode.apps.admin')
290 config.include('rhodecode.apps.channelstream')
291 config.include('rhodecode.apps.channelstream')
291 config.include('rhodecode.apps.login')
292 config.include('rhodecode.apps.login')
292 config.include('rhodecode.apps.home')
293 config.include('rhodecode.apps.home')
293 config.include('rhodecode.apps.journal')
294 config.include('rhodecode.apps.journal')
294 config.include('rhodecode.apps.repository')
295 config.include('rhodecode.apps.repository')
295 config.include('rhodecode.apps.repo_group')
296 config.include('rhodecode.apps.repo_group')
296 config.include('rhodecode.apps.user_group')
297 config.include('rhodecode.apps.user_group')
297 config.include('rhodecode.apps.search')
298 config.include('rhodecode.apps.search')
298 config.include('rhodecode.apps.user_profile')
299 config.include('rhodecode.apps.user_profile')
299 config.include('rhodecode.apps.my_account')
300 config.include('rhodecode.apps.my_account')
300 config.include('rhodecode.apps.svn_support')
301 config.include('rhodecode.apps.svn_support')
301 config.include('rhodecode.apps.ssh_support')
302 config.include('rhodecode.apps.ssh_support')
302 config.include('rhodecode.apps.gist')
303 config.include('rhodecode.apps.gist')
303
304
304 config.include('rhodecode.apps.debug_style')
305 config.include('rhodecode.apps.debug_style')
305 config.include('rhodecode.tweens')
306 config.include('rhodecode.tweens')
306 config.include('rhodecode.api')
307 config.include('rhodecode.api')
307
308
308 config.add_route(
309 config.add_route(
309 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
310 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
310
311
311 config.add_translation_dirs('rhodecode:i18n/')
312 config.add_translation_dirs('rhodecode:i18n/')
312 settings['default_locale_name'] = settings.get('lang', 'en')
313 settings['default_locale_name'] = settings.get('lang', 'en')
313
314
314 # Add subscribers.
315 # Add subscribers.
315 config.add_subscriber(inject_app_settings, ApplicationCreated)
316 config.add_subscriber(inject_app_settings, ApplicationCreated)
316 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
317 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
317 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
318 config.add_subscriber(write_metadata_if_needed, ApplicationCreated)
318 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
319 config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated)
319
320
320 config.add_request_method(
321 config.add_request_method(
321 'rhodecode.lib.partial_renderer.get_partial_renderer',
322 'rhodecode.lib.partial_renderer.get_partial_renderer',
322 'get_partial_renderer')
323 'get_partial_renderer')
323
324
324 # events
325 # events
325 # TODO(marcink): this should be done when pyramid migration is finished
326 # TODO(marcink): this should be done when pyramid migration is finished
326 # config.add_subscriber(
327 # config.add_subscriber(
327 # 'rhodecode.integrations.integrations_event_handler',
328 # 'rhodecode.integrations.integrations_event_handler',
328 # 'rhodecode.events.RhodecodeEvent')
329 # 'rhodecode.events.RhodecodeEvent')
329
330
330 # Set the authorization policy.
331 # Set the authorization policy.
331 authz_policy = ACLAuthorizationPolicy()
332 authz_policy = ACLAuthorizationPolicy()
332 config.set_authorization_policy(authz_policy)
333 config.set_authorization_policy(authz_policy)
333
334
334 # Set the default renderer for HTML templates to mako.
335 # Set the default renderer for HTML templates to mako.
335 config.add_mako_renderer('.html')
336 config.add_mako_renderer('.html')
336
337
337 config.add_renderer(
338 config.add_renderer(
338 name='json_ext',
339 name='json_ext',
339 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
340 factory='rhodecode.lib.ext_json_renderer.pyramid_ext_json')
340
341
341 # include RhodeCode plugins
342 # include RhodeCode plugins
342 includes = aslist(settings.get('rhodecode.includes', []))
343 includes = aslist(settings.get('rhodecode.includes', []))
343 for inc in includes:
344 for inc in includes:
344 config.include(inc)
345 config.include(inc)
345
346
346 # This is the glue which allows us to migrate in chunks. By registering the
347 # This is the glue which allows us to migrate in chunks. By registering the
347 # pylons based application as the "Not Found" view in Pyramid, we will
348 # pylons based application as the "Not Found" view in Pyramid, we will
348 # fallback to the old application each time the new one does not yet know
349 # fallback to the old application each time the new one does not yet know
349 # how to handle a request.
350 # how to handle a request.
350 config.add_notfound_view(make_not_found_view(config))
351 config.add_notfound_view(make_not_found_view(config))
351
352
352 if not settings.get('debugtoolbar.enabled', False):
353 if not settings.get('debugtoolbar.enabled', False):
353 # disabled debugtoolbar handle all exceptions via the error_handlers
354 # disabled debugtoolbar handle all exceptions via the error_handlers
354 config.add_view(error_handler, context=Exception)
355 config.add_view(error_handler, context=Exception)
355
356
356 config.add_view(error_handler, context=HTTPError)
357 config.add_view(error_handler, context=HTTPError)
357
358
358
359
359 def includeme_first(config):
360 def includeme_first(config):
360 # redirect automatic browser favicon.ico requests to correct place
361 # redirect automatic browser favicon.ico requests to correct place
361 def favicon_redirect(context, request):
362 def favicon_redirect(context, request):
362 return HTTPFound(
363 return HTTPFound(
363 request.static_path('rhodecode:public/images/favicon.ico'))
364 request.static_path('rhodecode:public/images/favicon.ico'))
364
365
365 config.add_view(favicon_redirect, route_name='favicon')
366 config.add_view(favicon_redirect, route_name='favicon')
366 config.add_route('favicon', '/favicon.ico')
367 config.add_route('favicon', '/favicon.ico')
367
368
368 def robots_redirect(context, request):
369 def robots_redirect(context, request):
369 return HTTPFound(
370 return HTTPFound(
370 request.static_path('rhodecode:public/robots.txt'))
371 request.static_path('rhodecode:public/robots.txt'))
371
372
372 config.add_view(robots_redirect, route_name='robots')
373 config.add_view(robots_redirect, route_name='robots')
373 config.add_route('robots', '/robots.txt')
374 config.add_route('robots', '/robots.txt')
374
375
375 config.add_static_view(
376 config.add_static_view(
376 '_static/deform', 'deform:static')
377 '_static/deform', 'deform:static')
377 config.add_static_view(
378 config.add_static_view(
378 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
379 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
379
380
380
381
381 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
382 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
382 """
383 """
383 Apply outer WSGI middlewares around the application.
384 Apply outer WSGI middlewares around the application.
384
385
385 Part of this has been moved up from the Pylons layer, so that the
386 Part of this has been moved up from the Pylons layer, so that the
386 data is also available if old Pylons code is hit through an already ported
387 data is also available if old Pylons code is hit through an already ported
387 view.
388 view.
388 """
389 """
389 settings = config.registry.settings
390 settings = config.registry.settings
390
391
391 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
392 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
392 pyramid_app = HttpsFixup(pyramid_app, settings)
393 pyramid_app = HttpsFixup(pyramid_app, settings)
393
394
394 # Add RoutesMiddleware to support the pylons compatibility tween during
395 # Add RoutesMiddleware to support the pylons compatibility tween during
395 # migration to pyramid.
396 # migration to pyramid.
396
397
397 # TODO(marcink): remove after migration to pyramid
398 # TODO(marcink): remove after migration to pyramid
398 if hasattr(config.registry, '_pylons_compat_config'):
399 if hasattr(config.registry, '_pylons_compat_config'):
399 routes_map = config.registry._pylons_compat_config['routes.map']
400 routes_map = config.registry._pylons_compat_config['routes.map']
400 pyramid_app = SkippableRoutesMiddleware(
401 pyramid_app = SkippableRoutesMiddleware(
401 pyramid_app, routes_map,
402 pyramid_app, routes_map,
402 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
403 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
403
404
404 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
405 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
405
406
406 if settings['gzip_responses']:
407 if settings['gzip_responses']:
407 pyramid_app = make_gzip_middleware(
408 pyramid_app = make_gzip_middleware(
408 pyramid_app, settings, compress_level=1)
409 pyramid_app, settings, compress_level=1)
409
410
410 # this should be the outer most middleware in the wsgi stack since
411 # this should be the outer most middleware in the wsgi stack since
411 # middleware like Routes make database calls
412 # middleware like Routes make database calls
412 def pyramid_app_with_cleanup(environ, start_response):
413 def pyramid_app_with_cleanup(environ, start_response):
413 try:
414 try:
414 return pyramid_app(environ, start_response)
415 return pyramid_app(environ, start_response)
415 finally:
416 finally:
416 # Dispose current database session and rollback uncommitted
417 # Dispose current database session and rollback uncommitted
417 # transactions.
418 # transactions.
418 meta.Session.remove()
419 meta.Session.remove()
419
420
420 # In a single threaded mode server, on non sqlite db we should have
421 # In a single threaded mode server, on non sqlite db we should have
421 # '0 Current Checked out connections' at the end of a request,
422 # '0 Current Checked out connections' at the end of a request,
422 # if not, then something, somewhere is leaving a connection open
423 # if not, then something, somewhere is leaving a connection open
423 pool = meta.Base.metadata.bind.engine.pool
424 pool = meta.Base.metadata.bind.engine.pool
424 log.debug('sa pool status: %s', pool.status())
425 log.debug('sa pool status: %s', pool.status())
425
426
426 return pyramid_app_with_cleanup
427 return pyramid_app_with_cleanup
427
428
428
429
429 def sanitize_settings_and_apply_defaults(settings):
430 def sanitize_settings_and_apply_defaults(settings):
430 """
431 """
431 Applies settings defaults and does all type conversion.
432 Applies settings defaults and does all type conversion.
432
433
433 We would move all settings parsing and preparation into this place, so that
434 We would move all settings parsing and preparation into this place, so that
434 we have only one place left which deals with this part. The remaining parts
435 we have only one place left which deals with this part. The remaining parts
435 of the application would start to rely fully on well prepared settings.
436 of the application would start to rely fully on well prepared settings.
436
437
437 This piece would later be split up per topic to avoid a big fat monster
438 This piece would later be split up per topic to avoid a big fat monster
438 function.
439 function.
439 """
440 """
440
441
441 settings.setdefault('rhodecode.edition', 'Community Edition')
442 settings.setdefault('rhodecode.edition', 'Community Edition')
442
443
443 if 'mako.default_filters' not in settings:
444 if 'mako.default_filters' not in settings:
444 # set custom default filters if we don't have it defined
445 # set custom default filters if we don't have it defined
445 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
446 settings['mako.imports'] = 'from rhodecode.lib.base import h_filter'
446 settings['mako.default_filters'] = 'h_filter'
447 settings['mako.default_filters'] = 'h_filter'
447
448
448 if 'mako.directories' not in settings:
449 if 'mako.directories' not in settings:
449 mako_directories = settings.setdefault('mako.directories', [
450 mako_directories = settings.setdefault('mako.directories', [
450 # Base templates of the original application
451 # Base templates of the original application
451 'rhodecode:templates',
452 'rhodecode:templates',
452 ])
453 ])
453 log.debug(
454 log.debug(
454 "Using the following Mako template directories: %s",
455 "Using the following Mako template directories: %s",
455 mako_directories)
456 mako_directories)
456
457
457 # Default includes, possible to change as a user
458 # Default includes, possible to change as a user
458 pyramid_includes = settings.setdefault('pyramid.includes', [
459 pyramid_includes = settings.setdefault('pyramid.includes', [
459 'rhodecode.lib.middleware.request_wrapper',
460 'rhodecode.lib.middleware.request_wrapper',
460 ])
461 ])
461 log.debug(
462 log.debug(
462 "Using the following pyramid.includes: %s",
463 "Using the following pyramid.includes: %s",
463 pyramid_includes)
464 pyramid_includes)
464
465
465 # TODO: johbo: Re-think this, usually the call to config.include
466 # TODO: johbo: Re-think this, usually the call to config.include
466 # should allow to pass in a prefix.
467 # should allow to pass in a prefix.
467 settings.setdefault('rhodecode.api.url', '/_admin/api')
468 settings.setdefault('rhodecode.api.url', '/_admin/api')
468
469
469 # Sanitize generic settings.
470 # Sanitize generic settings.
470 _list_setting(settings, 'default_encoding', 'UTF-8')
471 _list_setting(settings, 'default_encoding', 'UTF-8')
471 _bool_setting(settings, 'is_test', 'false')
472 _bool_setting(settings, 'is_test', 'false')
472 _bool_setting(settings, 'gzip_responses', 'false')
473 _bool_setting(settings, 'gzip_responses', 'false')
473
474
474 # Call split out functions that sanitize settings for each topic.
475 # Call split out functions that sanitize settings for each topic.
475 _sanitize_appenlight_settings(settings)
476 _sanitize_appenlight_settings(settings)
476 _sanitize_vcs_settings(settings)
477 _sanitize_vcs_settings(settings)
477
478
478 # configure instance id
479 # configure instance id
479 config_utils.set_instance_id(settings)
480 config_utils.set_instance_id(settings)
480
481
481 return settings
482 return settings
482
483
483
484
484 def _sanitize_appenlight_settings(settings):
485 def _sanitize_appenlight_settings(settings):
485 _bool_setting(settings, 'appenlight', 'false')
486 _bool_setting(settings, 'appenlight', 'false')
486
487
487
488
488 def _sanitize_vcs_settings(settings):
489 def _sanitize_vcs_settings(settings):
489 """
490 """
490 Applies settings defaults and does type conversion for all VCS related
491 Applies settings defaults and does type conversion for all VCS related
491 settings.
492 settings.
492 """
493 """
493 _string_setting(settings, 'vcs.svn.compatible_version', '')
494 _string_setting(settings, 'vcs.svn.compatible_version', '')
494 _string_setting(settings, 'git_rev_filter', '--all')
495 _string_setting(settings, 'git_rev_filter', '--all')
495 _string_setting(settings, 'vcs.hooks.protocol', 'http')
496 _string_setting(settings, 'vcs.hooks.protocol', 'http')
496 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
497 _string_setting(settings, 'vcs.scm_app_implementation', 'http')
497 _string_setting(settings, 'vcs.server', '')
498 _string_setting(settings, 'vcs.server', '')
498 _string_setting(settings, 'vcs.server.log_level', 'debug')
499 _string_setting(settings, 'vcs.server.log_level', 'debug')
499 _string_setting(settings, 'vcs.server.protocol', 'http')
500 _string_setting(settings, 'vcs.server.protocol', 'http')
500 _bool_setting(settings, 'startup.import_repos', 'false')
501 _bool_setting(settings, 'startup.import_repos', 'false')
501 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
502 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
502 _bool_setting(settings, 'vcs.server.enable', 'true')
503 _bool_setting(settings, 'vcs.server.enable', 'true')
503 _bool_setting(settings, 'vcs.start_server', 'false')
504 _bool_setting(settings, 'vcs.start_server', 'false')
504 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
505 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
505 _int_setting(settings, 'vcs.connection_timeout', 3600)
506 _int_setting(settings, 'vcs.connection_timeout', 3600)
506
507
507 # Support legacy values of vcs.scm_app_implementation. Legacy
508 # Support legacy values of vcs.scm_app_implementation. Legacy
508 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
509 # configurations may use 'rhodecode.lib.middleware.utils.scm_app_http'
509 # which is now mapped to 'http'.
510 # which is now mapped to 'http'.
510 scm_app_impl = settings['vcs.scm_app_implementation']
511 scm_app_impl = settings['vcs.scm_app_implementation']
511 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
512 if scm_app_impl == 'rhodecode.lib.middleware.utils.scm_app_http':
512 settings['vcs.scm_app_implementation'] = 'http'
513 settings['vcs.scm_app_implementation'] = 'http'
513
514
514
515
515 def _int_setting(settings, name, default):
516 def _int_setting(settings, name, default):
516 settings[name] = int(settings.get(name, default))
517 settings[name] = int(settings.get(name, default))
517
518
518
519
519 def _bool_setting(settings, name, default):
520 def _bool_setting(settings, name, default):
520 input = settings.get(name, default)
521 input = settings.get(name, default)
521 if isinstance(input, unicode):
522 if isinstance(input, unicode):
522 input = input.encode('utf8')
523 input = input.encode('utf8')
523 settings[name] = asbool(input)
524 settings[name] = asbool(input)
524
525
525
526
526 def _list_setting(settings, name, default):
527 def _list_setting(settings, name, default):
527 raw_value = settings.get(name, default)
528 raw_value = settings.get(name, default)
528
529
529 old_separator = ','
530 old_separator = ','
530 if old_separator in raw_value:
531 if old_separator in raw_value:
531 # If we get a comma separated list, pass it to our own function.
532 # If we get a comma separated list, pass it to our own function.
532 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
533 settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
533 else:
534 else:
534 # Otherwise we assume it uses pyramids space/newline separation.
535 # Otherwise we assume it uses pyramids space/newline separation.
535 settings[name] = aslist(raw_value)
536 settings[name] = aslist(raw_value)
536
537
537
538
538 def _string_setting(settings, name, default, lower=True):
539 def _string_setting(settings, name, default, lower=True):
539 value = settings.get(name, default)
540 value = settings.get(name, default)
540 if lower:
541 if lower:
541 value = value.lower()
542 value = value.lower()
542 settings[name] = value
543 settings[name] = value
General Comments 0
You need to be logged in to leave comments. Login now