Changeset - fd3557b09f01
[Not reviewed]
Merge beta
0 6 0
Marcin Kuzminski - 15 years ago 2011-01-28 12:19:20
marcin@python-works.com
merge
6 files changed with 87 insertions and 5 deletions:
0 comments (0 inline, 0 general)
development.ini
Show inline comments
 
################################################################################
 
################################################################################
 
# RhodeCode - Pylons environment configuration                                 #
 
#                                                                              # 
 
# The %(here)s variable will be replaced with the parent directory of this file#
 
################################################################################
 

	
 
[DEFAULT]
 
debug = true
 
################################################################################
 
## Uncomment and replace with the address which should receive                ## 
 
## any error reports after application crash                                  ##
 
## Additionally those settings will be used by RhodeCode mailing system       ##
 
################################################################################
 
#email_to = admin@localhost
 
#error_email_from = paste_error@localhost
 
#app_email_from = rhodecode-noreply@localhost
 
#error_message =
 

	
 
#smtp_server = mail.server.com
 
#smtp_username = 
 
#smtp_password = 
 
#smtp_port = 
 
#smtp_use_tls = false
 
#smtp_use_ssl = true
 

	
 
[server:main]
 
##nr of threads to spawn
 
threadpool_workers = 5
 

	
 
##max request before thread respawn
 
threadpool_max_requests = 6
 

	
 
##option to use threads of process
 
use_threadpool = false
 

	
 
use = egg:Paste#http
 
host = 0.0.0.0
 
port = 5000
 

	
 
[app:main]
 
use = egg:rhodecode
 
full_stack = true
 
static_files = true
 
lang=en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
cut_off_limit = 256000
 
force_https = false
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
 
broker.port = 5672
 
broker.user = rabbitmq
 
broker.password = qweqwe
 

	
 
celery.imports = rhodecode.lib.celerylib.tasks
 

	
 
celery.result.backend = amqp
 
celery.result.dburi = amqp://
 
celery.result.serialier = json
 

	
 
#celery.send.task.error.emails = true
 
#celery.amqp.task.result.expires = 18000
 

	
 
celeryd.concurrency = 2
 
#celeryd.log.file = celeryd.log
 
celeryd.log.level = debug
 
celeryd.max.tasks.per.child = 3
 

	
 
#tasks will never be sent to the queue, but executed locally instead.
 
celery.always.eager = false
 

	
 
####################################
 
###         BEAKER CACHE        ####
 
####################################
 
beaker.cache.data_dir=/%(here)s/data/cache/data
 
beaker.cache.lock_dir=/%(here)s/data/cache/lock
 
beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
 

	
 
beaker.cache.super_short_term.type=memory
 
beaker.cache.super_short_term.expire=10
 

	
 
beaker.cache.short_term.type=memory
 
beaker.cache.short_term.expire=60
 

	
 
beaker.cache.long_term.type=memory
 
beaker.cache.long_term.expire=36000
 

	
 
beaker.cache.sql_cache_short.type=memory
 
beaker.cache.sql_cache_short.expire=10
 

	
 
beaker.cache.sql_cache_med.type=memory
 
beaker.cache.sql_cache_med.expire=360
 

	
 
beaker.cache.sql_cache_long.type=file
 
beaker.cache.sql_cache_long.expire=3600
 

	
 
####################################
 
###       BEAKER SESSION        ####
 
####################################
 
## Type of storage used for the session, current types are 
 
## dbm, file, memcached, database, and memory. 
 
## The storage uses the Container API 
 
##that is also used by the cache system.
 
beaker.session.type = file
 

	
 
beaker.session.key = rhodecode
 
beaker.session.secret = g654dcno0-9873jhgfreyu
 
beaker.session.timeout = 36000
 

	
 
##auto save the session to not to use .save()
 
beaker.session.auto = False
 

	
 
##true exire at browser close
 
#beaker.session.cookie_expires = 3600
 

	
 
    
 
################################################################################
 
## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*  ##
 
## Debug mode will enable the interactive debugging tool, allowing ANYONE to  ##
 
## execute malicious code after an exception is raised.                       ##
 
################################################################################
 
#set debug = false
 

	
 
##################################
 
###       LOGVIEW CONFIG       ###
 
##################################
 
logview.sqlalchemy = #faa
 
logview.pylons.templating = #bfb
 
logview.pylons.util = #eee
 

	
 
#########################################################
 
### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG    ###
 
#########################################################
 
sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
 
#sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
 
sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
 
#sqlalchemy.db1.echo = False
 
#sqlalchemy.db1.pool_recycle = 3600
 
