Changeset - 6e8027c2f49c
[Not reviewed]
Merge beta
0 68 1
Leonardo - 13 years ago 2013-03-11 17:09:43
leo@unity3d.com
Merge
69 files changed with 1032 insertions and 432 deletions:
test.ini
90
6
0 comments (0 inline, 0 general)
development.ini
Show inline comments
 
@@ -62,12 +62,14 @@ full_stack = true
 
static_files = true
 
# Optional Languages
 
# en, fr, ja, pt_BR, zh_CN, zh_TW, pl
 
lang = en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
# set this path to use archive download cache
 
#archive_cache_dir = /tmp/rhodecode_tarballcache
 
app_instance_uuid = rc-develop
 
cut_off_limit = 256000
 
vcs_full_cache = True
 
# force https in RhodeCode, fixes https redirects, assumes it's always https
 
force_https = false
 
# use Strict-Transport-Security headers
 
@@ -151,12 +153,17 @@ instance_id =
 

	
 
## alternative return HTTP header for failed authentication. Default HTTP
 
## response is 401 HTTPUnauthorized. Currently HG clients have troubles with 
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
docs/api/api.rst
Show inline comments
 
@@ -175,25 +175,26 @@ OUTPUT::
 
    error :  null
 

	
 
lock
 
----
 

	
 
Set locking state on given repository by given user. If userid param is skipped
 
, then it is set to id of user whos calling this method.
 
, then it is set to id of user whos calling this method. If locked param is skipped
 
then function shows current lock state of given repo.
 
This command can be executed only using api_key belonging to user with admin
 
rights or regular user that have admin or write access to repository.
 

	
 
INPUT::
 

	
 
    id : <id_for_response>
 
    api_key : "<api_key>"
 
    method :  "lock"
 
    args :    {
 
                "repoid" : "<reponame or repo_id>"
 
                "userid" : "<user_id or username = Optional(=apiuser)>",
 
                "locked" : "<bool true|false>"
 
                "locked" : "<bool true|false = Optional(=None)>"
 
              }
 

	
 
OUTPUT::
 

	
 
    id : <id_given_in_input>
 
    result : "User `<username>` set lock state for repo `<reponame>` to `true|false`"
docs/changelog.rst
Show inline comments
 
@@ -13,12 +13,33 @@ Changelog
 
news
 
++++
 

	
 
fixes
 
+++++
 

	
 
1.5.4 (**2013-03-13**)
 
----------------------
 

	
 
news
 
++++
 

	
 

	
 
fixes
 
+++++
 

	
 
- fixed webtest dependency issues
 
- fixed issues with celery tasks for password reset
 
- fixed #763 gravatar helper function should fallback into default image
 
  if email is empty
 
- fixes #762 user global activation flag is also respected for LDAP created
 
  accounts
 
- use password obfuscate when clonning a remote repo with credentials inside
 
- fixed issue with renaming repos group together with changing parents
 
- disallow cloning from file:/// URIs
 
- handle all cases with multiple IP addresses in proxy headers
 

	
 
1.5.3 (**2013-02-12**)
 
----------------------
 

	
 
news
 
++++
 

	
 
@@ -136,14 +157,14 @@ fixes
 
- fixes #630 git statistics do too much work making them slow.
 
- fixes #625 Git-Tags are not displayed in Shortlog
 
- fix for issue #602, enforce str when setting mercurial UI object.
 
  When this is used together with mercurial internal translation system
 
  it can lead to UnicodeDecodeErrors
 
- fixes #645 Fix git handler when doing delete remote branch
 
- implements #649 added two seperate method for author and commiter to VCS
 
  changeset class switch author for git backed to be the real author not commiter
 
- implements #649 added two seperate method for author and committer to VCS
 
  changeset class switch author for git backed to be the real author not committer
 
- fix issue #504 RhodeCode is showing different versions of README on
 
  different summary page loads
 
- implemented #658 Changing username in LDAP-Mode should not be allowed.
 
- fixes #652 switch to generator approach when doing file annotation to prevent
 
  huge memory consumption
 
- fixes #666 move lockkey path location to cache_dir to ensure this path is
docs/setup.rst
Show inline comments
 
@@ -475,13 +475,13 @@ can be found at *rhodecode.lib.hooks*.
 

	
 
Changing default encoding
 
-------------------------
 

	
 
By default RhodeCode uses utf8 encoding, starting from 1.3 series this
 
can be changed, simply edit default_encoding in .ini file to desired one.
 
This affects many parts in rhodecode including commiters names, filenames,
 
This affects many parts in rhodecode including committers names, filenames,
 
encoding of commit messages. In addition RhodeCode can detect if `chardet`
 
library is installed. If `chardet` is detected RhodeCode will fallback to it
 
when there are encode/decode errors.
 

	
 

	
 
Setting Up Celery
docs/theme/nature/static/pygments.css
Show inline comments
 
@@ -48,7 +48,7 @@
 
.s1 { color: #bb8844 } /* Literal.String.Single */
 
.ss { color: #bb8844 } /* Literal.String.Symbol */
 
.bp { color: #999999 } /* Name.Builtin.Pseudo */
 
.vc { color: #ff99ff } /* Name.Variable.Class */
 
.vg { color: #ff99ff } /* Name.Variable.Global */
 
.vi { color: #ff99ff } /* Name.Variable.Instance */
 
.il { color: #009999 } /* Literal.Number.Integer.Long */
 
.il { color: #009999 } /* Literal.Number.Integer.Long */
 
\ No newline at end of file
production.ini
Show inline comments
 
@@ -62,12 +62,14 @@ full_stack = true
 
static_files = true
 
# Optional Languages
 
# en, fr, ja, pt_BR, zh_CN, zh_TW, pl
 
lang = en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
# set this path to use archive download cache
 
#archive_cache_dir = /tmp/rhodecode_tarballcache
 
app_instance_uuid = rc-production
 
cut_off_limit = 256000
 
vcs_full_cache = True
 
# force https in RhodeCode, fixes https redirects, assumes it's always https
 
force_https = false
 
# use Strict-Transport-Security headers
 
@@ -151,12 +153,17 @@ instance_id =
 

	
 
## alternative return HTTP header for failed authentication. Default HTTP
 
## response is 401 HTTPUnauthorized. Currently HG clients have troubles with 
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
rhodecode/config/deployment.ini_tmpl
Show inline comments
 
@@ -62,12 +62,14 @@ full_stack = true
 
static_files = true
 
# Optional Languages
 
# en, fr, ja, pt_BR, zh_CN, zh_TW, pl
 
lang = en
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
 
# set this path to use archive download cache
 
#archive_cache_dir = /tmp/rhodecode_tarballcache
 
app_instance_uuid = ${app_instance_uuid}
 
cut_off_limit = 256000
 
vcs_full_cache = True
 
# force https in RhodeCode, fixes https redirects, assumes it's always https
 
force_https = false
 
# use Strict-Transport-Security headers
 
@@ -151,12 +153,17 @@ instance_id =
 

	
 
## alternative return HTTP header for failed authentication. Default HTTP
 
## response is 401 HTTPUnauthorized. Currently HG clients have troubles with 
 
## handling that. Set this variable to 403 to return HTTPForbidden
 
auth_ret_code =
 

	
 
## locking return code. When repository is locked return this HTTP code. 2XX
 
## codes don't break the transactions while 4XX codes do
 
lock_ret_code = 423
 

	
 

	
 
####################################
 
###        CELERY CONFIG        ####
 
####################################
 
use_celery = false
 
broker.host = localhost
 
broker.vhost = rabbitmqhost
rhodecode/config/middleware.py
Show inline comments
 
@@ -12,12 +12,13 @@ from pylons.middleware import ErrorHandl
 
from pylons.wsgiapp import PylonsApp
 

	
 
from rhodecode.lib.middleware.simplehg import SimpleHg
 
from rhodecode.lib.middleware.simplegit import SimpleGit
 
from rhodecode.lib.middleware.https_fixup import HttpsFixup
 
from rhodecode.config.environment import load_environment
 
from rhodecode.lib.middleware.wrapper import RequestWrapper
 

	
 

	
 
def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
 
    """Create a Pylons WSGI application and return it
 

	
 
    ``global_conf``
 
@@ -52,25 +53,25 @@ def make_app(global_conf, full_stack=Tru
 
        app = ProfilingMiddleware(app)
 

	
 
    if asbool(full_stack):
 

	
 
        from rhodecode.lib.middleware.sentry import Sentry
 
        from rhodecode.lib.middleware.errormator import Errormator
 
        if Errormator:
 
        if Errormator and asbool(config['app_conf'].get('errormator')):
 
            app = Errormator(app, config)
 
        elif Sentry:
 
            app = Sentry(app, config)
 

	
 
        # Handle Python exceptions
 
        app = ErrorHandler(app, global_conf, **config['pylons.errorware'])
 

	
 
        # we want our low level middleware to get to the request ASAP. We don't
 
        # need any pylons stack middleware in them
 
        app = SimpleHg(app, config)
 
        app = SimpleGit(app, config)
 

	
 
        app = RequestWrapper(app, config)
 
        # Display error documents for 401, 403, 404 status codes (and
 
        # 500 when debug is disabled)
 
        if asbool(config['debug']):
 
            app = StatusCodeRedirect(app)
 
        else:
 
            app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])
rhodecode/config/routing.py
Show inline comments
 
@@ -53,12 +53,24 @@ def make_map(config):
 
        :param environ:
 
        :param match_dict:
 
        """
 
        repos_group_name = match_dict.get('group_name')
 
        return is_valid_repos_group(repos_group_name, config['base_path'])
 

	
 
    def check_group_skip_path(environ, match_dict):
 
        """
 
        check for valid repository group for proper 404 handling, but skips
 
        verification of existing path
 

	
 
        :param environ:
 
        :param match_dict:
 
        """
 
        repos_group_name = match_dict.get('group_name')
 
        return is_valid_repos_group(repos_group_name, config['base_path'],
 
                                    skip_path_check=True)
 

	
 
    def check_int(environ, match_dict):
 
        return match_dict.get('id').isdigit()
 

	
 
    # The ErrorController route (handles 404/500 error pages); it should
 
    # likely stay at the top, ensuring it can always be resolved
 
    rmap.connect('/error/{action}', controller='error')
 
@@ -168,15 +180,16 @@ def make_map(config):
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("update_repos_group", "/repos_groups/{group_name:.*?}",
 
                  action="update", conditions=dict(method=["PUT"],
 
                                                   function=check_group))
 
        m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}",
 
                  action="delete", conditions=dict(method=["DELETE"],
 
                                                   function=check_group))
 
                                                   function=check_group_skip_path))
 
        m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit",
 
                  action="edit", conditions=dict(method=["GET"],))
 
                  action="edit", conditions=dict(method=["GET"],
 
                                                 function=check_group))
 
        m.connect("formatted_edit_repos_group",
 
                  "/repos_groups/{group_name:.*?}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"],
 
                                                 function=check_group))
 
        m.connect("repos_group", "/repos_groups/{group_name:.*?}",
 
                  action="show", conditions=dict(method=["GET"],
rhodecode/controllers/admin/repos_groups.py
Show inline comments
 
@@ -248,37 +248,31 @@ class ReposGroupsController(BaseControll
 
        # url('repos_group', group_name=GROUP_NAME)
 

	
 
        gr = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
 
        repos = gr.repositories.all()
 
        if repos:
 
            h.flash(_('This group contains %s repositores and cannot be '
 
                      'deleted') % len(repos),
 
                    category='error')
 
                      'deleted') % len(repos), category='warning')
 
            return redirect(url('repos_groups'))
 

	
 
        children = gr.children.all()
 
        if children:
 
            h.flash(_('This group contains %s subgroups and cannot be deleted'
 
                      % (len(children))), category='warning')
 
            return redirect(url('repos_groups'))
 

	
 
        try:
 
            ReposGroupModel().delete(group_name)
 
            Session().commit()
 
            h.flash(_('removed repos group %s') % gr.group_name,
 
            h.flash(_('removed repos group %s') % group_name,
 
                    category='success')
 
            #TODO: in future action_logger(, '', '', '', self.sa)
 
        except IntegrityError, e:
 
            if str(e.message).find('groups_group_parent_id_fkey') != -1:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Cannot delete this group it still contains '
 
                          'subgroups'),
 
                        category='warning')
 
            else:
 
                log.error(traceback.format_exc())
 
                h.flash(_('error occurred during deletion of repos '
 
                          'group %s') % gr.group_name, category='error')
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occurred during deletion of repos '
 
                      'group %s') % gr.group_name, category='error')
 
                      'group %s') % group_name, category='error')
 

	
 
        return redirect(url('repos_groups'))
 

	
 
    @HasReposGroupPermissionAnyDecorator('group.admin')
 
    def delete_repos_group_user_perm(self, group_name):
 
        """
rhodecode/controllers/admin/settings.py
Show inline comments
 
@@ -35,13 +35,13 @@ from pylons import request, session, tmp
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator, NotAnonymous, HasPermissionAny,\
 
    HasReposGroupPermissionAll, HasReposGroupPermissionAny
 
    HasReposGroupPermissionAll, HasReposGroupPermissionAny, AuthUser
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.celerylib import tasks, run_task
 
from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
 
    set_rhodecode_config, repo_name_slug, check_git_version
 
from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
 
    RhodeCodeSetting, PullRequest, PullRequestReviewers
 
@@ -406,12 +406,14 @@ class SettingsController(BaseController)
 
        """
 
        GET /_admin/my_account Displays info about my account
 
        """
 
        # url('admin_settings_my_account')
 

	
 
        c.user = User.get(self.rhodecode_user.user_id)
 
        c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
 
                               ip_addr=self.ip_addr)
 
        c.ldap_dn = c.user.ldap_dn
 

	
 
        if c.user.username == 'default':
 
            h.flash(_("You can't edit this user since it's"
 
              " crucial for entire application"), category='warning')
 
            return redirect(url('users'))
 
@@ -437,12 +439,14 @@ class SettingsController(BaseController)
 
        # Or using helpers:
 
        #    h.form(url('admin_settings_my_account_update'),
 
        #           method='put')
 
        # url('admin_settings_my_account_update', id=ID)
 
        uid = self.rhodecode_user.user_id
 
        c.user = User.get(self.rhodecode_user.user_id)
 
        c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
 
                               ip_addr=self.ip_addr)
 
        c.ldap_dn = c.user.ldap_dn
 
        email = self.rhodecode_user.email
 
        _form = UserForm(edit=True,
 
                         old_data={'user_id': uid, 'email': email})()
 
        form_result = {}
 
        try:
rhodecode/controllers/api/api.py
Show inline comments
 
@@ -24,27 +24,28 @@
 
# along with this program; if not, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 

	
 
import traceback
 
import logging
 
from pylons.controllers.util import abort
 

	
 
from rhodecode.controllers.api import JSONRPCController, JSONRPCError
 
from rhodecode.lib.auth import PasswordGenerator, AuthUser, \
 
    HasPermissionAllDecorator, HasPermissionAnyDecorator, \
 
    HasPermissionAnyApi, HasRepoPermissionAnyApi
 
from rhodecode.lib.utils import map_groups, repo2db_mapper
 
from rhodecode.lib.utils2 import str2bool
 
from rhodecode.lib.utils2 import str2bool, time_to_datetime, safe_int
 
from rhodecode.lib import helpers as h
 
from rhodecode.model.meta import Session
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.users_group import UserGroupModel
 
from rhodecode.model.permission import PermissionModel
 
from rhodecode.model.db import Repository, RhodeCodeSetting, UserIpMap
 
from rhodecode.lib.compat import json
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class OptionalAttr(object):
 
    """
 
@@ -226,13 +227,14 @@ class ApiController(JSONRPCController):
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'Error occurred during cache invalidation action'
 
            )
 

	
 
    def lock(self, apiuser, repoid, locked, userid=Optional(OAttr('apiuser'))):
 
    def lock(self, apiuser, repoid, locked=Optional(None),
 
             userid=Optional(OAttr('apiuser'))):
 
        """
 
        Set locking state on particular repository by given user, if
 
        this command is runned by non-admin account userid is set to user
 
        who is calling this method
 

	
 
        :param apiuser:
 
@@ -254,27 +256,83 @@ class ApiController(JSONRPCController):
 
                )
 
        else:
 
            raise JSONRPCError('repository `%s` does not exist' % (repoid))
 

	
 
        if isinstance(userid, Optional):
 
            userid = apiuser.user_id
 

	
 
        user = get_user_or_error(userid)
 
        locked = str2bool(locked)
 
        try:
 
            if locked:
 
                Repository.lock(repo, user.user_id)
 

	
 
        if isinstance(locked, Optional):
 
            lockobj = Repository.getlock(repo)
 

	
 
            if lockobj[0] is None:
 
                return ('Repo `%s` not locked. Locked=`False`.'
 
                        % (repo.repo_name))
 
            else:
 
                Repository.unlock(repo)
 
                userid, time_ = lockobj
 
                user = get_user_or_error(userid)
 

	
 
                return ('Repo `%s` locked by `%s`. Locked=`True`. '
 
                        'Locked since: `%s`'
 
                    % (repo.repo_name, user.username,
 
                       json.dumps(time_to_datetime(time_))))
 

	
 
        else:
 
            locked = str2bool(locked)
 
            try:
 
                if locked:
 
                    Repository.lock(repo, user.user_id)
 
                else:
 
                    Repository.unlock(repo)
 

	
 
                return ('User `%s` set lock state for repo `%s` to `%s`'
 
                        % (user.username, repo.repo_name, locked))
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                raise JSONRPCError(
 
                    'Error occurred locking repository `%s`' % repo.repo_name
 
                )
 

	
 
            return ('User `%s` set lock state for repo `%s` to `%s`'
 
                    % (user.username, repo.repo_name, locked))
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise JSONRPCError(
 
                'Error occurred locking repository `%s`' % repo.repo_name
 
            )
 
    def get_locks(self, apiuser, userid=Optional(OAttr('apiuser'))):
 
        """
 
        Get all locks for given userid, if
 
        this command is runned by non-admin account userid is set to user
 
        who is calling this method, thus returning locks for himself
 

	
 
        :param apiuser:
 
        :param userid:
 
        """
 
        if HasPermissionAnyApi('hg.admin')(user=apiuser):
 
            pass
 
        else:
 
            #make sure normal user does not pass someone else userid,
 
            #he is not allowed to do that
 
            if not isinstance(userid, Optional) and userid != apiuser.user_id:
 
                raise JSONRPCError(
 
                    'userid is not the same as your user'
 
                )
 
        ret = []
 
        if isinstance(userid, Optional):
 
            user = None
 
        else:
 
            user = get_user_or_error(userid)
 

	
 
        #show all locks
 
        for r in Repository.getAll():
 
            userid, time_ = r.locked
 
            if time_:
 
                _api_data = r.get_api_data()
 
                # if we use userfilter just show the locks for this user
 
                if user:
 
                    if safe_int(userid) == user.user_id:
 
                        ret.append(_api_data)
 
                else:
 
                    ret.append(_api_data)
 

	
 
        return ret
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def show_ip(self, apiuser, userid):
 
        """
 
        Shows IP address as seen from RhodeCode server, together with all
 
        defined IP addresses for given user
