##// END OF EJS Templates
import/repo-checks: skip validating storage path in detection of SCMs.
marcink -
r3037:63d95a89 stable
parent child Browse files
Show More
@@ -1,778 +1,782 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 rhodecode.lib.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, 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 '
295 295 'repo group' % repo_group_name)
296 296 return False
297 297
298 298 try:
299 299 # we need to check bare git repos at higher level
300 300 # since we might match branches/hooks/info/objects or possible
301 301 # other things inside bare git repo
302 scm_ = get_scm(os.path.dirname(full_path))
303 log.debug('path: %s is a vcs object:%s, not valid '
304 'repo group' % (full_path, scm_))
302 maybe_repo = os.path.dirname(full_path)
303 if maybe_repo == base_path:
304 # skip root level repo check, we know root location CANNOT BE a repo group
305 return False
306
307 scm_ = get_scm(maybe_repo)
308 log.debug('path: %s is a vcs object:%s, not valid repo group', full_path, scm_)
305 309 return False
306 310 except VCSError:
307 311 pass
308 312
309 313 # check if it's a valid path
310 314 if skip_path_check or os.path.isdir(full_path):
311 315 log.debug('path: %s is a valid repo group !', full_path)
312 316 return True
313 317
314 318 log.debug('path: %s is not a valid repo group !', full_path)
315 319 return False
316 320
317 321
318 322 def ask_ok(prompt, retries=4, complaint='[y]es or [n]o please!'):
319 323 while True:
320 324 ok = raw_input(prompt)
321 325 if ok.lower() in ('y', 'ye', 'yes'):
322 326 return True
323 327 if ok.lower() in ('n', 'no', 'nop', 'nope'):
324 328 return False
325 329 retries = retries - 1
326 330 if retries < 0:
327 331 raise IOError
328 332 print(complaint)
329 333
330 334 # propagated from mercurial documentation
331 335 ui_sections = [
332 336 'alias', 'auth',
333 337 'decode/encode', 'defaults',
334 338 'diff', 'email',
335 339 'extensions', 'format',
336 340 'merge-patterns', 'merge-tools',
337 341 'hooks', 'http_proxy',
338 342 'smtp', 'patch',
339 343 'paths', 'profiling',
340 344 'server', 'trusted',
341 345 'ui', 'web', ]
342 346
343 347
344 348 def config_data_from_db(clear_session=True, repo=None):
345 349 """
346 350 Read the configuration data from the database and return configuration
347 351 tuples.
348 352 """
349 353 from rhodecode.model.settings import VcsSettingsModel
350 354
351 355 config = []
352 356
353 357 sa = meta.Session()
354 358 settings_model = VcsSettingsModel(repo=repo, sa=sa)
355 359
356 360 ui_settings = settings_model.get_ui_settings()
357 361
358 362 ui_data = []
359 363 for setting in ui_settings:
360 364 if setting.active:
361 365 ui_data.append((setting.section, setting.key, setting.value))
362 366 config.append((
363 367 safe_str(setting.section), safe_str(setting.key),
364 368 safe_str(setting.value)))
365 369 if setting.key == 'push_ssl':
366 370 # force set push_ssl requirement to False, rhodecode
367 371 # handles that
368 372 config.append((
369 373 safe_str(setting.section), safe_str(setting.key), False))
370 374 log.debug(
371 375 'settings ui from db: %s',
372 376 ','.join(map(lambda s: '[{}] {}={}'.format(*s), ui_data)))
373 377 if clear_session:
374 378 meta.Session.remove()
375 379
376 380 # TODO: mikhail: probably it makes no sense to re-read hooks information.
377 381 # It's already there and activated/deactivated
378 382 skip_entries = []
379 383 enabled_hook_classes = get_enabled_hook_classes(ui_settings)
380 384 if 'pull' not in enabled_hook_classes:
381 385 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PULL))
382 386 if 'push' not in enabled_hook_classes:
383 387 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PUSH))
384 388 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRETX_PUSH))
385 389 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PUSH_KEY))
386 390
387 391 config = [entry for entry in config if entry[:2] not in skip_entries]
388 392
389 393 return config
390 394
391 395
392 396 def make_db_config(clear_session=True, repo=None):
393 397 """
394 398 Create a :class:`Config` instance based on the values in the database.
395 399 """
396 400 config = Config()
397 401 config_data = config_data_from_db(clear_session=clear_session, repo=repo)
398 402 for section, option, value in config_data:
399 403 config.set(section, option, value)
400 404 return config
401 405
402 406
403 407 def get_enabled_hook_classes(ui_settings):
404 408 """
405 409 Return the enabled hook classes.
406 410
407 411 :param ui_settings: List of ui_settings as returned
408 412 by :meth:`VcsSettingsModel.get_ui_settings`
409 413
410 414 :return: a list with the enabled hook classes. The order is not guaranteed.
411 415 :rtype: list
412 416 """
413 417 enabled_hooks = []
414 418 active_hook_keys = [
415 419 key for section, key, value, active in ui_settings
416 420 if section == 'hooks' and active]
417 421
418 422 hook_names = {
419 423 RhodeCodeUi.HOOK_PUSH: 'push',
420 424 RhodeCodeUi.HOOK_PULL: 'pull',
421 425 RhodeCodeUi.HOOK_REPO_SIZE: 'repo_size'
422 426 }
423 427
424 428 for key in active_hook_keys:
425 429 hook = hook_names.get(key)
426 430 if hook:
427 431 enabled_hooks.append(hook)
428 432
429 433 return enabled_hooks
430 434
431 435
432 436 def set_rhodecode_config(config):
433 437 """
434 438 Updates pyramid config with new settings from database
435 439
436 440 :param config:
437 441 """
438 442 from rhodecode.model.settings import SettingsModel
439 443 app_settings = SettingsModel().get_all_settings()
440 444
441 445 for k, v in app_settings.items():
442 446 config[k] = v
443 447
444 448
445 449 def get_rhodecode_realm():
446 450 """
447 451 Return the rhodecode realm from database.
448 452 """
449 453 from rhodecode.model.settings import SettingsModel
450 454 realm = SettingsModel().get_setting_by_name('realm')
451 455 return safe_str(realm.app_settings_value)
452 456
453 457
454 458 def get_rhodecode_base_path():
455 459 """
456 460 Returns the base path. The base path is the filesystem path which points
457 461 to the repository store.
458 462 """
459 463 from rhodecode.model.settings import SettingsModel
460 464 paths_ui = SettingsModel().get_ui_by_section_and_key('paths', '/')
461 465 return safe_str(paths_ui.ui_value)
462 466
463 467
464 468 def map_groups(path):
465 469 """
466 470 Given a full path to a repository, create all nested groups that this
467 471 repo is inside. This function creates parent-child relationships between
468 472 groups and creates default perms for all new groups.
469 473
470 474 :param paths: full path to repository
471 475 """
472 476 from rhodecode.model.repo_group import RepoGroupModel
473 477 sa = meta.Session()
474 478 groups = path.split(Repository.NAME_SEP)
475 479 parent = None
476 480 group = None
477 481
478 482 # last element is repo in nested groups structure
479 483 groups = groups[:-1]
480 484 rgm = RepoGroupModel(sa)
481 485 owner = User.get_first_super_admin()
482 486 for lvl, group_name in enumerate(groups):
483 487 group_name = '/'.join(groups[:lvl] + [group_name])
484 488 group = RepoGroup.get_by_group_name(group_name)
485 489 desc = '%s group' % group_name
486 490
487 491 # skip folders that are now removed repos
488 492 if REMOVED_REPO_PAT.match(group_name):
489 493 break
490 494
491 495 if group is None:
492 496 log.debug('creating group level: %s group_name: %s',
493 497 lvl, group_name)
494 498 group = RepoGroup(group_name, parent)
495 499 group.group_description = desc
496 500 group.user = owner
497 501 sa.add(group)
498 502 perm_obj = rgm._create_default_perms(group)
499 503 sa.add(perm_obj)
500 504 sa.flush()
501 505
502 506 parent = group
503 507 return group
504 508
505 509
506 510 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
507 511 """
508 512 maps all repos given in initial_repo_list, non existing repositories
509 513 are created, if remove_obsolete is True it also checks for db entries
510 514 that are not in initial_repo_list and removes them.
511 515
512 516 :param initial_repo_list: list of repositories found by scanning methods
513 517 :param remove_obsolete: check for obsolete entries in database
514 518 """
515 519 from rhodecode.model.repo import RepoModel
516 520 from rhodecode.model.repo_group import RepoGroupModel
517 521 from rhodecode.model.settings import SettingsModel
518 522
519 523 sa = meta.Session()
520 524 repo_model = RepoModel()
521 525 user = User.get_first_super_admin()
522 526 added = []
523 527
524 528 # creation defaults
525 529 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
526 530 enable_statistics = defs.get('repo_enable_statistics')
527 531 enable_locking = defs.get('repo_enable_locking')
528 532 enable_downloads = defs.get('repo_enable_downloads')
529 533 private = defs.get('repo_private')
530 534
531 535 for name, repo in initial_repo_list.items():
532 536 group = map_groups(name)
533 537 unicode_name = safe_unicode(name)
534 538 db_repo = repo_model.get_by_repo_name(unicode_name)
535 539 # found repo that is on filesystem not in RhodeCode database
536 540 if not db_repo:
537 541 log.info('repository %s not found, creating now', name)
538 542 added.append(name)
539 543 desc = (repo.description
540 544 if repo.description != 'unknown'
541 545 else '%s repository' % name)
542 546
543 547 db_repo = repo_model._create_repo(
544 548 repo_name=name,
545 549 repo_type=repo.alias,
546 550 description=desc,
547 551 repo_group=getattr(group, 'group_id', None),
548 552 owner=user,
549 553 enable_locking=enable_locking,
550 554 enable_downloads=enable_downloads,
551 555 enable_statistics=enable_statistics,
552 556 private=private,
553 557 state=Repository.STATE_CREATED
554 558 )
555 559 sa.commit()
556 560 # we added that repo just now, and make sure we updated server info
557 561 if db_repo.repo_type == 'git':
558 562 git_repo = db_repo.scm_instance()
559 563 # update repository server-info
560 564 log.debug('Running update server info')
561 565 git_repo._update_server_info()
562 566
563 567 db_repo.update_commit_cache()
564 568
565 569 config = db_repo._config
566 570 config.set('extensions', 'largefiles', '')
567 571 repo = db_repo.scm_instance(config=config)
568 572 repo.install_hooks()
569 573
570 574 removed = []
571 575 if remove_obsolete:
572 576 # remove from database those repositories that are not in the filesystem
573 577 for repo in sa.query(Repository).all():
574 578 if repo.repo_name not in initial_repo_list.keys():
575 579 log.debug("Removing non-existing repository found in db `%s`",
576 580 repo.repo_name)
577 581 try:
578 582 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
579 583 sa.commit()
580 584 removed.append(repo.repo_name)
581 585 except Exception:
582 586 # don't hold further removals on error
583 587 log.error(traceback.format_exc())
584 588 sa.rollback()
585 589
586 590 def splitter(full_repo_name):
587 591 _parts = full_repo_name.rsplit(RepoGroup.url_sep(), 1)
588 592 gr_name = None
589 593 if len(_parts) == 2:
590 594 gr_name = _parts[0]
591 595 return gr_name
592 596
593 597 initial_repo_group_list = [splitter(x) for x in
594 598 initial_repo_list.keys() if splitter(x)]
595 599
596 600 # remove from database those repository groups that are not in the
597 601 # filesystem due to parent child relationships we need to delete them
598 602 # in a specific order of most nested first
599 603 all_groups = [x.group_name for x in sa.query(RepoGroup).all()]
600 604 nested_sort = lambda gr: len(gr.split('/'))
601 605 for group_name in sorted(all_groups, key=nested_sort, reverse=True):
602 606 if group_name not in initial_repo_group_list:
603 607 repo_group = RepoGroup.get_by_group_name(group_name)
604 608 if (repo_group.children.all() or
605 609 not RepoGroupModel().check_exist_filesystem(
606 610 group_name=group_name, exc_on_failure=False)):
607 611 continue
608 612
609 613 log.info(
610 614 'Removing non-existing repository group found in db `%s`',
611 615 group_name)
612 616 try:
613 617 RepoGroupModel(sa).delete(group_name, fs_remove=False)
614 618 sa.commit()
615 619 removed.append(group_name)
616 620 except Exception:
617 621 # don't hold further removals on error
618 622 log.exception(
619 623 'Unable to remove repository group `%s`',
620 624 group_name)
621 625 sa.rollback()
622 626 raise
623 627
624 628 return added, removed
625 629
626 630
627 631 def load_rcextensions(root_path):
628 632 import rhodecode
629 633 from rhodecode.config import conf
630 634
631 635 path = os.path.join(root_path, 'rcextensions', '__init__.py')
632 636 if os.path.isfile(path):
633 637 rcext = create_module('rc', path)
634 638 EXT = rhodecode.EXTENSIONS = rcext
635 639 log.debug('Found rcextensions now loading %s...', rcext)
636 640
637 641 # Additional mappings that are not present in the pygments lexers
638 642 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
639 643
640 644 # auto check if the module is not missing any data, set to default if is
641 645 # this will help autoupdate new feature of rcext module
642 646 #from rhodecode.config import rcextensions
643 647 #for k in dir(rcextensions):
644 648 # if not k.startswith('_') and not hasattr(EXT, k):
645 649 # setattr(EXT, k, getattr(rcextensions, k))
646 650
647 651
648 652 def get_custom_lexer(extension):
649 653 """
650 654 returns a custom lexer if it is defined in rcextensions module, or None
651 655 if there's no custom lexer defined
652 656 """
653 657 import rhodecode
654 658 from pygments import lexers
655 659
656 660 # custom override made by RhodeCode
657 661 if extension in ['mako']:
658 662 return lexers.get_lexer_by_name('html+mako')
659 663
660 664 # check if we didn't define this extension as other lexer
661 665 extensions = rhodecode.EXTENSIONS and getattr(rhodecode.EXTENSIONS, 'EXTRA_LEXERS', None)
662 666 if extensions and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
663 667 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
664 668 return lexers.get_lexer_by_name(_lexer_name)
665 669
666 670
667 671 #==============================================================================
668 672 # TEST FUNCTIONS AND CREATORS
669 673 #==============================================================================
670 674 def create_test_index(repo_location, config):
671 675 """
672 676 Makes default test index.
673 677 """
674 678 import rc_testdata
675 679
676 680 rc_testdata.extract_search_index(
677 681 'vcs_search_index', os.path.dirname(config['search.location']))
678 682
679 683
680 684 def create_test_directory(test_path):
681 685 """
682 686 Create test directory if it doesn't exist.
683 687 """
684 688 if not os.path.isdir(test_path):
685 689 log.debug('Creating testdir %s', test_path)
686 690 os.makedirs(test_path)
687 691
688 692
689 693 def create_test_database(test_path, config):
690 694 """
691 695 Makes a fresh database.
692 696 """
693 697 from rhodecode.lib.db_manage import DbManage
694 698
695 699 # PART ONE create db
696 700 dbconf = config['sqlalchemy.db1.url']
697 701 log.debug('making test db %s', dbconf)
698 702
699 703 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
700 704 tests=True, cli_args={'force_ask': True})
701 705 dbmanage.create_tables(override=True)
702 706 dbmanage.set_db_version()
703 707 # for tests dynamically set new root paths based on generated content
704 708 dbmanage.create_settings(dbmanage.config_prompt(test_path))
705 709 dbmanage.create_default_user()
706 710 dbmanage.create_test_admin_and_users()
707 711 dbmanage.create_permissions()
708 712 dbmanage.populate_default_permissions()
709 713 Session().commit()
710 714
711 715
712 716 def create_test_repositories(test_path, config):
713 717 """
714 718 Creates test repositories in the temporary directory. Repositories are
715 719 extracted from archives within the rc_testdata package.
716 720 """
717 721 import rc_testdata
718 722 from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO
719 723
720 724 log.debug('making test vcs repositories')
721 725
722 726 idx_path = config['search.location']
723 727 data_path = config['cache_dir']
724 728
725 729 # clean index and data
726 730 if idx_path and os.path.exists(idx_path):
727 731 log.debug('remove %s', idx_path)
728 732 shutil.rmtree(idx_path)
729 733
730 734 if data_path and os.path.exists(data_path):
731 735 log.debug('remove %s', data_path)
732 736 shutil.rmtree(data_path)
733 737
734 738 rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO))
735 739 rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO))
736 740
737 741 # Note: Subversion is in the process of being integrated with the system,
738 742 # until we have a properly packed version of the test svn repository, this
739 743 # tries to copy over the repo from a package "rc_testdata"
740 744 svn_repo_path = rc_testdata.get_svn_repo_archive()
741 745 with tarfile.open(svn_repo_path) as tar:
742 746 tar.extractall(jn(test_path, SVN_REPO))
743 747
744 748
745 749 def password_changed(auth_user, session):
746 750 # Never report password change in case of default user or anonymous user.
747 751 if auth_user.username == User.DEFAULT_USER or auth_user.user_id is None:
748 752 return False
749 753
750 754 password_hash = md5(auth_user.password) if auth_user.password else None
751 755 rhodecode_user = session.get('rhodecode_user', {})
752 756 session_password_hash = rhodecode_user.get('password', '')
753 757 return password_hash != session_password_hash
754 758
755 759
756 760 def read_opensource_licenses():
757 761 global _license_cache
758 762
759 763 if not _license_cache:
760 764 licenses = pkg_resources.resource_string(
761 765 'rhodecode', 'config/licenses.json')
762 766 _license_cache = json.loads(licenses)
763 767
764 768 return _license_cache
765 769
766 770
767 771 def generate_platform_uuid():
768 772 """
769 773 Generates platform UUID based on it's name
770 774 """
771 775 import platform
772 776
773 777 try:
774 778 uuid_list = [platform.platform()]
775 779 return hashlib.sha256(':'.join(uuid_list)).hexdigest()
776 780 except Exception as e:
777 781 log.error('Failed to generate host uuid: %s' % e)
778 782 return 'UNDEFINED'
General Comments 0
You need to be logged in to leave comments. Login now