sqlalchemy.convert_unicode = true
 

	
 
################################
 
### LOGGING CONFIGURATION   ####
 
################################
 
[loggers]
 
keys = root, routes, rhodecode, sqlalchemy,beaker,templates
 

	
 
[handlers]
 
keys = console
 

	
 
[formatters]
 
keys = generic,color_formatter
 

	
 
#############
 
## LOGGERS ##
 
#############
 
[logger_root]
 
level = NOTSET
 
handlers = console
 

	
 
[logger_routes]
 
level = DEBUG
 
handlers = console
 
qualname = routes.middleware
 
# "level = DEBUG" logs the route matched and routing variables.
 
propagate = 0
 

	
 
[logger_beaker]
 
level = ERROR
 
handlers = console
 
qualname = beaker.container
 
propagate = 0
 

	
 
[logger_templates]
 
level = INFO
 
handlers = console
 
qualname = pylons.templating
 
propagate = 0
 

	
 
[logger_rhodecode]
 
level = DEBUG
 
handlers = console
 
qualname = rhodecode
 
propagate = 0
 

	
 
[logger_sqlalchemy]
 
level = ERROR
 
handlers = console
 
qualname = sqlalchemy.engine
 
propagate = 0
 

	
 
##############
 
## HANDLERS ##
 
##############
 

	
 
[handler_console]
 
class = StreamHandler
 
args = (sys.stderr,)
 
level = NOTSET
 
formatter = color_formatter
 

	
 
################
 
## FORMATTERS ##
 
################
 

	
 
[formatter_generic]
 
format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 

	
 
[formatter_color_formatter]
 
class=rhodecode.lib.colored_formatter.ColorFormatter
 
format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 
\ No newline at end of file
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>    
 
    :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__
 
from rhodecode.model import meta
 

	
 
from rhodecode.lib.auth import get_crypt_password
 
from rhodecode.lib.utils import ask_ok
 
from rhodecode.model import init_model
 
from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
 
    UserToPerm, DbMigrateVersion
 

	
 
from sqlalchemy.engine import create_engine
 

	
 
log = logging.getLogger(__name__)
 

	
 
class DbManage(object):
 
    def __init__(self, log_sql, dbconf, root, tests=False):
 
        self.dbname = dbconf.split('/')[-1]
 
        self.tests = tests
 
        self.root = root
 
        self.dburi = dbconf
 
        self.log_sql = log_sql
 
        self.db_exists = False
 
        self.init_db()
 

	
 
    def init_db(self):
 
        engine = create_engine(self.dburi, echo=self.log_sql)
 
        init_model(engine)
 
        self.sa = meta.Session()
 

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

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

	
 

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

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

	
 
        checkfirst = not override
 
        meta.Base.metadata.create_all(checkfirst=checkfirst)
 
        log.info('Created tables for %s', self.dbname)
 

	
 

	
 

	
 
    def set_db_version(self):
 
        try:
 
            ver = DbMigrateVersion()
 
            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 
 
        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')
 

	
 
        repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
 
                             'rhodecode/lib/dbmigrate')
 
        db_uri = self.dburi
 

	
 
        try:
 
            curr_version = api.db_version(db_uri, repository_path)
 
            msg = ('Found current database under version'
 
                 ' control with version %s' % curr_version)
 

	
 
        except (RuntimeError, DatabaseNotControlledError), e:
 
            curr_version = 1
 
            msg = ('Current database is not under version control. Setting'
 
                   ' 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 
 
            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')
 

	
 
            def step_1(self):
 
                pass
 

	
 
            def step_2(self):
 
                print ('Patching repo paths for newer version of RhodeCode')
 
                self.klass.fix_repo_paths()
 

	
 
                print ('Patching default user of RhodeCode')
 
                self.klass.fix_default_user()
 

	
 
                log.info('Changing ui settings')
 
                self.klass.create_ui_settings()
 

	
 
            def step_3(self):
 
                print ('Adding additional settings into RhodeCode db')
 
                self.klass.fix_settings()
 

	
 
        upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
 

	
 
        #CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
 
        for step in upgrade_steps:
 
            print ('performing upgrade step %s' % step)
 
            callable = getattr(UpgradeSteps(self), 'step_%s' % step)()
 

	
 

	
 

	
 
    def fix_repo_paths(self):
 
        """Fixes a old rhodecode version path into new one without a '*'
 
        """
 

	
 
        paths = self.sa.query(RhodeCodeUi)\
 
                .filter(RhodeCodeUi.ui_key == '/')\
 
                .scalar()
 

	
 
        paths.ui_value = paths.ui_value.replace('*', '')
 

	
 
        try:
 
            self.sa.add(paths)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 

	
 
    def fix_default_user(self):
 
        """Fixes a old default user with some 'nicer' default values,
 
        used mostly for anonymous access
 
        """
 
        def_user = self.sa.query(User)\
 
                .filter(User.username == 'default')\
 
                .one()
 

	
 
        def_user.name = 'Anonymous'
 
        def_user.lastname = 'User'
 
        def_user.email = 'anonymous@rhodecode.org'
 

	
 
        try:
 
            self.sa.add(def_user)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 

	
 
    def fix_settings(self):
 
        """Fixes rhodecode settings adds ga_code key for google analytics
 
        """
 

	
 
        hgsettings3 = RhodeCodeSettings('ga_code', '')
 

	
 
        try:
 
            self.sa.add(hgsettings3)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 

	
 
    def admin_prompt(self, second=False):
 
        if not self.tests:
 
            import getpass
 

	
 

	
 
            def get_password():
 
                password = getpass.getpass('Specify admin password (min 6 chars):')
 
                confirm = getpass.getpass('Confirm password:')
 

	
 
                if password != confirm:
 
                    log.error('passwords mismatch')
 
                    return False
 
                if len(password) < 6:
 
                    log.error('password is to short use at least 6 characters')
 
                    return False
 

	
 
                return password
 

	
 
            username = raw_input('Specify admin username:')
 

	
 
            password = get_password()
 
            if not password:
 
                #second try
 
                password = get_password()
 
                if not password:
 
                    sys.exit()
 

	
 
            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)\