rhodecode/controllers/compare.py
Show inline comments
 
@@ -86,27 +86,34 @@ class CompareController(BaseRepoControll
 
        # org_ref will be evaluated in org_repo
 
        org_repo = c.rhodecode_db_repo.repo_name
 
        org_ref = (org_ref_type, org_ref)
 
        # other_ref will be evaluated in other_repo
 
        other_ref = (other_ref_type, other_ref)
 
        other_repo = request.GET.get('other_repo', org_repo)
 
        # If merge is True:
 
        #   Show what org would get if merged with other:
 
        #   List changesets that are ancestors of other but not of org.
 
        #   New changesets in org is thus ignored.
 
        #   Diff will be from common ancestor, and merges of org to other will thus be ignored.
 
        # If merge is False:
 
        #   Make a raw diff from org to other, no matter if related or not.
 
        #   Changesets in one and not in the other will be ignored
 
        merge = bool(request.GET.get('merge'))
 
        # fulldiff disables cut_off_limit
 
        c.fulldiff = request.GET.get('fulldiff')
 
        # only consider this range of changesets
 
        rev_start = request.GET.get('rev_start')
 
        rev_end = request.GET.get('rev_end')
 
        # partial uses compare_cs.html template directly
 
        partial = request.environ.get('HTTP_X_PARTIAL_XHR')
 
        # as_form puts hidden input field with changeset revisions
 
        c.as_form = partial and request.GET.get('as_form')
 
        # swap url for compare_diff page - never partial and never as_form
 
        c.swap_url = h.url('compare_url',
 
            repo_name=other_repo,
 
            org_ref_type=other_ref[0], org_ref=other_ref[1],
 
            other_repo=org_repo,
 
            other_ref_type=org_ref[0], other_ref=org_ref[1])
 
            other_ref_type=org_ref[0], other_ref=org_ref[1],
 
            merge=merge or '')
 

	
 
        org_repo = Repository.get_by_repo_name(org_repo)
 
        other_repo = Repository.get_by_repo_name(other_repo)
 

	
 
        self.__get_cs_or_redirect(rev=org_ref, repo=org_repo, partial=partial)
 
        self.__get_cs_or_redirect(rev=other_ref, repo=other_repo, partial=partial)
 
@@ -130,43 +137,29 @@ class CompareController(BaseRepoControll
 
        c.other_repo = other_repo
 
        c.org_ref = org_ref[1]
 
        c.other_ref = other_ref[1]
 
        c.org_ref_type = org_ref[0]
 
        c.other_ref_type = other_ref[0]
 

	
 
        if rev_start and rev_end:
 
            # swap revs with cherry picked ones, save them for display
 
            #org_ref = ('rev', rev_start)
 
            #other_ref = ('rev', rev_end)
 
            c.org_ref = rev_start[:12]
 
            c.other_ref = rev_end[:12]
 
            # get parent of
 
            # rev start to include it in the diff
 
            _cs = other_repo.scm_instance.get_changeset(rev_start)
 
            rev_start = _cs.parents[0].raw_id if _cs.parents else EmptyChangeset().raw_id
 
            org_ref = ('rev', rev_start)
 
            other_ref = ('rev', rev_end)
 
            #if we cherry pick it's not remote, make the other_repo org_repo
 
            org_repo = other_repo
 

	
 
        c.cs_ranges, ancestor = PullRequestModel().get_compare_data(
 
            org_repo, org_ref, other_repo, other_ref)
 
        c.cs_ranges, c.ancestor = PullRequestModel().get_compare_data(
 
            org_repo, org_ref, other_repo, other_ref, merge)
 

	
 
        c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
 
                                                   c.cs_ranges])
 
        if partial:
 
            assert c.ancestor
 
            return render('compare/compare_cs.html')
 

	
 
        if ancestor and org_repo != other_repo:
 
        if c.ancestor:
 
            assert merge
 
            # case we want a simple diff without incoming changesets,
 
            # previewing what will be merged.
 
            # Make the diff on the forked repo, with
 
            # revision that is common ancestor
 
            # Make the diff on the other repo (which is known to have other_ref)
 
            log.debug('Using ancestor %s as org_ref instead of %s'
 
                      % (ancestor, org_ref))
 
            org_ref = ('rev', ancestor)
 
                      % (c.ancestor, org_ref))
 
            org_ref = ('rev', c.ancestor)
 
            org_repo = other_repo
 

	
 
        diff_limit = self.cut_off_limit if not c.fulldiff else None
 

	
 
        _diff = diffs.differ(org_repo, org_ref, other_repo, other_ref)
 

	
rhodecode/controllers/files.py
Show inline comments
 
@@ -24,12 +24,13 @@
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
from __future__ import with_statement
 
import os
 
import logging
 
import traceback
 
import tempfile
 
import shutil
 

	
 
from pylons import request, response, tmpl_context as c, url
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import redirect
 
from rhodecode.lib.utils import jsonify
 

	
 
@@ -312,13 +313,13 @@ class FilesController(BaseRepoController
 
                    category='warning')
 
                return redirect(url('changeset_home', repo_name=c.repo_name,
 
                                    revision='tip'))
 
            try:
 
                self.scm_model.commit_change(repo=c.rhodecode_repo,
 
                                             repo_name=repo_name, cs=c.cs,
 
                                             user=self.rhodecode_user,
 
                                             user=self.rhodecode_user.user_id,
 
                                             author=author, message=message,
 
                                             content=content, f_path=f_path)
 
                h.flash(_('Successfully committed to %s') % f_path,
 
                        category='success')
 

	
 
            except Exception:
 
