Changeset - 93b980ebee55
[Not reviewed]
README.rst
Show inline comments
 
@@ -8,19 +8,19 @@ browser/management tool with a built in 
 
It works on http/https and has a built in permission/authentication system with 
 
the ability to authenticate via LDAP.
 

	
 
RhodeCode is similar in some respects to github or bitbucket, 
 
however RhodeCode can be run as standalone hosted application on your own server.  It is open source 
 
and donation ware and focuses more on providing a customized, self administered 
 
interface for Mercurial(and soon GIT) repositories. RhodeCode is powered by a vcs_ 
 
library that Lukasz Balcerzak and I created to handle multiple different version 
 
control systems.
 
RhodeCode is similar in some respects to github or bitbucket_, 
 
however RhodeCode can be run as standalone hosted application on your own server.  
 
It is open source and donation ware and focuses more on providing a customized, 
 
self administered interface for Mercurial(and soon GIT) repositories. 
 
RhodeCode is powered by a vcs_ library that Lukasz Balcerzak and I created to 
 
handle multiple different version control systems.
 

	
 
RhodeCode uses `Semantic Versioning <http://semver.org/>`_
 

	
 
RhodeCode demo
 
--------------
 

	
 
http://hg.python-works.com
 
http://demo.rhodecode.org
 

	
 
The default access is anonymous but you can login to an administrative account
 
using the following credentials:
 
@@ -31,8 +31,8 @@ using the following credentials:
 
Source code
 
-----------
 

	
 
The latest source for RhodeCode can be obtained from my own RhodeCode instance
 
https://rhodecode.org 
 
The latest source for RhodeCode can be obtained from official RhodeCode instance
 
https://hg.rhodecode.org 
 

	
 
Rarely updated source code and issue tracker is available at bitbcuket
 
http://bitbucket.org/marcinkuzminski/rhodecode
 
@@ -123,6 +123,7 @@ have sphinx installed you can install it
 
.. _python: http://www.python.org/
 
.. _django: http://www.djangoproject.com/
 
.. _mercurial: http://mercurial.selenic.com/
 
.. _bitbucket: http://bitbucket.org/
 
.. _subversion: http://subversion.tigris.org/
 
.. _git: http://git-scm.com/
 
.. _celery: http://celeryproject.org/
docs/changelog.rst
Show inline comments
 
@@ -3,6 +3,28 @@
 
Changelog
 
=========
 

	
 

	
 
1.1.5 (**2011-03-1X**)
 
======================
 

	
 
news
 
----
 

	
 
- basic windows support, by exchanging pybcrypt into sha256 for windows only
 
  highly inspired by idea of mantis406
 

	
 
fixes
 
-----
 

	
 
- fixed sorting by author in main page
 
- fixed crashes with diffs on binary files
 
- fixed #131 problem with boolean values for LDAP
 
- fixed #122 mysql problems thanks to striker69 
 
- fixed problem with errors on calling raw/raw_files/annotate functions 
 
  with unknown revisions
 
- fixed returned rawfiles attachment names with international character
 
- cleaned out docs, big thanks to Jason Harris
 

	
 
1.1.4 (**2011-02-19**)
 
======================
 

	
docs/contributing.rst
Show inline comments
 
@@ -7,13 +7,19 @@ If you would like to contribute to Rhode
 
greatly appreciated!
 

	
 
Could I request that you make your source contributions by first forking the
 
RhodeCode repository on bitbucket
 
RhodeCode repository on bitbucket_
 
https://bitbucket.org/marcinkuzminski/rhodecode and then make your changes to
 
your forked repository. Finally, when you are finished making a change, please
 
send me a pull request.
 
your forked repository. Please post all fixes into **BETA** branch since your 
 
fix might be already fixed there and i try to merge all fixes from beta into
 
stable, and not the other way. Finally, when you are finished making a change, 
 
please send me a pull request.
 

	
 
To run RhodeCode in a development version you always need to install the tip
 
version of RhodeCode and the VCS library.
 

	
 
| Thank you for any contributions!
 
|  Marcin
 
\ No newline at end of file
 
|  Marcin
 

	
 

	
 

	
 
.. _bitbucket: http://bitbucket.org/
docs/index.rst
Show inline comments
 
@@ -48,6 +48,7 @@ Other topics
 
.. _python: http://www.python.org/
 
.. _django: http://www.djangoproject.com/
 
.. _mercurial: http://mercurial.selenic.com/
 
.. _bitbucket: http://bitbucket.org/
 
.. _subversion: http://subversion.tigris.org/
 
.. _git: http://git-scm.com/
 
.. _celery: http://celeryproject.org/
docs/installation.rst
Show inline comments
 
@@ -9,12 +9,13 @@ together with celery you have to install
 
recommended one is rabbitmq_ to make the async tasks work.
 

	
 
Of course RhodeCode works in sync mode also and then you do not have to install
 
any third party applications. However, using Celery_ will give you a large speed improvement when using
 
many big repositories. If you plan to use RhodeCode for say 7 to 10 small repositories, RhodeCode
 
