##// END OF EJS Templates
db: Move db setup code to seperate function.
johbo -
r121:6b332d07 default
parent child Browse files
Show More
@@ -1,176 +1,192 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 # don't remove this import it does magic for celery
37 # don't remove this import it does magic for celery
38 from rhodecode.lib import celerypylons # noqa
38 from rhodecode.lib import celerypylons # noqa
39
39
40 import rhodecode.lib.app_globals as app_globals
40 import rhodecode.lib.app_globals as app_globals
41
41
42 from rhodecode.config import utils
42 from rhodecode.config import utils
43 from rhodecode.config.routing import make_map
43 from rhodecode.config.routing import make_map
44 from rhodecode.config.jsroutes import generate_jsroutes_content
44 from rhodecode.config.jsroutes import generate_jsroutes_content
45
45
46 from rhodecode.lib import helpers
46 from rhodecode.lib import helpers
47 from rhodecode.lib.auth import set_available_permissions
47 from rhodecode.lib.auth import set_available_permissions
48 from rhodecode.lib.utils import (
48 from rhodecode.lib.utils import (
49 repo2db_mapper, make_db_config, set_rhodecode_config,
49 repo2db_mapper, make_db_config, set_rhodecode_config,
50 load_rcextensions)
50 load_rcextensions)
51 from rhodecode.lib.utils2 import str2bool, aslist
51 from rhodecode.lib.utils2 import str2bool, aslist
52 from rhodecode.lib.vcs import connect_vcs, start_vcs_server
52 from rhodecode.lib.vcs import connect_vcs, start_vcs_server
53 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.scm import ScmModel
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57 def load_environment(global_conf, app_conf, initial=False,
57 def load_environment(global_conf, app_conf, initial=False,
58 test_env=None, test_index=None):
58 test_env=None, test_index=None):
59 """
59 """
60 Configure the Pylons environment via the ``pylons.config``
60 Configure the Pylons environment via the ``pylons.config``
61 object
61 object
62 """
62 """
63 config = PylonsConfig()
63 config = PylonsConfig()
64
64
65
65
66 # Pylons paths
66 # Pylons paths
67 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
67 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
68 paths = {
68 paths = {
69 'root': root,
69 'root': root,
70 'controllers': os.path.join(root, 'controllers'),
70 'controllers': os.path.join(root, 'controllers'),
71 'static_files': os.path.join(root, 'public'),
71 'static_files': os.path.join(root, 'public'),
72 'templates': [os.path.join(root, 'templates')],
72 'templates': [os.path.join(root, 'templates')],
73 }
73 }
74
74
75 # Initialize config with the basic options
75 # Initialize config with the basic options
76 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
76 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
77
77
78 # store some globals into rhodecode
78 # store some globals into rhodecode
79 rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery'))
79 rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery'))
80 rhodecode.CELERY_EAGER = str2bool(
80 rhodecode.CELERY_EAGER = str2bool(
81 config['app_conf'].get('celery.always.eager'))
81 config['app_conf'].get('celery.always.eager'))
82
82
83 config['routes.map'] = make_map(config)
83 config['routes.map'] = make_map(config)
84
84
85 if asbool(config['debug']):
85 if asbool(config['debug']):
86 jsroutes = config['routes.map'].jsroutes()
86 jsroutes = config['routes.map'].jsroutes()
87 jsroutes_file_content = generate_jsroutes_content(jsroutes)
87 jsroutes_file_content = generate_jsroutes_content(jsroutes)
88 jsroutes_file_path = os.path.join(
88 jsroutes_file_path = os.path.join(
89 paths['static_files'], 'js', 'rhodecode', 'routes.js')
89 paths['static_files'], 'js', 'rhodecode', 'routes.js')
90
90
91 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
91 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
92 f.write(jsroutes_file_content)
92 f.write(jsroutes_file_content)
93
93
94 config['pylons.app_globals'] = app_globals.Globals(config)
94 config['pylons.app_globals'] = app_globals.Globals(config)
95 config['pylons.h'] = helpers
95 config['pylons.h'] = helpers
96 rhodecode.CONFIG = config
96 rhodecode.CONFIG = config
97
97
98 load_rcextensions(root_path=config['here'])
98 load_rcextensions(root_path=config['here'])
99
99
100 # Setup cache object as early as possible
100 # Setup cache object as early as possible
101 import pylons
101 import pylons
102 pylons.cache._push_object(config['pylons.app_globals'].cache)
102 pylons.cache._push_object(config['pylons.app_globals'].cache)
103
103
104 # Create the Mako TemplateLookup, with the default auto-escaping
104 # Create the Mako TemplateLookup, with the default auto-escaping
105 config['pylons.app_globals'].mako_lookup = TemplateLookup(
105 config['pylons.app_globals'].mako_lookup = TemplateLookup(
106 directories=paths['templates'],
106 directories=paths['templates'],
107 error_handler=handle_mako_error,
107 error_handler=handle_mako_error,
108 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
108 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
109 input_encoding='utf-8', default_filters=['escape'],
109 input_encoding='utf-8', default_filters=['escape'],
110 imports=['from webhelpers.html import escape'])
110 imports=['from webhelpers.html import escape'])
111
111
112 # sets the c attribute access when don't existing attribute are accessed
112 # sets the c attribute access when don't existing attribute are accessed
113 config['pylons.strict_tmpl_context'] = True
113 config['pylons.strict_tmpl_context'] = True
114
114
115 # Limit backends to "vcs.backends" from configuration
115 # Limit backends to "vcs.backends" from configuration
116 backends = config['vcs.backends'] = aslist(
116 backends = config['vcs.backends'] = aslist(
117 config.get('vcs.backends', 'hg,git'), sep=',')
117 config.get('vcs.backends', 'hg,git'), sep=',')
118 for alias in rhodecode.BACKENDS.keys():
118 for alias in rhodecode.BACKENDS.keys():
119 if alias not in backends:
119 if alias not in backends:
120 del rhodecode.BACKENDS[alias]
120 del rhodecode.BACKENDS[alias]
121 log.info("Enabled backends: %s", backends)
121 log.info("Enabled backends: %s", backends)
122
122
123 # initialize vcs client and optionally run the server if enabled
123 # initialize vcs client and optionally run the server if enabled
124 vcs_server_uri = config.get('vcs.server', '')
124 vcs_server_uri = config.get('vcs.server', '')
125 vcs_server_enabled = str2bool(config.get('vcs.server.enable', 'true'))
125 vcs_server_enabled = str2bool(config.get('vcs.server.enable', 'true'))
126 start_server = (
126 start_server = (
127 str2bool(config.get('vcs.start_server', 'false')) and
127 str2bool(config.get('vcs.start_server', 'false')) and
128 not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0')))
128 not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0')))
129 if vcs_server_enabled and start_server:
129 if vcs_server_enabled and start_server:
130 log.info("Starting vcsserver")
130 log.info("Starting vcsserver")
131 start_vcs_server(server_and_port=vcs_server_uri,
131 start_vcs_server(server_and_port=vcs_server_uri,
132 protocol=utils.get_vcs_server_protocol(config),
132 protocol=utils.get_vcs_server_protocol(config),
133 log_level=config['vcs.server.log_level'])
133 log_level=config['vcs.server.log_level'])
134
134
135 set_available_permissions(config)
135 set_available_permissions(config)
136 db_cfg = make_db_config(clear_session=True)
136 db_cfg = make_db_config(clear_session=True)
137
137
138 repos_path = list(db_cfg.items('paths'))[0][1]
138 repos_path = list(db_cfg.items('paths'))[0][1]
139 config['base_path'] = repos_path
139 config['base_path'] = repos_path
140
140
141 config['vcs.hooks.direct_calls'] = _use_direct_hook_calls(config)
141 config['vcs.hooks.direct_calls'] = _use_direct_hook_calls(config)
142 config['vcs.hooks.protocol'] = _get_vcs_hooks_protocol(config)
142 config['vcs.hooks.protocol'] = _get_vcs_hooks_protocol(config)
143
143
144 # store db config also in main global CONFIG
144 # store db config also in main global CONFIG
145 set_rhodecode_config(config)
145 set_rhodecode_config(config)
146
146
147 # configure instance id
147 # configure instance id
148 utils.set_instance_id(config)
148 utils.set_instance_id(config)
149
149
150 # CONFIGURATION OPTIONS HERE (note: all config options will override
150 # CONFIGURATION OPTIONS HERE (note: all config options will override
151 # any Pylons config options)
151 # any Pylons config options)
152
152
153 # store config reference into our module to skip import magic of pylons
153 # store config reference into our module to skip import magic of pylons
154 rhodecode.CONFIG.update(config)
154 rhodecode.CONFIG.update(config)
155
155
156 utils.configure_pyro4(config)
156 utils.configure_pyro4(config)
157 utils.configure_vcs(config)
157 utils.configure_vcs(config)
158 if vcs_server_enabled:
158 if vcs_server_enabled:
159 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(config))
159 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(config))
160
160
161 import_on_startup = str2bool(config.get('startup.import_repos', False))
161 import_on_startup = str2bool(config.get('startup.import_repos', False))
162 if vcs_server_enabled and import_on_startup:
162 if vcs_server_enabled and import_on_startup:
163 repo2db_mapper(ScmModel().repo_scan(repos_path), remove_obsolete=False)
163 repo2db_mapper(ScmModel().repo_scan(repos_path), remove_obsolete=False)
164 return config
164 return config
165
165
166
166
167 def _use_direct_hook_calls(config):
167 def _use_direct_hook_calls(config):
168 default_direct_hook_calls = 'false'
168 default_direct_hook_calls = 'false'
169 direct_hook_calls = str2bool(
169 direct_hook_calls = str2bool(
170 config.get('vcs.hooks.direct_calls', default_direct_hook_calls))
170 config.get('vcs.hooks.direct_calls', default_direct_hook_calls))
171 return direct_hook_calls
171 return direct_hook_calls
172
172
173
173
174 def _get_vcs_hooks_protocol(config):
174 def _get_vcs_hooks_protocol(config):
175 protocol = config.get('vcs.hooks.protocol', 'pyro4').lower()
175 protocol = config.get('vcs.hooks.protocol', 'pyro4').lower()
176 return protocol
176 return protocol
177
178
179 def load_pyramid_environment(global_config, settings):
180 # Some parts of the code expect a merge of global and app settings.
181 settings_merged = global_config.copy()
182 settings_merged.update(settings)
183
184 # If this is a test run we prepare the test environment like
185 # creating a test database, test search index and test repositories.
186 # This has to be done before the database connection is initialized.
187 if settings['is_test']:
188 rhodecode.is_test = True
189 utils.initialize_test_environment(settings_merged)
190
191 # Initialize the database connection.
192 utils.initialize_database(settings_merged)
@@ -1,326 +1,315 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
25
26 from paste.registry import RegistryManager
26 from paste.registry import RegistryManager
27 from paste.gzipper import make_gzip_middleware
27 from paste.gzipper import make_gzip_middleware
28 from pylons.middleware import ErrorHandler, StatusCodeRedirect
28 from pylons.middleware import ErrorHandler, StatusCodeRedirect
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.static import static_view
32 from pyramid.static import static_view
33 from pyramid.settings import asbool, aslist
33 from pyramid.settings import asbool, aslist
34 from pyramid.wsgi import wsgiapp
34 from pyramid.wsgi import wsgiapp
35 from routes.middleware import RoutesMiddleware
35 from routes.middleware import RoutesMiddleware
36 import routes.util
36 import routes.util
37
37
38 import rhodecode
38 import rhodecode
39 from rhodecode.config import patches, utils
39 from rhodecode.config import patches
40 from rhodecode.config.environment import load_environment
40 from rhodecode.config.environment import (
41 load_environment, load_pyramid_environment)
41 from rhodecode.lib.middleware import csrf
42 from rhodecode.lib.middleware import csrf
42 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
43 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
43 from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
44 from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
44 from rhodecode.lib.middleware.https_fixup import HttpsFixup
45 from rhodecode.lib.middleware.https_fixup import HttpsFixup
45 from rhodecode.lib.middleware.vcs import VCSMiddleware
46 from rhodecode.lib.middleware.vcs import VCSMiddleware
46 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
47 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
47
48
48
49
49 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
50
51
51
52
52 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
53 def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
53 """Create a Pylons WSGI application and return it
54 """Create a Pylons WSGI application and return it
54
55
55 ``global_conf``
56 ``global_conf``
56 The inherited configuration for this application. Normally from
57 The inherited configuration for this application. Normally from
57 the [DEFAULT] section of the Paste ini file.
58 the [DEFAULT] section of the Paste ini file.
58
59
59 ``full_stack``
60 ``full_stack``
60 Whether or not this application provides a full WSGI stack (by
61 Whether or not this application provides a full WSGI stack (by
61 default, meaning it handles its own exceptions and errors).
62 default, meaning it handles its own exceptions and errors).
62 Disable full_stack when this application is "managed" by
63 Disable full_stack when this application is "managed" by
63 another WSGI middleware.
64 another WSGI middleware.
64
65
65 ``app_conf``
66 ``app_conf``
66 The application's local configuration. Normally specified in
67 The application's local configuration. Normally specified in
67 the [app:<name>] section of the Paste ini file (where <name>
68 the [app:<name>] section of the Paste ini file (where <name>
68 defaults to main).
69 defaults to main).
69
70
70 """
71 """
71 # Apply compatibility patches
72 # Apply compatibility patches
72 patches.kombu_1_5_1_python_2_7_11()
73 patches.kombu_1_5_1_python_2_7_11()
73 patches.inspect_getargspec()
74 patches.inspect_getargspec()
74
75
75 # Configure the Pylons environment
76 # Configure the Pylons environment
76 config = load_environment(global_conf, app_conf)
77 config = load_environment(global_conf, app_conf)
77
78
78 # The Pylons WSGI app
79 # The Pylons WSGI app
79 app = PylonsApp(config=config)
80 app = PylonsApp(config=config)
80 if rhodecode.is_test:
81 if rhodecode.is_test:
81 app = csrf.CSRFDetector(app)
82 app = csrf.CSRFDetector(app)
82
83
83 expected_origin = config.get('expected_origin')
84 expected_origin = config.get('expected_origin')
84 if expected_origin:
85 if expected_origin:
85 # The API can be accessed from other Origins.
86 # The API can be accessed from other Origins.
86 app = csrf.OriginChecker(app, expected_origin,
87 app = csrf.OriginChecker(app, expected_origin,
87 skip_urls=[routes.util.url_for('api')])
88 skip_urls=[routes.util.url_for('api')])
88
89
89 # Add RoutesMiddleware. Currently we have two instances in the stack. This
90 # Add RoutesMiddleware. Currently we have two instances in the stack. This
90 # is the lower one to make the StatusCodeRedirect middleware happy.
91 # is the lower one to make the StatusCodeRedirect middleware happy.
91 # TODO: johbo: This is not optimal, search for a better solution.
92 # TODO: johbo: This is not optimal, search for a better solution.
92 app = RoutesMiddleware(app, config['routes.map'])
93 app = RoutesMiddleware(app, config['routes.map'])
93
94
94 # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
95 # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
95 if asbool(config['pdebug']):
96 if asbool(config['pdebug']):
96 from rhodecode.lib.profiler import ProfilingMiddleware
97 from rhodecode.lib.profiler import ProfilingMiddleware
97 app = ProfilingMiddleware(app)
98 app = ProfilingMiddleware(app)
98
99
99 # Protect from VCS Server error related pages when server is not available
100 # Protect from VCS Server error related pages when server is not available
100 vcs_server_enabled = asbool(config.get('vcs.server.enable', 'true'))
101 vcs_server_enabled = asbool(config.get('vcs.server.enable', 'true'))
101 if not vcs_server_enabled:
102 if not vcs_server_enabled:
102 app = DisableVCSPagesWrapper(app)
103 app = DisableVCSPagesWrapper(app)
103
104
104 if asbool(full_stack):
105 if asbool(full_stack):
105
106
106 # Appenlight monitoring and error handler
107 # Appenlight monitoring and error handler
107 app, appenlight_client = wrap_in_appenlight_if_enabled(app, config)
108 app, appenlight_client = wrap_in_appenlight_if_enabled(app, config)
108
109
109 # Handle Python exceptions
110 # Handle Python exceptions
110 app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
111 app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
111
112
112 # we want our low level middleware to get to the request ASAP. We don't
113 # we want our low level middleware to get to the request ASAP. We don't
113 # need any pylons stack middleware in them
114 # need any pylons stack middleware in them
114 app = VCSMiddleware(app, config, appenlight_client)
115 app = VCSMiddleware(app, config, appenlight_client)
115 # Display error documents for 401, 403, 404 status codes (and
116 # Display error documents for 401, 403, 404 status codes (and
116 # 500 when debug is disabled)
117 # 500 when debug is disabled)
117 if asbool(config['debug']):
118 if asbool(config['debug']):
118 app = StatusCodeRedirect(app)
119 app = StatusCodeRedirect(app)
119 else:
120 else:
120 app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
121 app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
121
122
122 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
123 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
123 app = HttpsFixup(app, config)
124 app = HttpsFixup(app, config)
124
125
125 # Establish the Registry for this application
126 # Establish the Registry for this application
126 app = RegistryManager(app)
127 app = RegistryManager(app)
127
128
128 app.config = config
129 app.config = config
129
130
130 return app
131 return app
131
132
132
133
133 def make_pyramid_app(global_config, **settings):
134 def make_pyramid_app(global_config, **settings):
134 """
135 """
135 Constructs the WSGI application based on Pyramid and wraps the Pylons based
136 Constructs the WSGI application based on Pyramid and wraps the Pylons based
136 application.
137 application.
137
138
138 Specials:
139 Specials:
139
140
140 * We migrate from Pylons to Pyramid. While doing this, we keep both
141 * We migrate from Pylons to Pyramid. While doing this, we keep both
141 frameworks functional. This involves moving some WSGI middlewares around
142 frameworks functional. This involves moving some WSGI middlewares around
142 and providing access to some data internals, so that the old code is
143 and providing access to some data internals, so that the old code is
143 still functional.
144 still functional.
144
145
145 * The application can also be integrated like a plugin via the call to
146 * The application can also be integrated like a plugin via the call to
146 `includeme`. This is accompanied with the other utility functions which
147 `includeme`. This is accompanied with the other utility functions which
147 are called. Changing this should be done with great care to not break
148 are called. Changing this should be done with great care to not break
148 cases when these fragments are assembled from another place.
149 cases when these fragments are assembled from another place.
149
150
150 """
151 """
151 # The edition string should be available in pylons too, so we add it here
152 # The edition string should be available in pylons too, so we add it here
152 # before copying the settings.
153 # before copying the settings.
153 settings.setdefault('rhodecode.edition', 'Community Edition')
154 settings.setdefault('rhodecode.edition', 'Community Edition')
154
155
155 # As long as our Pylons application does expect "unprepared" settings, make
156 # As long as our Pylons application does expect "unprepared" settings, make
156 # sure that we keep an unmodified copy. This avoids unintentional change of
157 # sure that we keep an unmodified copy. This avoids unintentional change of
157 # behavior in the old application.
158 # behavior in the old application.
158 settings_pylons = settings.copy()
159 settings_pylons = settings.copy()
159
160
160 # Some parts of the code expect a merge of global and app settings.
161 settings_merged = global_config.copy()
162 settings_merged.update(settings)
163
164 sanitize_settings_and_apply_defaults(settings)
161 sanitize_settings_and_apply_defaults(settings)
165 config = Configurator(settings=settings)
162 config = Configurator(settings=settings)
166 add_pylons_compat_data(config.registry, global_config, settings_pylons)
163 add_pylons_compat_data(config.registry, global_config, settings_pylons)
167
164
168 # If this is a test run we prepare the test environment like
165 load_pyramid_environment(global_config, settings)
169 # creating a test database, test search index and test repositories.
170 # This has to be done before the database connection is initialized.
171 if settings['is_test']:
172 rhodecode.is_test = True
173 utils.initialize_test_environment(settings_merged)
174
175 # Initialize the database connection.
176 utils.initialize_database(settings_merged)
177
166
178 includeme(config)
167 includeme(config)
179 includeme_last(config)
168 includeme_last(config)
180 pyramid_app = config.make_wsgi_app()
169 pyramid_app = config.make_wsgi_app()
181 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
170 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
182 return pyramid_app
171 return pyramid_app
183
172
184
173
185 def add_pylons_compat_data(registry, global_config, settings):
174 def add_pylons_compat_data(registry, global_config, settings):
186 """
175 """
187 Attach data to the registry to support the Pylons integration.
176 Attach data to the registry to support the Pylons integration.
188 """
177 """
189 registry._pylons_compat_global_config = global_config
178 registry._pylons_compat_global_config = global_config
190 registry._pylons_compat_settings = settings
179 registry._pylons_compat_settings = settings
191
180
192
181
193 def includeme(config):
182 def includeme(config):
194 settings = config.registry.settings
183 settings = config.registry.settings
195
184
196 # Includes which are required. The application would fail without them.
185 # Includes which are required. The application would fail without them.
197 config.include('pyramid_mako')
186 config.include('pyramid_mako')
198 config.include('pyramid_beaker')
187 config.include('pyramid_beaker')
199 config.include('rhodecode.authentication')
188 config.include('rhodecode.authentication')
200 config.include('rhodecode.login')
189 config.include('rhodecode.login')
201 config.include('rhodecode.tweens')
190 config.include('rhodecode.tweens')
202 config.include('rhodecode.api')
191 config.include('rhodecode.api')
203
192
204 # Set the authorization policy.
193 # Set the authorization policy.
205 authz_policy = ACLAuthorizationPolicy()
194 authz_policy = ACLAuthorizationPolicy()
206 config.set_authorization_policy(authz_policy)
195 config.set_authorization_policy(authz_policy)
207
196
208 # Set the default renderer for HTML templates to mako.
197 # Set the default renderer for HTML templates to mako.
209 config.add_mako_renderer('.html')
198 config.add_mako_renderer('.html')
210
199
211 # plugin information
200 # plugin information
212 config.registry.rhodecode_plugins = {}
201 config.registry.rhodecode_plugins = {}
213
202
214 config.add_directive(
203 config.add_directive(
215 'register_rhodecode_plugin', register_rhodecode_plugin)
204 'register_rhodecode_plugin', register_rhodecode_plugin)
216 # include RhodeCode plugins
205 # include RhodeCode plugins
217 includes = aslist(settings.get('rhodecode.includes', []))
206 includes = aslist(settings.get('rhodecode.includes', []))
218 for inc in includes:
207 for inc in includes:
219 config.include(inc)
208 config.include(inc)
220
209
221 # This is the glue which allows us to migrate in chunks. By registering the
210 # This is the glue which allows us to migrate in chunks. By registering the
222 # pylons based application as the "Not Found" view in Pyramid, we will
211 # pylons based application as the "Not Found" view in Pyramid, we will
223 # fallback to the old application each time the new one does not yet know
212 # fallback to the old application each time the new one does not yet know
224 # how to handle a request.
213 # how to handle a request.
225 pylons_app = make_app(
214 pylons_app = make_app(
226 config.registry._pylons_compat_global_config,
215 config.registry._pylons_compat_global_config,
227 **config.registry._pylons_compat_settings)
216 **config.registry._pylons_compat_settings)
228 config.registry._pylons_compat_config = pylons_app.config
217 config.registry._pylons_compat_config = pylons_app.config
229 pylons_app_as_view = wsgiapp(pylons_app)
218 pylons_app_as_view = wsgiapp(pylons_app)
230 config.add_notfound_view(pylons_app_as_view)
219 config.add_notfound_view(pylons_app_as_view)
231
220
232
221
233 def includeme_last(config):
222 def includeme_last(config):
234 """
223 """
235 The static file catchall needs to be last in the view configuration.
224 The static file catchall needs to be last in the view configuration.
236 """
225 """
237 settings = config.registry.settings
226 settings = config.registry.settings
238
227
239 # Note: johbo: I would prefer to register a prefix for static files at some
228 # Note: johbo: I would prefer to register a prefix for static files at some
240 # point, e.g. move them under '_static/'. This would fully avoid that we
229 # point, e.g. move them under '_static/'. This would fully avoid that we
241 # can have name clashes with a repository name. Imaging someone calling his
230 # can have name clashes with a repository name. Imaging someone calling his
242 # repo "css" ;-) Also having an external web server to serve out the static
231 # repo "css" ;-) Also having an external web server to serve out the static
243 # files seems to be easier to set up if they have a common prefix.
232 # files seems to be easier to set up if they have a common prefix.
244 #
233 #
245 # Example: config.add_static_view('_static', path='rhodecode:public')
234 # Example: config.add_static_view('_static', path='rhodecode:public')
246 #
235 #
247 # It might be an option to register both paths for a while and then migrate
236 # It might be an option to register both paths for a while and then migrate
248 # over to the new location.
237 # over to the new location.
249
238
250 # Serving static files with a catchall.
239 # Serving static files with a catchall.
251 if settings['static_files']:
240 if settings['static_files']:
252 config.add_route('catchall_static', '/*subpath')
241 config.add_route('catchall_static', '/*subpath')
253 config.add_view(
242 config.add_view(
254 static_view('rhodecode:public'), route_name='catchall_static')
243 static_view('rhodecode:public'), route_name='catchall_static')
255
244
256
245
257 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
246 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
258 """
247 """
259 Apply outer WSGI middlewares around the application.
248 Apply outer WSGI middlewares around the application.
260
249
261 Part of this has been moved up from the Pylons layer, so that the
250 Part of this has been moved up from the Pylons layer, so that the
262 data is also available if old Pylons code is hit through an already ported
251 data is also available if old Pylons code is hit through an already ported
263 view.
252 view.
264 """
253 """
265 settings = config.registry.settings
254 settings = config.registry.settings
266
255
267 # Add RoutesMiddleware. Currently we have two instances in the stack. This
256 # Add RoutesMiddleware. Currently we have two instances in the stack. This
268 # is the upper one to support the pylons compatibility tween during
257 # is the upper one to support the pylons compatibility tween during
269 # migration to pyramid.
258 # migration to pyramid.
270 pyramid_app = RoutesMiddleware(
259 pyramid_app = RoutesMiddleware(
271 pyramid_app, config.registry._pylons_compat_config['routes.map'])
260 pyramid_app, config.registry._pylons_compat_config['routes.map'])
272
261
273 # TODO: johbo: Don't really see why we enable the gzip middleware when
262 # TODO: johbo: Don't really see why we enable the gzip middleware when
274 # serving static files, might be something that should have its own setting
263 # serving static files, might be something that should have its own setting
275 # as well?
264 # as well?
276 if settings['static_files']:
265 if settings['static_files']:
277 pyramid_app = make_gzip_middleware(
266 pyramid_app = make_gzip_middleware(
278 pyramid_app, settings, compress_level=1)
267 pyramid_app, settings, compress_level=1)
279
268
280 return pyramid_app
269 return pyramid_app
281
270
282
271
283 def sanitize_settings_and_apply_defaults(settings):
272 def sanitize_settings_and_apply_defaults(settings):
284 """
273 """
285 Applies settings defaults and does all type conversion.
274 Applies settings defaults and does all type conversion.
286
275
287 We would move all settings parsing and preparation into this place, so that
276 We would move all settings parsing and preparation into this place, so that
288 we have only one place left which deals with this part. The remaining parts
277 we have only one place left which deals with this part. The remaining parts
289 of the application would start to rely fully on well prepared settings.
278 of the application would start to rely fully on well prepared settings.
290
279
291 This piece would later be split up per topic to avoid a big fat monster
280 This piece would later be split up per topic to avoid a big fat monster
292 function.
281 function.
293 """
282 """
294
283
295 # Pyramid's mako renderer has to search in the templates folder so that the
284 # Pyramid's mako renderer has to search in the templates folder so that the
296 # old templates still work. Ported and new templates are expected to use
285 # old templates still work. Ported and new templates are expected to use
297 # real asset specifications for the includes.
286 # real asset specifications for the includes.
298 mako_directories = settings.setdefault('mako.directories', [
287 mako_directories = settings.setdefault('mako.directories', [
299 # Base templates of the original Pylons application
288 # Base templates of the original Pylons application
300 'rhodecode:templates',
289 'rhodecode:templates',
301 ])
290 ])
302 log.debug(
291 log.debug(
303 "Using the following Mako template directories: %s",
292 "Using the following Mako template directories: %s",
304 mako_directories)
293 mako_directories)
305
294
306 # Default includes, possible to change as a user
295 # Default includes, possible to change as a user
307 pyramid_includes = settings.setdefault('pyramid.includes', [
296 pyramid_includes = settings.setdefault('pyramid.includes', [
308 'rhodecode.lib.middleware.request_wrapper',
297 'rhodecode.lib.middleware.request_wrapper',
309 ])
298 ])
310 log.debug(
299 log.debug(
311 "Using the following pyramid.includes: %s",
300 "Using the following pyramid.includes: %s",
312 pyramid_includes)
301 pyramid_includes)
313
302
314 # TODO: johbo: Re-think this, usually the call to config.include
303 # TODO: johbo: Re-think this, usually the call to config.include
315 # should allow to pass in a prefix.
304 # should allow to pass in a prefix.
316 settings.setdefault('rhodecode.api.url', '/_admin/api')
305 settings.setdefault('rhodecode.api.url', '/_admin/api')
317
306
318 _bool_setting(settings, 'vcs.server.enable', 'true')
307 _bool_setting(settings, 'vcs.server.enable', 'true')
319 _bool_setting(settings, 'static_files', 'true')
308 _bool_setting(settings, 'static_files', 'true')
320 _bool_setting(settings, 'is_test', 'false')
309 _bool_setting(settings, 'is_test', 'false')
321
310
322 return settings
311 return settings
323
312
324
313
325 def _bool_setting(settings, name, default):
314 def _bool_setting(settings, name, default):
326 settings[name] = asbool(settings.get(name, default))
315 settings[name] = asbool(settings.get(name, default))
General Comments 0
You need to be logged in to leave comments. Login now