@@ -375,13 +376,13 @@ class FilesController(BaseRepoController
 
                return redirect(url('changeset_home', repo_name=c.repo_name,
 
                                    revision='tip'))
 

	
 
            try:
 
                self.scm_model.create_node(repo=c.rhodecode_repo,
 
                                           repo_name=repo_name, cs=c.cs,
 
                                           user=self.rhodecode_user,
 
                                           user=self.rhodecode_user.user_id,
 
                                           author=author, message=message,
 
                                           content=content, f_path=node_path)
 
                h.flash(_('Successfully committed to %s') % node_path,
 
                        category='success')
 
            except NodeAlreadyExistsError, e:
 
                h.flash(_(e), category='error')
 
@@ -426,31 +427,62 @@ class FilesController(BaseRepoController
 
        except ChangesetDoesNotExistError:
 
            return _('Unknown revision %s') % revision
 
        except EmptyRepositoryError:
 
            return _('Empty repository')
 
        except (ImproperArchiveTypeError, KeyError):
 
            return _('Unknown archive type')
 
        # archive cache
 
        from rhodecode import CONFIG
 
        rev_name = cs.raw_id[:12]
 
        archive_name = '%s-%s%s' % (safe_str(repo_name.replace('/', '_')),
 
                                    safe_str(rev_name), ext)
 

	
 
        fd, archive = tempfile.mkstemp()
 
        t = open(archive, 'wb')
 
        cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
 
        t.close()
 
        use_cached_archive = False  # defines if we use cached version of archive
 
        archive_cache_enabled = CONFIG.get('archive_cache_dir')
 
        if not subrepos and archive_cache_enabled:
 
            #check if we it's ok to write
 
            if not os.path.isdir(CONFIG['archive_cache_dir']):
 
                os.makedirs(CONFIG['archive_cache_dir'])
 
            cached_archive_path = os.path.join(CONFIG['archive_cache_dir'], archive_name)
 
            if os.path.isfile(cached_archive_path):
 
                log.debug('Found cached archive in %s' % cached_archive_path)
 
                fd, archive = None, cached_archive_path
 
                use_cached_archive = True
 
            else:
 
                log.debug('Archive %s is not yet cached' % (archive_name))
 

	
 
        if not use_cached_archive:
 
            #generate new archive
 
            try:
 
                fd, archive = tempfile.mkstemp()
 
                t = open(archive, 'wb')
 
                log.debug('Creating new temp archive in %s' % archive)
 
                cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
 
                if archive_cache_enabled:
 
                    #if we generated the archive and use cache rename that
 
                    log.debug('Storing new archive in %s' % cached_archive_path)
 
                    shutil.move(archive, cached_archive_path)
 
                    archive = cached_archive_path
 
            finally:
 
                t.close()
 

	
 
        def get_chunked_archive(archive):
 
            stream = open(archive, 'rb')
 
            while True:
 
                data = stream.read(16 * 1024)
 
                if not data:
 
                    stream.close()
 
                    os.close(fd)
 
                    os.remove(archive)
 
                    if fd:  # fd means we used temporary file
 
                        os.close(fd)
 
                    if not archive_cache_enabled:
 
                        log.debug('Destroing temp archive %s' % archive)
 
                        os.remove(archive)
 
                    break
 
                yield data
 

	
 
        response.content_disposition = str('attachment; filename=%s-%s%s' \
 
                                           % (repo_name, revision[:12], ext))
 
        response.content_disposition = str('attachment; filename=%s' % (archive_name))
 
        response.content_type = str(content_type)
 
        return get_chunked_archive(archive)
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
rhodecode/controllers/pullrequests.py
Show inline comments
 
@@ -49,12 +49,13 @@ from rhodecode.model.db import User, Pul
 
from rhodecode.model.pull_request import PullRequestModel
 
from rhodecode.model.meta import Session
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.comment import ChangesetCommentsModel
 
from rhodecode.model.changeset_status import ChangesetStatusModel
 
from rhodecode.model.forms import PullRequestForm
 
from mercurial import scmutil
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class PullrequestsController(BaseRepoController):
 

	
 
@@ -64,13 +65,13 @@ class PullrequestsController(BaseRepoCon
 
    def __before__(self):
 
        super(PullrequestsController, self).__before__()
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 

	
 
    def _get_repo_refs(self, repo, rev=None):
 
    def _get_repo_refs(self, repo, rev=None, branch_rev=None):
 
        """return a structure with repo's interesting changesets, suitable for
 
        the selectors in pullrequest.html"""
 
        branches = [('branch:%s:%s' % (k, v), k)
 
                    for k, v in repo.branches.iteritems()]
 
        bookmarks = [('book:%s:%s' % (k, v), k)
 
                     for k, v in repo.bookmarks.iteritems()]
 
@@ -80,17 +81,31 @@ class PullrequestsController(BaseRepoCon
 

	
 
        tip = repo.tags['tip']
 
        colontip = ':' + tip
 
        tips = [x[1] for x in branches + bookmarks + tags
 
                if x[0].endswith(colontip)]
 
        selected = 'tag:tip:%s' % tip
 
        special = [(selected, 'tip (%s)' % ', '.join(tips))]
 
        special = [(selected, 'tip: %s' % ', '.join(tips))]
 

	
 
        if rev:
 
            selected = 'rev:%s:%s' % (rev, rev)
 
            special.append((selected, rev))
 
            special.append((selected, '%s: %s' % (_("Selected"), rev[:12])))
 

	
 
        # list named branches that has been merged to this named branch - it should probably merge back
 
        if branch_rev:
 
            # not restricting to merge() would also get branch point and be better
 
            # (especially because it would get the branch point) ... but is currently too expensive
 
            revs = ["sort(parents(branch(id('%s')) and merge()) - branch(id('%s')))" %
 
                    (branch_rev, branch_rev)]
 
            otherbranches = {}
 
            for i in scmutil.revrange(repo._repo, revs):
 
                cs = repo.get_changeset(i)
 
                otherbranches[cs.branch] = cs.raw_id
 
            for branch, node in otherbranches.iteritems():
 
                selected = 'branch:%s:%s' % (branch, node)
 
                special.append((selected, '%s: %s' % (_('Peer'), branch)))
 

	
 
        return [(special, _("Special")),
 
                (bookmarks, _("Bookmarks")),
 
                (branches, _("Branches")),
 
                (tags, _("Tags")),
 
                ], selected
 
@@ -118,24 +133,29 @@ class PullrequestsController(BaseRepoCon
 
            org_repo.scm_instance.get_changeset()
 
        except EmptyRepositoryError, e:
 
            h.flash(h.literal(_('There are no changesets yet')),
 
                    category='warning')
 
            redirect(url('summary_home', repo_name=org_repo.repo_name))
 

	
 
        org_rev = request.GET.get('rev_end')
 
        # rev_start is not directly useful - its parent could however be used
 
        # as default for other and thus give a simple compare view
 
        #other_rev = request.POST.get('rev_start')
 

	
 
        other_repos_info = {}
 

	
 
        c.org_repos = []
 
        c.org_repos.append((org_repo.repo_name, org_repo.repo_name))
 
        c.default_org_repo = org_repo.repo_name
 
        c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance)
 
        c.org_refs, c.default_org_ref = self._get_repo_refs(org_repo.scm_instance, org_rev)
 

	
 
        c.other_repos = []
 
        # add org repo to other so we can open pull request against itself
 
        c.other_repos.extend(c.org_repos)
 
        c.default_other_repo = org_repo.repo_name
 
        c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.scm_instance)
 
        c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.scm_instance, branch_rev=org_rev)
 
        usr_data = lambda usr: dict(user_id=usr.user_id,
 
                                    username=usr.username,
 
                                    firstname=usr.firstname,
 
                                    lastname=usr.lastname,
 
                                    gravatar_link=h.gravatar_url(usr.email, 14))
 
        other_repos_info[org_repo.repo_name] = {
 
@@ -188,29 +208,18 @@ class PullrequestsController(BaseRepoCon
 
                msg = _('error during creation of pull request')
 

	
 
            h.flash(msg, 'error')
 
            return redirect(url('pullrequest_home', repo_name=repo_name))
 

	
 
        org_repo = _form['org_repo']
 
        org_ref = _form['org_ref']
 
        org_ref = 'rev:merge:%s' % _form['merge_rev']
 
        other_repo = _form['other_repo']
 
        other_ref = _form['other_ref']
 
        other_ref = 'rev:ancestor:%s' % _form['ancestor_rev']
 
        revisions = _form['revisions']
 
        reviewers = _form['review_members']
 

	
 
        # if we have cherry picked pull request we don't care what is in
 
        # org_ref/other_ref
 
        rev_start = request.POST.get('rev_start')
 
        rev_end = request.POST.get('rev_end')
 

	
 
        if rev_start and rev_end:
 
            # this is swapped to simulate that rev_end is a revision from
 
            # parent of the fork
 
            org_ref = 'rev:%s:%s' % (rev_end, rev_end)
 
            other_ref = 'rev:%s:%s' % (rev_start, rev_start)
 

	
 
        title = _form['pullrequest_title']
 
        description = _form['pullrequest_desc']
 

	
 
        try:
 
            pull_request = PullRequestModel().create(
 
                self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
 
@@ -262,41 +271,34 @@ class PullrequestsController(BaseRepoCon
 
        """
 
        Load context data needed for generating compare diff
 

	
 
        :param pull_request:
 
        :type pull_request:
 
        """
 
        rev_start = request.GET.get('rev_start')
 
        rev_end = request.GET.get('rev_end')
 

	
 
        org_repo = pull_request.org_repo
 
        (org_ref_type,
 
         org_ref_name,
 
         org_ref_rev) = pull_request.org_ref.split(':')
 

	
 
        other_repo = org_repo
 
        (other_ref_type,
 
         other_ref_name,
 
         other_ref_rev) = pull_request.other_ref.split(':')
 

	
 
        # despite opening revisions for bookmarks/branches/tags, we always
 
        # convert this to rev to prevent changes after book or branch change
 
        # convert this to rev to prevent changes after bookmark or branch change
 
        org_ref = ('rev', org_ref_rev)
 
        other_ref = ('rev', other_ref_rev)
 

	
 
        c.org_repo = org_repo
 
        c.other_repo = other_repo
 

	
 
        c.fulldiff = fulldiff = request.GET.get('fulldiff')
 

	
 
        c.cs_ranges = [org_repo.get_changeset(x) for x in pull_request.revisions]
 

	
 
        other_ref = ('rev', getattr(c.cs_ranges[0].parents[0]
 
                                  if c.cs_ranges[0].parents
 
                                  else EmptyChangeset(), 'raw_id'))
 

	
 
        c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
 

	
 
        c.org_ref = org_ref[1]
 
        c.org_ref_type = org_ref[0]
 
        c.other_ref = other_ref[1]
 
        c.other_ref_type = other_ref[0]
 
@@ -391,12 +393,13 @@ class PullrequestsController(BaseRepoCon
 
            c.current_changeset_status = cs_model.calculate_status(
 
                                            c.pull_request_reviewers,
 
                                         )
 
        c.changeset_statuses = ChangesetStatus.STATUSES
 

	
 
        c.as_form = False
 
        c.ancestor = None # there is one - but right here we don't know which
 
        return render('/pullrequests/pullrequest_show.html')
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def comment(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
rhodecode/i18n/en/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3727,13 +3727,13 @@ msgstr ""
 

	
 
#: rhodecode/templates/files/files_browser.html:51
 
msgid "Last modified"
 
msgstr ""
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr ""
 

	
 
#: rhodecode/templates/files/files_edit.html:19
 
msgid "edit file"
 
msgstr ""
 

	
rhodecode/i18n/fr/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3866,13 +3866,13 @@ msgstr "Dernière révision"
 

	
 
#: rhodecode/templates/files/files_browser.html:51
 
msgid "Last modified"
 
msgstr "Dernière modification"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "Dernier commiteur"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
 
msgid "edit file"
 
msgstr "Éditer le fichier"
 

	
rhodecode/i18n/ja/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3740,13 +3740,13 @@ msgstr "最後のリビジョン"
 

	
 
#: rhodecode/templates/files/files_browser.html:51
 
msgid "Last modified"
 
msgstr "最終更新日"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "最後の作成者"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
 
msgid "edit file"
 
msgstr "ファイルを編集"
 

	
rhodecode/i18n/pl/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3833,13 +3833,13 @@ msgstr "Rewizja"
 

	
 
#: rhodecode/templates/files/files_browser.html:51
 
msgid "Last modified"
 
msgstr "Ostatnio modyfikowany"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "Autor"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
 
msgid "edit file"
 
msgstr "edytuj plik"
 

	
rhodecode/i18n/pt_BR/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3907,13 +3907,13 @@ msgstr "Última revisão"
 

	
 
#: rhodecode/templates/files/files_browser.html:51
 
msgid "Last modified"
 
msgstr "Última alteração"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "Último commiter"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
 
msgid "edit file"
 
msgstr "editar arquivo"
 

	
rhodecode/i18n/rhodecode.pot
Show inline comments
 
@@ -3677,13 +3677,13 @@ msgstr ""
 

	
 
#: rhodecode/templates/files/files_browser.html:51
 
msgid "Last modified"
 
msgstr ""
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr ""
 

	
 
#: rhodecode/templates/files/files_edit.html:19
 
msgid "edit file"
 
msgstr ""
 

	
rhodecode/i18n/zh_CN/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3730,13 +3730,13 @@ msgstr "最后修订号"
 

	
 
#: rhodecode/templates/files/files_browser.html:51
 
msgid "Last modified"
 
msgstr "最后修改于"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "最后提交者"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
 
msgid "edit file"
 
msgstr "编辑文件"
 

	
rhodecode/i18n/zh_TW/LC_MESSAGES/rhodecode.po
Show inline comments
 
@@ -3857,13 +3857,13 @@ msgstr "下一個修訂"
 

	
 
#: rhodecode/templates/files/files_browser.html:51
 
msgid "Last modified"
 
msgstr "最後修改"
 

	
 
#: rhodecode/templates/files/files_browser.html:52
 
msgid "Last commiter"
 
msgid "Last committer"
 
msgstr "最後的遞交者"
 

	
 
#: rhodecode/templates/files/files_edit.html:19
 
msgid "edit file"
 
msgstr "編輯檔案"
 

	
rhodecode/lib/base.py
Show inline comments
 
@@ -40,21 +40,23 @@ def _get_ip_addr(environ):
 
    ip = environ.get(proxy_key)
 
    if ip:
 
        return ip
 

	
 
    ip = environ.get(proxy_key2)
 
    if ip:
 
        # HTTP_X_FORWARDED_FOR can have mutliple ips inside
 
        # the left-most being the original client, and each successive proxy
 
        # that passed the request adding the IP address where it received the
 
        # request from.
 
        if ',' in ip:
 
            ip = ip.split(',')[0].strip()
 
        return ip
 

	
 
    ip = environ.get(def_key, '0.0.0.0')
 

	
 
    # HEADERS can have mutliple ips inside
 
    # the left-most being the original client, and each successive proxy
 
    # that passed the request adding the IP address where it received the
 
    # request from.
 
    if ',' in ip:
 
        ip = ip.split(',')[0].strip()
 

	
 
    return ip
 

	
 

	
 
def _get_access_path(environ):
 
    path = environ.get('PATH_INFO')
 
    org_req = environ.get('pylons.original_request')
 
@@ -276,13 +278,12 @@ class BaseController(WSGIController):
 

	
 
    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']
 
        start = time.time()
 
        try:
 
            self.ip_addr = _get_ip_addr(environ)
 
            # make sure that we update permissions each time we call controller
 
            api_key = request.GET.get('api_key')
 
            cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
 
            user_id = cookie_store.get('user_id', None)
 
@@ -297,16 +298,12 @@ class BaseController(WSGIController):
 
                )
 
            log.info('IP: %s User: %s accessed %s' % (
 
               self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
 
            )
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            log.info('IP: %s Request to %s time: %.3fs' % (
 
                _get_ip_addr(environ),
 
                safe_unicode(_get_access_path(environ)), time.time() - start)
 
            )
 
            meta.Session.remove()
 

	
 

	
 
class BaseRepoController(BaseController):
 
    """
 
    Base class for controllers responsible for loading all needed data for
rhodecode/lib/celerylib/__init__.py
Show inline comments
 
@@ -56,22 +56,22 @@ class ResultWrapper(object):
 
    @LazyProperty
 
    def result(self):
 
        return self.task
 

	
 

	
 
def run_task(task, *args, **kwargs):
 
    global CELERY_ON
 
    if CELERY_ON:
 
        try:
 
            t = task.apply_async(args=args, kwargs=kwargs)
 
            log.info('running task %s:%s' % (t.task_id, task))
 
            return t
 

	
 
        except socket.error, e:
 
            if isinstance(e, IOError) and e.errno == 111:
 
                log.debug('Unable to connect to celeryd. Sync execution')
 
                global CELERY_ON
 
                CELERY_ON = False
 
            else:
 
                log.error(traceback.format_exc())
 
        except KeyError, e:
 
                log.debug('Unable to connect to celeryd. Sync execution')
 
        except Exception, e:
rhodecode/lib/exceptions.py
Show inline comments
 
@@ -57,15 +57,20 @@ class UserGroupsAssignedException(Except
 
class StatusChangeOnClosedPullRequestError(Exception):
 
    pass
 

	
 

	
 
class HTTPLockedRC(HTTPClientError):
 
    """
 
    Special Exception For locked Repos in RhodeCode
 
    Special Exception For locked Repos in RhodeCode, the return code can
 
    be overwritten by _code keyword argument passed into constructors
 
    """
 
    code = 423
 
    title = explanation = 'Repository Locked'
 

	
 
    def __init__(self, reponame, username, *args, **kwargs):
 
        from rhodecode import CONFIG
 
        from rhodecode.lib.utils2 import safe_int
 
        _code = CONFIG.get('lock_ret_code')
 
        self.code = safe_int(_code, self.code)
 
        self.title = self.explanation = ('Repository `%s` locked by '
 
                                         'user `%s`' % (reponame, username))
 
        super(HTTPLockedRC, self).__init__(*args, **kwargs)
rhodecode/lib/helpers.py
Show inline comments
 
@@ -547,19 +547,24 @@ def action_parser(user_log, feed=False, 
 
                title = _('Changeset not found')
 
            if parse_cs:
 
                return link_to(lbl, _url, title=title, class_='tooltip')
 
            return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
 
                           class_='lazy-cs' if lazy_cs else '')
 

	
 
        def _get_op(rev_txt):
 
            _op = None
 
            _name = rev_txt
 
            if len(rev_txt.split('=>')) == 2:
 
                _op, _name = rev_txt.split('=>')
 
            return _op, _name
 

	
 
        revs = []
 
        if len(filter(lambda v: v != '', revs_ids)) > 0:
 
            repo = None
 
            for rev in revs_ids[:revs_top_limit]:
 
                _op = _name = None
 
                if len(rev.split('=>')) == 2:
 
                    _op, _name = rev.split('=>')
 
                _op, _name = _get_op(rev)
 

	
 
                # we want parsed changesets, or new log store format is bad
 
                if parse_cs:
 
                    try:
 
                        if repo is None:
 
                            repo = user_log.repository.scm_instance
 
@@ -580,21 +585,25 @@ def action_parser(user_log, feed=False, 
 
                    revs.append(_rev)
 
        cs_links = []
 
        cs_links.append(" " + ', '.join(
 
            [lnk(rev, repo_name) for rev in revs[:revs_limit]]
 
            )
 
        )
 
        _op1, _name1 = _get_op(revs_ids[0])
 
        _op2, _name2 = _get_op(revs_ids[-1])
 

	
 
        _rev = '%s...%s' % (_name1, _name2)
 

	
 
        compare_view = (
 
            ' <div class="compare_view tooltip" title="%s">'
 
            '<a href="%s">%s</a> </div>' % (
 
                _('Show all combined changesets %s->%s') % (
 
                    revs_ids[0][:12], revs_ids[-1][:12]
 
                ),
 
                url('changeset_home', repo_name=repo_name,
 
                    revision='%s...%s' % (revs_ids[0], revs_ids[-1])
 
                    revision=_rev
 
                ),
 
                _('compare view')
 
            )
 
        )
 

	
 
        # if we have exactly one more than normally displayed
rhodecode/lib/hooks.py
Show inline comments
 
@@ -33,13 +33,13 @@ from mercurial.node import nullrev
 

	
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.utils import action_logger
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.exceptions import HTTPLockedRC
 
from rhodecode.lib.utils2 import safe_str, datetime_to_time
 
from rhodecode.lib.utils2 import safe_str
 
from rhodecode.model.db import Repository, User
 

	
 

	
 
def _get_scm_size(alias, root_path):
 

	
 
    if not alias.startswith('.'):
 
@@ -110,13 +110,20 @@ def pre_push(ui, repo, **kwargs):
 
    else:
 
        raise Exception('Missing data in repo.ui and os.environ')
 

	
 
    usr = User.get_by_username(username)
 
    if locked_by[0] and usr.user_id != int(locked_by[0]):
 
        locked_by = User.get(locked_by[0]).username
 
        raise HTTPLockedRC(repository, locked_by)
 
        # this exception is interpreted in git/hg middlewares and based
 
        # on that proper return code is server to client
 
        _http_ret = HTTPLockedRC(repository, locked_by)
 
        if str(_http_ret.code).startswith('2'):
 
            #2xx Codes don't raise exceptions
 
            sys.stdout.write(_http_ret.title)
 
        else:
 
            raise _http_ret
 

	
 

	
 
def pre_pull(ui, repo, **kwargs):
 
    # pre push function, currently used to ban pushing when
 
    # repository is locked
 
    try:
 
@@ -136,13 +143,20 @@ def pre_pull(ui, repo, **kwargs):
 
        locked_by = rc_extras['locked_by']
 
    else:
 
        raise Exception('Missing data in repo.ui and os.environ')
 

	
 
    if locked_by[0]:
 
        locked_by = User.get(locked_by[0]).username
 
        raise HTTPLockedRC(repository, locked_by)
 
        # this exception is interpreted in git/hg middlewares and based
 
        # on that proper return code is server to client
 
        _http_ret = HTTPLockedRC(repository, locked_by)
 
        if str(_http_ret.code).startswith('2'):
 
            #2xx Codes don't raise exceptions
 
            sys.stdout.write(_http_ret.title)
 
        else:
 
            raise _http_ret
 

	
 

	
 
def log_pull_action(ui, repo, **kwargs):
 
    """
 
    Logs user last pull action
 

	
 
@@ -156,18 +170,20 @@ def log_pull_action(ui, repo, **kwargs):
 
    extras = dict(repo.ui.configitems('rhodecode_extras'))
 
    if 'username' in extras:
 
        username = extras['username']
 
        repository = extras['repository']
 
        scm = extras['scm']
 
        make_lock = extras['make_lock']
 
        locked_by = extras['locked_by']
 
        ip = extras['ip']
 
    elif 'username' in rc_extras:
 
        username = rc_extras['username']
 
        repository = rc_extras['repository']
 
        scm = rc_extras['scm']
 
        make_lock = rc_extras['make_lock']
 
        locked_by = rc_extras['locked_by']
 
        ip = rc_extras['ip']
 
    else:
 
        raise Exception('Missing data in repo.ui and os.environ')
 
    user = User.get_by_username(username)
 
    action = 'pull'
 
    action_logger(user, action, repository, ip, commit=True)
 
@@ -182,12 +198,18 @@ def log_pull_action(ui, repo, **kwargs):
 

	
 
    if make_lock is True:
 
        Repository.lock(Repository.get_by_repo_name(repository), user.user_id)
 
        #msg = 'Made lock on repo `%s`' % repository
 
        #sys.stdout.write(msg)
 

	
 
    if locked_by[0]:
 
        locked_by = User.get(locked_by[0]).username
 
        _http_ret = HTTPLockedRC(repository, locked_by)
 
        if str(_http_ret.code).startswith('2'):
 
            #2xx Codes don't raise exceptions
 
            sys.stdout.write(_http_ret.title)
 
    return 0
 

	
 

	
 
def log_push_action(ui, repo, **kwargs):
 
    """
 
    Maps user last push action to new changeset id, from mercurial
 
@@ -204,21 +226,25 @@ def log_push_action(ui, repo, **kwargs):
 
    extras = dict(repo.ui.configitems('rhodecode_extras'))
 
    if 'username' in extras:
 
        username = extras['username']
 
        repository = extras['repository']
 
        scm = extras['scm']
 
        make_lock = extras['make_lock']
 
        locked_by = extras['locked_by']
 
        action = extras['action']
 
    elif 'username' in rc_extras:
 
        username = rc_extras['username']
 
        repository = rc_extras['repository']
 
        scm = rc_extras['scm']
 
        make_lock = rc_extras['make_lock']
 
        locked_by = rc_extras['locked_by']
 
        action = extras['action']
 
    else:
 
        raise Exception('Missing data in repo.ui and os.environ')
 

	
 
    action = 'push' + ':%s'
 
    action = action + ':%s'
 

	
 
    if scm == 'hg':
 
        node = kwargs['node']
 

	
 
        def get_revs(repo, rev_opt):
 
            if rev_opt:
 
@@ -252,12 +278,19 @@ def log_push_action(ui, repo, **kwargs):
 

	
 
    if make_lock is False:
 
        Repository.unlock(Repository.get_by_repo_name(repository))
 
        msg = 'Released lock on repo `%s`\n' % repository
 
        sys.stdout.write(msg)
 

	
 
    if locked_by[0]:
 
        locked_by = User.get(locked_by[0]).username
 
        _http_ret = HTTPLockedRC(repository, locked_by)
 
        if str(_http_ret.code).startswith('2'):
 
            #2xx Codes don't raise exceptions
 
            sys.stdout.write(_http_ret.title)
 

	
 
    return 0
 

	
 

	
 
def log_create_repository(repository_dict, created_by, **kwargs):
 
    """
 
    Post create repository Hook. This is a dummy function for admins to re-use
rhodecode/lib/middleware/simplegit.py
Show inline comments
 
@@ -231,13 +231,14 @@ class SimpleGit(BaseVCSController):
 
            self._handle_githooks(repo_name, action, baseui, environ)
 
            log.info('%s action on GIT repo "%s" by "%s" from %s' %
 
                     (action, repo_name, username, ip_addr))
 
            app = self.__make_app(repo_name, repo_path, extras)
 
            return app(environ, start_response)
 
        except HTTPLockedRC, e:
 
            log.debug('Repository LOCKED ret code 423!')
 
            _code = CONFIG.get('lock_ret_code')
 
            log.debug('Repository LOCKED ret code %s!' % (_code))
 
            return e(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            return HTTPInternalServerError()(environ, start_response)
 
        finally:
 
            # invalidate cache on push
rhodecode/lib/middleware/simplehg.py
Show inline comments
 
@@ -196,13 +196,14 @@ class SimpleHg(BaseVCSController):
 
            app = self.__make_app(repo_path, baseui, extras)
 
            return app(environ, start_response)
 
        except RepoError, e:
 
            if str(e).find('not found') != -1:
 
                return HTTPNotFound()(environ, start_response)
 
        except HTTPLockedRC, e:
 
            log.debug('Repository LOCKED ret code 423!')
 
            _code = CONFIG.get('lock_ret_code')
 
            log.debug('Repository LOCKED ret code %s!' % (_code))
 
            return e(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            return HTTPInternalServerError()(environ, start_response)
 
        finally:
 
            # invalidate cache on push
rhodecode/lib/middleware/wrapper.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.middleware.wrapper
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    request time mesuring app
 

	
 
    :created_on: May 23, 2013
 
    :author: marcink
 
    :copyright: (C) 2010-2012 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 time
 
import logging
 
from rhodecode.lib.base import _get_ip_addr, _get_access_path
 
from rhodecode.lib.utils2 import safe_unicode
 

	
 

	
 
class RequestWrapper(object):
 

	
 
    def __init__(self, app, config):
 
        self.application = app
 
        self.config = config
 

	
 
    def __call__(self, environ, start_response):
 
        start = time.time()
 
        try:
 
            return self.application(environ, start_response)
 
        finally:
 
            log = logging.getLogger('rhodecode.' + self.__class__.__name__)
 
            log.info('IP: %s Request to %s time: %.3fs' % (
 
                _get_ip_addr(environ),
 
                safe_unicode(_get_access_path(environ)), time.time() - start)
 
            )
rhodecode/lib/utils.py
Show inline comments
 
@@ -237,13 +237,13 @@ def is_valid_repo(repo_name, base_path, 
 
            return scm_[0] == scm
 
        return True
 
    except VCSError:
 
        return False
 

	
 

	
 
def is_valid_repos_group(repos_group_name, base_path):
 
def is_valid_repos_group(repos_group_name, base_path, skip_path_check=False):
 
    """
 
    Returns True if given path is a repos group False otherwise
 

	
 
    :param repo_name:
 
    :param base_path:
 
    """
 
@@ -260,13 +260,13 @@ def is_valid_repos_group(repos_group_nam
 
        get_scm(os.path.dirname(full_path))
 
        return False
 
    except VCSError:
 
        pass
 

	
 
    # check if it's a valid path
 
    if os.path.isdir(full_path):
 
    if skip_path_check or os.path.isdir(full_path):
 
        return True
 

	
 
    return False
 

	
 

	
 
def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
 
@@ -492,13 +492,12 @@ def repo2db_mapper(initial_repo_list, re
 
                    sa.commit()
 
                    removed.append(repo.repo_name)
 
                except:
 
                    #don't hold further removals on error
 
                    log.error(traceback.format_exc())
 
                    sa.rollback()
 

	
 
    return added, removed
 

	
 

	
 
# set cache regions for beaker so celery can utilise it
 
def add_cache(settings):
 
    cache_settings = {'regions': None}
rhodecode/lib/utils2.py
Show inline comments
 
@@ -562,16 +562,20 @@ def fix_PATH(os_=None):
 
    cur_path = os.path.split(sys.executable)[0]
 
    if not os.environ['PATH'].startswith(cur_path):
 
        os.environ['PATH'] = '%s:%s' % (cur_path, os.environ['PATH'])
 

	
 

	
 
def obfuscate_url_pw(engine):
 
    from sqlalchemy.engine import url
 
    url = url.make_url(engine)
 
    if url.password:
 
        url.password = 'XXXXX'
 
    return str(url)
 
    _url = engine or ''
 
    from sqlalchemy.engine import url as sa_url
 
    try:
 
        _url = sa_url.make_url(engine)
 
        if _url.password:
 
            _url.password = 'XXXXX'
 
    except:
 
        pass
 
    return str(_url)
 

	
 

	
 
def get_server_url(environ):
 
    req = webob.Request(environ)
 
    return req.host_url + req.script_name
rhodecode/lib/vcs/backends/base.py
Show inline comments
 
@@ -6,13 +6,13 @@
 
    Base for all available scm backends
 

	
 
    :created_on: Apr 8, 2010
 
    :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak.
 
"""
 

	
 

	
 
import datetime
 
from itertools import chain
 
from rhodecode.lib.vcs.utils import author_name, author_email
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
from rhodecode.lib.vcs.utils.helpers import get_dict_for_attrs
 
from rhodecode.lib.vcs.conf import settings
 

	
 
@@ -308,12 +308,33 @@ class BaseRepository(object):
 
    def workdir(self):
 
        """
 
        Returns ``Workdir`` instance for this repository.
 
        """
 
        raise NotImplementedError
 

	
 
    def inject_ui(self, **extras):
 
        """
 
        Injects extra parameters into UI object of this repo
 
        """
 
        required_extras = [
 
            'ip',
 
            'username',
 
            'action',
 
            'repository',
 
            'scm',
 
            'config',
 
            'server_url',
 
            'make_lock',
 
            'locked_by',
 
        ]
 
        for req in required_extras:
 
            if req not in extras:
 
                raise AttributeError('Missing attribute %s in extras' % (req))
 
        for k, v in extras.items():
 
            self._repo.ui.setconfig('rhodecode_extras', k, v)
 

	
 

	
 
class BaseChangeset(object):
 
    """
 
    Each backend should implement it's changeset representation.
 

	
 
    **Attributes**
 
@@ -430,34 +451,34 @@ class BaseChangeset(object):
 
        Returns integer identifying this changeset.
 

	
 
        """
 
        raise NotImplementedError
 

	
 
    @LazyProperty
 
    def commiter(self):
 
    def committer(self):
 
        """
 
        Returns Commiter for given commit
 
        Returns Committer for given commit
 
        """
 

	
 
        raise NotImplementedError
 

	
 
    @LazyProperty
 
    def commiter_name(self):
 
    def committer_name(self):
 
        """
 
        Returns Author name for given commit
 
        """
 

	
 
        return author_name(self.commiter)
 
        return author_name(self.committer)
 

	
 
    @LazyProperty
 
    def commiter_email(self):
 
    def committer_email(self):
 
        """
 
        Returns Author email address for given commit
 
        """
 

	
 
        return author_email(self.commiter)
 
        return author_email(self.committer)
 

	
 
    @LazyProperty
 
    def author(self):
 
        """
 
        Returns Author for given commit
 
        """
 
@@ -956,18 +977,18 @@ class EmptyChangeset(BaseChangeset):
 
    """
 
    An dummy empty changeset. It's possible to pass hash when creating
 
    an EmptyChangeset
 
    """
 

	
 
    def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
 
                 alias=None, revision=-1, message='', author='', date=''):
 
                 alias=None, revision=-1, message='', author='', date=None):
 
        self._empty_cs = cs
 
        self.revision = revision
 
        self.message = message
 
        self.author = author
 
        self.date = date
 
        self.date = date or datetime.datetime.fromtimestamp(0)
 
        self.repository = repo
 
        self.requested_revision = requested_revision
 
        self.alias = alias
 

	
 
    @LazyProperty
 
    def raw_id(self):
rhodecode/lib/vcs/backends/git/changeset.py
Show inline comments
 
@@ -14,12 +14,13 @@ from rhodecode.lib.vcs.backends.base imp
 
from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, \
 
    RemovedFileNode, SubModuleNode, ChangedFileNodesGenerator,\
 
    AddedFileNodesGenerator, RemovedFileNodesGenerator
 
from rhodecode.lib.vcs.utils import safe_unicode
 
from rhodecode.lib.vcs.utils import date_fromtimestamp
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
from rhodecode.lib.utils2 import safe_int
 

	
 

	
 
class GitChangeset(BaseChangeset):
 
    """
 
    Represents state of the repository at single revision.
 
    """
 
@@ -38,26 +39,26 @@ class GitChangeset(BaseChangeset):
 
        self.raw_id = revision
 
        self.id = self.raw_id
 
        self.short_id = self.raw_id[:12]
 
        self._commit = commit
 

	
 
        self._tree_id = commit.tree
 
        self._commiter_property = 'committer'
 
        self._committer_property = 'committer'
 
        self._author_property = 'author'
 
        self._date_property = 'commit_time'
 
        self._date_tz_property = 'commit_timezone'
 
        self.revision = repository.revisions.index(revision)
 

	
 
        self.message = safe_unicode(commit.message)
 

	
 
        self.nodes = {}
 
        self._paths = {}
 

	
 
    @LazyProperty
 
    def commiter(self):
 
        return safe_unicode(getattr(self._commit, self._commiter_property))
 
    def committer(self):
 
        return safe_unicode(getattr(self._commit, self._committer_property))
 

	
 
    @LazyProperty
 
    def author(self):
 
        return safe_unicode(getattr(self._commit, self._author_property))
 

	
 
    @LazyProperty
 
@@ -272,29 +273,33 @@ class GitChangeset(BaseChangeset):
 
        return blob.raw_length()
 

	
 
    def get_file_changeset(self, path):
 
        """
 
        Returns last commit of the file at the given ``path``.
 
        """
 
        node = self.get_node(path)
 
        return node.history[0]
 
        return self.get_file_history(path, limit=1)[0]
 

	
 
    def get_file_history(self, path):
 
    def get_file_history(self, path, limit=None):
 
        """
 
        Returns history of file as reversed list of ``Changeset`` objects for
 
        which file at given ``path`` has been modified.
 

	
 
        TODO: This function now uses os underlying 'git' and 'grep' commands
 
        which is generally not good. Should be replaced with algorithm
 
        iterating commits.
 
        """
 

	
 
        self._get_filectx(path)
 

	
 
        cmd = 'log --pretty="format: %%H" -s -p %s -- "%s"' % (
 
                  self.id, path
 
               )
 
        if limit:
 
            cmd = 'log -n %s --pretty="format: %%H" -s -p %s -- "%s"' % (
 
                      safe_int(limit, 0), self.id, path
 
                   )
 
        else:
 
            cmd = 'log --pretty="format: %%H" -s -p %s -- "%s"' % (
 
                      self.id, path
 
                   )
 
        so, se = self.repository.run_git_command(cmd)
 
        ids = re.findall(r'[0-9a-fA-F]{40}', so)
 
        return [self.repository.get_changeset(id) for id in ids]
 

	
 
    def get_file_history_2(self, path):
 
        """
rhodecode/lib/vcs/backends/git/repository.py
Show inline comments
 
@@ -64,20 +64,18 @@ class GitRepository(BaseRepository):
 
            abspath(get_user_home(), '.gitconfig'),
 
        ]
 

	
 
    @ThreadLocalLazyProperty
 
    def _repo(self):
 
        repo = Repo(self.path)
 
        #temporary set that to now at later we will move it to constructor
 
        baseui = None
 
        if baseui is None:
 
        # patch the instance of GitRepo with an "FAKE" ui object to add
 
        # compatibility layer with Mercurial
 
        if not hasattr(repo, 'ui'):
 
            from mercurial.ui import ui
 
            baseui = ui()
 
        # patch the instance of GitRepo with an "FAKE" ui object to add
 
        # compatibility layer with Mercurial
 
        setattr(repo, 'ui', baseui)
 
            setattr(repo, 'ui', baseui)
 
        return repo
 

	
 
    @property
 
    def head(self):
 
        try:
 
            return self._repo.head()
 
@@ -303,12 +301,21 @@ class GitRepository(BaseRepository):
 
        """
 
        url = str(url)
 
        if url != 'default' and not '://' in url:
 
            url = ':///'.join(('file', url))
 
        return url
 

	
 
    def get_hook_location(self):
 
        """
 
        returns absolute path to location where hooks are stored
 
        """
 
        loc = os.path.join(self.path, 'hooks')
 
        if not self.bare:
 
            loc = os.path.join(self.path, '.git', 'hooks')
 
        return loc
 

	
 
    @LazyProperty
 
    def name(self):
 
        return os.path.basename(self.path)
 

	
 
    @LazyProperty
 
    def last_change(self):
rhodecode/lib/vcs/backends/hg/changeset.py
Show inline comments
 
@@ -41,14 +41,14 @@ class MercurialChangeset(BaseChangeset):
 

	
 
    @LazyProperty
 
    def message(self):
 
        return safe_unicode(self._ctx.description())
 

	
 
    @LazyProperty
 
    def commiter(self):
 
        return safe_unicode(self.auhtor)
 
    def committer(self):
 
        return safe_unicode(self.author)
 

	
 
    @LazyProperty
 
    def author(self):
 
        return safe_unicode(self._ctx.user())
 

	
 
    @LazyProperty
 
@@ -216,25 +216,29 @@ class MercurialChangeset(BaseChangeset):
 
        return fctx.size()
 

	
 
    def get_file_changeset(self, path):
 
        """
 
        Returns last commit of the file at the given ``path``.
 
        """
 
        node = self.get_node(path)
 
        return node.history[0]
 
        return self.get_file_history(path, limit=1)[0]
 

	
 
    def get_file_history(self, path):
 
    def get_file_history(self, path, limit=None):
 
        """
 
        Returns history of file as reversed list of ``Changeset`` objects for
 
        which file at given ``path`` has been modified.
 
        """
 
        fctx = self._get_filectx(path)
 
        nodes = [fctx.filectx(x).node() for x in fctx.filelog()]
 
        changesets = [self.repository.get_changeset(hex(node))
 
            for node in reversed(nodes)]
 
        return changesets
 
        hist = []
 
        cnt = 0
 
        for cs in reversed([x for x in fctx.filelog()]):
 
            cnt += 1
 
            hist.append(hex(fctx.filectx(cs).node()))
 
            if limit and cnt == limit:
 
                break
 

	
 
        return [self.repository.get_changeset(node) for node in hist]
 

	
 
    def get_file_annotate(self, path):
 
        """
 
        Returns a generator of four element tuples with
 
            lineno, sha, changeset lazy loader and line
 
        """
rhodecode/lib/vcs/backends/hg/repository.py
Show inline comments
 
@@ -419,12 +419,18 @@ class MercurialRepository(BaseRepository
 
        """
 
        url = str(url)
 
        if url != 'default' and not '://' in url:
 
            url = "file:" + urllib.pathname2url(url)
 
        return url
 

	
 
    def get_hook_location(self):
 
        """
 
        returns absolute path to location where hooks are stored
 
        """
 
        return os.path.join(self.path, '.hg', '.hgrc')
 

	
 
    def get_changeset(self, revision=None):
 
        """
 
        Returns ``MercurialChangeset`` object representing repository's
 
        changeset at the given ``revision``.
 
        """
 
        revision = self._get_revision(revision)
 
@@ -489,13 +495,13 @@ class MercurialRepository(BaseRepository
 
    def workdir(self):
 
        """
 
        Returns ``Workdir`` instance for this repository.
 
        """
 
        return MercurialWorkdir(self)
 

	
 
    def get_config_value(self, section, name, config_file=None):
 
    def get_config_value(self, section, name=None, config_file=None):
 
        """
 
        Returns configuration value for a given [``section``] and ``name``.
 

	
 
        :param section: Section we want to retrieve value from
 
        :param name: Name of configuration we want to retrieve
 
        :param config_file: A path to file which should be used to retrieve
rhodecode/lib/vcs/utils/lazy.py
Show inline comments
 
class _Missing(object):
 

	
 
    def __repr__(self):
 
        return 'no value'
 

	
 
    def __reduce__(self):
 
        return '_missing'
 

	
 
_missing = _Missing()
 

	
 

	
 
class LazyProperty(object):
 
    """
 
    Decorator for easier creation of ``property`` from potentially expensive to
 
    calculate attribute of the class.
 

	
 
    Usage::
 
@@ -21,14 +32,17 @@ class LazyProperty(object):
 
        self.__name__ = func.__name__
 
        self.__doc__ = func.__doc__
 

	
 
    def __get__(self, obj, klass=None):
 
        if obj is None:
 
            return self
 
        result = obj.__dict__[self.__name__] = self._func(obj)
 
        return result
 
        value = obj.__dict__.get(self.__name__, _missing)
 
        if value is _missing:
 
            value = self._func(obj)
 
            obj.__dict__[self.__name__] = value
 
        return value
 

	
 
import threading
 

	
 

	
 
class ThreadLocalLazyProperty(LazyProperty):
 
    """
 
@@ -38,8 +52,11 @@ class ThreadLocalLazyProperty(LazyProper
 
    def __get__(self, obj, klass=None):
 
        if obj is None:
 
            return self
 
        if not hasattr(obj, '__tl_dict__'):
 
            obj.__tl_dict__ = threading.local().__dict__
 

	
 
        result = obj.__tl_dict__[self.__name__] = self._func(obj)
 
        return result
 
        value = obj.__tl_dict__.get(self.__name__, _missing)
 
        if value is _missing:
 
            value = self._func(obj)
 
            obj.__tl_dict__[self.__name__] = value
 
        return value
rhodecode/model/db.py
Show inline comments
 
@@ -44,13 +44,13 @@ from rhodecode.lib.vcs import get_backen
 
from rhodecode.lib.vcs.utils.helpers import get_scm
 
from rhodecode.lib.vcs.exceptions import VCSError
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 

	
 
from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
 
    safe_unicode, remove_suffix, remove_prefix
 
    safe_unicode, remove_suffix, remove_prefix, time_to_datetime
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.caching_query import FromCache
 

	
 
from rhodecode.model.meta import Base, Session
 

	
 
URL_SEP = '/'
 
@@ -935,21 +935,13 @@ class Repository(Base, BaseModel):
 
        """
 
        from rhodecode.lib.utils import make_ui
 
        return make_ui('db', clear_session=False)
 

	
 
    @classmethod
 
    def inject_ui(cls, repo, extras={}):
 
        from rhodecode.lib.vcs.backends.hg import MercurialRepository
 
        from rhodecode.lib.vcs.backends.git import GitRepository
 
        required = (MercurialRepository, GitRepository)
 
        if not isinstance(repo, required):
 
            raise Exception('repo must be instance of %s' % required)
 

	
 
        # inject ui extra param to log this action via push logger
 
        for k, v in extras.items():
 
            repo._repo.ui.setconfig('rhodecode_extras', k, v)
 
        repo.inject_ui(extras)
 

	
 
    @classmethod
 
    def is_valid(cls, repo_name):
 
        """
 
        returns True if given repo name is a valid filesystem repository
 

	
 
@@ -977,13 +969,17 @@ class Repository(Base, BaseModel):
 
            landing_rev=repo.landing_rev,
 
            owner=repo.user.username,
 
            fork_of=repo.fork.repo_name if repo.fork else None,
 
            enable_statistics=repo.enable_statistics,
 
            enable_locking=repo.enable_locking,
 
            enable_downloads=repo.enable_downloads,
 
            last_changeset=repo.changeset_cache
 
            last_changeset=repo.changeset_cache,
 
            locked_by=User.get(self.locked[0]).get_api_data() \
 
                if self.locked[0] else None,
 
            locked_date=time_to_datetime(self.locked[1]) \
 
                if self.locked[1] else None
 
        )
 
        rc_config = RhodeCodeSetting.get_app_settings()
 
        repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
 
        if repository_fields:
 
            for f in self.extra_fields:
 
                data[f.field_key_prefixed] = f.field_value
 
@@ -999,12 +995,16 @@ class Repository(Base, BaseModel):
 
    @classmethod
 
    def unlock(cls, repo):
 
        repo.locked = None
 
        Session().add(repo)
 
        Session().commit()
 

	
 
    @classmethod
 
    def getlock(cls, repo):
 
        return repo.locked
 

	
 
    @property
 
    def last_db_change(self):
 
        return self.updated_on
 

	
 
    def clone_url(self, **override):
 
        from pylons import url
 
@@ -1338,30 +1338,40 @@ class RepoGroup(Base, BaseModel):
 
                cnt += child.repositories.count()
 
                cnt += children_count(child)
 
            return cnt
 

	
 
        return cnt + children_count(self)
 

	
 
    def recursive_groups_and_repos(self):
 
        """
 
        Recursive return all groups, with repositories in those groups
 
        """
 
    def _recursive_objects(self, include_repos=True):
 
        all_ = []
 

	
 
        def _get_members(root_gr):
 
            for r in root_gr.repositories:
 
                all_.append(r)
 
            if include_repos:
 
                for r in root_gr.repositories:
 
                    all_.append(r)
 
            childs = root_gr.children.all()
 
            if childs:
 
                for gr in childs:
 
                    all_.append(gr)
 
                    _get_members(gr)
 

	
 
        _get_members(self)
 
        return [self] + all_
 

	
 
    def recursive_groups_and_repos(self):
 
        """
 
        Recursive return all groups, with repositories in those groups
 
        """
 
        return self._recursive_objects()
 

	
 
    def recursive_groups(self):
 
        """
 
        Returns all children groups for this group including children of children
 
        """
 
        return self._recursive_objects(include_repos=False)
 

	
 
    def get_new_name(self, group_name):
 
        """
 
        returns new full group name based on parent and new name
 

	
 
        :param group_name:
 
        """
 
@@ -1725,13 +1735,13 @@ class CacheInvalidation(Base, BaseModel)
 
            inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
 

	
 
        try:
 
            for inv_obj in inv_objs:
 
                inv_obj.cache_active = False
 
                log.debug('marking %s key for invalidation based on key=%s,repo_name=%s'
 
                  % (inv_obj, key, repo_name))
 
                  % (inv_obj, key, safe_str(repo_name)))
 
                invalidated_keys.append(inv_obj.cache_key)
 
                Session().add(inv_obj)
 
            Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            Session().rollback()
rhodecode/model/forms.py
Show inline comments
 
@@ -392,7 +392,10 @@ def PullRequestForm(repo_id):
 
                        v.UniqueList(not_empty=True))
 
        review_members = v.UniqueList(not_empty=True)
 

	
 
        pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
 
        pullrequest_desc = v.UnicodeString(strip=True, required=False)
 

	
 
        ancestor_rev = v.UnicodeString(strip=True, required=True)
 
        merge_rev = v.UnicodeString(strip=True, required=True)
 

	
 
    return _PullRequestForm
rhodecode/model/pull_request.py
Show inline comments
 
@@ -158,13 +158,13 @@ class PullRequestModel(BaseModel):
 
    def close_pull_request(self, pull_request):
 
        pull_request = self.__get_pull_request(pull_request)
 
        pull_request.status = PullRequest.STATUS_CLOSED
 
        pull_request.updated_on = datetime.datetime.now()
 
        Session().add(pull_request)
 

	
 
    def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref):
 
    def _get_changesets(self, alias, org_repo, org_ref, other_repo, other_ref, merge):
 
        """
 
        Returns a list of changesets that can be merged from org_repo@org_ref
 
        to other_repo@other_ref ... and the ancestor that would be used for merge
 

	
 
        :param org_repo:
 
        :param org_ref:
 
@@ -208,35 +208,40 @@ class PullRequestModel(BaseModel):
 
                # so rev numbers from hgrepo can be used in other_repo
 

	
 
            #no remote compare do it on the same repository
 
            else:
 
                hgrepo = other_repo._repo
 

	
 
            revs = ["ancestors(id('%s')) and not ancestors(id('%s'))" %
 
                    (other_rev, org_rev)]
 
            changesets = [other_repo.get_changeset(cs)
 
                          for cs in scmutil.revrange(hgrepo, revs)]
 
            if merge:
 
                revs = ["ancestors(id('%s')) and not ancestors(id('%s')) and not id('%s')" %
 
                        (other_rev, org_rev, org_rev)]
 

	
 
            if org_repo != other_repo:
 
                ancestors = scmutil.revrange(hgrepo,
 
                     ["ancestor(id('%s'), id('%s'))" % (org_rev, other_rev)])
 
                if len(ancestors) == 1:
 
                    ancestor = hgrepo[ancestors[0]].hex()
 
            else:
 
                # TODO: have both + and - changesets
 
                revs = ["id('%s') :: id('%s') - id('%s')" %
 
                        (org_rev, other_rev, org_rev)]
 

	
 
            changesets = [other_repo.get_changeset(cs)
 
                          for cs in scmutil.revrange(hgrepo, revs)]
 

	
 
        elif alias == 'git':
 
            assert org_repo == other_repo, (org_repo, other_repo) # no git support for different repos
 
            so, se = org_repo.run_git_command(
 
                'log --reverse --pretty="format: %%H" -s -p %s..%s' % (org_ref[1],
 
                                                                       other_ref[1])
 
            )
 
            changesets = [org_repo.get_changeset(cs)
 
                          for cs in re.findall(r'[0-9a-fA-F]{40}', so)]
 

	
 
        return changesets, ancestor
 

	
 
    def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
 
    def get_compare_data(self, org_repo, org_ref, other_repo, other_ref, merge):
 
        """
 
        Returns incoming changesets for mercurial repositories
 

	
 
        :param org_repo:
 
        :param org_ref:
 
        :param other_repo:
 
@@ -248,8 +253,9 @@ class PullRequestModel(BaseModel):
 

	
 
        if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
 
            raise Exception('other_ref must be a two element list/tuple')
 

	
 
        cs_ranges, ancestor = self._get_changesets(org_repo.scm_instance.alias,
 
                                                   org_repo.scm_instance, org_ref,
 
                                                   other_repo.scm_instance, other_ref)
 
                                                   other_repo.scm_instance, other_ref,
 
                                                   merge)
 
        return cs_ranges, ancestor
rhodecode/model/repo.py
Show inline comments
 
@@ -29,24 +29,22 @@ import logging
 
import traceback
 
from datetime import datetime
 

	
 
from rhodecode.lib.vcs.backends import get_backend
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode,\
 
    remove_prefix
 
    remove_prefix, obfuscate_url_pw
 
from rhodecode.lib.caching_query import FromCache
 
from rhodecode.lib.hooks import log_create_repository, log_delete_repository
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
 
    Statistics, UserGroup, UserGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
 
    RhodeCodeSetting, RepositoryField
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import HasRepoPermissionAny
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class RepoModel(BaseModel):
 

	
 
@@ -637,13 +635,14 @@ class RepoModel(BaseModel):
 

	
 
        # check if this path is a group
 
        if is_valid_repos_group(repo_path, self.repos_path):
 
            raise Exception('This path %s is a valid group' % repo_path)
 

	
 
        log.info('creating repo %s in %s @ %s' % (
 
                     repo_name, safe_unicode(repo_path), clone_uri
 
                     repo_name, safe_unicode(repo_path),
 
                     obfuscate_url_pw(clone_uri)
 
                )
 
        )
 
        backend = get_backend(alias)
 
        if alias == 'hg':
 
            backend(repo_path, create=True, src_url=clone_uri)
 
        elif alias == 'git':
rhodecode/model/repos_group.py
Show inline comments
 
@@ -246,33 +246,43 @@ class ReposGroupModel(BaseModel):
 
                                     form_data['perms_updates'], recursive)
 

	
 
            old_path = repos_group.full_path
 

	
 
            # change properties
 
            repos_group.group_description = form_data['group_description']
 
            repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
 
            repos_group.group_parent_id = form_data['group_parent_id']
 
            repos_group.enable_locking = form_data['enable_locking']
 

	
 
            repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
 
            repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
 
            new_path = repos_group.full_path
 

	
 
            self.sa.add(repos_group)
 

	
 
            # iterate over all members of this groups and set the locking !
 
            # iterate over all members of this groups and do fixes
 
            # set locking if given
 
            # if obj is a repoGroup also fix the name of the group according
 
            # to the parent
 
            # if obj is a Repo fix it's name
 
            # this can be potentially heavy operation
 
            for obj in repos_group.recursive_groups_and_repos():
 
                #set the value from it's parent
 
                obj.enable_locking = repos_group.enable_locking
 
                if isinstance(obj, RepoGroup):
 
                    new_name = obj.get_new_name(obj.name)
 
                    log.debug('Fixing group %s to new name %s' \
 
                                % (obj.group_name, new_name))
 
                    obj.group_name = new_name
 
                elif isinstance(obj, Repository):
 
                    # we need to get all repositories from this new group and
 
                    # rename them accordingly to new group path
 
                    new_name = obj.get_new_name(obj.just_name)
 
                    log.debug('Fixing repo %s to new name %s' \
 
                                % (obj.repo_name, new_name))
 
                    obj.repo_name = new_name
 
                self.sa.add(obj)
 

	
 
            # we need to get all repositories from this new group and
 
            # rename them accordingly to new group path
 
            for r in repos_group.repositories:
 
                r.repo_name = r.get_new_name(r.just_name)
 
                self.sa.add(r)
 

	
 
            self.__rename_group(old_path, new_path)
 

	
 
            return repos_group
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
rhodecode/model/scm.py
Show inline comments
 
@@ -41,19 +41,20 @@ from rhodecode.lib.vcs.exceptions import
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
from rhodecode.lib.vcs.nodes import FileNode
 
from rhodecode.lib.vcs.backends.base import EmptyChangeset
 

	
 
from rhodecode import BACKENDS
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.utils2 import safe_str, safe_unicode
 
from rhodecode.lib.utils2 import safe_str, safe_unicode, get_server_url
 
from rhodecode.lib.auth import HasRepoPermissionAny, HasReposGroupPermissionAny
 
from rhodecode.lib.utils import get_filesystem_repos, make_ui, \
 
    action_logger, REMOVED_REPO_PAT
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
 
    UserFollowing, UserLog, User, RepoGroup, PullRequest
 
from rhodecode.lib.hooks import log_push_action
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class UserTemp(object):
 
    def __init__(self, user_id):
 
@@ -399,58 +400,94 @@ class ScmModel(BaseModel):
 
        if fork and repo.repo_id == fork.repo_id:
 
            raise Exception("Cannot set repository as fork of itself")
 
        repo.fork = fork
 
        self.sa.add(repo)
 
        return repo
 

	
 
    def _handle_push(self, repo, username, action, repo_name, revisions):
 
        """
 
        Triggers push action hooks
 

	
 
        :param repo: SCM repo
 
        :param username: username who pushes
 
        :param action: push/push_loca/push_remote
 
        :param repo_name: name of repo
 
        :param revisions: list of revisions that we pushed
 
        """
 
        from rhodecode import CONFIG
 
        from rhodecode.lib.base import _get_ip_addr
 
        try:
 
            from pylons import request
 
            environ = request.environ
 
        except TypeError:
 
            # we might use this outside of request context, let's fake the
 
            # environ data
 
            from webob import Request
 
            environ = Request.blank('').environ
 

	
 
        #trigger push hook
 
        extras = {
 
            'ip': _get_ip_addr(environ),
 
            'username': username,
 
            'action': 'push_local',
 
            'repository': repo_name,
 
            'scm': repo.alias,
 
            'config': CONFIG['__file__'],
 
            'server_url': get_server_url(environ),
 
            'make_lock': None,
 
            'locked_by': [None, None]
 
        }
 
        _scm_repo = repo._repo
 
        repo.inject_ui(**extras)
 
        if repo.alias == 'hg':
 
            log_push_action(_scm_repo.ui, _scm_repo, node=revisions[0])
 
        elif repo.alias == 'git':
 
            log_push_action(_scm_repo.ui, _scm_repo, _git_revs=revisions)
 

	
 
    def _get_IMC_module(self, scm_type):
 
        """
 
        Returns InMemoryCommit class based on scm_type
 

	
 
        :param scm_type:
 
        """
 
        if scm_type == 'hg':
 
            from rhodecode.lib.vcs.backends.hg import \
 
                MercurialInMemoryChangeset as IMC
 
        elif scm_type == 'git':
 
            from rhodecode.lib.vcs.backends.git import \
 
                GitInMemoryChangeset as IMC
 
        return IMC
 

	
 
    def pull_changes(self, repo, username):
 
        dbrepo = self.__get_repo(repo)
 
        clone_uri = dbrepo.clone_uri
 
        if not clone_uri:
 
            raise Exception("This repository doesn't have a clone uri")
 

	
 
        repo = dbrepo.scm_instance
 
        from rhodecode import CONFIG
 
        repo_name = dbrepo.repo_name
 
        try:
 
            extras = {
 
                'ip': '',
 
                'username': username,
 
                'action': 'push_remote',
 
                'repository': dbrepo.repo_name,
 
                'scm': repo.alias,
 
                'config': CONFIG['__file__'],
 
                'make_lock': None,
 
                'locked_by': [None, None]
 
            }
 

	
 
            Repository.inject_ui(repo, extras=extras)
 

	
 
            if repo.alias == 'git':
 
                repo.fetch(clone_uri)
 
            else:
 
                repo.pull(clone_uri)
 
            self.mark_for_invalidation(dbrepo.repo_name)
 
            self.mark_for_invalidation(repo_name)
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def commit_change(self, repo, repo_name, cs, user, author, message,
 
                      content, f_path):
 
        """
 
        Commits changes
 

	
 
        :param repo: SCM instance
 

	
 
        """
 

	
 
        if repo.alias == 'hg':
 
            from rhodecode.lib.vcs.backends.hg import \
 
                MercurialInMemoryChangeset as IMC
 
        elif repo.alias == 'git':
 
            from rhodecode.lib.vcs.backends.git import \
 
                GitInMemoryChangeset as IMC
 
        user = self._get_user(user)
 
        IMC = self._get_IMC_module(repo.alias)
 

	
 
        # decoding here will force that we have proper encoded values
 
        # in any other case this will throw exceptions and deny commit
 
        content = safe_str(content)
 
        path = safe_str(f_path)
 
        # message and author needs to be unicode
 
@@ -460,26 +497,27 @@ class ScmModel(BaseModel):
 
        m = IMC(repo)
 
        m.change(FileNode(path, content))
 
        tip = m.commit(message=message,
 
                       author=author,
 
                       parents=[cs], branch=cs.branch)
 

	
 
        action = 'push_local:%s' % tip.raw_id
 
        action_logger(user, action, repo_name)
 
        self.mark_for_invalidation(repo_name)
 
        self._handle_push(repo,
 
                          username=user.username,
 
                          action='push_local',
 
                          repo_name=repo_name,
 
                          revisions=[tip.raw_id])
 
        return tip
 

	
 
    def create_node(self, repo, repo_name, cs, user, author, message, content,
 
                      f_path):
 
        if repo.alias == 'hg':
 
            from rhodecode.lib.vcs.backends.hg import MercurialInMemoryChangeset as IMC
 
        elif repo.alias == 'git':
 
            from rhodecode.lib.vcs.backends.git import GitInMemoryChangeset as IMC
 
        user = self._get_user(user)
 
        IMC = self._get_IMC_module(repo.alias)
 

	
 
        # decoding here will force that we have proper encoded values
 
        # in any other case this will throw exceptions and deny commit
 

	
 
        if isinstance(content, (basestring,)):
 
            content = safe_str(content)
 
        elif isinstance(content, (file, cStringIO.OutputType,)):
 
            content = content.read()
 
        else:
 
            raise Exception('Content is of unrecognized type %s' % (
 
@@ -499,15 +537,18 @@ class ScmModel(BaseModel):
 

	
 
        m.add(FileNode(path, content=content))
 
        tip = m.commit(message=message,
 
                       author=author,
 
                       parents=parents, branch=cs.branch)
 

	
 
        action = 'push_local:%s' % tip.raw_id
 
        action_logger(user, action, repo_name)
 
        self.mark_for_invalidation(repo_name)
 
        self._handle_push(repo,
 
                          username=user.username,
 
                          action='push_local',
 
                          repo_name=repo_name,
 
                          revisions=[tip.raw_id])
 
        return tip
 

	
 
    def get_nodes(self, repo_name, revision, root_path='/', flat=True):
 
        """
 
        recursive walk in root dir and return a set of all path in that dir
 
        based on repository walk function
rhodecode/model/validators.py
Show inline comments
 
@@ -413,23 +413,27 @@ def ValidCloneUri():
 
                httppeer(ui, url)._capabilities()
 
            elif url.startswith('svn+http'):
 
                from hgsubversion.svnrepo import svnremoterepo
 
                svnremoterepo(ui, url).capabilities
 
            elif url.startswith('git+http'):
 
                raise NotImplementedError()
 
            else:
 
                raise Exception('clone from URI %s not allowed' % (url))
 

	
 
        elif repo_type == 'git':
 
            from rhodecode.lib.vcs.backends.git.repository import GitRepository
 
            if url.startswith('http'):
 
                ## initially check if it's at least the proper URL
 
                ## or does it pass basic auth
 
                GitRepository._check_url(url)
 
            elif url.startswith('svn+http'):
 
                raise NotImplementedError()
 
            elif url.startswith('hg+http'):
 
                raise NotImplementedError()
 
            else:
 
                raise Exception('clone from URI %s not allowed' % (url))
 

	
 
    class _validator(formencode.validators.FancyValidator):
 
        messages = {
 
            'clone_uri': _(u'invalid clone url'),
 
            'invalid_clone_uri': _(u'Invalid clone url, provide a '
 
                                    'valid clone http(s)/svn+http(s) url')
rhodecode/public/css/codemirror.css
Show inline comments
 
@@ -168,7 +168,7 @@ div.CodeMirror span.CodeMirror-nonmatchi
 

	
 
  /* Hide the cursor when printing */
 
  .CodeMirror pre.CodeMirror-cursor {
 
    visibility: hidden;
 
  }
 

	
 
}
 
}
 
\ No newline at end of file
rhodecode/public/css/pygments.css
Show inline comments
 
@@ -11,56 +11,56 @@ div.codeblock {
 
    -moz-border-radius: 4px;
 
    border-radius: 4px;
 
}
 
div.codeblock .code-header {
 
    border-bottom: 1px solid #CCCCCC;
 
    background: #EEEEEE;
 
    padding:10px 0 10px 0;
 
    padding: 10px 0 10px 0;
 
}
 

	
 
div.codeblock .code-header .stats {
 
    clear: both;
 
    padding: 6px 8px 6px 10px;
 
    border-bottom: 1px solid rgb(204, 204, 204);
 
    height: 23px;
 
    margin-bottom: 6px;
 
}
 

	
 
div.codeblock .code-header .stats .left {
 
    float:left;
 
    float: left;
 
}
 
div.codeblock .code-header .stats .left.img {
 
    margin-top:-2px;
 
    margin-top: -2px;
 
}
 
div.codeblock .code-header .stats .left.item {
 
    float:left;
 
    float: left;
 
    padding: 0 9px 0 9px;
 
    border-right:1px solid #ccc;
 
    border-right: 1px solid #ccc;
 
}
 
div.codeblock .code-header .stats .left.item pre {
 
}
 
div.codeblock .code-header .stats .left.item.last {
 
    border-right:none;
 
    border-right: none;
 
}
 
div.codeblock .code-header .stats .buttons {
 
    float:right;
 
    padding-right:4px;
 
    float: right;
 
    padding-right: 4px;
 
}
 

	
 
div.codeblock .code-header .author {
 
    margin-left:25px;
 
    margin-left: 25px;
 
    font-weight: bold;
 
    height: 25px;
 
}
 
div.codeblock .code-header .author .user {
 
    padding-top:3px;
 
    padding-top: 3px;
 
}
 
div.codeblock .code-header .commit {
 
    margin-left:25px;
 
    margin-left: 25px;
 
    font-weight: normal;
 
    white-space:pre;
 
    white-space: pre;
 
}
 

	
 
div.codeblock .code-body table {
 
    width: 0 !important;
 
    border: 0px !important;
 
}
 
@@ -87,14 +87,14 @@ div.search-code-body pre .break {
 
    background-color: #DDE7EF;
 
    width: 100%;
 
    color: #747474;
 
    display: block;
 
}
 
div.annotatediv {
 
    margin-left:2px;
 
    margin-right:4px;
 
    margin-left: 2px;
 
    margin-right: 4px;
 
}
 
.code-highlight {
 
    padding: 0px;
 
    margin-top: 5px;
 
    margin-bottom: 5px;
 
    border-left: 2px solid #ccc;
 
@@ -167,7 +167,7 @@ div.annotatediv {
 
.code-highlight .s1, .codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
 
.code-highlight .ss, .codehilite .ss { color: #19177C } /* Literal.String.Symbol */
 
.code-highlight .bp, .codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
 
.code-highlight .vc, .codehilite .vc { color: #19177C } /* Name.Variable.Class */
 
.code-highlight .vg, .codehilite .vg { color: #19177C } /* Name.Variable.Global */
 
.code-highlight .vi, .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
 
.code-highlight .il, .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
 
.code-highlight .il, .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
 
\ No newline at end of file
rhodecode/public/css/style.css
Show inline comments
 
@@ -4140,17 +4140,17 @@ div.rst-block {
 
}
 

	
 
div.rst-block h2 {
 
    font-weight: normal;
 
}
 

	
 
div.rst-block  {
 
div.rst-block {
 
    background-color: #fafafa;
 
}
 

	
 
div.rst-block  {
 
div.rst-block {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 0 20px 10px;
 
}
 

	
 
@@ -4417,13 +4417,13 @@ form.comment-inline-form {
 

	
 
/** comment inline **/
 
.inline-comments {
 
    padding: 10px 20px;
 
}
 

	
 
.inline-comments div.rst-block  {
 
.inline-comments div.rst-block {
 
    clear: both;
 
    overflow: hidden;
 
    margin: 0;
 
    padding: 0 20px 0px;
 
}
 
.inline-comments .comment {
 
@@ -4808,7 +4808,7 @@ div.comment:target>.comment-wrapp {
 
    border: solid 2px #ee0 !important;
 
}
 

	
 
.lineno:target a {
 
    border: solid 2px #ee0 !important;
 
    margin: -2px;
 
}
 
}
 
\ No newline at end of file
rhodecode/public/js/graph.js
Show inline comments
 
@@ -23,13 +23,13 @@ var colors = [
 
];
 

	
 
function BranchRenderer() {
 
	
 
	this.canvas = document.getElementById("graph_canvas");
 
	
 
	if (!document.createElement("canvas").getContext) 
 
	if (!document.createElement("canvas").getContext)
 
		this.canvas = window.G_vmlCanvasManager.initElement(this.canvas);
 
	this.ctx = this.canvas.getContext('2d');
 
	this.ctx.strokeStyle = 'rgb(0, 0, 0)';
 
	this.ctx.fillStyle = 'rgb(0, 0, 0)';
 
	this.cur = [0, 0];
 
	this.line_width = 2.0;
rhodecode/public/js/rhodecode.js
Show inline comments
 
@@ -83,25 +83,12 @@ var prevElementSibling = function( el ) 
 
        while( el = el.previousSibling ) {
 
            if( el.nodeType === 1 ) return el;
 
        }
 
    }
 
}
 

	
 
var setSelectValue = function(select, val){
 
	var selection =  YUD.get(select);
 
	
 
    // select element
 
    for(var i=0;i<selection.options.length;i++){
 
        if (selection.options[i].innerHTML == val) {
 
            selection.selectedIndex = i;
 
            break;
 
        }
 
    }	
 
}
 

	
 

	
 
/**
 
 * SmartColorGenerator
 
 *
 
 *usage::
 
 *	var CG = new ColorGenerator();
 
 *  var col = CG.getColor(key); //returns array of RGB
 
@@ -574,13 +561,13 @@ var toggleFollowingRepo = function(targe
 
}
 

	
 
var showRepoSize = function(target, repo_name, token){
 
    var args= 'auth_token='+token;
 
    
 
    if(!YUD.hasClass(target, 'loaded')){
 
        YUD.get(target).innerHTML = _TM['loading...'];
 
        YUD.get(target).innerHTML = _TM['Loading ...'];
 
        var url = pyroutes.url('repo_size', {"repo_name":repo_name});
 
        YUC.asyncRequest('POST',url,{
 
            success:function(o){
 
            	YUD.get(target).innerHTML = JSON.parse(o.responseText);
 
            	YUD.addClass(target, 'loaded');
 
            }
 
@@ -907,13 +894,13 @@ var deleteComment = function(comment_id)
 
    }
 
    ajaxPOST(url,postData,success);
 
}
 

	
 
var createInlineAddButton = function(tr){
 

	
 
	var label = TRANSLATION_MAP['add another comment'];
 
	var label = TRANSLATION_MAP['Add another comment'];
 
	
 
	var html_el = document.createElement('div');
 
	YUD.addClass(html_el, 'add-comment');
 
	html_el.innerHTML = '<span class="ui-btn">{0}</span>'.format(label);
 
	
 
	var add = new YAHOO.util.Element(html_el);
 
@@ -1103,22 +1090,22 @@ var fileBrowserListeners = function(curr
 
	                      +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
 
	                      +n.substring(pos+query.length)
 
	                    var new_url = url_base.replace('__FPATH__',n);
 
	                    match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,new_url,n_hl));
 
	                }
 
	                if(match.length >= matches_max){
 
	                    match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['search truncated']));
 
	                    match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['Search truncated']));
 
	                }
 
	            }                       
 
	        }
 
	        if(query != ""){
 
	            YUD.setStyle('tbody','display','none');
 
	            YUD.setStyle('tbody_filtered','display','');
 
	            
 
	            if (match.length==0){
 
	              match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['no matching files']));
 
	              match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
 
	            }                           
 
	            
 
	            YUD.get('tbody_filtered').innerHTML = match.join("");   
 
	        }
 
	        else{
 
	            YUD.setStyle('tbody','display','');
 
@@ -2170,17 +2157,17 @@ YUE.onDOMReady(function(){
 
	YUE.on(YUQ('.diff-collapse-button'), 'click', function(e){
 
		var button = e.currentTarget;
 
		var t = YUD.get(button).getAttribute('target');
 
	    console.log(t);
 
		if(YUD.hasClass(t, 'hidden')){
 
			YUD.removeClass(t, 'hidden');
 
			YUD.get(button).innerHTML = "&uarr; {0} &uarr;".format(_TM['collapse diff']);
 
			YUD.get(button).innerHTML = "&uarr; {0} &uarr;".format(_TM['Collapse diff']);
 
		}
 
		else if(!YUD.hasClass(t, 'hidden')){
 
			YUD.addClass(t, 'hidden');
 
			YUD.get(button).innerHTML = "&darr; {0} &darr;".format(_TM['expand diff']);
 
			YUD.get(button).innerHTML = "&darr; {0} &darr;".format(_TM['Expand diff']);
 
		}
 
	});
 
	
 
	
 
	
 
});
rhodecode/templates/admin/users/user_edit.html
Show inline comments
 
@@ -40,17 +40,20 @@
 
        </div>
 
        <div class="field">
 
            <div class="label">
 
                <label>${_('API key')}:</label> ${c.user.api_key}
 
            </div>
 
        </div>
 
        ##show current ip just if we show ourself
 
        %if c.rhodecode_user.username == c.user.username:
 
        <div class="field">
 
            <div class="label">
 
                <label>${_('Current IP')}:</label> ${c.perm_user.ip_addr or "?"}
 
            </div>
 
        </div>
 
        %endif
 
        <div class="fields">
 
             <div class="field">
 
                <div class="label">
 
                    <label for="username">${_('Username')}:</label>
 
                </div>
 
                <div class="input">
rhodecode/templates/admin/users/user_edit_my_account_form.html
Show inline comments
 
@@ -17,12 +17,17 @@
 
             </div>
 
            <div class="field">
 
                <div class="label">
 
                    <label>${_('API key')}</label> ${c.user.api_key}
 
                </div>
 
            </div>
 
            <div class="field">
 
                <div class="label">
 
                    <label>${_('Current IP')}:</label> ${c.perm_user.ip_addr or "?"}
 
                </div>
 
            </div>
 
            <div class="fields">
 
                 <div class="field">
 
                    <div class="label">
 
                        <label for="username">${_('Username')}:</label>
 
                    </div>
 
                    <div class="input">
rhodecode/templates/base/root.html
Show inline comments
 
@@ -38,27 +38,27 @@
 

	
 
        ## JAVASCRIPT ##
 
        <%def name="js()">
 
            <script type="text/javascript">
 
            //JS translations map
 
            var TRANSLATION_MAP = {
 
                'add another comment':'${_("add another comment")}',
 
                'Add another comment':'${_("Add another comment")}',
 
                'Stop following this repository':"${_('Stop following this repository')}",
 
                'Start following this repository':"${_('Start following this repository')}",
 
                'Group':"${_('Group')}",
 
                'members':"${_('members')}",
 
                'loading...':"${_('loading...')}",
 
                'search truncated': "${_('search truncated')}",
 
                'no matching files': "${_('no matching files')}",
 
                'Loading ...':"${_('Loading ...')}",
 
                'Search truncated': "${_('Search truncated')}",
 
                'No matching files': "${_('No matching files')}",
 
                'Open new pull request': "${_('Open new pull request')}",
 
                'Open new pull request for selected changesets':  "${_('Open new pull request for selected changesets')}",
 
                'Show selected changes __S -> __E': "${_('Show selected changes __S -> __E')}",
 
                'Show selected change __S': "${_('Show selected change __S')}",
 
                'Selection link': "${_('Selection link')}",
 
                'collapse diff': "${_('collapse diff')}",
 
                'expand diff': "${_('expand diff')}",
 
                'Collapse diff': "${_('Collapse diff')}",
 
                'Expand diff': "${_('Expand diff')}"
 
            };
 
            var _TM = TRANSLATION_MAP;
 

	
 
            var TOGGLE_FOLLOW_URL  = "${h.url('toggle_following')}";
 

	
 
            </script>
rhodecode/templates/changelog/changelog.html
Show inline comments
 
modified file chmod 100644 => 100755
 
@@ -22,21 +22,21 @@ ${self.context_bar('changelog')}
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    <div class="table">
 
        % if c.pagination:
 
            <div id="graph">
 
                <div class="info_box" style="clear: both;padding: 10px 6px;text-align: right;">
 
                    <div class="info_box" style="clear: both;padding: 10px 6px;min-height: 12px;text-align: right;">
 
                    <a href="#" class="ui-btn small" id="rev_range_container" style="display:none"></a>
 
                    <a href="#" class="ui-btn small" id="rev_range_clear" style="display:none">${_('Clear selection')}</a>
 

	
 
                    %if c.rhodecode_db_repo.fork:
 
                        <a title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default')}" class="ui-btn small">${_('Compare fork with parent')}</a>
 
                        <a id="compare_fork" title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}" href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default',merge=1)}" class="ui-btn small">${_('Compare fork with parent')}</a>
 
                    %endif
 
                    %if h.is_hg(c.rhodecode_repo):
 
                    <a id="open_new_pr" href="${h.url('pullrequest_form',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
 
                    <a id="open_new_pr" href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="ui-btn small">${_('Open new pull request')}</a>
 
                    %endif
 
                </div>
 
                <div class="container_header">
 
                    ${h.form(h.url.current(),method='get')}
 
                    <div style="float:left">
 
                        ${h.submit('set',_('Show'),class_="ui-btn")}
 
@@ -122,28 +122,31 @@ ${self.context_bar('changelog')}
 
                //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__')}";
 
                var pr_tmpl = "${h.url('pullrequest_home',repo_name=c.repo_name)}";
 

	
 
                var checkbox_checker = function(e){
 
                    var clicked_cb = e.currentTarget;
 
                    var checkbox_checker = function(e){
 
                    var checked_checkboxes = [];
 
                    for (pos in checkboxes){
 
                        if(checkboxes[pos].checked){
 
                            checked_checkboxes.push(checkboxes[pos]);
 
                        }
 
                    }
 
                    if(YUD.get('open_new_pr')){
 
                        if(checked_checkboxes.length>0){
 
                            // modify open pull request to show we have selected cs
 
                            YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
 
                        }else{
 
                            YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
 
                            if(checked_checkboxes.length>1){
 
                              YUD.setStyle('open_new_pr','display','none');
 
                            } else {
 
                               YUD.setStyle('open_new_pr','display','');
 
                            if(checked_checkboxes.length>0){
 
                              YUD.get('open_new_pr').innerHTML = _TM['Open new pull request for selected changesets'];
 
                            }else{
 
                              YUD.get('open_new_pr').innerHTML = _TM['Open new pull request'];
 
                            }
 
                          }
 
                        }
 
                    }
 

	
 
                    if(checked_checkboxes.length>0){
 
                        var rev_end = checked_checkboxes[0].name;
 
                        var rev_start = checked_checkboxes[checked_checkboxes.length-1].name;
 
                        var url = url_tmpl.replace('__REVRANGE__',
 
                                rev_start+'...'+rev_end);
 
@@ -157,26 +160,31 @@ ${self.context_bar('changelog')}
 
                        YUD.get('rev_range_container').href = url;
 
                        YUD.get('rev_range_container').innerHTML = link;
 
                        YUD.setStyle('rev_range_container','display','');
 
                        YUD.setStyle('rev_range_clear','display','');
 

	
 
                        YUD.get('open_new_pr').href = pr_tmpl + '?rev_start={0}&rev_end={1}'.format(rev_start,rev_end);
 

	
 
                            YUD.setStyle('compare_fork','display','none');
 
                    } else{
 
                        YUD.setStyle('rev_range_container','display','none');
 
                        YUD.setStyle('rev_range_clear','display','none');
 
                    }
 
                };
 
                YUE.onDOMReady(checkbox_checker);
 
                YUE.on(checkboxes,'click', checkbox_checker);
 
                            if (checkboxes){
 
                                YUD.get('open_new_pr').href = pr_tmpl + '?rev_end={0}'.format(checkboxes[0].name);
 
                            }
 
                            YUD.setStyle('compare_fork','display','');
 
                        }
 
                    };
 
                    YUE.onDOMReady(checkbox_checker);
 
                    YUE.on(checkboxes,'click', checkbox_checker);
 

	
 
                YUE.on('rev_range_clear','click',function(e){
 
                    for (var i=0; i<checkboxes.length; i++){
 
                        var cb = checkboxes[i];
 
                        cb.checked = false;
 
                    }
 
                        checkbox_checker();
 
                    YUE.preventDefault(e);
 
                });
 

	
 
                var msgs = YUQ('.message');
 
                // get first element height
 
                var el = YUQ('#graph_content .container')[0];
rhodecode/templates/changeset/diff_block.html
Show inline comments
 
@@ -49,13 +49,13 @@
 
    <div id="${h.FID('',filenode_path)}_target" style="clear:both;margin-top:25px"></div>
 
    <div id="${h.FID('',filenode_path)}" class="diffblock  margined comm">
 
      <div class="code-header">
 
          <div class="changeset_header">
 
              <div class="changeset_file">
 
                  ${h.safe_unicode(filenode_path)} |
 
                  <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.org_ref)}" title="${_('show file at latest version in this repo')}">${c.org_ref_type}@${h.short_id(c.org_ref) if c.org_ref_type=='rev' else c.org_ref}</a> -&gt;
 
                  <a class="spantag" href="${h.url('files_home', repo_name=c.other_repo.repo_name, f_path=filenode_path, revision=c.org_ref)}" title="${_('show file at latest version in this repo')}">${c.org_ref_type}@${h.short_id(c.org_ref) if c.org_ref_type=='rev' else c.org_ref}</a> -&gt;
 
                  <a class="spantag" href="${h.url('files_home', repo_name=c.repo_name, f_path=filenode_path, revision=c.other_ref)}" title="${_('show file at initial version in this repo')}">${c.other_ref_type}@${h.short_id(c.other_ref) if c.other_ref_type=='rev' else c.other_ref}</a>
 
              </div>
 
          </div>
 
      </div>
 
        <div class="code-body">
 
            <div class="full_f_path" path="${h.safe_unicode(filenode_path)}"></div>
rhodecode/templates/compare/compare_cs.html
Show inline comments
 
## Changesets table !
 
<div class="container">
 
  <table class="compare_view_commits noborder">
 
  %if not c.cs_ranges:
 
    <span class="empty_data">${_('No changesets')}</span>
 
  %else:
 
    %for cnt, cs in enumerate(c.cs_ranges):
 
    <table class="compare_view_commits noborder">
 
    %for cs in reversed(c.cs_ranges):
 
        <tr>
 
        <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(h.email_or_none(cs.author),14)}"/></div></td>
 
        <td>
 
          %if cs.raw_id in c.statuses:
 
            <div title="${c.statuses[cs.raw_id][1]}" class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses[cs.raw_id][0])}" /></div>
 
          %endif
 
@@ -19,10 +19,18 @@
 
        </td>
 
        <td><div class="author">${h.person(cs.author)}</div></td>
 
        <td><span class="tooltip" title="${h.tooltip(h.age(cs.date))}">${cs.date}</span></td>
 
        <td><div class="message tooltip" title="${h.tooltip(cs.message)}" style="white-space:normal">${h.urlify_commit(h.shorter(cs.message, 60),c.repo_name)}</div></td>
 
        </tr>
 
    %endfor
 

	
 
    </table>
 
    %if c.ancestor:
 
    <span class="ancestor">${_('Ancestor')}:
 
      ${h.link_to(h.short_id(c.ancestor),h.url('changeset_home',repo_name=c.repo_name,revision=c.ancestor))}
 
    </span>
 
    %endif
 
    %if c.as_form:
 
      ${h.hidden('ancestor_rev',c.ancestor)}
 
      ${h.hidden('merge_rev',c.cs_ranges[-1].raw_id)}
 
    %endif
 
  %endif
 
  </table>
 
</div>
rhodecode/templates/email_templates/pull_request.html
Show inline comments
 
@@ -7,13 +7,12 @@ ${_('User %s opened pull request for rep
 
<div>${_('description')}:</div>
 
<p>
 
${body}
 
</p>
 

	
 
<div>${_('revisions for reviewing')}</div>
 
<pre>
 
<p style="white-space: pre-wrap;">
 
%for r,r_msg in pr_revisions:
 
${h.short_id(r)}:
 
    ${h.shorter(r_msg, 256)}
 

	
 
<b>${h.short_id(r)}</b>:
 
${h.shorter(r_msg, 256)}
 
%endfor
 
</pre>
 
</p>
rhodecode/templates/files/files_browser.html
Show inline comments
 
@@ -46,13 +46,13 @@
 
                <tr>
 
                    <th>${_('Name')}</th>
 
                    <th>${_('Size')}</th>
 
                    <th>${_('Mimetype')}</th>
 
                    <th>${_('Last Revision')}</th>
 
                    <th>${_('Last modified')}</th>
 
                    <th>${_('Last commiter')}</th>
 
                    <th>${_('Last committer')}</th>
 
                </tr>
 
            </thead>
 

	
 
            <tbody id="tbody">
 
                %if c.file.parent:
 
                <tr class="parity0">
 
@@ -86,14 +86,14 @@
 
                          ${node.mimetype}
 
                      %endif
 
                     </td>
 
                     <td>
 
                         %if node.is_file():
 
                             <div class="tooltip" title="${h.tooltip(node.last_changeset.message)}">
 
                             <pre>${'r%s:%s' % (node.last_changeset.revision,node.last_changeset.short_id)}</pre>
 
                            </div>
 
                              <pre>${'r%s:%s' % (node.last_changeset.revision,node.last_changeset.short_id)}</pre>
 
                             </div>
 
                         %endif
 
                     </td>
 
                     <td>
 
                         %if node.is_file():
 
                             <span class="tooltip" title="${h.tooltip(h.fmt_date(node.last_changeset.date))}">
 
                            ${h.age(node.last_changeset.date)}</span>
rhodecode/templates/pullrequests/pullrequest.html
Show inline comments
 
@@ -18,15 +18,12 @@
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    ${h.form(url('pullrequest', repo_name=c.repo_name), method='post', id='pull_request_form')}
 
    <div style="float:left;padding:0px 30px 30px 30px">
 
        <input type="hidden" name="rev_start" value="${request.GET.get('rev_start')}" />
 
        <input type="hidden" name="rev_end" value="${request.GET.get('rev_end')}" />
 

	
 
        ##ORG
 
        <div style="float:left">
 
            <div>
 
                <span style="font-size: 20px">
 
                ${h.select('org_repo','',c.org_repos,class_='refs')}:${h.select('org_ref',c.default_org_ref,c.org_refs,class_='refs')}
 
                </span>
 
@@ -98,13 +95,13 @@
 
                    ${h.text('pullrequest_title',size=30)}
 
                </div>
 
             </div>
 

	
 
            <div class="field">
 
                <div class="label label-textarea">
 
                    <label for="pullrequest_desc">${_('description')}:</label>
 
                    <label for="pullrequest_desc">${_('Description')}:</label>
 
                </div>
 
                <div class="textarea text-area editor">
 
                    ${h.textarea('pullrequest_desc',size=30)}
 
                </div>
 
            </div>
 

	
 
@@ -122,25 +119,48 @@
 
  var _USERS_AC_DATA = ${c.users_array|n};
 
  var _GROUPS_AC_DATA = ${c.users_groups_array|n};
 
  PullRequestAutoComplete('user', 'reviewers_container', _USERS_AC_DATA, _GROUPS_AC_DATA);
 

	
 
  var other_repos_info = ${c.other_repos_info|n};
 

	
 
  var otherrepoChanged = function(){
 
      var sel_box = YUQ('#pull_request_form #other_repo')[0];
 
      var repo_name = sel_box.options[sel_box.selectedIndex].value;
 

	
 
      YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
 
      // replace options of other_ref with the ones for the current other_repo
 
      var other_ref_selector = YUD.get('other_ref');
 
      var new_select = YUD.createElementFromMarkup(other_repos_info[repo_name]['revs']);
 
      var new_selectedIndex = new_select.selectedIndex;
 
      other_ref_selector.innerHTML = ""; // clear old options
 
      while (new_select.length > 0){ // children will be popped when appened to other_ref_selector
 
          other_ref_selector.appendChild(new_select.children[0]);
 
      }
 
      // browsers lost track of selected when appendChild was used
 
      other_ref_selector.selectedIndex = new_selectedIndex;
 

	
 
      // reset && add the reviewer based on selected repo
 
      var _data = other_repos_info[repo_name];
 
      YUD.get('review_members').innerHTML = '';
 
      addReviewMember(_data.user.user_id, _data.user.firstname,
 
                      _data.user.lastname, _data.user.username,
 
                      _data.user.gravatar_link);
 
  }
 

	
 
  var loadPreview = function(){
 
      YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','none');
 
      //url template
 
      var url = "${h.url('compare_url',
 
                         repo_name='__other_repo__',
 
                         org_ref_type='__other_ref_type__',
 
                         org_ref='__other_ref__',
 
                         other_repo='__org_repo__',
 
                         other_ref_type='__org_ref_type__',
 
                         other_ref='__org_ref__',
 
                         as_form=True,
 
                         rev_start=request.GET.get('rev_start',''),
 
                         rev_end=request.GET.get('rev_end',''))}";
 
                         merge=True,
 
                         )}";
 
      var org_repo = YUQ('#pull_request_form #org_repo')[0].value;
 
      var org_ref = YUQ('#pull_request_form #org_ref')[0].value.split(':');
 

	
 
      var other_repo = YUQ('#pull_request_form #other_repo')[0].value;
 
      var other_ref = YUQ('#pull_request_form #other_ref')[0].value.split(':');
 

	
 
@@ -156,47 +176,34 @@
 

	
 
      for (k in rev_data){
 
          url = url.replace('__'+k+'__',rev_data[k]);
 
      }
 

	
 
      YUD.get('pull_request_overview').innerHTML = "${_('Loading ...')}";
 
      ypjax(url,'pull_request_overview');
 

	
 
      YUD.get('pull_request_overview_url').href = url; // shouldn't have as_form ... but ...
 
      YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display','');
 
      ypjax(url,'pull_request_overview', function(data){
 
          var sel_box = YUQ('#pull_request_form #other_repo')[0];
 
          var repo_name = sel_box.options[sel_box.selectedIndex].value;
 
          var _data = other_repos_info[repo_name];
 
          YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description'];
 
          YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
 
          // select back the revision that was just compared
 
          setSelectValue(YUD.get('other_ref'), rev_data['other_ref']);
 
          // reset && add the reviewer based on selected repo
 
          YUD.get('review_members').innerHTML = '';
 
          addReviewMember(_data.user.user_id, _data.user.firstname,
 
                          _data.user.lastname, _data.user.username,
 
                          _data.user.gravatar_link);
 
      })
 
  }
 

	
 
  ## refresh automatically when something changes (org_repo can't change)
 

	
 
  YUE.on('org_ref', 'change', function(e){
 
     loadPreview();
 
  });
 

	
 
  YUE.on('other_repo', 'change', function(e){
 
      var repo_name = e.currentTarget.value;
 
      // replace the <select> of changed repo
 
      YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs'];
 
      otherrepoChanged();
 
      loadPreview();
 
  });
 

	
 
  YUE.on('other_ref', 'change', function(e){
 
     loadPreview();
 
  });
 

	
 
  otherrepoChanged();
 
  //lazy load overview after 0.5s
 
  setTimeout(loadPreview, 500)
 
  setTimeout(loadPreview, 500);
 

	
 
</script>
 

	
 
</%def>
rhodecode/templates/pullrequests/pullrequest_show.html
Show inline comments
 
@@ -158,13 +158,13 @@
 
            <div class="reviewer_ac">
 
               ${h.text('user', class_='yui-ac-input')}
 
               <span class="help-block">${_('Add or remove reviewer to this pull request.')}</span>
 
               <div id="reviewers_container"></div>
 
            </div>
 
            <div style="padding:0px 10px">
 
             <span id="update_pull_request" class="ui-btn xsmall">${_('save changes')}</span>
 
             <span id="update_pull_request" class="ui-btn xsmall">${_('Save changes')}</span>
 
            </div>
 
            %endif
 
          </div>
 
          %endif
 
        </div>
 
       </div>
rhodecode/tests/__init__.py
Show inline comments
 
@@ -44,13 +44,14 @@ __all__ = [
 
    'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS',
 
    'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
 
    'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN',
 
    'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
 
    'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
 
    'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'HG_REMOTE_REPO',
 
    'GIT_REMOTE_REPO', 'SCM_TESTS', '_get_repo_create_params'
 
    'GIT_REMOTE_REPO', 'SCM_TESTS', '_get_repo_create_params',
 
    '_get_group_create_params'
 
]
 

	
 
# Invoke websetup with the current config file
 
# SetupCommand('setup-app').run([config_file])
 

	
 
##RUNNING DESIRED TESTS
 
@@ -180,6 +181,21 @@ def _get_repo_create_params(**custom):
 
    }
 
    defs.update(custom)
 
    if 'repo_name_full' not in custom:
 
        defs.update({'repo_name_full': defs['repo_name']})
 

	
 
    return defs
 

	
 

	
 
def _get_group_create_params(**custom):
 
    defs = dict(
 
        group_name=None,
 
        group_description='DESC',
 
        group_parent_id=None,
 
        perms_updates=[],
 
        perms_new=[],
 
        enable_locking=False,
 
        recursive=False
 
    )
 
    defs.update(custom)
 

	
 
    return defs
rhodecode/tests/api/api_base.py
Show inline comments
 
@@ -367,23 +367,60 @@ class BaseTestApi(object):
 
                                  locked=True)
 
        response = api_call(self, params)
 
        expected = ('User `%s` set lock state for repo `%s` to `%s`'
 
                   % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_lock_repo_lock_optional_locked(self):
 
        from rhodecode.lib.utils2 import  time_to_datetime
 
        _locked_since = json.dumps(time_to_datetime(Repository\
 
                                    .get_by_repo_name(self.REPO).locked[1]))
 
        id_, params = _build_data(self.apikey, 'lock',
 
                                  repoid=self.REPO)
 
        response = api_call(self, params)
 
        expected = ('Repo `%s` locked by `%s`. Locked=`True`. Locked since: `%s`'
 
                   % (self.REPO, TEST_USER_ADMIN_LOGIN, _locked_since))
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    @mock.patch.object(Repository, 'lock', crash)
 
    def test_api_lock_error(self):
 
        id_, params = _build_data(self.apikey, 'lock',
 
                                  userid=TEST_USER_ADMIN_LOGIN,
 
                                  repoid=self.REPO,
 
                                  locked=True)
 
        response = api_call(self, params)
 

	
 
        expected = 'Error occurred locking repository `%s`' % self.REPO
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_get_locks_regular_user(self):
 
        id_, params = _build_data(self.apikey_regular, 'get_locks')
 
        response = api_call(self, params)
 
        expected = []
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_get_locks_with_userid_regular_user(self):
 
        id_, params = _build_data(self.apikey_regular, 'get_locks',
 
                                  userid=TEST_USER_ADMIN_LOGIN)
 
        response = api_call(self, params)
 
        expected = 'userid is not the same as your user'
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_get_locks(self):
 
        id_, params = _build_data(self.apikey, 'get_locks')
 
        response = api_call(self, params)
 
        expected = []
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_get_locks_with_userid(self):
 
        id_, params = _build_data(self.apikey, 'get_locks',
 
                                  userid=TEST_USER_REGULAR_LOGIN)
 
        response = api_call(self, params)
 
        expected = []
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_create_existing_user(self):
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=TEST_USER_ADMIN_LOGIN,
 
                                  email='test@foo.com',
 
                                  password='trololo')
 
        response = api_call(self, params)
rhodecode/tests/functional/test_compare.py
Show inline comments
 
@@ -103,27 +103,28 @@ class TestCompareController(TestControll
 
                                    repo_name=repo1.repo_name,
 
                                    org_ref_type="branch",
 
                                    org_ref=rev2,
 
                                    other_repo=repo2.repo_name,
 
                                    other_ref_type="branch",
 
                                    other_ref=rev1,
 
                                    merge='1',
 
                                    ))
 

	
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo1.repo_name, rev2, repo2.repo_name, rev1))
 
        response.mustcontain("""Showing 2 commits""")
 
        response.mustcontain("""1 file changed with 2 insertions and 0 deletions""")
 

	
 
        response.mustcontain("""<div class="message tooltip" title="commit2" style="white-space:normal">commit2</div>""")
 
        response.mustcontain("""<div class="message tooltip" title="commit3" style="white-space:normal">commit3</div>""")
 

	
 
        response.mustcontain("""<a href="/%s/changeset/%s">r1:%s</a>""" % (repo2.repo_name, cs1.raw_id, cs1.short_id))
 
        response.mustcontain("""<a href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
 
        ## files
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=1#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
 
        #swap
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 

	
 
    def test_compare_forks_on_branch_extra_commits_origin_has_incomming_hg(self):
 
        self.log_user()
 

	
 
        repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
 
                                        description='diff-test',
 
@@ -157,26 +158,27 @@ class TestCompareController(TestControll
 
                                    repo_name=repo1.repo_name,
 
                                    org_ref_type="branch",
 
                                    org_ref=rev2,
 
                                    other_repo=repo2.repo_name,
 
                                    other_ref_type="branch",
 
                                    other_ref=rev1,
 
                                    merge='x',
 
                                    ))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo1.repo_name, rev2, repo2.repo_name, rev1))
 
        response.mustcontain("""Showing 2 commits""")
 
        response.mustcontain("""1 file changed with 2 insertions and 0 deletions""")
 

	
 
        response.mustcontain("""<div class="message tooltip" title="commit2" style="white-space:normal">commit2</div>""")
 
        response.mustcontain("""<div class="message tooltip" title="commit3" style="white-space:normal">commit3</div>""")
 

	
 
        response.mustcontain("""<a href="/%s/changeset/%s">r1:%s</a>""" % (repo2.repo_name, cs1.raw_id, cs1.short_id))
 
        response.mustcontain("""<a href="/%s/changeset/%s">r2:%s</a>""" % (repo2.repo_name, cs2.raw_id, cs2.short_id))
 
        ## files
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=x#C--826e8142e6ba">file1</a>""" % (repo1.repo_name, rev2, rev1, repo2.repo_name))
 
        #swap
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 
        response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s?other_repo=%s&amp;merge=True">[swap]</a>""" % (repo2.repo_name, rev1, rev2, repo1.repo_name))
 

	
 
    def test_compare_cherry_pick_changesets_from_bottom(self):
 

	
 
#        repo1:
 
#            cs0:
 
#            cs1:
 
@@ -212,26 +214,22 @@ class TestCompareController(TestControll
 
                             message='commit4', vcs_type='hg', parent=cs2)
 
        cs4 = _commit_change(repo1.repo_name, filename='file1', content='line1\nline2\nline3\nline4\nline5\n',
 
                             message='commit5', vcs_type='hg', parent=cs3)
 
        cs5 = _commit_change(repo1.repo_name, filename='file1', content='line1\nline2\nline3\nline4\nline5\nline6\n',
 
                             message='commit6', vcs_type='hg', parent=cs4)
 

	
 
        rev1 = 'tip'
 
        rev2 = 'tip'
 

	
 
        response = self.app.get(url(controller='compare', action='index',
 
                                    repo_name=repo2.repo_name,
 
                                    org_ref_type="tag",
 
                                    org_ref=rev1,
 
                                    org_ref_type="rev",
 
                                    org_ref=cs1.short_id, # parent of cs2, in repo2
 
                                    other_repo=repo1.repo_name,
 
                                    other_ref_type="tag",
 
                                    other_ref=rev2,
 
                                    rev_start=cs2.raw_id,
 
                                    rev_end=cs4.raw_id,
 
                                    other_ref_type="rev",
 
                                    other_ref=cs4.short_id,
 
                                    merge='True',
 
                                    ))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo2.repo_name, cs2.short_id, repo1.repo_name, cs4.short_id))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo2.repo_name, cs1.short_id, repo1.repo_name, cs4.short_id))
 
        response.mustcontain("""Showing 3 commits""")
 
        response.mustcontain("""1 file changed with 3 insertions and 0 deletions""")
 

	
 
        response.mustcontain("""<div class="message tooltip" title="commit3" style="white-space:normal">commit3</div>""")
 
        response.mustcontain("""<div class="message tooltip" title="commit4" style="white-space:normal">commit4</div>""")
 
        response.mustcontain("""<div class="message tooltip" title="commit5" style="white-space:normal">commit5</div>""")
 
@@ -277,27 +275,22 @@ class TestCompareController(TestControll
 
        cs3 = _commit_change(repo1.repo_name, filename='file1', content='line1\nline2\nline3\nline4\n',
 
                             message='commit4', vcs_type='hg', parent=cs2)
 
        cs4 = _commit_change(repo1.repo_name, filename='file1', content='line1\nline2\nline3\nline4\nline5\n',
 
                             message='commit5', vcs_type='hg', parent=cs3)
 
        cs5 = _commit_change(repo1.repo_name, filename='file1', content='line1\nline2\nline3\nline4\nline5\nline6\n',
 
                             message='commit6', vcs_type='hg', parent=cs4)
 
        rev1 = 'tip'
 
        rev2 = 'tip'
 

	
 
        response = self.app.get(url(controller='compare', action='index',
 
                                    repo_name=repo2.repo_name,
 
                                    org_ref_type="tag",
 
                                    org_ref=rev1,
 
                                    other_repo=repo1.repo_name,
 
                                    other_ref_type="tag",
 
                                    other_ref=rev2,
 
                                    rev_start=cs3.raw_id,
 
                                    rev_end=cs5.raw_id,
 
                                    repo_name=repo1.repo_name,
 
                                    org_ref_type="rev",
 
                                    org_ref=cs2.short_id, # parent of cs3, not in repo2
 
                                    other_ref_type="rev",
 
                                    other_ref=cs5.short_id,
 
                                    merge='1',
 
                                    ))
 

	
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo2.repo_name, cs3.short_id, repo1.repo_name, cs5.short_id))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (repo1.repo_name, cs2.short_id, repo1.repo_name, cs5.short_id))
 
        response.mustcontain("""Showing 3 commits""")
 
        response.mustcontain("""1 file changed with 3 insertions and 0 deletions""")
 

	
 
        response.mustcontain("""<div class="message tooltip" title="commit4" style="white-space:normal">commit4</div>""")
 
        response.mustcontain("""<div class="message tooltip" title="commit5" style="white-space:normal">commit5</div>""")
 
        response.mustcontain("""<div class="message tooltip" title="commit6" style="white-space:normal">commit6</div>""")
 
@@ -327,24 +320,25 @@ class TestCompareController(TestControll
 
                                    repo_name=HG_REPO,
 
                                    org_ref_type="rev",
 
                                    org_ref=rev1,
 
                                    other_ref_type="rev",
 
                                    other_ref=rev2,
 
                                    other_repo=HG_FORK,
 
                                    merge='1',
 
                                    ))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (HG_REPO, rev1, HG_FORK, rev2))
 
        ## outgoing changesets between those revisions
 

	
 
        response.mustcontain("""<a href="/%s/changeset/2dda4e345facb0ccff1a191052dd1606dba6781d">r4:2dda4e345fac</a>""" % (HG_FORK))
 
        response.mustcontain("""<a href="/%s/changeset/6fff84722075f1607a30f436523403845f84cd9e">r5:6fff84722075</a>""" % (HG_FORK))
 
        response.mustcontain("""<a href="/%s/changeset/7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7">r6:%s</a>""" % (HG_FORK, rev2))
 

	
 
        ## files
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s#C--9c390eb52cd6">vcs/backends/hg.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s#C--41b41c1f2796">vcs/backends/__init__.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s#C--2f574d260608">vcs/backends/base.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s&amp;merge=1#C--9c390eb52cd6">vcs/backends/hg.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s&amp;merge=1#C--41b41c1f2796">vcs/backends/__init__.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 
        response.mustcontain("""<a href="/%s/compare/rev@%s...rev@%s?other_repo=%s&amp;merge=1#C--2f574d260608">vcs/backends/base.py</a>""" % (HG_REPO, rev1, rev2, HG_FORK))
 

	
 
    def test_org_repo_new_commits_after_forking_simple_diff(self):
 
        self.log_user()
 

	
 
        repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
 
                                        description='diff-test',
 
@@ -409,12 +403,13 @@ class TestCompareController(TestControll
 
                                    repo_name=r2_name,
 
                                    org_ref_type="branch",
 
                                    org_ref=rev1,
 
                                    other_ref_type="branch",
 
                                    other_ref=rev2,
 
                                    other_repo=r1_name,
 
                                    merge='1',
 
                                    ))
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (r2_name, rev1, r1_name, rev2))
 
        response.mustcontain('No files')
 
        response.mustcontain('No changesets')
 

	
 
        #add new commit into parent !
 
@@ -433,12 +428,13 @@ class TestCompareController(TestControll
 
                                    repo_name=r2_name,
 
                                    org_ref_type="branch",
 
                                    org_ref=rev1,
 
                                    other_ref_type="branch",
 
                                    other_ref=rev2,
 
                                    other_repo=r1_name,
 
                                    merge='1',
 
                                    ))
 

	
 
        response.mustcontain('%s@%s -&gt; %s@%s' % (r2_name, rev1, r1_name, rev2))
 

	
 
        response.mustcontain("""commit2-parent""")
 
        response.mustcontain("""1 file changed with 1 insertions and 0 deletions""")
rhodecode/tests/models/test_repos_groups.py
Show inline comments
 
@@ -18,24 +18,51 @@ def _make_group(path, desc='desc', paren
 
    if isinstance(parent_id, RepoGroup):
 
        parent_id = parent_id.group_id
 
    gr = ReposGroupModel().create(path, desc, TEST_USER_ADMIN_LOGIN, parent_id)
 
    return gr
 

	
 

	
 
def _update_group(id_, group_name, desc='desc', parent_id=None):
 
    form_data = _get_group_create_params(group_name=group_name,
 
                                         group_desc=desc,
 
                                         group_parent_id=parent_id)
 
    gr = ReposGroupModel().update(id_, form_data)
 
    return gr
 

	
 

	
 
def _make_repo(name, **kwargs):
 
    form_data = _get_repo_create_params(repo_name=name, **kwargs)
 
    cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
 
    r = RepoModel().create(form_data, cur_user)
 
    return r
 

	
 

	
 
def _update_repo(name, **kwargs):
 
    form_data = _get_repo_create_params(**kwargs)
 
    if not 'repo_name' in kwargs:
 
        form_data['repo_name'] = name
 
    if not 'perms_new' in kwargs:
 
        form_data['perms_new'] = []
 
    if not 'perms_updates' in kwargs:
 
        form_data['perms_updates'] = []
 
    r = RepoModel().update(name, **form_data)
 
    return r
 

	
 

	
 
class TestReposGroups(unittest.TestCase):
 

	
 
    def setUp(self):
 
        self.g1 = _make_group('test1', skip_if_exists=True)
 
        Session().commit()
 
        self.g2 = _make_group('test2', skip_if_exists=True)
 
        Session().commit()
 
        self.g3 = _make_group('test3', skip_if_exists=True)
 
        Session().commit()
 

	
 
    def tearDown(self):
 
        print 'out'
 
        Session.remove()
 

	
 
    def __check_path(self, *path):
 
        """
 
        Checks the path for existance !
 
        """
 
        path = [TESTS_TMP_PATH] + list(path)
 
@@ -45,104 +72,92 @@ class TestReposGroups(unittest.TestCase)
 
    def _check_folders(self):
 
        print os.listdir(TESTS_TMP_PATH)
 

	
 
    def __delete_group(self, id_):
 
        ReposGroupModel().delete(id_)
 

	
 
    def __update_group(self, id_, path, desc='desc', parent_id=None):
 
        form_data = dict(
 
            group_name=path,
 
            group_description=desc,
 
            group_parent_id=parent_id,
 
            perms_updates=[],
 
            perms_new=[],
 
            enable_locking=False,
 
            recursive=False
 
        )
 
        gr = ReposGroupModel().update(id_, form_data)
 
        return gr
 

	
 
    def test_create_group(self):
 
        g = _make_group('newGroup')
 
        Session().commit()
 
        self.assertEqual(g.full_path, 'newGroup')
 

	
 
        self.assertTrue(self.__check_path('newGroup'))
 

	
 
    def test_create_same_name_group(self):
 
        self.assertRaises(IntegrityError, lambda: _make_group('newGroup'))
 
        Session().rollback()
 

	
 
    def test_same_subgroup(self):
 
        sg1 = _make_group('sub1', parent_id=self.g1.group_id)
 
        Session().commit()
 
        self.assertEqual(sg1.parent_group, self.g1)
 
        self.assertEqual(sg1.full_path, 'test1/sub1')
 
        self.assertTrue(self.__check_path('test1', 'sub1'))
 

	
 
        ssg1 = _make_group('subsub1', parent_id=sg1.group_id)
 
        Session().commit()
 
        self.assertEqual(ssg1.parent_group, sg1)
 
        self.assertEqual(ssg1.full_path, 'test1/sub1/subsub1')
 
        self.assertTrue(self.__check_path('test1', 'sub1', 'subsub1'))
 

	
 
    def test_remove_group(self):
 
        sg1 = _make_group('deleteme')
 
        Session().commit()
 
        self.__delete_group(sg1.group_id)
 

	
 
        self.assertEqual(RepoGroup.get(sg1.group_id), None)
 
        self.assertFalse(self.__check_path('deteteme'))
 

	
 
        sg1 = _make_group('deleteme', parent_id=self.g1.group_id)
 
        Session().commit()
 
        self.__delete_group(sg1.group_id)
 

	
 
        self.assertEqual(RepoGroup.get(sg1.group_id), None)
 
        self.assertFalse(self.__check_path('test1', 'deteteme'))
 

	
 
    def test_rename_single_group(self):
 
        sg1 = _make_group('initial')
 
        Session().commit()
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after')
 
        new_sg1 = _update_group(sg1.group_id, 'after')
 
        self.assertTrue(self.__check_path('after'))
 
        self.assertEqual(RepoGroup.get_by_group_name('initial'), None)
 

	
 
    def test_update_group_parent(self):
 

	
 
        sg1 = _make_group('initial', parent_id=self.g1.group_id)
 
        Session().commit()
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
 
        new_sg1 = _update_group(sg1.group_id, 'after', parent_id=self.g1.group_id)
 
        self.assertTrue(self.__check_path('test1', 'after'))
 
        self.assertEqual(RepoGroup.get_by_group_name('test1/initial'), None)
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
 
        new_sg1 = _update_group(sg1.group_id, 'after', parent_id=self.g3.group_id)
 
        self.assertTrue(self.__check_path('test3', 'after'))
 
        self.assertEqual(RepoGroup.get_by_group_name('test3/initial'), None)
 

	
 
        new_sg1 = self.__update_group(sg1.group_id, 'hello')
 
        new_sg1 = _update_group(sg1.group_id, 'hello')
 
        self.assertTrue(self.__check_path('hello'))
 

	
 
        self.assertEqual(RepoGroup.get_by_group_name('hello'), new_sg1)
 

	
 
    def test_subgrouping_with_repo(self):
 

	
 
        g1 = _make_group('g1')
 
        g2 = _make_group('g2')
 

	
 
        Session().commit()
 
        # create new repo
 
        form_data = _get_repo_create_params(repo_name='john')
 
        cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
 
        r = RepoModel().create(form_data, cur_user)
 

	
 
        r = _make_repo('john')
 
        Session().commit()
 
        self.assertEqual(r.repo_name, 'john')
 

	
 
        # put repo into group
 
        form_data = form_data
 
        form_data['repo_group'] = g1.group_id
 
        form_data['perms_new'] = []
 
        form_data['perms_updates'] = []
 
        RepoModel().update(r.repo_name, **form_data)
 
        r = _update_repo('john', repo_group=g1.group_id)
 
        Session().commit()
 
        self.assertEqual(r.repo_name, 'g1/john')
 

	
 
        self.__update_group(g1.group_id, 'g1', parent_id=g2.group_id)
 
        _update_group(g1.group_id, 'g1', parent_id=g2.group_id)
 
        self.assertTrue(self.__check_path('g2', 'g1'))
 

	
 
        # test repo
 
        self.assertEqual(r.repo_name, RepoGroup.url_sep().join(['g2', 'g1',
 
                                                                r.just_name]))
 

	
 
@@ -152,14 +167,76 @@ class TestReposGroups(unittest.TestCase)
 
        g2 = _make_group('t22', parent_id=g1.group_id)
 
        Session().commit()
 

	
 
        self.assertEqual(g2.full_path, 't11/t22')
 
        self.assertTrue(self.__check_path('t11', 't22'))
 

	
 
        g2 = self.__update_group(g2.group_id, 'g22', parent_id=None)
 
        g2 = _update_group(g2.group_id, 'g22', parent_id=None)
 
        Session().commit()
 

	
 
        self.assertEqual(g2.group_name, 'g22')
 
        # we moved out group from t1 to '' so it's full path should be 'g2'
 
        self.assertEqual(g2.full_path, 'g22')
 
        self.assertFalse(self.__check_path('t11', 't22'))
 
        self.assertTrue(self.__check_path('g22'))
 

	
 
    def test_rename_top_level_group_in_nested_setup(self):
 
        g1 = _make_group('L1')
 
        Session().commit()
 
        g2 = _make_group('L2', parent_id=g1.group_id)
 
        Session().commit()
 
        g3 = _make_group('L3', parent_id=g2.group_id)
 
        Session().commit()
 

	
 
        r = _make_repo('L1/L2/L3/L3_REPO', repo_group=g3.group_id)
 
        Session().commit()
 

	
 
        ##rename L1 all groups should be now changed
 
        _update_group(g1.group_id, 'L1_NEW')
 
        Session().commit()
 
        self.assertEqual(g1.full_path, 'L1_NEW')
 
        self.assertEqual(g2.full_path, 'L1_NEW/L2')
 
        self.assertEqual(g3.full_path, 'L1_NEW/L2/L3')
 
        self.assertEqual(r.repo_name,  'L1_NEW/L2/L3/L3_REPO')
 

	
 
    def test_change_parent_of_top_level_group_in_nested_setup(self):
 
        g1 = _make_group('R1')
 
        Session().commit()
 
        g2 = _make_group('R2', parent_id=g1.group_id)
 
        Session().commit()
 
        g3 = _make_group('R3', parent_id=g2.group_id)
 
        Session().commit()
 

	
 
        g4 = _make_group('R1_NEW')
 
        Session().commit()
 

	
 
        r = _make_repo('R1/R2/R3/R3_REPO', repo_group=g3.group_id)
 
        Session().commit()
 
        ##rename L1 all groups should be now changed
 
        _update_group(g1.group_id, 'R1', parent_id=g4.group_id)
 
        Session().commit()
 
        self.assertEqual(g1.full_path, 'R1_NEW/R1')
 
        self.assertEqual(g2.full_path, 'R1_NEW/R1/R2')
 
        self.assertEqual(g3.full_path, 'R1_NEW/R1/R2/R3')
 
        self.assertEqual(r.repo_name,  'R1_NEW/R1/R2/R3/R3_REPO')
 

	
 
    def test_change_parent_of_top_level_group_in_nested_setup_with_rename(self):
 
        g1 = _make_group('X1')
 
        Session().commit()
 
        g2 = _make_group('X2', parent_id=g1.group_id)
 
        Session().commit()
 
        g3 = _make_group('X3', parent_id=g2.group_id)
 
        Session().commit()
 

	
 
        g4 = _make_group('X1_NEW')
 
        Session().commit()
 

	
 
        r = _make_repo('X1/X2/X3/X3_REPO', repo_group=g3.group_id)
 
        Session().commit()
 

	
 
        ##rename L1 all groups should be now changed
 
        _update_group(g1.group_id, 'X1_PRIM', parent_id=g4.group_id)
 
        Session().commit()
 
        self.assertEqual(g1.full_path, 'X1_NEW/X1_PRIM')
 
        self.assertEqual(g2.full_path, 'X1_NEW/X1_PRIM/X2')
 
        self.assertEqual(g3.full_path, 'X1_NEW/X1_PRIM/X2/X3')
 
        self.assertEqual(r.repo_name,  'X1_NEW/X1_PRIM/X2/X3/X3_REPO')
rhodecode/tests/scripts/test_vcs_operations.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.tests.test_scm_operations
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Test suite for making push/pull operations.
 
    Run using::
 
    Run using after doing paster serve test.ini::
 
     RC_WHOOSH_TEST_DISABLE=1 RC_NO_TMP_PATH=1 nosetests rhodecode/tests/scripts/test_vcs_operations.py
 

	
 
     RC_WHOOSH_TEST_DISABLE=1 RC_NO_TMP_PATH=1 nosetests rhodecode/tests/scripts/test_vcs_operations.py
 
    You must have git > 1.8.1 for tests to work fine
 

	
 
    :created_on: Dec 30, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
@@ -104,19 +105,20 @@ def _add_files_and_push(vcs, DEST, **kwa
 
    Command(cwd).execute('touch %s' % added_file)
 
    Command(cwd).execute('%s add %s' % (vcs, added_file))
 

	
 
    for i in xrange(3):
 
        cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
 
        Command(cwd).execute(cmd)
 
        author_str = 'Marcin Kuźminski <me@email.com>'
 
        if vcs == 'hg':
 
            cmd = """hg commit -m 'commited new %s' -u '%s' %s """ % (
 
                i, 'Marcin Kuźminski <marcin@python-blog.com>', added_file
 
                i, author_str, added_file
 
            )
 
        elif vcs == 'git':
 
            cmd = """git commit -m 'commited new %s' --author '%s' %s """ % (
 
                i, 'Marcin Kuźminski <marcin@python-blog.com>', added_file
 
                i, author_str, added_file
 
            )
 
        Command(cwd).execute(cmd)
 
    # PUSH it back
 
    if vcs == 'hg':
 
        _REPO = HG_REPO
 
    elif vcs == 'git':
 
@@ -126,13 +128,13 @@ def _add_files_and_push(vcs, DEST, **kwa
 
    clone_url = _construct_url(_REPO, **kwargs)
 
    if 'clone_url' in kwargs:
 
        clone_url = kwargs['clone_url']
 
    if vcs == 'hg':
 
        stdout, stderr = Command(cwd).execute('hg push --verbose', clone_url)
 
    elif vcs == 'git':
 
        stdout, stderr = Command(cwd).execute('git push', clone_url + " master")
 
        stdout, stderr = Command(cwd).execute('git push --verbose', clone_url + " master")
 

	
 
    return stdout, stderr
 

	
 

	
 
def set_anonymous_access(enable=True):
 
    user = User.get_by_username(User.DEFAULT_USER)
 
@@ -321,14 +323,13 @@ class TestVCSOperations(unittest.TestCas
 
        #lock repo
 
        r = Repository.get_by_repo_name(GIT_REPO)
 
        Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
 
        #pull fails since repo is locked
 
        clone_url = _construct_url(GIT_REPO)
 
        stdout, stderr = Command('/tmp').execute('git clone', clone_url)
 
        msg = ("""423 Repository `%s` locked by user `%s`"""
 
                % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
 
        msg = ("""The requested URL returned error: 423""")
 
        assert msg in stderr
 

	
 
    def test_push_on_locked_repo_by_other_user_hg(self):
 
        #clone some temp
 
        DEST = _get_tmp_dir()
 
        clone_url = _construct_url(HG_REPO, dest=DEST)
 
@@ -452,13 +453,14 @@ class TestVCSOperations(unittest.TestCas
 
        user_model = UserModel()
 
        try:
 
            user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
 
            Session().commit()
 
            clone_url = _construct_url(GIT_REPO)
 
            stdout, stderr = Command('/tmp').execute('git clone', clone_url)
 
            assert 'error: The requested URL returned error: 403 Forbidden' in stderr
 
            msg = ("""The requested URL returned error: 403""")
 
            assert msg in stderr
 
        finally:
 
            #release IP restrictions
 
            for ip in UserIpMap.getAll():
 
                UserIpMap.delete(ip.ip_id)
 
            Session().commit()
 

	
rhodecode/tests/vcs/conf.py
Show inline comments
 
@@ -4,12 +4,13 @@ Unit tests configuration module for vcs.
 

	
 
import os
 
import time
 
import hashlib
 
import tempfile
 
import datetime
 
import shutil
 
from rhodecode.tests import *
 
from utils import get_normalized_path
 
from os.path import join as jn
 

	
 
TEST_TMP_PATH = TESTS_TMP_PATH
 
#__all__ = (
 
@@ -55,8 +56,9 @@ THIS = os.path.abspath(os.path.dirname(_
 
#    name = '-'.join((name, hex))
 
#    path = os.path.join(TEST_DIR, name)
 
#    return get_normalized_path(path)
 

	
 
PACKAGE_DIR = os.path.abspath(os.path.join(
 
    os.path.dirname(__file__), '..'))
 

	
 
TEST_USER_CONFIG_FILE = jn(THIS, 'aconfig')
 
_dest = jn(TESTS_TMP_PATH,'aconfig')
 
shutil.copy(jn(THIS, 'aconfig'), _dest)
 
TEST_USER_CONFIG_FILE = _dest
setup.py
Show inline comments
 
@@ -59,16 +59,16 @@ if sys.version_info < (2, 6):
 

	
 
if sys.version_info < (2, 7):
 
    requirements.append("unittest2")
 
    requirements.append("argparse")
 

	
 
if is_windows:
 
    requirements.append("mercurial==2.5.1")
 
    requirements.append("mercurial==2.5.2")
 
else:
 
    requirements.append("py-bcrypt")
 
    requirements.append("mercurial==2.5.1")
 
    requirements.append("mercurial==2.5.2")
 

	
 

	
 
dependency_links = [
 
]
 

	
 
classifiers = [
test.ini
Show inline comments
 
@@ -28,28 +28,30 @@ pdebug = false
 
# Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
 
#smtp_auth = 
 

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

	
 
##max request before thread respawn
 
threadpool_max_requests = 10
 
#threadpool_max_requests = 10
 

	
 
##option to use threads of process
 
use_threadpool = true
 
#use_threadpool = true
 

	
 
use = egg:Paste#http
 
#use = egg:Paste#http
 

	
 
#WAITRESS
 
threads = 5
 
#100GB
 
max_request_body_size = 107374182400
 
use = egg:waitress#main
 

	
 
host = 127.0.0.1
 
port = 8001
 
port = 5000
 

	
 
[filter:proxy-prefix]
 
# prefix middleware for rc
 
use = egg:PasteDeploy#prefix
 
prefix = /<your-prefix>
 

	
 
@@ -60,12 +62,14 @@ full_stack = true
 
static_files = true
 
# Optional Languages
 
# en, fr, ja, pt_BR, zh_CN, zh_TW, pl
 
lang = en
 
cache_dir = /tmp/rc/data
 
index_dir = /tmp/rc/index
 
# set this path to use archive download cache
 
#archive_cache_dir = /tmp/rhodecode_tarballcache
 
app_instance_uuid = develop-test
 
cut_off_limit = 256000
 
vcs_full_cache = False
 
# force https in RhodeCode, fixes https redirects, assumes it's always https
 
force_https = false
 
# use Strict-Transport-Security headers
 
@@ -247,12 +251,93 @@ beaker.session.secure = false
 
beaker.session.auto = False
 

	
 
## default cookie expiration time in seconds `true` expire at browser close ##
 
#beaker.session.cookie_expires = 3600
 

	
 

	
 
############################
 
## ERROR HANDLING SYSTEMS ##
 
############################
 

	
 
####################
 
### [errormator] ###
 
####################
 

	
 
# Errormator is tailored to work with RhodeCode, see 
 
# http://errormator.com for details how to obtain an account
 
# you must install python package `errormator_client` to make it work
 

	
 
# errormator enabled
 
errormator = true
 

	
 
errormator.server_url = https://api.errormator.com
 
errormator.api_key = YOUR_API_KEY
 

	
 
# TWEAK AMOUNT OF INFO SENT HERE
 

	
 
# enables 404 error logging (default False)
 
errormator.report_404 = false
 

	
 
# time in seconds after request is considered being slow (default 1)
 
errormator.slow_request_time = 1
 

	
 
# record slow requests in application
 
# (needs to be enabled for slow datastore recording and time tracking)
 
errormator.slow_requests = true
 

	
 
# enable hooking to application loggers
 
# errormator.logging = true
 

	
 
# minimum log level for log capture
 
# errormator.logging.level = WARNING
 

	
 
# send logs only from erroneous/slow requests
 
# (saves API quota for intensive logging)
 
errormator.logging_on_error = false
 

	
 
# list of additonal keywords that should be grabbed from environ object 
 
# can be string with comma separated list of words in lowercase
 
# (by default client will always send following info:
 
# 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that 
 
# start with HTTP* this list be extended with additional keywords here
 
errormator.environ_keys_whitelist = 
 

	
 

	
 
# list of keywords that should be blanked from request object 
 
# can be string with comma separated list of words in lowercase
 
# (by default client will always blank keys that contain following words 
 
# 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
 
# this list be extended with additional keywords set here
 
errormator.request_keys_blacklist =
 

	
 

	
 
# list of namespaces that should be ignores when gathering log entries
 
# can be string with comma separated list of namespaces
 
# (by default the client ignores own entries: errormator_client.client)
 
errormator.log_namespace_blacklist =  
 

	
 

	
 
################
 
### [sentry] ###
 
################
 

	
 
# sentry is a alternative open source error aggregator
 
# you must install python packages `sentry` and `raven` to enable 
 

	
 
sentry.dsn = YOUR_DNS
 
sentry.servers =
 
sentry.name =
 
sentry.key =
 
sentry.public_key =
 
sentry.secret_key =
 
sentry.project =
 
sentry.site =
 
sentry.include_paths =
 
sentry.exclude_paths =
 

	
 

	
 
################################################################################
 
## 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
 
@@ -267,13 +352,12 @@ logview.pylons.util = #eee
 
#########################################################
 
### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG    ###
 
#########################################################
 
sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.sqlite
 
#sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode_test
 
#sqlalchemy.db1.url = mysql://root:qwe@localhost/rhodecode_test
 

	
 
sqlalchemy.db1.echo = false
 
sqlalchemy.db1.pool_recycle = 3600
 
sqlalchemy.db1.convert_unicode = true
 

	
 
################################
 
### LOGGING CONFIGURATION   ####
0 comments (0 inline, 0 general)