will perform perfectly well without celery running.
 
any third party applications. However, using Celery_ will give you a large 
 
speed improvement when using many big repositories. If you plan to use 
 
RhodeCode for say 7 to 10 small repositories, RhodeCode will perform perfectly 
 
well without celery running.
 
   
 
If you make the decision to run RhodeCode with celery make sure you run celeryd using paster
 
and message broker together with the application.   
 
If you make the decision to run RhodeCode with celery make sure you run 
 
celeryd using paster and message broker together with the application.   
 

	
 
Installing RhodeCode from Cheese Shop
 
-------------------------------------
docs/setup.rst
Show inline comments
 
@@ -348,19 +348,19 @@ Troubleshooting
 
   double check the root path for your http setup. It should point to 
 
   for example:
 
   /home/my-virtual-python/lib/python2.6/site-packages/rhodecode/public
 

	
 
|
 
   
 
| 
 

	
 
:Q: **Can't install celery/rabbitmq**
 
:A: Don't worry RhodeCode works without them too. No extra setup is required.
 

	
 
|
 

	
 
 
 
:Q: **Long lasting push timeouts?**
 
:A: Make sure you set a longer timeouts in your proxy/fcgi settings, timeouts
 
    are caused by https server and not RhodeCode.
 

	
 
|
 
    
 
| 
 

	
 
:Q: **Large pushes timeouts?**
 
:A: Make sure you set a proper max_body_size for the http server.
docs/upgrade.rst
Show inline comments
 
@@ -7,7 +7,8 @@ Upgrading from Cheese Shop
 
--------------------------
 

	
 
.. note::
 
   Firstly, it is recommended that you **always** perform a database backup before doing an upgrade.
 
   Firstly, it is recommended that you **always** perform a database backup 
 
   before doing an upgrade.
 

	
 
The easiest way to upgrade ``rhodecode`` is to run::
 

	
 
@@ -24,15 +25,16 @@ Then make sure you run the following com
 
 
 
This will display any changes made by the new version of RhodeCode to your
 
current configuration. It will try to perform an automerge. It's always better
 
to make a backup of your configuration file before hand and recheck the content after the automerge.
 
to make a backup of your configuration file before hand and recheck the 
 
content after the automerge.
 

	
 
.. note::
 
   The next steps only apply to upgrading from non bugfix releases eg. from
 
   any minor or major releases. Bugfix releases (eg. 1.1.2->1.1.3) will 
 
   not have any database schema changes or whoosh library updates.
 

	
 
It is also recommended that you rebuild the whoosh index after upgrading since the new whoosh 
 
version could introduce some incompatible index changes.
 
It is also recommended that you rebuild the whoosh index after upgrading since 
 
the new whoosh version could introduce some incompatible index changes.
 

	
 

	
 
The final step is to upgrade the database. To do this simply run::
 
@@ -40,8 +42,8 @@ The final step is to upgrade the databas
 
    paster upgrade-db production.ini
 
 
 
This will upgrade the schema and update some of the defaults in the database,
 
and will always recheck the settings of the application, if there are no new options
 
that need to be set.
 
and will always recheck the settings of the application, if there are no new 
 
options that need to be set.
 

	
 

	
 
.. _virtualenv: http://pypi.python.org/pypi/virtualenv  
rhodecode/__init__.py
Show inline comments
 
@@ -25,11 +25,12 @@
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import platform
 

	
 
VERSION = (1, 1, 4)
 
VERSION = (1, 1, 5)
 
__version__ = '.'.join((str(each) for each in VERSION[:4]))
 
__dbversion__ = 2 #defines current db version for migrations
 
__platform__ = platform.system()
 

	
 
try:
 
    from rhodecode.lib.utils import get_current_revision
rhodecode/config/deployment.ini_tmpl
Show inline comments
 
@@ -71,7 +71,7 @@ celery.result.serialier = json
 
celeryd.concurrency = 2
 
#celeryd.log.file = celeryd.log
 
celeryd.log.level = debug
 
celeryd.max.tasks.per.child = 3
 
celeryd.max.tasks.per.child = 1
 

	
 
#tasks will never be sent to the queue, but executed locally instead.
 
celery.always.eager = false
rhodecode/controllers/admin/settings.py
Show inline comments
 
@@ -140,8 +140,8 @@ class SettingsController(BaseController)
 

	
 
                except:
 
                    log.error(traceback.format_exc())
 
                    h.flash(_('error occurred during updating application settings'),
 
                            category='error')
 
                    h.flash(_('error occurred during updating'
 
                              ' application settings'), category='error')
 

	
 
                    self.sa.rollback()
 

	
rhodecode/controllers/files.py
Show inline comments
 
@@ -7,7 +7,7 @@
 
    
 
    :created_on: Apr 21, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
 
    :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
 
