Changeset - 3246fcce2402
[Not reviewed]
default
0 5 0
Marcin Kuzminski - 14 years ago 2012-01-12 05:21:48
marcin@python-works.com
backported fixes for statistics from beta branch, try to fix issue #271
- version bump
5 files changed with 18 insertions and 15 deletions:
0 comments (0 inline, 0 general)
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>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import platform
 

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

	
 
PLATFORM_WIN = ('Windows')
 
PLATFORM_OTHERS = ('Linux', 'Darwin', 'FreeBSD', 'OpenBSD', 'SunOS')
 

	
 
try:
 
    from rhodecode.lib import get_current_revision
 
    _rev = get_current_revision(quiet=True)
 
except ImportError:
 
    #this is needed when doing some setup.py operations
 
    _rev = False
 

	
 
if len(VERSION) > 3 and _rev:
 
    __version__ += ' [rev:%s]' % _rev[0]
 

	
 

	
 
def get_version():
 
    """Returns shorter version (digit parts only) as string."""
 

	
 
    return '.'.join((str(each) for each in VERSION[:3]))
 

	
 
BACKENDS = {
 
    'hg': 'Mercurial repository',
 
    #'git': 'Git repository',
 
}
rhodecode/controllers/summary.py
Show inline comments
 
@@ -22,162 +22,164 @@
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

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

	
 
from vcs.exceptions import ChangesetError
 

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

	
 
from rhodecode.model.db import Statistics, Repository
 
from rhodecode.model.repo import RepoModel
 

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

	
 
from rhodecode.lib.celerylib import run_task
 
from rhodecode.lib.celerylib.tasks import get_commits_stats, \
 
    LANGUAGES_EXTENSIONS_MAP
 
from rhodecode.lib.helpers import RepoPage
 
