Changeset - 51bd5404529c
[Not reviewed]
CONTRIBUTORS
Show inline comments
 
@@ -4,6 +4,7 @@ List of contributors to RhodeCode projec
 
    Jason Harris <jason@jasonfharris.com>
 
    Thayne Harbaugh  <thayne@fusionio.com>
 
    cejones
 
    Thomas Waldmann <tw-public@gmx.de>
 
    Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>
 
    Dmitri Kuznetsov
 
    Jared Bunting <jared.bunting@peachjean.com>
 
@@ -11,4 +12,4 @@ List of contributors to RhodeCode projec
 
    Augosto Hermann <augusto.herrmann@planejamento.gov.br>    
 
    Ankit Solanki <ankit.solanki@gmail.com>    
 
    Liad Shani <liadff@gmail.com>
 
    
 
    Les Peabody <lpeabody@gmail.com>
docs/changelog.rst
Show inline comments
 
@@ -13,9 +13,34 @@ Changelog
 
news
 
----
 

	
 
 
 
fixes
 
-----
 

	
 

	
 
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**)
 
======================
 

	
docs/setup.rst
Show inline comments
 
@@ -443,8 +443,8 @@ in the production.ini file::
 
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::
 

	
 
@@ -503,6 +503,31 @@ then change <someprefix> into your choos
 
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::
 

	
 
@@ -512,6 +537,9 @@ 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
 
@@ -519,6 +547,10 @@ Example wsgi dispatch script::
 
    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
 
-------------------------
init.d/rhodecode-daemon3
Show inline comments
 
new file 100644
 
#!/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
 
\ No newline at end of file
rhodecode/__init__.py
Show inline comments
 
@@ -35,7 +35,7 @@ PLATFORM_WIN = ('Windows')
 
PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS')
 

	
 
try:
 
    from rhodecode.lib.utils import get_current_revision
 
    from rhodecode.lib import get_current_revision
 
    _rev = get_current_revision()
 
except ImportError:
 
    #this is needed when doing some setup.py operations
rhodecode/config/routing.py
Show inline comments
 
@@ -19,10 +19,10 @@ def make_map(config):
 
                 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
 
@@ -30,7 +30,7 @@ def make_map(config):
 
        :param environ:
 
        :param match_dict:
 
        """
 
         
 

	
 
        repo_name = match_dict.get('repo_name')
 
        return is_valid_repo(repo_name, config['base_path'])
 

	
 
@@ -42,7 +42,7 @@ def make_map(config):
 
        :param match_dict:
 
        """
 
        repos_group_name = match_dict.get('group_name')
 
        
 

	
 
        return is_valid_repos_group(repos_group_name, config['base_path'])
 

	
 

	
 
@@ -333,13 +333,13 @@ def make_map(config):
 
    # 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))
rhodecode/controllers/admin/repos.py
Show inline comments
 
@@ -64,20 +64,10 @@ class ReposController(BaseController):
 
        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()
 

	
 
@@ -90,7 +80,7 @@ class ReposController(BaseController):
 
        self.__load_defaults()
 

	
 
        c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
 
        repo = scm_repo = db_repo.scm_instance
 
        repo = db_repo.scm_instance
 

	
 
        if c.repo_info is None:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
@@ -234,11 +224,11 @@ class ReposController(BaseController):
 
                         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)
 

	
rhodecode/controllers/admin/repos_groups.py
Show inline comments
 
@@ -9,9 +9,10 @@ from pylons import request, response, se
 
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
 
@@ -31,19 +32,7 @@ class ReposGroupsController(BaseControll
 
        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):
 