@@ -55,9 +55,30 @@ class FilesController(BaseController):
 
        super(FilesController, self).__before__()
 
        c.cut_off_limit = self.cut_off_limit
 

	
 
    def __get_cs_or_redirect(self, rev, repo_name):
 
        """
 
        Safe way to get changeset if error occur it redirects to tip with
 
        proper message
 
        
 
        :param rev: revision to fetch
 
        :param repo_name: repo name to redirect after
 
        """
 

	
 
        _repo = ScmModel().get_repo(c.repo_name)
 
        try:
 
            return _repo.get_changeset(rev)
 
        except EmptyRepositoryError, e:
 
            h.flash(_('There are no files yet'), category='warning')
 
            redirect(h.url('summary_home', repo_name=repo_name))
 

	
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
 

	
 
    def index(self, repo_name, revision, f_path):
 
        hg_model = ScmModel()
 
        c.repo = hg_model.get_repo(c.repo_name)
 
        cs = self.__get_cs_or_redirect(revision, repo_name)
 
        c.repo = ScmModel().get_repo(c.repo_name)
 

	
 
        revision = request.POST.get('at_rev', None) or revision
 

	
 
        def get_next_rev(cur):
 
@@ -72,68 +93,64 @@ class FilesController(BaseController):
 
            return r
 

	
 
        c.f_path = f_path
 
        c.changeset = cs
 
        cur_rev = c.changeset.revision
 
        prev_rev = c.repo.get_changeset(get_prev_rev(cur_rev)).raw_id
 
        next_rev = c.repo.get_changeset(get_next_rev(cur_rev)).raw_id
 

	
 
        c.url_prev = url('files_home', repo_name=c.repo_name,
 
                         revision=prev_rev, f_path=f_path)
 
        c.url_next = url('files_home', repo_name=c.repo_name,
 
                     revision=next_rev, f_path=f_path)
 

	
 
        try:
 
            c.changeset = c.repo.get_changeset(revision)
 
            cur_rev = c.changeset.revision
 
            prev_rev = c.repo.get_changeset(get_prev_rev(cur_rev)).raw_id
 
            next_rev = c.repo.get_changeset(get_next_rev(cur_rev)).raw_id
 

	
 
            c.url_prev = url('files_home', repo_name=c.repo_name,
 
                             revision=prev_rev, f_path=f_path)
 
            c.url_next = url('files_home', repo_name=c.repo_name,
 
                         revision=next_rev, f_path=f_path)
 

	
 
            try:
 
                c.files_list = c.changeset.get_node(f_path)
 
                c.file_history = self._get_history(c.repo, c.files_list, f_path)
 
            except RepositoryError, e:
 
                h.flash(str(e), category='warning')
 
                redirect(h.url('files_home', repo_name=repo_name, revision=revision))
 

	
 
        except EmptyRepositoryError, e:
 
            h.flash(_('There are no files yet'), category='warning')
 
            redirect(h.url('summary_home', repo_name=repo_name))
 

	
 
            c.files_list = c.changeset.get_node(f_path)
 
            c.file_history = self._get_history(c.repo, c.files_list, f_path)
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
 

	
 
            redirect(h.url('files_home', repo_name=repo_name,
 
                           revision=revision))
 

	
 

	
 
        return render('files/files.html')
 

	
 
    def rawfile(self, repo_name, revision, f_path):
 
        hg_model = ScmModel()
 
        c.repo = hg_model.get_repo(c.repo_name)
 
        file_node = c.repo.get_changeset(revision).get_node(f_path)
 
        cs = self.__get_cs_or_redirect(revision, repo_name)
 
        try:
 
            file_node = cs.get_node(f_path)
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name,
 
                           revision=cs.raw_id))
 

	
 
        fname = f_path.split('/')[-1].encode('utf8', 'replace')
 

	
 
        response.content_disposition = 'attachment; filename=%s' % fname
 
        response.content_type = file_node.mimetype
 
        response.content_disposition = 'attachment; filename=%s' \
 
                                                    % f_path.split('/')[-1]
 
        return file_node.content
 

	
 
    def raw(self, repo_name, revision, f_path):
 
        hg_model = ScmModel()
 
        c.repo = hg_model.get_repo(c.repo_name)
 
        file_node = c.repo.get_changeset(revision).get_node(f_path)
 
        cs = self.__get_cs_or_redirect(revision, repo_name)
 
        try:
 
            file_node = cs.get_node(f_path)
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name,
 
                           revision=cs.raw_id))
 

	
 
        response.content_type = 'text/plain'
 

	
 
        return file_node.content
 

	
 
    def annotate(self, repo_name, revision, f_path):
 
        hg_model = ScmModel()
 
        c.repo = hg_model.get_repo(c.repo_name)
 

	
 
        cs = self.__get_cs_or_redirect(revision, repo_name)
 
        try:
 
            c.cs = c.repo.get_changeset(revision)
 
            c.file = c.cs.get_node(f_path)
 
            c.file = cs.get_node(f_path)
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name, revision=revision))
 
            redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
 

	
 
        c.file_history = self._get_history(c.repo, c.file, f_path)
 

	
 
        c.file_history = self._get_history(ScmModel().get_repo(c.repo_name), c.file, f_path)
 
        c.cs = cs
 
        c.f_path = f_path
 

	
 
        return render('files/files_annotate.html')
 