rhodecode/lib/helpers.py
Show inline comments
 
"""Helper functions
 

	
 
Consists of functions to typically be used within templates, but also
 
available to Controllers. This module is available to both as 'h'.
 
"""
 
import random
 
import hashlib
 
import StringIO
 
from pygments.formatters import HtmlFormatter
 
from pygments import highlight as code_highlight
 
from pylons import url, app_globals as g
 
from pylons.i18n.translation import _, ungettext
 
from vcs.utils.annotate import annotate_highlight
 
from webhelpers.html import literal, HTML, escape
 
from webhelpers.html.tools import *
 
from webhelpers.html.builder import make_tag
 
from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
 
    end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
 
    link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
 
    password, textarea, title, ul, xml_declaration, radio
 
from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
 
    mail_to, strip_links, strip_tags, tag_re
 
from webhelpers.number import format_byte_size, format_bit_size
 
from webhelpers.pylonslib import Flash as _Flash
 
from webhelpers.pylonslib.secure_form import secure_form
 
from webhelpers.text import chop_at, collapse, convert_accented_entities, \
 
    convert_misc_entities, lchop, plural, rchop, remove_formatting, \
 
    replace_whitespace, urlify, truncate, wrap_paragraphs
 
from webhelpers.date import time_ago_in_words
 

	
 
from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
 
    convert_boolean_attrs, NotGiven
 

	
 
def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
 
    """Reset button
 
    """
 
    _set_input_attrs(attrs, type, name, value)
 
    _set_id_attr(attrs, id, name)
 
    convert_boolean_attrs(attrs, ["disabled"])
 
    return HTML.input(**attrs)
 

	
 
reset = _reset
 

	
 

	
 
def get_token():
 
    """Return the current authentication token, creating one if one doesn't
 
    already exist.
 
    """
 
    token_key = "_authentication_token"
 
    from pylons import session
 
    if not token_key in session:
 
        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()
 

	
 
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)
 

	
 
