##// END OF EJS Templates
system-info: fix unicode problem on translation
marcink -
r1308:8c3404aa default
parent child Browse files
Show More
@@ -1,642 +1,643 b''
1 1 import os
2 2 import sys
3 3 import time
4 4 import platform
5 5 import pkg_resources
6 6 import logging
7 7 import string
8 8
9 9
10 10 log = logging.getLogger(__name__)
11 11
12 12
13 13 psutil = None
14 14
15 15 try:
16 16 # cygwin cannot have yet psutil support.
17 17 import psutil as psutil
18 18 except ImportError:
19 19 pass
20 20
21 21
22 22 _NA = 'NOT AVAILABLE'
23 23
24 24 STATE_OK = 'ok'
25 25 STATE_ERR = 'error'
26 26 STATE_WARN = 'warning'
27 27
28 28 STATE_OK_DEFAULT = {'message': '', 'type': STATE_OK}
29 29
30 30
31 31 # HELPERS
32 32 def percentage(part, whole):
33 33 whole = float(whole)
34 34 if whole > 0:
35 35 return round(100 * float(part) / whole, 1)
36 36 return 0.0
37 37
38 38
39 39 def get_storage_size(storage_path):
40 40 sizes = []
41 41 for file_ in os.listdir(storage_path):
42 42 storage_file = os.path.join(storage_path, file_)
43 43 if os.path.isfile(storage_file):
44 44 try:
45 45 sizes.append(os.path.getsize(storage_file))
46 46 except OSError:
47 47 log.exception('Failed to get size of storage file %s',
48 48 storage_file)
49 49 pass
50 50
51 51 return sum(sizes)
52 52
53 53
54 54 class SysInfoRes(object):
55 55 def __init__(self, value, state=STATE_OK_DEFAULT, human_value=None):
56 56 self.value = value
57 57 self.state = state
58 58 self.human_value = human_value or value
59 59
60 60 def __json__(self):
61 61 return {
62 62 'value': self.value,
63 63 'state': self.state,
64 64 'human_value': self.human_value,
65 65 }
66 66
67 67 def get_value(self):
68 68 return self.__json__()
69 69
70 70 def __str__(self):
71 71 return '<SysInfoRes({})>'.format(self.__json__())
72 72
73 73
74 74 class SysInfo(object):
75 75
76 76 def __init__(self, func_name, **kwargs):
77 77 self.func_name = func_name
78 78 self.value = _NA
79 79 self.state = None
80 80 self.kwargs = kwargs or {}
81 81
82 82 def __call__(self):
83 83 computed = self.compute(**self.kwargs)
84 84 if not isinstance(computed, SysInfoRes):
85 85 raise ValueError(
86 86 'computed value for {} is not instance of '
87 87 '{}, got {} instead'.format(
88 88 self.func_name, SysInfoRes, type(computed)))
89 89 return computed.__json__()
90 90
91 91 def __str__(self):
92 92 return '<SysInfo({})>'.format(self.func_name)
93 93
94 94 def compute(self, **kwargs):
95 95 return self.func_name(**kwargs)
96 96
97 97
98 98 # SysInfo functions
99 99 def python_info():
100 100 value = dict(version=' '.join(platform._sys_version()),
101 101 executable=sys.executable)
102 102 return SysInfoRes(value=value)
103 103
104 104
105 105 def py_modules():
106 106 mods = dict([(p.project_name, p.version)
107 107 for p in pkg_resources.working_set])
108 108 value = sorted(mods.items(), key=lambda k: k[0].lower())
109 109 return SysInfoRes(value=value)
110 110
111 111
112 112 def platform_type():
113 113 from rhodecode.lib.utils import safe_unicode, generate_platform_uuid
114 114
115 115 value = dict(
116 116 name=safe_unicode(platform.platform()),
117 117 uuid=generate_platform_uuid()
118 118 )
119 119 return SysInfoRes(value=value)
120 120
121 121
122 122 def uptime():
123 123 from rhodecode.lib.helpers import age, time_to_datetime
124 124
125 125 value = dict(boot_time=0, uptime=0, text='')
126 126 state = STATE_OK_DEFAULT
127 127 if not psutil:
128 128 return SysInfoRes(value=value, state=state)
129 129
130 130 boot_time = psutil.boot_time()
131 131 value['boot_time'] = boot_time
132 132 value['uptime'] = time.time() - boot_time
133 133
134 134 human_value = value.copy()
135 135 human_value['boot_time'] = time_to_datetime(boot_time)
136 136 human_value['uptime'] = age(time_to_datetime(boot_time), show_suffix=False)
137 human_value['text'] = 'Server started {}'.format(
137
138 human_value['text'] = u'Server started {}'.format(
138 139 age(time_to_datetime(boot_time)))
139 140
140 141 return SysInfoRes(value=value, human_value=human_value)
141 142
142 143
143 144 def memory():
144 145 from rhodecode.lib.helpers import format_byte_size_binary
145 146 value = dict(available=0, used=0, used_real=0, cached=0, percent=0,
146 147 percent_used=0, free=0, inactive=0, active=0, shared=0,
147 148 total=0, buffers=0, text='')
148 149
149 150 state = STATE_OK_DEFAULT
150 151 if not psutil:
151 152 return SysInfoRes(value=value, state=state)
152 153
153 154 value.update(dict(psutil.virtual_memory()._asdict()))
154 155 value['used_real'] = value['total'] - value['available']
155 156 value['percent_used'] = psutil._common.usage_percent(
156 157 value['used_real'], value['total'], 1)
157 158
158 159 human_value = value.copy()
159 160 human_value['text'] = '%s/%s, %s%% used' % (
160 161 format_byte_size_binary(value['used_real']),
161 162 format_byte_size_binary(value['total']),
162 163 value['percent_used'],)
163 164
164 165 keys = value.keys()[::]
165 166 keys.pop(keys.index('percent'))
166 167 keys.pop(keys.index('percent_used'))
167 168 keys.pop(keys.index('text'))
168 169 for k in keys:
169 170 human_value[k] = format_byte_size_binary(value[k])
170 171
171 172 if state['type'] == STATE_OK and value['percent_used'] > 90:
172 173 msg = 'Critical: your available RAM memory is very low.'
173 174 state = {'message': msg, 'type': STATE_ERR}
174 175
175 176 elif state['type'] == STATE_OK and value['percent_used'] > 70:
176 177 msg = 'Warning: your available RAM memory is running low.'
177 178 state = {'message': msg, 'type': STATE_WARN}
178 179
179 180 return SysInfoRes(value=value, state=state, human_value=human_value)
180 181
181 182
182 183 def machine_load():
183 184 value = {'1_min': _NA, '5_min': _NA, '15_min': _NA, 'text': ''}
184 185 state = STATE_OK_DEFAULT
185 186 if not psutil:
186 187 return SysInfoRes(value=value, state=state)
187 188
188 189 # load averages
189 190 if hasattr(psutil.os, 'getloadavg'):
190 191 value.update(dict(
191 192 zip(['1_min', '5_min', '15_min'], psutil.os.getloadavg())))
192 193
193 194 human_value = value.copy()
194 195 human_value['text'] = '1min: {}, 5min: {}, 15min: {}'.format(
195 196 value['1_min'], value['5_min'], value['15_min'])
196 197
197 198 if state['type'] == STATE_OK and value['15_min'] > 5:
198 199 msg = 'Warning: your machine load is very high.'
199 200 state = {'message': msg, 'type': STATE_WARN}
200 201
201 202 return SysInfoRes(value=value, state=state, human_value=human_value)
202 203
203 204
204 205 def cpu():
205 206 value = 0
206 207 state = STATE_OK_DEFAULT
207 208
208 209 if not psutil:
209 210 return SysInfoRes(value=value, state=state)
210 211
211 212 value = psutil.cpu_percent(0.5)
212 213 human_value = '{} %'.format(value)
213 214 return SysInfoRes(value=value, state=state, human_value=human_value)
214 215
215 216
216 217 def storage():
217 218 from rhodecode.lib.helpers import format_byte_size_binary
218 219 from rhodecode.model.settings import VcsSettingsModel
219 220 path = VcsSettingsModel().get_repos_location()
220 221
221 222 value = dict(percent=0, used=0, total=0, path=path, text='')
222 223 state = STATE_OK_DEFAULT
223 224 if not psutil:
224 225 return SysInfoRes(value=value, state=state)
225 226
226 227 try:
227 228 value.update(dict(psutil.disk_usage(path)._asdict()))
228 229 except Exception as e:
229 230 log.exception('Failed to fetch disk info')
230 231 state = {'message': str(e), 'type': STATE_ERR}
231 232
232 233 human_value = value.copy()
233 234 human_value['used'] = format_byte_size_binary(value['used'])
234 235 human_value['total'] = format_byte_size_binary(value['total'])
235 236 human_value['text'] = "{}/{}, {}% used".format(
236 237 format_byte_size_binary(value['used']),
237 238 format_byte_size_binary(value['total']),
238 239 value['percent'])
239 240
240 241 if state['type'] == STATE_OK and value['percent'] > 90:
241 242 msg = 'Critical: your disk space is very low.'
242 243 state = {'message': msg, 'type': STATE_ERR}
243 244
244 245 elif state['type'] == STATE_OK and value['percent'] > 70:
245 246 msg = 'Warning: your disk space is running low.'
246 247 state = {'message': msg, 'type': STATE_WARN}
247 248
248 249 return SysInfoRes(value=value, state=state, human_value=human_value)
249 250
250 251
251 252 def storage_inodes():
252 253 from rhodecode.model.settings import VcsSettingsModel
253 254 path = VcsSettingsModel().get_repos_location()
254 255
255 256 value = dict(percent=0, free=0, used=0, total=0, path=path, text='')
256 257 state = STATE_OK_DEFAULT
257 258 if not psutil:
258 259 return SysInfoRes(value=value, state=state)
259 260
260 261 try:
261 262 i_stat = os.statvfs(path)
262 263 value['free'] = i_stat.f_ffree
263 264 value['used'] = i_stat.f_files-i_stat.f_favail
264 265 value['total'] = i_stat.f_files
265 266 value['percent'] = percentage(value['used'], value['total'])
266 267 except Exception as e:
267 268 log.exception('Failed to fetch disk inodes info')
268 269 state = {'message': str(e), 'type': STATE_ERR}
269 270
270 271 human_value = value.copy()
271 272 human_value['text'] = "{}/{}, {}% used".format(
272 273 value['used'], value['total'], value['percent'])
273 274
274 275 if state['type'] == STATE_OK and value['percent'] > 90:
275 276 msg = 'Critical: your disk free inodes are very low.'
276 277 state = {'message': msg, 'type': STATE_ERR}
277 278
278 279 elif state['type'] == STATE_OK and value['percent'] > 70:
279 280 msg = 'Warning: your disk free inodes are running low.'
280 281 state = {'message': msg, 'type': STATE_WARN}
281 282
282 283 return SysInfoRes(value=value, state=state, human_value=human_value)
283 284
284 285
285 286 def storage_archives():
286 287 import rhodecode
287 288 from rhodecode.lib.utils import safe_str
288 289 from rhodecode.lib.helpers import format_byte_size_binary
289 290
290 291 msg = 'Enable this by setting ' \
291 292 'archive_cache_dir=/path/to/cache option in the .ini file'
292 293 path = safe_str(rhodecode.CONFIG.get('archive_cache_dir', msg))
293 294
294 295 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
295 296 state = STATE_OK_DEFAULT
296 297 try:
297 298 items_count = 0
298 299 used = 0
299 300 for root, dirs, files in os.walk(path):
300 301 if root == path:
301 302 items_count = len(files)
302 303
303 304 for f in files:
304 305 try:
305 306 used += os.path.getsize(os.path.join(root, f))
306 307 except OSError:
307 308 pass
308 309 value.update({
309 310 'percent': 100,
310 311 'used': used,
311 312 'total': used,
312 313 'items': items_count
313 314 })
314 315
315 316 except Exception as e:
316 317 log.exception('failed to fetch archive cache storage')
317 318 state = {'message': str(e), 'type': STATE_ERR}
318 319
319 320 human_value = value.copy()
320 321 human_value['used'] = format_byte_size_binary(value['used'])
321 322 human_value['total'] = format_byte_size_binary(value['total'])
322 323 human_value['text'] = "{} ({} items)".format(
323 324 human_value['used'], value['items'])
324 325
325 326 return SysInfoRes(value=value, state=state, human_value=human_value)
326 327
327 328
328 329 def storage_gist():
329 330 from rhodecode.model.gist import GIST_STORE_LOC
330 331 from rhodecode.model.settings import VcsSettingsModel
331 332 from rhodecode.lib.utils import safe_str
332 333 from rhodecode.lib.helpers import format_byte_size_binary
333 334 path = safe_str(os.path.join(
334 335 VcsSettingsModel().get_repos_location(), GIST_STORE_LOC))
335 336
336 337 # gist storage
337 338 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
338 339 state = STATE_OK_DEFAULT
339 340
340 341 try:
341 342 items_count = 0
342 343 used = 0
343 344 for root, dirs, files in os.walk(path):
344 345 if root == path:
345 346 items_count = len(dirs)
346 347
347 348 for f in files:
348 349 try:
349 350 used += os.path.getsize(os.path.join(root, f))
350 351 except OSError:
351 352 pass
352 353 value.update({
353 354 'percent': 100,
354 355 'used': used,
355 356 'total': used,
356 357 'items': items_count
357 358 })
358 359 except Exception as e:
359 360 log.exception('failed to fetch gist storage items')
360 361 state = {'message': str(e), 'type': STATE_ERR}
361 362
362 363 human_value = value.copy()
363 364 human_value['used'] = format_byte_size_binary(value['used'])
364 365 human_value['total'] = format_byte_size_binary(value['total'])
365 366 human_value['text'] = "{} ({} items)".format(
366 367 human_value['used'], value['items'])
367 368
368 369 return SysInfoRes(value=value, state=state, human_value=human_value)
369 370
370 371
371 372 def storage_temp():
372 373 import tempfile
373 374 from rhodecode.lib.helpers import format_byte_size_binary
374 375
375 376 path = tempfile.gettempdir()
376 377 value = dict(percent=0, used=0, total=0, items=0, path=path, text='')
377 378 state = STATE_OK_DEFAULT
378 379
379 380 if not psutil:
380 381 return SysInfoRes(value=value, state=state)
381 382
382 383 try:
383 384 value.update(dict(psutil.disk_usage(path)._asdict()))
384 385 except Exception as e:
385 386 log.exception('Failed to fetch temp dir info')
386 387 state = {'message': str(e), 'type': STATE_ERR}
387 388
388 389 human_value = value.copy()
389 390 human_value['used'] = format_byte_size_binary(value['used'])
390 391 human_value['total'] = format_byte_size_binary(value['total'])
391 392 human_value['text'] = "{}/{}, {}% used".format(
392 393 format_byte_size_binary(value['used']),
393 394 format_byte_size_binary(value['total']),
394 395 value['percent'])
395 396
396 397 return SysInfoRes(value=value, state=state, human_value=human_value)
397 398
398 399
399 400 def search_info():
400 401 import rhodecode
401 402 from rhodecode.lib.index import searcher_from_config
402 403
403 404 backend = rhodecode.CONFIG.get('search.module', '')
404 405 location = rhodecode.CONFIG.get('search.location', '')
405 406
406 407 try:
407 408 searcher = searcher_from_config(rhodecode.CONFIG)
408 409 searcher = searcher.__class__.__name__
409 410 except Exception:
410 411 searcher = None
411 412
412 413 value = dict(
413 414 backend=backend, searcher=searcher, location=location, text='')
414 415 state = STATE_OK_DEFAULT
415 416
416 417 human_value = value.copy()
417 418 human_value['text'] = "backend:`{}`".format(human_value['backend'])
418 419
419 420 return SysInfoRes(value=value, state=state, human_value=human_value)
420 421
421 422
422 423 def git_info():
423 424 from rhodecode.lib.vcs.backends import git
424 425 state = STATE_OK_DEFAULT
425 426 value = human_value = ''
426 427 try:
427 428 value = git.discover_git_version(raise_on_exc=True)
428 429 human_value = 'version reported from VCSServer: {}'.format(value)
429 430 except Exception as e:
430 431 state = {'message': str(e), 'type': STATE_ERR}
431 432
432 433 return SysInfoRes(value=value, state=state, human_value=human_value)
433 434
434 435
435 436 def hg_info():
436 437 from rhodecode.lib.vcs.backends import hg
437 438 state = STATE_OK_DEFAULT
438 439 value = human_value = ''
439 440 try:
440 441 value = hg.discover_hg_version(raise_on_exc=True)
441 442 human_value = 'version reported from VCSServer: {}'.format(value)
442 443 except Exception as e:
443 444 state = {'message': str(e), 'type': STATE_ERR}
444 445 return SysInfoRes(value=value, state=state, human_value=human_value)
445 446
446 447
447 448 def svn_info():
448 449 from rhodecode.lib.vcs.backends import svn
449 450 state = STATE_OK_DEFAULT
450 451 value = human_value = ''
451 452 try:
452 453 value = svn.discover_svn_version(raise_on_exc=True)
453 454 human_value = 'version reported from VCSServer: {}'.format(value)
454 455 except Exception as e:
455 456 state = {'message': str(e), 'type': STATE_ERR}
456 457 return SysInfoRes(value=value, state=state, human_value=human_value)
457 458
458 459
459 460 def vcs_backends():
460 461 import rhodecode
461 462 value = map(
462 463 string.strip, rhodecode.CONFIG.get('vcs.backends', '').split(','))
463 464 human_value = 'Enabled backends in order: {}'.format(','.join(value))
464 465 return SysInfoRes(value=value, human_value=human_value)
465 466
466 467
467 468 def vcs_server():
468 469 import rhodecode
469 470 from rhodecode.lib.vcs.backends import get_vcsserver_version
470 471
471 472 server_url = rhodecode.CONFIG.get('vcs.server')
472 473 enabled = rhodecode.CONFIG.get('vcs.server.enable')
473 474 protocol = rhodecode.CONFIG.get('vcs.server.protocol') or 'http'
474 475 state = STATE_OK_DEFAULT
475 476 version = None
476 477
477 478 try:
478 479 version = get_vcsserver_version()
479 480 connection = 'connected'
480 481 except Exception as e:
481 482 connection = 'failed'
482 483 state = {'message': str(e), 'type': STATE_ERR}
483 484
484 485 value = dict(
485 486 url=server_url,
486 487 enabled=enabled,
487 488 protocol=protocol,
488 489 connection=connection,
489 490 version=version,
490 491 text='',
491 492 )
492 493
493 494 human_value = value.copy()
494 495 human_value['text'] = \
495 496 '{url}@ver:{ver} via {mode} mode, connection:{conn}'.format(
496 497 url=server_url, ver=version, mode=protocol, conn=connection)
497 498
498 499 return SysInfoRes(value=value, state=state, human_value=human_value)
499 500
500 501
501 502 def rhodecode_app_info():
502 503 import rhodecode
503 504 edition = rhodecode.CONFIG.get('rhodecode.edition')
504 505
505 506 value = dict(
506 507 rhodecode_version=rhodecode.__version__,
507 508 rhodecode_lib_path=os.path.abspath(rhodecode.__file__),
508 509 text=''
509 510 )
510 511 human_value = value.copy()
511 512 human_value['text'] = 'RhodeCode {edition}, version {ver}'.format(
512 513 edition=edition, ver=value['rhodecode_version']
513 514 )
514 515 return SysInfoRes(value=value, human_value=human_value)
515 516
516 517
517 518 def rhodecode_config():
518 519 import rhodecode
519 520 path = rhodecode.CONFIG.get('__file__')
520 521 rhodecode_ini_safe = rhodecode.CONFIG.copy()
521 522
522 523 blacklist = [
523 524 'rhodecode_license_key',
524 525 'routes.map',
525 526 'pylons.h',
526 527 'pylons.app_globals',
527 528 'pylons.environ_config',
528 529 'sqlalchemy.db1.url',
529 530 'channelstream.secret',
530 531 'beaker.session.secret',
531 532 'rhodecode.encrypted_values.secret',
532 533 'rhodecode_auth_github_consumer_key',
533 534 'rhodecode_auth_github_consumer_secret',
534 535 'rhodecode_auth_google_consumer_key',
535 536 'rhodecode_auth_google_consumer_secret',
536 537 'rhodecode_auth_bitbucket_consumer_secret',
537 538 'rhodecode_auth_bitbucket_consumer_key',
538 539 'rhodecode_auth_twitter_consumer_secret',
539 540 'rhodecode_auth_twitter_consumer_key',
540 541
541 542 'rhodecode_auth_twitter_secret',
542 543 'rhodecode_auth_github_secret',
543 544 'rhodecode_auth_google_secret',
544 545 'rhodecode_auth_bitbucket_secret',
545 546
546 547 'appenlight.api_key',
547 548 ('app_conf', 'sqlalchemy.db1.url')
548 549 ]
549 550 for k in blacklist:
550 551 if isinstance(k, tuple):
551 552 section, key = k
552 553 if section in rhodecode_ini_safe:
553 554 rhodecode_ini_safe[section] = '**OBFUSCATED**'
554 555 else:
555 556 rhodecode_ini_safe.pop(k, None)
556 557
557 558 # TODO: maybe put some CONFIG checks here ?
558 559 return SysInfoRes(value={'config': rhodecode_ini_safe, 'path': path})
559 560
560 561
561 562 def database_info():
562 563 import rhodecode
563 564 from sqlalchemy.engine import url as engine_url
564 565 from rhodecode.model.meta import Base as sql_base, Session
565 566 from rhodecode.model.db import DbMigrateVersion
566 567
567 568 state = STATE_OK_DEFAULT
568 569
569 570 db_migrate = DbMigrateVersion.query().filter(
570 571 DbMigrateVersion.repository_id == 'rhodecode_db_migrations').one()
571 572
572 573 db_url_obj = engine_url.make_url(rhodecode.CONFIG['sqlalchemy.db1.url'])
573 574
574 575 try:
575 576 engine = sql_base.metadata.bind
576 577 db_server_info = engine.dialect._get_server_version_info(
577 578 Session.connection(bind=engine))
578 579 db_version = '.'.join(map(str, db_server_info))
579 580 except Exception:
580 581 log.exception('failed to fetch db version')
581 582 db_version = 'UNKNOWN'
582 583
583 584 db_info = dict(
584 585 migrate_version=db_migrate.version,
585 586 type=db_url_obj.get_backend_name(),
586 587 version=db_version,
587 588 url=repr(db_url_obj)
588 589 )
589 590
590 591 human_value = db_info.copy()
591 592 human_value['url'] = "{} @ migration version: {}".format(
592 593 db_info['url'], db_info['migrate_version'])
593 594 human_value['version'] = "{} {}".format(db_info['type'], db_info['version'])
594 595 return SysInfoRes(value=db_info, state=state, human_value=human_value)
595 596
596 597
597 598 def server_info(environ):
598 599 import rhodecode
599 600 from rhodecode.lib.base import get_server_ip_addr, get_server_port
600 601
601 602 value = {
602 603 'server_ip': '%s:%s' % (
603 604 get_server_ip_addr(environ, log_errors=False),
604 605 get_server_port(environ)
605 606 ),
606 607 'server_id': rhodecode.CONFIG.get('instance_id'),
607 608 }
608 609 return SysInfoRes(value=value)
609 610
610 611
611 612 def get_system_info(environ):
612 613 environ = environ or {}
613 614 return {
614 615 'rhodecode_app': SysInfo(rhodecode_app_info)(),
615 616 'rhodecode_config': SysInfo(rhodecode_config)(),
616 617 'python': SysInfo(python_info)(),
617 618 'py_modules': SysInfo(py_modules)(),
618 619
619 620 'platform': SysInfo(platform_type)(),
620 621 'server': SysInfo(server_info, environ=environ)(),
621 622 'database': SysInfo(database_info)(),
622 623
623 624 'storage': SysInfo(storage)(),
624 625 'storage_inodes': SysInfo(storage_inodes)(),
625 626 'storage_archive': SysInfo(storage_archives)(),
626 627 'storage_gist': SysInfo(storage_gist)(),
627 628 'storage_temp': SysInfo(storage_temp)(),
628 629
629 630 'search': SysInfo(search_info)(),
630 631
631 632 'uptime': SysInfo(uptime)(),
632 633 'load': SysInfo(machine_load)(),
633 634 'cpu': SysInfo(cpu)(),
634 635 'memory': SysInfo(memory)(),
635 636
636 637 'vcs_backends': SysInfo(vcs_backends)(),
637 638 'vcs_server': SysInfo(vcs_server)(),
638 639
639 640 'git': SysInfo(git_info)(),
640 641 'hg': SysInfo(hg_info)(),
641 642 'svn': SysInfo(svn_info)(),
642 643 }
@@ -1,166 +1,166 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 import logging
23 23 import pylons
24 24 import Queue
25 25 import subprocess32
26 26
27 27 from pyramid.i18n import get_localizer
28 28 from pyramid.threadlocal import get_current_request
29 29 from threading import Thread
30 30
31 31 from rhodecode.translation import _ as tsf
32 32
33
34 33 log = logging.getLogger(__name__)
35 34
36 35
37 36 def add_renderer_globals(event):
38 37 # Put pylons stuff into the context. This will be removed as soon as
39 38 # migration to pyramid is finished.
40 39 conf = pylons.config._current_obj()
41 40 event['h'] = conf.get('pylons.h')
42 41 event['c'] = pylons.tmpl_context
43 42 event['url'] = pylons.url
44 43
45 44 # TODO: When executed in pyramid view context the request is not available
46 45 # in the event. Find a better solution to get the request.
47 46 request = event['request'] or get_current_request()
48 47
49 48 # Add Pyramid translation as '_' to context
50 49 event['_'] = request.translate
51 50 event['_ungettext'] = request.plularize
52 51
53 52
54 53 def add_localizer(event):
55 54 request = event.request
56 55 localizer = get_localizer(request)
57 56
58 57 def auto_translate(*args, **kwargs):
59 58 return localizer.translate(tsf(*args, **kwargs))
60 59
61 60 request.localizer = localizer
62 61 request.translate = auto_translate
63 62 request.plularize = localizer.pluralize
64 63
65 64
66 65 def set_user_lang(event):
67 66 cur_user = getattr(event.request, 'user', None)
68 67
69 68 if cur_user:
70 69 user_lang = cur_user.get_instance().user_data.get('language')
71 70 if user_lang:
71 log.debug('lang: setting current user:%s language to: %s', cur_user, user_lang)
72 72 event.request._LOCALE_ = user_lang
73 73
74 74
75 75 def scan_repositories_if_enabled(event):
76 76 """
77 77 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
78 78 does a repository scan if enabled in the settings.
79 79 """
80 80 from rhodecode.model.scm import ScmModel
81 81 from rhodecode.lib.utils import repo2db_mapper, get_rhodecode_base_path
82 82 settings = event.app.registry.settings
83 83 vcs_server_enabled = settings['vcs.server.enable']
84 84 import_on_startup = settings['startup.import_repos']
85 85 if vcs_server_enabled and import_on_startup:
86 86 repositories = ScmModel().repo_scan(get_rhodecode_base_path())
87 87 repo2db_mapper(repositories, remove_obsolete=False)
88 88
89 89
90 90 class Subscriber(object):
91 91 """
92 92 Base class for subscribers to the pyramid event system.
93 93 """
94 94 def __call__(self, event):
95 95 self.run(event)
96 96
97 97 def run(self, event):
98 98 raise NotImplementedError('Subclass has to implement this.')
99 99
100 100
101 101 class AsyncSubscriber(Subscriber):
102 102 """
103 103 Subscriber that handles the execution of events in a separate task to not
104 104 block the execution of the code which triggers the event. It puts the
105 105 received events into a queue from which the worker process takes them in
106 106 order.
107 107 """
108 108 def __init__(self):
109 109 self._stop = False
110 110 self._eventq = Queue.Queue()
111 111 self._worker = self.create_worker()
112 112 self._worker.start()
113 113
114 114 def __call__(self, event):
115 115 self._eventq.put(event)
116 116
117 117 def create_worker(self):
118 118 worker = Thread(target=self.do_work)
119 119 worker.daemon = True
120 120 return worker
121 121
122 122 def stop_worker(self):
123 123 self._stop = False
124 124 self._eventq.put(None)
125 125 self._worker.join()
126 126
127 127 def do_work(self):
128 128 while not self._stop:
129 129 event = self._eventq.get()
130 130 if event is not None:
131 131 self.run(event)
132 132
133 133
134 134 class AsyncSubprocessSubscriber(AsyncSubscriber):
135 135 """
136 136 Subscriber that uses the subprocess32 module to execute a command if an
137 137 event is received. Events are handled asynchronously.
138 138 """
139 139
140 140 def __init__(self, cmd, timeout=None):
141 141 super(AsyncSubprocessSubscriber, self).__init__()
142 142 self._cmd = cmd
143 143 self._timeout = timeout
144 144
145 145 def run(self, event):
146 146 cmd = self._cmd
147 147 timeout = self._timeout
148 148 log.debug('Executing command %s.', cmd)
149 149
150 150 try:
151 151 output = subprocess32.check_output(
152 152 cmd, timeout=timeout, stderr=subprocess32.STDOUT)
153 153 log.debug('Command finished %s', cmd)
154 154 if output:
155 155 log.debug('Command output: %s', output)
156 156 except subprocess32.TimeoutExpired as e:
157 157 log.exception('Timeout while executing command.')
158 158 if e.output:
159 159 log.error('Command output: %s', e.output)
160 160 except subprocess32.CalledProcessError as e:
161 161 log.exception('Error while executing command.')
162 162 if e.output:
163 163 log.error('Command output: %s', e.output)
164 164 except:
165 165 log.exception(
166 166 'Exception while executing command %s.', cmd)
General Comments 0
You need to be logged in to leave comments. Login now