@@ -201,25 +218,34 @@ class FilesController(BaseController):
 
            response.content_type = 'text/plain'
 
            response.content_disposition = 'attachment; filename=%s' \
 
                                                    % diff_name
 
            if node1.is_binary or node2.is_binary:
 
                return _('binary file changed')
 
            return diff.raw_diff()
 

	
 
        elif c.action == 'raw':
 
            response.content_type = 'text/plain'
 
            if node1.is_binary or node2.is_binary:
 
                return _('binary file changed')
 
            return diff.raw_diff()
 

	
 
        elif c.action == 'diff':
 
            if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
 
                c.cur_diff = _('Diff is to big to display')
 
            elif node1.is_binary or node2.is_binary:
 
                c.cur_diff = _('Binary file')
 
            else:
 
                c.cur_diff = diff.as_html()
 
        else:
 
            #default option
 
            if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
 
                c.cur_diff = _('Diff is to big to display')
 
            elif node1.is_binary or node2.is_binary:
 
                c.cur_diff = _('Binary file')
 
            else:
 
                c.cur_diff = diff.as_html()
 

	
 
        if not c.cur_diff: c.no_changes = True
 
        if not c.cur_diff:
 
            c.no_changes = True
 
        return render('files/file_diff.html')
 

	
 
    def _get_history(self, repo, node, f_path):
 
@@ -250,9 +276,3 @@ class FilesController(BaseController):
 
        hist_l.append(tags_group)
 

	
 
        return hist_l
 

	
 
#                [
 
#                 ([("u1", "User1"), ("u2", "User2")], "Users"),
 
#                 ([("g1", "Group1"), ("g2", "Group2")], "Groups")
 
#                 ]
 

	
rhodecode/controllers/home.py
Show inline comments
 
@@ -43,7 +43,7 @@ class HomeController(BaseController):
 
        super(HomeController, self).__before__()
 

	
 
    def index(self):
 
        sortables = ['name', 'description', 'last_change', 'tip', 'contact']
 
        sortables = ['name', 'description', 'last_change', 'tip', 'owner']
 
        current_sort = request.GET.get('sort', 'name')
 
        current_sort_slug = current_sort.replace('-', '')
 

	
rhodecode/controllers/journal.py
Show inline comments
 
@@ -26,9 +26,12 @@
 
# MA  02110-1301, USA.
 

	
 
import logging
 
from sqlalchemy import or_
 
import traceback
 

	
 
from pylons import request, response, session, tmpl_context as c, url
 
from paste.httpexceptions import HTTPInternalServerError, HTTPBadRequest
 

	
 
from sqlalchemy import or_
 

	
 
from rhodecode.lib.auth import LoginRequired, NotAnonymous
 
from rhodecode.lib.base import BaseController, render
 
@@ -36,8 +39,6 @@ from rhodecode.lib.helpers import get_to
 
from rhodecode.model.db import UserLog, UserFollowing
 
from rhodecode.model.scm import ScmModel
 

	
 
from paste.httpexceptions import HTTPInternalServerError
 

	
 
log = logging.getLogger(__name__)
 

	
 
class JournalController(BaseController):
 
@@ -81,6 +82,7 @@ class JournalController(BaseController):
 
                                                    c.rhodecode_user.user_id)
 
                    return 'ok'
 
                except:
 
                    log.error(traceback.format_exc())
 
                    raise HTTPInternalServerError()
 

	
 
            repo_id = request.POST.get('follows_repo_id')
 
@@ -90,8 +92,9 @@ class JournalController(BaseController):
 
                                                    c.rhodecode_user.user_id)
 
                    return 'ok'
 
                except:
 
                    log.error(traceback.format_exc())
 
                    raise HTTPInternalServerError()
 

	
 

	
 

	
 
        raise HTTPInternalServerError()
 
        raise HTTPBadRequest()
rhodecode/lib/__init__.py
Show inline comments
 
@@ -26,4 +26,21 @@
 
# MA  02110-1301, USA.
 

	
 
def str2bool(v):
 
    return v.lower() in ["yes", "true", "t", "1"] if v else None
 
    if isinstance(v, (str, unicode)):
 
        obj = v.strip().lower()
 
        if obj in ['true', 'yes', 'on', 'y', 't', '1']:
 
            return True
 
        elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
 
            return False
 
        else:
 
            raise ValueError("String is not true/false: %r" % obj)
 
    return bool(obj)
 

	
 
def generate_api_key(username, salt=None):
 
    from tempfile import _RandomNameSequence
 
    import hashlib
 

	
 
    if salt is None:
 
        salt = _RandomNameSequence().next()
 

	
 
    return hashlib.sha1(username + salt).hexdigest()
rhodecode/lib/auth.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# authentication and permission libraries
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
#
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.auth
 
    ~~~~~~~~~~~~~~~~~~
 
    
 
    authentication and permission libraries
 
    
 
    :created_on: Apr 4, 2010
 
    :copyright: (c) 2010 by marcink.
 
    :license: LICENSE_NAME, see LICENSE_FILE 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; version 2
 
