diff rhodecode/lib/utils.py @ 1512:bf263968da47

merge beta in stable branch
author Marcin Kuzminski <marcin@python-works.com>
date Fri, 07 Oct 2011 01:08:50 +0200
parents 9f6560667743 7d687ed11929
children 0b8fba8ab90b
line wrap: on
line diff
--- a/rhodecode/lib/utils.py	Thu May 12 19:50:48 2011 +0200
+++ b/rhodecode/lib/utils.py	Fri Oct 07 01:08:50 2011 +0200
@@ -29,24 +29,25 @@
 import traceback
 import paste
 import beaker
+from os.path import dirname as dn, join as jn
 
 from paste.script.command import Command, BadCommand
 
-from UserDict import DictMixin
-
-from mercurial import ui, config, hg
-from mercurial.error import RepoError
+from mercurial import ui, config
 
 from webhelpers.text import collapse, remove_formatting, strip_tags
 
+from vcs import get_backend
 from vcs.backends.base import BaseChangeset
 from vcs.utils.lazy import LazyProperty
+from vcs.utils.helpers import get_scm
+from vcs.exceptions import VCSError
 
 from rhodecode.model import meta
 from rhodecode.model.caching_query import FromCache
-from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog
+from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog, Group, \
+    RhodeCodeSettings
 from rhodecode.model.repo import RepoModel
-from rhodecode.model.user import UserModel
 
 log = logging.getLogger(__name__)
 
@@ -108,11 +109,10 @@
         sa = meta.Session()
 
     try:
-        um = UserModel()
         if hasattr(user, 'user_id'):
             user_obj = user
         elif isinstance(user, basestring):
-            user_obj = um.get_by_username(user, cache=False)
+            user_obj = User.by_username(user, cache=False)
         else:
             raise Exception('You have to provide user object or username')
 
@@ -144,64 +144,77 @@
         sa.rollback()
 
 
-def get_repos(path, recursive=False, initial=False):
+def get_repos(path, recursive=False):
     """
-    Scans given path for repos and return (name,(type,path)) tuple 
-    
-    :param prefix:
-    :param path:
-    :param recursive:
-    :param initial:
+    Scans given path for repos and return (name,(type,path)) tuple
+
+    :param path: path to scann for repositories
+    :param recursive: recursive search and return names with subdirs in front
     """
     from vcs.utils.helpers import get_scm
     from vcs.exceptions import VCSError
 
-    try:
-        scm = get_scm(path)
-    except:
-        pass
-    else:
-        raise Exception('The given path %s should not be a repository got %s',
-                        path, scm)
+    if path.endswith(os.sep):
+        #remove ending slash for better results
+        path = path[:-1]
 
-    for dirpath in os.listdir(path):
-        try:
-            yield dirpath, get_scm(os.path.join(path, dirpath))
-        except VCSError:
-            pass
+    def _get_repos(p):
+        if not os.access(p, os.W_OK):
+            return
+        for dirpath in os.listdir(p):
+            if os.path.isfile(os.path.join(p, dirpath)):
+                continue
+            cur_path = os.path.join(p, dirpath)
+            try:
+                scm_info = get_scm(cur_path)
+                yield scm_info[1].split(path)[-1].lstrip(os.sep), scm_info
+            except VCSError:
+                if not recursive:
+                    continue
+                #check if this dir containts other repos for recursive scan
+                rec_path = os.path.join(p, dirpath)
+                if os.path.isdir(rec_path):
+                    for inner_scm in _get_repos(rec_path):
+                        yield inner_scm
 
-def check_repo_fast(repo_name, base_path):
+    return _get_repos(path)
+
+
+def is_valid_repo(repo_name, base_path):
     """
-    Check given path for existence of directory
+    Returns True if given path is a valid repository False otherwise
     :param repo_name:
     :param base_path:
 
-    :return False: if this directory is present
+    :return True: if given path is a valid repository
     """
-    if os.path.isdir(os.path.join(base_path, repo_name)):
-        return False
-    return True
-
-
-def check_repo(repo_name, base_path, verify=True):
-
-    repo_path = os.path.join(base_path, repo_name)
-
+    full_path = os.path.join(base_path, repo_name)
+    
     try:
-        if not check_repo_fast(repo_name, base_path):
-            return False
-        r = hg.repository(ui.ui(), repo_path)
-        if verify:
-            hg.verify(r)
-        #here we hnow that repo exists it was verified
-        log.info('%s repo is already created', repo_name)
+        get_scm(full_path)
+        return True
+    except VCSError:
         return False
-    except RepoError:
-        #it means that there is no valid repo there...
-        log.info('%s repo is free for creation', repo_name)
+
+def is_valid_repos_group(repos_group_name, base_path):
+    """
+    Returns True if given path is a repos group False otherwise
+    
+    :param repo_name:
+    :param base_path:
+    """
+    full_path = os.path.join(base_path, repos_group_name)
+    
+    # check if it's not a repo
+    if is_valid_repo(repos_group_name, base_path):
+        return False
+    
+    # check if it's a valid path
+    if os.path.isdir(full_path):
         return True