class _ToolTip(object):
 

	
 
    def __call__(self, tooltip_title, trim_at=50):
 
        """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 
 
        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        
 
            };
 
            var myToolTips = new YAHOO.widget.Tooltip("tooltip", { 
 
                context: toolTipsId(),
 
                monitorresize:false,
 
                xyoffset :[0,0],
 
                autodismissdelay:300000,
 
                hidedelay:5,
 
                showdelay:20,
 
            });
 
            
 
            // Set the text for the tooltip just before we display it. Lazy method
 
            myToolTips.contextTriggerEvent.subscribe( 
 
                 function(type, args) { 
 

	
 
                        var context = args[0]; 
 
                        
 
                        //positioning of tooltip
 
                        var tt_w = this.element.clientWidth;//tooltip width
 
                        var tt_h = this.element.clientHeight;//tooltip height
 
                        
 
                        var context_w = context.offsetWidth;
 
                        var context_h = context.offsetHeight;
 
                        
 
                        var pos_x = YAHOO.util.Dom.getX(context);
 
                        var pos_y = YAHOO.util.Dom.getY(context);
 

	
 
                        var display_strategy = 'right';
 
                        var xy_pos = [0,0];
 
                        switch (display_strategy){
 
                        
 
                            case 'top':
 
                                var cur_x = (pos_x+context_w/2)-(tt_w/2);
 
                                var cur_y = (pos_y-tt_h-4);
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;
 
                            case 'bottom':
 
                                var cur_x = (pos_x+context_w/2)-(tt_w/2);
 
                                var cur_y = pos_y+context_h+4;
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;
 
                            case 'left':
 
                                var cur_x = (pos_x-tt_w-4);
 
                                var cur_y = pos_y-((tt_h/2)-context_h/2);
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;
 
                            case 'right':
 
                                var cur_x = (pos_x+context_w+4);
 
                                var cur_y = pos_y-((tt_h/2)-context_h/2);
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;
 
                             default:
 
                                var cur_x = (pos_x+context_w/2)-(tt_w/2);
 
                                var cur_y = pos_y-tt_h-4;
 
                                xy_pos = [cur_x,cur_y];                                
 
                                break;                             
 
                                 
 
                        }
 

	
 
                        this.cfg.setProperty("xy",xy_pos);
 

	
 
                  });
 
                  
 
            //Mouse out 
 
            myToolTips.contextMouseOutEvent.subscribe(
 
                function(type, args) {
 
                    var context = args[0];
 
                    
 
                });
 
        });
 
        '''
 
        return literal(js)
 

	
 
tooltip = _ToolTip()
 

	
 
class _FilesBreadCrumbs(object):
 

	
 
    def __call__(self, repo_name, rev, paths):
 
        if isinstance(paths, str):
 
            paths = paths.decode('utf-8')
 
        url_l = [link_to(repo_name, url('files_home',
 
                                        repo_name=repo_name,
 
                                        revision=rev, f_path=''))]
 
        paths_l = paths.split('/')
 
        for cnt, p in enumerate(paths_l):
 
            if p != '':
 
                url_l.append(link_to(p, url('files_home',
 
                                            repo_name=repo_name,
 
                                            revision=rev,
 
                                            f_path='/'.join(paths_l[:cnt + 1]))))
 

	
 
        return literal('/'.join(url_l))
 

	
 
files_breadcrumbs = _FilesBreadCrumbs()
 

	
 
class CodeHtmlFormatter(HtmlFormatter):
 
    """My code Html Formatter for source codes
 
    """
 

	
 
    def wrap(self, source, outfile):
 
        return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
 

	
 
    def _wrap_code(self, source):
 
        for cnt, it in enumerate(source):
 
            i, t = it
 
            t = '<div id="#S-%s">%s</div>' % (cnt + 1, t)
 
            t = '<div id="L%s">%s</div>' % (cnt + 1, t)
 
            yield i, t
 

	
 
    def _wrap_tablelinenos(self, inner):
 
        dummyoutfile = StringIO.StringIO()
 
        lncount = 0
 
        for t, line in inner:
 
            if t:
 
                lncount += 1
 
            dummyoutfile.write(line)
 

	
 
        fl = self.linenostart
 
        mw = len(str(lncount + fl - 1))
 
        sp = self.linenospecial
 
        st = self.linenostep
 
        la = self.lineanchors
 
        aln = self.anchorlinenos
 
        nocls = self.noclasses
 
        if sp:
 
            lines = []
 

	
 
            for i in range(fl, fl + lncount):
 
                if i % st == 0:
 
                    if i % sp == 0:
 
                        if aln:
 
                            lines.append('<a href="#%s%d" class="special">%*d</a>' %
 
                                         (la, i, mw, i))
 
                        else:
 
                            lines.append('<span class="special">%*d</span>' % (mw, i))
 
                    else:
 
                        if aln:
 
                            lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
 
                        else:
 
                            lines.append('%*d' % (mw, i))
 
                else:
 
                    lines.append('')
 
            ls = '\n'.join(lines)
 
        else:
 
            lines = []
 
            for i in range(fl, fl + lncount):
 
                if i % st == 0:
 
                    if aln:
 
                        lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
 
                    else:
 
                        lines.append('%*d' % (mw, i))
 
                else:
 
                    lines.append('')
 
            ls = '\n'.join(lines)
 

	
 
        # in case you wonder about the seemingly redundant <div> here: since the
 
        # content in the other cell also is wrapped in a div, some browsers in
 
        # some configurations seem to mess up the formatting...
 
        if nocls:
 
            yield 0, ('<table class="%stable">' % self.cssclass +
 
                      '<tr><td><div class="linenodiv" '
 
                      'style="background-color: #f0f0f0; padding-right: 10px">'
 
                      '<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(filenode, **kwargs):
 
    """pygmentize function for annotation
 
    
 
    :param filenode:
 
    """
 

	
 
    color_dict = {}
 
    def gen_color(n=10000):
 
        """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)
 

	
 
    cgenerator = gen_color()
 

	
 
    def get_color_string(cs):
 
        if color_dict.has_key(cs):
 
            col = color_dict[cs]
 
        else:
 
            col = color_dict[cs] = cgenerator.next()
 
        return "color: rgb(%s)! important;" % (', '.join(col))
 

	
 
    def url_func(changeset):
 
        tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \
 
        " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
 

	
 
        tooltip_html = tooltip_html % (changeset.author,
 
                                               changeset.date,
 
                                               tooltip(changeset.message))
 
        lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
 
                                 short_id(changeset.raw_id))
 
        uri = link_to(
 
                lnk_format,
 
                url('changeset_home', repo_name=changeset.repository.name,
 
                    revision=changeset.raw_id),
 
                style=get_color_string(changeset.raw_id),
 
                class_='tooltip',
 
                title=tooltip_html
 
              )
 

	
 
        uri += '\n'
 
        return uri
 
    return literal(annotate_highlight(filenode, url_func, **kwargs))
 

	
 
