Commits

Marcin Kuzminski  committed 7695d34 Merge

merged stable into demo

  • Participants
  • Parent commits 98fb507, c3b8a25
  • Branches demo

Comments (0)

Files changed (50)

 0000000000000000000000000000000000000000 1.2.0
 c252049af24cd98eef5f4143fa3abbff3c912e29 v1.2.0
 0b8fba8ab90b01f811a50e6e7384989cced21d38 v1.2.1
+22273bec00ba2fd860c60a9277d3d7229e288e18 v1.2.2

File CONTRIBUTORS

     Augosto Hermann <augusto.herrmann@planejamento.gov.br>    
     Ankit Solanki <ankit.solanki@gmail.com>    
     Liad Shani <liadff@gmail.com>
-    
+    Les Peabody <lpeabody@gmail.com>

File docs/changelog.rst

 Changelog
 =========
 
+
+1.2.2 (**2011-10-17**)
+======================
+
+news
+----
+
+- #226 repo groups are available by path instead of numerical id
+ 
+fixes
+-----
+
+- #259 Groups with the same name but with different parent group
+- #260 Put repo in group, then move group to another group -> repo becomes unavailable
+- #258 RhodeCode 1.2 assumes egg folder is writable (lockfiles problems)
+- #265 ldap save fails sometimes on converting attributes to booleans, 
+  added getter and setter into model that will prevent from this on db model level
+- fixed problems with timestamps issues #251 and #213
+- fixes #266 Rhodecode allows to create repo with the same name and in 
+  the same parent as group
+- fixes #245 Rescan of the repositories on Windows
+- fixes #248 cannot edit repos inside a group on windows
+- fixes #219 forking problems on windows
+
 1.2.1 (**2011-10-08**)
 ======================
 
 - gui fixes
 - fixed logger
 
-
 1.2.0 (**2011-10-07**)
 ======================
 
-
 news
 ----
 

File docs/setup.rst

 In order to not have the statics served by the application. This improves speed.
 
 
-Apache virtual host example
----------------------------
+Apache virtual host reverse proxy example
+-----------------------------------------
 
 Here is a sample configuration file for apache using proxy::
 
 Apache's WSGI config
 --------------------
 
+Alternatively, RhodeCode can be set up with Apache under mod_wsgi. For
+that, you'll need to:
+
+- Install mod_wsgi. If using a Debian-based distro, you can install
+  the package libapache2-mod-wsgi::
+
+    aptitude install libapache2-mod-wsgi
+
+- Enable mod_wsgi::
+
+    a2enmod wsgi
+
+- Create a wsgi dispatch script, like the one below. Make sure you
+  check the paths correctly point to where you installed RhodeCode
+  and its Python Virtual Environment.
+- Enable the WSGIScriptAlias directive for the wsgi dispatch script,
+  as in the following example. Once again, check the paths are
+  correctly specified.
+
+Here is a sample excerpt from an Apache Virtual Host configuration file::
+
+    WSGIDaemonProcess pylons user=www-data group=www-data processes=1 \
+        threads=4 \
+        python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages
+    WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi
 
 Example wsgi dispatch script::
 
     
     # sometimes it's needed to set the curent dir
     os.chdir('/home/web/rhodecode/') 
+
+    import site
+    site.addsitedir("/home/web/rhodecode/pyenv/lib/python2.6/site-packages")
     
     from paste.deploy import loadapp
     from paste.script.util.logging_config import fileConfig
     fileConfig('/home/web/rhodecode/production.ini')
     application = loadapp('config:/home/web/rhodecode/production.ini')
 
+Note: when using mod_wsgi you'll need to install the same version of
+Mercurial that's inside RhodeCode's virtualenv also on the system's Python
+environment.
+
 
 Other configuration files
 -------------------------

File init.d/rhodecode-daemon3

+#!/bin/sh
+########################################
+#### THIS IS A REDHAT INIT.D SCRIPT ####
+########################################
+
+##################################################
+#
+# RhodeCode server startup script
+# Recommended default-startup: 2 3 4 5
+# Recommended default-stop: 0 1 6
+#
+##################################################
+
+
+APP_NAME="rhodecode"
+# the location of your app
+# since this is a web app, it should go in /var/www
+APP_PATH="/var/www/$APP_NAME"
+
+CONF_NAME="production.ini"
+
+# write to wherever the PID should be stored, just ensure
+# that the user you run paster as has the appropriate permissions
+# same goes for the log file
+PID_PATH="/var/run/rhodecode/pid"
+LOG_PATH="/var/log/rhodecode/rhodecode.log"
+
+# replace this with the path to the virtual environment you
+# made for RhodeCode
+PYTHON_PATH="/opt/python_virtualenvironments/rhodecode-venv"
+
+RUN_AS="rhodecode"
+
+DAEMON="$PYTHON_PATH/bin/paster"
+
+DAEMON_OPTS="serve --daemon \
+    --user=$RUN_AS \
+    --group=$RUN_AS \
+    --pid-file=$PID_PATH \
+    --log-file=$LOG_PATH $APP_PATH/$CONF_NAME"
+
+DESC="rhodecode-server"
+LOCK_FILE="/var/lock/subsys/$APP_NAME"
+
+# source CentOS init functions
+. /etc/init.d/functions
+
+RETVAL=0
+
+remove_pid () {
+  rm -f ${PID_PATH}
+  rmdir `dirname ${PID_PATH}`
+}
+
+ensure_pid_dir () {
+  PID_DIR=`dirname ${PID_PATH}`
+  if [ ! -d ${PID_DIR} ] ; then
+    mkdir -p ${PID_DIR}
+    chown -R ${RUN_AS}:${RUN_AS} ${PID_DIR}
+    chmod 755 ${PID_DIR}
+  fi
+}
+
+start_rhodecode () {
+    ensure_pid_dir
+    PYTHON_EGG_CACHE="/tmp" daemon --pidfile $PID_PATH \
+        --user $RUN_AS "$DAEMON $DAEMON_OPTS"
+    RETVAL=$?
+    [ $RETVAL -eq 0 ] && touch $LOCK_FILE
+    return $RETVAL
+}
+
+stop_rhodecode () {
+    if [ -e $LOCK_FILE ]; then
+      killproc -p $PID_PATH
+      RETVAL=$?
+      rm -f $LOCK_FILE
+      rm -f $PID_PATH
+    else
+      RETVAL=1
+    fi
+    return $RETVAL
+}
+
+status_rhodecode() {
+  if [ -e $LOCK_FILE ]; then
+    # exit with non-zero to indicate failure
+    RETVAL=1
+  else
+    RETVAL=0
+  fi
+  return $RETVAL
+}
+
+restart_rhodecode () {
+    stop_rhodecode
+    start_rhodecode
+    RETVAL=$?
+}
+
+case "$1" in
+  start)
+    echo -n $"Starting $DESC: "
+    start_rhodecode
+    echo
+    ;;
+  stop)
+    echo -n $"Stopping $DESC: "
+    stop_rhodecode
+    echo
+    ;;
+  status)
+    status_rhodecode
+    RETVAL=$?
+    if [ ! $RETVAL -eq 0 ]; then
+      echo "RhodeCode server is running..."
+    else
+      echo "RhodeCode server is stopped."
+    fi
+    ;;
+  restart)
+    echo -n $"Restarting $DESC: "
+    restart_rhodecode
+    echo
+    ;;
+  *)
+    echo $"Usage: $0 {start|stop|restart|status}"
+    RETVAL=1
+    ;;
+esac
+
+exit $RETVAL