@@ -58,6 +47,8 @@ class ReposGroupsController(BaseControll
 

	
 
        data = repo_group.get_dict()
 

	
 
        data['group_name'] = repo_group.name
 

	
 
        return data
 

	
 
    @HasPermissionAnyDecorator('hg.admin')
 
@@ -169,13 +160,28 @@ class ReposGroupsController(BaseControll
 
            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)
rhodecode/controllers/admin/settings.py
Show inline comments
 
@@ -366,17 +366,7 @@ class SettingsController(BaseController)
 
    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', '')
rhodecode/controllers/files.py
Show inline comments
 
@@ -316,13 +316,6 @@ class FilesController(BaseRepoController
 
                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
 

	
rhodecode/lib/__init__.py
Show inline comments
 
@@ -23,6 +23,8 @@
 
# 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
 
@@ -379,3 +381,28 @@ def get_changeset_safe(repo, rev):
 
        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
 

	
rhodecode/lib/celerylib/__init__.py
Show inline comments
 
@@ -94,11 +94,11 @@ def __get_lockkey(func, *fargs, **fkwarg
 
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
rhodecode/lib/celerylib/tasks.py
Show inline comments
 
@@ -97,10 +97,11 @@ def get_commits_stats(repo_name, ts_min_
 

	
 
    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('"', "")
rhodecode/lib/compat.py
Show inline comments
 
@@ -24,6 +24,9 @@
 
# 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
 
#==============================================================================
 
@@ -358,3 +361,19 @@ class OrderedDict(_odict, dict):
 
# 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
rhodecode/lib/helpers.py
Show inline comments
 
@@ -598,12 +598,11 @@ def repo_link(groups_and_repos):
 
        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
rhodecode/lib/indexers/__init__.py
Show inline comments
 
@@ -101,7 +101,7 @@ class MakeIndex(BasePasterCommand):
 
        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)\
rhodecode/lib/pidlock.py
Show inline comments
 
@@ -6,20 +6,7 @@ import errno
 
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
 
@@ -29,17 +16,17 @@ class DaemonLock(object):
 
    """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
rhodecode/lib/utils.py
Show inline comments
 
@@ -360,16 +360,19 @@ def map_groups(groups):
 

	
 
    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
 

	
 

	
 
@@ -386,8 +389,13 @@ def repo2db_mapper(initial_repo_list, re
 
    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)
 
@@ -442,26 +450,6 @@ def add_cache(settings):
 
            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
 
#==============================================================================
 
@@ -483,7 +471,7 @@ def create_test_index(repo_location, con
 
        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)
rhodecode/model/db.py
Show inline comments
 
@@ -31,9 +31,10 @@ from datetime import date
 

	
 
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
 
@@ -42,13 +43,14 @@ from vcs.exceptions import VCSError
 
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__)
 

	
 
#==============================================================================
 
@@ -126,7 +128,8 @@ class BaseModel(object):
 

	
 
    @classmethod
 
    def get(cls, id_):
 
        return Session.query(cls).get(id_)
 
        if id_:
 
            return Session.query(cls).get(id_)
 

	
 
    @classmethod
 
    def delete(cls, id_):
 
@@ -140,12 +143,34 @@ class RhodeCodeSettings(Base, BaseModel)
 
    __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)
 
@@ -176,14 +201,11 @@ class RhodeCodeSettings(Base, BaseModel)
 
    @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
 

	
 

	
 
@@ -283,7 +305,7 @@ class User(Base, BaseModel):
 
    @classmethod
 
    def get_by_username(cls, username, case_insensitive=False):
 
        if case_insensitive:
 
            return Session.query(cls).filter(cls.username.like(username)).scalar()
 
            return Session.query(cls).filter(cls.username.ilike(username)).scalar()
 
        else:
 
            return Session.query(cls).filter(cls.username == username).scalar()
 

	
 
@@ -486,12 +508,16 @@ class Repository(Base, BaseModel):
 
                                  self.repo_id, self.repo_name)
 

	
 
    @classmethod
 
    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()
 

	
 
@@ -506,13 +532,14 @@ class Repository(Base, BaseModel):
 
        
 
        :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):
 
@@ -541,7 +568,8 @@ class Repository(Base, BaseModel):
 
        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
 

	
 
@@ -551,9 +579,18 @@ class Repository(Base, BaseModel):
 
        # 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):
 
        """
 
@@ -718,9 +755,26 @@ class Group(Base, BaseModel):
 
                                  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
 
@@ -750,9 +804,16 @@ class Group(Base, BaseModel):
 
        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):
 
@@ -771,6 +832,17 @@ class Group(Base, BaseModel):
 

	
 
        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}
rhodecode/model/forms.py
Show inline comments
 
@@ -122,7 +122,7 @@ def ValidReposGroup(edit, old_data):
 
        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)
 
