# -*- 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>
: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 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.odict import OrderedDict
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
try:
import json
except ImportError:
#python 2.5 compatibility
import simplejson as json
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 = Repository.by_repo_name(repo_name)
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://'
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]:
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]:
c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash)
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.no_data_msg = _('No data loaded yet')
run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y)
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 \
if c.rhodecode_repo.revisions else 0
if last_rev == 0 or c.repo_last_rev == 0:
pass
c.stats_percentage = '%.2f' % ((float((last_rev)) /
c.repo_last_rev) * 100)
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
rhodecode.lib.__init__
~~~~~~~~~~~~~~~~~~~~~~~
Some simple helper functions
:created_on: Jan 5, 2011
:copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
def __get_lem():
from pygments import lexers
from string import lower
from collections import defaultdict
d = defaultdict(lambda: [])
def __clean(s):
s = s.lstrip('*')
s = s.lstrip('.')
if s.find('[') != -1:
exts = []
start, stop = s.find('['), s.find(']')
for suffix in s[start + 1:stop]:
exts.append(s[:s.find('[')] + suffix)
return map(lower, exts)
return map(lower, [s])
for lx, t in sorted(lexers.LEXERS.items()):
m = map(__clean, t[-2])
if m:
m = reduce(lambda x, y: x + y, m)
for ext in m:
desc = lx.replace('Lexer', '')
d[ext].append(desc)
return dict(d)
# language map is also used by whoosh indexer, which for those specified
# extensions will index it's content
LANGUAGES_EXTENSIONS_MAP = __get_lem()
# Additional mappings that are not present in the pygments lexers
# NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
ADDITIONAL_MAPPINGS = {'xaml': 'XAML'}
LANGUAGES_EXTENSIONS_MAP.update(ADDITIONAL_MAPPINGS)
def str2bool(_str):
returs True/False value from given string, it tries to translate the
string into boolean
:param _str: string value to translate into boolean
:rtype: boolean
:returns: boolean from given string
if _str is None:
return False
if _str in (True, False):
return _str
_str = str(_str).strip().lower()
return _str in ('t', 'true', 'y', 'yes', 'on', '1')
def convert_line_endings(temp, mode):
def convert_line_endings(line, mode):
Converts a given line "line end" accordingly to given mode
Available modes are::
0 - Unix
1 - Mac
2 - DOS
:param line: given line to convert
:param mode: mode to convert to
:rtype: str
:return: converted line according to mode
from string import replace
#modes: 0 - Unix, 1 - Mac, 2 - DOS
if mode == 0:
temp = replace(temp, '\r\n', '\n')
temp = replace(temp, '\r', '\n')
line = replace(line, '\r\n', '\n')
line = replace(line, '\r', '\n')
elif mode == 1:
temp = replace(temp, '\r\n', '\r')
temp = replace(temp, '\n', '\r')
line = replace(line, '\r\n', '\r')
line = replace(line, '\n', '\r')
elif mode == 2:
import re
temp = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", temp)
return temp
line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
return line
def detect_mode(line, default):
Detects line break for given line, if line break couldn't be found
given default value is returned
:param line: str line
:param default: default
:rtype: int
:return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
if line.endswith('\r\n'):
return 2
elif line.endswith('\n'):
return 0
elif line.endswith('\r'):
return 1
return default
def generate_api_key(username, salt=None):
Generates unique API key for given username,if salt is not given
it'll be generated from some random string
:param username: username as string
:param salt: salt to hash generate KEY
:returns: sha1 hash from username+salt
from tempfile import _RandomNameSequence
import hashlib
if salt is None:
salt = _RandomNameSequence().next()
return hashlib.sha1(username + salt).hexdigest()
def safe_unicode(_str, from_encoding='utf8'):
safe unicode function. In case of UnicodeDecode error we try to return
unicode with errors replace
:param _str: string to decode
:rtype: unicode
:returns: unicode object
if isinstance(_str, unicode):
u_str = unicode(_str, from_encoding)
except UnicodeDecodeError:
u_str = unicode(_str, from_encoding, 'replace')
return u_str
def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
Custom engine_from_config functions that makes sure we use NullPool for
file based sqlite databases. This prevents errors on sqlite. This only
applies to sqlalchemy versions < 0.7.0
import sqlalchemy
from sqlalchemy import engine_from_config as efc
if int(sqlalchemy.__version__.split('.')[1]) < 7:
# This solution should work for sqlalchemy < 0.7.0, and should use
# proxy=TimerProxy() for execution time profiling
from sqlalchemy.pool import NullPool
url = configuration[prefix + 'url']
if url.startswith('sqlite'):
kwargs.update({'poolclass': NullPool})
return efc(configuration, prefix, **kwargs)
import time
from sqlalchemy import event
from sqlalchemy.engine import Engine
log = logging.getLogger('sqlalchemy.engine')
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
engine = efc(configuration, prefix, **kwargs)
def color_sql(sql):
COLOR_SEQ = "\033[1;%dm"
COLOR_SQL = YELLOW
normal = '\x1b[0m'
return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
if configuration['debug']:
#attach events only for debug configuration
def before_cursor_execute(conn, cursor, statement,
parameters, context, executemany):
context._query_start_time = time.time()
log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
def after_cursor_execute(conn, cursor, statement,
total = time.time() - context._query_start_time
log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
event.listen(engine, "before_cursor_execute",
before_cursor_execute)
event.listen(engine, "after_cursor_execute",
after_cursor_execute)
return engine
def age(curdate):
turns a datetime into an age string.
:param curdate: datetime object
:returns: unicode words describing age
from datetime import datetime
from webhelpers.date import time_ago_in_words
_ = lambda s:s
if not curdate:
return ''
agescales = [(_(u"year"), 3600 * 24 * 365),
(_(u"month"), 3600 * 24 * 30),
(_(u"day"), 3600 * 24),
(_(u"hour"), 3600),
(_(u"minute"), 60),
(_(u"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 '%s %s' % (time_ago_in_words(curdate,
agescales[pos][0]), _('ago'))
pos += 1
return _(u'just now')
def credentials_hidder(uri):
def uri_filter(uri):
Removes user:password from given url string
:param uri:
:returns: filtered list of strings
if not uri:
proto = ''
for pat in ('https://', 'http://'):
if uri.startswith(pat):
uri = uri[len(pat):]
proto = pat
break
# remove passwords and username
uri = uri[uri.find('@') + 1:]
# get the port
cred_pos = uri.find(':')
if cred_pos == -1:
host, port = uri, None
host, port = uri[:cred_pos], uri[cred_pos + 1:]
return filter(None, [proto, host, port])
def credentials_filter(uri):
Returns a url with removed credentials
uri = uri_filter(uri)
#check if we have port
if len(uri) > 2 and uri[2]:
uri[2] = ':' + uri[2]
return ''.join(uri)
"""The base Controller API
Provides the BaseController class for subclassing.
from pylons import config, tmpl_context as c, request, session
from pylons import config, tmpl_context as c, request, session, url
from pylons.controllers import WSGIController
from pylons.controllers.util import redirect
from pylons.templating import render_mako as render
from rhodecode import __version__
from rhodecode.lib.auth import AuthUser
from rhodecode.lib.utils import get_repo_slug
from rhodecode.model import meta
from rhodecode.model.scm import ScmModel
from rhodecode import BACKENDS
from rhodecode.model.db import Repository
class BaseController(WSGIController):
c.rhodecode_version = __version__
c.rhodecode_name = config.get('rhodecode_title')
c.ga_code = config.get('rhodecode_ga_code')
c.repo_name = get_repo_slug(request)
c.backends = BACKENDS.keys()
self.cut_off_limit = int(config.get('cut_off_limit'))
self.sa = meta.Session()
self.scm_model = ScmModel(self.sa)
#c.unread_journal = scm_model.get_unread_journal()
def __call__(self, environ, start_response):
"""Invoke the Controller"""
# WSGIController.__call__ dispatches to the Controller method
# the request is routed to. This routing information is
# available in environ['pylons.routes_dict']
# putting this here makes sure that we update permissions each time
api_key = request.GET.get('api_key')
user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
self.rhodecode_user = c.rhodecode_user = AuthUser(user_id, api_key)
self.rhodecode_user.set_authenticated(
getattr(session.get('rhodecode_user'),
'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)
super(BaseRepoController, self).__before__()
if c.repo_name:
c.rhodecode_repo = Repository.by_repo_name(c.repo_name).scm_instance
c.rhodecode_db_repo = Repository.by_repo_name(c.repo_name)
c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
if c.rhodecode_repo is None:
log.error('%s this repository is present in database but it '
'cannot be created as an scm instance', c.repo_name)
if c.rhodecode_repo is not None:
c.repository_followers = \
self.scm_model.get_followers(c.repo_name)
c.repository_forks = self.scm_model.get_forks(c.repo_name)
c.repository_followers = 0
c.repository_forks = 0
redirect(url('home'))
@@ -228,201 +228,201 @@ class CodeHtmlFormatter(HtmlFormatter):
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
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 _ 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]
col = color_dict[cs] = cgenerator.next()
return "color: rgb(%s)! important;" % (', '.join(col))
def url_func(repo_name):
def _url_func(changeset):
author = changeset.author
date = changeset.date
message = tooltip(changeset.message)
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 % (author, date, message)
lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
short_id(changeset.raw_id))
uri = link_to(
lnk_format,
url('changeset_home', repo_name=repo_name,
revision=changeset.raw_id),
style=get_color_string(changeset.raw_id),
class_='tooltip',
title=tooltip_html
uri += '\n'
return uri
return _url_func
return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
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))
cs = repo.get_changeset(rev)
except RepositoryError:
cs = EmptyChangeset()
return cs
def is_following_repo(repo_name, user_id):
return ScmModel().is_following_repo(repo_name, user_id)
flash = _Flash()
#==============================================================================
# SCM FILTERS available via h.
from vcs.utils import author_name, author_email
from rhodecode.lib import credentials_hidder, age as _age
from rhodecode.lib import credentials_filter, age as _age
age = lambda x:_age(x)
capitalize = lambda x: x.capitalize()
email = author_email
email_or_none = lambda x: email(x) if email(x) != x else None
person = lambda x: author_name(x)
short_id = lambda x: x[:12]
hide_credentials = lambda x: ''.join(credentials_hidder(x))
hide_credentials = lambda x: ''.join(credentials_filter(x))
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
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
repo = user_log.repository.scm_instance
message = lambda rev: get_changeset_safe(repo, rev).message
cs_links = []
cs_links.append(" " + ', '.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] ]))
compare_view = (' <div class="compare_view tooltip" title="%s">'
'<a href="%s">%s</a> '
'</div>' % (_('Show all combined changesets %s->%s' \
% (revs[0], revs[-1])),
revision='%s...%s' % (revs[0], revs[-1])
),
_('compare view'))
if len(revs) > revs_limit:
uniq_id = revs[0]
html_tmpl = ('<span> %s '
'<a class="show_more" id="_%s" href="#more">%s</a> '
'%s</span>')
if not feed:
cs_links.append(html_tmpl % (_('and'), uniq_id, _('%s more') \
% (len(revs) - revs_limit),
_('revisions')))
html_tmpl = '<span id="%s" style="display:none"> %s </span>'
html_tmpl = '<span id="%s"> %s </span>'
cs_links.append(html_tmpl % (uniq_id, ', '.join([link_to(rev,
repo_name=repo_name, revision=rev),
title=message(rev), class_='tooltip')
for rev in revs[revs_limit:revs_top_limit]])))
if len(revs) > 1:
cs_links.append(compare_view)
return ''.join(cs_links)
def get_fork_name():
repo_name = action_params
return _('fork name ') + str(link_to(action_params, url('summary_home',
repo_name=repo_name,)))
action_map = {'user_deleted_repo':(_('[deleted] repository'), None),
'user_created_repo':(_('[created] repository'), None),
'user_forked_repo':(_('[forked] repository'), get_fork_name),
'user_updated_repo':(_('[updated] repository'), None),
'admin_deleted_repo':(_('[delete] repository'), None),
@@ -19,193 +19,197 @@
import os
import traceback
from mercurial import ui
from sqlalchemy.exc import DatabaseError
from sqlalchemy.orm import make_transient
from beaker.cache import cache_region, region_invalidate
from vcs import get_backend
from vcs.utils.helpers import get_scm
from vcs.exceptions import RepositoryError, VCSError
from vcs.utils.lazy import LazyProperty
from vcs.nodes import FileNode
from rhodecode.lib import helpers as h
from rhodecode.lib.auth import HasRepoPermissionAny
from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
action_logger
from rhodecode.model import BaseModel
from rhodecode.model.user import UserModel
from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
UserFollowing, UserLog
from rhodecode.model.caching_query import FromCache
class UserTemp(object):
def __init__(self, user_id):
self.user_id = user_id
def __repr__(self):
return "<%s('id:%s')>" % (self.__class__.__name__, self.user_id)
class RepoTemp(object):
def __init__(self, repo_id):
self.repo_id = repo_id
return "<%s('id:%s')>" % (self.__class__.__name__, self.repo_id)
class CachedRepoList(object):
def __init__(self, db_repo_list, invalidation_list, repos_path,
order_by=None):
self.db_repo_list = db_repo_list
self.invalidation_list = invalidation_list
self.repos_path = repos_path
self.order_by = order_by
self.reversed = (order_by or '').startswith('-')
def __len__(self):
return len(self.db_repo_list)
return '<%s (%s)>' % (self.__class__.__name__, self.__len__())
def __iter__(self):
for db_repo in self.db_repo_list:
dbr = db_repo
# invalidate the repo cache if needed before getting the
# scm instance
scm_invalidate = False
if self.invalidation_list is not None:
scm_invalidate = dbr.repo_name in self.invalidation_list
if scm_invalidate:
log.info('invalidating cache for repository %s',
dbr.repo_name)
db_repo.set_invalidate
scmr = db_repo.scm_instance_cached
#check permission at this level
if not HasRepoPermissionAny('repository.read',
'repository.write',
'repository.admin')(dbr.repo_name,
'get repo check'):
continue
if not scmr:
'cannot be created as an scm instance',
last_change = scmr.last_change
tip = h.get_changeset_safe(scmr, 'tip')
tmp_d = {}
tmp_d['name'] = dbr.repo_name
tmp_d['name_sort'] = tmp_d['name'].lower()
tmp_d['description'] = dbr.description
tmp_d['description_sort'] = tmp_d['description']
tmp_d['last_change'] = last_change
tmp_d['last_change_sort'] = time.mktime(last_change \
.timetuple())
tmp_d['tip'] = tip.raw_id
tmp_d['tip_sort'] = tip.revision
tmp_d['rev'] = tip.revision
tmp_d['contact'] = dbr.user.full_contact
tmp_d['contact_sort'] = tmp_d['contact']
tmp_d['owner_sort'] = tmp_d['contact']
tmp_d['repo_archives'] = list(scmr._get_archives())
tmp_d['last_msg'] = tip.message
tmp_d['repo'] = scmr
tmp_d['dbrepo'] = dbr.get_dict()
tmp_d['dbrepo_fork'] = dbr.fork.get_dict() if dbr.fork \
else {}
yield tmp_d
class ScmModel(BaseModel):
"""Generic Scm Model
@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
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):
if name in repos_list:
raise RepositoryError('Duplicate repository name %s '
'found in %s' % (name, path))
klass = get_backend(path[0])
if path[0] == 'hg' and path[0] in BACKENDS.keys():
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:
return repos_list
def get_repos(self, all_repos=None, sort_key=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: list of repository names as strings
give specific repositories list, good for filtering
if all_repos is None:
all_repos = self.sa.query(Repository)\
.filter(Repository.group_id == None)\
.order_by(Repository.repo_name).all()
#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)\
.all()]
repo_iter = CachedRepoList(all_repos, invalidation_list,
repos_path=self.repos_path,
order_by=sort_key)
import unittest
from rhodecode.tests import *
@@ -47,161 +47,173 @@ cache_dir = /tmp/data
index_dir = /tmp/index
app_instance_uuid = develop-test
cut_off_limit = 256000
force_https = false
commit_parse_limit = 25
####################################
### 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 = 1
#tasks will never be sent to the queue, but executed locally instead.
celery.always.eager = false
### BEAKER CACHE ####
beaker.cache.data_dir=/tmp/data/cache/data
beaker.cache.lock_dir=/tmp/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/test.db
sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_tests
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,beaker,templates
[handlers]
keys = console
[formatters]
keys = generic,color_formatter
#############
## LOGGERS ##
[logger_root]
level = ERROR
handlers = console
[logger_routes]
qualname = routes.middleware
# "level = DEBUG" logs the route matched and routing variables.
[logger_beaker]
level = DEBUG
handlers =
qualname = beaker.container
propagate = 1
[logger_templates]
level = INFO
qualname = pylons.templating
[logger_rhodecode]
qualname = rhodecode
propagate = 0
[logger_sqlalchemy]
qualname = sqlalchemy.engine
##############
## 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
\ No newline at end of file
Status change: