view 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 source

#!/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.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 os
import time

log = logging.getLogger(__name__)

class HgModel(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 such repo make backend and 
        fetch dependent data from db
        """
        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 = 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)