from rhodecode.lib.compat import json, OrderedDict
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SummaryController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def __before__(self):
 
        super(SummaryController, self).__before__()
 

	
 
    def index(self, repo_name):
 

	
 
        e = request.environ
 
        c.dbrepo = dbrepo = c.rhodecode_db_repo
 

	
 
        c.following = self.scm_model.is_following_repo(repo_name,
 
                                                self.rhodecode_user.user_id)
 

	
 
        def url_generator(**kw):
 
            return url('shortlog_home', repo_name=repo_name, size=10, **kw)
 

	
 
        c.repo_changesets = RepoPage(c.rhodecode_repo, page=1,
 
                                     items_per_page=10, url=url_generator)
 

	
 
        if self.rhodecode_user.username == 'default':
 
            #for default(anonymous) user we don't need to pass credentials
 
            username = ''
 
            password = ''
 
        else:
 
            username = str(self.rhodecode_user.username)
 
            password = '@'
 

	
 
        if e.get('wsgi.url_scheme') == 'https':
 
            split_s = 'https://'
 
        else:
 
            split_s = 'http://'
 

	
 
        qualified_uri = [split_s] + [url.current(qualified=True)\
 
                                     .split(split_s)[-1]]
 
        uri = u'%(proto)s%(user)s%(pass)s%(rest)s' \
 
                % {'user': username,
 
                     'pass': password,
 
                     'proto': qualified_uri[0],
 
                     'rest': qualified_uri[1]}
 
        c.clone_repo_url = uri
 
        c.repo_tags = OrderedDict()
 
        for name, hash in c.rhodecode_repo.tags.items()[:10]:
 
            try:
 
                c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash)
 
            except ChangesetError:
 
                c.repo_tags[name] = EmptyChangeset(hash)
 

	
 
        c.repo_branches = OrderedDict()
 
        for name, hash in c.rhodecode_repo.branches.items()[:10]:
 
            try:
 
                c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash)
 
            except ChangesetError:
 
                c.repo_branches[name] = EmptyChangeset(hash)
 

	
 
        td = date.today() + timedelta(days=1)
 
        td_1m = td - timedelta(days=calendar.mdays[td.month])
 
        td_1y = td - timedelta(days=365)
 

	
 
        ts_min_m = mktime(td_1m.timetuple())
 
        ts_min_y = mktime(td_1y.timetuple())
 
        ts_max_y = mktime(td.timetuple())
 

	
 
        if dbrepo.enable_statistics:
 
            c.show_stats = True
 
            c.no_data_msg = _('No data loaded yet')
 
            run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y)
 
        else:
 
            c.show_stats = False
 
            c.no_data_msg = _('Statistics are disabled for this repository')
 
        c.ts_min = ts_min_m
 
        c.ts_max = ts_max_y
 

	
 
        stats = self.sa.query(Statistics)\
 
            .filter(Statistics.repository == dbrepo)\
 
            .scalar()
 

	
 
        c.stats_percentage = 0
 

	
 
        if stats and stats.languages:
 
            c.no_data = False is dbrepo.enable_statistics
 
            lang_stats_d = json.loads(stats.languages)
 
            c.commit_data = stats.commit_activity
 
            c.overview_data = stats.commit_activity_combined
 

	
 
            lang_stats = ((x, {"count": y,
 
                               "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
 
                          for x, y in lang_stats_d.items())
 

	
 
            c.trending_languages = json.dumps(OrderedDict(
 
                                       sorted(lang_stats, reverse=True,
 
                                            key=lambda k: k[1])[:10]
 
                                        )
 
                                    )
 
            last_rev = stats.stat_on_revision
 
            c.repo_last_rev = c.rhodecode_repo.count() - 1 \
 
            last_rev = stats.stat_on_revision + 1
 
            c.repo_last_rev = c.rhodecode_repo.count()\
 
                if c.rhodecode_repo.revisions else 0
 
            if last_rev == 0 or c.repo_last_rev == 0:
 
                pass
 
            else:
 
                c.stats_percentage = '%.2f' % ((float((last_rev)) /
 
                                                c.repo_last_rev) * 100)
 
        else:
 
            c.commit_data = json.dumps({})
 
            c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
 
            c.trending_languages = json.dumps({})
 
            c.no_data = True
 

	
 
        c.enable_downloads = dbrepo.enable_downloads
 
        if c.enable_downloads:
 
            c.download_options = self._get_download_links(c.rhodecode_repo)
 

	
 
        return render('summary/summary.html')
 

	
 
    def _get_download_links(self, repo):
 

	
 
        download_l = []
 

	
 
        branches_group = ([], _("Branches"))
 
        tags_group = ([], _("Tags"))
 

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

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

	
 
        return download_l
rhodecode/lib/celerylib/tasks.py
Show inline comments
 
@@ -7,240 +7,241 @@
 
    by celery daemon
 

	
 
    :created_on: Oct 6, 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, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
from celery.decorators import task
 

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

	
 
from time import mktime
 
from operator import itemgetter
 
from string import lower
 

	
 
from pylons import config, url
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import LANGUAGES_EXTENSIONS_MAP, safe_str
 
from rhodecode.lib.celerylib import run_task, locked_task, str2bool, \
 
    __get_lockkey, LockHeld, DaemonLock
 
from rhodecode.lib.helpers import person
 
from rhodecode.lib.smtp_mailer import SmtpMailer
 
from rhodecode.lib.utils import add_cache
 
from rhodecode.lib.compat import json, OrderedDict
 

	
 
from rhodecode.model import init_model
 
from rhodecode.model import meta
 
from rhodecode.model.db import RhodeCodeUi, Statistics, Repository, User
 

	
 
from vcs.backends import get_repo
 

	
 
from sqlalchemy import engine_from_config
 

	
 
add_cache(config)
 

	
 
__all__ = ['whoosh_index', 'get_commits_stats',
 
           'reset_user_password', 'send_email']
 

	
 
CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
 

	
 

	
 
def get_session():
 
    if CELERY_ON:
 
        engine = engine_from_config(config, 'sqlalchemy.db1.')
 
        init_model(engine)
 

	
 
    sa = meta.Session()
 
    return sa
 

	
 

	
 
def get_repos_path():
 
    sa = get_session()
 
    q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
 
    return q.ui_value
 

	
 

	
 
@task(ignore_result=True)
 
@locked_task
 
def whoosh_index(repo_location, full_index):
 
    #log = whoosh_index.get_logger()
 
    from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
 
    index_location = config['index_dir']
 
    WhooshIndexingDaemon(index_location=index_location,
 
                         repo_location=repo_location, sa=get_session())\
 
                         .run(full_index=full_index)
 

	
 

	
 
@task(ignore_result=True)
 
def get_commits_stats(repo_name, ts_min_y, ts_max_y):
 
    try:
 
        log = get_commits_stats.get_logger()
 
    except:
 
        log = logging.getLogger(__name__)
 

	
 
    lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
 
                            ts_max_y)
 
    lockkey_path = config['here']
 

	
 
    log.info('running task with lockkey %s', lockkey)
 
    try:
 
        sa = get_session()
 
        lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
 

	
 
        # for js data compatibilty cleans the key for person from '
 
        akc = lambda k: person(k).replace('"', "")
 

	
 
        co_day_auth_aggr = {}
 
        commits_by_day_aggregate = {}
 
        repos_path = get_repos_path()
 
        repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
 
        repo_size = len(repo.revisions)
 
        repo_size = repo.count()
 
        #return if repo have no revisions
 
        if repo_size < 1:
 
            lock.release()
 
            return True
 

	
 
        skip_date_limit = True
 
        parse_limit = int(config['app_conf'].get('commit_parse_limit'))
 
        last_rev = 0
 
        last_rev = None
 
        last_cs = None
 
        timegetter = itemgetter('time')
 

	
 
        sa = get_session()
 

	
 
        dbrepo = sa.query(Repository)\
 
            .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
 

	
 
        if last_rev == repo.get_changeset().revision and repo_size > 1:
 
            #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
 
            lock.release()
 
            return True
 

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

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

	
 
        last_rev = last_rev + 1 if last_rev > 0 else last_rev
 

	
 
        last_rev = last_rev + 1 if last_rev >= 0 else 0
 
        log.debug('Getting revisions from %s to %s' % (
 
             last_rev, last_rev + parse_limit)
 
        )
 
        for cs in repo[last_rev:last_rev + parse_limit]:
 
            last_cs = cs  # remember last parsed changeset
 
            k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
 
                          cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
 

	
 
            if akc(cs.author) in co_day_auth_aggr:
 
                try:
 
                    l = [timegetter(x) for x in
 
                         co_day_auth_aggr[akc(cs.author)]['data']]
 
                    time_pos = l.index(k)
 
                except ValueError:
 
                    time_pos = False
 

	
 
                if time_pos >= 0 and time_pos is not False:
 

	
 
                    datadict = \
 
                        co_day_auth_aggr[akc(cs.author)]['data'][time_pos]
 

	
 
                    datadict["commits"] += 1
 
                    datadict["added"] += len(cs.added)
 
                    datadict["changed"] += len(cs.changed)
 
                    datadict["removed"] += len(cs.removed)
 

	
 
                else:
 
                    if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
 

	
 
                        datadict = {"time": k,
 
                                    "commits": 1,
 
                                    "added": len(cs.added),
 
                                    "changed": len(cs.changed),
 
                                    "removed": len(cs.removed),
 
                                   }
 
                        co_day_auth_aggr[akc(cs.author)]['data']\
 
                            .append(datadict)
 

	
 
            else:
 
                if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
 
                    co_day_auth_aggr[akc(cs.author)] = {
 
                                        "label": akc(cs.author),
 
                                        "data": [{"time":k,
 
                                                 "commits":1,
 
                                                 "added":len(cs.added),
 
                                                 "changed":len(cs.changed),
 
                                                 "removed":len(cs.removed),
 
                                                 }],
 
                                        "schema": ["commits"],
 
                                        }
 

	
 
            #gather all data by day
 
            if k in commits_by_day_aggregate:
 
                commits_by_day_aggregate[k] += 1
 
            else:
 
                commits_by_day_aggregate[k] = 1
 

	
 
        overview_data = sorted(commits_by_day_aggregate.items(),
 
                               key=itemgetter(0))
 

	
 
        if not co_day_auth_aggr:
 
            co_day_auth_aggr[akc(repo.contact)] = {
 
                "label": akc(repo.contact),
 
                "data": [0, 1],
 
                "schema": ["commits"],
 
            }
 

	
 
        stats = cur_stats if cur_stats else Statistics()
 
        stats.commit_activity = json.dumps(co_day_auth_aggr)
 
        stats.commit_activity_combined = json.dumps(overview_data)
 

	
 
        log.debug('last revison %s', last_rev)
 
        leftovers = len(repo.revisions[last_rev:])
 
        log.debug('revisions to parse %s', leftovers)
 

	
 
        if last_rev == 0 or leftovers < parse_limit:
 
            log.debug('getting code trending stats')
 
            stats.languages = json.dumps(__get_codes_stats(repo_name))
 

	
 
        try:
 
            stats.repository = dbrepo
 
            stats.stat_on_revision = last_cs.revision if last_cs else 0
 
            sa.add(stats)
 
            sa.commit()
 
        except:
 
            log.error(traceback.format_exc())
 
            sa.rollback()
 
            lock.release()
 
            return False
 

	
 
        # final release
 
        lock.release()
 

	
 
        # execute another task if celery is enabled
 
        if len(repo.revisions) > 1 and CELERY_ON:
 
            run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
 
        return True
 
    except LockHeld:
 
        log.info('LockHeld')
rhodecode/tests/functional/test_summary.py
Show inline comments
 
from rhodecode.tests import *
 
from rhodecode.model.db import Repository
 
from rhodecode.lib.utils import invalidate_cache
 

	
 

	
 
class TestSummaryController(TestController):
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(url(controller='summary',
 
                                    action='index', repo_name=HG_REPO))
 

	
 
        #repo type
 
        self.assertTrue("""<img style="margin-bottom:2px" class="icon" """
 
                        """title="Mercurial repository" alt="Mercurial """
 
                        """repository" src="/images/icons/hgicon.png"/>"""
 
                        in response.body)
 
        self.assertTrue("""<img style="margin-bottom:2px" class="icon" """
 
                        """title="public repository" alt="public """
 
                        """repository" src="/images/icons/lock_open.png"/>"""
 
                        in response.body)
 

	
 
        #codes stats
 
        self._enable_stats()
 

	
 

	
 
        invalidate_cache('get_repo_cached_%s' % HG_REPO)
 
        response = self.app.get(url(controller='summary', action='index',
 
                                    repo_name=HG_REPO))
 

	
 
        self.assertTrue("""var data = {"py": {"count": 42, "desc": """
 
        response.mustcontain(
 
            """var data = {"py": {"count": 42, "desc": """
 
                        """["Python"]}, "rst": {"count": 11, "desc": """
 
                        """["Rst"]}, "sh": {"count": 2, "desc": ["Bash"]}, """
 
                        """"makefile": {"count": 1, "desc": ["Makefile", """
 
                        """"Makefile"]}, "cfg": {"count": 1, "desc": ["Ini"]},"""
 
                        """ "css": {"count": 1, "desc": ["Css"]}, "bat": """
 
                        """{"count": 1, "desc": ["Batch"]}};"""
 
                        in response.body)
 
        )
 

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

	
 
        response.mustcontain("""<input type="text" id="clone_url" readonly="readonly" value="hg clone http://test_admin@localhost:80/%s" size="70"/>""" % HG_REPO)
 

	
 
    def _enable_stats(self):
 
        r = Repository.get_by_repo_name(HG_REPO)
 
        r.enable_statistics = True
 
        self.sa.add(r)
 
        self.sa.commit()
setup.py
Show inline comments
 
import sys
 
from rhodecode import get_version
 
from rhodecode import __platform__
 
from rhodecode import __license__
 
from rhodecode import PLATFORM_OTHERS
 

	
 
py_version = sys.version_info
 

	
 
if py_version < (2, 5):
 
    raise Exception('RhodeCode requires python 2.5 or later')
 

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

	
 
dependency_links = [
 
]
 

	
 
classifiers = ['Development Status :: 5 - Production/Stable',
 
               'Environment :: Web Environment',
 
               'Framework :: Pylons',
 
               'Intended Audience :: Developers',
 
               'License :: OSI Approved :: GNU General Public License (GPL)',
 
               'Operating System :: OS Independent',
 
               'Programming Language :: Python',
 
               'Programming Language :: Python :: 2.5',
 
               'Programming Language :: Python :: 2.6',
 
               'Programming Language :: Python :: 2.7', ]
 

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

	
 
if __platform__ in PLATFORM_OTHERS:
 
    requirements.append("py-bcrypt")
 

	
 

	
 
# additional files from project that goes somewhere in the filesystem
 
# relative to sys.prefix
 
data_files = []
 

	
 
# additional files that goes into package itself
 
package_data = {'rhodecode': ['i18n/*/LC_MESSAGES/*.mo', ], }
 

	
 
description = ('Mercurial repository browser/management with '
 
               'build in push/pull server and full text search')
 
keywords = ' '.join(['rhodecode', 'rhodiumcode', 'mercurial', 'git',
 
                     'code review', 'repo groups', 'ldap'
 
                      'repository management', 'hgweb replacement'
 
                      'hgwebdir', 'gitweb replacement', 'serving hgweb', ])
 
# long description
 
try:
 
    readme_file = 'README.rst'
 
    changelog_file = 'docs/changelog.rst'
 
    long_description = open(readme_file).read() + '\n\n' + \
 
        open(changelog_file).read()
 

	
 
except IOError, err:
 
    sys.stderr.write("[WARNING] Cannot find file specified as "
 
        "long_description (%s)\n or changelog (%s) skipping that file" \
 
            % (readme_file, changelog_file))
 
    long_description = description
 

	
 

	
 
try:
 
    from setuptools import setup, find_packages
 
except ImportError:
 
    from ez_setup import use_setuptools
 
    use_setuptools()
 
    from setuptools import setup, find_packages
 
# packages
 
packages = find_packages(exclude=['ez_setup'])
 

	
 
setup(
 
    name='RhodeCode',
 
    version=get_version(),
 
    description=description,
 
    long_description=long_description,
 
    keywords=keywords,
 
    license=__license__,
 
    author='Marcin Kuzminski',
 
    author_email='marcin@python-works.com',
 
    dependency_links=dependency_links,
 
    url='http://rhodecode.org',
 
    install_requires=requirements,
 
    classifiers=classifiers,
 
    setup_requires=["PasteScript>=1.6.3"],
 
    data_files=data_files,
 
    packages=packages,
 
    include_package_data=True,
 
    test_suite='nose.collector',
 
    package_data=package_data,
 
    message_extractors={'rhodecode': [
 
            ('**.py', 'python', None),
 
            ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
 
            ('templates/**.html', 'mako', {'input_encoding': 'utf-8'}),
 
            ('public/**', 'ignore', None)]},
 
    zip_safe=False,
 
    paster_plugins=['PasteScript', 'Pylons'],
 
    entry_points="""
 
    [paste.app_factory]
 
    main = rhodecode.config.middleware:make_app
 

	
 
    [paste.app_install]
 
    main = pylons.util:PylonsInstaller
 

	
 
    [paste.global_paster_command]
 
    make-index = rhodecode.lib.indexers:MakeIndex
0 comments (0 inline, 0 general)