@@ -17,26 +23,34 @@
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on April 4, 2010
 

	
 
@author: marcink
 
"""
 
import random
 
import logging
 
import traceback
 

	
 
from decorator import decorator
 

	
 
from pylons import config, session, url, request
 
from pylons.controllers.util import abort, redirect
 
from rhodecode.lib.exceptions import *
 
from pylons.i18n.translation import _
 

	
 
from rhodecode import __platform__
 

	
 
if __platform__ == 'Windows':
 
    from hashlib import sha256
 
if __platform__ in ('Linux', 'Darwin'):
 
    import bcrypt
 

	
 
from rhodecode.lib import str2bool
 
from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
 
from rhodecode.lib.utils import get_repo_slug
 
from rhodecode.lib.auth_ldap import AuthLdap
 

	
 
from rhodecode.model import meta
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
 
    UserToPerm
 
import bcrypt
 
from decorator import decorator
 
import logging
 
import random
 
import traceback
 
from rhodecode.model.db import Permission, RepoToPerm, Repository, \
 
    User, UserToPerm
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
@@ -65,15 +79,46 @@ class PasswordGenerator(object):
 
        self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
 
        return self.passwd
 

	
 
class RhodeCodeCrypto(object):
 

	
 
    @classmethod
 
    def hash_string(cls, str_):
 
        """
 
        Cryptographic function used for password hashing based on pybcrypt
 
        or pycrypto in windows
 
        
 
        :param password: password to hash
 
        """
 
        if __platform__ == 'Windows':
 
            return sha256(str_).hexdigest()
 
        elif __platform__ in ('Linux', 'Darwin'):
 
            return bcrypt.hashpw(str_, bcrypt.gensalt(10))
 
        else:
 
            raise Exception('Unknown or unsupported platform %s' % __platform__)
 

	
 
    @classmethod
 
    def hash_check(cls, password, hashed):
 
        """
 
        Checks matching password with it's hashed value, runs different
 
        implementation based on platform it runs on
 
        
 
        :param password: password
 
        :param hashed: password in hashed form
 
        """
 

	
 
        if __platform__ == 'Windows':
 
            return sha256(password).hexdigest() == hashed
 
        elif __platform__ in ('Linux', 'Darwin'):
 
            return bcrypt.hashpw(password, hashed) == hashed
 
        else:
 
            raise Exception('Unknown or unsupported platform %s' % __platform__)
 

	
 

	
 
def get_crypt_password(password):
 
    """Cryptographic function used for password hashing based on sha1
 
    :param password: password to hash
 
    """
 
    return bcrypt.hashpw(password, bcrypt.gensalt(10))
 
    return RhodeCodeCrypto.hash_string(password)
 

	
 
def check_password(password, hashed):
 
    return bcrypt.hashpw(password, hashed) == hashed
 
    return RhodeCodeCrypto.hash_check(password, hashed)
 

	
 
def authfunc(environ, username, password):
 
    """
 
@@ -126,7 +171,7 @@ def authenticate(username, password):
 
        #======================================================================
 
        # FALLBACK TO LDAP AUTH IN ENABLE                
 
        #======================================================================
 
        if ldap_settings.get('ldap_active', False):
 
        if str2bool(ldap_settings.get('ldap_active')):
 
            log.debug("Authenticating user using ldap")
 
            kwargs = {
 
                  'server':ldap_settings.get('ldap_host', ''),
 
@@ -134,7 +179,7 @@ def authenticate(username, password):
 
                  'port':ldap_settings.get('ldap_port'),
 
                  'bind_dn':ldap_settings.get('ldap_dn_user'),
 
                  'bind_pass':ldap_settings.get('ldap_dn_pass'),
 
                  'use_ldaps':ldap_settings.get('ldap_ldaps'),
 
                  'use_ldaps':str2bool(ldap_settings.get('ldap_ldaps')),
 
                  'ldap_version':3,
 
                  }
 
            log.debug('Checking for ldap authentication')
rhodecode/lib/auth_ldap.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# ldap authentication lib
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
# Copyright (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
#
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
rhodecode/lib/db_manage.py
Show inline comments
 
