##// END OF EJS Templates
subscribers: use shlex in the async-subscriber directly
milka -
r4582:5c8aeb25 stable
parent child Browse files
Show More
@@ -1,90 +1,90 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2020 RhodeCode GmbH
3 # Copyright (C) 2016-2020 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 import os
20 import os
21 import logging
21 import logging
22 import shlex
22 import shlex
23 from pyramid import compat
23 from pyramid import compat
24
24
25 # Do not use `from rhodecode import events` here, it will be overridden by the
25 # Do not use `from rhodecode import events` here, it will be overridden by the
26 # events module in this package due to pythons import mechanism.
26 # events module in this package due to pythons import mechanism.
27 from rhodecode.events import RepoGroupEvent
27 from rhodecode.events import RepoGroupEvent
28 from rhodecode.subscribers import AsyncSubprocessSubscriber
28 from rhodecode.subscribers import AsyncSubprocessSubscriber
29 from rhodecode.config.middleware import (
29 from rhodecode.config.middleware import (
30 _bool_setting, _string_setting, _int_setting)
30 _bool_setting, _string_setting, _int_setting)
31
31
32 from .events import ModDavSvnConfigChange
32 from .events import ModDavSvnConfigChange
33 from .subscribers import generate_config_subscriber
33 from .subscribers import generate_config_subscriber
34 from . import config_keys
34 from . import config_keys
35
35
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 def includeme(config):
40 def includeme(config):
41 settings = config.registry.settings
41 settings = config.registry.settings
42 _sanitize_settings_and_apply_defaults(settings)
42 _sanitize_settings_and_apply_defaults(settings)
43
43
44 if settings[config_keys.generate_config]:
44 if settings[config_keys.generate_config]:
45 # Add subscriber to generate the Apache mod dav svn configuration on
45 # Add subscriber to generate the Apache mod dav svn configuration on
46 # repository group events.
46 # repository group events.
47 config.add_subscriber(generate_config_subscriber, RepoGroupEvent)
47 config.add_subscriber(generate_config_subscriber, RepoGroupEvent)
48
48
49 # If a reload command is set add a subscriber to execute it on
49 # If a reload command is set add a subscriber to execute it on
50 # configuration changes.
50 # configuration changes.
51 reload_cmd = shlex.split(settings[config_keys.reload_command])
51 reload_cmd = settings[config_keys.reload_command]
52 if reload_cmd:
52 if reload_cmd:
53 reload_timeout = settings[config_keys.reload_timeout] or None
53 reload_timeout = settings[config_keys.reload_timeout] or None
54 reload_subscriber = AsyncSubprocessSubscriber(
54 reload_subscriber = AsyncSubprocessSubscriber(
55 cmd=reload_cmd, timeout=reload_timeout)
55 cmd=reload_cmd, timeout=reload_timeout)
56 config.add_subscriber(reload_subscriber, ModDavSvnConfigChange)
56 config.add_subscriber(reload_subscriber, ModDavSvnConfigChange)
57
57
58
58
59 def _sanitize_settings_and_apply_defaults(settings):
59 def _sanitize_settings_and_apply_defaults(settings):
60 """
60 """
61 Set defaults, convert to python types and validate settings.
61 Set defaults, convert to python types and validate settings.
62 """
62 """
63 _bool_setting(settings, config_keys.generate_config, 'false')
63 _bool_setting(settings, config_keys.generate_config, 'false')
64 _bool_setting(settings, config_keys.list_parent_path, 'true')
64 _bool_setting(settings, config_keys.list_parent_path, 'true')
65 _int_setting(settings, config_keys.reload_timeout, 10)
65 _int_setting(settings, config_keys.reload_timeout, 10)
66 _string_setting(settings, config_keys.config_file_path, '', lower=False)
66 _string_setting(settings, config_keys.config_file_path, '', lower=False)
67 _string_setting(settings, config_keys.location_root, '/', lower=False)
67 _string_setting(settings, config_keys.location_root, '/', lower=False)
68 _string_setting(settings, config_keys.reload_command, '', lower=False)
68 _string_setting(settings, config_keys.reload_command, '', lower=False)
69 _string_setting(settings, config_keys.template, '', lower=False)
69 _string_setting(settings, config_keys.template, '', lower=False)
70
70
71 # Convert negative timeout values to zero.
71 # Convert negative timeout values to zero.
72 if settings[config_keys.reload_timeout] < 0:
72 if settings[config_keys.reload_timeout] < 0:
73 settings[config_keys.reload_timeout] = 0
73 settings[config_keys.reload_timeout] = 0
74
74
75 # Append path separator to location root.
75 # Append path separator to location root.
76 settings[config_keys.location_root] = _append_path_sep(
76 settings[config_keys.location_root] = _append_path_sep(
77 settings[config_keys.location_root])
77 settings[config_keys.location_root])
78
78
79 # Validate settings.
79 # Validate settings.
80 if settings[config_keys.generate_config]:
80 if settings[config_keys.generate_config]:
81 assert len(settings[config_keys.config_file_path]) > 0
81 assert len(settings[config_keys.config_file_path]) > 0
82
82
83
83
84 def _append_path_sep(path):
84 def _append_path_sep(path):
85 """
85 """
86 Append the path separator if missing.
86 Append the path separator if missing.
87 """
87 """
88 if isinstance(path, compat.string_types) and not path.endswith(os.path.sep):
88 if isinstance(path, compat.string_types) and not path.endswith(os.path.sep):
89 path += os.path.sep
89 path += os.path.sep
90 return path
90 return path
@@ -1,389 +1,397 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2020 RhodeCode GmbH
3 # Copyright (C) 2010-2020 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 import io
20 import io
21 import shlex
22
21 import math
23 import math
22 import re
24 import re
23 import os
25 import os
24 import datetime
26 import datetime
25 import logging
27 import logging
26 import Queue
28 import Queue
27 import subprocess32
29 import subprocess32
28
30
29
31
30 from dateutil.parser import parse
32 from dateutil.parser import parse
31 from pyramid.threadlocal import get_current_request
33 from pyramid.threadlocal import get_current_request
32 from pyramid.interfaces import IRoutesMapper
34 from pyramid.interfaces import IRoutesMapper
33 from pyramid.settings import asbool
35 from pyramid.settings import asbool
34 from pyramid.path import AssetResolver
36 from pyramid.path import AssetResolver
35 from threading import Thread
37 from threading import Thread
36
38
37 from rhodecode.translation import _ as tsf
39 from rhodecode.translation import _ as tsf
38 from rhodecode.config.jsroutes import generate_jsroutes_content
40 from rhodecode.config.jsroutes import generate_jsroutes_content
39 from rhodecode.lib import auth
41 from rhodecode.lib import auth
40 from rhodecode.lib.base import get_auth_user
42 from rhodecode.lib.base import get_auth_user
41
43
42 import rhodecode
44 import rhodecode
43
45
44
46
45 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
46
48
47
49
48 def add_renderer_globals(event):
50 def add_renderer_globals(event):
49 from rhodecode.lib import helpers
51 from rhodecode.lib import helpers
50
52
51 # TODO: When executed in pyramid view context the request is not available
53 # TODO: When executed in pyramid view context the request is not available
52 # in the event. Find a better solution to get the request.
54 # in the event. Find a better solution to get the request.
53 request = event['request'] or get_current_request()
55 request = event['request'] or get_current_request()
54
56
55 # Add Pyramid translation as '_' to context
57 # Add Pyramid translation as '_' to context
56 event['_'] = request.translate
58 event['_'] = request.translate
57 event['_ungettext'] = request.plularize
59 event['_ungettext'] = request.plularize
58 event['h'] = helpers
60 event['h'] = helpers
59
61
60
62
61 def add_localizer(event):
63 def add_localizer(event):
62 request = event.request
64 request = event.request
63 localizer = request.localizer
65 localizer = request.localizer
64
66
65 def auto_translate(*args, **kwargs):
67 def auto_translate(*args, **kwargs):
66 return localizer.translate(tsf(*args, **kwargs))
68 return localizer.translate(tsf(*args, **kwargs))
67
69
68 request.translate = auto_translate
70 request.translate = auto_translate
69 request.plularize = localizer.pluralize
71 request.plularize = localizer.pluralize
70
72
71
73
72 def set_user_lang(event):
74 def set_user_lang(event):
73 request = event.request
75 request = event.request
74 cur_user = getattr(request, 'user', None)
76 cur_user = getattr(request, 'user', None)
75
77
76 if cur_user:
78 if cur_user:
77 user_lang = cur_user.get_instance().user_data.get('language')
79 user_lang = cur_user.get_instance().user_data.get('language')
78 if user_lang:
80 if user_lang:
79 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
81 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
80 event.request._LOCALE_ = user_lang
82 event.request._LOCALE_ = user_lang
81
83
82
84
83 def add_request_user_context(event):
85 def add_request_user_context(event):
84 """
86 """
85 Adds auth user into request context
87 Adds auth user into request context
86 """
88 """
87 request = event.request
89 request = event.request
88 # access req_id as soon as possible
90 # access req_id as soon as possible
89 req_id = request.req_id
91 req_id = request.req_id
90
92
91 if hasattr(request, 'vcs_call'):
93 if hasattr(request, 'vcs_call'):
92 # skip vcs calls
94 # skip vcs calls
93 return
95 return
94
96
95 if hasattr(request, 'rpc_method'):
97 if hasattr(request, 'rpc_method'):
96 # skip api calls
98 # skip api calls
97 return
99 return
98
100
99 auth_user, auth_token = get_auth_user(request)
101 auth_user, auth_token = get_auth_user(request)
100 request.user = auth_user
102 request.user = auth_user
101 request.user_auth_token = auth_token
103 request.user_auth_token = auth_token
102 request.environ['rc_auth_user'] = auth_user
104 request.environ['rc_auth_user'] = auth_user
103 request.environ['rc_auth_user_id'] = auth_user.user_id
105 request.environ['rc_auth_user_id'] = auth_user.user_id
104 request.environ['rc_req_id'] = req_id
106 request.environ['rc_req_id'] = req_id
105
107
106
108
107 def scan_repositories_if_enabled(event):
109 def scan_repositories_if_enabled(event):
108 """
110 """
109 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
111 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
110 does a repository scan if enabled in the settings.
112 does a repository scan if enabled in the settings.
111 """
113 """
112 settings = event.app.registry.settings
114 settings = event.app.registry.settings
113 vcs_server_enabled = settings['vcs.server.enable']
115 vcs_server_enabled = settings['vcs.server.enable']
114 import_on_startup = settings['startup.import_repos']
116 import_on_startup = settings['startup.import_repos']
115 if vcs_server_enabled and import_on_startup:
117 if vcs_server_enabled and import_on_startup:
116 from rhodecode.model.scm import ScmModel
118 from rhodecode.model.scm import ScmModel
117 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
119 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
118 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
120 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
119 repo2db_mapper(repositories, remove_obsolete=False)
121 repo2db_mapper(repositories, remove_obsolete=False)
120
122
121
123
122 def write_metadata_if_needed(event):
124 def write_metadata_if_needed(event):
123 """
125 """
124 Writes upgrade metadata
126 Writes upgrade metadata
125 """
127 """
126 import rhodecode
128 import rhodecode
127 from rhodecode.lib import system_info
129 from rhodecode.lib import system_info
128 from rhodecode.lib import ext_json
130 from rhodecode.lib import ext_json
129
131
130 fname = '.rcmetadata.json'
132 fname = '.rcmetadata.json'
131 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
133 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
132 metadata_destination = os.path.join(ini_loc, fname)
134 metadata_destination = os.path.join(ini_loc, fname)
133
135
134 def get_update_age():
136 def get_update_age():
135 now = datetime.datetime.utcnow()
137 now = datetime.datetime.utcnow()
136
138
137 with open(metadata_destination, 'rb') as f:
139 with open(metadata_destination, 'rb') as f:
138 data = ext_json.json.loads(f.read())
140 data = ext_json.json.loads(f.read())
139 if 'created_on' in data:
141 if 'created_on' in data:
140 update_date = parse(data['created_on'])
142 update_date = parse(data['created_on'])
141 diff = now - update_date
143 diff = now - update_date
142 return diff.total_seconds() / 60.0
144 return diff.total_seconds() / 60.0
143
145
144 return 0
146 return 0
145
147
146 def write():
148 def write():
147 configuration = system_info.SysInfo(
149 configuration = system_info.SysInfo(
148 system_info.rhodecode_config)()['value']
150 system_info.rhodecode_config)()['value']
149 license_token = configuration['config']['license_token']
151 license_token = configuration['config']['license_token']
150
152
151 setup = dict(
153 setup = dict(
152 workers=configuration['config']['server:main'].get(
154 workers=configuration['config']['server:main'].get(
153 'workers', '?'),
155 'workers', '?'),
154 worker_type=configuration['config']['server:main'].get(
156 worker_type=configuration['config']['server:main'].get(
155 'worker_class', 'sync'),
157 'worker_class', 'sync'),
156 )
158 )
157 dbinfo = system_info.SysInfo(system_info.database_info)()['value']
159 dbinfo = system_info.SysInfo(system_info.database_info)()['value']
158 del dbinfo['url']
160 del dbinfo['url']
159
161
160 metadata = dict(
162 metadata = dict(
161 desc='upgrade metadata info',
163 desc='upgrade metadata info',
162 license_token=license_token,
164 license_token=license_token,
163 created_on=datetime.datetime.utcnow().isoformat(),
165 created_on=datetime.datetime.utcnow().isoformat(),
164 usage=system_info.SysInfo(system_info.usage_info)()['value'],
166 usage=system_info.SysInfo(system_info.usage_info)()['value'],
165 platform=system_info.SysInfo(system_info.platform_type)()['value'],
167 platform=system_info.SysInfo(system_info.platform_type)()['value'],
166 database=dbinfo,
168 database=dbinfo,
167 cpu=system_info.SysInfo(system_info.cpu)()['value'],
169 cpu=system_info.SysInfo(system_info.cpu)()['value'],
168 memory=system_info.SysInfo(system_info.memory)()['value'],
170 memory=system_info.SysInfo(system_info.memory)()['value'],
169 setup=setup
171 setup=setup
170 )
172 )
171
173
172 with open(metadata_destination, 'wb') as f:
174 with open(metadata_destination, 'wb') as f:
173 f.write(ext_json.json.dumps(metadata))
175 f.write(ext_json.json.dumps(metadata))
174
176
175 settings = event.app.registry.settings
177 settings = event.app.registry.settings
176 if settings.get('metadata.skip'):
178 if settings.get('metadata.skip'):
177 return
179 return
178
180
179 # only write this every 24h, workers restart caused unwanted delays
181 # only write this every 24h, workers restart caused unwanted delays
180 try:
182 try:
181 age_in_min = get_update_age()
183 age_in_min = get_update_age()
182 except Exception:
184 except Exception:
183 age_in_min = 0
185 age_in_min = 0
184
186
185 if age_in_min > 60 * 60 * 24:
187 if age_in_min > 60 * 60 * 24:
186 return
188 return
187
189
188 try:
190 try:
189 write()
191 write()
190 except Exception:
192 except Exception:
191 pass
193 pass
192
194
193
195
194 def write_usage_data(event):
196 def write_usage_data(event):
195 import rhodecode
197 import rhodecode
196 from rhodecode.lib import system_info
198 from rhodecode.lib import system_info
197 from rhodecode.lib import ext_json
199 from rhodecode.lib import ext_json
198
200
199 settings = event.app.registry.settings
201 settings = event.app.registry.settings
200 instance_tag = settings.get('metadata.write_usage_tag')
202 instance_tag = settings.get('metadata.write_usage_tag')
201 if not settings.get('metadata.write_usage'):
203 if not settings.get('metadata.write_usage'):
202 return
204 return
203
205
204 def get_update_age(dest_file):
206 def get_update_age(dest_file):
205 now = datetime.datetime.utcnow()
207 now = datetime.datetime.utcnow()
206
208
207 with open(dest_file, 'rb') as f:
209 with open(dest_file, 'rb') as f:
208 data = ext_json.json.loads(f.read())
210 data = ext_json.json.loads(f.read())
209 if 'created_on' in data:
211 if 'created_on' in data:
210 update_date = parse(data['created_on'])
212 update_date = parse(data['created_on'])
211 diff = now - update_date
213 diff = now - update_date
212 return math.ceil(diff.total_seconds() / 60.0)
214 return math.ceil(diff.total_seconds() / 60.0)
213
215
214 return 0
216 return 0
215
217
216 utc_date = datetime.datetime.utcnow()
218 utc_date = datetime.datetime.utcnow()
217 hour_quarter = int(math.ceil((utc_date.hour + utc_date.minute/60.0) / 6.))
219 hour_quarter = int(math.ceil((utc_date.hour + utc_date.minute/60.0) / 6.))
218 fname = '.rc_usage_{date.year}{date.month:02d}{date.day:02d}_{hour}.json'.format(
220 fname = '.rc_usage_{date.year}{date.month:02d}{date.day:02d}_{hour}.json'.format(
219 date=utc_date, hour=hour_quarter)
221 date=utc_date, hour=hour_quarter)
220 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
222 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
221
223
222 usage_dir = os.path.join(ini_loc, '.rcusage')
224 usage_dir = os.path.join(ini_loc, '.rcusage')
223 if not os.path.isdir(usage_dir):
225 if not os.path.isdir(usage_dir):
224 os.makedirs(usage_dir)
226 os.makedirs(usage_dir)
225 usage_metadata_destination = os.path.join(usage_dir, fname)
227 usage_metadata_destination = os.path.join(usage_dir, fname)
226
228
227 try:
229 try:
228 age_in_min = get_update_age(usage_metadata_destination)
230 age_in_min = get_update_age(usage_metadata_destination)
229 except Exception:
231 except Exception:
230 age_in_min = 0
232 age_in_min = 0
231
233
232 # write every 6th hour
234 # write every 6th hour
233 if age_in_min and age_in_min < 60 * 6:
235 if age_in_min and age_in_min < 60 * 6:
234 log.debug('Usage file created %s minutes ago, skipping (threashold: %s)...',
236 log.debug('Usage file created %s minutes ago, skipping (threashold: %s)...',
235 age_in_min, 60 * 6)
237 age_in_min, 60 * 6)
236 return
238 return
237
239
238 def write(dest_file):
240 def write(dest_file):
239 configuration = system_info.SysInfo(system_info.rhodecode_config)()['value']
241 configuration = system_info.SysInfo(system_info.rhodecode_config)()['value']
240 license_token = configuration['config']['license_token']
242 license_token = configuration['config']['license_token']
241
243
242 metadata = dict(
244 metadata = dict(
243 desc='Usage data',
245 desc='Usage data',
244 instance_tag=instance_tag,
246 instance_tag=instance_tag,
245 license_token=license_token,
247 license_token=license_token,
246 created_on=datetime.datetime.utcnow().isoformat(),
248 created_on=datetime.datetime.utcnow().isoformat(),
247 usage=system_info.SysInfo(system_info.usage_info)()['value'],
249 usage=system_info.SysInfo(system_info.usage_info)()['value'],
248 )
250 )
249
251
250 with open(dest_file, 'wb') as f:
252 with open(dest_file, 'wb') as f:
251 f.write(ext_json.json.dumps(metadata, indent=2, sort_keys=True))
253 f.write(ext_json.json.dumps(metadata, indent=2, sort_keys=True))
252
254
253 try:
255 try:
254 log.debug('Writing usage file at: %s', usage_metadata_destination)
256 log.debug('Writing usage file at: %s', usage_metadata_destination)
255 write(usage_metadata_destination)
257 write(usage_metadata_destination)
256 except Exception:
258 except Exception:
257 pass
259 pass
258
260
259
261
260 def write_js_routes_if_enabled(event):
262 def write_js_routes_if_enabled(event):
261 registry = event.app.registry
263 registry = event.app.registry
262
264
263 mapper = registry.queryUtility(IRoutesMapper)
265 mapper = registry.queryUtility(IRoutesMapper)
264 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
266 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
265
267
266 def _extract_route_information(route):
268 def _extract_route_information(route):
267 """
269 """
268 Convert a route into tuple(name, path, args), eg:
270 Convert a route into tuple(name, path, args), eg:
269 ('show_user', '/profile/%(username)s', ['username'])
271 ('show_user', '/profile/%(username)s', ['username'])
270 """
272 """
271
273
272 routepath = route.pattern
274 routepath = route.pattern
273 pattern = route.pattern
275 pattern = route.pattern
274
276
275 def replace(matchobj):
277 def replace(matchobj):
276 if matchobj.group(1):
278 if matchobj.group(1):
277 return "%%(%s)s" % matchobj.group(1).split(':')[0]
279 return "%%(%s)s" % matchobj.group(1).split(':')[0]
278 else:
280 else:
279 return "%%(%s)s" % matchobj.group(2)
281 return "%%(%s)s" % matchobj.group(2)
280
282
281 routepath = _argument_prog.sub(replace, routepath)
283 routepath = _argument_prog.sub(replace, routepath)
282
284
283 if not routepath.startswith('/'):
285 if not routepath.startswith('/'):
284 routepath = '/'+routepath
286 routepath = '/'+routepath
285
287
286 return (
288 return (
287 route.name,
289 route.name,
288 routepath,
290 routepath,
289 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
291 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
290 for arg in _argument_prog.findall(pattern)]
292 for arg in _argument_prog.findall(pattern)]
291 )
293 )
292
294
293 def get_routes():
295 def get_routes():
294 # pyramid routes
296 # pyramid routes
295 for route in mapper.get_routes():
297 for route in mapper.get_routes():
296 if not route.name.startswith('__'):
298 if not route.name.startswith('__'):
297 yield _extract_route_information(route)
299 yield _extract_route_information(route)
298
300
299 if asbool(registry.settings.get('generate_js_files', 'false')):
301 if asbool(registry.settings.get('generate_js_files', 'false')):
300 static_path = AssetResolver().resolve('rhodecode:public').abspath()
302 static_path = AssetResolver().resolve('rhodecode:public').abspath()
301 jsroutes = get_routes()
303 jsroutes = get_routes()
302 jsroutes_file_content = generate_jsroutes_content(jsroutes)
304 jsroutes_file_content = generate_jsroutes_content(jsroutes)
303 jsroutes_file_path = os.path.join(
305 jsroutes_file_path = os.path.join(
304 static_path, 'js', 'rhodecode', 'routes.js')
306 static_path, 'js', 'rhodecode', 'routes.js')
305
307
306 try:
308 try:
307 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
309 with io.open(jsroutes_file_path, 'w', encoding='utf-8') as f:
308 f.write(jsroutes_file_content)
310 f.write(jsroutes_file_content)
309 except Exception:
311 except Exception:
310 log.exception('Failed to write routes.js into %s', jsroutes_file_path)
312 log.exception('Failed to write routes.js into %s', jsroutes_file_path)
311
313
312
314
313 class Subscriber(object):
315 class Subscriber(object):
314 """
316 """
315 Base class for subscribers to the pyramid event system.
317 Base class for subscribers to the pyramid event system.
316 """
318 """
317 def __call__(self, event):
319 def __call__(self, event):
318 self.run(event)
320 self.run(event)
319
321
320 def run(self, event):
322 def run(self, event):
321 raise NotImplementedError('Subclass has to implement this.')
323 raise NotImplementedError('Subclass has to implement this.')
322
324
323
325
324 class AsyncSubscriber(Subscriber):
326 class AsyncSubscriber(Subscriber):
325 """
327 """
326 Subscriber that handles the execution of events in a separate task to not
328 Subscriber that handles the execution of events in a separate task to not
327 block the execution of the code which triggers the event. It puts the
329 block the execution of the code which triggers the event. It puts the
328 received events into a queue from which the worker process takes them in
330 received events into a queue from which the worker process takes them in
329 order.
331 order.
330 """
332 """
331 def __init__(self):
333 def __init__(self):
332 self._stop = False
334 self._stop = False
333 self._eventq = Queue.Queue()
335 self._eventq = Queue.Queue()
334 self._worker = self.create_worker()
336 self._worker = self.create_worker()
335 self._worker.start()
337 self._worker.start()
336
338
337 def __call__(self, event):
339 def __call__(self, event):
338 self._eventq.put(event)
340 self._eventq.put(event)
339
341
340 def create_worker(self):
342 def create_worker(self):
341 worker = Thread(target=self.do_work)
343 worker = Thread(target=self.do_work)
342 worker.daemon = True
344 worker.daemon = True
343 return worker
345 return worker
344
346
345 def stop_worker(self):
347 def stop_worker(self):
346 self._stop = False
348 self._stop = False
347 self._eventq.put(None)
349 self._eventq.put(None)
348 self._worker.join()
350 self._worker.join()
349
351
350 def do_work(self):
352 def do_work(self):
351 while not self._stop:
353 while not self._stop:
352 event = self._eventq.get()
354 event = self._eventq.get()
353 if event is not None:
355 if event is not None:
354 self.run(event)
356 self.run(event)
355
357
356
358
357 class AsyncSubprocessSubscriber(AsyncSubscriber):
359 class AsyncSubprocessSubscriber(AsyncSubscriber):
358 """
360 """
359 Subscriber that uses the subprocess32 module to execute a command if an
361 Subscriber that uses the subprocess32 module to execute a command if an
360 event is received. Events are handled asynchronously.
362 event is received. Events are handled asynchronously::
363
364 subscriber = AsyncSubprocessSubscriber('ls -la', timeout=10)
365 subscriber(dummyEvent) # running __call__(event)
366
361 """
367 """
362
368
363 def __init__(self, cmd, timeout=None):
369 def __init__(self, cmd, timeout=None):
370 if not isinstance(cmd, (list, tuple)):
371 cmd = shlex.split(cmd)
364 super(AsyncSubprocessSubscriber, self).__init__()
372 super(AsyncSubprocessSubscriber, self).__init__()
365 self._cmd = cmd
373 self._cmd = cmd
366 self._timeout = timeout
374 self._timeout = timeout
367
375
368 def run(self, event):
376 def run(self, event):
369 cmd = self._cmd
377 cmd = self._cmd
370 timeout = self._timeout
378 timeout = self._timeout
371 log.debug('Executing command %s.', cmd)
379 log.debug('Executing command %s.', cmd)
372
380
373 try:
381 try:
374 output = subprocess32.check_output(
382 output = subprocess32.check_output(
375 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
383 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
376 log.debug('Command finished %s', cmd)
384 log.debug('Command finished %s', cmd)
377 if output:
385 if output:
378 log.debug('Command output: %s', output)
386 log.debug('Command output: %s', output)
379 except subprocess32.TimeoutExpired as e:
387 except subprocess32.TimeoutExpired as e:
380 log.exception('Timeout while executing command.')
388 log.exception('Timeout while executing command.')
381 if e.output:
389 if e.output:
382 log.error('Command output: %s', e.output)
390 log.error('Command output: %s', e.output)
383 except subprocess32.CalledProcessError as e:
391 except subprocess32.CalledProcessError as e:
384 log.exception('Error while executing command.')
392 log.exception('Error while executing command.')
385 if e.output:
393 if e.output:
386 log.error('Command output: %s', e.output)
394 log.error('Command output: %s', e.output)
387 except:
395 except Exception:
388 log.exception(
396 log.exception(
389 'Exception while executing command %s.', cmd)
397 'Exception while executing command %s.', cmd)
General Comments 0
You need to be logged in to leave comments. Login now