diff rhodecode/model/scm.py @ 691:7486da5f0628 beta

Refactor codes for scm model Some test updates, added test for admin user controller
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 14 Nov 2010 22:54:16 +0100
parents rhodecode/model/hg.py@4685f3eafd35
children cb0d9ce6ac5c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/scm.py	Sun Nov 14 22:54:16 2010 +0100
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Model for RhodeCode
+# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
+# 
+# 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; version 2
+# of the License or (at your opinion) any later version of the license.
+# 
+# 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.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.
+"""
+Created on April 9, 2010
+Model for RhodeCode
+@author: marcink
+"""
+from beaker.cache import cache_region, region_invalidate
+from mercurial import ui
+from rhodecode.lib import helpers as h
+from rhodecode.lib.auth import HasRepoPermissionAny
+from rhodecode.lib.utils import get_repos
+from rhodecode.model import meta
+from rhodecode.model.db import Repository, User, RhodeCodeUi
+from sqlalchemy.orm import joinedload
+from vcs import get_backend
+from vcs.utils.helpers import get_scm
+from vcs.exceptions import RepositoryError, VCSError
+from vcs.utils.lazy import LazyProperty
+import logging
+import os
+import time
+
+log = logging.getLogger(__name__)
+
+class ScmModel(object):
+    """
+    Mercurial Model
+    """
+
+    def __init__(self, sa=None):
+        if not sa:
+            self.sa = meta.Session()
+        else:
+            self.sa = sa
+
+
+    @LazyProperty
+    def repos_path(self):
+        """
+        Get's the repositories root path from database
+        """
+        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
+
+        return q.ui_value
+
+    def repo_scan(self, repos_path, baseui, initial=False):
+        """
+        Listing of repositories in given path. This path should not be a 
+        repository itself. Return a dictionary of repository objects
+        
+        :param repos_path: path to directory containing repositories
+        :param baseui
+        :param initial: initial scan
+        """
+        log.info('scanning for repositories in %s', repos_path)
+
+        if not isinstance(baseui, ui.ui):
+            baseui = ui.ui()
+        repos_list = {}
+
+        for name, path in get_repos(repos_path):
+            try:
+                if repos_list.has_key(name):
+                    raise RepositoryError('Duplicate repository name %s '
+                                    'found in %s' % (name, path))
+                else:
+
+                    klass = get_backend(path[0])
+
+                    if path[0] == 'hg':
+                        repos_list[name] = klass(path[1], baseui=baseui)
+
+                    if path[0] == 'git':
+                        repos_list[name] = klass(path[1])
+            except OSError:
+                continue
+
+        return repos_list
+
+    def get_repos(self, all_repos=None):
+        """
+        Get all repos from db and for each repo create it's backend instance.
+        and fill that backed with information from database
+        
+        :param all_repos: give specific repositories list, good for filtering
+        """
+        if not all_repos:
+            all_repos = self.sa.query(Repository).all()
+
+        for r in all_repos:
+
+            repo = self.get(r.repo_name)
+
+            if repo is not None:
+                last_change = repo.last_change
+                tip = h.get_changeset_safe(repo, 'tip')
+
+                tmp_d = {}
+                tmp_d['name'] = repo.name
+                tmp_d['name_sort'] = tmp_d['name'].lower()
+                tmp_d['description'] = repo.dbrepo.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'] = repo.dbrepo.user.full_contact
+                tmp_d['contact_sort'] = tmp_d['contact']
+                tmp_d['repo_archives'] = list(repo._get_archives())
+                tmp_d['last_msg'] = tip.message
+                tmp_d['repo'] = repo
+                yield tmp_d
+
+    def get_repo(self, repo_name):
+        return self.get(repo_name)
+
+    def get(self, repo_name):
+        """
+        Get's repository from given name, creates BackendInstance and
+        propagates it's data from database with all additional information
+        :param repo_name:
+        """
+        if not HasRepoPermissionAny('repository.read', 'repository.write',
+                            'repository.admin')(repo_name, 'get repo check'):
+            return
+
+        @cache_region('long_term', 'get_repo_cached_%s' % repo_name)
+        def _get_repo(repo_name):
+
+            repo_path = os.path.join(self.repos_path, repo_name)
+            alias = get_scm(repo_path)[0]
+
+            log.debug('Creating instance of %s repository', alias)
+            backend = get_backend(alias)
+
+            if alias == 'hg':
+                repo = backend(repo_path, create=False, baseui=None)
+                #skip hidden web repository
+                if repo._get_hidden():
+                    return
+            else:
+                repo = backend(repo_path, create=False)
+
+            dbrepo = self.sa.query(Repository)\
+                .options(joinedload(Repository.fork))\
+                .options(joinedload(Repository.user))\
+                .filter(Repository.repo_name == repo_name)\
+                .scalar()
+            repo.dbrepo = dbrepo
+            return repo
+
+        invalidate = False
+        if invalidate:
+            log.info('INVALIDATING CACHE FOR %s', repo_name)
+            region_invalidate(_get_repo, None, repo_name)
+
+        return _get_repo(repo_name)
+