@@ -250,7 +250,7 @@ def ValidRepoName(edit, old_data):
 
                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:
 
@@ -259,25 +259,32 @@ def ValidRepoName(edit, old_data):
 

	
 

	
 
            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():
rhodecode/model/repo.py
Show inline comments
 
@@ -98,7 +98,7 @@ class RepoModel(BaseModel):
 
        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)\
 
@@ -122,7 +122,7 @@ class RepoModel(BaseModel):
 
                                                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()
 
@@ -144,26 +144,29 @@ class RepoModel(BaseModel):
 
                                                .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.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()
 
@@ -235,7 +238,7 @@ class RepoModel(BaseModel):
 
            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()
 
@@ -302,7 +305,7 @@ class RepoModel(BaseModel):
 
        :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())
 
@@ -313,12 +316,20 @@ class RepoModel(BaseModel):
 
        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):
rhodecode/model/repos_group.py
Show inline comments
 
@@ -50,7 +50,7 @@ class ReposGroupModel(BaseModel):
 
        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
 

	
 
@@ -58,44 +58,30 @@ class ReposGroupModel(BaseModel):
 
        :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)
 

	
 
@@ -114,22 +100,23 @@ class ReposGroupModel(BaseModel):
 
        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()
 
@@ -139,23 +126,27 @@ class ReposGroupModel(BaseModel):
 

	
 
        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()
rhodecode/model/scm.py
Show inline comments
 
@@ -22,6 +22,7 @@
 
#
 
# 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
 
import time
 
import traceback
 
import logging
 
@@ -146,10 +147,15 @@ class ScmModel(BaseModel):
 
        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])
rhodecode/public/css/style.css
Show inline comments
 
@@ -246,12 +246,13 @@ color:#FFF;
 
}
 
 
#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; 
 
@@ -272,7 +273,10 @@ padding:0;
 
#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;
 
@@ -348,7 +352,7 @@ top:0;
 
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 {
 
@@ -356,7 +360,10 @@ top:0;
 
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 {
 
@@ -564,6 +571,14 @@ padding:12px 9px 7px 24px;
 
}
 
 
 
.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;
 
@@ -1895,19 +1910,6 @@ div.browserblock .add_node{
 
    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;    
 
}
 
@@ -2371,8 +2373,10 @@ border-left:1px solid #316293;
 
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;
 
@@ -2387,17 +2391,19 @@ margin:0 !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;
 
@@ -2410,6 +2416,7 @@ color:#fff;
 
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 {
rhodecode/templates/admin/repos_groups/repos_groups.html
Show inline comments
 
@@ -5,12 +5,14 @@
 
</%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()">
rhodecode/templates/admin/repos_groups/repos_groups_edit.html
Show inline comments
 
@@ -2,14 +2,14 @@
 
<%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()">
rhodecode/templates/admin/repos_groups/repos_groups_show.html
Show inline comments
 
@@ -44,14 +44,14 @@
 
                      <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>
rhodecode/templates/files/files_browser.html
Show inline comments
 
@@ -11,9 +11,9 @@
 
			${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()}
 
@@ -24,11 +24,11 @@
 
	    </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>
rhodecode/templates/index_base.html
Show inline comments
 
@@ -35,7 +35,7 @@
 
                      <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>
 
                      <td>${gr.group_description}</td>
rhodecode/templates/summary/summary.html
Show inline comments
 
@@ -45,17 +45,17 @@
 
                 
 
                 ##REPO TYPE
 
		         %if c.dbrepo.repo_type =='hg':
 
		           <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
 
		           <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url('/images/icons/hgicon.png')}"/>
 
		         %endif
 
		         %if c.dbrepo.repo_type =='git':
 
		           <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
 
		           <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url('/images/icons/giticon.png')}"/>
 
		         %endif 
 
                            
 
                 ##PUBLIC/PRIVATE     			  
 
	             %if c.dbrepo.private:
 
	                <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url("/images/icons/lock.png")}"/>
 
	                <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url('/images/icons/lock.png')}"/>
 
	             %else:
 
	                <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url("/images/icons/lock_open.png")}"/>
 
	                <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url('/images/icons/lock_open.png')}"/>
 
	             %endif
 
	             
 
	              ##REPO NAME
 