def repo_name_slug(value):
 
    """Return slug of name of repository
 
    This function is called on each creation/modification
 
    of repository to prevent bad names in repo
 
    """
 

	
 
    slug = remove_formatting(value)
 
    slug = strip_tags(slug)
 

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

	
 
def get_changeset_safe(repo, rev):
 
    from vcs.backends.base import BaseRepository
 
    from vcs.exceptions import RepositoryError
 
    if not isinstance(repo, BaseRepository):
 
        raise Exception('You must pass an Repository '
 
                        'object as first argument got %s', type(repo))
 

	
 
    try:
 
        cs = repo.get_changeset(rev)
 
    except RepositoryError:
 
        from rhodecode.lib.utils import EmptyChangeset
 
        cs = EmptyChangeset()
 
    return cs
 

	
 

	
 
flash = _Flash()
 

	
 

	
 
#==============================================================================
 
# MERCURIAL FILTERS available via h.
 
#==============================================================================
 
from mercurial import util
 
from mercurial.templatefilters import person as _person
 

	
 
def _age(curdate):
 
    """turns a datetime into an age string."""
 

	
 
    if not curdate:
 
        return ''
 

	
 
    from datetime import timedelta, datetime
 

	
 
    agescales = [("year", 3600 * 24 * 365),
 
                 ("month", 3600 * 24 * 30),
 
                 ("day", 3600 * 24),
 
                 ("hour", 3600),
 
                 ("minute", 60),
 
                 ("second", 1), ]
 

	
 
    age = datetime.now() - curdate
 
    age_seconds = (age.days * agescales[2][1]) + age.seconds
 
    pos = 1
 
    for scale in agescales:
 
        if scale[1] <= age_seconds:
 
            if pos == 6:pos = 5
 
            return time_ago_in_words(curdate, agescales[pos][0]) + ' ' + _('ago')
 
        pos += 1
 

	
 
    return _('just now')
 

	
 
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="/images/icons/accept.png", alt=_('True'))
 

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

	
 
    return value
 

	
 

	
 
def action_parser(user_log):
 
    """This helper will map the specified string action into translated
 
    fancy names with icons and links
 
    
 
    :param user_log: user log instance
 
    """
 

	
 
    action = user_log.action
 
    action_params = ' '
 

	
 
    x = action.split(':')
 

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

	
 
    def get_cs_links():
 
        revs_limit = 5 #display this amount always
 
        revs_top_limit = 50 #show upto this amount of changesets hidden
 
        revs = action_params.split(',')
 
        repo_name = user_log.repository.repo_name
 
        from rhodecode.model.scm import ScmModel
 

	
 
        message = lambda rev: get_changeset_safe(ScmModel().get(repo_name),
 
                                                 rev).message
 

	
 
        cs_links = " " + ', '.join ([link_to(rev,
 
                url('changeset_home',
 
                repo_name=repo_name,
 
                revision=rev), title=tooltip(message(rev)),
 
                class_='tooltip') for rev in revs[:revs_limit] ])
 
        if len(revs) > revs_limit:
 
            uniq_id = revs[0]
 
            html_tmpl = ('<span> %s '
 
            '<a class="show_more" id="_%s" href="#">%s</a> '
 
            '%s</span>')
 
            cs_links += html_tmpl % (_('and'), uniq_id, _('%s more') \
 
                                        % (len(revs) - revs_limit),
 
                                        _('revisions'))
 

	