File rhodecode/__init__.py

 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import platform
 
-VERSION = (1, 2, 1)
+VERSION = (1, 2, 2)
 __version__ = '.'.join((str(each) for each in VERSION[:4]))
 __dbversion__ = 3 #defines current db version for migrations
 __platform__ = platform.system()
 PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS')
 
 try:
-    from rhodecode.lib.utils import get_current_revision
-    _rev = get_current_revision()
+    from rhodecode.lib import get_current_revision
+    _rev = get_current_revision(quiet=True)
 except ImportError:
     #this is needed when doing some setup.py operations
     _rev = False

File rhodecode/config/middleware.py

File contents unchanged.

File rhodecode/config/routing.py

                  always_scan=config['debug'])
     rmap.minimization = False
     rmap.explicit = False
-    
+
     from rhodecode.lib.utils import is_valid_repo
     from rhodecode.lib.utils import is_valid_repos_group
-    
+
     def check_repo(environ, match_dict):
         """
         check for valid repository for proper 404 handling
         :param environ:
         :param match_dict:
         """
-         
+
         repo_name = match_dict.get('repo_name')
         return is_valid_repo(repo_name, config['base_path'])
 
         :param match_dict:
         """
         repos_group_name = match_dict.get('group_name')
-        
+
         return is_valid_repos_group(repos_group_name, config['base_path'])
 
 
     # REPOSITORY ROUTES
     #==========================================================================
     rmap.connect('summary_home', '/{repo_name:.*}',
-                controller='summary', 
+                controller='summary',
                 conditions=dict(function=check_repo))
-    
-#    rmap.connect('repo_group_home', '/{group_name:.*}',
-#                controller='admin/repos_groups',action="show_by_name", 
-#                conditions=dict(function=check_group))
-    
+
+    rmap.connect('repos_group_home', '/{group_name:.*}',
+                controller='admin/repos_groups', action="show_by_name",
+                conditions=dict(function=check_group))
+
     rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
                 controller='changeset', revision='tip',
                 conditions=dict(function=check_repo))

File rhodecode/controllers/admin/permissions.py

         c.create_choices = self.create_choices
 
         if id == 'default':
-            default_user = User.by_username('default')
+            default_user = User.get_by_username('default')
             defaults = {'_method': 'put',
                         'anonymous': default_user.active}
 

File rhodecode/controllers/admin/repos.py

         super(ReposController, self).__before__()
 
     def __load_defaults(self):
+        c.repo_groups = Group.groups_choices()
+        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
+        
         repo_model = RepoModel()
-
-        c.repo_groups = [('', '')]
-        parents_link = lambda k: h.literal('&raquo;'.join(
-                                    map(lambda k: k.group_name,
-                                        k.parents + [k])
-                                    )
-                                )
-
-        c.repo_groups.extend([(x.group_id, parents_link(x)) for \
-                                            x in self.sa.query(Group).all()])
-        c.repo_groups = sorted(c.repo_groups,
-                               key=lambda t: t[1].split('&raquo;')[0])
-        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
         c.users_array = repo_model.get_users_js()
         c.users_groups_array = repo_model.get_users_groups_js()
 
         """
         self.__load_defaults()
 