-
-
+    
+    return False
+    
 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
     while True:
         ok = raw_input(prompt)
@@ -277,8 +290,7 @@
 
     :param config:
     """
-    from rhodecode.model.settings import SettingsModel
-    hgsettings = SettingsModel().get_app_settings()
+    hgsettings = RhodeCodeSettings.get_app_settings()
 
     for k, v in hgsettings.items():
         config[k] = v
@@ -302,13 +314,15 @@
     an EmptyChangeset
     """
 
-    def __init__(self, cs='0' * 40, repo=None):
+    def __init__(self, cs='0' * 40, repo=None, requested_revision=None, alias=None):
         self._empty_cs = cs
         self.revision = -1
         self.message = ''
         self.author = ''
         self.date = ''
         self.repository = repo
+        self.requested_revision = requested_revision
+        self.alias = alias
 
     @LazyProperty
     def raw_id(self):
@@ -319,6 +333,10 @@
         return self._empty_cs
 
     @LazyProperty
+    def branch(self):
+        return get_backend(self.alias).DEFAULT_BRANCH_NAME
+
+    @LazyProperty
     def short_id(self):
         return self.raw_id[:12]
 
@@ -331,135 +349,70 @@
     def get_file_size(self, path):
         return 0
 
+
+def map_groups(groups):
+    """Checks for groups existence, and creates groups structures.
+    It returns last group in structure
+
+    :param groups: list of groups structure
+    """
+    sa = meta.Session()
+
+    parent = None
+    group = None
+    for lvl, group_name in enumerate(groups[:-1]):
+        group = sa.query(Group).filter(Group.group_name == group_name).scalar()
+
+        if group is None:
+            group = Group(group_name, parent)
+            sa.add(group)
+            sa.commit()
+
+        parent = group
+
+    return group
+
+
 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
-    """maps all found repositories into db
+    """maps all repos given in initial_repo_list, non existing repositories
+    are created, if remove_obsolete is True it also check for db entries
+    that are not in initial_repo_list and removes them.
+
+    :param initial_repo_list: list of repositories found by scanning methods
+    :param remove_obsolete: check for obsolete entries in database
     """
 
     sa = meta.Session()
     rm = RepoModel()
     user = sa.query(User).filter(User.admin == True).first()
-
+    added = []
     for name, repo in initial_repo_list.items():
+        group = map_groups(name.split(os.sep))
         if not rm.get_by_repo_name(name, cache=False):
             log.info('repository %s not found creating default', name)
-
+            added.append(name)
             form_data = {
-                         'repo_name':name,
-                         'repo_type':repo.alias,
-                         'description':repo.description \
+                         'repo_name': name,
+                         'repo_name_full': name,
+                         'repo_type': repo.alias,
+                         'description': repo.description \
                             if repo.description != 'unknown' else \
                                         '%s repository' % name,
-                         'private':False
+                         'private': False,
+                         'group_id': getattr(group, 'group_id', None)
                          }
             rm.create(form_data, user, just_db=True)
 
+    removed = []
     if remove_obsolete:
         #remove from database those repositories that are not in the filesystem
         for repo in sa.query(Repository).all():
             if repo.repo_name not in initial_repo_list.keys():
+                removed.append(repo.repo_name)
                 sa.delete(repo)
                 sa.commit()
 
-
-class OrderedDict(dict, DictMixin):
-
-    def __init__(self, *args, **kwds):
-        if len(args) > 1:
-            raise TypeError('expected at most 1 arguments, got %d' % len(args))
-        try:
-            self.__end
-        except AttributeError:
-            self.clear()
-        self.update(*args, **kwds)
-
-    def clear(self):
-        self.__end = end = []
-        end += [None, end, end]         # sentinel node for doubly linked list
-        self.__map = {}                 # key --> [key, prev, next]
-        dict.clear(self)
-
-    def __setitem__(self, key, value):
-        if key not in self:
-            end = self.__end
-            curr = end[1]
-            curr[2] = end[1] = self.__map[key] = [key, curr, end]
-        dict.__setitem__(self, key, value)
-
-    def __delitem__(self, key):
-        dict.__delitem__(self, key)
-        key, prev, next = self.__map.pop(key)
-        prev[2] = next
-        next[1] = prev
-
-    def __iter__(self):
-        end = self.__end
-        curr = end[2]
-        while curr is not end:
-            yield curr[0]
-            curr = curr[2]
-
-    def __reversed__(self):
-        end = self.__end
-        curr = end[1]
-        while curr is not end:
-            yield curr[0]
-            curr = curr[1]
-
-    def popitem(self, last=True):
-        if not self:
-            raise KeyError('dictionary is empty')
-        if last:
-            key = reversed(self).next()
-        else:
-            key = iter(self).next()
-        value = self.pop(key)
-        return key, value
-
-    def __reduce__(self):
-        items = [[k, self[k]] for k in self]
-        tmp = self.__map, self.__end
-        del self.__map, self.__end
-        inst_dict = vars(self).copy()
-        self.__map, self.__end = tmp
-        if inst_dict:
-            return (self.__class__, (items,), inst_dict)
-        return self.__class__, (items,)
-
-    def keys(self):
-        return list(self)
-
-    setdefault = DictMixin.setdefault
-    update = DictMixin.update
-    pop = DictMixin.pop
-    values = DictMixin.values
-    items = DictMixin.items
-    iterkeys = DictMixin.iterkeys
-    itervalues = DictMixin.itervalues
-    iteritems = DictMixin.iteritems
-
-    def __repr__(self):
-        if not self:
-            return '%s()' % (self.__class__.__name__,)
-        return '%s(%r)' % (self.__class__.__name__, self.items())
-
-    def copy(self):
-        return self.__class__(self)
-
-    @classmethod
-    def fromkeys(cls, iterable, value=None):
-        d = cls()
-        for key in iterable:
-            d[key] = value
-        return d
-
-    def __eq__(self, other):
-        if isinstance(other, OrderedDict):
-            return len(self) == len(other) and self.items() == other.items()
-        return dict.__eq__(self, other)
-
-    def __ne__(self, other):
-        return not self == other
-
+    return added, removed
 
 #set cache regions for beaker so celery can utilise it
 def add_cache(settings):
@@ -512,21 +465,25 @@
 #==============================================================================
 # TEST FUNCTIONS AND CREATORS
 #==============================================================================
-def create_test_index(repo_location, full_index):
-    """Makes default test index
-    :param repo_location:
+def create_test_index(repo_location, config, full_index):
+    """
+    Makes default test index
+    
+    :param config: test config
     :param full_index:
     """