@@ -60,39 +60,19 @@ class DbManage(object):
 
        init_model(engine)
 
        self.sa = meta.Session()
 

	
 
    def check_for_db(self, override):
 
        db_path = jn(self.root, self.dbname)
 
        if self.dburi.startswith('sqlite'):
 
            log.info('checking for existing db in %s', db_path)
 
            if os.path.isfile(db_path):
 

	
 
                self.db_exists = True
 
                if not override:
 
                    raise Exception('database already exists')
 
            return 'sqlite'
 
        if self.dburi.startswith('postgresql'):
 
            self.db_exists = True
 
            return 'postgresql'
 

	
 

	
 
    def create_tables(self, override=False):
 
        """Create a auth database
 
        """
 

	
 
        db_type = self.check_for_db(override)
 
        if self.db_exists:
 
            log.info("database exist and it's going to be destroyed")
 
            if self.tests:
 
                destroy = True
 
            else:
 
                destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
 
            if not destroy:
 
                sys.exit()
 
            if self.db_exists and destroy:
 
                if db_type == 'sqlite':
 
                    os.remove(jn(self.root, self.dbname))
 
                if db_type == 'postgresql':
 
                    meta.Base.metadata.drop_all()
 
        log.info("Any existing database is going to be destroyed")
 
        if self.tests:
 
            destroy = True
 
        else:
 
            destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
 
        if not destroy:
 
            sys.exit()
 
        if destroy:
 
            meta.Base.metadata.drop_all()
 

	
 
        checkfirst = not override
 
        meta.Base.metadata.create_all(checkfirst=checkfirst)
 
@@ -322,10 +302,14 @@ class DbManage(object):
 
        """Creates ldap settings"""
 

	
 
        try:
 
            for k in ['ldap_active', 'ldap_host', 'ldap_port', 'ldap_ldaps',
 
                      'ldap_dn_user', 'ldap_dn_pass', 'ldap_base_dn']:
 
            for k, v in [('ldap_active', 'false'),
 
                        ('ldap_host', ''),
 
                        ('ldap_port', '389'),
 
                        ('ldap_ldaps', 'false'),
 
                        ('ldap_dn_user', ''), ('ldap_dn_pass', ''),
 
                        ('ldap_base_dn', '')]:
 

	
 
                setting = RhodeCodeSettings(k, '')
 
                setting = RhodeCodeSettings(k, v)
 
                self.sa.add(setting)
 
            self.sa.commit()
 
        except:
rhodecode/lib/helpers.py
Show inline comments
 
@@ -230,6 +230,8 @@ tooltip = _ToolTip()
 
class _FilesBreadCrumbs(object):
 

	
 
    def __call__(self, repo_name, rev, paths):
 
        if isinstance(paths, str):
 
            paths = paths.decode('utf-8', 'replace')
 
        url_l = [link_to(repo_name, url('files_home',
 
                                        repo_name=repo_name,
 
                                        revision=rev, f_path=''))]
 
@@ -483,7 +485,7 @@ def action_parser_icon(user_log):
 
    if len(x) > 1:
 
        action, action_params = x
 

	
 
    tmpl = """<img src="%s/%s" alt="%s"/>"""
 
    tmpl = """<img src="%s%s" alt="%s"/>"""
 
    map = {'user_deleted_repo':'database_delete.png',
 
           'user_created_repo':'database_add.png',
 
           'user_forked_repo':'arrow_divide.png',
 
@@ -550,6 +552,6 @@ def changed_tooltip(nodes):
 
        suf = ''
 
        if len(nodes) > 30:
 
            suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
 
        return literal(pref + '<br/> '.join([x.path for x in nodes[:30]]) + suf)
 
        return literal(pref + '<br/> '.join([x.path.decode('utf-8', 'replace') for x in nodes[:30]]) + suf)
 
    else:
 
        return ': ' + _('No Files')
rhodecode/model/db.py
Show inline comments
 
@@ -30,51 +30,20 @@ from datetime import date
 

	
 
from sqlalchemy import *
 
from sqlalchemy.exc import DatabaseError
 
from sqlalchemy.orm import relationship, backref, class_mapper
 
from sqlalchemy.orm.session import Session
 
from sqlalchemy.orm import relationship, backref
 
from sqlalchemy.orm.interfaces import MapperExtension
 

	
 
from rhodecode.model.meta import Base
 
from rhodecode.model.meta import Base, Session
 

	
 
log = logging.getLogger(__name__)
 

	
 
class BaseModel(object):
 

	
 
    @classmethod
 
    def _get_keys(cls):
 
        """return column names for this model """
 
        return class_mapper(cls).c.keys()
 

	
 
    def get_dict(self):
 
        """return dict with keys and values corresponding 
 
        to this model data """
 

	
 
        d = {}
 
        for k in self._get_keys():
 
            d[k] = getattr(self, k)
 
        return d
 

	
 
    def get_appstruct(self):
 
        """return list with keys and values tupples corresponding 
 
        to this model data """
 

	
 
        l = []
 
        for k in self._get_keys():
 
            l.append((k, getattr(self, k),))
 
        return l
 

	
 
    def populate_obj(self, populate_dict):
 
        """populate model with data from given populate_dict"""
 

	
 
        for k in self._get_keys():
 
            if k in populate_dict:
 
                setattr(self, k, populate_dict[k])
 

	
 
class RhodeCodeSettings(Base, BaseModel):
 
class RhodeCodeSettings(Base):
 
    __tablename__ = 'rhodecode_settings'
 
    __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':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=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    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)
 

	
 
    def __init__(self, k='', v=''):
 
        self.app_settings_name = k
 
@@ -84,27 +53,27 @@ class RhodeCodeSettings(Base, BaseModel)
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.app_settings_name, self.app_settings_value)
 

	
 
