Mercurial > kallithea
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 |