rhodecode/public/css/pygments.css
Show inline comments
 
div.codeblock {
 
    overflow: auto;
 
    padding: 0px;
 
    border: 1px solid #ccc;
 
    background: #f8f8f8;
 
    font-size: 100%;
 
    line-height: 100%;
 
    /* new */
 
    line-height: 125%;
 
}
 
div.codeblock .code-header{
 
	border-bottom: 1px solid #CCCCCC;
 
	background: #EEEEEE;
 
	padding:10px 0 10px 0;
 
}
 
div.codeblock .code-header .revision{
 
	margin-left:25px;
 
	font-weight: bold;
 
}
 
div.codeblock .code-header .commit{
 
	margin-left:25px;
 
	font-weight: normal;
 
	white-space:pre;
 
}
 

	
 
div.codeblock .code-body table{
 
    width: 0 !important;    
 
}
 
div.code-body {
 
	background-color: #FFFFFF;
 
}
 
div.code-body pre .match{
 
	background-color: #FAFFA6;
 
}
 
div.code-body pre .break{
 
	background-color: #DDE7EF;
 
	width: 100%;
 
	color: #747474;
 
	display: block;
 
	
 
}
 
div.annotatediv{
 
	margin-left:2px;
 
	margin-right:4px;
 
}
 
.code-highlight {
 
    padding: 0px;
 
    margin-top: 5px;
 
    margin-bottom: 5px;
 
    border-left: 2px solid #ccc;
 
}
 
.code-highlight pre, .linenodiv pre { 
 
	padding: 5px;
 
    margin: 0;
 
}
 
.code-highlight pre div:target { 
 
    background-color: #FFFFBE !important;
 
}
 
    
 
.linenos a { text-decoration: none; }
 

	
 
.code { display: block; }
 