-        c.repo_info = db_repo = Repository.by_repo_name(repo_name)
-        repo = scm_repo = db_repo.scm_instance
+        c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
+        repo = db_repo.scm_instance
 
         if c.repo_info is None:
             h.flash(_('%s repository is not mapped to db perhaps'
 
             return redirect(url('repos'))
 
-        c.default_user_id = User.by_username('default').user_id
+        c.default_user_id = User.get_by_username('default').user_id
         c.in_public_journal = self.sa.query(UserFollowing)\
             .filter(UserFollowing.user_id == c.default_user_id)\
             .filter(UserFollowing.follows_repository == c.repo_info).scalar()
                          repo_groups=c.repo_groups_choices)()
         try:
             form_result = _form.to_python(dict(request.POST))
-            repo_model.update(repo_name, form_result)
+            repo = repo_model.update(repo_name, form_result)
             invalidate_cache('get_repo_cached_%s' % repo_name)
             h.flash(_('Repository %s updated successfully' % repo_name),
                     category='success')
-            changed_name = form_result['repo_name_full']
+            changed_name = repo.repo_name
             action_logger(self.rhodecode_user, 'admin_updated_repo',
                               changed_name, '', self.sa)
 
         token = get_token()
         if cur_token == token:
             try:
-                repo_id = Repository.by_repo_name(repo_name).repo_id
-                user_id = User.by_username('default').user_id
+                repo_id = Repository.get_by_repo_name(repo_name).repo_id
+                user_id = User.get_by_username('default').user_id
                 self.scm_model.toggle_following_repo(repo_id, user_id)
                 h.flash(_('Updated repository visibility in public journal'),
                         category='success')

File rhodecode/controllers/admin/repos_groups.py

 from pylons.controllers.util import abort, redirect
 from pylons.i18n.translation import _
 
+from sqlalchemy.exc import IntegrityError
+
 from rhodecode.lib import helpers as h
-from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
-    HasPermissionAnyDecorator
+from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator
 from rhodecode.lib.base import BaseController, render
 from rhodecode.model.db import Group
 from rhodecode.model.repos_group import ReposGroupModel
         super(ReposGroupsController, self).__before__()
 
     def __load_defaults(self):
-
-        c.repo_groups = [('', '')]
-        parents_link = lambda k: h.literal('&raquo;'.join(
-                                    map(lambda k: k.group_name,
-                                        k.parents + [k])
-                                    )
-                                )
-
-        c.repo_groups.extend([(x.group_id, parents_link(x)) for \
-                                            x in self.sa.query(Group).all()])
-
-        c.repo_groups = sorted(c.repo_groups,
-                               key=lambda t: t[1].split('&raquo;')[0])
+        c.repo_groups = Group.groups_choices()
         c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 
     def __load_data(self, group_id):
 
         data = repo_group.get_dict()
 
+        data['group_name'] = repo_group.name
+
         return data
 
     @HasPermissionAnyDecorator('hg.admin')
             repos_group_model.delete(id)
             h.flash(_('removed repos group %s' % gr.group_name), category='success')
             #TODO: in future action_logger(, '', '', '', self.sa)
+        except IntegrityError, e:
+            if e.message.find('groups_group_parent_id_fkey'):
+                log.error(traceback.format_exc())
+                h.flash(_('Cannot delete this group it still contains '
+                          'subgroups'),
+                        category='warning')
+            else:
+                log.error(traceback.format_exc())
+                h.flash(_('error occurred during deletion of repos '
+                          'group %s' % gr.group_name), category='error')
+
         except Exception:
             log.error(traceback.format_exc())
-            h.flash(_('error occurred during deletion of repos group %s' % gr.group_name),
-                    category='error')
+            h.flash(_('error occurred during deletion of repos '
+                      'group %s' % gr.group_name), category='error')
 
         return redirect(url('repos_groups'))
 
+    def show_by_name(self, group_name):
+        id_ = Group.get_by_group_name(group_name).group_id
+        return self.show(id_)
+
     def show(self, id, format='html'):
         """GET /repos_groups/id: Show a specific item"""
         # url('repos_group', id=ID)

File rhodecode/controllers/admin/settings.py

     def create_repository(self):
         """GET /_admin/create_repository: Form to create a new item"""
 
-        c.repo_groups = [('', '')]
-        parents_link = lambda k: h.literal('&raquo;'.join(
-                                    map(lambda k: k.group_name,
-                                        k.parents + [k])
-                                    )
-                                )
-
-        c.repo_groups.extend([(x.group_id, parents_link(x)) for \
-                                            x in self.sa.query(Group).all()])
-        c.repo_groups = sorted(c.repo_groups,
-                               key=lambda t: t[1].split('&raquo;')[0])
+        c.repo_groups = Group.groups_choices()
         c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 
         new_repo = request.GET.get('repo', '')

File rhodecode/controllers/files.py

                 filename = file_obj.filename
                 content = file_obj.file
 
-            #TODO: REMOVE THIS !!
-            ################################
-            import ipdb;ipdb.set_trace()
-            print 'setting ipdb debuggin for rhodecode.controllers.files.FilesController.add'
-            ################################
-
-
             node_path = os.path.join(location, filename)
             author = self.rhodecode_user.full_contact
 

File rhodecode/controllers/login.py

                 c.form_result = login_form.to_python(dict(request.POST))
                 #form checks for username/password, now we're authenticated
                 username = c.form_result['username']
-                user = User.by_username(username,
-                                                   case_insensitive=True)
+                user = User.get_by_username(username, case_insensitive=True)
                 auth_user = AuthUser(user.user_id)
                 auth_user.set_authenticated()
                 session['rhodecode_user'] = auth_user
     def register(self):
         user_model = UserModel()
         c.auto_active = False
-        for perm in user_model.get_by_username('default',
-                                               cache=False).user_perms:
+        for perm in User.get_by_username('default').user_perms:
             if perm.permission.permission_name == 'hg.register.auto_activate':
                 c.auto_active = True
                 break

File rhodecode/lib/__init__.py

 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import os
+
 def __get_lem():
     from pygments import lexers
     from string import lower
         from rhodecode.lib.utils import EmptyChangeset
         cs = EmptyChangeset(requested_revision=rev)
     return cs
+
+
+def get_current_revision(quiet=False):
+    """
+    Returns tuple of (number, id) from repository containing this package
+    or None if repository could not be found.
+    
+    :param quiet: prints error for fetching revision if True
+    """
+
+    try:
+        from vcs import get_repo
+        from vcs.utils.helpers import get_scm
+        from vcs.exceptions import RepositoryError, VCSError
+        repopath = os.path.join(os.path.dirname(__file__), '..', '..')
+        scm = get_scm(repopath)[0]
+        repo = get_repo(path=repopath, alias=scm)
+        tip = repo.get_changeset()
+        return (tip.revision, tip.short_id)
+    except (ImportError, RepositoryError, VCSError), err:
+        if not quiet:
+            print ("Cannot retrieve rhodecode's revision. Original error "
+                   "was: %s" % err)
+        return None
+

File rhodecode/lib/auth.py

     authentication and permission libraries
 
     :created_on: Apr 4, 2010
-    :copyright: (c) 2010 by marcink.
-    :license: LICENSE_NAME, see LICENSE_FILE for more details.
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
+    :license: GPLv3, see COPYING for more details.
 """
 # 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
 
 from rhodecode.model import meta
 from rhodecode.model.user import UserModel
-from rhodecode.model.db import Permission, RhodeCodeSettings
+from rhodecode.model.db import Permission, RhodeCodeSettings, User
 
 log = logging.getLogger(__name__)
 
     """
 
     user_model = UserModel()
-    user = user_model.get_by_username(username, cache=False)
+    user = User.get_by_username(username)
 
     log.debug('Authenticating user using RhodeCode account')
     if user is not None and not user.ldap_dn:
 
     else:
         log.debug('Regular authentication failed')
-        user_obj = user_model.get_by_username(username, cache=False,
-                                            case_insensitive=True)
+        user_obj = User.get_by_username(username, case_insensitive=True)
 
         if user_obj is not None and not user_obj.ldap_dn:
             log.debug('this user already exists as non ldap')
 
     def propagate_data(self):
         user_model = UserModel()
-        self.anonymous_user = user_model.get_by_username('default', cache=True)
+        self.anonymous_user = User.get_by_username('default')
         if self._api_key and self._api_key != self.anonymous_user.api_key:
             #try go get user by api key
             log.debug('Auth User lookup by API KEY %s', self._api_key)

File rhodecode/lib/backup_manager.py

     repositories and send it to backup server using RSA key via ssh.
 
     :created_on: Feb 28, 2010
-    :copyright: (c) 2010 by marcink.
-    :license: LICENSE_NAME, see LICENSE_FILE for more details.
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
+    :license: GPLv3, see COPYING for more details.
 """
 # 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

File rhodecode/lib/base.py

         super(BaseRepoController, self).__before__()
         if c.repo_name:
 
-            c.rhodecode_db_repo = Repository.by_repo_name(c.repo_name)
+            c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
             c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
 
             if c.rhodecode_repo is None:

File rhodecode/lib/celerylib/__init__.py

 def locked_task(func):
     def __wrapper(func, *fargs, **fkwargs):
         lockkey = __get_lockkey(func, *fargs, **fkwargs)
-        lockkey_path = dn(dn(dn(os.path.abspath(__file__))))
+        lockkey_path = config['here']
 
         log.info('running task with lockkey %s', lockkey)
         try:
-            l = DaemonLock(jn(lockkey_path, lockkey))
+            l = DaemonLock(file_=jn(lockkey_path, lockkey))
             ret = func(*fargs, **fkwargs)
             l.release()
             return ret

File rhodecode/lib/celerylib/tasks.py

 
     lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
                             ts_max_y)
-    lockkey_path = dn(dn(dn(dn(os.path.abspath(__file__)))))
+    lockkey_path = config['here']
+
     log.info('running task with lockkey %s', lockkey)
     try:
-        lock = l = DaemonLock(jn(lockkey_path, lockkey))
+        lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
 
         #for js data compatibilty cleans the key for person from '
         akc = lambda k: person(k).replace('"', "")

File rhodecode/lib/compat.py

 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import os
+from rhodecode import __platform__, PLATFORM_WIN
+
 #==============================================================================
 # json
 #==============================================================================
 # OrderedSet
 #==============================================================================
 from sqlalchemy.util import OrderedSet
+
+
+#==============================================================================
+# kill FUNCTIONS
+#==============================================================================
+if __platform__ in PLATFORM_WIN:
+    import ctypes
+
+    def kill(pid, sig):
+        """kill function for Win32"""
+        kernel32 = ctypes.windll.kernel32
+        handle = kernel32.OpenProcess(1, 0, pid)
+        return (0 != kernel32.TerminateProcess(handle, 0))
+
+else:
+    kill = os.kill

File rhodecode/lib/exceptions.py

     Set of custom exceptions used in RhodeCode
 
     :created_on: Nov 17, 2010
-    :copyright: (c) 2010 by marcink.
-    :license: LICENSE_NAME, see LICENSE_FILE for more details.
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
+    :license: GPLv3, see COPYING for more details.
 """
 # 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

File rhodecode/lib/helpers.py

         return repo_name
     else:
         def make_link(group):
-            return link_to(group.group_name, url('repos_group',
-                                                 id=group.group_id))
+            return link_to(group.name, url('repos_group_home',
+                                           group_name=group.group_name))
         return literal(' &raquo; '.join(map(make_link, groups)) + \
                        " &raquo; " + repo_name)
 
-
 def fancy_file_stats(stats):
     """
     Displays a fancy two colored bar for number of added/deleted

File rhodecode/lib/indexers/__init__.py

         from rhodecode.lib.pidlock import LockHeld, DaemonLock
         from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
         try:
-            l = DaemonLock(file=jn(dn(dn(index_location)), 'make_index.lock'))
+            l = DaemonLock(file_=jn(dn(dn(index_location)), 'make_index.lock'))
             WhooshIndexingDaemon(index_location=index_location,
                                  repo_location=repo_location,
                                  repo_list=repo_list)\

File rhodecode/lib/middleware/simplegit.py

         return repo_name
 
     def __get_user(self, username):
-        return User.by_username(username)
+        return User.get_by_username(username)
 
     def __get_action(self, environ):
         """Maps git request commands into a pull or push command.

File rhodecode/lib/middleware/simplehg.py

 
         # skip passing error to error controller
         environ['pylons.status_code_redirect'] = True
-                
+
         #======================================================================
         # EXTRACT REPOSITORY NAME FROM ENV
         #======================================================================
         # GET ACTION PULL or PUSH
         #======================================================================
         action = self.__get_action(environ)
-        
+
         #======================================================================
         # CHECK ANONYMOUS PERMISSION
         #======================================================================
         if action in ['pull', 'push']:
             anonymous_user = self.__get_user('default')
+
             username = anonymous_user.username
             anonymous_perm = self.__check_permission(action,
                                                      anonymous_user,
         #======================================================================
         # MERCURIAL REQUEST HANDLING
         #======================================================================
-        
+
         repo_path = safe_str(os.path.join(self.basepath, repo_name))
         log.debug('Repository path is %s' % repo_path)
-        
+
         baseui = make_ui('db')
         self.__inject_extras(repo_path, baseui, extras)
-        
+
 
         # quick check if that dir exists...
         if is_valid_repo(repo_name, self.basepath) is False:
         return repo_name
 
     def __get_user(self, username):
-        return User.by_username(username)
+        return User.get_by_username(username)
 
     def __get_action(self, environ):
         """
         push requests"""
         invalidate_cache('get_repo_cached_%s' % repo_name)
 
-    def __inject_extras(self,repo_path, baseui, extras={}):
+    def __inject_extras(self, repo_path, baseui, extras={}):
         """
         Injects some extra params into baseui instance
         

File rhodecode/lib/pidlock.py

 from warnings import warn
 from multiprocessing.util import Finalize
 
-from rhodecode import __platform__, PLATFORM_WIN
-
-if __platform__ in PLATFORM_WIN:
-    import ctypes
-
-    def kill(pid, sig):
-        """kill function for Win32"""
-        kernel32 = ctypes.windll.kernel32
-        handle = kernel32.OpenProcess(1, 0, pid)
-        return (0 != kernel32.TerminateProcess(handle, 0))
-
-else:
-    kill = os.kill
-
+from rhodecode.lib.compat import kill
 
 class LockHeld(Exception):
     pass
     """daemon locking
     USAGE:
     try:
-        l = DaemonLock(desc='test lock')
+        l = DaemonLock(file_='/path/tolockfile',desc='test lock')
         main()
         l.release()
     except LockHeld:
         sys.exit(1)
     """
 
-    def __init__(self, file=None, callbackfn=None,
+    def __init__(self, file_=None, callbackfn=None,
                  desc='daemon lock', debug=False):
 
-        self.pidfile = file if file else os.path.join(
+        self.pidfile = file_ if file_ else os.path.join(
                                                     os.path.dirname(__file__),
                                                     'running.lock')
         self.callbackfn = callbackfn

File rhodecode/lib/smtp_mailer.py

     Simple smtp mailer used in RhodeCode
 
     :created_on: Sep 13, 2010
-    :copyright: (c) 2011 by marcink.
-    :license: LICENSE_NAME, see LICENSE_FILE for more details.
+    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
+    :license: GPLv3, see COPYING for more details.
 """
+# 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.
+#
+# 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, see <http://www.gnu.org/licenses/>.
 
 import logging
 import smtplib

File rhodecode/lib/utils.py

         if hasattr(user, 'user_id'):
             user_obj = user
         elif isinstance(user, basestring):
-            user_obj = User.by_username(user)
+            user_obj = User.get_by_username(user)
         else:
             raise Exception('You have to provide user object or username')
 
 
     parent = None
     group = None
-    for lvl, group_name in enumerate(groups[:-1]):
+
+    # last element is repo in nested groups structure
+    groups = groups[:-1]
+
+    for lvl, group_name in enumerate(groups):
+        group_name = '/'.join(groups[:lvl] + [group_name])
         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
 
 
     rm = RepoModel()
     user = sa.query(User).filter(User.admin == True).first()
     added = []
+    # fixup groups paths to new format on the fly
+    # TODO: remove this in future
+    for g in Group.query().all():
+        g.group_name = g.get_new_name(g.name)
+        sa.add(g)    
     for name, repo in initial_repo_list.items():
-        group = map_groups(name.split(os.sep))
+        group = map_groups(name.split(Repository.url_sep()))
         if not rm.get_by_repo_name(name, cache=False):
             log.info('repository %s not found creating default', name)
             added.append(name)
             beaker.cache.cache_regions[region] = region_settings
 
 
-def get_current_revision():
-    """Returns tuple of (number, id) from repository containing this package
-    or None if repository could not be found.
-    """
-
-    try:
-        from vcs import get_repo
-        from vcs.utils.helpers import get_scm
-        from vcs.exceptions import RepositoryError, VCSError
-        repopath = os.path.join(os.path.dirname(__file__), '..', '..')
-        scm = get_scm(repopath)[0]
-        repo = get_repo(path=repopath, alias=scm)
-        tip = repo.get_changeset()
-        return (tip.revision, tip.short_id)
-    except (ImportError, RepositoryError, VCSError), err:
-        logging.debug("Cannot retrieve rhodecode's revision. Original error "
-                      "was: %s" % err)
-        return None
-
-
 #==============================================================================
 # TEST FUNCTIONS AND CREATORS
 #==============================================================================
         os.makedirs(index_location)
 
     try:
-        l = DaemonLock(file=jn(dn(index_location), 'make_index.lock'))
+        l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
         WhooshIndexingDaemon(index_location=index_location,
                              repo_location=repo_location)\
             .run(full_index=full_index)

File rhodecode/model/db.py

 
 from sqlalchemy import *
 from sqlalchemy.exc import DatabaseError
-from sqlalchemy.orm import relationship, backref, joinedload, class_mapper
+from sqlalchemy.ext.hybrid import hybrid_property
+from sqlalchemy.orm import relationship, backref, joinedload, class_mapper, \
+    validates
 from sqlalchemy.orm.interfaces import MapperExtension
-
 from beaker.cache import cache_region, region_invalidate
 
 from vcs import get_backend
 from vcs.utils.lazy import LazyProperty
 
 from rhodecode.lib import str2bool, safe_str, get_changeset_safe, \
-    generate_api_key
+    generate_api_key, safe_unicode
 from rhodecode.lib.exceptions import UsersGroupsAssignedException
 from rhodecode.lib.compat import json
 
 from rhodecode.model.meta import Base, Session
 from rhodecode.model.caching_query import FromCache
 
+
 log = logging.getLogger(__name__)
 
 #==============================================================================
 
     @classmethod
     def get(cls, id_):
-        return Session.query(cls).get(id_)
+        if id_:
+            return Session.query(cls).get(id_)
 
     @classmethod
     def delete(cls, id_):
     __table_args__ = (UniqueConstraint('app_settings_name'), {'extend_existing':True})
     app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
     app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
-    app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
+    _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
     def __init__(self, k='', v=''):
         self.app_settings_name = k
         self.app_settings_value = v
 
+
+    @validates('_app_settings_value')
+    def validate_settings_value(self, key, val):
+        assert type(val) == unicode
+        return val
+
+    @hybrid_property
+    def app_settings_value(self):
+        v = self._app_settings_value
+        if v == 'ldap_active':
+            v = str2bool(v)
+        return v 
+
+    @app_settings_value.setter
+    def app_settings_value(self,val):
+        """
+        Setter that will always make sure we use unicode in app_settings_value
+        
+        :param val:
+        """
+        self._app_settings_value = safe_unicode(val)
+
     def __repr__(self):
         return "<%s('%s:%s')>" % (self.__class__.__name__,
                                   self.app_settings_name, self.app_settings_value)
     @classmethod
     def get_ldap_settings(cls, cache=False):
         ret = Session.query(cls)\
-                .filter(cls.app_settings_name.startswith('ldap_'))\
-                .all()
+                .filter(cls.app_settings_name.startswith('ldap_')).all()
         fd = {}
         for row in ret:
             fd.update({row.app_settings_name:row.app_settings_value})
 
-        fd.update({'ldap_active':str2bool(fd.get('ldap_active'))})
-
         return fd
 
 
             return self.__class__.__name__
 
     @classmethod
-    def by_username(cls, username, case_insensitive=False):
+    def get_by_username(cls, username, case_insensitive=False):
         if case_insensitive:
-            return Session.query(cls).filter(cls.username.like(username)).one()
+            return Session.query(cls).filter(cls.username.ilike(username)).scalar()
         else:
-            return Session.query(cls).filter(cls.username == username).one()
+            return Session.query(cls).filter(cls.username == username).scalar()
 
     @classmethod
     def get_by_api_key(cls, api_key):
         return Session.query(cls).filter(cls.api_key == api_key).one()
 
-
     def update_lastlogin(self):
         """Update user lastlogin"""
 
                                   self.repo_id, self.repo_name)
 
     @classmethod
-    def by_repo_name(cls, repo_name):
+    def url_sep(cls):
+        return '/'
+    
+    @classmethod
+    def get_by_repo_name(cls, repo_name):
         q = Session.query(cls).filter(cls.repo_name == repo_name)
 
         q = q.options(joinedload(Repository.fork))\
-            .options(joinedload(Repository.user))\
-            .options(joinedload(Repository.group))\
+                .options(joinedload(Repository.user))\
+                .options(joinedload(Repository.group))\
 
         return q.one()
 
         
         :param cls:
         """
-        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/')
+        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == 
+                                              cls.url_sep())
         q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
 
     @property
     def just_name(self):
-        return self.repo_name.split(os.sep)[-1]
+        return self.repo_name.split(Repository.url_sep())[-1]
 
     @property
     def groups_with_parents(self):
         Returns base full path for that repository means where it actually
         exists on a filesystem
         """
-        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/')
+        q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == 
+                                              Repository.url_sep())
         q.options(FromCache("sql_cache_short", "repository_repo_path"))
         return q.one().ui_value
 
         # we need to split the name by / since this is how we store the
         # names in the database, but that eventually needs to be converted
         # into a valid system path
