diff rhodecode/model/hg.py @ 665:070f32743632 beta

Moved out reposcan into hg Model. Rewrote repo scann and caching of repositories, all is in hgModel. Changed invalidate cache calls. mergeds main repo list and repo switcher list into one new based on hgModel.
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 07 Nov 2010 15:02:56 +0100
parents ffd07396d315
children 4685f3eafd35
line wrap: on
line diff
--- a/rhodecode/model/hg.py	Sat Nov 06 16:19:01 2010 +0100
+++ b/rhodecode/model/hg.py	Sun Nov 07 15:02:56 2010 +0100
@@ -22,57 +22,25 @@
 Model for RhodeCode
 @author: marcink
 """
-from beaker.cache import cache_region
+from beaker.cache import cache_region, region_invalidate
 from mercurial import ui
 from rhodecode.lib import helpers as h
-from rhodecode.lib.utils import invalidate_cache
 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
+from rhodecode.model.caching_query import FromCache
+from rhodecode.model.db import Repository, User, RhodeCodeUi
 from sqlalchemy.orm import joinedload
+from vcs import get_repo as vcs_get_repo, get_backend
+from vcs.backends.hg import MercurialRepository
 from vcs.exceptions import RepositoryError, VCSError
+from vcs.utils.lazy import LazyProperty
 import logging
-import sys
+import os
 import time
 
 log = logging.getLogger(__name__)
 
-try:
-    from vcs.backends.hg import MercurialRepository
-    from vcs.backends.git import GitRepository
-except ImportError:
-    sys.stderr.write('You have to import vcs module')
-    raise Exception('Unable to import vcs')
-
-def _get_repos_cached_initial(app_globals, initial):
-    """return cached dict with repos
-    """
-    g = app_globals
-    return HgModel().repo_scan(g.paths[0][1], g.baseui, initial)
-
-@cache_region('long_term', 'cached_repo_list')
-def _get_repos_cached():
-    """return cached dict with repos
-    """
-    log.info('getting all repositories list')
-    from pylons import app_globals as g
-    return HgModel().repo_scan(g.paths[0][1], g.baseui)
-
-@cache_region('super_short_term', 'cached_repos_switcher_list')
-def _get_repos_switcher_cached(cached_repo_list):
-    repos_lst = []
-    for repo in [x for x in cached_repo_list.values()]:
-        if HasRepoPermissionAny('repository.write', 'repository.read',
-                    'repository.admin')(repo.name, 'main page check'):
-            repos_lst.append((repo.name, repo.dbrepo.private,))
-
-    return sorted(repos_lst, key=lambda k:k[0].lower())
-
-@cache_region('long_term', 'full_changelog')
-def _full_changelog_cached(repo_name):
-    log.info('getting full changelog for %s', repo_name)
-    return list(reversed(list(HgModel().get_repo(repo_name))))
-
 class HgModel(object):
     """
     Mercurial Model
@@ -84,6 +52,16 @@
         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 
@@ -91,93 +69,100 @@
         
         :param repos_path: path to directory containing repositories
         :param baseui
-        :param initial: initial scann
+        :param initial: initial scan
         """
         log.info('scanning for repositories in %s', repos_path)
 
         if not isinstance(baseui, ui.ui):
             baseui = ui.ui()
-
-        from rhodecode.lib.utils import get_repos
-        repos = get_repos(repos_path)
-
-
         repos_list = {}
-        for name, path in repos:
+        for name, path in get_repos(repos_path):
             try:
-                #name = name.split('/')[-1]
                 if repos_list.has_key(name):
-                    raise RepositoryError('Duplicate repository name %s found in'
-                                    ' %s' % (name, path))
+                    raise RepositoryError('Duplicate repository name %s '
+                                    'found in %s' % (name, path))
                 else:
+
+                    klass = get_backend(path[0])
+
                     if path[0] == 'hg':
-                        repos_list[name] = MercurialRepository(path[1], baseui=baseui)
-                        repos_list[name].name = name
+                        repos_list[name] = klass(path[1], baseui=baseui)
 
                     if path[0] == 'git':
-                        repos_list[name] = GitRepository(path[1])
-                        repos_list[name].name = name
-
-                    dbrepo = None
-                    if not initial:
-                        #for initial scann on application first run we don't
-                        #have db repos yet.
-                        dbrepo = self.sa.query(Repository)\
-                            .options(joinedload(Repository.fork))\
-                            .filter(Repository.repo_name == name)\
-                            .scalar()
-
-                    if dbrepo:
-                        log.info('Adding db instance to cached list')
-                        repos_list[name].dbrepo = dbrepo
-                        repos_list[name].description = dbrepo.description
-                        if dbrepo.user:
-                            repos_list[name].contact = dbrepo.user.full_contact
-                        else:
-                            repos_list[name].contact = self.sa.query(User)\
-                            .filter(User.admin == True).first().full_contact
+                        repos_list[name] = klass(path[1])
             except OSError:
                 continue
 
         return repos_list
 
-    def get_repos(self):
-        for name, repo in _get_repos_cached().items():
+    def get_repos(self, all_repos=None):
+        """
+        Get all repos from db and for each such repo make backend and 
+        fetch dependent data from db
+        """
+        if not all_repos:
+            all_repos = self.sa.query(Repository).all()
 
-            if isinstance(repo, MercurialRepository) and repo._get_hidden():
-                #skip hidden web repository
-                continue
+        for r in all_repos:
+
+            repo = self.get(r.repo_name)
 
-            last_change = repo.last_change
-            tip = h.get_changeset_safe(repo, 'tip')
+            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.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.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
+                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):
-        try:
-            repo = _get_repos_cached()[repo_name]
-            return repo
-        except KeyError:
-            #i we're here and we got key errors let's try to invalidate the
-            #cahce and try again
-            invalidate_cache('cached_repo_list')
-            repo = _get_repos_cached()[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 = vcs_get_repo(os.path.join(self.repos_path, repo_name),
+                                alias=None, create=False)
+
+            #skip hidden web repository
+            if isinstance(repo, MercurialRepository) and repo._get_hidden():
+                return
+
+            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)