comparison rhodecode/lib/utils.py @ 4116:ffd45b185016 rhodecode-2.2.5-gpl

Imported some of the GPLv3'd changes from RhodeCode v2.2.5. This imports changes between changesets 21af6c4eab3d and 6177597791c2 in RhodeCode's original repository, including only changes to Python files and HTML. RhodeCode clearly licensed its changes to these files under GPLv3 in their /LICENSE file, which states the following: The Python code and integrated HTML are licensed under the GPLv3 license. (See: https://code.rhodecode.com/rhodecode/files/v2.2.5/LICENSE or http://web.archive.org/web/20140512193334/https://code.rhodecode.com/rhodecode/files/f3b123159901f15426d18e3dc395e8369f70ebe0/LICENSE for an online copy of that LICENSE file) Conservancy reviewed these changes and confirmed that they can be licensed as a whole to the Kallithea project under GPLv3-only. While some of the contents committed herein are clearly licensed GPLv3-or-later, on the whole we must assume the are GPLv3-only, since the statement above from RhodeCode indicates that they intend GPLv3-only as their license, per GPLv3ยง14 and other relevant sections of GPLv3.
author Bradley M. Kuhn <bkuhn@sfconservancy.org>
date Wed, 02 Jul 2014 19:03:13 -0400
parents 55dbc440878b
children 7e5f8c12a3fc
comparison
equal deleted inserted replaced
4115:8b7294a804a0 4116:ffd45b185016
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
5
6 Utilities library for RhodeCode
7
8 :created_on: Apr 18, 2010
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify 2 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by 3 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or 4 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version. 5 # (at your option) any later version.
17 # 6 #
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details. 10 # GNU General Public License for more details.
22 # 11 #
23 # You should have received a copy of the GNU General Public License 12 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>. 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
15 rhodecode.lib.utils
16 ~~~~~~~~~~~~~~~~~~~
17
18 Utilities library for RhodeCode
19
20 :created_on: Apr 18, 2010
21 :author: marcink
22 :copyright: (c) 2013 RhodeCode GmbH.
23 :license: GPLv3, see LICENSE for more details.
24 """
25 25
26 import os 26 import os
27 import re 27 import re
28 import logging 28 import logging
29 import datetime 29 import datetime
38 from os.path import dirname as dn, join as jn 38 from os.path import dirname as dn, join as jn
39 39
40 from paste.script.command import Command, BadCommand 40 from paste.script.command import Command, BadCommand
41 41
42 from webhelpers.text import collapse, remove_formatting, strip_tags 42 from webhelpers.text import collapse, remove_formatting, strip_tags
43 from beaker.cache import _cache_decorate
43 44
44 from rhodecode.lib.vcs import get_backend 45 from rhodecode.lib.vcs import get_backend
45 from rhodecode.lib.vcs.backends.base import BaseChangeset 46 from rhodecode.lib.vcs.backends.base import BaseChangeset
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty 47 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 from rhodecode.lib.vcs.utils.hgcompat import ui, config 48 from rhodecode.lib.vcs.utils.hgcompat import ui, config
52 53
53 from rhodecode.model import meta 54 from rhodecode.model import meta
54 from rhodecode.model.db import Repository, User, RhodeCodeUi, \ 55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
55 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation, UserGroup 56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation, UserGroup
56 from rhodecode.model.meta import Session 57 from rhodecode.model.meta import Session
57 from rhodecode.model.repos_group import ReposGroupModel 58 from rhodecode.model.repo_group import RepoGroupModel
58 from rhodecode.lib.utils2 import safe_str, safe_unicode, get_current_rhodecode_user 59 from rhodecode.lib.utils2 import safe_str, safe_unicode, get_current_rhodecode_user
59 from rhodecode.lib.vcs.utils.fakemod import create_module 60 from rhodecode.lib.vcs.utils.fakemod import create_module
60 from rhodecode.model.users_group import UserGroupModel 61 from rhodecode.model.user_group import UserGroupModel
61 62
62 log = logging.getLogger(__name__) 63 log = logging.getLogger(__name__)
63 64
64 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*') 65 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
65 66
108 if _repo: 109 if _repo:
109 _repo = _repo.rstrip('/') 110 _repo = _repo.rstrip('/')
110 return _repo 111 return _repo
111 112
112 113
113 def get_repos_group_slug(request): 114 def get_repo_group_slug(request):
114 _group = request.environ['pylons.routes_dict'].get('group_name') 115 _group = request.environ['pylons.routes_dict'].get('group_name')
115 if _group: 116 if _group:
116 _group = _group.rstrip('/') 117 _group = _group.rstrip('/')
117 return _group 118 return _group
118 119
129 pass 130 pass
130 131
131 return _group 132 return _group
132 133
133 134
135 def _extract_id_from_repo_name(repo_name):
136 if repo_name.startswith('/'):
137 repo_name = repo_name.lstrip('/')
138 by_id_match = re.match(r'^_(\d{1,})', repo_name)
139 if by_id_match:
140 return by_id_match.groups()[0]
141
142
143 def get_repo_by_id(repo_name):
144 """
145 Extracts repo_name by id from special urls. Example url is _11/repo_name
146
147 :param repo_name:
148 :return: repo_name if matched else None
149 """
150 try:
151 _repo_id = _extract_id_from_repo_name(repo_name)
152 if _repo_id:
153 from rhodecode.model.db import Repository
154 return Repository.get(_repo_id).repo_name
155 except Exception:
156 log.debug('Failed to extract repo_name from URL %s' % (
157 traceback.format_exc()))
158 return
159
160
134 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False): 161 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
135 """ 162 """
136 Action logger for various actions made by users 163 Action logger for various actions made by users
137 164
138 :param user: user that made this action, can be a unique username string or 165 :param user: user that made this action, can be a unique username string or
152 # in tmpl context var 179 # in tmpl context var
153 if not ipaddr: 180 if not ipaddr:
154 ipaddr = getattr(get_current_rhodecode_user(), 'ip_addr', '') 181 ipaddr = getattr(get_current_rhodecode_user(), 'ip_addr', '')
155 182
156 try: 183 try:
157 if hasattr(user, 'user_id'): 184 if getattr(user, 'user_id', None):
158 user_obj = User.get(user.user_id) 185 user_obj = User.get(user.user_id)
159 elif isinstance(user, basestring): 186 elif isinstance(user, basestring):
160 user_obj = User.get_by_username(user) 187 user_obj = User.get_by_username(user)
161 else: 188 else:
162 raise Exception('You have to provide a user object or a username') 189 raise Exception('You have to provide a user object or a username')
163 190
164 if hasattr(repo, 'repo_id'): 191 if getattr(repo, 'repo_id', None):
165 repo_obj = Repository.get(repo.repo_id) 192 repo_obj = Repository.get(repo.repo_id)
166 repo_name = repo_obj.repo_name 193 repo_name = repo_obj.repo_name
167 elif isinstance(repo, basestring): 194 elif isinstance(repo, basestring):
168 repo_name = repo.lstrip('/') 195 repo_name = repo.lstrip('/')
169 repo_obj = Repository.get_by_repo_name(repo_name) 196 repo_obj = Repository.get_by_repo_name(repo_name)
259 return True 286 return True
260 except VCSError: 287 except VCSError:
261 return False 288 return False
262 289
263 290
264 def is_valid_repos_group(repos_group_name, base_path, skip_path_check=False): 291 def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False):
265 """ 292 """
266 Returns True if given path is a repository group False otherwise 293 Returns True if given path is a repository group False otherwise
267 294
268 :param repo_name: 295 :param repo_name:
269 :param base_path: 296 :param base_path:
270 """ 297 """
271 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name)) 298 full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name))
272 299
273 # check if it's not a repo 300 # check if it's not a repo
274 if is_valid_repo(repos_group_name, base_path): 301 if is_valid_repo(repo_group_name, base_path):
275 return False 302 return False
276 303
277 try: 304 try:
278 # we need to check bare git repos at higher level 305 # we need to check bare git repos at higher level
279 # since we might match branches/hooks/info/objects or possible 306 # since we might match branches/hooks/info/objects or possible
412 parent = None 439 parent = None
413 group = None 440 group = None
414 441
415 # last element is repo in nested groups structure 442 # last element is repo in nested groups structure
416 groups = groups[:-1] 443 groups = groups[:-1]
417 rgm = ReposGroupModel(sa) 444 rgm = RepoGroupModel(sa)
418 owner = User.get_first_admin() 445 owner = User.get_first_admin()
419 for lvl, group_name in enumerate(groups): 446 for lvl, group_name in enumerate(groups):
420 group_name = '/'.join(groups[:lvl] + [group_name]) 447 group_name = '/'.join(groups[:lvl] + [group_name])
421 group = RepoGroup.get_by_group_name(group_name) 448 group = RepoGroup.get_by_group_name(group_name)
422 desc = '%s group' % group_name 449 desc = '%s group' % group_name
453 for a repo if missing 480 for a repo if missing
454 """ 481 """
455 from rhodecode.model.repo import RepoModel 482 from rhodecode.model.repo import RepoModel
456 from rhodecode.model.scm import ScmModel 483 from rhodecode.model.scm import ScmModel
457 sa = meta.Session() 484 sa = meta.Session()
458 rm = RepoModel() 485 repo_model = RepoModel()
459 user = User.get_first_admin() 486 user = User.get_first_admin()
460 added = [] 487 added = []
461 488
462 ##creation defaults 489 ##creation defaults
463 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True) 490 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
466 enable_downloads = defs.get('repo_enable_downloads') 493 enable_downloads = defs.get('repo_enable_downloads')
467 private = defs.get('repo_private') 494 private = defs.get('repo_private')
468 495
469 for name, repo in initial_repo_list.items(): 496 for name, repo in initial_repo_list.items():
470 group = map_groups(name) 497 group = map_groups(name)
471 db_repo = rm.get_by_repo_name(name) 498 unicode_name = safe_unicode(name)
499 db_repo = repo_model.get_by_repo_name(unicode_name)
472 # found repo that is on filesystem not in RhodeCode database 500 # found repo that is on filesystem not in RhodeCode database
473 if not db_repo: 501 if not db_repo:
474 log.info('repository %s not found, creating now' % name) 502 log.info('repository %s not found, creating now' % name)
475 added.append(name) 503 added.append(name)
476 desc = (repo.description 504 desc = (repo.description
477 if repo.description != 'unknown' 505 if repo.description != 'unknown'
478 else '%s repository' % name) 506 else '%s repository' % name)
479 507
480 new_repo = rm.create_repo( 508 new_repo = repo_model._create_repo(
481 repo_name=name, 509 repo_name=name,
482 repo_type=repo.alias, 510 repo_type=repo.alias,
483 description=desc, 511 description=desc,
484 repos_group=getattr(group, 'group_id', None), 512 repo_group=getattr(group, 'group_id', None),
485 owner=user, 513 owner=user,
486 just_db=True,
487 enable_locking=enable_locking, 514 enable_locking=enable_locking,
488 enable_downloads=enable_downloads, 515 enable_downloads=enable_downloads,
489 enable_statistics=enable_statistics, 516 enable_statistics=enable_statistics,
490 private=private 517 private=private,
518 state=Repository.STATE_CREATED
491 ) 519 )
520 sa.commit()
492 # we added that repo just now, and make sure it has githook 521 # we added that repo just now, and make sure it has githook
493 # installed 522 # installed, and updated server info
494 if new_repo.repo_type == 'git': 523 if new_repo.repo_type == 'git':
495 ScmModel().install_git_hook(new_repo.scm_instance) 524 git_repo = new_repo.scm_instance
525 ScmModel().install_git_hook(git_repo)
526 # update repository server-info
527 log.debug('Running update server info')
528 git_repo._update_server_info()
496 new_repo.update_changeset_cache() 529 new_repo.update_changeset_cache()
497 elif install_git_hook: 530 elif install_git_hook:
498 if db_repo.repo_type == 'git': 531 if db_repo.repo_type == 'git':
499 ScmModel().install_git_hook(db_repo.scm_instance) 532 ScmModel().install_git_hook(db_repo.scm_instance)
500 533
501 sa.commit()
502 removed = [] 534 removed = []
503 if remove_obsolete: 535 if remove_obsolete:
504 # remove from database those repositories that are not in the filesystem 536 # remove from database those repositories that are not in the filesystem
505 for repo in sa.query(Repository).all(): 537 for repo in sa.query(Repository).all():
506 if repo.repo_name not in initial_repo_list.keys(): 538 if repo.repo_name not in initial_repo_list.keys():
568 log.debug('adding extra into INDEX_EXTENSIONS') 600 log.debug('adding extra into INDEX_EXTENSIONS')
569 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', [])) 601 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
570 602
571 # auto check if the module is not missing any data, set to default if is 603 # auto check if the module is not missing any data, set to default if is
572 # this will help autoupdate new feature of rcext module 604 # this will help autoupdate new feature of rcext module
573 from rhodecode.config import rcextensions 605 #from rhodecode.config import rcextensions
574 for k in dir(rcextensions): 606 #for k in dir(rcextensions):
575 if not k.startswith('_') and not hasattr(EXT, k): 607 # if not k.startswith('_') and not hasattr(EXT, k):
576 setattr(EXT, k, getattr(rcextensions, k)) 608 # setattr(EXT, k, getattr(rcextensions, k))
577 609
578 610
579 def get_custom_lexer(extension): 611 def get_custom_lexer(extension):
580 """ 612 """
581 returns a custom lexer if it's defined in rcextensions module, or None 613 returns a custom lexer if it's defined in rcextensions module, or None
637 os.makedirs(repos_test_path) 669 os.makedirs(repos_test_path)
638 670
639 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'], 671 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
640 tests=True) 672 tests=True)
641 dbmanage.create_tables(override=True) 673 dbmanage.create_tables(override=True)
674 # for tests dynamically set new root paths based on generated content
642 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path)) 675 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
643 dbmanage.create_default_user() 676 dbmanage.create_default_user()
644 dbmanage.admin_prompt() 677 dbmanage.admin_prompt()
645 dbmanage.create_permissions() 678 dbmanage.create_permissions()
646 dbmanage.populate_default_permissions() 679 dbmanage.populate_default_permissions()
817 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings" 850 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
818 warnings.warn(msg, Warning, 2) 851 warnings.warn(msg, Warning, 2)
819 log.warning(msg) 852 log.warning(msg)
820 log.debug("Returning JSON wrapped action output") 853 log.debug("Returning JSON wrapped action output")
821 return json.dumps(data, encoding='utf-8') 854 return json.dumps(data, encoding='utf-8')
855
856
857 def conditional_cache(region, prefix, condition, func):
858 """
859
860 Conditional caching function use like::
861 def _c(arg):
862 #heavy computation function
863 return data
864
865 # denpending from condition the compute is wrapped in cache or not
866 compute = conditional_cache('short_term', 'cache_desc', codnition=True, func=func)
867 return compute(arg)
868
869 :param region: name of cache region
870 :param prefix: cache region prefix
871 :param condition: condition for cache to be triggered, and return data cached
872 :param func: wrapped heavy function to compute
873
874 """
875 wrapped = func
876 if condition:
877 log.debug('conditional_cache: True, wrapping call of '
878 'func: %s into %s region cache' % (region, func))
879 wrapped = _cache_decorate((prefix,), None, None, region)(func)
880
881 return wrapped