-        p += self.repo_name.split('/')
+        p += self.repo_name.split(Repository.url_sep())
         return os.path.join(*p)
 
+    def get_new_name(self, repo_name):
+        """
+        returns new full repository name based on assigned group and new new
+        
+        :param group_name:
+        """
+        path_prefix = self.group.full_path_splitted if self.group else []
+        return Repository.url_sep().join(path_prefix + [repo_name])
+
     @property
     def _ui(self):
         """
                                   self.group_name)
 
     @classmethod
+    def groups_choices(cls):
+        from webhelpers.html import literal as _literal
+        repo_groups = [('', '')]
+        sep = ' &raquo; '
+        _name = lambda k: _literal(sep.join(k))
+
+        repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
+                              for x in cls.query().all()])
+        
+        repo_groups = sorted(repo_groups,key=lambda t: t[1].split(sep)[0])        
+        return repo_groups
+    
+    @classmethod
     def url_sep(cls):
         return '/'
 
+    @classmethod
+    def get_by_group_name(cls, group_name):
+        return cls.query().filter(cls.group_name == group_name).scalar()
+
     @property
     def parents(self):
         parents_recursion_limit = 5
         return Session.query(Group).filter(Group.parent_group == self)
 
     @property
+    def name(self):
+        return self.group_name.split(Group.url_sep())[-1]
+
+    @property
     def full_path(self):
-        return Group.url_sep().join([g.group_name for g in self.parents] +
-                        [self.group_name])
+        return self.group_name
+
+    @property
+    def full_path_splitted(self):
+        return self.group_name.split(Group.url_sep())
 
     @property
     def repositories(self):
 
         return cnt + children_count(self)
 
+
+    def get_new_name(self, group_name):
+        """
+        returns new full group name based on parent and new name
+        
+        :param group_name:
+        """
+        path_prefix = self.parent_group.full_path_splitted if self.parent_group else []
+        return Group.url_sep().join(path_prefix + [group_name])
+
+
 class Permission(Base, BaseModel):
     __tablename__ = 'permissions'
     __table_args__ = {'extend_existing':True}

File rhodecode/model/forms.py

 from pylons.i18n.translation import _
 from webhelpers.pylonslib.secure_form import authentication_token
 
+from rhodecode.config.routing import ADMIN_PREFIX
 from rhodecode.lib.utils import repo_name_slug
 from rhodecode.lib.auth import authenticate, get_crypt_password
 from rhodecode.lib.exceptions import LdapImportError
                 old_un = UserModel().get(old_data.get('user_id')).username
 
             if old_un != value or not edit:
-                if UserModel().get_by_username(value, cache=False,
-                                               case_insensitive=True):
+                if User.get_by_username(value, case_insensitive=True):
                     raise formencode.Invalid(_('This username already '
                                                'exists') , value, state)
 
         def validate_python(self, value, state):
             #TODO WRITE VALIDATIONS
             group_name = value.get('group_name')
-            group_parent_id = int(value.get('group_parent_id') or - 1)
+            group_parent_id = int(value.get('group_parent_id') or -1)
 
             # slugify repo group just in case :)
             slug = repo_name_slug(group_name)
     def validate_python(self, value, state):
         password = value['password']
         username = value['username']
-        user = UserModel().get_by_username(username)
+        user = User.get_by_username(username)
 
         if authenticate(username, password):
             return value
             repo_name = value.get('repo_name')
 
             slug = repo_name_slug(repo_name)
-            if slug in ['_admin', '']:
+            if slug in [ADMIN_PREFIX, '']:
                 e_dict = {'repo_name': _('This repository name is disallowed')}
                 raise formencode.Invalid('', value, state, error_dict=e_dict)
 
                 gr = Group.get(value.get('repo_group'))
                 group_path = gr.full_path
                 # value needs to be aware of group name in order to check
-                # db key This is an actuall just the name to store in the
+                # db key This is an actual just the name to store in the
                 # database
                 repo_name_full = group_path + Group.url_sep() + repo_name
             else:
 
 
             value['repo_name_full'] = repo_name_full
-            if old_data.get('repo_name') != repo_name_full or not edit:
+            rename = old_data.get('repo_name') != repo_name_full
+            create = not edit
+            if  rename or create:
 
                 if group_path != '':
                     if RepoModel().get_by_repo_name(repo_name_full,):
                         e_dict = {'repo_name':_('This repository already '
-                                                'exists in group "%s"') %
+                                                'exists in a group "%s"') %
                                   gr.group_name}
                         raise formencode.Invalid('', value, state,
                                                  error_dict=e_dict)
+                elif Group.get_by_group_name(repo_name_full):
+                        e_dict = {'repo_name':_('There is a group with this'
+                                                ' name already "%s"') %
+                                  repo_name_full}
+                        raise formencode.Invalid('', value, state,
+                                                 error_dict=e_dict)
 
-                else:
-                    if RepoModel().get_by_repo_name(repo_name_full):
+                elif RepoModel().get_by_repo_name(repo_name_full):
                         e_dict = {'repo_name':_('This repository '
                                                 'already exists')}
                         raise formencode.Invalid('', value, state,
                                                  error_dict=e_dict)
+
             return value
 
-
     return _ValidRepoName
 
 def ValidForkName():
             repo_name = value.get('fork_name')
 
             slug = repo_name_slug(repo_name)
-            if slug in ['_admin', '']:
+            if slug in [ADMIN_PREFIX, '']:
                 e_dict = {'repo_name': _('This repository name is disallowed')}
                 raise formencode.Invalid('', value, state, error_dict=e_dict)
 

File rhodecode/model/repo.py

         try:
             cur_repo = self.get_by_repo_name(repo_name, cache=False)
 
-            #update permissions
+            # update permissions
             for member, perm, member_type in form_data['perms_updates']:
                 if member_type == 'user':
                     r2p = self.sa.query(RepoToPerm)\
-                            .filter(RepoToPerm.user == User.by_username(member))\
+                            .filter(RepoToPerm.user == User.get_by_username(member))\
                             .filter(RepoToPerm.repository == cur_repo)\
                             .one()
 
                                                 perm).scalar()
                     self.sa.add(g2p)
 
-            #set new permissions
+            # set new permissions
             for member, perm, member_type in form_data['perms_new']:
                 if member_type == 'user':
                     r2p = RepoToPerm()
                     r2p.repository = cur_repo
-                    r2p.user = User.by_username(member)
+                    r2p.user = User.get_by_username(member)
 
                     r2p.permission = self.sa.query(Permission)\
                                         .filter(Permission.
                                                 .scalar()
                     self.sa.add(g2p)
 
-            #update current repo
+            # update current repo
             for k, v in form_data.items():
                 if k == 'user':
-                    cur_repo.user = User.by_username(v)
+                    cur_repo.user = User.get_by_username(v)
                 elif k == 'repo_name':
-                    cur_repo.repo_name = form_data['repo_name_full']
+                    pass
                 elif k == 'repo_group':
                     cur_repo.group_id = v
 
                 else:
                     setattr(cur_repo, k, v)
 
+            new_name = cur_repo.get_new_name(form_data['repo_name'])
+            cur_repo.repo_name = new_name
+
             self.sa.add(cur_repo)
 
-            if repo_name != form_data['repo_name_full']:
+            if repo_name != new_name:
                 # rename repository
-                self.__rename_repo(old=repo_name,
-                                   new=form_data['repo_name_full'])
+                self.__rename_repo(old=repo_name, new=new_name)
 
             self.sa.commit()
+            return cur_repo
         except:
             log.error(traceback.format_exc())
             self.sa.rollback()
             #create default permission
             repo_to_perm = RepoToPerm()
             default = 'repository.read'
-            for p in UserModel(self.sa).get_by_username('default',
-                                                    cache=False).user_perms:
+            for p in User.get_by_username('default').user_perms:
                 if p.permission.permission_name.startswith('repository.'):
                     default = p.permission.permission_name
                     break
                     .one().permission_id
 
             repo_to_perm.repository = new_repo
-            repo_to_perm.user_id = UserModel(self.sa)\
-                .get_by_username('default', cache=False).user_id
+            repo_to_perm.user_id = User.get_by_username('default').user_id
 
             self.sa.add(repo_to_perm)
 
             from rhodecode.model.scm import ScmModel
             ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
                                              cur_user.user_id)
-
+            return new_repo
         except:
             log.error(traceback.format_exc())
             self.sa.rollback()
         :param parent_id:
         :param clone_uri:
         """
