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