@@ -67,7 +67,7 @@
 
	            	<a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}">
 
	            	<img class="icon" alt="${_('public')}"
 
	            	title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" 
 
	            	src="${h.url("/images/icons/arrow_divide.png")}"/>
 
	            	src="${h.url('/images/icons/arrow_divide.png')}"/>
 
	            	${_('Fork of')} ${c.dbrepo.fork.repo_name}
 
	            	</a>
 
	            	</div>
 
@@ -78,7 +78,7 @@
 
                    <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}">
 
                    <img class="icon" alt="${_('remote clone')}"
 
                    title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" 
 
                    src="${h.url("/images/icons/connect.png")}"/>
 
                    src="${h.url('/images/icons/connect.png')}"/>
 
                    ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
 
                    </a>
 
                    </div>					
 
@@ -151,7 +151,7 @@
 
		        %elif c.enable_downloads is False:
 
		          ${_('Downloads are disabled for this repository')}
 
                    %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
 
                        [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
 
                        ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-button-small")}
 
                    %endif  		          
 
		        %else:
 
			        ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
 
@@ -317,7 +317,7 @@
 
         %if c.no_data:
 
           ${c.no_data_msg}
 
           %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
 
                [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
 
                ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-button-small")}
 
           %endif         
 
           
 
        %else:
rhodecode/tests/functional/test_changelog.py
Show inline comments
 
@@ -13,7 +13,7 @@ class TestChangelogController(TestContro
 
                        """name="5e204e7583b9" type="checkbox" value="1" />"""
 
                        in response.body)
 
        self.assertTrue("""<span>commit 154: 5e204e7583b9@2010-08-10 """
 
                        """01:18:46</span>""" in response.body)
 
                        """02:18:46</span>""" in response.body)
 
        self.assertTrue("""Small update at simplevcs app""" in response.body)
 

	
 

	
 
@@ -43,7 +43,7 @@ class TestChangelogController(TestContro
 
                        """name="46ad32a4f974" type="checkbox" value="1" />"""
 
                        in response.body)
 
        self.assertTrue("""<span>commit 64: 46ad32a4f974@2010-04-20"""
 
                        """ 00:33:21</span>"""in response.body)
 
                        """ 01:33:21</span>"""in response.body)
 

	
 
        self.assertTrue("""<span id="46ad32a4f974e45472a898c6b0acb600320"""
 
                        """579b1" class="changed_total tooltip" """
rhodecode/tests/functional/test_login.py
Show inline comments
 
@@ -145,8 +145,8 @@ class TestLoginController(TestController
 
                                             'lastname':'test'})
 

	
 
        self.assertEqual(response.status , '200 OK')
 
        assert 'An email address must contain a single @' in response.body
 
        assert 'This username already exists' in response.body
 
        self.assertTrue('An email address must contain a single @' in response.body)
 
        self.assertTrue('This username already exists' in response.body)
 

	
 

	
 

	
 