-        from rhodecode.lib.utils import is_valid_repo
+        from rhodecode.lib.utils import is_valid_repo,is_valid_repos_group
 
         if new_parent_id:
             paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
         repo_path = os.path.join(*map(lambda x:safe_str(x),
                                 [self.repos_path, new_parent_path, repo_name]))
 
-        if is_valid_repo(repo_path, self.repos_path) is False:
-            log.info('creating repo %s in %s @ %s', repo_name, repo_path,
-                     clone_uri)
-            backend = get_backend(alias)
+        
+        # check if this path is not a repository
+        if is_valid_repo(repo_path, self.repos_path):
+            raise Exception('This path %s is a valid repository' % repo_path)
 
-            backend(repo_path, create=True, src_url=clone_uri)
+        # check if this path is a group
+        if is_valid_repos_group(repo_path, self.repos_path):
+            raise Exception('This path %s is a valid group' % repo_path)
+                
+        log.info('creating repo %s in %s @ %s', repo_name, repo_path,
+                 clone_uri)
+        backend = get_backend(alias)
+
+        backend(repo_path, create=True, src_url=clone_uri)
 
 
     def __rename_repo(self, old, new):

File rhodecode/model/repos_group.py

         q = RhodeCodeUi.get_by_key('/').one()
         return q.ui_value
 