class RhodeCodeUi(Base, BaseModel):
 
class RhodeCodeUi(Base):
 
    __tablename__ = 'rhodecode_ui'
 
    __table_args__ = {'useexisting':True}
 
    ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    ui_section = Column("ui_section", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_key = Column("ui_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_value = Column("ui_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
 

	
 

	
 
class User(Base, BaseModel):
 
class User(Base):
 
    __tablename__ = 'users'
 
    __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
 
    user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    username = Column("username", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    password = Column("password", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    active = Column("active", Boolean(), nullable=True, unique=None, default=None)
 
    admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
 
    name = Column("name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    lastname = Column("lastname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    email = Column("email", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
 
    is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
 

	
 
@@ -118,6 +87,10 @@ class User(Base, BaseModel):
 
    def full_contact(self):
 
        return '%s %s <%s>' % (self.name, self.lastname, self.email)
 

	
 
    @property
 
    def short_contact(self):
 
        return '%s %s' % (self.name, self.lastname)
 

	
 

	
 
    @property
 
    def is_admin(self):
 
@@ -127,6 +100,11 @@ class User(Base, BaseModel):
 
        return "<%s('id:%s:%s')>" % (self.__class__.__name__,
 
                                     self.user_id, self.username)
 

	
 
    @classmethod
 
    def by_username(cls, username):
 
        return Session.query(cls).filter(cls.username == username).one()
 

	
 

	
 
    def update_lastlogin(self):
 
        """Update user lastlogin"""
 

	
 
@@ -140,15 +118,15 @@ class User(Base, BaseModel):
 
            session.rollback()
 

	
 

	
 
class UserLog(Base, BaseModel):
 
class UserLog(Base):
 
    __tablename__ = 'user_logs'
 
    __table_args__ = {'useexisting':True}
 
    user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
 
    repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
 

	
 
    @property
 
@@ -158,16 +136,16 @@ class UserLog(Base, BaseModel):
 
    user = relationship('User')
 
    repository = relationship('Repository')
 

	
 
class Repository(Base, BaseModel):
 
class Repository(Base):
 
    __tablename__ = 'repositories'
 
    __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
 
    repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
 
    repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
 
    private = Column("private", Boolean(), nullable=True, unique=None, default=None)
 
    enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
 
    description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
 

	
 
    user = relationship('User')
 
@@ -178,23 +156,23 @@ class Repository(Base, BaseModel):
 
    repo_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
 

	
 
    logs = relationship('UserLog', cascade='all')
 
    
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.repo_id, self.repo_name)
 

	
 
class Permission(Base, BaseModel):
 
class Permission(Base):
 
    __tablename__ = 'permissions'
 
    __table_args__ = {'useexisting':True}
 
    permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    permission_name = Column("permission_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    def __repr__(self):
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.permission_id, self.permission_name)
 

	
 
class RepoToPerm(Base, BaseModel):
 
class RepoToPerm(Base):
 
    __tablename__ = 'repo_to_perm'
 
    __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
 
    repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
@@ -206,7 +184,7 @@ class RepoToPerm(Base, BaseModel):
 
    permission = relationship('Permission')
 
    repository = relationship('Repository')
 

	
 
class UserToPerm(Base, BaseModel):
 
class UserToPerm(Base):
 
    __tablename__ = 'user_to_perm'
 
    __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
 
    user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
@@ -216,19 +194,19 @@ class UserToPerm(Base, BaseModel):
 
    user = relationship('User')
 
    permission = relationship('Permission')
 

	
 
class Statistics(Base, BaseModel):
 
class Statistics(Base):
 
    __tablename__ = 'statistics'
 
    __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
 
    stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
 
    stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
 
    commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data
 
    commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
 
    commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
 
    languages = Column("languages", LargeBinary(), nullable=False)#JSON data
 
    languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
 

	
 
    repository = relationship('Repository', single_parent=True)
 

	
 
class UserFollowing(Base, BaseModel):
 
class UserFollowing(Base):
 
    __tablename__ = 'user_followings'
 
    __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
 
                      UniqueConstraint('user_id', 'follows_user_id')
 
@@ -244,12 +222,12 @@ class UserFollowing(Base, BaseModel):
 
    follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
 
    follows_repository = relationship('Repository', order_by='Repository.repo_name')
 

	
 
class CacheInvalidation(Base, BaseModel):
 
class CacheInvalidation(Base):
 
    __tablename__ = 'cache_invalidation'
 
    __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
 
    cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
 

	
 

	
 
@@ -262,10 +240,10 @@ class CacheInvalidation(Base, BaseModel)
 
        return "<%s('%s:%s')>" % (self.__class__.__name__,
 
                                  self.cache_id, self.cache_key)
 

	
 
class DbMigrateVersion(Base, BaseModel):
 
class DbMigrateVersion(Base):
 
    __tablename__ = 'db_migrate_version'
 
    __table_args__ = {'useexisting':True}
 
    repository_id = Column('repository_id', String(250), primary_key=True)
 
    repository_id = Column('repository_id', String(255), primary_key=True)
 
    repository_path = Column('repository_path', Text)
 
    version = Column('version', Integer)
 

	
rhodecode/model/meta.py
Show inline comments
 
"""SQLAlchemy Metadata and Session object"""
 
from sqlalchemy.ext.declarative import declarative_base
 
from sqlalchemy.orm import scoped_session, sessionmaker
 
from sqlalchemy.orm import scoped_session, sessionmaker, class_mapper
 
from beaker import cache
 

	
 
from rhodecode.model import caching_query
 
from beaker import cache
 

	
 

	
 
# Beaker CacheManager.  A home base for cache configurations.
 
cache_manager = cache.CacheManager()
 
@@ -17,10 +19,52 @@ Session = scoped_session(
 
                )
 
          )
 

	
 
class BaseModel(object):
 
    """Base Model for all classess
 
    
 
    """
 

	
 
    @classmethod
 
    def _get_keys(cls):
 
        """return column names for this model """
 
        return class_mapper(cls).c.keys()
 

	
 
    def get_dict(self):
 
        """return dict with keys and values corresponding 
 
        to this model data """
 

	
 
        d = {}
 
        for k in self._get_keys():
 
            d[k] = getattr(self, k)
 
        return d
 

	
 
    def get_appstruct(self):
 
        """return list with keys and values tupples corresponding 
 
        to this model data """
 

	
 
        l = []
 
        for k in self._get_keys():
 
            l.append((k, getattr(self, k),))
 
        return l
 

	
 
    def populate_obj(self, populate_dict):
 
        """populate model with data from given populate_dict"""
 

	
 
        for k in self._get_keys():
 
            if k in populate_dict:
 
                setattr(self, k, populate_dict[k])
 

	
 
    @classmethod
 
    def query(cls):
 
        return Session.query(cls)
 

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

	
 

	
 
# The declarative Base
 
Base = declarative_base()
 
#For another db...
 
#Base2 = declarative_base()
 
Base = declarative_base(cls=BaseModel)
 

	
 
#to use cache use this in query
 
#.options(FromCache("sqlalchemy_cache_type", "cachekey"))
rhodecode/model/scm.py
Show inline comments
 
@@ -146,6 +146,7 @@ class ScmModel(BaseModel):
 
                tmp_d['rev'] = tip.revision
 
                tmp_d['contact'] = repo.dbrepo.user.full_contact
 
                tmp_d['contact_sort'] = tmp_d['contact']
 
                tmp_d['owner_sort'] = tmp_d['contact']
 
                tmp_d['repo_archives'] = list(repo._get_archives())
 
                tmp_d['last_msg'] = tip.message
 
                tmp_d['repo'] = repo
setup.py
Show inline comments
 
import sys
 
from rhodecode import get_version
 
from rhodecode import __platform__
 

	
 
py_version = sys.version_info
 

	
 
from rhodecode import get_version
 

	
 
requirements = [
 
        "Pylons==1.0.0",
 
        "WebHelpers==1.2",
 
        "SQLAlchemy==0.6.6",
 
        "Mako==0.3.6",
 
        "vcs==0.1.10",
 
        "pygments==1.3.1",
 
        "Mako==0.4.0",
 
        "vcs==0.1.11",
 
        "pygments==1.4.0",
 
        "mercurial==1.7.5",
 
        "whoosh==1.3.4",
 
        "celery==2.1.4",
 
        "py-bcrypt",
 
        "celery==2.2.4",
 
        "babel",
 
    ]
 

	
 
@@ -25,10 +25,14 @@ classifiers = ['Development Status :: 5 
 
               'Operating System :: OS Independent',
 
               'Programming Language :: Python', ]
 

	
 
if sys.version_info < (2, 6):
 
if py_version < (2, 6):
 
    requirements.append("simplejson")
 
    requirements.append("pysqlite")
 

	
 
if __platform__ in ('Linux', 'Darwin'):
 
    requirements.append("py-bcrypt")
 

	
 

	
 
#additional files from project that goes somewhere in the filesystem
 
#relative to sys.prefix
 
data_files = []
 
@@ -38,6 +42,10 @@ package_data = {'rhodecode': ['i18n/*/LC
 

	
 
description = ('Mercurial repository browser/management with '
 
               'build in push/pull server and full text search')
 
keywords = ' '.join (['rhodecode', 'rhodiumcode', 'mercurial', 'git',
 
                      'repository management', 'hgweb replacement'
 
                      'hgwebdir', 'gitweb replacement', 'serving hgweb',
 
                     ])
 
#long description
 
try:
 
    readme_file = 'README.rst'
 
@@ -66,7 +74,7 @@ setup(
 
    version=get_version(),
 
    description=description,
 
    long_description=long_description,
 
    keywords='rhodiumcode mercurial web hgwebdir gitweb git replacement serving hgweb rhodecode',
 
    keywords=keywords,
 
    license='BSD',
 
    author='Marcin Kuzminski',
 
    author_email='marcin@python-works.com',
0 comments (0 inline, 0 general)