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