##// END OF EJS Templates
logging: dont spawn UI logs across multiple lines
marcink -
r2640:58f3399b default
parent child Browse files
Show More
@@ -1,779 +1,781 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2018 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 Utilities library for RhodeCode
23 23 """
24 24
25 25 import datetime
26 26 import decorator
27 27 import json
28 28 import logging
29 29 import os
30 30 import re
31 31 import shutil
32 32 import tempfile
33 33 import traceback
34 34 import tarfile
35 35 import warnings
36 36 import hashlib
37 37 from os.path import join as jn
38 38
39 39 import paste
40 40 import pkg_resources
41 41 from webhelpers.text import collapse, remove_formatting, strip_tags
42 42 from mako import exceptions
43 43 from pyramid.threadlocal import get_current_registry
44 44 from pyramid.request import Request
45 45
46 46 from rhodecode.lib.fakemod import create_module
47 47 from rhodecode.lib.vcs.backends.base import Config
48 48 from rhodecode.lib.vcs.exceptions import VCSError
49 49 from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend
50 50 from rhodecode.lib.utils2 import (
51 51 safe_str, safe_unicode, get_current_rhodecode_user, md5)
52 52 from rhodecode.model import meta
53 53 from rhodecode.model.db import (
54 54 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
55 55 from rhodecode.model.meta import Session
56 56
57 57
58 58 log = logging.getLogger(__name__)
59 59
60 60 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
61 61
62 62 # String which contains characters that are not allowed in slug names for
63 63 # repositories or repository groups. It is properly escaped to use it in
64 64 # regular expressions.
65 65 SLUG_BAD_CHARS = re.escape('`?=[]\;\'"<>,/~!@#$%^&*()+{}|:')
66 66
67 67 # Regex that matches forbidden characters in repo/group slugs.
68 68 SLUG_BAD_CHAR_RE = re.compile('[{}]'.format(SLUG_BAD_CHARS))
69 69
70 70 # Regex that matches allowed characters in repo/group slugs.
71 71 SLUG_GOOD_CHAR_RE = re.compile('[^{}]'.format(SLUG_BAD_CHARS))
72 72
73 73 # Regex that matches whole repo/group slugs.
74 74 SLUG_RE = re.compile('[^{}]+'.format(SLUG_BAD_CHARS))
75 75
76 76 _license_cache = None
77 77
78 78
79 79 def repo_name_slug(value):
80 80 """
81 81 Return slug of name of repository
82 82 This function is called on each creation/modification
83 83 of repository to prevent bad names in repo
84 84 """
85 85 replacement_char = '-'
86 86
87 87 slug = remove_formatting(value)
88 88 slug = SLUG_BAD_CHAR_RE.sub('', slug)
89 89 slug = re.sub('[\s]+', '-', slug)
90 90 slug = collapse(slug, replacement_char)
91 91 return slug
92 92
93 93
94 94 #==============================================================================
95 95 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
96 96 #==============================================================================
97 97 def get_repo_slug(request):
98 98 _repo = ''
99 99
100 100 if hasattr(request, 'db_repo'):
101 101 # if our requests has set db reference use it for name, this
102 102 # translates the example.com/_<id> into proper repo names
103 103 _repo = request.db_repo.repo_name
104 104 elif getattr(request, 'matchdict', None):
105 105 # pyramid
106 106 _repo = request.matchdict.get('repo_name')
107 107
108 108 if _repo:
109 109 _repo = _repo.rstrip('/')
110 110 return _repo
111 111
112 112
113 113 def get_repo_group_slug(request):
114 114 _group = ''
115 115 if hasattr(request, 'db_repo_group'):
116 116 # if our requests has set db reference use it for name, this
117 117 # translates the example.com/_<id> into proper repo group names
118 118 _group = request.db_repo_group.group_name
119 119 elif getattr(request, 'matchdict', None):
120 120 # pyramid
121 121 _group = request.matchdict.get('repo_group_name')
122 122
123 123
124 124 if _group:
125 125 _group = _group.rstrip('/')
126 126 return _group
127 127
128 128
129 129 def get_user_group_slug(request):
130 130 _user_group = ''
131 131
132 132 if hasattr(request, 'db_user_group'):
133 133 _user_group = request.db_user_group.users_group_name
134 134 elif getattr(request, 'matchdict', None):
135 135 # pyramid
136 136 _user_group = request.matchdict.get('user_group_id')
137 137 _user_group_name = request.matchdict.get('user_group_name')
138 138 try:
139 139 if _user_group:
140 140 _user_group = UserGroup.get(_user_group)
141 141 elif _user_group_name:
142 142 _user_group = UserGroup.get_by_group_name(_user_group_name)
143 143
144 144 if _user_group:
145 145 _user_group = _user_group.users_group_name
146 146 except Exception:
147 147 log.exception('Failed to get user group by id and name')
148 148 # catch all failures here
149 149 return None
150 150
151 151 return _user_group
152 152
153 153
154 154 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
155 155 """
156 156 Scans given path for repos and return (name,(type,path)) tuple
157 157
158 158 :param path: path to scan for repositories
159 159 :param recursive: recursive search and return names with subdirs in front
160 160 """
161 161
162 162 # remove ending slash for better results
163 163 path = path.rstrip(os.sep)
164 164 log.debug('now scanning in %s location recursive:%s...', path, recursive)
165 165
166 166 def _get_repos(p):
167 167 dirpaths = _get_dirpaths(p)
168 168 if not _is_dir_writable(p):
169 169 log.warning('repo path without write access: %s', p)
170 170
171 171 for dirpath in dirpaths:
172 172 if os.path.isfile(os.path.join(p, dirpath)):
173 173 continue
174 174 cur_path = os.path.join(p, dirpath)
175 175
176 176 # skip removed repos
177 177 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
178 178 continue
179 179
180 180 #skip .<somethin> dirs
181 181 if dirpath.startswith('.'):
182 182 continue
183 183
184 184 try:
185 185 scm_info = get_scm(cur_path)
186 186 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
187 187 except VCSError:
188 188 if not recursive:
189 189 continue
190 190 #check if this dir containts other repos for recursive scan
191 191 rec_path = os.path.join(p, dirpath)
192 192 if os.path.isdir(rec_path):
193 193 for inner_scm in _get_repos(rec_path):
194 194 yield inner_scm
195 195
196 196 return _get_repos(path)
197 197
198 198
199 199 def _get_dirpaths(p):
200 200 try:
201 201 # OS-independable way of checking if we have at least read-only
202 202 # access or not.
203 203 dirpaths = os.listdir(p)
204 204 except OSError:
205 205 log.warning('ignoring repo path without read access: %s', p)
206 206 return []
207 207
208 208 # os.listpath has a tweak: If a unicode is passed into it, then it tries to
209 209 # decode paths and suddenly returns unicode objects itself. The items it
210 210 # cannot decode are returned as strings and cause issues.
211 211 #
212 212 # Those paths are ignored here until a solid solution for path handling has
213 213 # been built.
214 214 expected_type = type(p)
215 215
216 216 def _has_correct_type(item):
217 217 if type(item) is not expected_type:
218 218 log.error(
219 219 u"Ignoring path %s since it cannot be decoded into unicode.",
220 220 # Using "repr" to make sure that we see the byte value in case
221 221 # of support.
222 222 repr(item))
223 223 return False
224 224 return True
225 225
226 226 dirpaths = [item for item in dirpaths if _has_correct_type(item)]
227 227
228 228 return dirpaths
229 229
230 230
231 231 def _is_dir_writable(path):
232 232 """
233 233 Probe if `path` is writable.
234 234
235 235 Due to trouble on Cygwin / Windows, this is actually probing if it is
236 236 possible to create a file inside of `path`, stat does not produce reliable
237 237 results in this case.
238 238 """
239 239 try:
240 240 with tempfile.TemporaryFile(dir=path):
241 241 pass
242 242 except OSError:
243 243 return False
244 244 return True
245 245
246 246
247 247 def is_valid_repo(repo_name, base_path, expect_scm=None, explicit_scm=None, config=None):
248 248 """
249 249 Returns True if given path is a valid repository False otherwise.
250 250 If expect_scm param is given also, compare if given scm is the same
251 251 as expected from scm parameter. If explicit_scm is given don't try to
252 252 detect the scm, just use the given one to check if repo is valid
253 253
254 254 :param repo_name:
255 255 :param base_path:
256 256 :param expect_scm:
257 257 :param explicit_scm:
258 258 :param config:
259 259
260 260 :return True: if given path is a valid repository
261 261 """
262 262 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
263 263 log.debug('Checking if `%s` is a valid path for repository. '
264 264 'Explicit type: %s', repo_name, explicit_scm)
265 265
266 266 try:
267 267 if explicit_scm:
268 268 detected_scms = [get_scm_backend(explicit_scm)(
269 269 full_path, config=config).alias]
270 270 else:
271 271 detected_scms = get_scm(full_path)
272 272
273 273 if expect_scm:
274 274 return detected_scms[0] == expect_scm
275 275 log.debug('path: %s is an vcs object:%s', full_path, detected_scms)
276 276 return True
277 277 except VCSError:
278 278 log.debug('path: %s is not a valid repo !', full_path)
279 279 return False
280 280
281 281
282 282 def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False):
283 283 """
284 284 Returns True if given path is a repository group, False otherwise
285 285
286 286 :param repo_name:
287 287 :param base_path:
288 288 """
289 289 full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name))
290 290 log.debug('Checking if `%s` is a valid path for repository group',
291 291 repo_group_name)
292 292
293 293 # check if it's not a repo
294 294 if is_valid_repo(repo_group_name, base_path):
295 295 log.debug('Repo called %s exist, it is not a valid '
296 296 'repo group' % repo_group_name)
297 297 return False
298 298
299 299 try:
300 300 # we need to check bare git repos at higher level
301 301 # since we might match branches/hooks/info/objects or possible
302 302 # other things inside bare git repo
303 303 scm_ = get_scm(os.path.dirname(full_path))
304 304 log.debug('path: %s is a vcs object:%s, not valid '
305 305 'repo group' % (full_path, scm_))
306 306 return False
307 307 except VCSError:
308 308 pass
309 309
310 310 # check if it's a valid path
311 311 if skip_path_check or os.path.isdir(full_path):
312 312 log.debug('path: %s is a valid repo group !', full_path)
313 313 return True
314 314
315 315 log.debug('path: %s is not a valid repo group !', full_path)
316 316 return False
317 317
318 318
319 319 def ask_ok(prompt, retries=4, complaint='[y]es or [n]o please!'):
320 320 while True:
321 321 ok = raw_input(prompt)
322 322 if ok.lower() in ('y', 'ye', 'yes'):
323 323 return True
324 324 if ok.lower() in ('n', 'no', 'nop', 'nope'):
325 325 return False
326 326 retries = retries - 1
327 327 if retries < 0:
328 328 raise IOError
329 329 print(complaint)
330 330
331 331 # propagated from mercurial documentation
332 332 ui_sections = [
333 333 'alias', 'auth',
334 334 'decode/encode', 'defaults',
335 335 'diff', 'email',
336 336 'extensions', 'format',
337 337 'merge-patterns', 'merge-tools',
338 338 'hooks', 'http_proxy',
339 339 'smtp', 'patch',
340 340 'paths', 'profiling',
341 341 'server', 'trusted',
342 342 'ui', 'web', ]
343 343
344 344
345 345 def config_data_from_db(clear_session=True, repo=None):
346 346 """
347 347 Read the configuration data from the database and return configuration
348 348 tuples.
349 349 """
350 350 from rhodecode.model.settings import VcsSettingsModel
351 351
352 352 config = []
353 353
354 354 sa = meta.Session()
355 355 settings_model = VcsSettingsModel(repo=repo, sa=sa)
356 356
357 357 ui_settings = settings_model.get_ui_settings()
358 358
359 ui_data = []
359 360 for setting in ui_settings:
360 361 if setting.active:
361 log.debug(
362 'settings ui from db: [%s] %s=%s',
363 setting.section, setting.key, setting.value)
362 ui_data.append((setting.section, setting.key, setting.value))
364 363 config.append((
365 364 safe_str(setting.section), safe_str(setting.key),
366 365 safe_str(setting.value)))
367 366 if setting.key == 'push_ssl':
368 367 # force set push_ssl requirement to False, rhodecode
369 368 # handles that
370 369 config.append((
371 370 safe_str(setting.section), safe_str(setting.key), False))
371 log.debug(
372 'settings ui from db: %s',
373 ','.join(map(lambda s: '[{}] {}={}'.format(*s), ui_data)))
372 374 if clear_session:
373 375 meta.Session.remove()
374 376
375 377 # TODO: mikhail: probably it makes no sense to re-read hooks information.
376 378 # It's already there and activated/deactivated
377 379 skip_entries = []
378 380 enabled_hook_classes = get_enabled_hook_classes(ui_settings)
379 381 if 'pull' not in enabled_hook_classes:
380 382 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PULL))
381 383 if 'push' not in enabled_hook_classes:
382 384 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PUSH))
383 385 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRETX_PUSH))
384 386 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PUSH_KEY))
385 387
386 388 config = [entry for entry in config if entry[:2] not in skip_entries]
387 389
388 390 return config
389 391
390 392
391 393 def make_db_config(clear_session=True, repo=None):
392 394 """
393 395 Create a :class:`Config` instance based on the values in the database.
394 396 """
395 397 config = Config()
396 398 config_data = config_data_from_db(clear_session=clear_session, repo=repo)
397 399 for section, option, value in config_data:
398 400 config.set(section, option, value)
399 401 return config
400 402
401 403
402 404 def get_enabled_hook_classes(ui_settings):
403 405 """
404 406 Return the enabled hook classes.
405 407
406 408 :param ui_settings: List of ui_settings as returned
407 409 by :meth:`VcsSettingsModel.get_ui_settings`
408 410
409 411 :return: a list with the enabled hook classes. The order is not guaranteed.
410 412 :rtype: list
411 413 """
412 414 enabled_hooks = []
413 415 active_hook_keys = [
414 416 key for section, key, value, active in ui_settings
415 417 if section == 'hooks' and active]
416 418
417 419 hook_names = {
418 420 RhodeCodeUi.HOOK_PUSH: 'push',
419 421 RhodeCodeUi.HOOK_PULL: 'pull',
420 422 RhodeCodeUi.HOOK_REPO_SIZE: 'repo_size'
421 423 }
422 424
423 425 for key in active_hook_keys:
424 426 hook = hook_names.get(key)
425 427 if hook:
426 428 enabled_hooks.append(hook)
427 429
428 430 return enabled_hooks
429 431
430 432
431 433 def set_rhodecode_config(config):
432 434 """
433 435 Updates pyramid config with new settings from database
434 436
435 437 :param config:
436 438 """
437 439 from rhodecode.model.settings import SettingsModel
438 440 app_settings = SettingsModel().get_all_settings()
439 441
440 442 for k, v in app_settings.items():
441 443 config[k] = v
442 444
443 445
444 446 def get_rhodecode_realm():
445 447 """
446 448 Return the rhodecode realm from database.
447 449 """
448 450 from rhodecode.model.settings import SettingsModel
449 451 realm = SettingsModel().get_setting_by_name('realm')
450 452 return safe_str(realm.app_settings_value)
451 453
452 454
453 455 def get_rhodecode_base_path():
454 456 """
455 457 Returns the base path. The base path is the filesystem path which points
456 458 to the repository store.
457 459 """
458 460 from rhodecode.model.settings import SettingsModel
459 461 paths_ui = SettingsModel().get_ui_by_section_and_key('paths', '/')
460 462 return safe_str(paths_ui.ui_value)
461 463
462 464
463 465 def map_groups(path):
464 466 """
465 467 Given a full path to a repository, create all nested groups that this
466 468 repo is inside. This function creates parent-child relationships between
467 469 groups and creates default perms for all new groups.
468 470
469 471 :param paths: full path to repository
470 472 """
471 473 from rhodecode.model.repo_group import RepoGroupModel
472 474 sa = meta.Session()
473 475 groups = path.split(Repository.NAME_SEP)
474 476 parent = None
475 477 group = None
476 478
477 479 # last element is repo in nested groups structure
478 480 groups = groups[:-1]
479 481 rgm = RepoGroupModel(sa)
480 482 owner = User.get_first_super_admin()
481 483 for lvl, group_name in enumerate(groups):
482 484 group_name = '/'.join(groups[:lvl] + [group_name])
483 485 group = RepoGroup.get_by_group_name(group_name)
484 486 desc = '%s group' % group_name
485 487
486 488 # skip folders that are now removed repos
487 489 if REMOVED_REPO_PAT.match(group_name):
488 490 break
489 491
490 492 if group is None:
491 493 log.debug('creating group level: %s group_name: %s',
492 494 lvl, group_name)
493 495 group = RepoGroup(group_name, parent)
494 496 group.group_description = desc
495 497 group.user = owner
496 498 sa.add(group)
497 499 perm_obj = rgm._create_default_perms(group)
498 500 sa.add(perm_obj)
499 501 sa.flush()
500 502
501 503 parent = group
502 504 return group
503 505
504 506
505 507 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
506 508 """
507 509 maps all repos given in initial_repo_list, non existing repositories
508 510 are created, if remove_obsolete is True it also checks for db entries
509 511 that are not in initial_repo_list and removes them.
510 512
511 513 :param initial_repo_list: list of repositories found by scanning methods
512 514 :param remove_obsolete: check for obsolete entries in database
513 515 """
514 516 from rhodecode.model.repo import RepoModel
515 517 from rhodecode.model.scm import ScmModel
516 518 from rhodecode.model.repo_group import RepoGroupModel
517 519 from rhodecode.model.settings import SettingsModel
518 520
519 521 sa = meta.Session()
520 522 repo_model = RepoModel()
521 523 user = User.get_first_super_admin()
522 524 added = []
523 525
524 526 # creation defaults
525 527 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
526 528 enable_statistics = defs.get('repo_enable_statistics')
527 529 enable_locking = defs.get('repo_enable_locking')
528 530 enable_downloads = defs.get('repo_enable_downloads')
529 531 private = defs.get('repo_private')
530 532
531 533 for name, repo in initial_repo_list.items():
532 534 group = map_groups(name)
533 535 unicode_name = safe_unicode(name)
534 536 db_repo = repo_model.get_by_repo_name(unicode_name)
535 537 # found repo that is on filesystem not in RhodeCode database
536 538 if not db_repo:
537 539 log.info('repository %s not found, creating now', name)
538 540 added.append(name)
539 541 desc = (repo.description
540 542 if repo.description != 'unknown'
541 543 else '%s repository' % name)
542 544
543 545 db_repo = repo_model._create_repo(
544 546 repo_name=name,
545 547 repo_type=repo.alias,
546 548 description=desc,
547 549 repo_group=getattr(group, 'group_id', None),
548 550 owner=user,
549 551 enable_locking=enable_locking,
550 552 enable_downloads=enable_downloads,
551 553 enable_statistics=enable_statistics,
552 554 private=private,
553 555 state=Repository.STATE_CREATED
554 556 )
555 557 sa.commit()
556 558 # we added that repo just now, and make sure we updated server info
557 559 if db_repo.repo_type == 'git':
558 560 git_repo = db_repo.scm_instance()
559 561 # update repository server-info
560 562 log.debug('Running update server info')
561 563 git_repo._update_server_info()
562 564
563 565 db_repo.update_commit_cache()
564 566
565 567 config = db_repo._config
566 568 config.set('extensions', 'largefiles', '')
567 569 ScmModel().install_hooks(
568 570 db_repo.scm_instance(config=config),
569 571 repo_type=db_repo.repo_type)
570 572
571 573 removed = []
572 574 if remove_obsolete:
573 575 # remove from database those repositories that are not in the filesystem
574 576 for repo in sa.query(Repository).all():
575 577 if repo.repo_name not in initial_repo_list.keys():
576 578 log.debug("Removing non-existing repository found in db `%s`",
577 579 repo.repo_name)
578 580 try:
579 581 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
580 582 sa.commit()
581 583 removed.append(repo.repo_name)
582 584 except Exception:
583 585 # don't hold further removals on error
584 586 log.error(traceback.format_exc())
585 587 sa.rollback()
586 588
587 589 def splitter(full_repo_name):
588 590 _parts = full_repo_name.rsplit(RepoGroup.url_sep(), 1)
589 591 gr_name = None
590 592 if len(_parts) == 2:
591 593 gr_name = _parts[0]
592 594 return gr_name
593 595
594 596 initial_repo_group_list = [splitter(x) for x in
595 597 initial_repo_list.keys() if splitter(x)]
596 598
597 599 # remove from database those repository groups that are not in the
598 600 # filesystem due to parent child relationships we need to delete them
599 601 # in a specific order of most nested first
600 602 all_groups = [x.group_name for x in sa.query(RepoGroup).all()]
601 603 nested_sort = lambda gr: len(gr.split('/'))
602 604 for group_name in sorted(all_groups, key=nested_sort, reverse=True):
603 605 if group_name not in initial_repo_group_list:
604 606 repo_group = RepoGroup.get_by_group_name(group_name)
605 607 if (repo_group.children.all() or
606 608 not RepoGroupModel().check_exist_filesystem(
607 609 group_name=group_name, exc_on_failure=False)):
608 610 continue
609 611
610 612 log.info(
611 613 'Removing non-existing repository group found in db `%s`',
612 614 group_name)
613 615 try:
614 616 RepoGroupModel(sa).delete(group_name, fs_remove=False)
615 617 sa.commit()
616 618 removed.append(group_name)
617 619 except Exception:
618 620 # don't hold further removals on error
619 621 log.exception(
620 622 'Unable to remove repository group `%s`',
621 623 group_name)
622 624 sa.rollback()
623 625 raise
624 626
625 627 return added, removed
626 628
627 629
628 630 def load_rcextensions(root_path):
629 631 import rhodecode
630 632 from rhodecode.config import conf
631 633
632 634 path = os.path.join(root_path, 'rcextensions', '__init__.py')
633 635 if os.path.isfile(path):
634 636 rcext = create_module('rc', path)
635 637 EXT = rhodecode.EXTENSIONS = rcext
636 638 log.debug('Found rcextensions now loading %s...', rcext)
637 639
638 640 # Additional mappings that are not present in the pygments lexers
639 641 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
640 642
641 643 # auto check if the module is not missing any data, set to default if is
642 644 # this will help autoupdate new feature of rcext module
643 645 #from rhodecode.config import rcextensions
644 646 #for k in dir(rcextensions):
645 647 # if not k.startswith('_') and not hasattr(EXT, k):
646 648 # setattr(EXT, k, getattr(rcextensions, k))
647 649
648 650
649 651 def get_custom_lexer(extension):
650 652 """
651 653 returns a custom lexer if it is defined in rcextensions module, or None
652 654 if there's no custom lexer defined
653 655 """
654 656 import rhodecode
655 657 from pygments import lexers
656 658
657 659 # custom override made by RhodeCode
658 660 if extension in ['mako']:
659 661 return lexers.get_lexer_by_name('html+mako')
660 662
661 663 # check if we didn't define this extension as other lexer
662 664 extensions = rhodecode.EXTENSIONS and getattr(rhodecode.EXTENSIONS, 'EXTRA_LEXERS', None)
663 665 if extensions and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
664 666 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
665 667 return lexers.get_lexer_by_name(_lexer_name)
666 668
667 669
668 670 #==============================================================================
669 671 # TEST FUNCTIONS AND CREATORS
670 672 #==============================================================================
671 673 def create_test_index(repo_location, config):
672 674 """
673 675 Makes default test index.
674 676 """
675 677 import rc_testdata
676 678
677 679 rc_testdata.extract_search_index(
678 680 'vcs_search_index', os.path.dirname(config['search.location']))
679 681
680 682
681 683 def create_test_directory(test_path):
682 684 """
683 685 Create test directory if it doesn't exist.
684 686 """
685 687 if not os.path.isdir(test_path):
686 688 log.debug('Creating testdir %s', test_path)
687 689 os.makedirs(test_path)
688 690
689 691
690 692 def create_test_database(test_path, config):
691 693 """
692 694 Makes a fresh database.
693 695 """
694 696 from rhodecode.lib.db_manage import DbManage
695 697
696 698 # PART ONE create db
697 699 dbconf = config['sqlalchemy.db1.url']
698 700 log.debug('making test db %s', dbconf)
699 701
700 702 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
701 703 tests=True, cli_args={'force_ask': True})
702 704 dbmanage.create_tables(override=True)
703 705 dbmanage.set_db_version()
704 706 # for tests dynamically set new root paths based on generated content
705 707 dbmanage.create_settings(dbmanage.config_prompt(test_path))
706 708 dbmanage.create_default_user()
707 709 dbmanage.create_test_admin_and_users()
708 710 dbmanage.create_permissions()
709 711 dbmanage.populate_default_permissions()
710 712 Session().commit()
711 713
712 714
713 715 def create_test_repositories(test_path, config):
714 716 """
715 717 Creates test repositories in the temporary directory. Repositories are
716 718 extracted from archives within the rc_testdata package.
717 719 """
718 720 import rc_testdata
719 721 from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO
720 722
721 723 log.debug('making test vcs repositories')
722 724
723 725 idx_path = config['search.location']
724 726 data_path = config['cache_dir']
725 727
726 728 # clean index and data
727 729 if idx_path and os.path.exists(idx_path):
728 730 log.debug('remove %s', idx_path)
729 731 shutil.rmtree(idx_path)
730 732
731 733 if data_path and os.path.exists(data_path):
732 734 log.debug('remove %s', data_path)
733 735 shutil.rmtree(data_path)
734 736
735 737 rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO))
736 738 rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO))
737 739
738 740 # Note: Subversion is in the process of being integrated with the system,
739 741 # until we have a properly packed version of the test svn repository, this
740 742 # tries to copy over the repo from a package "rc_testdata"
741 743 svn_repo_path = rc_testdata.get_svn_repo_archive()
742 744 with tarfile.open(svn_repo_path) as tar:
743 745 tar.extractall(jn(test_path, SVN_REPO))
744 746
745 747
746 748 def password_changed(auth_user, session):
747 749 # Never report password change in case of default user or anonymous user.
748 750 if auth_user.username == User.DEFAULT_USER or auth_user.user_id is None:
749 751 return False
750 752
751 753 password_hash = md5(auth_user.password) if auth_user.password else None
752 754 rhodecode_user = session.get('rhodecode_user', {})
753 755 session_password_hash = rhodecode_user.get('password', '')
754 756 return password_hash != session_password_hash
755 757
756 758
757 759 def read_opensource_licenses():
758 760 global _license_cache
759 761
760 762 if not _license_cache:
761 763 licenses = pkg_resources.resource_string(
762 764 'rhodecode', 'config/licenses.json')
763 765 _license_cache = json.loads(licenses)
764 766
765 767 return _license_cache
766 768
767 769
768 770 def generate_platform_uuid():
769 771 """
770 772 Generates platform UUID based on it's name
771 773 """
772 774 import platform
773 775
774 776 try:
775 777 uuid_list = [platform.platform()]
776 778 return hashlib.sha256(':'.join(uuid_list)).hexdigest()
777 779 except Exception as e:
778 780 log.error('Failed to generate host uuid: %s' % e)
779 781 return 'UNDEFINED'
General Comments 0
You need to be logged in to leave comments. Login now