.code-highlight .hll { background-color: #ffffcc }
 
.code-highlight .c { color: #408080; font-style: italic } /* Comment */
 
.code-highlight .err { border: 1px solid #FF0000 } /* Error */
 
.code-highlight .k { color: #008000; font-weight: bold } /* Keyword */
 
.code-highlight .o { color: #666666 } /* Operator */
 
.code-highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
 
.code-highlight .cp { color: #BC7A00 } /* Comment.Preproc */
 
.code-highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
 
.code-highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
 
.code-highlight .gd { color: #A00000 } /* Generic.Deleted */
 
.code-highlight .ge { font-style: italic } /* Generic.Emph */
 
.code-highlight .gr { color: #FF0000 } /* Generic.Error */
 
.code-highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
 
.code-highlight .gi { color: #00A000 } /* Generic.Inserted */
 
.code-highlight .go { color: #808080 } /* Generic.Output */
 
.code-highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
 
.code-highlight .gs { font-weight: bold } /* Generic.Strong */
 
.code-highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
 
.code-highlight .gt { color: #0040D0 } /* Generic.Traceback */
 
.code-highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
 
.code-highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
 
.code-highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
 
.code-highlight .kp { color: #008000 } /* Keyword.Pseudo */
 
.code-highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
 
.code-highlight .kt { color: #B00040 } /* Keyword.Type */
 
.code-highlight .m { color: #666666 } /* Literal.Number */
 
.code-highlight .s { color: #BA2121 } /* Literal.String */
 
.code-highlight .na { color: #7D9029 } /* Name.Attribute */
 
.code-highlight .nb { color: #008000 } /* Name.Builtin */
 
.code-highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
 
.code-highlight .no { color: #880000 } /* Name.Constant */
 
.code-highlight .nd { color: #AA22FF } /* Name.Decorator */
 
.code-highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
 
.code-highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
 
.code-highlight .nf { color: #0000FF } /* Name.Function */
 
.code-highlight .nl { color: #A0A000 } /* Name.Label */
 
.code-highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
 
.code-highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
 
.code-highlight .nv { color: #19177C } /* Name.Variable */
 
.code-highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
 
.code-highlight .w { color: #bbbbbb } /* Text.Whitespace */
 
.code-highlight .mf { color: #666666 } /* Literal.Number.Float */
 
.code-highlight .mh { color: #666666 } /* Literal.Number.Hex */
 
.code-highlight .mi { color: #666666 } /* Literal.Number.Integer */
 
.code-highlight .mo { color: #666666 } /* Literal.Number.Oct */
 
.code-highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
 
.code-highlight .sc { color: #BA2121 } /* Literal.String.Char */
 
.code-highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
 
.code-highlight .s2 { color: #BA2121 } /* Literal.String.Double */
 
.code-highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
 
.code-highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
 
.code-highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
 
.code-highlight .sx { color: #008000 } /* Literal.String.Other */
 
.code-highlight .sr { color: #BB6688 } /* Literal.String.Regex */
 
.code-highlight .s1 { color: #BA2121 } /* Literal.String.Single */
 
.code-highlight .ss { color: #19177C } /* Literal.String.Symbol */
 
.code-highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
 
.code-highlight .vc { color: #19177C } /* Name.Variable.Class */
 
.code-highlight .vg { color: #19177C } /* Name.Variable.Global */
 
.code-highlight .vi { color: #19177C } /* Name.Variable.Instance */
 
.code-highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
rhodecode/templates/files/files_source.html
Show inline comments
 
<dl>
 
	<dt>${_('Revision')}</dt>
 
	<dd>
 
		${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,h.short_id(c.files_list.last_changeset.raw_id)),
 
						h.url('changeset_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.raw_id))} 
 
	</dd>
 
	<dt>${_('Size')}</dt>
 
	<dd>${h.format_byte_size(c.files_list.size,binary=True)}</dd>
 
	<dt>${_('Mimetype')}</dt>
 
	<dd>${c.files_list.mimetype}</dd>
 
	<dt>${_('Options')}</dt>
 
	<dd>${h.link_to(_('show annotation'),
 
			h.url('files_annotate_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
 
		 / ${h.link_to(_('show as raw'),
 
			h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}			
 
		 / ${h.link_to(_('download as raw'),
 
			h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
 
	</dd>
 
	<dt>${_('History')}</dt>
 
	<dd>
 
		<div>
 
		${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
 
		${h.hidden('diff2',c.files_list.last_changeset.raw_id)}
 
		${h.select('diff1',c.files_list.last_changeset.raw_id,c.file_history)}
 
		${h.submit('diff','diff to revision',class_="ui-button")}
 
		${h.submit('show_rev','show at revision',class_="ui-button")}
 
		${h.end_form()}
 
		</div>
 
	</dd>
 
</dl>	
 

	
 
	
 
<div id="body" class="codeblock">
 
	<div class="code-header">
 
		<div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${h.short_id(c.files_list.last_changeset.raw_id)}</div>
 
		<div class="commit">"${c.files_list.last_changeset.message}"</div>
 
	</div>
 
	<div class="code-body">
 
		% if c.files_list.size < c.cut_off_limit:
 
			${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
 
			${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
 
		%else:
 
			${_('File is to big to display')} ${h.link_to(_('show as raw'),
 
			h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
 
		%endif
 
	</div>
 
</div>
 

	
 
<script type="text/javascript">
 
YAHOO.util.Event.onDOMReady(function(){
 
    YAHOO.util.Event.addListener('show_rev','click',function(e){
 
    	YAHOO.util.Event.preventDefault(e);
 
        var cs = YAHOO.util.Dom.get('diff1').value;
 
        var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
 
        window.location = url;
 
        });
 
   });
 
</script>
 
\ No newline at end of file
test.ini
Show inline comments
 
################################################################################
 
################################################################################
 
# rhodecode - Pylons environment configuration                                 #
 
#                                                                              # 
 
# The %(here)s variable will be replaced with the parent directory of this file#
 
################################################################################
 

	
 
[DEFAULT]
 
debug = true
 
################################################################################
 
## Uncomment and replace with the address which should receive                ## 
 
## any error reports after application crash                                  ##
 
## Additionally those settings will be used by rhodecode mailing system       ##
 
################################################################################
 
#email_to = admin@localhost
 
#error_email_from = paste_error@localhost
 
#app_email_from = rhodecode-noreply@localhost
 
#error_message =
 

	
 
#smtp_server = mail.server.com
 
#smtp_username = 
 
#smtp_password = 
 
#smtp_port = 
 
#smtp_use_tls = false
 

	
 
[server:main]
 
##nr of threads to spawn
 
threadpool_workers = 5
 

	
 
##max request before thread respawn
 
threadpool_max_requests = 2
 

	
 
##option to use threads of process
 
use_threadpool = true
 

	
 
use = egg:Paste#http
 
host = 127.0.0.1
 
port = 5000
 

	
 
[app:main]
 
use = egg:rhodecode
 
full_stack = true
 
static_files = true
 
lang=en
 
cache_dir = %(here)s/data
 
index_dir = /tmp/index
 
cut_off_limit = 256000
 
force_https = false
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
 
broker.port = 5672
 
broker.user = rabbitmq
 
broker.password = qweqwe
 

	
 
celery.imports = rhodecode.lib.celerylib.tasks
 

	
 
celery.result.backend = amqp
 
celery.result.dburi = amqp://
 
celery.result.serialier = json
 

	
 
#celery.send.task.error.emails = true
 
#celery.amqp.task.result.expires = 18000
 

	
 
celeryd.concurrency = 2
 
#celeryd.log.file = celeryd.log
 
celeryd.log.level = debug
 
celeryd.max.tasks.per.child = 3
 

	
 
#tasks will never be sent to the queue, but executed locally instead.
 
celery.always.eager = false
 

	
 
####################################
 
###         BEAKER CACHE        ####
 
####################################
 
beaker.cache.data_dir=/%(here)s/data/cache/data
 
beaker.cache.lock_dir=/%(here)s/data/cache/lock
 
beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
 

	
 
beaker.cache.super_short_term.type=memory
 
beaker.cache.super_short_term.expire=10
 

	
 
beaker.cache.short_term.type=memory
 
beaker.cache.short_term.expire=60
 

	
 
beaker.cache.long_term.type=memory
 
beaker.cache.long_term.expire=36000
 

	
 

	
 
beaker.cache.sql_cache_short.type=memory
 
beaker.cache.sql_cache_short.expire=5
 

	
 
beaker.cache.sql_cache_med.type=memory
 
beaker.cache.sql_cache_med.expire=360
 

	
 
beaker.cache.sql_cache_long.type=file
 
beaker.cache.sql_cache_long.expire=3600
 

	
 
####################################
 
###       BEAKER SESSION        ####
 
####################################
 
## Type of storage used for the session, current types are 
 
## dbm, file, memcached, database, and memory. 
 
## The storage uses the Container API 
 
##that is also used by the cache system.
 
beaker.session.type = file
 

	
 
beaker.session.key = rhodecode
 
beaker.session.secret = g654dcno0-9873jhgfreyu
 
beaker.session.timeout = 36000
 

	
 
##auto save the session to not to use .save()
 
beaker.session.auto = False
 

	
 
##true exire at browser close
 
#beaker.session.cookie_expires = 3600
 

	
 
    
 
################################################################################
 
## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*  ##
 
## Debug mode will enable the interactive debugging tool, allowing ANYONE to  ##
 
## execute malicious code after an exception is raised.                       ##
 
################################################################################
 
#set debug = false
 

	
 
##################################
 
###       LOGVIEW CONFIG       ###
 
##################################
 
logview.sqlalchemy = #faa
 
logview.pylons.templating = #bfb
 
logview.pylons.util = #eee
 

	
 
#########################################################
 
### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG    ###
 
#########################################################
 
sqlalchemy.db1.url = sqlite:///%(here)s/test.db
 
#sqlalchemy.db1.url = sqlite:///%(here)s/test.db
 
sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_tests
 
#sqlalchemy.db1.echo = False
 
#sqlalchemy.db1.pool_recycle = 3600
 
sqlalchemy.convert_unicode = true
 

	
 
################################
 
### LOGGING CONFIGURATION   ####
 
################################
 
[loggers]
 
keys = root, routes, rhodecode, sqlalchemy
 

	
 
[handlers]
 
keys = console
 

	
 
[formatters]
 
keys = generic,color_formatter
 

	
 
#############
 
## LOGGERS ##
 
#############
 
[logger_root]
 
level = ERROR
 
handlers = console
 

	
 
[logger_routes]
 
level = ERROR
 
handlers = console
 
qualname = routes.middleware
 
# "level = DEBUG" logs the route matched and routing variables.
 

	
 
[logger_rhodecode]
 
level = ERROR
 
handlers = console
 
qualname = rhodecode
 
propagate = 0
 

	
 
[logger_sqlalchemy]
 
level = ERROR
 
handlers = console
 
qualname = sqlalchemy.engine
 
propagate = 0
 

	
 
##############
 
## HANDLERS ##
 
##############
 

	
 
[handler_console]
 
class = StreamHandler
 
args = (sys.stderr,)
 
level = NOTSET
 
formatter = color_formatter
 

	
 
################
 
## FORMATTERS ##
 
################
 

	
 
[formatter_generic]
 
format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 

	
 
[formatter_color_formatter]
 
class=rhodecode.lib.colored_formatter.ColorFormatter
 
format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 
datefmt = %Y-%m-%d %H:%M:%S
 
\ No newline at end of file
0 comments (0 inline, 0 general)