+
     from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
     from rhodecode.lib.pidlock import DaemonLock, LockHeld
-    import shutil
+
+    repo_location = repo_location
 
-    index_location = os.path.join(repo_location, 'index')
-    if os.path.exists(index_location):
-        shutil.rmtree(index_location)
+    index_location = os.path.join(config['app_conf']['index_dir'])
+    if not os.path.exists(index_location):
+        os.makedirs(index_location)
 
     try:
-        l = DaemonLock()
+        l = DaemonLock(file=jn(dn(index_location), 'make_index.lock'))
         WhooshIndexingDaemon(index_location=index_location,
                              repo_location=repo_location)\
             .run(full_index=full_index)
@@ -544,30 +501,17 @@
         HG_FORK, GIT_FORK, TESTS_TMP_PATH
     import tarfile
     import shutil
-    from os.path import dirname as dn, join as jn, abspath
-
-    log = logging.getLogger('TestEnvCreator')
-    # create logger
-    log.setLevel(logging.DEBUG)
-    log.propagate = True
-    # create console handler and set level to debug
-    ch = logging.StreamHandler()
-    ch.setLevel(logging.DEBUG)
+    from os.path import abspath
 
-    # create formatter
-    formatter = logging.Formatter("%(asctime)s - %(name)s -"
-                                  " %(levelname)s - %(message)s")
-
-    # add formatter to ch
-    ch.setFormatter(formatter)
-
-    # add ch to logger
-    log.addHandler(ch)
-
-    #PART ONE create db
+    # PART ONE create db
     dbconf = config['sqlalchemy.db1.url']
     log.debug('making test db %s', dbconf)
 
+    # create test dir if it doesn't exist
+    if not os.path.isdir(repos_test_path):
+        log.debug('Creating testdir %s' % repos_test_path)
+        os.makedirs(repos_test_path)
+
     dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
                         tests=True)
     dbmanage.create_tables(override=True)
@@ -577,15 +521,20 @@
     dbmanage.create_permissions()
     dbmanage.populate_default_permissions()
 
-    #PART TWO make test repo
+    # PART TWO make test repo
     log.debug('making test vcs repositories')
 
-    #remove old one from previos tests
-    for r in [HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, HG_FORK, GIT_FORK]:
+    idx_path = config['app_conf']['index_dir']
+    data_path = config['app_conf']['cache_dir']
 
-        if os.path.isdir(jn(TESTS_TMP_PATH, r)):
-            log.debug('removing %s', r)
-            shutil.rmtree(jn(TESTS_TMP_PATH, r))
+    #clean index and data
+    if idx_path and os.path.exists(idx_path):
+        log.debug('remove %s' % idx_path)
+        shutil.rmtree(idx_path)
+
+    if data_path and os.path.exists(data_path):
+        log.debug('remove %s' % data_path)
+        shutil.rmtree(data_path)
 
     #CREATE DEFAULT HG REPOSITORY
     cur_dir = dn(dn(abspath(__file__)))
@@ -659,3 +608,4 @@
         path_to_ini_file = os.path.realpath(conf)
         conf = paste.deploy.appconfig('config:' + path_to_ini_file)
         pylonsconfig.init_app(conf.global_conf, conf.local_conf)
+