##// END OF EJS Templates
Fixed test_hg_operations test and added concurency test
Fixed test_hg_operations test and added concurency test

File last commit:

r1512:bf263968 merge default
r1529:0b268dd3 beta
Show More
scm.py
410 lines | 13.6 KiB | text/x-python | PythonLexer
rolled back to make transient since got some exceptions on expunge...
r757 # -*- coding: utf-8 -*-
"""
docs updates
r811 rhodecode.model.scm
~~~~~~~~~~~~~~~~~~~
rolled back to make transient since got some exceptions on expunge...
r757
docs updates
r811 Scm model for RhodeCode
rolled back to make transient since got some exceptions on expunge...
r757 :created_on: Apr 9, 2010
:author: marcink
source code cleanup: remove trailing white space, normalize file endings
r1203 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
rolled back to make transient since got some exceptions on expunge...
r757 :license: GPLv3, see COPYING for more details.
"""
fixed license issue #149
r1206 # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
Refactor codes for scm model...
r691 # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
Refactor codes for scm model...
r691 # You should have received a copy of the GNU General Public License
fixed license issue #149
r1206 # along with this program. If not, see <http://www.gnu.org/licenses/>.
rolled back to make transient since got some exceptions on expunge...
r757 import os
import time
import traceback
import logging
Code refactor number 2
r1022 from sqlalchemy.exc import DatabaseError
rolled back to make transient since got some exceptions on expunge...
r757 from vcs import get_backend
added welcome message if no repositories are present in current view
r1437 from vcs.exceptions import RepositoryError
rolled back to make transient since got some exceptions on expunge...
r757 from vcs.utils.lazy import LazyProperty
moved out commit into scm model, and added cache invalidation after commit.
r1311 from vcs.nodes import FileNode
rolled back to make transient since got some exceptions on expunge...
r757
Disable git support due to large problems with dulwich....
r710 from rhodecode import BACKENDS
Refactor codes for scm model...
r691 from rhodecode.lib import helpers as h
Unicode fixes, added safe_str method for global str() operations +better test sandboxing
r1401 from rhodecode.lib import safe_str
Refactor codes for scm model...
r691 from rhodecode.lib.auth import HasRepoPermissionAny
another major code rafactor, reimplemented (almost from scratch)...
r1038 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
Added initial support for creating new nodes in repos
r1483 action_logger, EmptyChangeset
fixed Example celery config to ampq,...
r752 from rhodecode.model import BaseModel
code cleanups
r758 from rhodecode.model.user import UserModel
from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
Implemented fancier top menu for logged and anonymous users...
r784 UserFollowing, UserLog
rolled back to make transient since got some exceptions on expunge...
r757
Refactor codes for scm model...
r691 log = logging.getLogger(__name__)
rolled back to make transient since got some exceptions on expunge...
r757
added action loggers to following repositories,...
r735 class UserTemp(object):
def __init__(self, user_id):
self.user_id = user_id
Fixed repo of Temp user and repo for better logging
r901
def __repr__(self):
return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
#150 fixes for errors on repositories mapped in db but corrupted in filesystem
r1213
added action loggers to following repositories,...
r735 class RepoTemp(object):
def __init__(self, repo_id):
self.repo_id = repo_id
Added icons with numbers of followers and number of forks
r747
Fixed repo of Temp user and repo for better logging
r901 def __repr__(self):
return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 class CachedRepoList(object):
fixed some issues with cache invalidation, and simplified invalidation codes
r1428 def __init__(self, db_repo_list, repos_path, order_by=None):
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 self.db_repo_list = db_repo_list
self.repos_path = repos_path
self.order_by = order_by
self.reversed = (order_by or '').startswith('-')
def __len__(self):
return len(self.db_repo_list)
def __repr__(self):
return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
def __iter__(self):
fixed some issues with cache invalidation, and simplified invalidation codes
r1428 for dbr in self.db_repo_list:
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366
fixed some issues with cache invalidation, and simplified invalidation codes
r1428 scmr = dbr.scm_instance_cached
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366
added welcome message if no repositories are present in current view
r1437 # check permission at this level
if not HasRepoPermissionAny('repository.read', 'repository.write',
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 'repository.admin')(dbr.repo_name,
'get repo check'):
continue
Fixed problem with new repos, and visibility on the main list.
r1380 if scmr is None:
Fixes issue #201...
r1373 log.error('%s this repository is present in database but it '
'cannot be created as an scm instance',
dbr.repo_name)
continue
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366
last_change = scmr.last_change
tip = h.get_changeset_safe(scmr, 'tip')
tmp_d = {}
tmp_d['name'] = dbr.repo_name
tmp_d['name_sort'] = tmp_d['name'].lower()
tmp_d['description'] = dbr.description
tmp_d['description_sort'] = tmp_d['description']
tmp_d['last_change'] = last_change
tmp_d['last_change_sort'] = time.mktime(last_change \
.timetuple())
tmp_d['tip'] = tip.raw_id
tmp_d['tip_sort'] = tip.revision
tmp_d['rev'] = tip.revision
tmp_d['contact'] = dbr.user.full_contact
tmp_d['contact_sort'] = tmp_d['contact']
tmp_d['owner_sort'] = tmp_d['contact']
tmp_d['repo_archives'] = list(scmr._get_archives())
tmp_d['last_msg'] = tip.message
added author to main page tooltip
r1459 tmp_d['author'] = tip.author
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 tmp_d['dbrepo'] = dbr.get_dict()
tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork \
else {}
yield tmp_d
#150 fixes for errors on repositories mapped in db but corrupted in filesystem
r1213
fixed Example celery config to ampq,...
r752 class ScmModel(BaseModel):
docs updates
r811 """Generic Scm Model
Refactor codes for scm model...
r691 """
@LazyProperty
def repos_path(self):
docs updates
r811 """Get's the repositories root path from database
Refactor codes for scm model...
r691 """
docs updates
r811
Refactor codes for scm model...
r691 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
return q.ui_value
another major code rafactor, reimplemented (almost from scratch)...
r1038 def repo_scan(self, repos_path=None):
source code cleanup: remove trailing white space, normalize file endings
r1203 """Listing of repositories in given path. This path should not be a
Refactor codes for scm model...
r691 repository itself. Return a dictionary of repository objects
source code cleanup: remove trailing white space, normalize file endings
r1203
Refactor codes for scm model...
r691 :param repos_path: path to directory containing repositories
"""
docs updates
r811
Refactor codes for scm model...
r691 log.info('scanning for repositories in %s', repos_path)
another major code rafactor, reimplemented (almost from scratch)...
r1038 if repos_path is None:
repos_path = self.repos_path
baseui = make_ui('db')
Refactor codes for scm model...
r691 repos_list = {}
Added recursive scanning for repositories in directory
r877 for name, path in get_filesystem_repos(repos_path, recursive=True):
Refactor codes for scm model...
r691 try:
#150 fixes for errors on repositories mapped in db but corrupted in filesystem
r1213 if name in repos_list:
Refactor codes for scm model...
r691 raise RepositoryError('Duplicate repository name %s '
'found in %s' % (name, path))
else:
klass = get_backend(path[0])
Disable git support due to large problems with dulwich....
r710 if path[0] == 'hg' and path[0] in BACKENDS.keys():
Unicode fixes, added safe_str method for global str() operations +better test sandboxing
r1401
# for mercurial we need to have an str path
repos_list[name] = klass(safe_str(path[1]),
baseui=baseui)
Refactor codes for scm model...
r691
Disable git support due to large problems with dulwich....
r710 if path[0] == 'git' and path[0] in BACKENDS.keys():
Refactor codes for scm model...
r691 repos_list[name] = klass(path[1])
except OSError:
continue
return repos_list
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 def get_repos(self, all_repos=None, sort_key=None):
#47 implemented basic gui for browsing repo groups
r1343 """
Get all repos from db and for each repo create it's
#150 fixes for errors on repositories mapped in db but corrupted in filesystem
r1213 backend instance and fill that backed with information from database
source code cleanup: remove trailing white space, normalize file endings
r1203
#47 implemented basic gui for browsing repo groups
r1343 :param all_repos: list of repository names as strings
give specific repositories list, good for filtering
Refactor codes for scm model...
r691 """
bugfix, when user had no repos he would see all repos in my account, (correct commit)
r767 if all_repos is None:
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 all_repos = self.sa.query(Repository)\
#47 implemented basic gui for browsing repo groups
r1343 .filter(Repository.group_id == None)\
Added repo group page showing what reposiories are inside a group
r1193 .order_by(Repository.repo_name).all()
Refactor codes for scm model...
r691
fixed some issues with cache invalidation, and simplified invalidation codes
r1428 repo_iter = CachedRepoList(all_repos, repos_path=self.repos_path,
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 order_by=sort_key)
Refactor codes for scm model...
r691
fixes #200, rewrote the whole caching mechanism to get rid of such problems. Now cached instances are attached...
r1366 return repo_iter
Refactor codes for scm model...
r691
#50 on point cache invalidation changes....
r692 def mark_for_invalidation(self, repo_name):
source code cleanup: remove trailing white space, normalize file endings
r1203 """Puts cache invalidation task into db for
#50 on point cache invalidation changes....
r692 further global cache invalidation
source code cleanup: remove trailing white space, normalize file endings
r1203
#50 on point cache invalidation changes....
r692 :param repo_name: this repo that should invalidation take place
"""
docs updates
r811
#50 on point cache invalidation changes....
r692 log.debug('marking %s for invalidation', repo_name)
cache = self.sa.query(CacheInvalidation)\
.filter(CacheInvalidation.cache_key == repo_name).scalar()
if cache:
fixed some issues with cache invalidation, and simplified invalidation codes
r1428 # mark this cache as inactive
#50 on point cache invalidation changes....
r692 cache.cache_active = False
else:
log.debug('cache key not found in invalidation db -> creating one')
cache = CacheInvalidation(repo_name)
try:
self.sa.add(cache)
self.sa.commit()
code cleanups
r758 except (DatabaseError,):
#50 on point cache invalidation changes....
r692 log.error(traceback.format_exc())
self.sa.rollback()
implemented user dashboards, and following system.
r734 def toggle_following_repo(self, follow_repo_id, user_id):
#50 on point cache invalidation changes....
r692
implemented user dashboards, and following system.
r734 f = self.sa.query(UserFollowing)\
.filter(UserFollowing.follows_repo_id == follow_repo_id)\
.filter(UserFollowing.user_id == user_id).scalar()
if f is not None:
Added icons with numbers of followers and number of forks
r747
implemented user dashboards, and following system.
r734 try:
self.sa.delete(f)
self.sa.commit()
added action loggers to following repositories,...
r735 action_logger(UserTemp(user_id),
'stopped_following_repo',
Added icons with numbers of followers and number of forks
r747 RepoTemp(follow_repo_id))
implemented user dashboards, and following system.
r734 return
except:
log.error(traceback.format_exc())
self.sa.rollback()
raise
try:
f = UserFollowing()
f.user_id = user_id
f.follows_repo_id = follow_repo_id
self.sa.add(f)
self.sa.commit()
added action loggers to following repositories,...
r735 action_logger(UserTemp(user_id),
'started_following_repo',
Added icons with numbers of followers and number of forks
r747 RepoTemp(follow_repo_id))
implemented user dashboards, and following system.
r734 except:
log.error(traceback.format_exc())
self.sa.rollback()
raise
#150 fixes for errors on repositories mapped in db but corrupted in filesystem
r1213 def toggle_following_user(self, follow_user_id, user_id):
implemented user dashboards, and following system.
r734 f = self.sa.query(UserFollowing)\
.filter(UserFollowing.follows_user_id == follow_user_id)\
.filter(UserFollowing.user_id == user_id).scalar()
if f is not None:
try:
self.sa.delete(f)
self.sa.commit()
return
except:
log.error(traceback.format_exc())
self.sa.rollback()
raise
try:
f = UserFollowing()
f.user_id = user_id
f.follows_user_id = follow_user_id
self.sa.add(f)
self.sa.commit()
except:
log.error(traceback.format_exc())
self.sa.rollback()
raise
fixed following js snipet. It' can be called multiple times now next to each repository...
r999 def is_following_repo(self, repo_name, user_id, cache=False):
implemented user dashboards, and following system.
r734 r = self.sa.query(Repository)\
.filter(Repository.repo_name == repo_name).scalar()
f = self.sa.query(UserFollowing)\
.filter(UserFollowing.follows_repository == r)\
.filter(UserFollowing.user_id == user_id).scalar()
return f is not None
fixed following js snipet. It' can be called multiple times now next to each repository...
r999 def is_following_user(self, username, user_id, cache=False):
code cleanups
r758 u = UserModel(self.sa).get_by_username(username)
implemented user dashboards, and following system.
r734
f = self.sa.query(UserFollowing)\
.filter(UserFollowing.follows_user == u)\
.filter(UserFollowing.user_id == user_id).scalar()
return f is not None
#50 on point cache invalidation changes....
r692
Added icons with numbers of followers and number of forks
r747 def get_followers(self, repo_id):
fixed condition evaluated for gitrepo that returned null, simplified scm functions
r1282 if not isinstance(repo_id, int):
repo_id = getattr(Repository.by_repo_name(repo_id), 'repo_id')
return self.sa.query(UserFollowing)\
.filter(UserFollowing.follows_repo_id == repo_id).count()
Added icons with numbers of followers and number of forks
r747
def get_forks(self, repo_id):
fixed condition evaluated for gitrepo that returned null, simplified scm functions
r1282 if not isinstance(repo_id, int):
repo_id = getattr(Repository.by_repo_name(repo_id), 'repo_id')
return self.sa.query(Repository)\
Added icons with numbers of followers and number of forks
r747 .filter(Repository.fork_id == repo_id).count()
#50 on point cache invalidation changes....
r692
#109, added manual pull of changes for repositories that have remote location filled in....
r1114 def pull_changes(self, repo_name, username):
Fixed remote pull command from todays code refactoring
r1370 dbrepo = Repository.by_repo_name(repo_name)
API added checks for a valid repository on pull command...
r1508 clone_uri = dbrepo.clone_uri
if not clone_uri:
raise Exception("This repository doesn't have a clone uri")
Fixed remote pull command from todays code refactoring
r1370 repo = dbrepo.scm_instance
#109, added manual pull of changes for repositories that have remote location filled in....
r1114 try:
#150 fixes for errors on repositories mapped in db but corrupted in filesystem
r1213 extras = {'ip': '',
'username': username,
'action': 'push_remote',
'repository': repo_name}
#109, added manual pull of changes for repositories that have remote location filled in....
r1114
source code cleanup: remove trailing white space, normalize file endings
r1203 #inject ui extra param to log this action via push logger
#109, added manual pull of changes for repositories that have remote location filled in....
r1114 for k, v in extras.items():
repo._repo.ui.setconfig('rhodecode_extras', k, v)
API added checks for a valid repository on pull command...
r1508 repo.pull(clone_uri)
#109, added manual pull of changes for repositories that have remote location filled in....
r1114 self.mark_for_invalidation(repo_name)
except:
log.error(traceback.format_exc())
raise
logged local commit with special action via action_logger,
r1312 def commit_change(self, repo, repo_name, cs, user, author, message, content,
moved out commit into scm model, and added cache invalidation after commit.
r1311 f_path):
if repo.alias == 'hg':
from vcs.backends.hg import MercurialInMemoryChangeset as IMC
elif repo.alias == 'git':
from vcs.backends.git import GitInMemoryChangeset as IMC
# decoding here will force that we have proper encoded values
# in any other case this will throw exceptions and deny commit
Unicode fixes, added safe_str method for global str() operations +better test sandboxing
r1401 content = safe_str(content)
message = safe_str(message)
path = safe_str(f_path)
author = safe_str(author)
moved out commit into scm model, and added cache invalidation after commit.
r1311 m = IMC(repo)
m.change(FileNode(path, content))
logged local commit with special action via action_logger,
r1312 tip = m.commit(message=message,
moved out commit into scm model, and added cache invalidation after commit.
r1311 author=author,
parents=[cs], branch=cs.branch)
logged local commit with special action via action_logger,
r1312 new_cs = tip.short_id
action = 'push_local:%s' % new_cs
action_logger(user, action, repo_name)
moved out commit into scm model, and added cache invalidation after commit.
r1311 self.mark_for_invalidation(repo_name)
Added initial support for creating new nodes in repos
r1483 def create_node(self, repo, repo_name, cs, user, author, message, content,
f_path):
if repo.alias == 'hg':
from vcs.backends.hg import MercurialInMemoryChangeset as IMC
elif repo.alias == 'git':
from vcs.backends.git import GitInMemoryChangeset as IMC
# decoding here will force that we have proper encoded values
# in any other case this will throw exceptions and deny commit
added uploading of files from web interface directly into repo
r1485
if isinstance(content,(basestring,)):
content = safe_str(content)
elif isinstance(content,file):
content = content.read()
Added initial support for creating new nodes in repos
r1483 message = safe_str(message)
path = safe_str(f_path)
author = safe_str(author)
m = IMC(repo)
if isinstance(cs, EmptyChangeset):
# Emptychangeset means we we're editing empty repository
parents = None
else:
parents = [cs]
m.add(FileNode(path, content=content))
tip = m.commit(message=message,
author=author,
parents=parents, branch=cs.branch)
new_cs = tip.short_id
action = 'push_local:%s' % new_cs
action_logger(user, action, repo_name)
self.mark_for_invalidation(repo_name)
moved out commit into scm model, and added cache invalidation after commit.
r1311
Implemented fancier top menu for logged and anonymous users...
r784 def get_unread_journal(self):
return self.sa.query(UserLog).count()
#50 on point cache invalidation changes....
r692 def _should_invalidate(self, repo_name):
docs updates
r811 """Looks up database for invalidation signals for this repo_name
source code cleanup: remove trailing white space, normalize file endings
r1203
#50 on point cache invalidation changes....
r692 :param repo_name:
"""
ret = self.sa.query(CacheInvalidation)\
.filter(CacheInvalidation.cache_key == repo_name)\
.filter(CacheInvalidation.cache_active == False)\
.scalar()
return ret
Added initial support for creating new nodes in repos
r1483