Changeset - 6832ef664673
[Not reviewed]
beta
! ! !
Marcin Kuzminski - 15 years ago 2011-04-03 18:23:15
marcin@python-works.com
source code cleanup: remove trailing white space, normalize file endings
83 files changed with 475 insertions and 537 deletions:
0 comments (0 inline, 0 general)
ez_setup.py
Show inline comments
 
@@ -83,25 +83,25 @@ def use_setuptools(
 
    should one be required.  If an older version of setuptools is installed,
 
    this routine will print a message to ``sys.stderr`` and raise SystemExit in
 
    an attempt to abort the calling script.
 
    """
 
    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
 
    def do_download():
 
        egg = download_setuptools(version, download_base, to_dir, download_delay)
 
        sys.path.insert(0, egg)
 
        import setuptools; setuptools.bootstrap_install_from = egg
 
    try:
 
        import pkg_resources
 
    except ImportError:
 
        return do_download()       
 
        return do_download()
 
    try:
 
        pkg_resources.require("setuptools>="+version); return
 
    except pkg_resources.VersionConflict, e:
 
        if was_imported:
 
            print >>sys.stderr, (
 
            "The required version of setuptools (>=%s) is not available, and\n"
 
            "can't be installed while this script is running. Please install\n"
 
            " a more recent version first, using 'easy_install -U setuptools'."
 
            "\n\n(Currently using %r)"
 
            ) % (version, e.args[0])
 
            sys.exit(2)
 
        else:
 
@@ -259,18 +259,12 @@ def update_md5(filenames):
 

	
 
    src = src[:match.start(1)] + repl + src[match.end(1):]
 
    f = open(srcfile,'w')
 
    f.write(src)
 
    f.close()
 

	
 

	
 
if __name__=='__main__':
 
    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
 
        update_md5(sys.argv[2:])
 
    else:
 
        main(sys.argv[1:])
 

	
 

	
 

	
 

	
 

	
 

	
rhodecode/__init__.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.__init__
 
    ~~~~~~~~~~~~~~~~~~
 

	
 
    RhodeCode, a web based repository management based on pylons
 
    versioning implementation: http://semver.org/
 

	
 
    :created_on: Apr 9, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import platform
 

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

	
 
PLATFORM_WIN = ('Windows',)
rhodecode/config/middleware.py
Show inline comments
 
@@ -67,13 +67,12 @@ def make_app(global_conf, full_stack=Tru
 
    # Establish the Registry for this application
 
    app = RegistryManager(app)
 

	
 
    if asbool(static_files):
 
        # Serve static files
 
        static_app = StaticURLParser(config['pylons.paths']['static_files'])
 
        app = Cascade([static_app, app])
 
        app = make_gzip_middleware(app, global_conf, compress_level=1)
 

	
 
    app.config = config
 

	
 
    return app
 

	
rhodecode/config/routing.py
Show inline comments
 
@@ -10,25 +10,25 @@ from routes import Mapper
 
from rhodecode.lib.utils import check_repo_fast as cr
 

	
 
def make_map(config):
 
    """Create, configure and return the routes Mapper"""
 
    routes_map = Mapper(directory=config['pylons.paths']['controllers'],
 
                 always_scan=config['debug'])
 
    routes_map.minimization = False
 
    routes_map.explicit = False
 

	
 
    def check_repo(environ, match_dict):
 
        """
 
        check for valid repository for proper 404 handling
 
        
 

	
 
        :param environ:
 
        :param match_dict:
 
        """
 
        repo_name = match_dict.get('repo_name')
 
        return not cr(repo_name, config['base_path'])
 

	
 
    # The ErrorController route (handles 404/500 error pages); it should
 
    # likely stay at the top, ensuring it can always be resolved
 
    routes_map.connect('/error/{action}', controller='error')
 
    routes_map.connect('/error/{action}/{id}', controller='error')
 

	
 
    #==========================================================================
rhodecode/controllers/admin/admin.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.admin
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Controller for Admin panel of Rhodecode
 
    
 

	
 
    :created_on: Apr 7, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 

	
 
from pylons import request, tmpl_context as c
 
from sqlalchemy.orm import joinedload
 
from webhelpers.paginate import Page
 

	
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 
@@ -48,13 +48,12 @@ class AdminController(BaseController):
 

	
 
        users_log = self.sa.query(UserLog)\
 
                .options(joinedload(UserLog.user))\
 
                .options(joinedload(UserLog.repository))\
 
                .order_by(UserLog.action_date.desc())
 

	
 
        p = int(request.params.get('page', 1))
 
        c.users_log = Page(users_log, page=p, items_per_page=10)
 
        c.log_data = render('admin/admin_log.html')
 
        if request.params.get('partial'):
 
            return c.log_data
 
        return render('admin/admin.html')
 

	
rhodecode/controllers/admin/ldap_settings.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.ldap_settings
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    ldap controller for RhodeCode
 
    
 

	
 
    :created_on: Nov 26, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import logging
 
import formencode
 
import traceback
 

	
 
from formencode import htmlfill
 

	
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
rhodecode/controllers/admin/permissions.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.permissions
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
    
 

	
 
    permissions controller for Rhodecode
 
    
 

	
 
    :created_on: Apr 27, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 
from rhodecode.lib.auth_ldap import LdapImportError
rhodecode/controllers/admin/repos.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.repos
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
    
 

	
 
    Admin controller for RhodeCode
 
    
 

	
 
    :created_on: Apr 7, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import traceback
 
import formencode
 
from operator import itemgetter
 
from formencode import htmlfill
 

	
 
from paste.httpexceptions import HTTPInternalServerError
 
@@ -73,25 +73,25 @@ class ReposController(BaseController):
 
                                    )
 
                                )
 

	
 
        c.repo_groups.extend([(x.group_id, parents_link(x)) for \
 
                                            x in self.sa.query(Group).all()])
 
        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()
 

	
 
    def __load_data(self, repo_name=None):
 
        """
 
        Load defaults settings for edit, and update
 
        
 

	
 
        :param repo_name:
 
        """
 
        self.__load_defaults()
 

	
 
        repo, dbrepo = ScmModel().get(repo_name, retval='repo')
 

	
 
        repo_model = RepoModel()
 
        c.repo_info = repo_model.get_by_repo_name(repo_name)
 

	
 

	
 
        if c.repo_info is None:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
@@ -292,89 +292,89 @@ class ReposController(BaseController):
 

	
 
        except Exception, e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of %s') % repo_name,
 
                    category='error')
 

	
 
        return redirect(url('repos'))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete_perm_user(self, repo_name):
 
        """
 
        DELETE an existing repository permission user
 
        
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            repo_model = RepoModel()
 
            repo_model.delete_perm_user(request.POST, repo_name)
 
        except Exception, e:
 
            h.flash(_('An error occurred during deletion of repository user'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete_perm_users_group(self, repo_name):
 
        """
 
        DELETE an existing repository permission users group
 
        
 

	
 
        :param repo_name:
 
        """
 
        try:
 
            repo_model = RepoModel()
 
            repo_model.delete_perm_users_group(request.POST, repo_name)
 
        except Exception, e:
 
            h.flash(_('An error occurred during deletion of repository'
 
                      ' users groups'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_stats(self, repo_name):
 
        """
 
        DELETE an existing repository statistics
 
        
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            repo_model = RepoModel()
 
            repo_model.delete_stats(repo_name)
 
        except Exception, e:
 
            h.flash(_('An error occurred during deletion of repository stats'),
 
                    category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_cache(self, repo_name):
 
        """
 
        INVALIDATE existing repository cache
 
        
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            ScmModel().mark_for_invalidation(repo_name)
 
        except Exception, e:
 
            h.flash(_('An error occurred during cache invalidation'),
 
                    category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_public_journal(self, repo_name):
 
        """
 
        Set's this repository to be visible in public journal,
 
        in other words assing default user to follow this repo
 
        
 

	
 
        :param repo_name:
 
        """
 

	
 
        cur_token = request.POST.get('auth_token')
 
        token = get_token()
 
        if cur_token == token:
 
            try:
 
                repo_id = Repository.by_repo_name(repo_name).repo_id
 
                user_id = User.by_username('default').user_id
 
                self.scm_model.toggle_following_repo(repo_id, user_id)
 
                h.flash(_('Updated repository visibility in public journal'),
 
                        category='success')
 
@@ -383,25 +383,25 @@ class ReposController(BaseController):
 
                          ' repository in public journal'),
 
                        category='error')
 

	
 
        else:
 
            h.flash(_('Token mismatch'), category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_pull(self, repo_name):
 
        """
 
        Runs task to update given repository with remote changes,
 
        ie. make pull on remote location
 
        
 

	
 
        :param repo_name:
 
        """
 
        try:
 
            ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
 
            h.flash(_('Pulled from remote location'), category='success')
 
        except Exception, e:
 
            h.flash(_('An error occurred during pull from remote location'),
 
                    category='error')
 

	
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
rhodecode/controllers/admin/settings.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.settings
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
    
 

	
 
    settings controller for rhodecode admin
 
        
 

	
 
    :created_on: Jul 14, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import traceback
 
import formencode
 

	
 
from sqlalchemy import func
 
from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url, config
 
@@ -47,25 +47,25 @@ from rhodecode.model.forms import UserFo
 
    ApplicationUiSettingsForm
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.settings import SettingsModel
 
from rhodecode.model.user import UserModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SettingsController(BaseController):
 
    """REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('setting', 'settings', controller='admin/settings', 
 
    #     map.resource('setting', 'settings', controller='admin/settings',
 
    #         path_prefix='/admin', name_prefix='admin_')
 

	
 

	
 
    @LoginRequired()
 
    def __before__(self):
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        super(SettingsController, self).__before__()
 

	
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def index(self, format='html'):
 
@@ -242,25 +242,25 @@ class SettingsController(BaseController)
 
    def show(self, setting_id, format='html'):
 
        """GET /admin/settings/setting_id: Show a specific item"""
 
        # url('admin_setting', setting_id=ID)
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def edit(self, setting_id, format='html'):
 
        """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
 
        # url('admin_edit_setting', setting_id=ID)
 

	
 
    @NotAnonymous()
 
    def my_account(self):
 
        """
 
        GET /_admin/my_account Displays info about my account 
 
        GET /_admin/my_account Displays info about my account
 
        """
 
        # url('admin_settings_my_account')
 

	
 
        c.user = UserModel().get(self.rhodecode_user.user_id, cache=False)
 
        all_repos = [r.repo_name for r in self.sa.query(Repository)\
 
                     .filter(Repository.user_id == c.user.user_id)\
 
                     .order_by(func.lower(Repository.repo_name)).all()]
 
        c.user_repos = ScmModel().get_repos(all_repos)
 

	
 
        if c.user.username == 'default':
 
            h.flash(_("You can't edit this user since it's"
 
              " crucial for entire application"), category='warning')
rhodecode/controllers/admin/users.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.users
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Users crud controller for pylons
 
    
 

	
 
    :created_on: Apr 4, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import traceback
 
import formencode
 

	
 
from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url, config
 
from pylons.controllers.util import abort, redirect
rhodecode/controllers/admin/users_groups.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.users_groups
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Users Groups crud controller for pylons
 
    
 

	
 
    :created_on: Jan 25, 2011
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import traceback
 
import formencode
 

	
 
from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url, config
 
from pylons.controllers.util import abort, redirect
rhodecode/controllers/branches.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.branches
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    branches controller for rhodecode
 
    
 

	
 
    :created_on: Apr 21, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 

	
 
from pylons import tmpl_context as c
 

	
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import OrderedDict
rhodecode/controllers/changelog.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.changelog
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    changelog controller for rhodecode
 

	
 
    :created_on: Apr 21, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 

	
 
try:
 
    import json
 
except ImportError:
 
    #python 2.5 compatibility
 
    import simplejson as json
 
@@ -71,36 +71,35 @@ class ChangelogController(BaseRepoContro
 
        c.total_cs = len(c.rhodecode_repo)
 
        c.pagination = RepoPage(c.rhodecode_repo, page=p, item_count=c.total_cs,
 
                            items_per_page=c.size, branch_name=branch_name)
 

	
 
        self._graph(c.rhodecode_repo, c.total_cs, c.size, p)
 

	
 
        return render('changelog/changelog.html')
 

	
 

	
 
    def _graph(self, repo, repo_size, size, p):
 
        """
 
        Generates a DAG graph for mercurial
 
        
 

	
 
        :param repo: repo instance
 
        :param size: number of commits to show
 
        :param p: page number
 
        """
 
        if not repo.revisions or repo.alias == 'git':
 
            c.jsdata = json.dumps([])
 
            return
 

	
 
        revcount = min(repo_size, size)
 
        offset = 1 if p == 1 else  ((p - 1) * revcount + 1)
 
        rev_start = repo.revisions.index(repo.revisions[(-1 * offset)])
 
        rev_end = max(0, rev_start - revcount)
 

	
 
        dag = graph_rev(repo._repo, rev_start, rev_end)
 
        c.dag = tree = list(colored(dag))
 
        data = []
 
        for (id, type, ctx, vtx, edges) in tree:
 
            if type != CHANGESET:
 
                continue
 
            data.append(('', vtx, edges))
 

	
 
        c.jsdata = json.dumps(data)
 

	
rhodecode/controllers/changeset.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.changeset
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    changeset controller for pylons showoing changes beetween 
 
    changeset controller for pylons showoing changes beetween
 
    revisions
 
    
 

	
 
    :created_on: Apr 25, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import logging
 
import traceback
 

	
 
from pylons import tmpl_context as c, url, request, response
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import redirect
 

	
 
import rhodecode.lib.helpers as h
 
@@ -141,25 +141,25 @@ class ChangesetController(BaseRepoContro
 
                                c.sum_removed += len(diff)
 
                        else:
 
                            diff = wrap_to_table(_('Changeset is to big and was cut'
 
                                                ' off, see raw changeset instead'))
 
                            c.cut_off = True
 
                            break
 

	
 
                    cs1 = filenode_old.last_changeset.raw_id
 
                    cs2 = node.last_changeset.raw_id
 
                    c.changes[changeset.raw_id].append(('changed', node, diff, cs1, cs2))
 

	
 
            #==================================================================
 
            # REMOVED FILES    
 
            # REMOVED FILES
 
            #==================================================================
 
            if not c.cut_off:
 
                for node in changeset.removed:
 
                    c.changes[changeset.raw_id].append(('removed', node, None, None, None))
 

	
 
        if len(c.cs_ranges) == 1:
 
            c.changeset = c.cs_ranges[0]
 
            c.changes = c.changes[c.changeset.raw_id]
 

	
 
            return render('changeset/changeset.html')
 
        else:
 
            return render('changeset/changeset_range.html')
rhodecode/controllers/error.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.error
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    RhodeCode error controller
 
    
 

	
 
    :created_on: Dec 8, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import os
 
import cgi
 
import logging
 
import paste.fileapp
 

	
 
from pylons import tmpl_context as c, request, config
 
from pylons.i18n.translation import _
 
from pylons.middleware import  media_path
 
@@ -98,14 +98,12 @@ class ErrorController(BaseController):
 
            code = 500
 

	
 
        if code == 400:
 
            return _('The request could not be understood by the server due to malformed syntax.')
 
        if code == 401:
 
            return _('Unauthorized access to resource')
 
        if code == 403:
 
            return _("You don't have permission to view this page")
 
        if code == 404:
 
            return _('The resource could not be found')
 
        if code == 500:
 
            return _('The server encountered an unexpected condition which prevented it from fulfilling the request.')
 

	
 

	
rhodecode/controllers/feed.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.feed
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Feed controller for rhodecode
 
    
 

	
 
    :created_on: Apr 23, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 

	
 
from pylons import url, response, tmpl_context as c
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseRepoController
rhodecode/controllers/files.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.files
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Files controller for RhodeCode
 
    
 

	
 
    :created_on: Apr 21, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import os
 
import logging
 
import rhodecode.lib.helpers as h
 

	
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import redirect
 
@@ -51,45 +51,45 @@ class FilesController(BaseRepoController
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def __before__(self):
 
        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
 
        """
 

	
 
        try:
 
            return c.rhodecode_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 __get_filenode_or_redirect(self, repo_name, cs, path):
 
        """
 
        Returns file_node, if error occurs or given path is directory,
 
        it'll redirect to top level path
 
        
 

	
 
        :param repo_name: repo_name
 
        :param cs: given changeset
 
        :param path: path to lookup
 
        """
 

	
 

	
 
        try:
 
            file_node = cs.get_node(path)
 
            if file_node.is_dir():
 
                raise RepositoryError('given path is a directory')
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
@@ -292,13 +292,12 @@ class FilesController(BaseRepoController
 

	
 
        for name, chs in c.rhodecode_repo.branches.items():
 
            #chs = chs.split(':')[-1]
 
            branches_group[0].append((chs, name),)
 
        hist_l.append(branches_group)
 

	
 
        for name, chs in c.rhodecode_repo.tags.items():
 
            #chs = chs.split(':')[-1]
 
            tags_group[0].append((chs, name),)
 
        hist_l.append(tags_group)
 

	
 
        return hist_l
 

	
rhodecode/controllers/home.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.home
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Home controller for Rhodecode
 
    
 

	
 
    :created_on: Feb 18, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
from operator import itemgetter
 

	
 
from pylons import tmpl_context as c, request
 
from paste.httpexceptions import HTTPBadRequest
 

	
 
from rhodecode.lib.auth import LoginRequired
rhodecode/controllers/journal.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.journal
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Journal controller for pylons
 
    
 

	
 
    :created_on: Nov 21, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import logging
 

	
 
from sqlalchemy import or_
 
from sqlalchemy.orm import joinedload, make_transient
 
from webhelpers.paginate import Page
 
from itertools import groupby
 

	
 
from paste.httpexceptions import HTTPBadRequest
 
@@ -229,20 +229,12 @@ class JournalController(BaseController):
 
            title = "%s - %s %s" % (entry.user.short_contact, action,
 
                                 entry.repository.repo_name)
 
            desc = action_extra()
 
            feed.add_item(title=title,
 
                          pubdate=entry.action_date,
 
                          link=url('', qualified=True),
 
                          author_email=entry.user.email,
 
                          author_name=entry.user.full_contact,
 
                          description=desc)
 

	
 
        response.content_type = feed.mime_type
 
        return feed.writeString('utf-8')
 

	
 

	
 

	
 

	
 

	
 

	
 

	
 

	
rhodecode/controllers/login.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.login
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Login controller for rhodeocode
 
    
 

	
 
    :created_on: Apr 22, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import formencode
 

	
 
from formencode import htmlfill
 

	
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import abort, redirect
rhodecode/controllers/search.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.search
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Search controller for rhodecode
 
    
 

	
 
    :created_on: Aug 7, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import logging
 
import traceback
 

	
 
from pylons.i18n.translation import _
 
from pylons import request, config, session, tmpl_context as c
 

	
 
from rhodecode.lib.auth import LoginRequired
 
from rhodecode.lib.base import BaseController, render
rhodecode/controllers/settings.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.settings
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Settings controller for rhodecode
 
    
 

	
 
    :created_on: Jun 30, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import traceback
 
import formencode
 

	
 
from formencode import htmlfill
 

	
 
from pylons import tmpl_context as c, request, url
rhodecode/controllers/shortlog.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.shortlog
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Shortlog controller for rhodecode
 
    
 

	
 
    :created_on: Apr 18, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 

	
 
from pylons import tmpl_context as c, request
 

	
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.helpers import RepoPage
rhodecode/controllers/summary.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.summary
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Summary controller for Rhodecode
 
    
 

	
 
    :created_on: Apr 18, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import calendar
 
import logging
 
from time import mktime
 
from datetime import datetime, timedelta, date
 

	
 
from vcs.exceptions import ChangesetError
 

	
rhodecode/controllers/tags.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.tags
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Tags controller for rhodecode
 
    
 

	
 
    :created_on: Apr 21, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import logging
 

	
 
from pylons import tmpl_context as c
 

	
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import OrderedDict
 

	
rhodecode/lib/__init__.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.__init__
 
    ~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Some simple helper functions
 
    
 

	
 
    :created_on: Jan 5, 2011
 
    :author: marcink
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
def str2bool(s):
 
    if s is None:
 
        return False
 
    if s in (True, False):
 
        return s
 
    s = str(s).strip().lower()
 
    return s in ('t', 'true', 'y', 'yes', 'on', '1')
 

	
 
def generate_api_key(username, salt=None):
 
    """
 
    Generates uniq API key for given username
 
    
 

	
 
    :param username: username as string
 
    :param salt: salt to hash generate KEY
 
    """
 
    from tempfile import _RandomNameSequence
 
    import hashlib
 

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

	
 
    return hashlib.sha1(username + salt).hexdigest()
 

	
 
def safe_unicode(_str):
 
    """
 
    safe unicode function. In case of UnicodeDecode error we try to return
 
    unicode with errors replace, if this fails we return unicode with 
 
    string_escape decoding 
 
    unicode with errors replace, if this fails we return unicode with
 
    string_escape decoding
 
    """
 

	
 
    if isinstance(_str, unicode):
 
        return _str
 

	
 
    try:
 
        u_str = unicode(_str)
 
    except UnicodeDecodeError:
 
        try:
 
            u_str = _str.decode('utf-8', 'replace')
 
        except UnicodeDecodeError:
 
            #incase we have a decode error just represent as byte string
rhodecode/lib/auth.py
Show inline comments
 
# -*- 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
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import random
 
import logging
 
import traceback
 
import hashlib
 

	
 
from tempfile import _RandomNameSequence
 
from decorator import decorator
 
@@ -52,25 +52,25 @@ from rhodecode.model import meta
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.db import Permission
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class PasswordGenerator(object):
 
    """This is a simple class for generating password from
 
        different sets of characters
 
        usage:
 
        passwd_gen = PasswordGenerator()
 
        #print 8-letter password containing only big and small letters of alphabet
 
        print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)        
 
        print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
 
    """
 
    ALPHABETS_NUM = r'''1234567890'''#[0]
 
    ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
 
    ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
 
    ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''    #[3]
 
    ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
 
    ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
 
    ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
 
    ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
 
    ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
 

	
 
    def __init__(self, passwd=''):
 
@@ -78,40 +78,40 @@ class PasswordGenerator(object):
 

	
 
    def gen_password(self, len, type):
 
        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__ in PLATFORM_WIN:
 
            return sha256(str_).hexdigest()
 
        elif __platform__ in PLATFORM_OTHERS:
 
            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__ in PLATFORM_WIN:
 
            return sha256(password).hexdigest() == hashed
 
        elif __platform__ in PLATFORM_OTHERS:
 
            return bcrypt.hashpw(password, hashed) == hashed
 
        else:
 
            raise Exception('Unknown or unsupported platform %s' % __platform__)
 

	
 

	
 
@@ -120,35 +120,35 @@ def get_crypt_password(password):
 

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

	
 
def generate_api_key(username, salt=None):
 
    if salt is None:
 
        salt = _RandomNameSequence().next()
 

	
 
    return hashlib.sha1(username + salt).hexdigest()
 

	
 
def authfunc(environ, username, password):
 
    """Dummy authentication function used in Mercurial/Git/ and access control,
 
    
 

	
 
    :param environ: needed only for using in Basic auth
 
    """
 
    return authenticate(username, password)
 

	
 

	
 
def authenticate(username, password):
 
    """Authentication function used for access control,
 
    firstly checks for db authentication then if ldap is enabled for ldap
 
    authentication, also creates ldap user if not in database
 
    
 

	
 
    :param username: username
 
    :param password: password
 
    """
 
    user_model = UserModel()
 
    user = user_model.get_by_username(username, cache=False)
 

	
 
    log.debug('Authenticating user using RhodeCode account')
 
    if user is not None and not user.ldap_dn:
 
        if user.active:
 

	
 
            if user.username == 'default' and user.active:
 
                log.info('user %s authenticated correctly as anonymous user',
 
@@ -165,25 +165,25 @@ def authenticate(username, password):
 
        log.debug('Regular authentication failed')
 
        user_obj = user_model.get_by_username(username, cache=False,
 
                                            case_insensitive=True)
 

	
 
        if user_obj is not None and not user_obj.ldap_dn:
 
            log.debug('this user already exists as non ldap')
 
            return False
 

	
 
        from rhodecode.model.settings import SettingsModel
 
        ldap_settings = SettingsModel().get_ldap_settings()
 

	
 
        #======================================================================
 
        # FALLBACK TO LDAP AUTH IF ENABLE                
 
        # FALLBACK TO LDAP AUTH IF ENABLE
 
        #======================================================================
 
        if str2bool(ldap_settings.get('ldap_active')):
 
            log.debug("Authenticating user using ldap")
 
            kwargs = {
 
                  'server':ldap_settings.get('ldap_host', ''),
 
                  'base_dn':ldap_settings.get('ldap_base_dn', ''),
 
                  'port':ldap_settings.get('ldap_port'),
 
                  'bind_dn':ldap_settings.get('ldap_dn_user'),
 
                  'bind_pass':ldap_settings.get('ldap_dn_pass'),
 
                  'use_ldaps':str2bool(ldap_settings.get('ldap_ldaps')),
 
                  'tls_reqcert':ldap_settings.get('ldap_tls_reqcert'),
 
                  'ldap_filter':ldap_settings.get('ldap_filter'),
 
@@ -208,27 +208,27 @@ def authenticate(username, password):
 

	
 
                return True
 
            except (LdapUsernameError, LdapPasswordError,):
 
                pass
 
            except (Exception,):
 
                log.error(traceback.format_exc())
 
                pass
 
    return False
 

	
 
class  AuthUser(object):
 
    """
 
    A simple object that handles all attributes of user in RhodeCode
 
    
 

	
 
    It does lookup based on API key,given user, or user present in session
 
    Then it fills all required information for such user. It also checks if 
 
    Then it fills all required information for such user. It also checks if
 
    anonymous access is enabled and if so, it returns default user as logged
 
    in
 
    """
 

	
 
    def __init__(self, user_id=None, api_key=None):
 

	
 
        self.user_id = user_id
 
        self.api_key = None
 

	
 
        self.username = 'None'
 
        self.name = ''
 
        self.lastname = ''
 
@@ -269,50 +269,50 @@ class  AuthUser(object):
 
    def __repr__(self):
 
        return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
 
                                              self.is_authenticated)
 

	
 
    def set_authenticated(self, authenticated=True):
 

	
 
        if self.user_id != self.anonymous_user.user_id:
 
            self.is_authenticated = authenticated
 

	
 

	
 
def set_available_permissions(config):
 
    """This function will propagate pylons globals with all available defined
 
    permission given in db. We don't want to check each time from db for new 
 
    permission given in db. We don't want to check each time from db for new
 
    permissions since adding a new permission also requires application restart
 
    ie. to decorate new views with the newly created permission
 
    
 

	
 
    :param config: current pylons config instance
 
    
 

	
 
    """
 
    log.info('getting information about all available permissions')
 
    try:
 
        sa = meta.Session()
 
        all_perms = sa.query(Permission).all()
 
    except:
 
        pass
 
    finally:
 
        meta.Session.remove()
 

	
 
    config['available_permissions'] = [x.permission_name for x in all_perms]
 

	
 
#===============================================================================
 
# CHECK DECORATORS
 
#===============================================================================
 
class LoginRequired(object):
 
    """
 
    Must be logged in to execute this function else 
 
    Must be logged in to execute this function else
 
    redirect to login page
 
    
 

	
 
    :param api_access: if enabled this checks only for valid auth token
 
        and grants access based on valid token
 
    """
 

	
 
    def __init__(self, api_access=False):
 
        self.api_access = api_access
 

	
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 

	
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
        cls = fargs[0]
 
@@ -336,25 +336,25 @@ class LoginRequired(object):
 
            p = ''
 
            if request.environ.get('SCRIPT_NAME') != '/':
 
                p += request.environ.get('SCRIPT_NAME')
 

	
 
            p += request.environ.get('PATH_INFO')
 
            if request.environ.get('QUERY_STRING'):
 
                p += '?' + request.environ.get('QUERY_STRING')
 

	
 
            log.debug('redirecting to login page with %s', p)
 
            return redirect(url('login_home', came_from=p))
 

	
 
class NotAnonymous(object):
 
    """Must be logged in to execute this function else 
 
    """Must be logged in to execute this function else
 
    redirect to login page"""
 

	
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 

	
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
        cls = fargs[0]
 
        self.user = cls.rhodecode_user
 

	
 
        log.debug('Checking if user is not anonymous @%s', cls)
 

	
 
        anonymous = self.user.username == 'default'
 
@@ -405,62 +405,62 @@ class PermsDecorator(object):
 
        else:
 
            log.warning('Permission denied for %s %s', cls, self.user)
 
            #redirect with forbidden ret code
 
            return abort(403)
 

	
 

	
 

	
 
    def check_permissions(self):
 
        """Dummy function for overriding"""
 
        raise Exception('You have to write this function in child class')
 

	
 
class HasPermissionAllDecorator(PermsDecorator):
 
    """Checks for access permission for all given predicates. All of them 
 
    """Checks for access permission for all given predicates. All of them
 
    have to be meet in order to fulfill the request
 
    """
 

	
 
    def check_permissions(self):
 
        if self.required_perms.issubset(self.user_perms.get('global')):
 
            return True
 
        return False
 

	
 

	
 
class HasPermissionAnyDecorator(PermsDecorator):
 
    """Checks for access permission for any of given predicates. In order to 
 
    """Checks for access permission for any of given predicates. In order to
 
    fulfill the request any of predicates must be meet
 
    """
 

	
 
    def check_permissions(self):
 
        if self.required_perms.intersection(self.user_perms.get('global')):
 
            return True
 
        return False
 

	
 
class HasRepoPermissionAllDecorator(PermsDecorator):
 
    """Checks for access permission for all given predicates for specific 
 
    """Checks for access permission for all given predicates for specific
 
    repository. All of them have to be meet in order to fulfill the request
 
    """
 

	
 
    def check_permissions(self):
 
        repo_name = get_repo_slug(request)
 
        try:
 
            user_perms = set([self.user_perms['repositories'][repo_name]])
 
        except KeyError:
 
            return False
 
        if self.required_perms.issubset(user_perms):
 
            return True
 
        return False
 

	
 

	
 
class HasRepoPermissionAnyDecorator(PermsDecorator):
 
    """Checks for access permission for any of given predicates for specific 
 
    """Checks for access permission for any of given predicates for specific
 
    repository. In order to fulfill the request any of predicates must be meet
 
    """
 

	
 
    def check_permissions(self):
 
        repo_name = get_repo_slug(request)
 

	
 
        try:
 
            user_perms = set([self.user_perms['repositories'][repo_name]])
 
        except KeyError:
 
            return False
 
        if self.required_perms.intersection(user_perms):
 
            return True
rhodecode/lib/auth_ldap.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# ldap authentication lib
 
# 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
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on Nov 17, 2010
 

	
 
@author: marcink
 
"""
 

	
 
from rhodecode.lib.exceptions import *
 
import logging
 
@@ -57,28 +57,28 @@ class AuthLdap(object):
 
        self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
 
                                               self.LDAP_SERVER_ADDRESS,
 
                                               self.LDAP_SERVER_PORT)
 

	
 
        self.BASE_DN = base_dn
 
        self.LDAP_FILTER = ldap_filter
 
        self.SEARCH_SCOPE = ldap.__dict__['SCOPE_' + search_scope]
 
        self.attr_login = attr_login
 

	
 

	
 
    def authenticate_ldap(self, username, password):
 
        """Authenticate a user via LDAP and return his/her LDAP properties.
 
    
 

	
 
        Raises AuthenticationError if the credentials are rejected, or
 
        EnvironmentError if the LDAP server can't be reached.
 
        
 

	
 
        :param username: username
 
        :param password: password
 
        """
 

	
 
        from rhodecode.lib.helpers import chop_at
 

	
 
        uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
 

	
 
        if "," in username:
 
            raise LdapUsernameError("invalid character in username: ,")
 
        try:
 
            ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
rhodecode/lib/backup_manager.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# mercurial repository backup manager
 
# 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
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
"""
 
Created on Feb 28, 2010
 
Mercurial repositories backup manager
 
@author: marcink
 
"""
 

	
 

	
 
@@ -29,41 +29,41 @@ import logging
 
import tarfile
 
import os
 
import datetime
 
import sys
 
import subprocess
 
logging.basicConfig(level=logging.DEBUG,
 
                    format="%(asctime)s %(levelname)-5.5s %(message)s")
 

	
 
class BackupManager(object):
 
    def __init__(self, repos_location, rsa_key, backup_server):
 
        today = datetime.datetime.now().weekday() + 1
 
        self.backup_file_name = "mercurial_repos.%s.tar.gz" % today
 
        
 

	
 
        self.id_rsa_path = self.get_id_rsa(rsa_key)
 
        self.repos_path = self.get_repos_path(repos_location)
 
        self.backup_server = backup_server
 

	
 
        self.backup_file_path = '/tmp'
 

	
 
        logging.info('starting backup for %s', self.repos_path)
 
        logging.info('backup target %s', self.backup_file_path)
 

	
 

	
 
    def get_id_rsa(self, rsa_key):
 
        if not os.path.isfile(rsa_key):
 
            logging.error('Could not load id_rsa key file in %s', rsa_key)
 
            sys.exit()
 
        return rsa_key
 
    
 

	
 
    def get_repos_path(self, path):
 
        if not os.path.isdir(path):
 
            logging.error('Wrong location for repositories in %s', path)
 
            sys.exit()
 
        return path
 

	
 
    def backup_repos(self):
 
        bckp_file = os.path.join(self.backup_file_path, self.backup_file_name)
 
        tar = tarfile.open(bckp_file, "w:gz")
 

	
 
        for dir_name in os.listdir(self.repos_path):
 
            logging.info('backing up %s', dir_name)
 
@@ -77,32 +77,30 @@ class BackupManager(object):
 
        params = {
 
                  'id_rsa_key': self.id_rsa_path,
 
                  'backup_file':os.path.join(self.backup_file_path,
 
                                             self.backup_file_name),
 
                  'backup_server':self.backup_server
 
                  }
 
        cmd = ['scp', '-l', '40000', '-i', '%(id_rsa_key)s' % params,
 
               '%(backup_file)s' % params,
 
               '%(backup_server)s' % params]
 

	
 
        subprocess.call(cmd)
 
        logging.info('Transfered file %s to %s', self.backup_file_name, cmd[4])
 
        
 
    
 

	
 

	
 
    def rm_file(self):
 
        logging.info('Removing file %s', self.backup_file_name)
 
        os.remove(os.path.join(self.backup_file_path, self.backup_file_name))
 
    
 

	
 

	
 

	
 
if __name__ == "__main__":
 
    
 

	
 
    repo_location = '/home/repo_path'
 
    backup_server = 'root@192.168.1.100:/backups/mercurial'
 
    rsa_key = '/home/id_rsa'
 
    
 

	
 
    B_MANAGER = BackupManager(repo_location, rsa_key, backup_server)
 
    B_MANAGER.backup_repos()
 
    B_MANAGER.transfer_files()
 
    B_MANAGER.rm_file()
 

	
 

	
rhodecode/lib/base.py
Show inline comments
 
@@ -42,27 +42,27 @@ class BaseController(WSGIController):
 
                                       'is_authenticated', False))
 
            session['rhodecode_user'] = self.rhodecode_user
 
            session.save()
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            meta.Session.remove()
 

	
 

	
 
class BaseRepoController(BaseController):
 
    """
 
    Base class for controllers responsible for loading all needed data
 
    for those controllers, loaded items are
 
    
 

	
 
    c.rhodecode_repo: instance of scm repository (taken from cache)
 
     
 

	
 
    """
 

	
 
    def __before__(self):
 
        super(BaseRepoController, self).__before__()
 
        if c.repo_name:
 

	
 
            c.rhodecode_repo, dbrepo = self.scm_model.get(c.repo_name,
 
                                                          retval='repo')
 
            if c.rhodecode_repo:
 
                c.repository_followers = self.scm_model.get_followers(c.repo_name)
 
                c.repository_forks = self.scm_model.get_forks(c.repo_name)
 
            else:
rhodecode/lib/celerylib/__init__.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.celerylib.__init__
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    celery libs for RhodeCode
 
    
 

	
 
    :created_on: Nov 27, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import os
 
import sys
 
import socket
 
import traceback
 
import logging
 

	
 
from hashlib import md5
 
@@ -88,20 +88,12 @@ def locked_task(func):
 
                '-'.join(map(str, params))).hexdigest()
 
        log.info('running task with lockkey %s', lockkey)
 
        try:
 
            l = DaemonLock(lockkey)
 
            ret = func(*fargs, **fkwargs)
 
            l.release()
 
            return ret
 
        except LockHeld:
 
            log.info('LockHeld')
 
            return 'Task with key %s already running' % lockkey
 

	
 
    return decorator(__wrapper, func)
 

	
 

	
 

	
 

	
 

	
 

	
 

	
 

	
rhodecode/lib/celerylib/tasks.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.celerylib.tasks
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    RhodeCode task modules, containing all task that suppose to be run
 
    by celery daemon
 
    
 

	
 
    :created_on: Oct 6, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
from celery.decorators import task
 

	
 
import os
 
import traceback
 
import logging
 

	
 
from time import mktime
 
from operator import itemgetter
 
@@ -115,25 +115,25 @@ def get_commits_stats(repo_name, ts_min_
 
        .filter(Repository.repo_name == repo_name).scalar()
 
    cur_stats = sa.query(Statistics)\
 
        .filter(Statistics.repository == dbrepo).scalar()
 

	
 
    if cur_stats is not None:
 
        last_rev = cur_stats.stat_on_revision
 

	
 
    #return if repo is empty
 
    if not repo.revisions:
 
        return True
 

	
 
    if last_rev == repo.get_changeset().revision and len(repo.revisions) > 1:
 
        #pass silently without any work if we're not on first revision or 
 
        #pass silently without any work if we're not on first revision or
 
        #current state of parsing revision(from db marker) is the last revision
 
        return True
 

	
 
    if cur_stats:
 
        commits_by_day_aggregate = OrderedDict(
 
                                       json.loads(
 
                                        cur_stats.commit_activity_combined))
 
        commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
 

	
 
    log.debug('starting parsing %s', parse_limit)
 
    lmktime = mktime
 

	
 
@@ -263,26 +263,26 @@ def reset_user_password(user_email):
 

	
 

	
 
    except:
 
        log.error('Failed to update user password')
 
        log.error(traceback.format_exc())
 

	
 
    return True
 

	
 
@task(ignore_result=True)
 
def send_email(recipients, subject, body):
 
    """
 
    Sends an email with defined parameters from the .ini files.
 
    
 
    
 

	
 

	
 
    :param recipients: list of recipients, it this is empty the defined email
 
        address from field 'email_to' is used instead
 
    :param subject: subject of the mail
 
    :param body: body of the mail
 
    """
 
    try:
 
        log = send_email.get_logger()
 
    except:
 
        log = logging.getLogger(__name__)
 

	
 
    email_config = config
 

	
 
@@ -395,16 +395,12 @@ def __get_codes_stats(repo_name):
 
            ext = f.extension
 
            key = LANGUAGES_EXTENSIONS_MAP.get(ext, ext)
 
            key = key or ext
 
            if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
 
                if code_stats.has_key(key):
 
                    code_stats[key] += 1
 
                else:
 
                    code_stats[key] = 1
 

	
 
    map(aggregate, tip.walk('/'))
 

	
 
    return code_stats or {}
 

	
 

	
 

	
 

	
rhodecode/lib/colored_formatter.py
Show inline comments
 

	
 
import logging
 

	
 
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
 

	
 
# Sequences 
 
# Sequences
 
RESET_SEQ = "\033[0m"
 
COLOR_SEQ = "\033[1;%dm"
 
BOLD_SEQ = "\033[1m"
 

	
 
COLORS = {
 
    'CRITICAL': MAGENTA, # level 50
 
    'ERROR': RED, # level 40
 
    'WARNING': CYAN, # level 30
 
    'INFO': GREEN, # level 20
 
    'DEBUG': BLUE, # level 10
 
    'SQL' : YELLOW
 
}
 
@@ -71,13 +71,12 @@ class ColorFormatterSql(logging.Formatte
 

	
 
    def format(self, record):
 
        """
 
        Changes record's levelname to use with COLORS enum
 
        """
 

	
 
        start = COLOR_SEQ % (COLORS['SQL'])
 
        def_record = format_sql(logging.Formatter.format(self, record))
 
        end = RESET_SEQ
 

	
 
        colored_record = start + def_record + end
 
        return colored_record
 

	
rhodecode/lib/db_manage.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.db_manage
 
    ~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Database creation, and setup module for RhodeCode. Used for creation
 
    of database as well as for migration operations
 
    
 

	
 
    :created_on: Apr 10, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import os
 
import sys
 
import uuid
 
import logging
 
from os.path import dirname as dn, join as jn
 

	
 
from rhodecode import __dbversion__
 
@@ -86,27 +86,27 @@ class DbManage(object):
 
            ver.version = __dbversion__
 
            ver.repository_id = 'rhodecode_db_migrations'
 
            ver.repository_path = 'versions'
 
            self.sa.add(ver)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 
        log.info('db version set to: %s', __dbversion__)
 

	
 

	
 
    def upgrade(self):
 
        """Upgrades given database schema to given revision following 
 
        """Upgrades given database schema to given revision following
 
        all needed steps, to perform the upgrade
 
        
 

	
 
        """
 

	
 
        from rhodecode.lib.dbmigrate.migrate.versioning import api
 
        from rhodecode.lib.dbmigrate.migrate.exceptions import \
 
            DatabaseNotControlledError
 

	
 
        upgrade = ask_ok('You are about to perform database upgrade, make '
 
                         'sure You backed up your database before. '
 
                         'Continue ? [y/n]')
 
        if not upgrade:
 
            sys.exit('Nothing done')
 

	
 
@@ -125,25 +125,25 @@ class DbManage(object):
 
                   ' as version %s' % curr_version)
 
            api.version_control(db_uri, repository_path, curr_version)
 

	
 
        print (msg)
 

	
 
        if curr_version == __dbversion__:
 
            sys.exit('This database is already at the newest version')
 

	
 
        #======================================================================
 
        # UPGRADE STEPS
 
        #======================================================================
 
        class UpgradeSteps(object):
 
            """Those steps follow schema versions so for example schema 
 
            """Those steps follow schema versions so for example schema
 
            for example schema with seq 002 == step_2 and so on.
 
            """
 

	
 
            def __init__(self, klass):
 
                self.klass = klass
 

	
 
            def step_0(self):
 
                #step 0 is the schema upgrade, and than follow proper upgrades
 
                print ('attempting to do database upgrade to version %s' \
 
                                % __dbversion__)
 
                api.upgrade(db_uri, repository_path, __dbversion__)
 
                print ('Schema upgrade completed')
 
@@ -252,25 +252,25 @@ class DbManage(object):
 

	
 
            email = raw_input('Specify admin email:')
 
            self.create_user(username, password, email, True)
 
        else:
 
            log.info('creating admin and regular test users')
 
            self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
 
            self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
 
            self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
 

	
 
    def create_ui_settings(self):
 
        """Creates ui settings, fills out hooks
 
        and disables dotencode
 
        
 

	
 
        """
 
        #HOOKS
 
        hooks1_key = 'changegroup.update'
 
        hooks1_ = self.sa.query(RhodeCodeUi)\
 
            .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
 

	
 
        hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
 
        hooks1.ui_section = 'hooks'
 
        hooks1.ui_key = hooks1_key
 
        hooks1.ui_value = 'hg update >&2'
 
        hooks1.ui_active = False
 

	
 
@@ -507,13 +507,12 @@ class DbManage(object):
 
        default_repo_perm.permission = self.sa.query(Permission)\
 
        .filter(Permission.permission_name == 'repository.read')\
 
        .scalar()
 

	
 
        try:
 
            self.sa.add(reg_perm)
 
            self.sa.add(create_repo_perm)
 
            self.sa.add(default_repo_perm)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 

	
rhodecode/lib/dbmigrate/__init__.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.dbmigrate.__init__
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
    
 

	
 
    Database migration modules
 
    
 

	
 
    :created_on: Dec 11, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
from sqlalchemy import engine_from_config
 

	
 

	
 
from rhodecode.lib.utils import BasePasterCommand, Command, add_cache
 
from rhodecode.lib.db_manage import DbManage
 

	
rhodecode/lib/dbmigrate/migrate/changeset/ansisql.py
Show inline comments
 
@@ -50,25 +50,25 @@ class AlterTableVisitor(SchemaVisitor):
 
    def __init__(self, dialect, connection, **kw):
 
        self.connection = connection
 
        self.buffer = StringIO.StringIO()
 
        self.preparer = dialect.identifier_preparer
 
        self.dialect = dialect
 

	
 
    def traverse_single(self, elem):
 
        ret = super(AlterTableVisitor, self).traverse_single(elem)
 
        if ret:
 
            # adapt to 0.6 which uses a string-returning
 
            # object
 
            self.append(" %s" % ret)
 
            
 

	
 
    def _to_table(self, param):
 
        """Returns the table object for the given param object."""
 
        if isinstance(param, (sa.Column, sa.Index, sa.schema.Constraint)):
 
            ret = param.table
 
        else:
 
            ret = param
 
        return ret
 

	
 
    def start_alter_table(self, param):
 
        """Returns the start of an ``ALTER TABLE`` SQL-Statement.
 

	
 
        Use the param object to determine the table name and use it
 
@@ -288,28 +288,28 @@ if SQLA_06:
 

	
 
    class ANSIConstraintDropper(ANSIConstraintCommon, SchemaDropper):
 
        def _visit_constraint(self, constraint):
 
            constraint.name = self.get_constraint_name(constraint)
 
            self.append(self.process(DropConstraint(constraint, cascade=constraint.cascade)))
 
            self.execute()
 

	
 
else:
 
    class ANSIConstraintGenerator(ANSIConstraintCommon, SchemaGenerator):
 

	
 
        def get_constraint_specification(self, cons, **kwargs):
 
            """Constaint SQL generators.
 
        
 

	
 
            We cannot use SA visitors because they append comma.
 
            """
 
        
 

	
 
            if isinstance(cons, PrimaryKeyConstraint):
 
                if cons.name is not None:
 
                    self.append("CONSTRAINT %s " % self.preparer.format_constraint(cons))
 
                self.append("PRIMARY KEY ")
 
                self.append("(%s)" % ', '.join(self.preparer.quote(c.name, c.quote)
 
                                               for c in cons))
 
                self.define_constraint_deferrability(cons)
 
            elif isinstance(cons, ForeignKeyConstraint):
 
                self.define_foreign_key(cons)
 
            elif isinstance(cons, CheckConstraint):
 
                if cons.name is not None:
 
                    self.append("CONSTRAINT %s " %
 
@@ -318,31 +318,31 @@ else:
 
                self.define_constraint_deferrability(cons)
 
            elif isinstance(cons, UniqueConstraint):
 
                if cons.name is not None:
 
                    self.append("CONSTRAINT %s " %
 
                                self.preparer.format_constraint(cons))
 
                self.append("UNIQUE (%s)" % \
 
                    (', '.join(self.preparer.quote(c.name, c.quote) for c in cons)))
 
                self.define_constraint_deferrability(cons)
 
            else:
 
                raise exceptions.InvalidConstraintError(cons)
 

	
 
        def _visit_constraint(self, constraint):
 
        
 

	
 
            table = self.start_alter_table(constraint)
 
            constraint.name = self.get_constraint_name(constraint)
 
            self.append("ADD ")
 
            self.get_constraint_specification(constraint)
 
            self.execute()
 
    
 

	
 

	
 
    class ANSIConstraintDropper(ANSIConstraintCommon, SchemaDropper):
 

	
 
        def _visit_constraint(self, constraint):
 
            self.start_alter_table(constraint)
 
            self.append("DROP CONSTRAINT ")
 
            constraint.name = self.get_constraint_name(constraint)
 
            self.append(self.preparer.format_constraint(constraint))
 
            if constraint.cascade:
 
                self.cascade_constraint(constraint)
 
            self.execute()
 

	
rhodecode/lib/dbmigrate/migrate/changeset/databases/firebird.py
Show inline comments
 
@@ -25,25 +25,25 @@ class FBColumnDropper(ansisql.ANSIColumn
 
        Drop primary key and unique constraints if dropped column is referencing it."""
 
        if column.primary_key:
 
            if column.table.primary_key.columns.contains_column(column):
 
                column.table.primary_key.drop()
 
                # TODO: recreate primary key if it references more than this column
 

	
 
        for index in column.table.indexes:
 
            # "column in index.columns" causes problems as all
 
            # column objects compare equal and return a SQL expression
 
            if column.name in [col.name for col in index.columns]:
 
                index.drop()
 
                # TODO: recreate index if it references more than this column
 
        
 

	
 
        for cons in column.table.constraints:
 
            if isinstance(cons,PrimaryKeyConstraint):
 
                # will be deleted only when the column its on
 
                # is deleted!
 
                continue
 

	
 
            if SQLA_06:
 
                should_drop = column.name in cons.columns
 
            else:
 
                should_drop = cons.contains_column(column) and cons.name
 
            if should_drop:
 
                self.start_alter_table(column)
rhodecode/lib/dbmigrate/migrate/changeset/databases/sqlite.py
Show inline comments
 
@@ -35,35 +35,35 @@ class SQLiteHelper(SQLiteCommon):
 
            index.drop()
 

	
 
        self.append('ALTER TABLE %s RENAME TO migration_tmp' % table_name)
 
        self.execute()
 

	
 
        insertion_string = self._modify_table(table, column, delta)
 

	
 
        table.create()
 
        self.append(insertion_string % {'table_name': table_name})
 
        self.execute()
 
        self.append('DROP TABLE migration_tmp')
 
        self.execute()
 
        
 

	
 
    def visit_column(self, delta):
 
        if isinstance(delta, DictMixin):
 
            column = delta.result_column
 
            table = self._to_table(delta.table)
 
        else:
 
            column = delta
 
            table = self._to_table(column.table)
 
        self.recreate_table(table,column,delta)
 

	
 
class SQLiteColumnGenerator(SQLiteSchemaGenerator, 
 
class SQLiteColumnGenerator(SQLiteSchemaGenerator,
 
                            ansisql.ANSIColumnGenerator,
 
                            # at the end so we get the normal
 
                            # visit_column by default
 
                            SQLiteHelper,
 
                            SQLiteCommon
 
                            ):
 
    """SQLite ColumnGenerator"""
 

	
 
    def _modify_table(self, table, column, delta):
 
        columns = ' ,'.join(map(
 
                self.preparer.format_column,
 
                [c for c in table.columns if c.name!=column.name]))
 
@@ -71,25 +71,25 @@ class SQLiteColumnGenerator(SQLiteSchema
 
                'SELECT %(cols)s from migration_tmp')%{'cols':columns}
 

	
 
    def visit_column(self,column):
 
        if column.foreign_keys:
 
            SQLiteHelper.visit_column(self,column)
 
        else:
 
            super(SQLiteColumnGenerator,self).visit_column(column)
 

	
 
class SQLiteColumnDropper(SQLiteHelper, ansisql.ANSIColumnDropper):
 
    """SQLite ColumnDropper"""
 

	
 
    def _modify_table(self, table, column, delta):
 
        
 

	
 
        columns = ' ,'.join(map(self.preparer.format_column, table.columns))
 
        return 'INSERT INTO %(table_name)s SELECT ' + columns + \
 
            ' from migration_tmp'
 

	
 
    def visit_column(self,column):
 
        # For SQLite, we *have* to remove the column here so the table
 
        # is re-created properly.
 
        column.remove_from_table(column.table,unset_table=False)
 
        super(SQLiteColumnDropper,self).visit_column(column)
 

	
 

	
 
class SQLiteSchemaChanger(SQLiteHelper, ansisql.ANSISchemaChanger):
rhodecode/lib/dbmigrate/migrate/changeset/schema.py
Show inline comments
 
@@ -22,35 +22,35 @@ __all__ = [
 
    'alter_column',
 
    'rename_table',
 
    'rename_index',
 
    'ChangesetTable',
 
    'ChangesetColumn',
 
    'ChangesetIndex',
 
    'ChangesetDefaultClause',
 
    'ColumnDelta',
 
]
 

	
 
def create_column(column, table=None, *p, **kw):
 
    """Create a column, given the table.
 
    
 

	
 
    API to :meth:`ChangesetColumn.create`.
 
    """
 
    if table is not None:
 
        return table.create_column(column, *p, **kw)
 
    return column.create(*p, **kw)
 

	
 

	
 
def drop_column(column, table=None, *p, **kw):
 
    """Drop a column, given the table.
 
    
 

	
 
    API to :meth:`ChangesetColumn.drop`.
 
    """
 
    if table is not None:
 
        return table.drop_column(column, *p, **kw)
 
    return column.drop(*p, **kw)
 

	
 

	
 
def rename_table(table, name, engine=None, **kw):
 
    """Rename a table.
 

	
 
    If Table instance is given, engine is not used.
 

	
 
@@ -96,49 +96,49 @@ def alter_column(*p, **k):
 

	
 
    :argument column:
 
      The name of the column to be altered or a
 
      :class:`ChangesetColumn` column representing it.
 

	
 
    :param table:
 
      A :class:`~sqlalchemy.schema.Table` or table name to
 
      for the table where the column will be changed.
 

	
 
    :param engine:
 
      The :class:`~sqlalchemy.engine.base.Engine` to use for table
 
      reflection and schema alterations.
 
    
 

	
 
    :returns: A :class:`ColumnDelta` instance representing the change.
 

	
 
    
 

	
 
    """
 
    
 

	
 
    if 'table' not in k and isinstance(p[0], sqlalchemy.Column):
 
        k['table'] = p[0].table
 
    if 'engine' not in k:
 
        k['engine'] = k['table'].bind
 

	
 
    # deprecation
 
    if len(p) >= 2 and isinstance(p[1], sqlalchemy.Column):
 
        warnings.warn(
 
            "Passing a Column object to alter_column is deprecated."
 
            " Just pass in keyword parameters instead.",
 
            MigrateDeprecationWarning
 
            )
 
    engine = k['engine']
 

	
 
    # enough tests seem to break when metadata is always altered
 
    # that this crutch has to be left in until they can be sorted
 
    # out
 
    k['alter_metadata']=True
 
    
 

	
 
    delta = ColumnDelta(*p, **k)
 

	
 
    visitorcallable = get_engine_visitor(engine, 'schemachanger')
 
    engine._run_visitor(visitorcallable, delta)
 

	
 
    return delta
 

	
 

	
 
def _to_table(table, engine=None):
 
    """Return if instance of Table, else construct new with metadata"""
 
    if isinstance(table, sqlalchemy.Table):
 
        return table
 
@@ -174,53 +174,53 @@ class ColumnDelta(DictMixin, sqlalchemy.
 
        * **current_column, \*p, \*\*kw**
 
            Additional parameters alter current_column. Table name is extracted
 
            from current_column object.
 
            Name is changed to current_column.name from current_name,
 
            if current_name is specified.
 

	
 
        * **current_col_name, \*p, \*\*kw**
 
            Table kw must specified.
 

	
 
        :param table: Table at which current Column should be bound to.\
 
        If table name is given, reflection will be used.
 
        :type table: string or Table instance
 
        
 

	
 
        :param metadata: A :class:`MetaData` instance to store
 
                         reflected table names
 
                         
 

	
 
        :param engine: When reflecting tables, either engine or metadata must \
 
        be specified to acquire engine object.
 
        :type engine: :class:`Engine` instance
 
        :returns: :class:`ColumnDelta` instance provides interface for altered attributes to \
 
        `result_column` through :func:`dict` alike object.
 

	
 
        * :class:`ColumnDelta`.result_column is altered column with new attributes
 

	
 
        * :class:`ColumnDelta`.current_name is current name of column in db
 

	
 

	
 
    """
 

	
 
    # Column attributes that can be altered
 
    diff_keys = ('name', 'type', 'primary_key', 'nullable',
 
        'server_onupdate', 'server_default', 'autoincrement')
 
    diffs = dict()
 
    __visit_name__ = 'column'
 

	
 
    def __init__(self, *p, **kw):
 
        # 'alter_metadata' is not a public api. It exists purely
 
        # as a crutch until the tests that fail when 'alter_metadata'
 
        # behaviour always happens can be sorted out
 
        self.alter_metadata = kw.pop("alter_metadata", False)
 
        
 

	
 
        self.meta = kw.pop("metadata", None)
 
        self.engine = kw.pop("engine", None)
 

	
 
        # Things are initialized differently depending on how many column
 
        # parameters are given. Figure out how many and call the appropriate
 
        # method.
 
        if len(p) >= 1 and isinstance(p[0], sqlalchemy.Column):
 
            # At least one column specified
 
            if len(p) >= 2 and isinstance(p[1], sqlalchemy.Column):
 
                # Two columns specified
 
                diffs = self.compare_2_columns(*p, **kw)
 
            else:
 
@@ -230,25 +230,25 @@ class ColumnDelta(DictMixin, sqlalchemy.
 
            # Zero columns specified
 
            if not len(p) or not isinstance(p[0], basestring):
 
                raise ValueError("First argument must be column name")
 
            diffs = self.compare_parameters(*p, **kw)
 

	
 
        self.apply_diffs(diffs)
 

	
 
    def __repr__(self):
 
        return '<ColumnDelta altermetadata=%r, %s>' % (
 
            self.alter_metadata,
 
            super(ColumnDelta, self).__repr__()
 
            )
 
    
 

	
 
    def __getitem__(self, key):
 
        if key not in self.keys():
 
            raise KeyError("No such diff key, available: %s" % self.diffs )
 
        return getattr(self.result_column, key)
 

	
 
    def __setitem__(self, key, value):
 
        if key not in self.keys():
 
            raise KeyError("No such diff key, available: %s" % self.diffs )
 
        setattr(self.result_column, key, value)
 

	
 
    def __delitem__(self, key):
 
        raise NotImplementedError
 
@@ -269,25 +269,25 @@ class ColumnDelta(DictMixin, sqlalchemy.
 
        self.table = k.pop('table', None)
 
        if self.table is None:
 
            self.table = col.table
 
        self.result_column = col
 
        if len(p):
 
            k = self._extract_parameters(p, k, self.result_column)
 
        return k
 

	
 
    def compare_2_columns(self, old_col, new_col, *p, **k):
 
        """Compares two Column objects"""
 
        self.process_column(new_col)
 
        self.table = k.pop('table', None)
 
        # we cannot use bool() on table in SA06 
 
        # we cannot use bool() on table in SA06
 
        if self.table is None:
 
            self.table = old_col.table
 
        if self.table is None:
 
            new_col.table
 
        self.result_column = old_col
 

	
 
        # set differences
 
        # leave out some stuff for later comp
 
        for key in (set(self.diff_keys) - set(('type',))):
 
            val = getattr(new_col, key, None)
 
            if getattr(self.result_column, key, None) != val:
 
                k.setdefault(key, val)
 
@@ -358,25 +358,25 @@ class ColumnDelta(DictMixin, sqlalchemy.
 
            if isinstance(column.server_default, sqlalchemy.FetchedValue):
 
                toinit.append(column.server_default)
 
            else:
 
                toinit.append(sqlalchemy.DefaultClause(column.server_default))
 
        if column.server_onupdate is not None:
 
            if isinstance(column.server_onupdate, FetchedValue):
 
                toinit.append(column.server_default)
 
            else:
 
                toinit.append(sqlalchemy.DefaultClause(column.server_onupdate,
 
                                            for_update=True))
 
        if toinit:
 
            column._init_items(*toinit)
 
            
 

	
 
        if not SQLA_06:
 
            column.args = []
 

	
 
    def _get_table(self):
 
        return getattr(self, '_table', None)
 

	
 
    def _set_table(self, table):
 
        if isinstance(table, basestring):
 
            if self.alter_metadata:
 
                if not self.meta:
 
                    raise ValueError("metadata must be specified for table"
 
                        " reflection when using alter_metadata")
 
@@ -475,25 +475,25 @@ class ChangesetTable(object):
 
        """Remove this table from its metadata"""
 
        key = self._meta_key()
 
        meta = self.metadata
 
        if key in meta.tables:
 
            del meta.tables[key]
 

	
 

	
 
class ChangesetColumn(object):
 
    """Changeset extensions to SQLAlchemy columns."""
 

	
 
    def alter(self, *p, **k):
 
        """Makes a call to :func:`alter_column` for the column this
 
        method is called on. 
 
        method is called on.
 
        """
 
        if 'table' not in k:
 
            k['table'] = self.table
 
        if 'engine' not in k:
 
            k['engine'] = k['table'].bind
 
        return alter_column(self, *p, **k)
 

	
 
    def create(self, table=None, index_name=None, unique_name=None,
 
               primary_key_name=None, populate_default=True, connection=None, **kwargs):
 
        """Create this column in the database.
 

	
 
        Assumes the given table exists. ``ALTER TABLE ADD COLUMN``,
 
@@ -550,54 +550,54 @@ populated with defaults
 
        visitorcallable = get_engine_visitor(engine, 'columndropper')
 
        engine._run_visitor(visitorcallable, self, connection, **kwargs)
 
        self.remove_from_table(self.table, unset_table=False)
 
        self.table = None
 
        return self
 

	
 
    def add_to_table(self, table):
 
        if table is not None  and self.table is None:
 
            self._set_parent(table)
 

	
 
    def _col_name_in_constraint(self,cons,name):
 
        return False
 
    
 

	
 
    def remove_from_table(self, table, unset_table=True):
 
        # TODO: remove primary keys, constraints, etc
 
        if unset_table:
 
            self.table = None
 
            
 

	
 
        to_drop = set()
 
        for index in table.indexes:
 
            columns = []
 
            for col in index.columns:
 
                if col.name!=self.name:
 
                    columns.append(col)
 
            if columns:
 
                index.columns=columns
 
            else:
 
                to_drop.add(index)
 
        table.indexes = table.indexes - to_drop
 
        
 

	
 
        to_drop = set()
 
        for cons in table.constraints:
 
            # TODO: deal with other types of constraint
 
            if isinstance(cons,(ForeignKeyConstraint,
 
                                UniqueConstraint)):
 
                for col_name in cons.columns:
 
                    if not isinstance(col_name,basestring):
 
                        col_name = col_name.name
 
                    if self.name==col_name:
 
                        to_drop.add(cons)
 
        table.constraints = table.constraints - to_drop
 
        
 

	
 
        if table.c.contains_column(self):
 
            table.c.remove(self)
 

	
 
    # TODO: this is fixed in 0.6
 
    def copy_fixed(self, **kw):
 
        """Create a copy of this ``Column``, with all attributes."""
 
        return sqlalchemy.Column(self.name, self.type, self.default,
 
            key=self.key,
 
            primary_key=self.primary_key,
 
            nullable=self.nullable,
 
            quote=self.quote,
 
            index=self.index,
rhodecode/lib/dbmigrate/migrate/versioning/genmodel.py
Show inline comments
 
@@ -198,27 +198,27 @@ class ModelGenerator(object):
 
        for table in self._get_tables(missingA=True):
 
            table = table.tometadata(meta)
 
            table.drop()
 
        for table in self._get_tables(missingB=True):
 
            table = table.tometadata(meta)
 
            table.create()
 
        for modelTable in self._get_tables(modified=True):
 
            tableName = modelTable.name
 
            modelTable = modelTable.tometadata(meta)
 
            dbTable = self.diff.metadataB.tables[tableName]
 

	
 
            td = self.diff.tables_different[tableName]
 
            
 

	
 
            if self._db_can_handle_this_change(td):
 
                
 

	
 
                for col in td.columns_missing_from_B:
 
                    modelTable.columns[col].create()
 
                for col in td.columns_missing_from_A:
 
                    dbTable.columns[col].drop()
 
                # XXX handle column changes here.
 
            else:
 
                # Sqlite doesn't support drop column, so you have to
 
                # do more: create temp table, copy data to it, drop
 
                # old table, create new table, copy data back.
 
                #
 
                # I wonder if this is guaranteed to be unique?
 
                tempName = '_temp_%s' % modelTable.name
rhodecode/lib/dbmigrate/migrate/versioning/repository.py
Show inline comments
 
@@ -209,23 +209,23 @@ class Repository(pathed.Pathed):
 
            step = -1
 
            range_mod = 0
 
            op = 'downgrade'
 

	
 
        versions = range(start + range_mod, end + range_mod, step)
 
        changes = [self.version(v).script(database, op) for v in versions]
 
        ret = Changeset(start, step=step, *changes)
 
        return ret
 

	
 
    @classmethod
 
    def create_manage_file(cls, file_, **opts):
 
        """Create a project management script (manage.py)
 
        
 

	
 
        :param file_: Destination file to be written
 
        :param opts: Options that are passed to :func:`migrate.versioning.shell.main`
 
        """
 
        mng_file = Template(opts.pop('templates_path', None))\
 
            .get_manage(theme=opts.pop('templates_theme', None))
 

	
 
        tmpl = open(mng_file).read()
 
        fd = open(file_, 'w')
 
        fd.write(TempitaTemplate(tmpl).substitute(opts))
 
        fd.close()
rhodecode/lib/dbmigrate/migrate/versioning/schema.py
Show inline comments
 
@@ -55,25 +55,25 @@ class ControlledSchema(object):
 

	
 
    def drop(self):
 
        """
 
        Remove version control from a database.
 
        """
 
        try:
 
            self.table.drop()
 
        except (sa_exceptions.SQLError):
 
            raise exceptions.DatabaseNotControlledError(str(self.table))
 

	
 
    def changeset(self, version=None):
 
        """API to Changeset creation.
 
        
 

	
 
        Uses self.version for start version and engine.name
 
        to get database name.
 
        """
 
        database = self.engine.name
 
        start_ver = self.version
 
        changeset = self.repository.changeset(database, start_ver, version)
 
        return changeset
 

	
 
    def runchange(self, ver, change, step):
 
        startver = ver
 
        endver = ver + step
 
        # Current database version must be correct! Don't run if corrupt!
rhodecode/lib/dbmigrate/migrate/versioning/schemadiff.py
Show inline comments
 
@@ -30,45 +30,45 @@ def getDiffOfModelAgainstModel(metadataA
 

	
 
    :return: object which will evaluate to :keyword:`True` if there \
 
      are differences else :keyword:`False`.
 
    """
 
    return SchemaDiff(metadataA, metadataB, excludeTables)
 

	
 

	
 
class ColDiff(object):
 
    """
 
    Container for differences in one :class:`~sqlalchemy.schema.Column`
 
    between two :class:`~sqlalchemy.schema.Table` instances, ``A``
 
    and ``B``.
 
    
 

	
 
    .. attribute:: col_A
 

	
 
      The :class:`~sqlalchemy.schema.Column` object for A.
 
      
 

	
 
    .. attribute:: col_B
 

	
 
      The :class:`~sqlalchemy.schema.Column` object for B.
 

	
 
    .. attribute:: type_A
 

	
 
      The most generic type of the :class:`~sqlalchemy.schema.Column`
 
      object in A. 
 
      
 
      object in A.
 

	
 
    .. attribute:: type_B
 

	
 
      The most generic type of the :class:`~sqlalchemy.schema.Column`
 
      object in A. 
 
      
 
      object in A.
 

	
 
    """
 
    
 

	
 
    diff = False
 

	
 
    def __init__(self,col_A,col_B):
 
        self.col_A = col_A
 
        self.col_B = col_B
 

	
 
        self.type_A = col_A.type
 
        self.type_B = col_B.type
 

	
 
        self.affinity_A = self.type_A._type_affinity
 
        self.affinity_B = self.type_B._type_affinity
 

	
 
@@ -78,104 +78,104 @@ class ColDiff(object):
 

	
 
        if isinstance(self.type_A,Float) or isinstance(self.type_B,Float):
 
            if not (isinstance(self.type_A,Float) and isinstance(self.type_B,Float)):
 
                self.diff=True
 
                return
 

	
 
        for attr in ('precision','scale','length'):
 
            A = getattr(self.type_A,attr,None)
 
            B = getattr(self.type_B,attr,None)
 
            if not (A is None or B is None) and A!=B:
 
                self.diff=True
 
                return
 
        
 

	
 
    def __nonzero__(self):
 
        return self.diff
 
    
 

	
 
class TableDiff(object):
 
    """
 
    Container for differences in one :class:`~sqlalchemy.schema.Table`
 
    between two :class:`~sqlalchemy.schema.MetaData` instances, ``A``
 
    and ``B``.
 

	
 
    .. attribute:: columns_missing_from_A
 

	
 
      A sequence of column names that were found in B but weren't in
 
      A.
 
      
 

	
 
    .. attribute:: columns_missing_from_B
 

	
 
      A sequence of column names that were found in A but weren't in
 
      B.
 
      
 

	
 
    .. attribute:: columns_different
 

	
 
      A dictionary containing information about columns that were
 
      found to be different.
 
      It maps column names to a :class:`ColDiff` objects describing the
 
      differences found.
 
    """
 
    __slots__ = (
 
        'columns_missing_from_A',
 
        'columns_missing_from_B',
 
        'columns_different',
 
        )
 

	
 
    def __nonzero__(self):
 
        return bool(
 
            self.columns_missing_from_A or
 
            self.columns_missing_from_B or
 
            self.columns_different
 
            )
 
    
 

	
 
class SchemaDiff(object):
 
    """
 
    Compute the difference between two :class:`~sqlalchemy.schema.MetaData`
 
    objects.
 

	
 
    The string representation of a :class:`SchemaDiff` will summarise
 
    the changes found between the two
 
    :class:`~sqlalchemy.schema.MetaData` objects.
 

	
 
    The length of a :class:`SchemaDiff` will give the number of
 
    changes found, enabling it to be used much like a boolean in
 
    expressions.
 
        
 

	
 
    :param metadataA:
 
      First :class:`~sqlalchemy.schema.MetaData` to compare.
 
      
 

	
 
    :param metadataB:
 
      Second :class:`~sqlalchemy.schema.MetaData` to compare.
 
      
 

	
 
    :param labelA:
 
      The label to use in messages about the first
 
      :class:`~sqlalchemy.schema.MetaData`. 
 
    
 
    :param labelB: 
 
      :class:`~sqlalchemy.schema.MetaData`.
 

	
 
    :param labelB:
 
      The label to use in messages about the second
 
      :class:`~sqlalchemy.schema.MetaData`. 
 
    
 
      :class:`~sqlalchemy.schema.MetaData`.
 

	
 
    :param excludeTables:
 
      A sequence of table names to exclude.
 
      
 

	
 
    .. attribute:: tables_missing_from_A
 

	
 
      A sequence of table names that were found in B but weren't in
 
      A.
 
      
 

	
 
    .. attribute:: tables_missing_from_B
 

	
 
      A sequence of table names that were found in A but weren't in
 
      B.
 
      
 

	
 
    .. attribute:: tables_different
 

	
 
      A dictionary containing information about tables that were found
 
      to be different.
 
      It maps table names to a :class:`TableDiff` objects describing the
 
      differences found.
 
    """
 

	
 
    def __init__(self,
 
                 metadataA, metadataB,
 
                 labelA='metadataA',
 
                 labelB='metadataB',
 
@@ -186,97 +186,97 @@ class SchemaDiff(object):
 
        self.label_width = max(len(labelA),len(labelB))
 
        excludeTables = set(excludeTables or [])
 

	
 
        A_table_names = set(metadataA.tables.keys())
 
        B_table_names = set(metadataB.tables.keys())
 

	
 
        self.tables_missing_from_A = sorted(
 
            B_table_names - A_table_names - excludeTables
 
            )
 
        self.tables_missing_from_B = sorted(
 
            A_table_names - B_table_names - excludeTables
 
            )
 
        
 

	
 
        self.tables_different = {}
 
        for table_name in A_table_names.intersection(B_table_names):
 

	
 
            td = TableDiff()
 
            
 

	
 
            A_table = metadataA.tables[table_name]
 
            B_table = metadataB.tables[table_name]
 
            
 

	
 
            A_column_names = set(A_table.columns.keys())
 
            B_column_names = set(B_table.columns.keys())
 

	
 
            td.columns_missing_from_A = sorted(
 
                B_column_names - A_column_names
 
                )
 
            
 

	
 
            td.columns_missing_from_B = sorted(
 
                A_column_names - B_column_names
 
                )
 
            
 

	
 
            td.columns_different = {}
 

	
 
            for col_name in A_column_names.intersection(B_column_names):
 

	
 
                cd = ColDiff(
 
                    A_table.columns.get(col_name),
 
                    B_table.columns.get(col_name)
 
                    )
 

	
 
                if cd:
 
                    td.columns_different[col_name]=cd
 
                
 

	
 
            # XXX - index and constraint differences should
 
            #       be checked for here
 

	
 
            if td:
 
                self.tables_different[table_name]=td
 

	
 
    def __str__(self):
 
        ''' Summarize differences. '''
 
        out = []
 
        column_template ='      %%%is: %%r' % self.label_width
 
        
 

	
 
        for names,label in (
 
            (self.tables_missing_from_A,self.labelA),
 
            (self.tables_missing_from_B,self.labelB),
 
            ):
 
            if names:
 
                out.append(
 
                    '  tables missing from %s: %s' % (
 
                        label,', '.join(sorted(names))
 
                        )
 
                    )
 
                
 

	
 
        for name,td in sorted(self.tables_different.items()):
 
            out.append(
 
               '  table with differences: %s' % name
 
               )
 
            for names,label in (
 
                (td.columns_missing_from_A,self.labelA),
 
                (td.columns_missing_from_B,self.labelB),
 
                ):
 
                if names:
 
                    out.append(
 
                        '    %s missing these columns: %s' % (
 
                            label,', '.join(sorted(names))
 
                            )
 
                        )
 
            for name,cd in td.columns_different.items():
 
                out.append('    column with differences: %s' % name)
 
                out.append(column_template % (self.labelA,cd.col_A))
 
                out.append(column_template % (self.labelB,cd.col_B))
 
                
 

	
 
        if out:
 
            out.insert(0, 'Schema diffs:')
 
            return '\n'.join(out)
 
        else:
 
            return 'No schema diffs'
 

	
 
    def __len__(self):
 
        """
 
        Used in bool evaluation, return of 0 means no diffs.
 
        """
 
        return (
 
            len(self.tables_missing_from_A) +
rhodecode/lib/dbmigrate/migrate/versioning/script/base.py
Show inline comments
 
@@ -19,25 +19,25 @@ class BaseScript(pathed.Pathed):
 
      The version number of the script
 
    operations (script.operations())
 
      The operations defined by the script: upgrade(), downgrade() or both.
 
      Returns a tuple of operations.
 
      Can also check for an operation with ex. script.operation(Script.ops.up)
 
    """ # TODO: sphinxfy this and implement it correctly
 

	
 
    def __init__(self, path):
 
        log.debug('Loading script %s...' % path)
 
        self.verify(path)
 
        super(BaseScript, self).__init__(path)
 
        log.debug('Script %s loaded successfully' % path)
 
    
 

	
 
    @classmethod
 
    def verify(cls, path):
 
        """Ensure this is a valid script
 
        This version simply ensures the script file's existence
 

	
 
        :raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>`
 
        """
 
        try:
 
            cls.require_found(path)
 
        except:
 
            raise exceptions.InvalidScriptError(path)
 

	
rhodecode/lib/dbmigrate/migrate/versioning/script/py.py
Show inline comments
 
@@ -16,50 +16,50 @@ from rhodecode.lib.dbmigrate.migrate.ver
 
from rhodecode.lib.dbmigrate.migrate.exceptions import MigrateDeprecationWarning, InvalidScriptError, ScriptError
 

	
 
log = logging.getLogger(__name__)
 
__all__ = ['PythonScript']
 

	
 

	
 
class PythonScript(base.BaseScript):
 
    """Base for Python scripts"""
 

	
 
    @classmethod
 
    def create(cls, path, **opts):
 
        """Create an empty migration script at specified path
 
        
 

	
 
        :returns: :class:`PythonScript instance <migrate.versioning.script.py.PythonScript>`"""
 
        cls.require_notfound(path)
 

	
 
        src = Template(opts.pop('templates_path', None)).get_script(theme=opts.pop('templates_theme', None))
 
        shutil.copy(src, path)
 

	
 
        return cls(path)
 

	
 
    @classmethod
 
    def make_update_script_for_model(cls, engine, oldmodel,
 
                                     model, repository, **opts):
 
        """Create a migration script based on difference between two SA models.
 
        
 

	
 
        :param repository: path to migrate repository
 
        :param oldmodel: dotted.module.name:SAClass or SAClass object
 
        :param model: dotted.module.name:SAClass or SAClass object
 
        :param engine: SQLAlchemy engine
 
        :type repository: string or :class:`Repository instance <migrate.versioning.repository.Repository>`
 
        :type oldmodel: string or Class
 
        :type model: string or Class
 
        :type engine: Engine instance
 
        :returns: Upgrade / Downgrade script
 
        :rtype: string
 
        """
 
        
 

	
 
        if isinstance(repository, basestring):
 
            # oh dear, an import cycle!
 
            from rhodecode.lib.dbmigrate.migrate.versioning.repository import Repository
 
            repository = Repository(repository)
 

	
 
        oldmodel = load_model(oldmodel)
 
        model = load_model(model)
 

	
 
        # Compute differences.
 
        diff = schemadiff.getDiffOfModelAgainstModel(
 
            oldmodel,
 
            model,
 
@@ -77,58 +77,58 @@ class PythonScript(base.BaseScript):
 
        # generate source
 
        search = 'def upgrade(migrate_engine):'
 
        contents = contents.replace(search, '\n\n'.join((decls, search)), 1)
 
        if upgradeCommands:
 
            contents = contents.replace('    pass', upgradeCommands, 1)
 
        if downgradeCommands:
 
            contents = contents.replace('    pass', downgradeCommands, 1)
 
        return contents
 

	
 
    @classmethod
 
    def verify_module(cls, path):
 
        """Ensure path is a valid script
 
        
 

	
 
        :param path: Script location
 
        :type path: string
 
        :raises: :exc:`InvalidScriptError <migrate.exceptions.InvalidScriptError>`
 
        :returns: Python module
 
        """
 
        # Try to import and get the upgrade() func
 
        module = import_path(path)
 
        try:
 
            assert callable(module.upgrade)
 
        except Exception, e:
 
            raise InvalidScriptError(path + ': %s' % str(e))
 
        return module
 

	
 
    def preview_sql(self, url, step, **args):
 
        """Mocks SQLAlchemy Engine to store all executed calls in a string 
 
        """Mocks SQLAlchemy Engine to store all executed calls in a string
 
        and runs :meth:`PythonScript.run <migrate.versioning.script.py.PythonScript.run>`
 

	
 
        :returns: SQL file
 
        """
 
        buf = StringIO()
 
        args['engine_arg_strategy'] = 'mock'
 
        args['engine_arg_executor'] = lambda s, p = '': buf.write(str(s) + p)
 

	
 
        @with_engine
 
        def go(url, step, **kw):
 
            engine = kw.pop('engine')
 
            self.run(engine, step)
 
            return buf.getvalue()
 

	
 
        return go(url, step, **args)
 

	
 
    def run(self, engine, step):
 
        """Core method of Script file. 
 
        """Core method of Script file.
 
        Exectues :func:`update` or :func:`downgrade` functions
 

	
 
        :param engine: SQLAlchemy Engine
 
        :param step: Operation to run
 
        :type engine: string
 
        :type step: int
 
        """
 
        if step > 0:
 
            op = 'upgrade'
 
        elif step < 0:
 
            op = 'downgrade'
 
        else:
rhodecode/lib/dbmigrate/migrate/versioning/script/sql.py
Show inline comments
 
@@ -6,25 +6,25 @@ import shutil
 
from rhodecode.lib.dbmigrate.migrate.versioning.script import base
 
from rhodecode.lib.dbmigrate.migrate.versioning.template import Template
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
class SqlScript(base.BaseScript):
 
    """A file containing plain SQL statements."""
 

	
 
    @classmethod
 
    def create(cls, path, **opts):
 
        """Create an empty migration script at specified path
 
        
 

	
 
        :returns: :class:`SqlScript instance <migrate.versioning.script.sql.SqlScript>`"""
 
        cls.require_notfound(path)
 

	
 
        src = Template(opts.pop('templates_path', None)).get_sql_script(theme=opts.pop('templates_theme', None))
 
        shutil.copy(src, path)
 
        return cls(path)
 

	
 
    # TODO: why is step parameter even here?
 
    def run(self, engine, step=None, executemany=True):
 
        """Runs SQL script through raw dbapi execute call"""
 
        text = self.source()
 
        # Don't rely on SA's autocommit here
rhodecode/lib/dbmigrate/migrate/versioning/template.py
Show inline comments
 
@@ -24,25 +24,25 @@ class RepositoryCollection(Collection):
 

	
 
class ScriptCollection(Collection):
 
    _mask = '%s.py_tmpl'
 

	
 
class ManageCollection(Collection):
 
    _mask = '%s.py_tmpl'
 

	
 
class SQLScriptCollection(Collection):
 
    _mask = '%s.py_tmpl'
 

	
 
class Template(pathed.Pathed):
 
    """Finds the paths/packages of various Migrate templates.
 
    
 

	
 
    :param path: Templates are loaded from rhodecode.lib.dbmigrate.migrate package
 
    if `path` is not provided.
 
    """
 
    pkg = 'rhodecode.lib.dbmigrate.migrate.versioning.templates'
 
    _manage = 'manage.py_tmpl'
 

	
 
    def __new__(cls, path=None):
 
        if path is None:
 
            path = cls._find_path(cls.pkg)
 
        return super(Template, cls).__new__(cls, path)
 

	
 
    def __init__(self, path=None):
 
@@ -57,38 +57,38 @@ class Template(pathed.Pathed):
 
    @classmethod
 
    def _find_path(cls, pkg):
 
        """Returns absolute path to dotted python package."""
 
        tmp_pkg = pkg.rsplit('.', 1)
 

	
 
        if len(tmp_pkg) != 1:
 
            return resource_filename(tmp_pkg[0], tmp_pkg[1])
 
        else:
 
            return resource_filename(tmp_pkg[0], '')
 

	
 
    def _get_item(self, collection, theme=None):
 
        """Locates and returns collection.
 
        
 

	
 
        :param collection: name of collection to locate
 
        :param type_: type of subfolder in collection (defaults to "_default")
 
        :returns: (package, source)
 
        :rtype: str, str
 
        """
 
        item = getattr(self, collection)
 
        theme_mask = getattr(item, '_mask')
 
        theme = theme_mask % (theme or 'default')
 
        return item.get_path(theme)
 

	
 
    def get_repository(self, *a, **kw):
 
        """Calls self._get_item('repository', *a, **kw)"""
 
        return self._get_item('repository', *a, **kw)
 
    
 

	
 
    def get_script(self, *a, **kw):
 
        """Calls self._get_item('script', *a, **kw)"""
 
        return self._get_item('script', *a, **kw)
 

	
 
    def get_sql_script(self, *a, **kw):
 
        """Calls self._get_item('sql_script', *a, **kw)"""
 
        return self._get_item('sql_script', *a, **kw)
 

	
 
    def get_manage(self, *a, **kw):
 
        """Calls self._get_item('manage', *a, **kw)"""
 
        return self._get_item('manage', *a, **kw)
rhodecode/lib/dbmigrate/migrate/versioning/util/__init__.py
Show inline comments
 
@@ -13,25 +13,25 @@ from sqlalchemy.pool import StaticPool
 

	
 
from rhodecode.lib.dbmigrate.migrate import exceptions
 
from rhodecode.lib.dbmigrate.migrate.versioning.util.keyedinstance import KeyedInstance
 
from rhodecode.lib.dbmigrate.migrate.versioning.util.importpath import import_path
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 
def load_model(dotted_name):
 
    """Import module and use module-level variable".
 

	
 
    :param dotted_name: path to model in form of string: ``some.python.module:Class``
 
    
 

	
 
    .. versionchanged:: 0.5.4
 

	
 
    """
 
    if isinstance(dotted_name, basestring):
 
        if ':' not in dotted_name:
 
            # backwards compatibility
 
            warnings.warn('model should be in form of module.model:User '
 
                'and not module.model.User', exceptions.MigrateDeprecationWarning)
 
            dotted_name = ':'.join(dotted_name.rsplit('.', 1))
 
        return EntryPoint.parse('x=%s' % dotted_name).load(False)
 
    else:
 
        # Assume it's already loaded.
 
@@ -45,52 +45,52 @@ def asbool(obj):
 
            return True
 
        elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
 
            return False
 
        else:
 
            raise ValueError("String is not true/false: %r" % obj)
 
    if obj in (True, False):
 
        return bool(obj)
 
    else:
 
        raise ValueError("String is not true/false: %r" % obj)
 

	
 
def guess_obj_type(obj):
 
    """Do everything to guess object type from string
 
    
 

	
 
    Tries to convert to `int`, `bool` and finally returns if not succeded.
 
    
 

	
 
    .. versionadded: 0.5.4
 
    """
 

	
 
    result = None
 

	
 
    try:
 
        result = int(obj)
 
    except:
 
        pass
 

	
 
    if result is None:
 
        try:
 
            result = asbool(obj)
 
        except:
 
            pass
 

	
 
    if result is not None:
 
        return result
 
    else:
 
        return obj
 

	
 
@decorator
 
def catch_known_errors(f, *a, **kw):
 
    """Decorator that catches known api errors
 
    
 

	
 
    .. versionadded: 0.5.4
 
    """
 

	
 
    try:
 
        return f(*a, **kw)
 
    except exceptions.PathFoundError, e:
 
        raise exceptions.KnownError("The path %s already exists" % e.args[0])
 

	
 
def construct_engine(engine, **opts):
 
    """.. versionadded:: 0.5.4
 

	
 
    Constructs and returns SQLAlchemy engine.
rhodecode/lib/dbmigrate/migrate/versioning/util/importpath.py
Show inline comments
 
import os
 
import sys
 

	
 
def import_path(fullpath):
 
    """ Import a file with full path specification. Allows one to
 
        import from anywhere, something __import__ does not do. 
 
        import from anywhere, something __import__ does not do.
 
    """
 
    # http://zephyrfalcon.org/weblog/arch_d7_2002_08_31.html
 
    path, filename = os.path.split(fullpath)
 
    filename, ext = os.path.splitext(filename)
 
    sys.path.append(path)
 
    module = __import__(filename)
 
    reload(module) # Might be out of date during tests
 
    del sys.path[-1]
 
    return module
 

	
rhodecode/lib/dbmigrate/migrate/versioning/util/keyedinstance.py
Show inline comments
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 

	
 
class KeyedInstance(object):
 
    """A class whose instances have a unique identifier of some sort
 
    No two instances with the same unique ID should exist - if we try to create
 
    a second instance, the first should be returned. 
 
    a second instance, the first should be returned.
 
    """
 

	
 
    _instances = dict()
 

	
 
    def __new__(cls, *p, **k):
 
        instances = cls._instances
 
        clskey = str(cls)
 
        if clskey not in instances:
 
            instances[clskey] = dict()
 
        instances = instances[clskey]
 

	
 
        key = cls._key(*p, **k)
 
        if key not in instances:
 
            instances[key] = super(KeyedInstance, cls).__new__(cls)
 
        return instances[key]
 

	
 
    @classmethod
 
    def _key(cls, *p, **k):
 
        """Given a unique identifier, return a dictionary key
 
        This should be overridden by child classes, to specify which parameters 
 
        This should be overridden by child classes, to specify which parameters
 
        should determine an object's uniqueness
 
        """
 
        raise NotImplementedError()
 

	
 
    @classmethod
 
    def clear(cls):
 
        # Allow cls.clear() as well as uniqueInstance.clear(cls)
 
        if str(cls) in cls._instances:
 
            del cls._instances[str(cls)]
rhodecode/lib/dbmigrate/migrate/versioning/version.py
Show inline comments
 
@@ -50,25 +50,25 @@ class VerNum(object):
 

	
 

	
 
class Collection(pathed.Pathed):
 
    """A collection of versioning scripts in a repository"""
 

	
 
    FILENAME_WITH_VERSION = re.compile(r'^(\d{3,}).*')
 

	
 
    def __init__(self, path):
 
        """Collect current version scripts in repository
 
        and store them in self.versions
 
        """
 
        super(Collection, self).__init__(path)
 
        
 

	
 
        # Create temporary list of files, allowing skipped version numbers.
 
        files = os.listdir(path)
 
        if '1' in files:
 
            # deprecation
 
            raise Exception('It looks like you have a repository in the old '
 
                'format (with directories for each version). '
 
                'Please convert repository before proceeding.')
 

	
 
        tempVersions = dict()
 
        for filename in files:
 
            match = self.FILENAME_WITH_VERSION.match(filename)
 
            if match:
 
@@ -95,73 +95,73 @@ class Collection(pathed.Pathed):
 

	
 
        if extra:
 
            if extra == '_':
 
                extra = ''
 
            elif not extra.startswith('_'):
 
                extra = '_%s' % extra
 

	
 
        filename = '%03d%s.py' % (ver, extra)
 
        filepath = self._version_path(filename)
 

	
 
        script.PythonScript.create(filepath, **k)
 
        self.versions[ver] = Version(ver, self.path, [filename])
 
        
 

	
 
    def create_new_sql_version(self, database, **k):
 
        """Create SQL files for new version"""
 
        ver = self.latest + 1
 
        self.versions[ver] = Version(ver, self.path, [])
 

	
 
        # Create new files.
 
        for op in ('upgrade', 'downgrade'):
 
            filename = '%03d_%s_%s.sql' % (ver, database, op)
 
            filepath = self._version_path(filename)
 
            script.SqlScript.create(filepath, **k)
 
            self.versions[ver].add_script(filepath)
 
        
 

	
 
    def version(self, vernum=None):
 
        """Returns latest Version if vernum is not given.
 
        Otherwise, returns wanted version"""
 
        if vernum is None:
 
            vernum = self.latest
 
        return self.versions[VerNum(vernum)]
 

	
 
    @classmethod
 
    def clear(cls):
 
        super(Collection, cls).clear()
 

	
 
    def _version_path(self, ver):
 
        """Returns path of file in versions repository"""
 
        return os.path.join(self.path, str(ver))
 

	
 

	
 
class Version(object):
 
    """A single version in a collection
 
    :param vernum: Version Number 
 
    :param vernum: Version Number
 
    :param path: Path to script files
 
    :param filelist: List of scripts
 
    :type vernum: int, VerNum
 
    :type path: string
 
    :type filelist: list
 
    """
 

	
 
    def __init__(self, vernum, path, filelist):
 
        self.version = VerNum(vernum)
 

	
 
        # Collect scripts in this folder
 
        self.sql = dict()
 
        self.python = None
 

	
 
        for script in filelist:
 
            self.add_script(os.path.join(path, script))
 
    
 

	
 
    def script(self, database=None, operation=None):
 
        """Returns SQL or Python Script"""
 
        for db in (database, 'default'):
 
            # Try to return a .sql script first
 
            try:
 
                return self.sql[db][operation]
 
            except KeyError:
 
                continue  # No .sql script exists
 

	
 
        # TODO: maybe add force Python parameter?
 
        ret = self.python
 

	
rhodecode/lib/dbmigrate/versions/002_version_1_1_0.py
Show inline comments
 
@@ -4,60 +4,60 @@ import datetime
 
from sqlalchemy import *
 
from sqlalchemy.exc import DatabaseError
 
from sqlalchemy.orm import relation, backref, class_mapper
 
from sqlalchemy.orm.session import Session
 
from rhodecode.model.meta import Base
 

	
 
from rhodecode.lib.dbmigrate.migrate import *
 
from rhodecode.lib.dbmigrate.migrate.changeset import *
 

	
 
log = logging.getLogger(__name__)
 

	
 
def upgrade(migrate_engine):
 
    """ Upgrade operations go here. 
 
    """ Upgrade operations go here.
 
    Don't create your own engine; bind migrate_engine to your metadata
 
    """
 

	
 
    #==========================================================================
 
    # Upgrade of `users` table
 
    #==========================================================================
 
    tblname = 'users'
 
    tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
 
                    autoload_with=migrate_engine)
 

	
 
    #ADD is_ldap column
 
    is_ldap = Column("is_ldap", Boolean(), nullable=True,
 
                     unique=None, default=False)
 
    is_ldap.create(tbl, populate_default=True)
 
    is_ldap.alter(nullable=False)
 

	
 
    #==========================================================================
 
    # Upgrade of `user_logs` table
 
    #==========================================================================    
 
    #==========================================================================
 

	
 
    tblname = 'users'
 
    tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
 
                    autoload_with=migrate_engine)
 

	
 
    #ADD revision column
 
    revision = Column('revision', TEXT(length=None, convert_unicode=False,
 
                                       assert_unicode=None),
 
                      nullable=True, unique=None, default=None)
 
    revision.create(tbl)
 

	
 

	
 

	
 
    #==========================================================================
 
    # Upgrade of `repositories` table
 
    #==========================================================================    
 
    #==========================================================================
 
    tblname = 'repositories'
 
    tbl = Table(tblname, MetaData(bind=migrate_engine), autoload=True,
 
                    autoload_with=migrate_engine)
 

	
 
    #ADD repo_type column#
 
    repo_type = Column("repo_type", String(length=None, convert_unicode=False,
 
                                           assert_unicode=None),
 
                       nullable=True, unique=False, default='hg')
 

	
 
    repo_type.create(tbl, populate_default=True)
 
    #repo_type.alter(nullable=False)
 

	
 
@@ -75,25 +75,25 @@ def upgrade(migrate_engine):
 
                          UniqueConstraint('user_id', 'follows_user_id')
 
                          , {'useexisting':True})
 

	
 
        user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
        user_id = Column("user_id", Integer(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
 
        follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=None, default=None)
 
        follows_user_id = Column("follows_user_id", Integer(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
 

	
 
        user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
 

	
 
        follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
 
        follows_repository = relation('Repository')
 
        
 

	
 
    UserFollowing().__table__.create()
 

	
 
    #==========================================================================
 
    # Add table `cache_invalidation`
 
    #==========================================================================
 
    class CacheInvalidation(Base, BaseModel):
 
        __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_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
 
@@ -104,14 +104,12 @@ def upgrade(migrate_engine):
 
            self.cache_args = cache_args
 
            self.cache_active = False
 

	
 
        def __repr__(self):
 
            return "<CacheInvalidation('%s:%s')>" % (self.cache_id, self.cache_key)
 
    CacheInvalidation().__table__.create()
 

	
 
    return
 

	
 
def downgrade(migrate_engine):
 
    meta = MetaData()
 
    meta.bind = migrate_engine
 

	
 

	
rhodecode/lib/dbmigrate/versions/003_version_1_2_0.py
Show inline comments
 
@@ -6,25 +6,25 @@ from sqlalchemy.exc import DatabaseError
 
from sqlalchemy.orm import relation, backref, class_mapper
 
from sqlalchemy.orm.session import Session
 

	
 
from rhodecode.lib.dbmigrate.migrate import *
 
from rhodecode.lib.dbmigrate.migrate.changeset import *
 

	
 
from rhodecode.model.meta import Base
 
from rhodecode.model.db import BaseModel
 

	
 
log = logging.getLogger(__name__)
 

	
 
def upgrade(migrate_engine):
 
    """ Upgrade operations go here. 
 
    """ Upgrade operations go here.
 
    Don't create your own engine; bind migrate_engine to your metadata
 
    """
 

	
 
    #==========================================================================
 
    # Add table `groups``
 
    #==========================================================================
 
    from rhodecode.model.db import Group
 
    Group().__table__.create()
 

	
 
    #==========================================================================
 
    # Add table `group_to_perm`
 
    #==========================================================================
 
@@ -60,25 +60,25 @@ def upgrade(migrate_engine):
 
    ldap_dn.create(User().__table__)
 

	
 
    api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    api_key.create(User().__table__)
 

	
 
    #remove old column
 
    is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
 
    is_ldap.drop(User().__table__)
 

	
 

	
 
    #==========================================================================
 
    # Upgrade of `repositories` table
 
    #==========================================================================    
 
    #==========================================================================
 
    from rhodecode.model.db import Repository
 

	
 
    #ADD downloads column#
 
    enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
 
    enable_downloads.create(Repository().__table__)
 

	
 
    #ADD group_id column#
 
    group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'),
 
                  nullable=True, unique=False, default=None)
 

	
 
    group_id.create(Repository().__table__)
 

	
 
@@ -87,14 +87,12 @@ def upgrade(migrate_engine):
 

	
 
    clone_uri = Column("clone_uri", String(length=255, convert_unicode=False,
 
                                           assert_unicode=None),
 
                        nullable=True, unique=False, default=None)
 

	
 
    clone_uri.create(Repository().__table__)
 
    return
 

	
 

	
 
def downgrade(migrate_engine):
 
    meta = MetaData()
 
    meta.bind = migrate_engine
 

	
 

	
rhodecode/lib/dbmigrate/versions/__init__.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.dbmigrate.versions.__init__
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Package containing new versions of database models
 
    
 

	
 
    :created_on: Dec 11, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
rhodecode/lib/exceptions.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# Custom Exceptions modules
 
# 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
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
"""
 
Created on Nov 17, 2010
 
Custom Exceptions modules
 
@author: marcink
 
"""
 

	
 
class LdapUsernameError(Exception):pass
 
class LdapPasswordError(Exception):pass
rhodecode/lib/helpers.py
Show inline comments
 
@@ -60,79 +60,79 @@ def get_token():
 
        try:
 
            token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
 
        except AttributeError: # Python < 2.4
 
            token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
 
        session[token_key] = token
 
        if hasattr(session, 'save'):
 
            session.save()
 
    return session[token_key]
 

	
 
class _GetError(object):
 
    """Get error from form_errors, and represent it as span wrapped error
 
    message
 
    
 

	
 
    :param field_name: field to fetch errors for
 
    :param form_errors: form errors dict
 
    """
 

	
 
    def __call__(self, field_name, form_errors):
 
        tmpl = """<span class="error_msg">%s</span>"""
 
        if form_errors and form_errors.has_key(field_name):
 
            return literal(tmpl % form_errors.get(field_name))
 

	
 
get_error = _GetError()
 

	
 
class _ToolTip(object):
 

	
 
    def __call__(self, tooltip_title, trim_at=50):
 
        """Special function just to wrap our text into nice formatted 
 
        """Special function just to wrap our text into nice formatted
 
        autowrapped text
 
        
 

	
 
        :param tooltip_title:
 
        """
 

	
 
        return wrap_paragraphs(escape(tooltip_title), trim_at)\
 
                       .replace('\n', '<br/>')
 

	
 
    def activate(self):
 
        """Adds tooltip mechanism to the given Html all tooltips have to have 
 
        """Adds tooltip mechanism to the given Html all tooltips have to have
 
        set class `tooltip` and set attribute `tooltip_title`.
 
        Then a tooltip will be generated based on that. All with yui js tooltip
 
        """
 

	
 
        js = '''
 
        YAHOO.util.Event.onDOMReady(function(){
 
            function toolTipsId(){
 
                var ids = [];
 
                var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
 
                
 

	
 
                for (var i = 0; i < tts.length; i++) {
 
                    //if element doesn't not have and id autogenerate one for tooltip
 
                    
 

	
 
                    if (!tts[i].id){
 
                        tts[i].id='tt'+i*100;
 
                    }
 
                    ids.push(tts[i].id);
 
                }
 
                return ids        
 
                return ids
 
            };
 
            var myToolTips = new YAHOO.widget.Tooltip("tooltip", { 
 
            var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
 
                context: [[toolTipsId()],"tl","bl",null,[0,5]],
 
                monitorresize:false,
 
                xyoffset :[0,0],
 
                autodismissdelay:300000,
 
                hidedelay:5,
 
                showdelay:20,
 
            });
 
            
 

	
 
        });
 
        '''
 
        return literal(js)
 

	
 
tooltip = _ToolTip()
 

	
 
class _FilesBreadCrumbs(object):
 

	
 
    def __call__(self, repo_name, rev, paths):
 
        if isinstance(paths, str):
 
            paths = safe_unicode(paths)
 
        url_l = [link_to(repo_name, url('files_home',
 
@@ -219,42 +219,42 @@ class CodeHtmlFormatter(HtmlFormatter):
 
                      '<pre style="line-height: 125%">' +
 
                      ls + '</pre></div></td><td class="code">')
 
        else:
 
            yield 0, ('<table class="%stable">' % self.cssclass +
 
                      '<tr><td class="linenos"><div class="linenodiv"><pre>' +
 
                      ls + '</pre></div></td><td class="code">')
 
        yield 0, dummyoutfile.getvalue()
 
        yield 0, '</td></tr></table>'
 

	
 

	
 
def pygmentize(filenode, **kwargs):
 
    """pygmentize function using pygments
 
    
 

	
 
    :param filenode:
 
    """
 

	
 
    return literal(code_highlight(filenode.content,
 
                                  filenode.lexer, CodeHtmlFormatter(**kwargs)))
 

	
 
def pygmentize_annotation(repo_name, filenode, **kwargs):
 
    """pygmentize function for annotation
 
    
 

	
 
    :param filenode:
 
    """
 

	
 
    color_dict = {}
 
    def gen_color(n=10000):
 
        """generator for getting n of evenly distributed colors using 
 
        """generator for getting n of evenly distributed colors using
 
        hsv color and golden ratio. It always return same order of colors
 
        
 

	
 
        :returns: RGB tuple
 
        """
 
        import colorsys
 
        golden_ratio = 0.618033988749895
 
        h = 0.22717784590367374
 

	
 
        for c in xrange(n):
 
            h += golden_ratio
 
            h %= 1
 
            HSV_tuple = [h, 0.95, 0.95]
 
            RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple)
 
            yield map(lambda x:str(int(x * 256)), RGB_tuple)
 
@@ -347,43 +347,43 @@ def _age(curdate):
 

	
 
age = lambda  x:_age(x)
 
capitalize = lambda x: x.capitalize()
 
email = util.email
 
email_or_none = lambda x: util.email(x) if util.email(x) != x else None
 
person = lambda x: _person(x)
 
short_id = lambda x: x[:12]
 

	
 

	
 
def bool2icon(value):
 
    """Returns True/False values represented as small html image of true/false
 
    icons
 
    
 

	
 
    :param value: bool value
 
    """
 

	
 
    if value is True:
 
        return HTML.tag('img', src=url("/images/icons/accept.png"),
 
                        alt=_('True'))
 

	
 
    if value is False:
 
        return HTML.tag('img', src=url("/images/icons/cancel.png"),
 
                        alt=_('False'))
 

	
 
    return value
 

	
 

	
 
def action_parser(user_log, feed=False):
 
    """This helper will action_map the specified string action into translated
 
    fancy names with icons and links
 
    
 

	
 
    :param user_log: user log instance
 
    :param feed: use output for feeds (no html and fancy icons)
 
    """
 

	
 
    action = user_log.action
 
    action_params = ' '
 

	
 
    x = action.split(':')
 

	
 
    if len(x) > 1:
 
        action, action_params = x
 

	
 
@@ -629,14 +629,12 @@ def changed_tooltip(nodes):
 

	
 

	
 
def repo_link(groups_and_repos):
 
    groups, repo_name = groups_and_repos
 

	
 
    if not groups:
 
        return repo_name
 
    else:
 
        def make_link(group):
 
            return link_to(group.group_name, url('repos_group', id=group.group_id))
 
        return literal(' &raquo; '.join(map(make_link, groups)) + \
 
                       " &raquo; " + repo_name)
 

	
 

	
rhodecode/lib/hooks.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.hooks
 
    ~~~~~~~~~~~~~~~~~~~
 

	
 
    Hooks runned by rhodecode
 
    
 

	
 
    :created_on: Aug 6, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import os
 
import sys
 
import getpass
 

	
 
from mercurial.cmdutil import revrange
 
from mercurial.node import nullrev
 

	
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.utils import action_logger
 

	
 
def repo_size(ui, repo, hooktype=None, **kwargs):
 
    """Presents size of repository after push
 
    
 

	
 
    :param ui:
 
    :param repo:
 
    :param hooktype:
 
    """
 

	
 
    if hooktype != 'changegroup':
 
        return False
 
    size_hg, size_root = 0, 0
 
    for path, dirs, files in os.walk(repo.root):
 
        if path.find('.hg') != -1:
 
            for f in files:
 
                try:
 
@@ -58,41 +58,41 @@ def repo_size(ui, repo, hooktype=None, *
 
                    size_root += os.path.getsize(os.path.join(path, f))
 
                except OSError:
 
                    pass
 

	
 
    size_hg_f = h.format_byte_size(size_hg)
 
    size_root_f = h.format_byte_size(size_root)
 
    size_total_f = h.format_byte_size(size_root + size_hg)
 
    sys.stdout.write('Repository size .hg:%s repo:%s total:%s\n' \
 
                     % (size_hg_f, size_root_f, size_total_f))
 

	
 
def log_pull_action(ui, repo, **kwargs):
 
    """Logs user last pull action
 
    
 

	
 
    :param ui:
 
    :param repo:
 
    """
 

	
 
    extra_params = dict(repo.ui.configitems('rhodecode_extras'))
 
    username = extra_params['username']
 
    repository = extra_params['repository']
 
    action = 'pull'
 

	
 
    action_logger(username, action, repository, extra_params['ip'])
 

	
 
    return 0
 

	
 
def log_push_action(ui, repo, **kwargs):
 
    """Maps user last push action to new changeset id, from mercurial
 
    
 

	
 
    :param ui:
 
    :param repo:
 
    """
 

	
 
    extra_params = dict(repo.ui.configitems('rhodecode_extras'))
 
    username = extra_params['username']
 
    repository = extra_params['repository']
 
    action = extra_params['action'] + ':%s'
 
    node = kwargs['node']
 

	
 
    def get_revs(repo, rev_opt):
 
        if rev_opt:
 
@@ -104,13 +104,12 @@ def log_push_action(ui, repo, **kwargs):
 
        else:
 
            return (len(repo) - 1, 0)
 

	
 
    stop, start = get_revs(repo, [node + ':'])
 

	
 
    revs = (str(repo[r]) for r in xrange(start, stop + 1))
 

	
 
    action = action % ','.join(revs)
 

	
 
    action_logger(username, action, repository, extra_params['ip'])
 

	
 
    return 0
 

	
rhodecode/lib/indexers/__init__.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.indexers.__init__
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Whoosh indexing module for RhodeCode
 
    
 

	
 
    :created_on: Aug 17, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import os
 
import sys
 
import traceback
 
from os.path import dirname as dn, join as jn
 

	
 
#to get the rhodecode import
 
sys.path.append(dn(dn(dn(os.path.realpath(__file__)))))
 

	
rhodecode/lib/middleware/https_fixup.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.middleware.https_fixup
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    middleware to handle https correctly
 
    
 

	
 
    :created_on: May 23, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
from rhodecode.lib import str2bool
 

	
 
class HttpsFixup(object):
 
    def __init__(self, app, config):
 
        self.application = app
 
        self.config = config
 

	
 
    def __call__(self, environ, start_response):
 
        self.__fixup(environ)
 
        return self.application(environ, start_response)
 

	
 

	
 
    def __fixup(self, environ):
 
        """Function to fixup the environ as needed. In order to use this
 
        middleware you should set this header inside your 
 
        middleware you should set this header inside your
 
        proxy ie. nginx, apache etc.
 
        """
 
        proto = environ.get('HTTP_X_URL_SCHEME')
 

	
 
        if str2bool(self.config.get('force_https')):
 
            proto = 'https'
 

	
 
        if proto == 'https':
 
            environ['wsgi.url_scheme'] = proto
 
        else:
 
            environ['wsgi.url_scheme'] = 'http'
 
        return None
rhodecode/lib/middleware/simplegit.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.middleware.simplegit
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    SimpleGit middleware for handling git protocol request (push/clone etc.)
 
    It's implemented with basic auth function    
 
    
 
    It's implemented with basic auth function
 

	
 
    :created_on: Apr 28, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import os
 
import logging
 
import traceback
 

	
 
from dulwich import server as dulserver
 

	
 
class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
 
@@ -69,86 +69,86 @@ from dulwich.web import HTTPGitApplicati
 
from paste.auth.basic import AuthBasicAuthenticator
 
from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 

	
 
from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
 
from rhodecode.lib.utils import invalidate_cache, check_repo_fast
 
from rhodecode.model.user import UserModel
 

	
 
from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
 

	
 
log = logging.getLogger(__name__)
 

	
 
def is_git(environ):
 
    """Returns True if request's target is git server. 
 
    """Returns True if request's target is git server.
 
    ``HTTP_USER_AGENT`` would then have git client version given.
 
    
 

	
 
    :param environ:
 
    """
 
    http_user_agent = environ.get('HTTP_USER_AGENT')
 
    if http_user_agent and http_user_agent.startswith('git'):
 
        return True
 
    return False
 

	
 
class SimpleGit(object):
 

	
 
    def __init__(self, application, config):
 
        self.application = application
 
        self.config = config
 
        #authenticate this git request using 
 
        #authenticate this git request using
 
        self.authenticate = AuthBasicAuthenticator('', authfunc)
 
        self.ipaddr = '0.0.0.0'
 
        self.repository = None
 
        self.username = None
 
        self.action = None
 

	
 
    def __call__(self, environ, start_response):
 
        if not is_git(environ):
 
            return self.application(environ, start_response)
 

	
 
        proxy_key = 'HTTP_X_REAL_IP'
 
        def_key = 'REMOTE_ADDR'
 
        self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
 
        # skip passing error to error controller
 
        environ['pylons.status_code_redirect'] = True
 

	
 
        #======================================================================
 
        # GET ACTION PULL or PUSH
 
        #======================================================================
 
        self.action = self.__get_action(environ)
 
        try:
 
            #==================================================================
 
            # GET REPOSITORY NAME
 
            #==================================================================            
 
            #==================================================================
 
            self.repo_name = self.__get_repository(environ)
 
        except:
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
        #======================================================================
 
        # CHECK ANONYMOUS PERMISSION
 
        #======================================================================
 
        if self.action in ['pull', 'push'] or self.action:
 
            anonymous_user = self.__get_user('default')
 
            self.username = anonymous_user.username
 
            anonymous_perm = self.__check_permission(self.action, anonymous_user ,
 
                                           self.repo_name)
 

	
 
            if anonymous_perm is not True or anonymous_user.active is False:
 
                if anonymous_perm is not True:
 
                    log.debug('Not enough credentials to access this repository'
 
                              'as anonymous user')
 
                if anonymous_user.active is False:
 
                    log.debug('Anonymous access is disabled, running '
 
                              'authentication')
 
                #==============================================================
 
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE 
 
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
 
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
 
                #==============================================================
 

	
 
                if not REMOTE_USER(environ):
 
                    self.authenticate.realm = str(self.config['rhodecode_realm'])
 
                    result = self.authenticate(environ)
 
                    if isinstance(result, str):
 
                        AUTH_TYPE.update(environ, 'basic')
 
                        REMOTE_USER.update(environ, result)
 
                    else:
 
                        return result.wsgi_application(environ, start_response)
 

	
 
@@ -202,68 +202,68 @@ class SimpleGit(object):
 
            return app(environ, start_response)
 

	
 

	
 
    def __make_app(self):
 
        backend = dulserver.DictBackend({'/' + self.repo_name: Repo(self.repo_path)})
 
        gitserve = HTTPGitApplication(backend)
 

	
 
        return gitserve
 

	
 
    def __check_permission(self, action, user, repo_name):
 
        """Checks permissions using action (push/pull) user and repository
 
        name
 
        
 

	
 
        :param action: push or pull action
 
        :param user: user instance
 
        :param repo_name: repository name
 
        """
 
        if action == 'push':
 
            if not HasPermissionAnyMiddleware('repository.write',
 
                                              'repository.admin')\
 
                                                (user, repo_name):
 
                return False
 

	
 
        else:
 
            #any other action need at least read permission
 
            if not HasPermissionAnyMiddleware('repository.read',
 
                                              'repository.write',
 
                                              'repository.admin')\
 
                                                (user, repo_name):
 
                return False
 

	
 
        return True
 

	
 

	
 
    def __get_repository(self, environ):
 
        """Get's repository name out of PATH_INFO header
 
        
 

	
 
        :param environ: environ where PATH_INFO is stored
 
        """
 
        try:
 
            repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
            if repo_name.endswith('/'):
 
                repo_name = repo_name.rstrip('/')
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 
        repo_name = repo_name.split('/')[0]
 
        return repo_name
 

	
 

	
 
    def __get_user(self, username):
 
        return UserModel().get_by_username(username, cache=True)
 

	
 
    def __get_action(self, environ):
 
        """Maps git request commands into a pull or push command.
 
        
 

	
 
        :param environ:
 
        """
 
        service = environ['QUERY_STRING'].split('=')
 
        if len(service) > 1:
 
            service_cmd = service[1]
 
            mapping = {'git-receive-pack': 'push',
 
                       'git-upload-pack': 'pull',
 
                       }
 

	
 
            return mapping.get(service_cmd, service_cmd if service_cmd else 'other')
 
        else:
 
            return 'other'
rhodecode/lib/middleware/simplehg.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.middleware.simplehg
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    SimpleHG middleware for handling mercurial protocol request 
 
    SimpleHG middleware for handling mercurial protocol request
 
    (push/clone etc.). It's implemented with basic auth function
 
    
 

	
 
    :created_on: Apr 28, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import os
 
import logging
 
import traceback
 

	
 
from mercurial.error import RepoError
 
from mercurial.hgweb import hgweb
 
from mercurial.hgweb.request import wsgiapplication
 
@@ -75,47 +75,47 @@ class SimpleHg(object):
 
        def_key = 'REMOTE_ADDR'
 
        self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
 
        # skip passing error to error controller
 
        environ['pylons.status_code_redirect'] = True
 

	
 
        #======================================================================
 
        # GET ACTION PULL or PUSH
 
        #======================================================================
 
        self.action = self.__get_action(environ)
 
        try:
 
            #==================================================================
 
            # GET REPOSITORY NAME
 
            #==================================================================            
 
            #==================================================================
 
            self.repo_name = self.__get_repository(environ)
 
        except:
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
        #======================================================================
 
        # CHECK ANONYMOUS PERMISSION
 
        #======================================================================
 
        if self.action in ['pull', 'push']:
 
            anonymous_user = self.__get_user('default')
 
            self.username = anonymous_user.username
 
            anonymous_perm = self.__check_permission(self.action, anonymous_user ,
 
                                           self.repo_name)
 

	
 
            if anonymous_perm is not True or anonymous_user.active is False:
 
                if anonymous_perm is not True:
 
                    log.debug('Not enough credentials to access this repository'
 
                              'as anonymous user')
 
                if anonymous_user.active is False:
 
                    log.debug('Anonymous access is disabled, running '
 
                              'authentication')
 
                #==============================================================
 
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE 
 
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
 
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
 
                #==============================================================
 

	
 
                if not REMOTE_USER(environ):
 
                    self.authenticate.realm = str(self.config['rhodecode_realm'])
 
                    result = self.authenticate(environ)
 
                    if isinstance(result, str):
 
                        AUTH_TYPE.update(environ, 'basic')
 
                        REMOTE_USER.update(environ, result)
 
                    else:
 
                        return result.wsgi_application(environ, start_response)
 

	
 
@@ -174,68 +174,68 @@ class SimpleHg(object):
 
    def __make_app(self):
 
        """Make an wsgi application using hgweb, and my generated baseui
 
        instance
 
        """
 

	
 
        hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
 
        return  self.__load_web_settings(hgserve, self.extras)
 

	
 

	
 
    def __check_permission(self, action, user, repo_name):
 
        """Checks permissions using action (push/pull) user and repository
 
        name
 
        
 

	
 
        :param action: push or pull action
 
        :param user: user instance
 
        :param repo_name: repository name
 
        """
 
        if action == 'push':
 
            if not HasPermissionAnyMiddleware('repository.write',
 
                                              'repository.admin')\
 
                                                (user, repo_name):
 
                return False
 

	
 
        else:
 
            #any other action need at least read permission
 
            if not HasPermissionAnyMiddleware('repository.read',
 
                                              'repository.write',
 
                                              'repository.admin')\
 
                                                (user, repo_name):
 
                return False
 

	
 
        return True
 

	
 

	
 
    def __get_repository(self, environ):
 
        """Get's repository name out of PATH_INFO header
 
        
 

	
 
        :param environ: environ where PATH_INFO is stored
 
        """
 
        try:
 
            repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
            if repo_name.endswith('/'):
 
                repo_name = repo_name.rstrip('/')
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
        return repo_name
 

	
 
    def __get_user(self, username):
 
        return UserModel().get_by_username(username, cache=True)
 

	
 
    def __get_action(self, environ):
 
        """Maps mercurial request commands into a clone,pull or push command.
 
        This should always return a valid command string
 
        
 

	
 
        :param environ:
 
        """
 
        mapping = {'changegroup': 'pull',
 
                   'changegroupsubset': 'pull',
 
                   'stream_out': 'pull',
 
                   'listkeys': 'pull',
 
                   'unbundle': 'push',
 
                   'pushkey': 'push', }
 
        for qry in environ['QUERY_STRING'].split('&'):
 
            if qry.startswith('cmd'):
 
                cmd = qry.split('=')[-1]
 
                if mapping.has_key(cmd):
rhodecode/lib/profiler.py
Show inline comments
 
@@ -3,26 +3,26 @@ from __future__ import with_statement
 
import cProfile
 
import pstats
 
import cgi
 
import pprint
 
import threading
 

	
 
from StringIO import StringIO
 

	
 
class ProfilingMiddleware(object):
 
    def __init__(self, app):
 
        self.lock = threading.Lock()
 
        self.app = app
 
    
 
    
 

	
 

	
 
    def __call__(self, environ, start_response):
 
        with self.lock:
 
            profiler = cProfile.Profile()
 
            def run_app(*a, **kw):
 
                self.response = self.app(environ, start_response)
 

	
 
            profiler.runcall(run_app, environ, start_response)
 

	
 
            profiler.snapshot_stats()
 

	
 
            stats = pstats.Stats(profiler)
 
            stats.sort_stats('cumulative')
 
@@ -32,22 +32,20 @@ class ProfilingMiddleware(object):
 
            stats.stream = out
 

	
 
            stats.print_stats()
 

	
 
            resp = ''.join(self.response)
 

	
 
            # Lets at least only put this on html-like responses.
 
            if resp.strip().startswith('<'):
 
                ## The profiling info is just appended to the response.
 
                ##  Browsers don't mind this.
 
                resp += '<pre style="text-align:left; border-top: 4px dashed red; padding: 1em;">'
 
                resp += cgi.escape(out.getvalue(), True)
 
                
 

	
 
                output = StringIO()
 
                pprint.pprint(environ, output, depth=3)
 
                
 

	
 
                resp += cgi.escape(output.getvalue(), True)
 
                resp += '</pre>'
 
                
 

	
 
            return resp
 
    
 

	
rhodecode/lib/smtp_mailer.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.smtp_mailer
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~
 
    
 

	
 
    Simple smtp mailer used in RhodeCode
 
    
 

	
 
    :created_on: Sep 13, 2010
 
    :copyright: (c) 2011 by marcink.
 
    :license: LICENSE_NAME, see LICENSE_FILE for more details.
 
"""
 

	
 
import logging
 
import smtplib
 
import mimetypes
 
from socket import sslerror
 

	
 
from email.mime.multipart import MIMEMultipart
 
from email.mime.image import MIMEImage
 
from email.mime.audio import MIMEAudio
 
from email.mime.base import MIMEBase
 
from email.mime.text import MIMEText
 
from email.utils import formatdate
 
from email import encoders
 

	
 
class SmtpMailer(object):
 
    """SMTP mailer class
 
    
 

	
 
    mailer = SmtpMailer(mail_from, user, passwd, mail_server, mail_port, ssl, tls)
 
    mailer.send(recipients, subject, body, attachment_files)    
 
    
 
    mailer.send(recipients, subject, body, attachment_files)
 

	
 
    :param recipients might be a list of string or single string
 
    :param attachment_files is a dict of {filename:location} 
 
        it tries to guess the mimetype and attach the file 
 
    
 
    :param attachment_files is a dict of {filename:location}
 
        it tries to guess the mimetype and attach the file
 

	
 
    """
 

	
 
    def __init__(self, mail_from, user, passwd, mail_server,
 
                    mail_port=None, ssl=False, tls=False, debug=False):
 

	
 
        self.mail_from = mail_from
 
        self.mail_server = mail_server
 
        self.mail_port = mail_port
 
        self.user = user
 
        self.passwd = passwd
 
        self.ssl = ssl
 
        self.tls = tls
 
@@ -123,21 +123,21 @@ class SmtpMailer(object):
 
                # Set the filename parameter
 
                file_part.add_header('Content-Disposition', 'attachment',
 
                                     filename=f_name)
 
                file_part.add_header('Content-Type', ctype, name=f_name)
 
                msg.attach(file_part)
 
        else:
 
            raise Exception('Attachment files should be'
 
                            'a dict in format {"filename":"filepath"}')
 

	
 
    def get_content(self, msg_file):
 
        """Get content based on type, if content is a string do open first
 
        else just read because it's a probably open file object
 
        
 

	
 
        :param msg_file:
 
        """
 
        if isinstance(msg_file, str):
 
            return open(msg_file, "rb").read()
 
        else:
 
            #just for safe seek to 0
 
            msg_file.seek(0)
 
            return msg_file.read()
rhodecode/lib/utils.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.utils
 
    ~~~~~~~~~~~~~~~~~~~
 

	
 
    Utilities library for RhodeCode
 
    
 

	
 
    :created_on: Apr 18, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import os
 
import logging
 
import datetime
 
import traceback
 
import paste
 
import beaker
 

	
 
@@ -46,28 +46,28 @@ from vcs.utils.lazy import LazyProperty
 

	
 
from rhodecode.model import meta
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog, Group
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.user import UserModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def recursive_replace(str, replace=' '):
 
    """Recursive replace of given sign to just one instance
 
    
 

	
 
    :param str: given string
 
    :param replace: char to find and replace multiple instances
 
        
 

	
 
    Examples::
 
    >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
 
    'Mighty-Mighty-Bo-sstones'
 
    """
 

	
 
    if str.find(replace * 2) == -1:
 
        return str
 
    else:
 
        str = str.replace(replace * 2, replace)
 
        return recursive_replace(str, replace)
 

	
 
def repo_name_slug(value):
 
@@ -82,34 +82,34 @@ def repo_name_slug(value):
 
    for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
 
        slug = slug.replace(c, '-')
 
    slug = recursive_replace(slug, '-')
 
    slug = collapse(slug, '-')
 
    return slug
 

	
 
def get_repo_slug(request):
 
    return request.environ['pylons.routes_dict'].get('repo_name')
 

	
 
def action_logger(user, action, repo, ipaddr='', sa=None):
 
    """
 
    Action logger for various actions made by users
 
    
 

	
 
    :param user: user that made this action, can be a unique username string or
 
        object containing user_id attribute
 
    :param action: action to log, should be on of predefined unique actions for
 
        easy translations
 
    :param repo: string name of repository or object containing repo_id,
 
        that action was made on
 
    :param ipaddr: optional ip address from what the action was made
 
    :param sa: optional sqlalchemy session
 
    
 

	
 
    """
 

	
 
    if not sa:
 
        sa = meta.Session()
 

	
 
    try:
 
        um = UserModel()
 
        if hasattr(user, 'user_id'):
 
            user_obj = user
 
        elif isinstance(user, basestring):
 
            user_obj = um.get_by_username(user, cache=False)
 
        else:
 
@@ -137,28 +137,28 @@ def action_logger(user, action, repo, ip
 
        user_log.action_date = datetime.datetime.now()
 
        user_log.user_ip = ipaddr
 
        sa.add(user_log)
 
        sa.commit()
 

	
 
        log.info('Adding user %s, action %s on %s', user_obj, action, repo)
 
    except:
 
        log.error(traceback.format_exc())
 
        sa.rollback()
 

	
 
def get_repos(path, recursive=False):
 
    """
 
    Scans given path for repos and return (name,(type,path)) tuple 
 
    
 
    Scans given path for repos and return (name,(type,path)) tuple
 

	
 
    :param path: path to scann for repositories
 
    :param recursive: recursive search and return names with subdirs in front 
 
    :param recursive: recursive search and return names with subdirs in front
 
    """
 
    from vcs.utils.helpers import get_scm
 
    from vcs.exceptions import VCSError
 

	
 
    if path.endswith('/'):
 
        #add ending slash for better results
 
        path = path[:-1]
 

	
 
    def _get_repos(p):
 
        for dirpath in os.listdir(p):
 
            if os.path.isfile(os.path.join(p, dirpath)):
 
                continue
 
@@ -173,25 +173,25 @@ def get_repos(path, recursive=False):
 
                rec_path = os.path.join(p, dirpath)
 
                if os.path.isdir(rec_path):
 
                    for inner_scm in _get_repos(rec_path):
 
                        yield inner_scm
 

	
 
    return _get_repos(path)
 

	
 
def check_repo_fast(repo_name, base_path):
 
    """
 
    Check given path for existence of directory
 
    :param repo_name:
 
    :param base_path:
 
    
 

	
 
    :return False: if this directory is present
 
    """
 
    if os.path.isdir(os.path.join(base_path, repo_name)):return False
 
    return True
 

	
 
def check_repo(repo_name, base_path, verify=True):
 

	
 
    repo_path = os.path.join(base_path, repo_name)
 

	
 
    try:
 
        if not check_repo_fast(repo_name, base_path):
 
            return False
 
@@ -221,25 +221,25 @@ ui_sections = ['alias', 'auth',
 
                'diff', 'email',
 
                'extensions', 'format',
 
                'merge-patterns', 'merge-tools',
 
                'hooks', 'http_proxy',
 
                'smtp', 'patch',
 
                'paths', 'profiling',
 
                'server', 'trusted',
 
                'ui', 'web', ]
 

	
 
def make_ui(read_from='file', path=None, checkpaths=True):
 
    """A function that will read python rc files or database
 
    and make an mercurial ui object from read options
 
    
 

	
 
    :param path: path to mercurial config file
 
    :param checkpaths: check the path
 
    :param read_from: read from 'file' or 'db'
 
    """
 

	
 
    baseui = ui.ui()
 

	
 
    #clean the baseui object
 
    baseui._ocfg = config.config()
 
    baseui._ucfg = config.config()
 
    baseui._tcfg = config.config()
 

	
 
@@ -266,35 +266,35 @@ def make_ui(read_from='file', path=None,
 
        for ui_ in hg_ui:
 
            if ui_.ui_active:
 
                log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
 
                          ui_.ui_key, ui_.ui_value)
 
                baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
 

	
 
        meta.Session.remove()
 
    return baseui
 

	
 

	
 
def set_rhodecode_config(config):
 
    """Updates pylons config with new settings from database
 
    
 

	
 
    :param config:
 
    """
 
    from rhodecode.model.settings import SettingsModel
 
    hgsettings = SettingsModel().get_app_settings()
 

	
 
    for k, v in hgsettings.items():
 
        config[k] = v
 

	
 
def invalidate_cache(cache_key, *args):
 
    """Puts cache invalidation task into db for 
 
    """Puts cache invalidation task into db for
 
    further global cache invalidation
 
    """
 

	
 
    from rhodecode.model.scm import ScmModel
 

	
 
    if cache_key.startswith('get_repo_cached_'):
 
        name = cache_key.split('get_repo_cached_')[-1]
 
        ScmModel().mark_for_invalidation(name)
 

	
 
class EmptyChangeset(BaseChangeset):
 
    """
 
    An dummy empty changeset. It's possible to pass hash when creating
 
@@ -323,48 +323,48 @@ class EmptyChangeset(BaseChangeset):
 
    def get_file_changeset(self, path):
 
        return self
 

	
 
    def get_file_content(self, path):
 
        return u''
 

	
 
    def get_file_size(self, path):
 
        return 0
 

	
 
def map_groups(groups):
 
    """Checks for groups existence, and creates groups structures.
 
    It returns last group in structure
 
    
 

	
 
    :param groups: list of groups structure
 
    """
 
    sa = meta.Session()
 

	
 
    parent = None
 
    group = None
 
    for lvl, group_name in enumerate(groups[:-1]):
 
        group = sa.query(Group).filter(Group.group_name == group_name).scalar()
 

	
 
        if group is None:
 
            group = Group(group_name, parent)
 
            sa.add(group)
 
            sa.commit()
 

	
 
        parent = group
 

	
 
    return group
 

	
 
def repo2db_mapper(initial_repo_list, remove_obsolete=False):
 
    """maps all repos given in initial_repo_list, non existing repositories
 
    are created, if remove_obsolete is True it also check for db entries
 
    that are not in initial_repo_list and removes them.
 
    
 

	
 
    :param initial_repo_list: list of repositories found by scanning methods
 
    :param remove_obsolete: check for obsolete entries in database
 
    """
 

	
 
    sa = meta.Session()
 
    rm = RepoModel()
 
    user = sa.query(User).filter(User.admin == True).first()
 
    added = []
 
    for name, repo in initial_repo_list.items():
 
        group = map_groups(name.split('/'))
 
        if not rm.get_by_repo_name(name, cache=False):
 
            log.info('repository %s not found creating default', name)
 
@@ -553,25 +553,25 @@ def create_test_index(repo_location, ful
 
        shutil.rmtree(index_location)
 

	
 
    try:
 
        l = DaemonLock()
 
        WhooshIndexingDaemon(index_location=index_location,
 
                             repo_location=repo_location)\
 
            .run(full_index=full_index)
 
        l.release()
 
    except LockHeld:
 
        pass
 

	
 
def create_test_env(repos_test_path, config):
 
    """Makes a fresh database and 
 
    """Makes a fresh database and
 
    install test repository into tmp dir
 
    """
 
    from rhodecode.lib.db_manage import DbManage
 
    from rhodecode.tests import HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, \
 
        HG_FORK, GIT_FORK, TESTS_TMP_PATH
 
    import tarfile
 
    import shutil
 
    from os.path import dirname as dn, join as jn, abspath
 

	
 
    log = logging.getLogger('TestEnvCreator')
 
    # create logger
 
    log.setLevel(logging.DEBUG)
 
@@ -632,37 +632,37 @@ class BasePasterCommand(Command):
 
    environment variable to our loader, we have to bootstrap a bit and
 
    make sure we've had a chance to load the pylons config off of the
 
    command line, otherwise everything fails.
 
    """
 
    min_args = 1
 
    min_args_error = "Please provide a paster config file as an argument."
 
    takes_config_file = 1
 
    requires_config_file = True
 

	
 
    def notify_msg(self, msg, log=False):
 
        """Make a notification to user, additionally if logger is passed
 
        it logs this action using given logger
 
        
 

	
 
        :param msg: message that will be printed to user
 
        :param log: logging instance, to use to additionally log this message
 
        
 

	
 
        """
 
        if log and isinstance(log, logging):
 
            log(msg)
 

	
 

	
 
    def run(self, args):
 
        """
 
        Overrides Command.run
 
        
 

	
 
        Checks for a config file argument and loads it.
 
        """
 
        if len(args) < self.min_args:
 
            raise BadCommand(
 
                self.min_args_error % {'min_args': self.min_args,
 
                                       'actual_args': len(args)})
 

	
 
        # Decrement because we're going to lob off the first argument.
 
        # @@ This is hacky
 
        self.min_args -= 1
 
        self.bootstrap_config(args[0])
 
        self.update_parser()
rhodecode/model/__init__.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.__init__
 
    ~~~~~~~~~~~~~~~~~~~~~~~~
 
    
 

	
 
    The application's model objects
 
    
 

	
 
    :created_on: Nov 25, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>    
 
    :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
    
 
    
 

	
 

	
 
    :example:
 
    
 

	
 
        .. code-block:: python
 
    
 

	
 
           from paste.deploy import appconfig
 
           from pylons import config
 
           from sqlalchemy import engine_from_config
 
           from rhodecode.config.environment import load_environment
 
           
 

	
 
           conf = appconfig('config:development.ini', relative_to = './../../')
 
           load_environment(conf.global_conf, conf.local_conf)
 
           
 

	
 
           engine = engine_from_config(config, 'sqlalchemy.')
 
           init_model(engine)
 
           # RUN YOUR CODE HERE
 
    
 

	
 
"""
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 

	
 
from rhodecode.model import meta
 

	
 
log = logging.getLogger(__name__)
 

	
 
def init_model(engine):
 
    """Initializes db session, bind the engine with the metadata,
 
    Call this before using any of the tables or classes in the model, preferably
 
    once in application start
 
    
 

	
 
    :param engine: engine to bind to
 
    """
 
    log.info("initializing db for %s", engine)
 
    meta.Base.metadata.bind = engine
 

	
 
class BaseModel(object):
 
    """Base Model for all RhodeCode models, it adds sql alchemy session
 
    into instance of model
 
    
 

	
 
    :param sa: If passed it reuses this session instead of creating a new one
 
    """
 

	
 
    def __init__(self, sa=None):
 
        if sa is not None:
 
            self.sa = sa
 
        else:
 
            self.sa = meta.Session()
rhodecode/model/caching_query.py
Show inline comments
 
@@ -2,85 +2,85 @@
 

	
 
Represent persistence structures which allow the usage of
 
Beaker caching with SQLAlchemy.
 

	
 
The three new concepts introduced here are:
 

	
 
 * CachingQuery - a Query subclass that caches and
 
   retrieves results in/from Beaker.
 
 * FromCache - a query option that establishes caching
 
   parameters on a Query
 
 * RelationshipCache - a variant of FromCache which is specific
 
   to a query invoked during a lazy load.
 
 * _params_from_query - extracts value parameters from 
 
 * _params_from_query - extracts value parameters from
 
   a Query.
 

	
 
The rest of what's here are standard SQLAlchemy and
 
Beaker constructs.
 
   
 

	
 
"""
 
from beaker.exceptions import BeakerException
 
from sqlalchemy.orm.interfaces import MapperOption
 
from sqlalchemy.orm.query import Query
 
from sqlalchemy.sql import visitors
 
import beaker
 

	
 
class CachingQuery(Query):
 
    """A Query subclass which optionally loads full results from a Beaker 
 
    """A Query subclass which optionally loads full results from a Beaker
 
    cache region.
 
    
 

	
 
    The CachingQuery stores additional state that allows it to consult
 
    a Beaker cache before accessing the database:
 
    
 
    * A "region", which is a cache region argument passed to a 
 

	
 
    * A "region", which is a cache region argument passed to a
 
      Beaker CacheManager, specifies a particular cache configuration
 
      (including backend implementation, expiration times, etc.)
 
    * A "namespace", which is a qualifying name that identifies a
 
      group of keys within the cache.  A query that filters on a name 
 
      might use the name "by_name", a query that filters on a date range 
 
      group of keys within the cache.  A query that filters on a name
 
      might use the name "by_name", a query that filters on a date range
 
      to a joined table might use the name "related_date_range".
 
      
 

	
 
    When the above state is present, a Beaker cache is retrieved.
 
    
 
    The "namespace" name is first concatenated with 
 
    a string composed of the individual entities and columns the Query 
 

	
 
    The "namespace" name is first concatenated with
 
    a string composed of the individual entities and columns the Query
 
    requests, i.e. such as ``Query(User.id, User.name)``.
 
    
 

	
 
    The Beaker cache is then loaded from the cache manager based
 
    on the region and composed namespace.  The key within the cache
 
    itself is then constructed against the bind parameters specified
 
    by this query, which are usually literals defined in the 
 
    by this query, which are usually literals defined in the
 
    WHERE clause.
 

	
 
    The FromCache and RelationshipCache mapper options below represent
 
    the "public" method of configuring this state upon the CachingQuery.
 

	
 
    """
 

	
 
    def __init__(self, manager, *args, **kw):
 
        self.cache_manager = manager
 
        Query.__init__(self, *args, **kw)
 

	
 
    def __iter__(self):
 
        """override __iter__ to pull results from Beaker
 
           if particular attributes have been configured.
 
           
 

	
 
           Note that this approach does *not* detach the loaded objects from
 
           the current session. If the cache backend is an in-process cache
 
           (like "memory") and lives beyond the scope of the current session's
 
           transaction, those objects may be expired. The method here can be
 
           modified to first expunge() each loaded item from the current
 
           session before returning the list of items, so that the items
 
           in the cache are not the same ones in the current Session.
 
           
 

	
 
        """
 
        if hasattr(self, '_cache_parameters'):
 
            return self.get_value(createfunc=lambda: list(Query.__iter__(self)))
 
        else:
 
            return Query.__iter__(self)
 

	
 
    def invalidate(self):
 
        """Invalidate the value represented by this Query."""
 

	
 
        cache, cache_key = _get_cache_parameters(self)
 
        cache.remove(cache_key)
 

	
 
@@ -134,25 +134,25 @@ def _get_cache_parameters(query):
 
        cache_key = " ".join([str(x) for x in args])
 

	
 
    # get cache
 
    #cache = query.cache_manager.get_cache_region(namespace, region)
 
    cache = get_cache_region(namespace, region)
 
    # optional - hash the cache_key too for consistent length
 
    # import uuid
 
    # cache_key= str(uuid.uuid5(uuid.NAMESPACE_DNS, cache_key))
 

	
 
    return cache, cache_key
 

	
 
def _namespace_from_query(namespace, query):
 
    # cache namespace - the token handed in by the 
 
    # cache namespace - the token handed in by the
 
    # option + class we're querying against
 
    namespace = " ".join([namespace] + [str(x) for x in query._entities])
 

	
 
    # memcached wants this
 
    namespace = namespace.replace(' ', '_')
 

	
 
    return namespace
 

	
 
def _set_cache_parameters(query, region, namespace, cache_key):
 

	
 
    if hasattr(query, '_cache_parameters'):
 
        region, namespace, cache_key = query._cache_parameters
 
@@ -160,68 +160,68 @@ def _set_cache_parameters(query, region,
 
                        "for region %r namespace %r" %
 
                        (region, namespace)
 
                    )
 
    query._cache_parameters = region, namespace, cache_key
 

	
 
class FromCache(MapperOption):
 
    """Specifies that a Query should load results from a cache."""
 

	
 
    propagate_to_loaders = False
 

	
 
    def __init__(self, region, namespace, cache_key=None):
 
        """Construct a new FromCache.
 
        
 

	
 
        :param region: the cache region.  Should be a
 
        region configured in the Beaker CacheManager.
 
        
 

	
 
        :param namespace: the cache namespace.  Should
 
        be a name uniquely describing the target Query's
 
        lexical structure.
 
        
 
        :param cache_key: optional.  A string cache key 
 

	
 
        :param cache_key: optional.  A string cache key
 
        that will serve as the key to the query.   Use this
 
        if your query has a huge amount of parameters (such
 
        as when using in_()) which correspond more simply to 
 
        as when using in_()) which correspond more simply to
 
        some other identifier.
 

	
 
        """
 
        self.region = region
 
        self.namespace = namespace
 
        self.cache_key = cache_key
 

	
 
    def process_query(self, query):
 
        """Process a Query during normal loading operation."""
 

	
 
        _set_cache_parameters(query, self.region, self.namespace, self.cache_key)
 

	
 
class RelationshipCache(MapperOption):
 
    """Specifies that a Query as called within a "lazy load" 
 
    """Specifies that a Query as called within a "lazy load"
 
       should load results from a cache."""
 

	
 
    propagate_to_loaders = True
 

	
 
    def __init__(self, region, namespace, attribute):
 
        """Construct a new RelationshipCache.
 
        
 

	
 
        :param region: the cache region.  Should be a
 
        region configured in the Beaker CacheManager.
 
        
 

	
 
        :param namespace: the cache namespace.  Should
 
        be a name uniquely describing the target Query's
 
        lexical structure.
 
        
 

	
 
        :param attribute: A Class.attribute which
 
        indicates a particular class relationship() whose
 
        lazy loader should be pulled from the cache.
 
        
 

	
 
        """
 
        self.region = region
 
        self.namespace = namespace
 
        self._relationship_options = {
 
            (attribute.property.parent.class_, attribute.property.key) : self
 
        }
 

	
 
    def process_query_conditionally(self, query):
 
        """Process a Query that is used within a lazy loader.
 

	
 
        (the process_query_conditionally() method is a SQLAlchemy
 
        hook invoked only within lazyload.)
 
@@ -232,42 +232,42 @@ class RelationshipCache(MapperOption):
 

	
 
            for cls in mapper.class_.__mro__:
 
                if (cls, key) in self._relationship_options:
 
                    relationship_option = self._relationship_options[(cls, key)]
 
                    _set_cache_parameters(
 
                            query,
 
                            relationship_option.region,
 
                            relationship_option.namespace,
 
                            None)
 

	
 
    def and_(self, option):
 
        """Chain another RelationshipCache option to this one.
 
        
 

	
 
        While many RelationshipCache objects can be specified on a single
 
        Query separately, chaining them together allows for a more efficient
 
        lookup during load.
 
        
 

	
 
        """
 
        self._relationship_options.update(option._relationship_options)
 
        return self
 

	
 

	
 
def _params_from_query(query):
 
    """Pull the bind parameter values from a query.
 
    
 

	
 
    This takes into account any scalar attribute bindparam set up.
 
    
 

	
 
    E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
 
    would return [5, 7].
 
    
 

	
 
    """
 
    v = []
 
    def visit_bindparam(bind):
 
        value = query._params.get(bind.key, bind.value)
 

	
 
        # lazyloader may dig a callable in here, intended
 
        # to late-evaluate params after autoflush is called.
 
        # convert to a scalar value.
 
        if callable(value):
 
            value = value()
 

	
 
        v.append(value)
rhodecode/model/db.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.db
 
    ~~~~~~~~~~~~~~~~~~
 
    
 

	
 
    Database Models for RhodeCode
 
    
 

	
 
    :created_on: Apr 08, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import os
 
import logging
 
import datetime
 
from datetime import date
 

	
 
from sqlalchemy import *
 
from sqlalchemy.exc import DatabaseError
 
@@ -378,13 +378,12 @@ class CacheInvalidation(Base):
 
        self.cache_active = False
 

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

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

	
rhodecode/model/forms.py
Show inline comments
 
""" this is forms validation classes
 
http://formencode.org/module-formencode.validators.html
 
for list off all availible validators
 

	
 
we can create our own validators
 

	
 
The table below outlines the options which can be used in a schema in addition to the validators themselves
 
pre_validators          []     These validators will be applied before the schema
 
chained_validators      []     These validators will be applied after the schema
 
allow_extra_fields      False     If True, then it is not an error when keys that aren't associated with a validator are present
 
filter_extra_fields     False     If True, then keys that aren't associated with a validator are removed
 
if_key_missing          NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
 
ignore_key_missing      False     If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already    
 
  
 
  
 
ignore_key_missing      False     If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
 

	
 

	
 
<name> = formencode.validators.<name of validator>
 
<name> must equal form name
 
list=[1,2,3,4,5]
 
for SELECT use formencode.All(OneOf(list), Int())
 
    
 

	
 
"""
 
import os
 
import re
 
import logging
 

	
 
import formencode
 
from formencode import All
 
from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
 
    Email, Bool, StringBoolean, Set
 

	
 
from pylons.i18n.translation import _
 
from webhelpers.pylonslib.secure_form import authentication_token
 
@@ -352,25 +352,25 @@ class AttrLoginValidator(formencode.vali
 
    def to_python(self, value, state):
 

	
 
        if not value or not isinstance(value, (str, unicode)):
 
            raise formencode.Invalid(_("The LDAP Login attribute of the CN "
 
                                       "must be specified - this is the name "
 
                                       "of the attribute that is equivalent "
 
                                       "to 'username'"),
 
                                     value, state)
 

	
 
        return value
 

	
 
#===============================================================================
 
# FORMS        
 
# FORMS
 
#===============================================================================
 
class LoginForm(formencode.Schema):
 
    allow_extra_fields = True
 
    filter_extra_fields = True
 
    username = UnicodeString(
 
                             strip=True,
 
                             min=1,
 
                             not_empty=True,
 
                             messages={
 
                                       'empty':_('Please enter a login'),
 
                                       'tooShort':_('Enter a value %(min)i characters long or more')}
 
                            )
rhodecode/model/meta.py
Show inline comments
 
@@ -12,43 +12,43 @@ cache_manager = cache.CacheManager()
 
__all__ = ['Base', 'Session']
 
#
 
# SQLAlchemy session manager. Updated by model.init_model()
 
#
 
Session = scoped_session(
 
                sessionmaker(
 
                    query_cls=caching_query.query_callable(cache_manager)
 
                )
 
          )
 

	
 
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 
 
        """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 
 
        """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:
rhodecode/model/permission.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.permission
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    permissions model for RhodeCode
 
    
 

	
 
    :created_on: Aug 20, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import traceback
 

	
 
from sqlalchemy.exc import DatabaseError
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import User, Permission, UserToPerm, RepoToPerm
 
from rhodecode.model.caching_query import FromCache
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PermissionModel(BaseModel):
 
    """Permissions model for RhodeCode
 
    """
 

	
 
    def get_permission(self, permission_id, cache=False):
 
        """Get's permissions by id
 
        
 

	
 
        :param permission_id: id of permission to get from database
 
        :param cache: use Cache for this query
 
        """
 
        perm = self.sa.query(Permission)
 
        if cache:
 
            perm = perm.options(FromCache("sql_cache_short",
 
                                          "get_permission_%s" % permission_id))
 
        return perm.get(permission_id)
 

	
 
    def get_permission_by_name(self, name, cache=False):
 
        """Get's permissions by given name
 
        
 

	
 
        :param name: name to fetch
 
        :param cache: Use cache for this query
 
        """
 
        perm = self.sa.query(Permission)\
 
            .filter(Permission.permission_name == name)
 
        if cache:
 
            perm = perm.options(FromCache("sql_cache_short",
 
                                          "get_permission_%s" % name))
 
        return perm.scalar()
 

	
 
    def update(self, form_result):
 
        perm_user = self.sa.query(User)\
 
                .filter(User.username == form_result['perm_user_name']).scalar()
 
        u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == perm_user).all()
 
        if len(u2p) != 3:
 
            raise Exception('Defined: %s should be 3  permissions for default'
 
                            ' user. This should not happen please verify'
 
                            ' your database' % len(u2p))
 

	
 
        try:
 
            #stage 1 change defaults    
 
            #stage 1 change defaults
 
            for p in u2p:
 
                if p.permission.permission_name.startswith('repository.'):
 
                    p.permission = self.get_permission_by_name(
 
                                       form_result['default_perm'])
 
                    self.sa.add(p)
 

	
 
                if p.permission.permission_name.startswith('hg.register.'):
 
                    p.permission = self.get_permission_by_name(
 
                                       form_result['default_register'])
 
                    self.sa.add(p)
 

	
 
                if p.permission.permission_name.startswith('hg.create.'):
rhodecode/model/repo.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.repo
 
    ~~~~~~~~~~~~~~~~~~~~
 

	
 
    Repository model for rhodecode
 
    
 

	
 
    :created_on: Jun 5, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import os
 
import shutil
 
import logging
 
import traceback
 
from datetime import datetime
 

	
 
from sqlalchemy.orm import joinedload, make_transient
 

	
 
@@ -295,59 +295,59 @@ class RepoModel(BaseModel):
 
                .filter(Statistics.repository == \
 
                        self.get_by_repo_name(repo_name)).delete()
 
            self.sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 

	
 
    def __create_repo(self, repo_name, alias, clone_uri=False):
 
        """
 
        makes repository on filesystem
 
        
 

	
 
        :param repo_name:
 
        :param alias:
 
        """
 
        from rhodecode.lib.utils import check_repo
 
        repo_path = os.path.join(self.repos_path, repo_name)
 
        if check_repo(repo_name, self.repos_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):
 
        """
 
        renames repository on filesystem
 
        
 

	
 
        :param old: old name
 
        :param new: new name
 
        """
 
        log.info('renaming repo from %s to %s', old, new)
 

	
 
        old_path = os.path.join(self.repos_path, old)
 
        new_path = os.path.join(self.repos_path, new)
 
        if os.path.isdir(new_path):
 
            raise Exception('Was trying to rename to already existing dir %s',
 
                            new_path)
 
        shutil.move(old_path, new_path)
 

	
 
    def __delete_repo(self, repo):
 
        """
 
        removes repo from filesystem, the removal is acctually made by
 
        added rm__ prefix into dir, and rename internat .hg/.git dirs so this
 
        repository is no longer valid for rhodecode, can be undeleted later on
 
        by reverting the renames on this repository
 
        
 

	
 
        :param repo: repo object
 
        """
 
        rm_path = os.path.join(self.repos_path, repo.repo_name)
 
        log.info("Removing %s", rm_path)
 
        #disable hg/git
 
        alias = repo.repo_type
 
        shutil.move(os.path.join(rm_path, '.%s' % alias),
 
                    os.path.join(rm_path, 'rm__.%s' % alias))
 
        #disable repo
 
        shutil.move(rm_path, os.path.join(self.repos_path, 'rm__%s__%s' \
 
                                          % (datetime.today()\
 
                                             .strftime('%Y%m%d_%H%M%S_%f'),
rhodecode/model/scm.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.scm
 
    ~~~~~~~~~~~~~~~~~~~
 

	
 
    Scm model for RhodeCode
 

	
 
    :created_on: Apr 9, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import os
 
import time
 
import traceback
 
import logging
 

	
 
from mercurial import ui
 

	
 
from sqlalchemy.exc import DatabaseError
 
@@ -75,27 +75,27 @@ class ScmModel(BaseModel):
 
    """
 

	
 
    @LazyProperty
 
    def repos_path(self):
 
        """Get's the repositories root path from database
 
        """
 

	
 
        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
 

	
 
        return q.ui_value
 

	
 
    def repo_scan(self, repos_path=None):
 
        """Listing of repositories in given path. This path should not be a 
 
        """Listing of repositories in given path. This path should not be a
 
        repository itself. Return a dictionary of repository objects
 
        
 

	
 
        :param repos_path: path to directory containing repositories
 
        """
 

	
 
        log.info('scanning for repositories in %s', repos_path)
 

	
 
        if repos_path is None:
 
            repos_path = self.repos_path
 

	
 
        baseui = make_ui('db')
 
        repos_list = {}
 

	
 
        for name, path in get_filesystem_repos(repos_path, recursive=True):
 
@@ -111,25 +111,25 @@ class ScmModel(BaseModel):
 
                        repos_list[name] = klass(path[1], baseui=baseui)
 

	
 
                    if path[0] == 'git' and path[0] in BACKENDS.keys():
 
                        repos_list[name] = klass(path[1])
 
            except OSError:
 
                continue
 

	
 
        return repos_list
 

	
 
    def get_repos(self, all_repos=None):
 
        """Get all repos from db and for each repo create it's backend instance.
 
        and fill that backed with information from database
 
        
 

	
 
        :param all_repos: give specific repositories list, good for filtering
 
            this have to be a list of  just the repository names
 
        """
 
        if all_repos is None:
 
            repos = self.sa.query(Repository)\
 
                        .order_by(Repository.repo_name).all()
 
            all_repos = [r.repo_name for r in repos]
 

	
 
        #get the repositories that should be invalidated
 
        invalidation_list = [str(x.cache_key) for x in \
 
                             self.sa.query(CacheInvalidation.cache_key)\
 
                             .filter(CacheInvalidation.cache_active == False)\
 
@@ -157,28 +157,28 @@ class ScmModel(BaseModel):
 
                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
 
                tmp_d['dbrepo'] = dbrepo.get_dict()
 
                tmp_d['dbrepo_fork'] = dbrepo.fork.get_dict() if dbrepo.fork else {}
 
                yield tmp_d
 

	
 
    def get(self, repo_name, invalidation_list=None, retval='all'):
 
        """Returns a tuple of Repository,DbRepository,
 
        Get's repository from given name, creates BackendInstance and
 
        propagates it's data from database with all additional information
 
        
 

	
 
        :param repo_name:
 
        :param invalidation_list: if a invalidation list is given the get
 
            method should not manually check if this repository needs 
 
            method should not manually check if this repository needs
 
            invalidation and just invalidate the repositories in list
 
        :param retval: string specifing what to return one of 'repo','dbrepo',
 
            'all'if repo or dbrepo is given it'll just lazy load chosen type
 
            and return None as the second
 
        """
 
        if not HasRepoPermissionAny('repository.read', 'repository.write',
 
                            'repository.admin')(repo_name, 'get repo check'):
 
            return
 

	
 
        #======================================================================
 
        # CACHE FUNCTION
 
        #======================================================================
 
@@ -225,27 +225,27 @@ class ScmModel(BaseModel):
 

	
 
        r, dbr = None, None
 
        if retval == 'repo' or 'all':
 
            r = _get_repo(repo_name)
 
        if retval == 'dbrepo' or 'all':
 
            dbr = RepoModel().get_full(repo_name, cache=True,
 
                                          invalidate=dbinvalidate)
 

	
 

	
 
        return r, dbr
 

	
 
    def mark_for_invalidation(self, repo_name):
 
        """Puts cache invalidation task into db for 
 
        """Puts cache invalidation task into db for
 
        further global cache invalidation
 
        
 

	
 
        :param repo_name: this repo that should invalidation take place
 
        """
 

	
 
        log.debug('marking %s for invalidation', repo_name)
 
        cache = self.sa.query(CacheInvalidation)\
 
            .filter(CacheInvalidation.cache_key == repo_name).scalar()
 

	
 
        if cache:
 
            #mark this cache as inactive
 
            cache.cache_active = False
 
        else:
 
            log.debug('cache key not found in invalidation db -> creating one')
 
@@ -358,56 +358,55 @@ class ScmModel(BaseModel):
 
                        == RepoModel().get_by_repo_name(repo_id)).count()
 

	
 

	
 
    def pull_changes(self, repo_name, username):
 
        repo, dbrepo = self.get(repo_name, retval='all')
 

	
 
        try:
 
            extras = {'ip':'',
 
                      'username':username,
 
                      'action':'push_remote',
 
                      'repository':repo_name}
 

	
 
            #inject ui extra param to log this action via push logger        
 
            #inject ui extra param to log this action via push logger
 
            for k, v in extras.items():
 
                repo._repo.ui.setconfig('rhodecode_extras', k, v)
 

	
 
            repo.pull(dbrepo.clone_uri)
 
            self.mark_for_invalidation(repo_name)
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def get_unread_journal(self):
 
        return self.sa.query(UserLog).count()
 

	
 

	
 
    def _should_invalidate(self, repo_name):
 
        """Looks up database for invalidation signals for this repo_name
 
        
 

	
 
        :param repo_name:
 
        """
 

	
 
        ret = self.sa.query(CacheInvalidation)\
 
            .filter(CacheInvalidation.cache_key == repo_name)\
 
            .filter(CacheInvalidation.cache_active == False)\
 
            .scalar()
 

	
 
        return ret
 

	
 
    def _mark_invalidated(self, cache_key):
 
        """ Marks all occurrences of cache to invalidation as already 
 
        """ Marks all occurrences of cache to invalidation as already
 
        invalidated
 
        
 

	
 
        :param cache_key:
 
        """
 

	
 
        if cache_key:
 
            log.debug('marking %s as already invalidated', cache_key)
 
        try:
 
            cache_key.cache_active = True
 
            self.sa.add(cache_key)
 
            self.sa.commit()
 
        except (DatabaseError,):
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 

	
rhodecode/model/settings.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.settings
 
    ~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Settings model for RhodeCode
 

	
 
    :created on Nov 17, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import  RhodeCodeSettings
 

	
 
log = logging.getLogger(__name__)
 
@@ -38,53 +38,53 @@ class SettingsModel(BaseModel):
 
    Settings model
 
    """
 

	
 
    def get(self, settings_key, cache=False):
 
        r = self.sa.query(RhodeCodeSettings)\
 
            .filter(RhodeCodeSettings.app_settings_name == settings_key).scalar()
 
        if cache:
 
            r = r.options(FromCache("sql_cache_short",
 
                                          "get_setting_%s" % settings_key))
 
        return r
 

	
 
    def get_app_settings(self, cache=False):
 
        """Get's config from database, each config key is prefixed with 
 
        'rhodecode_' prefix, than global pylons config is updated with such 
 
        """Get's config from database, each config key is prefixed with
 
        'rhodecode_' prefix, than global pylons config is updated with such
 
        keys
 
        """
 

	
 
        ret = self.sa.query(RhodeCodeSettings)
 

	
 
        if cache:
 
            ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
 

	
 
        if not ret:
 
            raise Exception('Could not get application settings !')
 
        settings = {}
 
        for each in ret:
 
            settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
 

	
 
        return settings
 

	
 
    def get_ldap_settings(self):
 
        """
 
        Returns ldap settings from database
 
        :returns:
 
        ldap_active
 
        ldap_host
 
        ldap_port 
 
        ldap_port
 
        ldap_ldaps
 
        ldap_tls_reqcert
 
        ldap_dn_user 
 
        ldap_dn_pass 
 
        ldap_dn_user
 
        ldap_dn_pass
 
        ldap_base_dn
 
        ldap_filter
 
        ldap_search_scope
 
        ldap_attr_login
 
        ldap_attr_firstname
 
        ldap_attr_lastname
 
        ldap_attr_email
 
        """
 
        # ldap_search_scope
 

	
 
        r = self.sa.query(RhodeCodeSettings)\
 
                .filter(RhodeCodeSettings.app_settings_name\
rhodecode/model/user.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.user
 
    ~~~~~~~~~~~~~~~~~~~~
 

	
 
    users model for RhodeCode
 
    
 

	
 
    :created_on: Apr 9, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import traceback
 

	
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.caching_query import FromCache
 
@@ -214,27 +214,27 @@ class UserModel(BaseModel):
 
            self.sa.rollback()
 
            raise
 

	
 
    def reset_password(self, data):
 
        from rhodecode.lib.celerylib import tasks, run_task
 
        run_task(tasks.reset_user_password, data['email'])
 

	
 

	
 
    def fill_data(self, auth_user, user_id=None, api_key=None):
 
        """
 
        Fetches auth_user by user_id,or api_key if present.
 
        Fills auth_user attributes with those taken from database.
 
        Additionally set's is_authenitated if lookup fails 
 
        Additionally set's is_authenitated if lookup fails
 
        present in database
 
        
 

	
 
        :param auth_user: instance of user to set attributes
 
        :param user_id: user id to fetch by
 
        :param api_key: api key to fetch by
 
        """
 
        if user_id is None and api_key is None:
 
            raise Exception('You need to pass user_id or api_key')
 

	
 
        try:
 
            if api_key:
 
                dbuser = self.get_by_api_key(api_key)
 
            else:
 
                dbuser = self.get(user_id)
 
@@ -246,44 +246,44 @@ class UserModel(BaseModel):
 

	
 
        except:
 
            log.error(traceback.format_exc())
 
            auth_user.is_authenticated = False
 

	
 
        return auth_user
 

	
 

	
 
    def fill_perms(self, user):
 
        """Fills user permission attribute with permissions taken from database
 
        works for permissions given for repositories, and for permissions that
 
        as part of beeing group member
 
        
 

	
 
        :param user: user instance to fill his perms
 
        """
 

	
 
        user.permissions['repositories'] = {}
 
        user.permissions['global'] = set()
 

	
 
        #===========================================================================
 
        # fetch default permissions
 
        #===========================================================================
 
        default_user = self.get_by_username('default', cache=True)
 

	
 
        default_perms = self.sa.query(RepoToPerm, Repository, Permission)\
 
            .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
 
            .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
 
            .filter(RepoToPerm.user == default_user).all()
 

	
 
        if user.is_admin:
 
            #=======================================================================
 
            # #admin have all default rights set to admin        
 
            # #admin have all default rights set to admin
 
            #=======================================================================
 
            user.permissions['global'].add('hg.admin')
 

	
 
            for perm in default_perms:
 
                p = 'repository.admin'
 
                user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
 

	
 
        else:
 
            #=======================================================================
 
            # set default permissions
 
            #=======================================================================
 

	
 
@@ -316,25 +316,25 @@ class UserModel(BaseModel):
 
                .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
 
                .filter(RepoToPerm.user_id == user.user_id).all()
 

	
 
            for perm in user_perms:
 
                if perm.Repository.user_id == user.user_id:#set admin if owner
 
                    p = 'repository.admin'
 
                else:
 
                    p = perm.Permission.permission_name
 
                user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
 

	
 

	
 
            #=======================================================================
 
            # check if user is part of groups for this repository and fill in 
 
            # check if user is part of groups for this repository and fill in
 
            # (or replace with higher) permissions
 
            #=======================================================================
 
            user_perms_from_users_groups = self.sa.query(UsersGroupToPerm, Permission, Repository,)\
 
                .join((Repository, UsersGroupToPerm.repository_id == Repository.repo_id))\
 
                .join((Permission, UsersGroupToPerm.permission_id == Permission.permission_id))\
 
                .join((UsersGroupMember, UsersGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
 
                .filter(UsersGroupMember.user_id == user.user_id).all()
 

	
 
            for perm in user_perms_from_users_groups:
 
                p = perm.Permission.permission_name
 
                cur_perm = user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name]
 
                #overwrite permission only if it's greater than permission given from other sources
rhodecode/model/users_group.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.user_group
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    users groups model for RhodeCode
 
    
 

	
 
    :created_on: Jan 25, 2011
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import logging
 
import traceback
 

	
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.caching_query import FromCache
rhodecode/tests/functional/test_files.py
Show inline comments
 
@@ -302,13 +302,12 @@ removed extra unicode conversion in diff
 

	
 

	
 
    def test_raw_wrong_f_path(self):
 
        self.log_user()
 
        rev = '27cd5cce30c96924232dffcd24178a07ffeb5dfc'
 
        f_path = 'vcs/ERRORnodes.py'
 
        response = self.app.get(url(controller='files', action='raw',
 
                                    repo_name=HG_REPO,
 
                                    revision=rev,
 
                                    f_path=f_path))
 

	
 
        assert "There is no file nor directory at the given path: %r at revision %r" % (f_path, rev[:12]) in response.session['flash'][0][1], 'No flash message'
 

	
rhodecode/tests/functional/test_login.py
Show inline comments
 
@@ -219,15 +219,12 @@ class TestLoginController(TestController
 
                                            {'username':username,
 
                                             'password':password,
 
                                             'password_confirmation':password,
 
                                             'email':email,
 
                                             'name':name,
 
                                             'lastname':lastname})
 
        #register new user for email test
 
        response = self.app.post(url(controller='login', action='password_reset'),
 
                                            {'email':email, })
 
        print response.session['flash']
 
        assert 'You have successfully registered into rhodecode' in response.session['flash'][0], 'No flash message about user registration'
 
        assert 'Your new password was sent' in response.session['flash'][1], 'No flash message about password reset'
 

	
 

	
 

	
rhodecode/tests/functional/test_search.py
Show inline comments
 
@@ -24,13 +24,12 @@ class TestSearchController(TestControlle
 
        response = self.app.get(url(controller='search', action='index'), {'q':'def repo'})
 
        print response.body
 
        assert '10 results' in response.body, 'no message about proper search results'
 
        assert 'Permission denied' not in response.body, 'Wrong permissions settings for that repo and user'
 

	
 

	
 
    def test_repo_search(self):
 
        self.log_user()
 
        response = self.app.get(url(controller='search', action='index'), {'q':'repository:%s def test' % HG_REPO})
 
        print response.body
 
        assert '4 results' in response.body, 'no message about proper search results'
 
        assert 'Permission denied' not in response.body, 'Wrong permissions settings for that repo and user'
 

	
rhodecode/tests/functional/test_settings.py
Show inline comments
 
@@ -38,13 +38,12 @@ class TestSettingsController(TestControl
 
        assert fork_repo.fork.repo_name == repo_name, 'wrong fork parrent'
 

	
 

	
 
        #test if fork is visible in the list ?
 
        response = response.follow()
 

	
 

	
 
        #check if fork is marked as fork
 
        response = self.app.get(url(controller='summary', action='index',
 
                                    repo_name=fork_name))
 

	
 
        assert 'Fork of %s' % repo_name in response.body, 'no message about that this repo is a fork'
 

	
rhodecode/tests/functional/test_summary.py
Show inline comments
 
@@ -20,13 +20,12 @@ class TestSummaryController(TestControll
 
        response = self.app.get(url(controller='summary', action='index', repo_name=HG_REPO))
 
        assert """var data = {"Python": 42, "Rst": 11, "Bash": 2, "Makefile": 1, "Batch": 1, "Ini": 1, "Css": 1};""" in response.body, 'wrong info about % of codes stats'
 

	
 
        # clone url...
 
        assert """<input type="text" id="clone_url" readonly="readonly" value="hg clone http://test_admin@localhost:80/%s" size="70"/>""" % HG_REPO in response.body
 

	
 

	
 
    def _enable_stats(self):
 
        r = Repository.by_repo_name(HG_REPO)
 
        r.enable_statistics = True
 
        self.sa.add(r)
 
        self.sa.commit()
 

	
rhodecode/tests/test_hg_operations.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.tests.test_hg_operations
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Test suite for making push/pull operations
 
    
 

	
 
    :created_on: Dec 30, 2010
 
    :copyright: (c) 2010 by marcink.
 
    :license: LICENSE_NAME, see LICENSE_FILE for more details.
 
"""
 

	
 
import os
 
import shutil
 
import logging
 
from os.path import join as jn
 

	
 
from tempfile import _RandomNameSequence
 
from subprocess import Popen, PIPE
 
@@ -319,14 +319,12 @@ if __name__ == '__main__':
 
    create_test_user(force=False)
 
    create_test_repo()
 
    #test_push_modify_file()
 
    #test_clone()
 
    #test_clone_anonymous_ok()
 

	
 
    #test_clone_wrong_credentials()
 

	
 
    #test_pull()
 
    test_push_new_file(commits=15)
 
    #test_push_wrong_path()
 
    #test_push_wrong_credentials()
 

	
 

	
rhodecode/websetup.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.websetup
 
    ~~~~~~~~~~~~~~~~~~
 

	
 
    Weboperations and setup for rhodecode
 
    
 

	
 
    :created_on: Dec 11, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2011 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
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import os
 
import logging
 

	
 
from rhodecode.config.environment import load_environment
 
from rhodecode.lib.db_manage import DbManage
 

	
 

	
 
@@ -38,17 +38,12 @@ def setup_app(command, conf, vars):
 
    """Place any commands to setup rhodecode here"""
 
    dbconf = conf['sqlalchemy.db1.url']
 
    dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'], tests=False)
 
    dbmanage.create_tables(override=True)
 
    dbmanage.set_db_version()
 
    dbmanage.create_settings(dbmanage.config_prompt(None))
 
    dbmanage.create_default_user()
 
    dbmanage.admin_prompt()
 
    dbmanage.create_permissions()
 
    dbmanage.populate_default_permissions()
 

	
 
    load_environment(conf.global_conf, conf.local_conf, initial=True)
 

	
 

	
 

	
 

	
 

	
setup.py
Show inline comments
 
@@ -106,15 +106,15 @@ setup(
 
    main = rhodecode.config.middleware:make_app
 

	
 
    [paste.app_install]
 
    main = pylons.util:PylonsInstaller
 

	
 
    [paste.global_paster_command]
 
    make-index = rhodecode.lib.indexers:MakeIndex
 
    upgrade-db = rhodecode.lib.dbmigrate:UpgradeDb
 
    celeryd=rhodecode.lib.celerypylons.commands:CeleryDaemonCommand
 
    celerybeat=rhodecode.lib.celerypylons.commands:CeleryBeatCommand
 
    camqadm=rhodecode.lib.celerypylons.commands:CAMQPAdminCommand
 
    celeryev=rhodecode.lib.celerypylons.commands:CeleryEventCommand
 
              
 

	
 
    """,
 
)
0 comments (0 inline, 0 general)