-    def __create_group(self, group_name, parent_id):
+    def __create_group(self, group_name):
         """
         makes repositories group on filesystem
 
         :param parent_id:
         """
 
-        if parent_id:
-            paths = Group.get(parent_id).full_path.split(Group.url_sep())
-            parent_path = os.sep.join(paths)
-        else:
-            parent_path = ''
-
-        create_path = os.path.join(self.repos_path, parent_path, group_name)
+        create_path = os.path.join(self.repos_path, group_name)
         log.debug('creating new group in %s', create_path)
 
         if os.path.isdir(create_path):
             raise Exception('That directory already exists !')
 
-
         os.makedirs(create_path)
 
-
-    def __rename_group(self, old, old_parent_id, new, new_parent_id):
+    def __rename_group(self, old, new):
         """
         Renames a group on filesystem
         
         :param group_name:
         """
+
+        if old == new:
+            log.debug('skipping group rename')
+            return
+
         log.debug('renaming repos group from %s to %s', old, new)
 
-        if new_parent_id:
-            paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
-            new_parent_path = os.sep.join(paths)
-        else:
-            new_parent_path = ''
 
-        if old_parent_id:
-            paths = Group.get(old_parent_id).full_path.split(Group.url_sep())
-            old_parent_path = os.sep.join(paths)
-        else:
-            old_parent_path = ''
-
-        old_path = os.path.join(self.repos_path, old_parent_path, old)
-        new_path = os.path.join(self.repos_path, new_parent_path, new)
+        old_path = os.path.join(self.repos_path, old)
+        new_path = os.path.join(self.repos_path, new)
 
         log.debug('renaming repos paths from %s to %s', old_path, new_path)
 
         paths = os.sep.join(paths)
 
         rm_path = os.path.join(self.repos_path, paths)
