##// END OF EJS Templates
merged dev into stable
merged dev into stable

File last commit:

r3700:3563bb7b merge default
r3965:5aa571d5 merge default
Show More
tasks.py
391 lines | 13.5 KiB | text/x-python | PythonLexer
code docs, updates
r903 # -*- coding: utf-8 -*-
"""
rhodecode.lib.celerylib.tasks
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
code docs, updates
r903
RhodeCode task modules, containing all task that suppose to be run
by celery daemon
source code cleanup: remove trailing white space, normalize file endings
r1203
code docs, updates
r903 :created_on: Oct 6, 2010
:author: marcink
2012 copyrights
r1824 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
code docs, updates
r903 :license: GPLv3, see COPYING for more details.
"""
fixed license issue #149
r1206 # 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.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
code docs, updates
r903 # 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.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
code docs, updates
r903 # You should have received a copy of the GNU General Public License
fixed license issue #149
r1206 # along with this program. If not, see <http://www.gnu.org/licenses/>.
renamed project to rhodecode
r547 from celery.decorators import task
added fault tolerant case when celeryconfig is not present in the directory....
r555
#50 on point cache invalidation changes....
r692 import os
import traceback
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 import logging
Notification fixes...
r1717 from os.path import join as jn
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002
#50 on point cache invalidation changes....
r692 from time import mktime
renamed project to rhodecode
r547 from operator import itemgetter
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244 from string import lower
Celery is configured by the .ini files and run from paster now...
r776
fixes #223 improve password reset form
r1417 from pylons import config, url
renamed project to rhodecode
r547 from pylons.i18n.translation import _
Celery is configured by the .ini files and run from paster now...
r776
Added VCS into rhodecode core for faster and easier deployments of new versions
r2007 from rhodecode.lib.vcs import get_backend
Notification fixes...
r1717
Don't clear dbsessions when celery_eager is turned on
r2299 from rhodecode import CELERY_ON, CELERY_EAGER
utils/conf...
r2109 from rhodecode.lib.utils2 import safe_str
fixes #340 session cleanup for celery tasks
r1929 from rhodecode.lib.celerylib import run_task, locked_task, dbsession, \
str2bool, __get_lockkey, LockHeld, DaemonLock, get_session
renamed project to rhodecode
r547 from rhodecode.lib.helpers import person
Notification fixes...
r1717 from rhodecode.lib.rcmail.smtp_mailer import SmtpMailer
#235 forking page repo group selection...
r1722 from rhodecode.lib.utils import add_cache, action_logger
fixed issues with python2.5...
r1514 from rhodecode.lib.compat import json, OrderedDict
fixed repo_create hooks for forks
r2185 from rhodecode.lib.hooks import log_create_repository
fixed issues with python2.5...
r1514
#235 forking page repo group selection...
r1722 from rhodecode.model.db import Statistics, Repository, User
added missing installation of git hooks when doing a fork
r2991 from rhodecode.model.scm import ScmModel
Celery is configured by the .ini files and run from paster now...
r776
#50 on point cache invalidation changes....
r692
fixed cache problem,...
r777 add_cache(config)
renamed project to rhodecode
r547 __all__ = ['whoosh_index', 'get_commits_stats',
'reset_user_password', 'send_email']
#235 forking page repo group selection...
r1722
Notification fixes...
r1717 def get_logger(cls):
if CELERY_ON:
try:
log = cls.get_logger()
except:
log = logging.getLogger(__name__)
else:
log = logging.getLogger(__name__)
return log
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
- fixed issue with missing commits on some repos commands...
r1807
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
renamed project to rhodecode
r547 @locked_task
fixes #340 session cleanup for celery tasks
r1929 @dbsession
renamed project to rhodecode
r547 def whoosh_index(repo_location, full_index):
#235 forking page repo group selection...
r1722 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
fixed issue #459. Changed the way of obtaining logger in reindex task.
r2344 log = get_logger(whoosh_index)
fixes #340 session cleanup for celery tasks
r1929 DBS = get_session()
#235 forking page repo group selection...
r1722
Celery is configured by the .ini files and run from paster now...
r776 index_location = config['index_dir']
fixed annotation bug, added history to annotation....
r662 WhooshIndexingDaemon(index_location=index_location,
fixes #340 session cleanup for celery tasks
r1929 repo_location=repo_location, sa=DBS)\
fixed cache problem,...
r777 .run(full_index=full_index)
renamed project to rhodecode
r547
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
fixes #340 session cleanup for celery tasks
r1929 @dbsession
added recursion limit for stats gathering, sometimes it did >1000 loops which lead to python throwing max recursion depth exceeded error....
r3276 def get_commits_stats(repo_name, ts_min_y, ts_max_y, recurse_limit=100):
Notification fixes...
r1717 log = get_logger(get_commits_stats)
fixes #340 session cleanup for celery tasks
r1929 DBS = get_session()
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
ts_max_y)
fixes #666 move lockkey path location to cache_dir to ensure this path is always writable for rhodecode server
r3055 lockkey_path = config['app_conf']['cache_dir']
fixes #258 RhodeCode 1.2 assumes egg folder is writable
r1540
garden...
r1976 log.info('running task with lockkey %s' % lockkey)
- fixed issue with missing commits on some repos commands...
r1807
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 try:
fixes #258 RhodeCode 1.2 assumes egg folder is writable
r1540 lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
Code refactor for auth func, preparing for ldap support...
r699
garden...
r1976 # for js data compatibility cleans the key for person from '
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 akc = lambda k: person(k).replace('"', "")
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 co_day_auth_aggr = {}
commits_by_day_aggregate = {}
commit less models...
r1749 repo = Repository.get_by_repo_name(repo_name)
if repo is None:
return True
auto white-space removal
r1818
commit less models...
r1749 repo = repo.scm_instance
- fixed issue with missing commits on some repos commands...
r1807 repo_size = repo.count()
# return if repo have no revisions
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if repo_size < 1:
lock.release()
return True
renamed project to rhodecode
r547
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 skip_date_limit = True
parse_limit = int(config['app_conf'].get('commit_parse_limit'))
- fixed issue with missing commits on some repos commands...
r1807 last_rev = None
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 last_cs = None
timegetter = itemgetter('time')
Code refactoring,models renames...
r629
fixes #340 session cleanup for celery tasks
r1929 dbrepo = DBS.query(Repository)\
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 .filter(Repository.repo_name == repo_name).scalar()
fixes #340 session cleanup for celery tasks
r1929 cur_stats = DBS.query(Statistics)\
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 .filter(Statistics.repository == dbrepo).scalar()
Added branch filter to repo pager...
r1105
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if cur_stats is not None:
last_rev = cur_stats.stat_on_revision
Added branch filter to repo pager...
r1105
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if last_rev == repo.get_changeset().revision and repo_size > 1:
#235 forking page repo group selection...
r1722 # 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
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 lock.release()
return True
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 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)
Code refactoring,models renames...
r629
garden...
r1976 log.debug('starting parsing %s' % parse_limit)
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 lmktime = mktime
- fixed issue with missing commits on some repos commands...
r1807 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)
)
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 for cs in repo[last_rev:last_rev + parse_limit]:
utils/conf...
r2109 log.debug('parsing %s' % cs)
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 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])
moved statistics parse_limit into .ini files...
r1076
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 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:
Mads Kiilerich
celery tasks: use None as special value...
r3626 time_pos = None
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264
Mads Kiilerich
celery tasks: use None as special value...
r3626 if time_pos >= 0 and time_pos is not None:
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264
datadict = \
co_day_auth_aggr[akc(cs.author)]['data'][time_pos]
code stats speed improvments
r804
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 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:
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 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)
Code refactoring,models renames...
r629
renamed project to rhodecode
r547 else:
if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 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"],
}
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 #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
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 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"],
}
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 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)
renamed project to rhodecode
r547
garden...
r1976 log.debug('last revison %s' % last_rev)
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 leftovers = len(repo.revisions[last_rev:])
garden...
r1976 log.debug('revisions to parse %s' % leftovers)
renamed project to rhodecode
r547
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if last_rev == 0 or leftovers < parse_limit:
log.debug('getting code trending stats')
stats.languages = json.dumps(__get_codes_stats(repo_name))
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 try:
stats.repository = dbrepo
stats.stat_on_revision = last_cs.revision if last_cs else 0
fixes #340 session cleanup for celery tasks
r1929 DBS.add(stats)
DBS.commit()
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 except:
log.error(traceback.format_exc())
fixes #340 session cleanup for celery tasks
r1929 DBS.rollback()
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 lock.release()
return False
Code refactoring,models renames...
r629
utils/conf...
r2109 # final release
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 lock.release()
Code refactoring,models renames...
r629
utils/conf...
r2109 # execute another task if celery is enabled
added recursion limit for stats gathering, sometimes it did >1000 loops which lead to python throwing max recursion depth exceeded error....
r3276 if len(repo.revisions) > 1 and CELERY_ON and recurse_limit > 0:
recurse_limit -= 1
run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y,
recurse_limit)
if recurse_limit <= 0:
log.debug('Breaking recursive mode due to reach of recurse limit')
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 return True
except LockHeld:
log.info('LockHeld')
return 'Task with key %s already running' % lockkey
renamed project to rhodecode
r547
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
fixes #340 session cleanup for celery tasks
r1929 @dbsession
notification model should only send html emails not generating multipart ones
r3448 def send_email(recipients, subject, body='', html_body=''):
fixes #59, notifications for user registrations + some changes to mailer
r689 """
Sends an email with defined parameters from the .ini files.
source code cleanup: remove trailing white space, normalize file endings
r1203
fixes #59, notifications for user registrations + some changes to mailer
r689 :param recipients: list of recipients, it this is empty the defined email
address from field 'email_to' is used instead
:param subject: subject of the mail
:param body: body of the mail
Notification fixes...
r1717 :param html_body: html version of body
fixes #59, notifications for user registrations + some changes to mailer
r689 """
Notification fixes...
r1717 log = get_logger(send_email)
fixes #340 session cleanup for celery tasks
r1929 DBS = get_session()
white space cleanup
r1944
Celery is configured by the .ini files and run from paster now...
r776 email_config = config
fixed email prefix sent as None
r2154 subject = "%s %s" % (email_config.get('email_prefix', ''), subject)
fixes #59, notifications for user registrations + some changes to mailer
r689 if not recipients:
implements #291 email notification sent to all admin users
r1612 # if recipients are not defined we send to email_config + all admins
Notification fixes...
r1717 admins = [u.email for u in User.query()
.filter(User.admin == True).all()]
implements #291 email notification sent to all admin users
r1612 recipients = [email_config.get('email_to')] + admins
fixes #59, notifications for user registrations + some changes to mailer
r689
Notification fixes...
r1717 mail_from = email_config.get('app_email_from', 'RhodeCode')
renamed project to rhodecode
r547 user = email_config.get('smtp_username')
passwd = email_config.get('smtp_password')
mail_server = email_config.get('smtp_server')
mail_port = email_config.get('smtp_port')
fixes #59, notifications for user registrations + some changes to mailer
r689 tls = str2bool(email_config.get('smtp_use_tls'))
ssl = str2bool(email_config.get('smtp_use_ssl'))
notification model should only send html emails not generating multipart ones
r3448 debug = str2bool(email_config.get('debug'))
Les Peabody
applied smth_auth options update patch
r1581 smtp_auth = email_config.get('smtp_auth')
Code refactoring,models renames...
r629
Mads Kiilerich
email: fail nicely when no SMTP server has been configured
r3139 if not mail_server:
log.error("SMTP mail server not configured - cannot send mail")
return False
renamed project to rhodecode
r547 try:
Added email sending test site
r1673 m = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth,
control mailer debug with the .ini file
r1169 mail_port, ssl, tls, debug=debug)
Notification fixes...
r1717 m.send(recipients, subject, body, html_body)
renamed project to rhodecode
r547 except:
log.error('Mail sending failed')
log.error(traceback.format_exc())
return False
return True
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
fixes #340 session cleanup for celery tasks
r1929 @dbsession
renamed project to rhodecode
r547 def create_repo_fork(form_data, cur_user):
#235 forking page repo group selection...
r1722 """
Creates a fork of repository using interval VCS methods
auto white-space removal
r1818
#235 forking page repo group selection...
r1722 :param form_data:
:param cur_user:
"""
from rhodecode.model.repo import RepoModel
Refactored create fork function to use new RepoModel functions instead of old...
r2652 from rhodecode.model.user import UserModel
#235 forking page repo group selection...
r1722
Notification fixes...
r1717 log = get_logger(create_repo_fork)
fix leftover bad code on fork function
r1941 DBS = get_session()
#235 forking page repo group selection...
r1722 base_path = Repository.base_path()
Refactored create fork function to use new RepoModel functions instead of old...
r2652 cur_user = UserModel(DBS)._get_user(cur_user)
#235 forking page repo group selection...
r1722
fixed fork journal entry
r1730 fork_name = form_data['repo_name_full']
Refactored create fork function to use new RepoModel functions instead of old...
r2652 repo_type = form_data['repo_type']
description = form_data['description']
owner = cur_user
private = form_data['private']
clone_uri = form_data.get('clone_uri')
repos_group = form_data['repo_group']
landing_rev = form_data['landing_rev']
copy_fork_permissions = form_data.get('copy_permissions')
fork_of = RepoModel(DBS)._get_repo(form_data.get('fork_parent_id'))
fork_repo = RepoModel(DBS).create_repo(
fork_name, repo_type, description, owner, private, clone_uri,
repos_group, landing_rev, just_db=True, fork_of=fork_of,
copy_fork_permissions=copy_fork_permissions
)
added option to do a checkout after cloning a repository
r1742 update_after_clone = form_data['update_after_clone']
Refactored create fork function to use new RepoModel functions instead of old...
r2652
source_repo_path = os.path.join(base_path, fork_of.repo_name)
fixed fork journal entry
r1730 destination_fork_path = os.path.join(base_path, fork_name)
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264
#235 forking page repo group selection...
r1722 log.info('creating fork of %s as %s', source_repo_path,
destination_fork_path)
Refactored create fork function to use new RepoModel functions instead of old...
r2652 backend = get_backend(repo_type)
Fixed mercurial backend doesn't take bare parameter when forking
r2813
if repo_type == 'git':
added missing installation of git hooks when doing a fork
r2991 r = backend(safe_str(destination_fork_path), create=True,
Fixed mercurial backend doesn't take bare parameter when forking
r2813 src_url=safe_str(source_repo_path),
update_after_clone=update_after_clone,
bare=True)
git hook installation should be only executed for git backend
r2992 # add rhodecode hook into this repo
ScmModel().install_git_hook(repo=r)
Fixed mercurial backend doesn't take bare parameter when forking
r2813 elif repo_type == 'hg':
added missing installation of git hooks when doing a fork
r2991 r = backend(safe_str(destination_fork_path), create=True,
Fixed mercurial backend doesn't take bare parameter when forking
r2813 src_url=safe_str(source_repo_path),
update_after_clone=update_after_clone)
else:
raise Exception('Unknown backend type %s' % repo_type)
fixed repo_create hooks for forks
r2185 log_create_repository(fork_repo.get_dict(), created_by=cur_user.username)
fixed fork journal entry
r1730 action_logger(cur_user, 'user_forked_repo:%s' % fork_name,
Refactored create fork function to use new RepoModel functions instead of old...
r2652 fork_of.repo_name, '', DBS)
auto white-space removal
r1818
implements #193 journal stores information about deleting of repos...
r1747 action_logger(cur_user, 'user_created_fork:%s' % fork_name,
fixes #340 session cleanup for celery tasks
r1929 fork_name, '', DBS)
#235 forking page repo group selection...
r1722 # finally commit at latest possible stage
fixes #340 session cleanup for celery tasks
r1929 DBS.commit()
fixes issue #747, load changeset cache after forking to refresh lightweight dashboard caches
r3279 fork_repo.update_changeset_cache()
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
fixed repo_create hooks for forks
r2185
renamed project to rhodecode
r547 def __get_codes_stats(repo_name):
utils/conf...
r2109 from rhodecode.config.conf import LANGUAGES_EXTENSIONS_MAP
#235 forking page repo group selection...
r1722 repo = Repository.get_by_repo_name(repo_name).scm_instance
removed soon deprecated walk method on repository instance
r603 tip = repo.get_changeset()
renamed project to rhodecode
r547 code_stats = {}
some small fixes
r630
def aggregate(cs):
for f in cs[2]:
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244 ext = lower(f.extension)
removed binary files from trending sources
r789 if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244 if ext in code_stats:
code_stats[ext] += 1
renamed project to rhodecode
r547 else:
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244 code_stats[ext] = 1
Code refactoring,models renames...
r629
some small fixes
r630 map(aggregate, tip.walk('/'))
renamed project to rhodecode
r547 return code_stats or {}