@@ -160,7 +160,7 @@ class TestLoginController(TestController
 
                                             'lastname':'test'})
 

	
 
        self.assertEqual(response.status , '200 OK')
 
        assert 'Invalid characters in password' in response.body
 
        self.assertTrue('Invalid characters in password' in response.body)
 

	
 

	
 
    def test_register_password_mismatch(self):
rhodecode/tests/test_models.py
Show inline comments
 
import os
 
import unittest
 
from rhodecode.tests import *
 

	
 
from rhodecode.model.repos_group import ReposGroupModel
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.db import Group, User
 
from sqlalchemy.exc import IntegrityError
 

	
 
class TestReposGroups(unittest.TestCase):
 

	
 
    def setUp(self):
 
        self.g1 = self.__make_group('test1', skip_if_exists=True)
 
        self.g2 = self.__make_group('test2', skip_if_exists=True)
 
        self.g3 = self.__make_group('test3', skip_if_exists=True)
 

	
 
    def tearDown(self):
 
        print 'out'
 

	
 
    def __check_path(self, *path):
 
        path = [TESTS_TMP_PATH] + list(path)
 
        path = os.path.join(*path)
 
        return os.path.isdir(path)
 

	
 
    def _check_folders(self):
 
        print os.listdir(TESTS_TMP_PATH)
 

	
 
    def __make_group(self, path, desc='desc', parent_id=None,
 
                     skip_if_exists=False):
 

	
 
        gr = Group.get_by_group_name(path)
 
        if gr and skip_if_exists:
 
            return gr
 

	
 
        form_data = dict(group_name=path,
 
                         group_description=desc,
 
                         group_parent_id=parent_id)
 
        gr = ReposGroupModel().create(form_data)
 
        return gr
 

	
 
    def __delete_group(self, id_):
 
        ReposGroupModel().delete(id_)
 

	
 

	
 
    def __update_group(self, id_, path, desc='desc', parent_id=None):
 
        form_data = dict(group_name=path,
 
                         group_description=desc,
 
                         group_parent_id=parent_id)
 

	
 
        gr = ReposGroupModel().update(id_, form_data)
 
        return gr
 

	
 
    def test_create_group(self):
 
        g = self.__make_group('newGroup')
 
        self.assertEqual(g.full_path, 'newGroup')
 

	
 
        self.assertTrue(self.__check_path('newGroup'))
 

	
 

	
 
    def test_create_same_name_group(self):
 
        self.assertRaises(IntegrityError, lambda:self.__make_group('newGroup'))
 

	
 

	
 
    def test_same_subgroup(self):
 
        sg1 = self.__make_group('sub1', parent_id=self.g1.group_id)
 
        self.assertEqual(sg1.parent_group, self.g1)
 
        self.assertEqual(sg1.full_path, 'test1/sub1')
 
        self.assertTrue(self.__check_path('test1', 'sub1'))
 

	
 
        ssg1 = self.__make_group('subsub1', parent_id=sg1.group_id)
 
        self.assertEqual(ssg1.parent_group, sg1)
 
        self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
 
        self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
 

	
 

	
 
    def test_remove_group(self):
 
        sg1 = self.__make_group('deleteme')
 
        self.__delete_group(sg1.group_id)
 

	
 
        self.assertEqual(Group.get(sg1.group_id), None)
 
        self.assertFalse(self.__check_path('deteteme'))
 

	
 
        sg1 = self.__make_group('deleteme', parent_id=self.g1.group_id)
 
        self.__delete_group(sg1.group_id)
 

	
 
        self.assertEqual(Group.get(sg1.group_id), None)
 
        self.assertFalse(self.__check_path('test1', 'deteteme'))
 

	
 

	
 
    def test_rename_single_group(self):
 
        sg1 = self.__make_group('initial')
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after')
 
        self.assertTrue(self.__check_path('after'))
 
        self.assertEqual(Group.get_by_group_name('initial'), None)
 

	
 

	
 
    def test_update_group_parent(self):
 

	
 
        sg1 = self.__make_group('initial', parent_id=self.g1.group_id)
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
 
        self.assertTrue(self.__check_path('test1', 'after'))
 
        self.assertEqual(Group.get_by_group_name('test1/initial'), None)
 

	
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
 
        self.assertTrue(self.__check_path('test3', 'after'))
 
        self.assertEqual(Group.get_by_group_name('test3/initial'), None)
 

	
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'hello')
 
        self.assertTrue(self.__check_path('hello'))
 

	
 
        self.assertEqual(Group.get_by_group_name('hello'), new_sg1)
 

	
 

	
 

	
 
    def test_subgrouping_with_repo(self):
 

	
 
        g1 = self.__make_group('g1')
 
        g2 = self.__make_group('g2')
 

	
 
        # create new repo
 
        form_data = dict(repo_name='john',
 
                         repo_name_full='john',
 
                         fork_name=None,
 
                         description=None,
 
                         repo_group=None,
 
                         private=False,
 
                         repo_type='hg',
 
                         clone_uri=None)
 
        cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
 
        r = RepoModel().create(form_data, cur_user)
 

	
 
        self.assertEqual(r.repo_name, 'john')
 

	
 
        # put repo into group
 
        form_data = form_data
 
        form_data['repo_group'] = g1.group_id
 
        form_data['perms_new'] = []
 
        form_data['perms_updates'] = []
 
        RepoModel().update(r.repo_name, form_data)
 
        self.assertEqual(r.repo_name, 'g1/john')
 

	
 

	
 
        self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
 
        self.assertTrue(self.__check_path('g2', 'g1'))
 

	
 
        # test repo
 
        self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name))
 

	
 

	