-        os.rmdir(rm_path)
+        if os.path.isdir(rm_path):
+            # delete only if that path really exists
+            os.rmdir(rm_path)
 
     def create(self, form_data):
         try:
             new_repos_group = Group()
-            new_repos_group.group_name = form_data['group_name']
-            new_repos_group.group_description = \
-                form_data['group_description']
-            new_repos_group.group_parent_id = form_data['group_parent_id']
+            new_repos_group.group_description = form_data['group_description']
+            new_repos_group.parent_group = Group.get(form_data['group_parent_id'])
+            new_repos_group.group_name = new_repos_group.get_new_name(form_data['group_name'])
 
             self.sa.add(new_repos_group)
 
-            self.__create_group(form_data['group_name'],
-                                form_data['group_parent_id'])
+            self.__create_group(new_repos_group.group_name)
 
             self.sa.commit()
+            return new_repos_group
         except:
             log.error(traceback.format_exc())
             self.sa.rollback()
 
         try:
             repos_group = Group.get(repos_group_id)
-            old_name = repos_group.group_name
-            old_parent_id = repos_group.group_parent_id
+            old_path = repos_group.full_path
 
-            repos_group.group_name = form_data['group_name']
-            repos_group.group_description = \
-                form_data['group_description']
-            repos_group.group_parent_id = form_data['group_parent_id']
+            #change properties
+            repos_group.group_description = form_data['group_description']
+            repos_group.parent_group = Group.get(form_data['group_parent_id'])
+            repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
+
+            new_path = repos_group.full_path
 
             self.sa.add(repos_group)
 
-            if old_name != form_data['group_name'] or (old_parent_id !=
-                                                form_data['group_parent_id']):
-                self.__rename_group(old=old_name, old_parent_id=old_parent_id,
-                                    new=form_data['group_name'],
-                                    new_parent_id=form_data['group_parent_id'])
+            self.__rename_group(old_path, new_path)
+
+            # we need to get all repositories from this new group and 
+            # rename them accordingly to new group path
+            for r in repos_group.repositories:
+                r.repo_name = r.get_new_name(r.just_name)
+                self.sa.add(r)
 
             self.sa.commit()
+            return repos_group
         except:
             log.error(traceback.format_exc())
             self.sa.rollback()

File rhodecode/model/scm.py

 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
     action_logger, EmptyChangeset
 from rhodecode.model import BaseModel
-from rhodecode.model.user import UserModel
 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
-    UserFollowing, UserLog
+    UserFollowing, UserLog, User
 
 log = logging.getLogger(__name__)
 
         repos_list = {}
 
         for name, path in get_filesystem_repos(repos_path, recursive=True):
+            
+            # name need to be decomposed and put back together using the /
+            # since this is internal storage separator for rhodecode
+            name = Repository.url_sep().join(name.split(os.sep))
+            
             try:
                 if name in repos_list:
                     raise RepositoryError('Duplicate repository name %s '
-                                    'found in %s' % (name, path))
+                                          'found in %s' % (name, path))
                 else:
 
                     klass = get_backend(path[0])
         return f is not None
 
     def is_following_user(self, username, user_id, cache=False):
-        u = UserModel(self.sa).get_by_username(username)
+        u = User.get_by_username(username)
 
         f = self.sa.query(UserFollowing)\
             .filter(UserFollowing.follows_user == u)\
 
     def get_followers(self, repo_id):
         if not isinstance(repo_id, int):
-            repo_id = getattr(Repository.by_repo_name(repo_id), 'repo_id')
+            repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
 
         return self.sa.query(UserFollowing)\
                 .filter(UserFollowing.follows_repo_id == repo_id).count()
 
     def get_forks(self, repo_id):
         if not isinstance(repo_id, int):
-            repo_id = getattr(Repository.by_repo_name(repo_id), 'repo_id')
+            repo_id = getattr(Repository.get_by_repo_name(repo_id), 'repo_id')
 
         return self.sa.query(Repository)\
                 .filter(Repository.fork_id == repo_id).count()
 
     def pull_changes(self, repo_name, username):
-        dbrepo = Repository.by_repo_name(repo_name)
+        dbrepo = Repository.get_by_repo_name(repo_name)
         clone_uri = dbrepo.clone_uri
         if not clone_uri:
             raise Exception("This repository doesn't have a clone uri")
-        
+
         repo = dbrepo.scm_instance
         try:
             extras = {'ip': '',
             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
-        
-        if isinstance(content,(basestring,)):
+
+        if isinstance(content, (basestring,)):
             content = safe_str(content)
-        elif isinstance(content,file):
+        elif isinstance(content, file):
             content = content.read()
-            
+
         message = safe_str(message)
         path = safe_str(f_path)
         author = safe_str(author)

File rhodecode/public/css/style.css

 }
 
 #header #header-inner {
-height:40px;
+min-height:40px;
 clear:both;
 position:relative;
 background:#003367 url("../images/header_inner.png") repeat-x;
 margin:0;
 padding:0;
+display:block;
 box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 -webkit-border-radius: 4px 4px 4px 4px;
 -khtml-border-radius: 4px 4px 4px 4px; 
 #header #header-inner #home a:hover {
 background-position:0 -40px;
 }
-
+#header #header-inner #logo {
+    float: left;
+    position: absolute;	
+}
 #header #header-inner #logo h1 {
 color:#FFF;
 font-size:18px;
 left:0;
 border-left:none;
 border-right:1px solid #2e5c89;
-padding:8px 8px 4px;
+padding:8px 6px 4px;
 }
 
 #header #header-inner #quick li span.icon_short {
 left:0;
 border-left:none;
 border-right:1px solid #2e5c89;
