@@ -13,103 +13,124 @@ pdebug = false
## 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 =
#email_prefix = [RhodeCode]
#smtp_server = mail.server.com
#smtp_username =
#smtp_password =
#smtp_port =
#smtp_use_tls = false
#smtp_use_ssl = true
# Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
#smtp_auth =
[server:main]
##nr of threads to spawn
threadpool_workers = 5
##max request before thread respawn
threadpool_max_requests = 10
##option to use threads of process
use_threadpool = true
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
app_instance_uuid = develop
cut_off_limit = 256000
force_https = false
commit_parse_limit = 25
use_gravatar = true
container_auth_enabled = false
proxypass_auth_enabled = false
## overwrite schema of clone url
# available vars:
# scheme - http/https
# user - current user
# pass - password
# netloc - network location
# path - usually repo_name
# clone_uri = {scheme}://{user}{pass}{netloc}{path}
## available vars:
## scheme - http/https
## user - current user
## pass - password
## netloc - network location
## path - usually repo_name
#clone_uri = {scheme}://{user}{pass}{netloc}{path}
## issue tracking mapping for commits messages
## uncomment url_pat, issue_server, issue_prefix to enable
## pattern to get the issues from commit messages
## default one used here is #1234
#url_pat = (?:^#|\s#)(\w+)
## server url to the issue, each {id} will be replaced with id
## fetched from the regex
#issue_server = https://myissueserver.com/issue/{id}
## prefix to add to link to indicate it's an url
## #314 will be replaced by <issue_prefix><id>
#issue_prefix = #
####################################
### 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=%(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.super_short_term.key_length = 256
beaker.cache.short_term.type=memory
beaker.cache.short_term.expire=60
beaker.cache.short_term.key_length = 256
beaker.cache.long_term.type=memory
beaker.cache.long_term.expire=36000
beaker.cache.long_term.key_length = 256
host = 127.0.0.1
port = 8001
app_instance_uuid = prod1234
commit_parse_limit = 50
@@ -13,104 +13,125 @@ pdebug = false
app_instance_uuid = ${app_instance_uuid}
beaker.cache.sql_cache_short.type=memory
"""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
import urllib
import math
import logging
from datetime import datetime
from pygments.formatters.html import HtmlFormatter
from pygments import highlight as code_highlight
from pylons import url, request, config
from pylons.i18n.translation import _, ungettext
from hashlib import md5
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.paginate import Page
from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
convert_boolean_attrs, NotGiven, _make_safe_id_component
from rhodecode.lib.annotate import annotate_highlight
from rhodecode.lib.utils import repo_name_slug
from rhodecode.lib import str2bool, safe_unicode, safe_str, get_changeset_safe
from rhodecode.lib.markup_renderer import MarkupRenderer
log = logging.getLogger(__name__)
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
safeid = _make_safe_id_component
def FID(raw_id, path):
Creates a uniqe ID for filenode based on it's hash of path and revision
it's safe to use in urls
:param raw_id:
:param path:
return 'C-%s-%s' % (short_id(raw_id), md5(path).hexdigest()[:12])
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
@@ -695,61 +698,88 @@ def fancy_file_stats(stats):
else:
d_p = d_p - (p_sum - width)
a_v = a if a > 0 else ''
d_v = d if d > 0 else ''
def cgen(l_type):
mapping = {'tr':'top-right-rounded-corner',
'tl':'top-left-rounded-corner',
'br':'bottom-right-rounded-corner',
'bl':'bottom-left-rounded-corner'}
map_getter = lambda x:mapping[x]
if l_type == 'a' and d_v:
#case when added and deleted are present
return ' '.join(map(map_getter, ['tl', 'bl']))
if l_type == 'a' and not d_v:
return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
if l_type == 'd' and a_v:
return ' '.join(map(map_getter, ['tr', 'br']))
if l_type == 'd' and not a_v:
d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (cgen('a'),
a_p, a_v)
d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (cgen('d'),
d_p, d_v)
return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
def urlify_text(text):
import re
url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
'''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
def url_func(match_obj):
url_full = match_obj.groups()[0]
return '<a href="%(url)s">%(url)s</a>' % ({'url':url_full})
return literal(url_pat.sub(url_func, text))
def urlify_commit(text):
import traceback
conf = config['app_conf']
URL_PAT = re.compile(r'%s' % conf.get('url_pat'))
if URL_PAT:
ISSUE_SERVER = conf.get('issue_server')
ISSUE_PREFIX = conf.get('issue_prefix')
issue_id = match_obj.groups()[0]
return ' <a href="%(url)s">%(issue-prefix)s%(id-repr)s</a>' % (
{'url':ISSUE_SERVER.replace('{id}',issue_id),
'id-repr':issue_id,
'issue-prefix':ISSUE_PREFIX,
'serv':ISSUE_SERVER,
}
)
return literal(URL_PAT.sub(url_func, text))
except:
log.error(traceback.format_exc())
pass
return text
def rst(source):
return literal('<div class="rst-block">%s</div>' %
MarkupRenderer.rst(source))
def rst_w_mentions(source):
Wrapped rst renderer with @mention highlighting
:param source:
MarkupRenderer.rst_with_mentions(source))
@@ -2101,98 +2101,96 @@ h3.files_location {
font-weight: 700;
border-bottom: none !important;
margin: 10px 0 !important;
#files_data dl dt {
float: left;
width: 60px;
margin: 0 !important;
padding: 5px;
#files_data dl dd {
padding: 5px !important;
#changeset_content {
border: 1px solid #CCC;
#changeset_compare_view_content {
#changeset_content .container {
min-height: 120px;
font-size: 1.2em;
overflow: hidden;
#changeset_compare_view_content .compare_view_commits {
width: auto !important;
#changeset_compare_view_content .compare_view_commits td {
padding: 0px 0px 0px 12px !important;
#changeset_content .container .right {
float: right;
width: 25%;
text-align: right;
#changeset_content .container .left .message {
font-style: italic;
color: #556CB5;
white-space: pre-wrap;
#changeset_content .container .left .message a:hover {
text-decoration: none;
.cs_files .cur_cs {
margin: 10px 2px;
font-weight: bold;
.cs_files .node {
.cs_files .changes {
color:#003367;
.cs_files .changes .added {
background-color: #BBFFBB;
text-align: center;
font-size: 9px;
padding: 2px 0px 2px 0px;
.cs_files .changes .deleted {
background-color: #FF8888;
.cs_files .cs_added {
background: url("../images/icons/page_white_add.png") no-repeat scroll
3px;
height: 16px;
padding-left: 20px;
margin-top: 7px;
text-align: left;
.cs_files .cs_changed {
background: url("../images/icons/page_white_edit.png") no-repeat scroll
@@ -3,105 +3,105 @@
<%inherit file="/base/base.html"/>
<%def name="title()">
${c.repo_name} ${_('Changelog')} - ${c.rhodecode_name}
</%def>
<%def name="breadcrumbs_links()">
${h.link_to(u'Home',h.url('/'))}
»
${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
${_('Changelog')} - ${_('showing ')} ${c.size if c.size <= c.total_cs else c.total_cs} ${_('out of')} ${c.total_cs} ${_('revisions')}
<%def name="page_nav()">
${self.menu('changelog')}
<%def name="main()">
<div class="box">
<!-- box / title -->
<div class="title">
${self.breadcrumbs()}
</div>
<div class="table">
% if c.pagination:
<div id="graph">
<div id="graph_nodes">
<canvas id="graph_canvas"></canvas>
<div id="graph_content">
<div class="container_header">
${h.form(h.url.current(),method='get')}
<div class="info_box" style="float:left">
${h.submit('set',_('Show'),class_="ui-btn")}
${h.text('size',size=1,value=c.size)}
<span class="rev">${_('revisions')}</span>
${h.end_form()}
<div style="float:right">${h.select('branch_filter',c.branch_name,c.branch_filters)}</div>
<div id="rev_range_container" style="display:none"></div>
%for cnt,cs in enumerate(c.pagination):
<div id="chg_${cnt+1}" class="container">
<div class="left">
<div class="date">
${h.checkbox(cs.short_id,class_="changeset_range")}
<span>${_('commit')} ${cs.revision}: ${h.short_id(cs.raw_id)}@${cs.date}</span>
<span class="tooltip" title="${cs.date}"><a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">${cs.revision}:${h.short_id(cs.raw_id)}</a></span>
<div class="author">
<div class="gravatar">
<img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),16)}"/>
<div title="${cs.author}" class="user">${h.person(cs.author)}</div>
<div class="message">${h.link_to(h.wrap_paragraphs(cs.message),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div>
<div class="message">${h.urlify_commit(h.wrap_paragraphs(cs.message))}</div>
<div class="right">
<div id="${cs.raw_id}_changes_info" class="changes">
<span id="${cs.raw_id}" class="changed_total tooltip" title="${_('Affected number of files, click to show more details')}">${len(cs.affected_files)}</span>
%if len(cs.parents)>1:
<div class="merge">${_('merge')}</div>
%endif
%if cs.parents:
%for p_cs in reversed(cs.parents):
<div class="parent">${_('Parent')} ${p_cs.revision}: ${h.link_to(h.short_id(p_cs.raw_id),
h.url('changeset_home',repo_name=c.repo_name,revision=p_cs.raw_id),title=p_cs.message)}
%endfor
%else:
<div class="parent">${_('No parents')}</div>
<span class="logtags">
%if cs.branch:
<span class="branchtag" title="${'%s %s' % (_('branch'),cs.branch)}">
${h.link_to(cs.branch,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
%for tag in cs.tags:
<span class="tagtag" title="${'%s %s' % (_('tag'),tag)}">
${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id))}</span>
</span>
<div class="pagination-wh pagination-left">
${c.pagination.pager('$link_previous ~2~ $link_next')}
<script type="text/javascript" src="${h.url('/js/graph.js')}"></script>
<script type="text/javascript">
YAHOO.util.Event.onDOMReady(function(){
//Monitor range checkboxes and build a link to changesets
//ranges
var checkboxes = YUD.getElementsByClassName('changeset_range');
var url_tmpl = "${h.url('changeset_home',repo_name=c.repo_name,revision='__REVRANGE__')}";
YUE.on(checkboxes,'click',function(e){
var checked_checkboxes = [];
@@ -7,97 +7,97 @@
${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
<div class="diffblock">
<div class="code-header">
<div class="date">${_('commit')} ${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} ${c.changeset.date}</div>
<div class="diff-menu-wrapper">
<img class="diff-menu-activate" style="cursor: pointer" alt="diff-menu" src="${h.url('/images/icons/script_gear.png')}" />
<div class="diff-menu" style="display:none">
<ul>
<li>${h.link_to(_('raw diff'),h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</li>
<li>${h.link_to(_('download diff'),h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</li>
<li>${c.ignorews_url()}</li>
<li>${c.context_url()}</li>
</ul>
<div class="comments-number" style="float:right;padding-right:5px">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
<div id="changeset_content">
<div class="container">
<img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
<span>${h.person(c.changeset.author)}</span><br/>
<span><a href="mailto:${h.email_or_none(c.changeset.author)}">${h.email_or_none(c.changeset.author)}</a></span><br/>
<div class="message">${h.link_to(h.wrap_paragraphs(c.changeset.message),h.url('changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</div>
<div class="message">${h.urlify_commit(h.wrap_paragraphs(c.changeset.message))}</div>
<div class="changes">
% if len(c.changeset.affected_files) <= c.affected_files_cut_off:
<span class="removed" title="${_('removed')}">${len(c.changeset.removed)}</span>
<span class="changed" title="${_('changed')}">${len(c.changeset.changed)}</span>
<span class="added" title="${_('added')}">${len(c.changeset.added)}</span>
% else:
<span class="removed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
<span class="changed" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
<span class="added" title="${_('affected %s files') % len(c.changeset.affected_files)}">!</span>
% endif
%if len(c.changeset.parents)>1:
<div class="merge">
${_('merge')}<img alt="merge" src="${h.url('/images/icons/arrow_join.png')}"/>
%if c.changeset.parents:
%for p_cs in reversed(c.changeset.parents):
<span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}">
${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
%for tag in c.changeset.tags:
${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span>
<span style="font-size:1.1em;font-weight: bold">
${_('%s files affected with %s additions and %s deletions.') % (len(c.changeset.affected_files),c.lines_added,c.lines_deleted)}
<div class="cs_files">
%for change,filenode,diff,cs1,cs2,stat in c.changes:
<div class="cs_${change}">
<div class="node">
%if change != 'removed':
${h.link_to(h.safe_unicode(filenode.path),c.anchor_url(filenode.changeset.raw_id,filenode.path))}
## -*- coding: utf-8 -*-
${c.repo_name} ${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)} - ${c.rhodecode_name}
${_('Changesets')} - r${c.cs_ranges[0].revision}:${h.short_id(c.cs_ranges[0].raw_id)} -> r${c.cs_ranges[-1].revision}:${h.short_id(c.cs_ranges[-1].raw_id)}
<div id="body" class="diffblock">
<div class="code-header cv">
<h3 class="code-header-title">${_('Compare View')}</h3>
<div>
<div id="changeset_compare_view_content">
<table class="compare_view_commits noborder">
%for cs in c.cs_ranges:
<tr>
<td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email(cs.author),14)}"/></div></td>
<td>${h.link_to('r%s:%s' % (cs.revision,h.short_id(cs.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</td>
<td><div class="author">${h.person(cs.author)}</div></td>
<td><span class="tooltip" title="${h.age(cs.date)}">${cs.date}</span></td>
<td><div class="message">${h.link_to(h.wrap_paragraphs(cs.message),h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id))}</div></td>
<td><div class="message">${h.urlify_commit(h.wrap_paragraphs(c.changeset.message))}</div></td>
</tr>
</table>
<div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
<div class="cur_cs">r${cs}</div>
%for change,filenode,diff,cs1,cs2,st in c.changes[cs.raw_id]:
<div class="cs_${change}">${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID(cs.raw_id,filenode.path)))}</div>
<%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
<%namespace name="diff_block" file="/changeset/diff_block.html"/>
##${comment.comment_inline_form(cs)}
## diff block
<h3 style="border:none;padding-top:8px;">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</h3>
${diff_block.diff_block(c.changes[cs.raw_id])}
##${comment.comments(cs)}
YUE.onDOMReady(function(){
YUE.on(YUQ('.diff-menu-activate'),'click',function(e){
var act = e.currentTarget.nextElementSibling;
if(YUD.hasClass(act,'active')){
YUD.removeClass(act,'active');
YUD.setStyle(act,'display','none');
}else{
YUD.addClass(act,'active');
YUD.setStyle(act,'display','');
});
})
</script>
\ No newline at end of file
%if c.repo_changesets:
<table class="table_disp">
<th class="left">${_('commit message')}</th>
<th class="left">${_('revision')}</th>
<th class="left">${_('age')}</th>
<th class="left">${_('author')}</th>
<th class="left">${_('branch')}</th>
<th class="left">${_('tags')}</th>
%for cnt,cs in enumerate(c.repo_changesets):
<tr class="parity${cnt%2}">
<td>
<div><pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre></div>
</td>
${h.link_to(h.truncate(cs.message,50),
h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id),
title=cs.message)}
<td><span class="tooltip" title="${cs.date}">
${h.age(cs.date)}</span>
<td title="${cs.author}">${h.person(cs.author)}</td>
<td><div><pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre></div></td>
<span class="branchtag">${cs.branch}</span>
<span class="tagtag">${tag}</span>
YUE.delegate("shortlog_data","click",function(e, matchedEl, container){
ypjax(e.target.href,"shortlog_data",function(){tooltip_activate();});
YUE.preventDefault(e);
},'.pager_link');
${c.repo_changesets.pager('$link_previous ~2~ $link_next')}
%if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
<h4>${_('Add or upload files directly via RhodeCode')}</h4>
<div style="margin: 20px 30px;">
<div id="add_node_id" class="add_node">
<a class="ui-btn" href="${h.url('files_add_home',repo_name=c.repo_name,revision=0,f_path='')}">${_('add new file')}</a>
<h4>${_('Push new repo')}</h4>
<pre>
${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
${c.rhodecode_repo.alias} add README # add first file
${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
${c.rhodecode_repo.alias} push # push changes back
</pre>
Status change: