##// END OF EJS Templates
core: use proper event to bootstrap pylons env....
marcink -
r1309:8a946991 default
parent child Browse files
Show More
@@ -1,166 +1,213 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import logging
22 import logging
23 import pylons
23 import pylons
24 import Queue
24 import Queue
25 import subprocess32
25 import subprocess32
26
26
27 from pyramid.i18n import get_localizer
27 from pyramid.i18n import get_localizer
28 from pyramid.threadlocal import get_current_request
28 from pyramid.threadlocal import get_current_request
29 from threading import Thread
29 from threading import Thread
30
30
31 from rhodecode.translation import _ as tsf
31 from rhodecode.translation import _ as tsf
32
32
33 import rhodecode
34
35 from pylons.i18n.translation import _get_translator
36 from pylons.util import ContextObj
37 from routes.util import URLGenerator
38
39 from rhodecode.lib.base import attach_context_attributes, get_auth_user
40
33 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
34
42
35
43
36 def add_renderer_globals(event):
44 def add_renderer_globals(event):
37 # Put pylons stuff into the context. This will be removed as soon as
45 # Put pylons stuff into the context. This will be removed as soon as
38 # migration to pyramid is finished.
46 # migration to pyramid is finished.
39 conf = pylons.config._current_obj()
47 conf = pylons.config._current_obj()
40 event['h'] = conf.get('pylons.h')
48 event['h'] = conf.get('pylons.h')
41 event['c'] = pylons.tmpl_context
49 event['c'] = pylons.tmpl_context
42 event['url'] = pylons.url
50 event['url'] = pylons.url
43
51
44 # TODO: When executed in pyramid view context the request is not available
52 # TODO: When executed in pyramid view context the request is not available
45 # in the event. Find a better solution to get the request.
53 # in the event. Find a better solution to get the request.
46 request = event['request'] or get_current_request()
54 request = event['request'] or get_current_request()
47
55
48 # Add Pyramid translation as '_' to context
56 # Add Pyramid translation as '_' to context
49 event['_'] = request.translate
57 event['_'] = request.translate
50 event['_ungettext'] = request.plularize
58 event['_ungettext'] = request.plularize
51
59
52
60
53 def add_localizer(event):
61 def add_localizer(event):
54 request = event.request
62 request = event.request
55 localizer = get_localizer(request)
63 localizer = get_localizer(request)
56
64
57 def auto_translate(*args, **kwargs):
65 def auto_translate(*args, **kwargs):
58 return localizer.translate(tsf(*args, **kwargs))
66 return localizer.translate(tsf(*args, **kwargs))
59
67
60 request.localizer = localizer
68 request.localizer = localizer
61 request.translate = auto_translate
69 request.translate = auto_translate
62 request.plularize = localizer.pluralize
70 request.plularize = localizer.pluralize
63
71
64
72
65 def set_user_lang(event):
73 def set_user_lang(event):
66 cur_user = getattr(event.request, 'user', None)
74 request = event.request
75 cur_user = getattr(request, 'user', None)
67
76
68 if cur_user:
77 if cur_user:
69 user_lang = cur_user.get_instance().user_data.get('language')
78 user_lang = cur_user.get_instance().user_data.get('language')
70 if user_lang:
79 if user_lang:
71 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
80 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
72 event.request._LOCALE_ = user_lang
81 event.request._LOCALE_ = user_lang
73
82
74
83
84 def add_pylons_context(event):
85 request = event.request
86
87 config = rhodecode.CONFIG
88 environ = request.environ
89 session = request.session
90
91 if hasattr(request, 'vcs_call'):
92 # skip vcs calls
93 return
94
95 # Setup pylons globals.
96 pylons.config._push_object(config)
97 pylons.request._push_object(request)
98 pylons.session._push_object(session)
99 pylons.translator._push_object(_get_translator(config.get('lang')))
100
101 pylons.url._push_object(URLGenerator(config['routes.map'], environ))
102 session_key = (
103 config['pylons.environ_config'].get('session', 'beaker.session'))
104 environ[session_key] = session
105
106 if hasattr(request, 'rpc_method'):
107 # skip api calls
108 return
109
110 # Get the rhodecode auth user object and make it available.
111 auth_user = get_auth_user(environ)
112 request.user = auth_user
113 environ['rc_auth_user'] = auth_user
114
115 # Setup the pylons context object ('c')
116 context = ContextObj()
117 context.rhodecode_user = auth_user
118 attach_context_attributes(context, request)
119 pylons.tmpl_context._push_object(context)
120
121
75 def scan_repositories_if_enabled(event):
122 def scan_repositories_if_enabled(event):
76 """
123 """
77 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
124 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
78 does a repository scan if enabled in the settings.
125 does a repository scan if enabled in the settings.
79 """
126 """
80 from rhodecode.model.scm import ScmModel
127 from rhodecode.model.scm import ScmModel
81 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
128 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
82 settings = event.app.registry.settings
129 settings = event.app.registry.settings
83 vcs_server_enabled = settings['vcs.server.enable']
130 vcs_server_enabled = settings['vcs.server.enable']
84 import_on_startup = settings['startup.import_repos']
131 import_on_startup = settings['startup.import_repos']
85 if vcs_server_enabled and import_on_startup:
132 if vcs_server_enabled and import_on_startup:
86 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
133 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
87 repo2db_mapper(repositories, remove_obsolete=False)
134 repo2db_mapper(repositories, remove_obsolete=False)
88
135
89
136
90 class Subscriber(object):
137 class Subscriber(object):
91 """
138 """
92 Base class for subscribers to the pyramid event system.
139 Base class for subscribers to the pyramid event system.
93 """
140 """
94 def __call__(self, event):
141 def __call__(self, event):
95 self.run(event)
142 self.run(event)
96
143
97 def run(self, event):
144 def run(self, event):
98 raise NotImplementedError('Subclass has to implement this.')
145 raise NotImplementedError('Subclass has to implement this.')
99
146
100
147
101 class AsyncSubscriber(Subscriber):
148 class AsyncSubscriber(Subscriber):
102 """
149 """
103 Subscriber that handles the execution of events in a separate task to not
150 Subscriber that handles the execution of events in a separate task to not
104 block the execution of the code which triggers the event. It puts the
151 block the execution of the code which triggers the event. It puts the
105 received events into a queue from which the worker process takes them in
152 received events into a queue from which the worker process takes them in
106 order.
153 order.
107 """
154 """
108 def __init__(self):
155 def __init__(self):
109 self._stop = False
156 self._stop = False
110 self._eventq = Queue.Queue()
157 self._eventq = Queue.Queue()
111 self._worker = self.create_worker()
158 self._worker = self.create_worker()
112 self._worker.start()
159 self._worker.start()
113
160
114 def __call__(self, event):
161 def __call__(self, event):
115 self._eventq.put(event)
162 self._eventq.put(event)
116
163
117 def create_worker(self):
164 def create_worker(self):
118 worker = Thread(target=self.do_work)
165 worker = Thread(target=self.do_work)
119 worker.daemon = True
166 worker.daemon = True
120 return worker
167 return worker
121
168
122 def stop_worker(self):
169 def stop_worker(self):
123 self._stop = False
170 self._stop = False
124 self._eventq.put(None)
171 self._eventq.put(None)
125 self._worker.join()
172 self._worker.join()
126
173
127 def do_work(self):
174 def do_work(self):
128 while not self._stop:
175 while not self._stop:
129 event = self._eventq.get()
176 event = self._eventq.get()
130 if event is not None:
177 if event is not None:
131 self.run(event)
178 self.run(event)
132
179
133
180
134 class AsyncSubprocessSubscriber(AsyncSubscriber):
181 class AsyncSubprocessSubscriber(AsyncSubscriber):
135 """
182 """
136 Subscriber that uses the subprocess32 module to execute a command if an
183 Subscriber that uses the subprocess32 module to execute a command if an
137 event is received. Events are handled asynchronously.
184 event is received. Events are handled asynchronously.
138 """
185 """
139
186
140 def __init__(self, cmd, timeout=None):
187 def __init__(self, cmd, timeout=None):
141 super(AsyncSubprocessSubscriber, self).__init__()
188 super(AsyncSubprocessSubscriber, self).__init__()
142 self._cmd = cmd
189 self._cmd = cmd
143 self._timeout = timeout
190 self._timeout = timeout
144
191
145 def run(self, event):
192 def run(self, event):
146 cmd = self._cmd
193 cmd = self._cmd
147 timeout = self._timeout
194 timeout = self._timeout
148 log.debug('Executing command %s.', cmd)
195 log.debug('Executing command %s.', cmd)
149
196
150 try:
197 try:
151 output = subprocess32.check_output(
198 output = subprocess32.check_output(
152 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
199 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
153 log.debug('Command finished %s', cmd)
200 log.debug('Command finished %s', cmd)
154 if output:
201 if output:
155 log.debug('Command output: %s', output)
202 log.debug('Command output: %s', output)
156 except subprocess32.TimeoutExpired as e:
203 except subprocess32.TimeoutExpired as e:
157 log.exception('Timeout while executing command.')
204 log.exception('Timeout while executing command.')
158 if e.output:
205 if e.output:
159 log.error('Command output: %s', e.output)
206 log.error('Command output: %s', e.output)
160 except subprocess32.CalledProcessError as e:
207 except subprocess32.CalledProcessError as e:
161 log.exception('Error while executing command.')
208 log.exception('Error while executing command.')
162 if e.output:
209 if e.output:
163 log.error('Command output: %s', e.output)
210 log.error('Command output: %s', e.output)
164 except:
211 except:
165 log.exception(
212 log.exception(
166 'Exception while executing command %s.', cmd)
213 'Exception while executing command %s.', cmd)
@@ -1,98 +1,66 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import logging
22 import logging
23 import pylons
24 import rhodecode
25
23
26 from pylons.i18n.translation import _get_translator
27 from pylons.util import ContextObj
28 from routes.util import URLGenerator
29
30 from rhodecode.lib.base import attach_context_attributes, get_auth_user
31 from rhodecode.lib.middleware.vcs import (
24 from rhodecode.lib.middleware.vcs import (
32 detect_vcs_request, VCS_TYPE_KEY, VCS_TYPE_SKIP)
25 detect_vcs_request, VCS_TYPE_KEY, VCS_TYPE_SKIP)
33 from rhodecode.model import meta
34
26
35
27
36 log = logging.getLogger(__name__)
28 log = logging.getLogger(__name__)
37
29
38
30
39 def pylons_compatibility_tween_factory(handler, registry):
31 def vcs_detection_tween_factory(handler, registry):
40
32
41 def pylons_compatibility_tween(request):
33 def vcs_detection_tween(request):
42 """
34 """
43 While migrating from pylons to pyramid we need to call some pylons code
35 Do detection of vcs type, and save results for other layers to re-use
44 from pyramid. For example while rendering an old template that uses the
36 this information
45 'c' or 'h' objects. This tween sets up the needed pylons globals.
46 """
37 """
47 config = rhodecode.CONFIG
48 environ = request.environ
49 session = request.session
50
38
51 vcs_handler = detect_vcs_request(
39 vcs_handler = detect_vcs_request(
52 request.environ, request.registry.settings.get('vcs.backends'))
40 request.environ, request.registry.settings.get('vcs.backends'))
53
41
54 if vcs_handler:
42 if vcs_handler:
55 # save detected VCS type for later re-use
43 # save detected VCS type for later re-use
56 request.environ[VCS_TYPE_KEY] = vcs_handler.SCM
44 request.environ[VCS_TYPE_KEY] = vcs_handler.SCM
45 request.vcs_call = vcs_handler.SCM
57 return handler(request)
46 return handler(request)
58
47
59 # mark that we didn't detect an VCS, and we can skip detection later on
48 # mark that we didn't detect an VCS, and we can skip detection later on
60 request.environ[VCS_TYPE_KEY] = VCS_TYPE_SKIP
49 request.environ[VCS_TYPE_KEY] = VCS_TYPE_SKIP
61
50
62 # Setup pylons globals.
63 pylons.config._push_object(config)
64 pylons.request._push_object(request)
65 pylons.session._push_object(session)
66
67 session_key = (
68 config['pylons.environ_config'].get('session', 'beaker.session'))
69 environ[session_key] = session
70 pylons.url._push_object(URLGenerator(config['routes.map'], environ))
71
72 # TODO: Maybe we should use the language from pyramid.
73 translator = _get_translator(config.get('lang'))
74 pylons.translator._push_object(translator)
75
76 # Get the rhodecode auth user object and make it available.
77 auth_user = get_auth_user(environ)
78 request.user = auth_user
79 environ['rc_auth_user'] = auth_user
80
81 # Setup the pylons context object ('c')
82 context = ContextObj()
83 context.rhodecode_user = auth_user
84 attach_context_attributes(context, request)
85 pylons.tmpl_context._push_object(context)
86 return handler(request)
51 return handler(request)
87
52
88 return pylons_compatibility_tween
53 return vcs_detection_tween
89
54
90
55
91 def includeme(config):
56 def includeme(config):
92 config.add_subscriber('rhodecode.subscribers.add_renderer_globals',
57 config.add_subscriber('rhodecode.subscribers.add_renderer_globals',
93 'pyramid.events.BeforeRender')
58 'pyramid.events.BeforeRender')
94 config.add_subscriber('rhodecode.subscribers.set_user_lang',
59 config.add_subscriber('rhodecode.subscribers.set_user_lang',
95 'pyramid.events.NewRequest')
60 'pyramid.events.NewRequest')
96 config.add_subscriber('rhodecode.subscribers.add_localizer',
61 config.add_subscriber('rhodecode.subscribers.add_localizer',
97 'pyramid.events.NewRequest')
62 'pyramid.events.NewRequest')
98 config.add_tween('rhodecode.tweens.pylons_compatibility_tween_factory')
63 config.add_subscriber('rhodecode.subscribers.add_pylons_context',
64 'pyramid.events.ContextFound')
65
66 config.add_tween('rhodecode.tweens.vcs_detection_tween_factory')
General Comments 0
You need to be logged in to leave comments. Login now