-padding:9px 4px 4px;
+padding:8px 6px 4px;
+}
+#header #header-inner #quick li span.icon img, #header #header-inner #quick li span.icon_short img {
+	margin: 0px -2px 0px 0px;
 }
 
 #header #header-inner #quick li a:hover {
 }
 
 
+.groups_breadcrumbs a {
+	color: #fff;
+}
+.groups_breadcrumbs a:hover {
+    color: #bfe3ff;
+    text-decoration: none;
+}
+
 .quick_repo_menu{
 	background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
 	cursor: pointer;
     padding-left: 5px;
 }
 
-div.browserblock .search_activate #filter_activate,div.browserblock .add_node a{
-	vertical-align: sub;
-	border: 1px solid;
-	padding:2px;
-	-webkit-border-radius: 4px 4px 4px 4px;
-	-khtml-border-radius: 4px 4px 4px 4px; 
-	-moz-border-radius: 4px 4px 4px 4px;
-	border-radius: 4px 4px 4px 4px;
-	background: url("../images/button.png") repeat-x scroll 0 0 #E5E3E3;
-	border-color: #DDDDDD #DDDDDD #C6C6C6 #C6C6C6;
-	color: #515151;
-}
-
 div.browserblock .search_activate a:hover,div.browserblock .add_node a:hover{
     text-decoration: none !important;    
 }
 border:1px solid #316293;
 }
 
-
-input.ui-button-small {
+.ui-button-small a:hover {
+	
+}
+input.ui-button-small,.ui-button-small {
 background:#e5e3e3 url("../images/button.png") repeat-x !important;
 border-top:1px solid #DDD !important;
 border-left:1px solid #c6c6c6 !important;
 border-radius: 4px 4px 4px 4px !important;
 box-shadow: 0 1px 0 #ececec !important;
 cursor: pointer !important;
-}
-
-input.ui-button-small:hover {
+padding:0px 2px 1px 2px;
+}
+
+input.ui-button-small:hover,.ui-button-small:hover {
 background:#b4b4b4 url("../images/button_selected.png") repeat-x !important;
 border-top:1px solid #ccc !important;
 border-left:1px solid #bebebe !important;
 border-right:1px solid #b1b1b1 !important;
-border-bottom:1px solid #afafaf !important;	
-}
-
-input.ui-button-small-blue {
+border-bottom:1px solid #afafaf !important;
+text-decoration: none;
+}
+
+input.ui-button-small-blue,.ui-button-small-blue {
 background:#4e85bb url("../images/button_highlight.png") repeat-x;
 border-top:1px solid #5c91a4;
 border-left:1px solid #2a6f89;
 border-radius: 4px 4px 4px 4px;
 box-shadow: 0 1px 0 #ececec;
 cursor: pointer;
+padding:0px 2px 1px 2px;
 }
 
 input.ui-button-small-blue:hover {

File rhodecode/templates/admin/repos_groups/repos_groups.html

 </%def>
 
 <%def name="breadcrumbs()">
+    <span class="groups_breadcrumbs">
     ${_('Groups')} 
     %if c.group.parent_group:
-        &raquo; ${h.link_to(c.group.parent_group.group_name,
-        h.url('repos_group',id=c.group.parent_group.group_id))}
+        &raquo; ${h.link_to(c.group.parent_group.name,
+        h.url('repos_group_home',group_name=c.group.parent_group.group_name))}
     %endif
-    &raquo; "${c.group.group_name}" ${_('with')} 
+    &raquo; "${c.group.name}" ${_('with')}
+    </span> 
 </%def>
 
 <%def name="page_nav()">

File rhodecode/templates/admin/repos_groups/repos_groups_edit.html

 <%inherit file="/base/base.html"/>
 
 <%def name="title()">
-    ${_('Edit repos group')} ${c.repos_group.group_name} - ${c.rhodecode_name}
+    ${_('Edit repos group')} ${c.repos_group.name} - ${c.rhodecode_name}
 </%def>
 <%def name="breadcrumbs_links()">
     ${h.link_to(_('Admin'),h.url('admin_home'))} 
     &raquo; 
     ${h.link_to(_('Repos groups'),h.url('repos_groups'))} 
     &raquo;
-    ${_('edit repos group')} "${c.repos_group.group_name}"
+    ${_('edit repos group')} "${c.repos_group.name}"
 </%def>
 
 <%def name="page_nav()">

File rhodecode/templates/admin/repos_groups/repos_groups_show.html

                       <td>
                           <div style="white-space: nowrap">
                           <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
-                          ${h.link_to(h.literal(' &raquo; '.join([g.group_name for g in gr.parents+[gr]])),url('edit_repos_group',id=gr.group_id))}
+                          ${h.link_to(h.literal(' &raquo; '.join([g.name for g in gr.parents+[gr]])),url('edit_repos_group',id=gr.group_id))}
                           </div>
                       </td>
                       <td>${gr.group_description}</td>
                       <td><b>${gr.repositories.count()}</b></td>
 		               <td>
 		                 ${h.form(url('repos_group', id=gr.group_id),method='delete')}
-		                   ${h.submit('remove_%s' % gr.group_name,'delete',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this group')+"');")}
+		                   ${h.submit('remove_%s' % gr.name,'delete',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this group')+"');")}
 		                 ${h.end_form()}
 		               </td>                      
                   </tr>

File rhodecode/templates/files/files_browser.html

 			${h.form(h.url.current())}
 			<div class="info_box">
 	          <span class="rev">${_('view')}@rev</span> 
-	          <a class="rev" href="${c.url_prev}" title="${_('previous revision')}">&laquo;</a>
+	          <a class="ui-button-small" href="${c.url_prev}" title="${_('previous revision')}">&laquo;</a>
 	          ${h.text('at_rev',value=c.changeset.revision,size=5)}
-	          <a class="rev" href="${c.url_next}" title="${_('next revision')}">&raquo;</a>
+	          <a class="ui-button-small" href="${c.url_next}" title="${_('next revision')}">&raquo;</a>
 	          ## ${h.submit('view',_('view'),class_="ui-button-small")}
 		    </div>           
 			${h.end_form()}
 	    </div>
         <div class="browser-search">
               <div id="search_activate_id" class="search_activate">
-                  <a id="filter_activate" href="#">${_('search file list')}</a>
+                  <a class="ui-button-small" id="filter_activate" href="#">${_('search file list')}</a>
               </div>
               % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):            
-                    <div  id="add_node_id" class="add_node">
-                        <a href="${h.url('files_add_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path)}">${_('add new file')}</a>
+                    <div id="add_node_id" class="add_node">
+                        <a class="ui-button-small" href="${h.url('files_add_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path)}">${_('add new file')}</a>
                     </div>
               % endif               
         <div>

File rhodecode/templates/index_base.html

                       <td>
                           <div style="white-space: nowrap">
                           <img class="icon" alt="${_('Repositories group')}" src="${h.url('/images/icons/database_link.png')}"/>
-                          ${h.link_to(gr.group_name,url('repos_group',id=gr.group_id))}
+                          ${h.link_to(gr.name,url('repos_group_home',group_name=gr.group_name))}
                           </div>
                       </td>