setup.py
Show inline comments
 
@@ -11,30 +11,32 @@ if py_version < (2, 5):
 

	
 
requirements = [
 
        "Pylons==1.0.0",
 
        "Beaker==1.5.4",
 
        "WebHelpers>=1.2",
 
        "formencode==1.2.4",
 
        "SQLAlchemy>=0.7.2,<0.8",
 
        "Mako>=0.4.2",
 
        "SQLAlchemy==0.7.3",
 
        "Mako==0.5.0",
 
        "pygments>=1.4",
 
        "mercurial>=1.9,<2.0",
 
        "mercurial>=1.9.3,<2.0",
 
        "whoosh<1.8",
 
        "celery>=2.2.5,<2.3",
 
        "babel",
 
        "python-dateutil>=1.5.0,<2.0.0",
 
        "dulwich>=0.8.0",
 
        "vcs>=0.2.1.dev",
 
        "dulwich>=0.8.0,<0.9.0",
 
        "vcs>=0.2.3.dev",
 
        "webob==1.0.8"
 
    ]
 

	
 
dependency_links = [
 
    "https://secure.rhodecode.org/vcs/archive/default.zip#egg=vcs-0.2.2.dev",
 
    "https://bitbucket.org/marcinkuzminski/vcs/get/default.zip#egg=vcs-0.2.2.dev",
 
    "https://secure.rhodecode.org/vcs/archive/default.zip#egg=vcs-0.2.3.dev",
 
    "https://bitbucket.org/marcinkuzminski/vcs/get/default.zip#egg=vcs-0.2.3.dev",
 
]
 

	
 
classifiers = ['Development Status :: 4 - Beta',
 
               'Environment :: Web Environment',
 
               'Framework :: Pylons',
 
               'Intended Audience :: Developers',
 
               'License :: OSI Approved :: GNU General Public License (GPL)',
 
               'Operating System :: OS Independent',
 
               'Programming Language :: Python',
 
               'Programming Language :: Python :: 2.5',
0 comments (0 inline, 0 general)