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