Changeset - 60115135b77e
[Not reviewed]
beta
0 3 0
Marcin Kuzminski - 14 years ago 2012-03-01 05:34:37
marcin@python-works.com
fixed raw_changeset for git, accidentally it was generated with hg patch headers
- Code garden
3 files changed with 32 insertions and 24 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/changeset.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.changeset
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    changeset controller for pylons showoing changes beetween
 
    revisions
 

	
 
    :created_on: Apr 25, 2010
 
    :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 logging
 
import traceback
 
from collections import defaultdict
 
from webob.exc import HTTPForbidden
 

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

	
 
from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetError, \
 
    ChangesetDoesNotExistError
 
from rhodecode.lib.vcs.nodes import FileNode
 

	
 
import rhodecode.lib.helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import EmptyChangeset
 
from rhodecode.lib.compat import OrderedDict
 
from rhodecode.lib import diffs
 
from rhodecode.model.db import ChangesetComment
 
from rhodecode.model.comment import ChangesetCommentsModel
 
from rhodecode.model.meta import Session
 
from rhodecode.lib.diffs import wrapped_diff
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def anchor_url(revision, path):
 
    fid = h.FID(revision, path)
 
    return h.url.current(anchor=fid, **dict(request.GET))
 

	
 

	
 
def get_ignore_ws(fid, GET):
 
    ig_ws_global = request.GET.get('ignorews')
 
    ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
 
    if ig_ws:
 
        try:
 
            return int(ig_ws[0].split(':')[-1])
 
        except:
 
            pass
 
    return ig_ws_global
 

	
 

	
 
def _ignorews_url(fileid=None):
 

	
 
    params = defaultdict(list)
 
    lbl = _('show white space')
 
    ig_ws = get_ignore_ws(fileid, request.GET)
 
    ln_ctx = get_line_ctx(fileid, request.GET)
 
    # global option
 
    if fileid is None:
 
        if ig_ws is None:
 
            params['ignorews'] += [1]
 
            lbl = _('ignore white space')
 
        ctx_key = 'context'
 
        ctx_val = ln_ctx
 
    # per file options
 
    else:
 
        if ig_ws is None:
 
            params[fileid] += ['WS:1']
 
            lbl = _('ignore white space')
 

	
 
        ctx_key = fileid
 
        ctx_val = 'C:%s' % ln_ctx
 
    # if we have passed in ln_ctx pass it along to our params
 
    if ln_ctx:
 
        params[ctx_key] += [ctx_val]
 

	
 
    params['anchor'] = fileid
 
    img = h.image(h.url('/images/icons/text_strikethrough.png'), lbl, class_='icon')
 
    return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
 

	
 

	
 
def get_line_ctx(fid, GET):
 
    ln_ctx_global = request.GET.get('context')
 
    ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
 

	
 
    if ln_ctx:
 
        retval = ln_ctx[0].split(':')[-1]
 
    else:
 
        retval = ln_ctx_global
 

	
 
    try:
 
        return int(retval)
 
    except:
 
        return
 

	
 

	
 
def _context_url(fileid=None):
 
    """
 
    Generates url for context lines
 

	
 
    :param fileid:
 
    """
 
    ig_ws = get_ignore_ws(fileid, request.GET)
 
    ln_ctx = (get_line_ctx(fileid, request.GET) or 3) * 2
 

	
 
    params = defaultdict(list)
 

	
 
    # global option
 
    if fileid is None:
 
        if ln_ctx > 0:
 
            params['context'] += [ln_ctx]
 

	
 
        if ig_ws:
 
            ig_ws_key = 'ignorews'
 
            ig_ws_val = 1
 

	
 
    # per file option
 
    else:
 
        params[fileid] += ['C:%s' % ln_ctx]
 
        ig_ws_key = fileid
 
        ig_ws_val = 'WS:%s' % 1
 

	
 
    if ig_ws:
 
        params[ig_ws_key] += [ig_ws_val]
 

	
 
    lbl = _('%s line context') % ln_ctx
 

	
 
    params['anchor'] = fileid
 
    img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
 
    return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
 

	
 

	
 
class ChangesetController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def __before__(self):
 
        super(ChangesetController, self).__before__()
 
        c.affected_files_cut_off = 60
 

	
 
    def index(self, revision):
 

	
 
        c.anchor_url = anchor_url
 
        c.ignorews_url = _ignorews_url
 
        c.context_url = _context_url
 

	
 
        #get ranges of revisions if preset
 
        rev_range = revision.split('...')[:2]
 
        enable_comments = True
 
        try:
 
            if len(rev_range) == 2:
 
                enable_comments = False
 
                rev_start = rev_range[0]
 
                rev_end = rev_range[1]
 
                rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
 
                                                            end=rev_end)
 
            else:
 
                rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
 

	
 
            c.cs_ranges = list(rev_ranges)
 
            if not c.cs_ranges:
 
                raise RepositoryError('Changeset range returned empty result')
 

	
 
        except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
 
            log.error(traceback.format_exc())
 
            h.flash(str(e), category='warning')
 
            return redirect(url('home'))
 

	
 
        c.changes = OrderedDict()
 

	
 
        c.lines_added = 0  # count of lines added
 
        c.lines_deleted = 0  # count of lines removes
 

	
 
        cumulative_diff = 0
 
        c.cut_off = False  # defines if cut off limit is reached
 

	
 
        c.comments = []
 
        c.inline_comments = []
 
        c.inline_cnt = 0
 
        # Iterate over ranges (default changeset view is always one changeset)
 
        for changeset in c.cs_ranges:
 
            c.comments.extend(ChangesetCommentsModel()\
 
                              .get_comments(c.rhodecode_db_repo.repo_id,
 
                                            changeset.raw_id))
 
            inlines = ChangesetCommentsModel()\
 
                        .get_inline_comments(c.rhodecode_db_repo.repo_id,
 
                                             changeset.raw_id)
 
            c.inline_comments.extend(inlines)
 
            c.changes[changeset.raw_id] = []
 
            try:
 
                changeset_parent = changeset.parents[0]
 
            except IndexError:
 
                changeset_parent = None
 

	
 
            #==================================================================
 
            # ADDED FILES
 
            #==================================================================
 
            for node in changeset.added:
 
                fid = h.FID(revision, node.path)
 
                line_context_lcl = get_line_ctx(fid, request.GET)
 
                ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
 
                lim = self.cut_off_limit
 
                if cumulative_diff > self.cut_off_limit:
 
                    lim = -1
 
                size, cs1, cs2, diff, st = wrapped_diff(filenode_old=None,
 
                                         filenode_new=node,
 
                                         cut_off_limit=lim,
 
                                         ignore_whitespace=ign_whitespace_lcl,
 
                                         line_context=line_context_lcl,
 
                                         enable_comments=enable_comments)
 
                size, cs1, cs2, diff, st = wrapped_diff(
 
                    filenode_old=None,
 
                    filenode_new=node,
 
                    cut_off_limit=lim,
 
                    ignore_whitespace=ign_whitespace_lcl,
 
                    line_context=line_context_lcl,
 
                    enable_comments=enable_comments
 
                )
 
                cumulative_diff += size
 
                c.lines_added += st[0]
 
                c.lines_deleted += st[1]
 
                c.changes[changeset.raw_id].append(('added', node, diff,
 
                                                    cs1, cs2, st))
 
                c.changes[changeset.raw_id].append(
 
                    ('added', node, diff, cs1, cs2, st)
 
                )
 

	
 
            #==================================================================
 
            # CHANGED FILES
 
            #==================================================================
 
            for node in changeset.changed:
 
                try:
 
                    filenode_old = changeset_parent.get_node(node.path)
 
                except ChangesetError:
 
                    log.warning('Unable to fetch parent node for diff')
 
                    filenode_old = FileNode(node.path, '', EmptyChangeset())
 

	
 
                fid = h.FID(revision, node.path)
 
                line_context_lcl = get_line_ctx(fid, request.GET)
 
                ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
 
                lim = self.cut_off_limit
 
                if cumulative_diff > self.cut_off_limit:
 
                    lim = -1
 
                size, cs1, cs2, diff, st = wrapped_diff(filenode_old=filenode_old,
 
                                         filenode_new=node,
 
                                         cut_off_limit=lim,
 
                                         ignore_whitespace=ign_whitespace_lcl,
 
                                         line_context=line_context_lcl,
 
                                         enable_comments=enable_comments)
 
                size, cs1, cs2, diff, st = wrapped_diff(
 
                    filenode_old=filenode_old,
 
                    filenode_new=node,
 
                    cut_off_limit=lim,
 
                    ignore_whitespace=ign_whitespace_lcl,
 
                    line_context=line_context_lcl,
 
                    enable_comments=enable_comments
 
                )
 
                cumulative_diff += size
 
                c.lines_added += st[0]
 
                c.lines_deleted += st[1]
 
                c.changes[changeset.raw_id].append(('changed', node, diff,
 
                                                    cs1, cs2, st))
 

	
 
                c.changes[changeset.raw_id].append(
 
                    ('changed', node, diff, cs1, cs2, st)
 
                )
 
            #==================================================================
 
            # REMOVED FILES
 
            #==================================================================
 
            for node in changeset.removed:
 
                c.changes[changeset.raw_id].append(('removed', node, None,
 
                                                    None, None, (0, 0)))
 
                c.changes[changeset.raw_id].append(
 
                    ('removed', node, None, None, None, (0, 0))
 
                )
 

	
 
        # count inline comments
 
        for path, lines in c.inline_comments:
 
            for comments in lines.values():
 
                c.inline_cnt += len(comments)
 

	
 
        if len(c.cs_ranges) == 1:
 
            c.changeset = c.cs_ranges[0]
 
            c.changes = c.changes[c.changeset.raw_id]
 

	
 
            return render('changeset/changeset.html')
 
        else:
 
            return render('changeset/changeset_range.html')
 

	
 
    def raw_changeset(self, revision):
 

	
 
        method = request.GET.get('diff', 'show')
 
        ignore_whitespace = request.GET.get('ignorews') == '1'
 
        line_context = request.GET.get('context', 3)
 
        try:
 
            c.scm_type = c.rhodecode_repo.alias
 
            c.changeset = c.rhodecode_repo.get_changeset(revision)
 
        except RepositoryError:
 
            log.error(traceback.format_exc())
 
            return redirect(url('home'))
 
        else:
 
            try:
 
                c.changeset_parent = c.changeset.parents[0]
 
            except IndexError:
 
                c.changeset_parent = None
 
            c.changes = []
 

	
 
            for node in c.changeset.added:
 
                filenode_old = FileNode(node.path, '')
 
                if filenode_old.is_binary or node.is_binary:
 
                    diff = _('binary file') + '\n'
 
                else:
 
                    f_gitdiff = diffs.get_gitdiff(filenode_old, node,
 
                                           ignore_whitespace=ignore_whitespace,
 
                                           context=line_context)
 
                    diff = diffs.DiffProcessor(f_gitdiff,
 
                                                format='gitdiff').raw_diff()
 

	
 
                cs1 = None
 
                cs2 = node.last_changeset.raw_id
 
                c.changes.append(('added', node, diff, cs1, cs2))
 

	
 
            for node in c.changeset.changed:
 
                filenode_old = c.changeset_parent.get_node(node.path)
 
                if filenode_old.is_binary or node.is_binary:
 
                    diff = _('binary file')
 
                else:
 
                    f_gitdiff = diffs.get_gitdiff(filenode_old, node,
 
                                           ignore_whitespace=ignore_whitespace,
 
                                           context=line_context)
 
                    diff = diffs.DiffProcessor(f_gitdiff,
 
                                                format='gitdiff').raw_diff()
 

	
 
                cs1 = filenode_old.last_changeset.raw_id
 
                cs2 = node.last_changeset.raw_id
 
                c.changes.append(('changed', node, diff, cs1, cs2))
 

	
 
        response.content_type = 'text/plain'
 

	
 
        if method == 'download':
 
            response.content_disposition = 'attachment; filename=%s.patch' \
 
                                            % revision
 

	
 
        c.parent_tmpl = ''.join(['# Parent  %s\n' % x.raw_id for x in
 
                                                 c.changeset.parents])
 
        c.parent_tmpl = ''.join(['# Parent  %s\n' % x.raw_id
 
                                 for x in c.changeset.parents])
 

	
 
        c.diffs = ''
 
        for x in c.changes:
 
            c.diffs += x[2]
 

	
 
        return render('changeset/raw_changeset.html')
 

	
 
    def comment(self, repo_name, revision):
 
        ChangesetCommentsModel().create(text=request.POST.get('text'),
 
                                        repo_id=c.rhodecode_db_repo.repo_id,
 
                                        user_id=c.rhodecode_user.user_id,
 
                                        revision=revision,
 
                                        f_path=request.POST.get('f_path'),
 
                                        line_no=request.POST.get('line'))
 
        Session.commit()
 
        return redirect(h.url('changeset_home', repo_name=repo_name,
 
                              revision=revision))
 

	
 
    @jsonify
 
    def delete_comment(self, repo_name, comment_id):
 
        co = ChangesetComment.get(comment_id)
 
        owner = lambda: co.author.user_id == c.rhodecode_user.user_id
 
        if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
 
            ChangesetCommentsModel().delete(comment=co)
 
            Session.commit()
 
            return True
 
        else:
 
            raise HTTPForbidden()
rhodecode/controllers/files.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.files
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Files controller for RhodeCode
 

	
 
    :created_on: Apr 21, 2010
 
    :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 os
 
import logging
 
import traceback
 

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

	
 
from rhodecode.lib.vcs.conf import settings
 
from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
 
    EmptyRepositoryError, ImproperArchiveTypeError, VCSError, \
 
    NodeAlreadyExistsError
 
from rhodecode.lib.vcs.nodes import FileNode
 

	
 
from rhodecode.lib.compat import OrderedDict
 
from rhodecode.lib import convert_line_endings, detect_mode, safe_str
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseRepoController, render
 
from rhodecode.lib.utils import EmptyChangeset
 
from rhodecode.lib import diffs
 
import rhodecode.lib.helpers as h
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
 
    _context_url, get_line_ctx, get_ignore_ws
 
from rhodecode.lib.diffs import wrapped_diff
 
from rhodecode.model.scm import ScmModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class FilesController(BaseRepoController):
 

	
 
    @LoginRequired()
 
    def __before__(self):
 
        super(FilesController, self).__before__()
 
        c.cut_off_limit = self.cut_off_limit
 

	
 
    def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
 
        """
 
        Safe way to get changeset if error occur it redirects to tip with
 
        proper message
 

	
 
        :param rev: revision to fetch
 
        :param repo_name: repo name to redirect after
 
        """
 

	
 
        try:
 
            return c.rhodecode_repo.get_changeset(rev)
 
        except EmptyRepositoryError, e:
 
            if not redirect_after:
 
                return None
 
            url_ = url('files_add_home',
 
                       repo_name=c.repo_name,
 
                       revision=0, f_path='')
 
            add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
 
            h.flash(h.literal(_('There are no files yet %s' % add_new)),
 
                    category='warning')
 
            redirect(h.url('summary_home', repo_name=repo_name))
 

	
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
 

	
 
    def __get_filenode_or_redirect(self, repo_name, cs, path):
 
        """
 
        Returns file_node, if error occurs or given path is directory,
 
        it'll redirect to top level path
 

	
 
        :param repo_name: repo_name
 
        :param cs: given changeset
 
        :param path: path to lookup
 
        """
 

	
 
        try:
 
            file_node = cs.get_node(path)
 
            if file_node.is_dir():
 
                raise RepositoryError('given path is a directory')
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name,
 
                           revision=cs.raw_id))
 

	
 
        return file_node
 

	
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def index(self, repo_name, revision, f_path):
 
        # redirect to given revision from form if given
 
        post_revision = request.POST.get('at_rev', None)
 
        if post_revision:
 
            cs = self.__get_cs_or_redirect(post_revision, repo_name)
 
            redirect(url('files_home', repo_name=c.repo_name,
 
                         revision=cs.raw_id, f_path=f_path))
 

	
 
        c.changeset = self.__get_cs_or_redirect(revision, repo_name)
 
        c.branch = request.GET.get('branch', None)
 
        c.f_path = f_path
 

	
 
        cur_rev = c.changeset.revision
 

	
 
        # prev link
 
        try:
 
            prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
 
            c.url_prev = url('files_home', repo_name=c.repo_name,
 
                         revision=prev_rev.raw_id, f_path=f_path)
 
            if c.branch:
 
                c.url_prev += '?branch=%s' % c.branch
 
        except (ChangesetDoesNotExistError, VCSError):
 
            c.url_prev = '#'
 

	
 
        # next link
 
        try:
 
            next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
 
            c.url_next = url('files_home', repo_name=c.repo_name,
 
                     revision=next_rev.raw_id, f_path=f_path)
 
            if c.branch:
 
                c.url_next += '?branch=%s' % c.branch
 
        except (ChangesetDoesNotExistError, VCSError):
 
            c.url_next = '#'
 

	
 
        # files or dirs
 
        try:
 
            c.file = c.changeset.get_node(f_path)
 

	
 
            if c.file.is_file():
 
                c.file_history = self._get_node_history(c.changeset, f_path)
 
            else:
 
                c.file_history = []
 
        except RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name,
 
                           revision=revision))
 

	
 
        return render('files/files.html')
 

	
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def rawfile(self, repo_name, revision, f_path):
 
        cs = self.__get_cs_or_redirect(revision, repo_name)
 
        file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
 

	
 
        response.content_disposition = 'attachment; filename=%s' % \
 
            safe_str(f_path.split(os.sep)[-1])
 

	
 
        response.content_type = file_node.mimetype
 
        return file_node.content
 

	
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def raw(self, repo_name, revision, f_path):
 
        cs = self.__get_cs_or_redirect(revision, repo_name)
 
        file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
 

	
 
        raw_mimetype_mapping = {
 
            # map original mimetype to a mimetype used for "show as raw"
 
            # you can also provide a content-disposition to override the
 
            # default "attachment" disposition.
 
            # orig_type: (new_type, new_dispo)
 

	
 
            # show images inline:
 
            'image/x-icon': ('image/x-icon', 'inline'),
 
            'image/png': ('image/png', 'inline'),
 
            'image/gif': ('image/gif', 'inline'),
 
            'image/jpeg': ('image/jpeg', 'inline'),
 
            'image/svg+xml': ('image/svg+xml', 'inline'),
 
        }
 

	
 
        mimetype = file_node.mimetype
 
        try:
 
            mimetype, dispo = raw_mimetype_mapping[mimetype]
 
        except KeyError:
 
            # we don't know anything special about this, handle it safely
 
            if file_node.is_binary:
 
                # do same as download raw for binary files
 
                mimetype, dispo = 'application/octet-stream', 'attachment'
 
            else:
 
                # do not just use the original mimetype, but force text/plain,
 
                # otherwise it would serve text/html and that might be unsafe.
 
                # Note: underlying vcs library fakes text/plain mimetype if the
 
                # mimetype can not be determined and it thinks it is not
 
                # binary.This might lead to erroneous text display in some
 
                # cases, but helps in other cases, like with text files
 
                # without extension.
 
                mimetype, dispo = 'text/plain', 'inline'
 

	
 
        if dispo == 'attachment':
 
            dispo = 'attachment; filename=%s' % \
 
                        safe_str(f_path.split(os.sep)[-1])
 

	
 
        response.content_disposition = dispo
 
        response.content_type = mimetype
 
        return file_node.content
 

	
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def annotate(self, repo_name, revision, f_path):
 
        c.cs = self.__get_cs_or_redirect(revision, repo_name)
 
        c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
 

	
 
        c.file_history = self._get_node_history(c.cs, f_path)
 
        c.f_path = f_path
 
        return render('files/files_annotate.html')
 

	
 
    @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
 
    def edit(self, repo_name, revision, f_path):
 
        r_post = request.POST
 

	
 
        c.cs = self.__get_cs_or_redirect(revision, repo_name)
 
        c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
 

	
 
        if c.file.is_binary:
 
            return redirect(url('files_home', repo_name=c.repo_name,
 
                         revision=c.cs.raw_id, f_path=f_path))
 

	
 
        c.f_path = f_path
 

	
 
        if r_post:
 

	
 
            old_content = c.file.content
 
            sl = old_content.splitlines(1)
 
            first_line = sl[0] if sl else ''
 
            # modes:  0 - Unix, 1 - Mac, 2 - DOS
 
            mode = detect_mode(first_line, 0)
 
            content = convert_line_endings(r_post.get('content'), mode)
 

	
 
            message = r_post.get('message') or (_('Edited %s via RhodeCode')
 
                                                % (f_path))
 
            author = self.rhodecode_user.full_contact
 

	
 
            if content == old_content:
 
                h.flash(_('No changes'),
 
                    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,
 
                                             author=author, message=message,
 
                                             content=content, f_path=f_path)
 
                h.flash(_('Successfully committed to %s' % f_path),
 
                        category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred during commit'), category='error')
 
            return redirect(url('changeset_home',
 
                                repo_name=c.repo_name, revision='tip'))
 

	
 
        return render('files/files_edit.html')
 

	
 
    @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
 
    def add(self, repo_name, revision, f_path):
 
        r_post = request.POST
 
        c.cs = self.__get_cs_or_redirect(revision, repo_name,
 
                                         redirect_after=False)
 
        if c.cs is None:
 
            c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
 

	
 
        c.f_path = f_path
 

	
 
        if r_post:
 
            unix_mode = 0
 
            content = convert_line_endings(r_post.get('content'), unix_mode)
 

	
 
            message = r_post.get('message') or (_('Added %s via RhodeCode')
 
                                                % (f_path))
 
            location = r_post.get('location')
 
            filename = r_post.get('filename')
 
            file_obj = r_post.get('upload_file', None)
 

	
 
            if file_obj is not None and hasattr(file_obj, 'filename'):
 
                filename = file_obj.filename
 
                content = file_obj.file
 

	
 
            node_path = os.path.join(location, filename)
 
            author = self.rhodecode_user.full_contact
 

	
 
            if not content:
 
                h.flash(_('No content'), category='warning')
 
                return redirect(url('changeset_home', repo_name=c.repo_name,
 
                                    revision='tip'))
 
            if not filename:
 
                h.flash(_('No filename'), category='warning')
 
                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,
 
                                             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')
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Error occurred during commit'), category='error')
 
            return redirect(url('changeset_home',
 
                                repo_name=c.repo_name, revision='tip'))
 

	
 
        return render('files/files_add.html')
 

	
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def archivefile(self, repo_name, fname):
 

	
 
        fileformat = None
 
        revision = None
 
        ext = None
 
        subrepos = request.GET.get('subrepos') == 'true'
 

	
 
        for a_type, ext_data in settings.ARCHIVE_SPECS.items():
 
            archive_spec = fname.split(ext_data[1])
 
            if len(archive_spec) == 2 and archive_spec[1] == '':
 
                fileformat = a_type or ext_data[1]
 
                revision = archive_spec[0]
 
                ext = ext_data[1]
 

	
 
        try:
 
            dbrepo = RepoModel().get_by_repo_name(repo_name)
 
            if dbrepo.enable_downloads is False:
 
                return _('downloads disabled')
 

	
 
            if c.rhodecode_repo.alias == 'hg':
 
                # patch and reset hooks section of UI config to not run any
 
                # hooks on fetching archives with subrepos
 
                for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
 
                    c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
 

	
 
            cs = c.rhodecode_repo.get_changeset(revision)
 
            content_type = settings.ARCHIVE_SPECS[fileformat][0]
 
        except ChangesetDoesNotExistError:
 
            return _('Unknown revision %s') % revision
 
        except EmptyRepositoryError:
 
            return _('Empty repository')
 
        except (ImproperArchiveTypeError, KeyError):
 
            return _('Unknown archive type')
 

	
 
        response.content_type = content_type
 
        response.content_disposition = 'attachment; filename=%s-%s%s' \
 
            % (repo_name, revision, ext)
 

	
 
        import tempfile
 
        archive = tempfile.mkstemp()[1]
 
        t = open(archive, 'wb')
 
        cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
 

	
 
        def get_chunked_archive(archive):
 
            stream = open(archive, 'rb')
 
            while True:
 
                data = stream.read(4096)
 
                if not data:
 
                    os.remove(archive)
 
                    break
 
                yield data
 

	
 
        return get_chunked_archive(archive)
 

	
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def diff(self, repo_name, f_path):
 
        ignore_whitespace = request.GET.get('ignorews') == '1'
 
        line_context = request.GET.get('context', 3)
 
        diff1 = request.GET.get('diff1', '')
 
        diff2 = request.GET.get('diff2', '')
 
        c.action = request.GET.get('diff')
 
        c.no_changes = diff1 == diff2
 
        c.f_path = f_path
 
        c.big_diff = False
 
        c.anchor_url = anchor_url
 
        c.ignorews_url = _ignorews_url
 
        c.context_url = _context_url
 
        c.changes = OrderedDict()
 
        c.changes[diff2] = []
 
        try:
 
            if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
 
                c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
 
                node1 = c.changeset_1.get_node(f_path)
 
            else:
 
                c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
 
                node1 = FileNode('.', '', changeset=c.changeset_1)
 

	
 
            if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
 
                c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
 
                node2 = c.changeset_2.get_node(f_path)
 
            else:
 
                c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
 
                node2 = FileNode('.', '', changeset=c.changeset_2)
 
        except RepositoryError:
 
            return redirect(url('files_home', repo_name=c.repo_name,
 
                                f_path=f_path))
 

	
 
        if c.action == 'download':
 
            _diff = diffs.get_gitdiff(node1, node2,
 
                                      ignore_whitespace=ignore_whitespace,
 
                                      context=line_context)
 
            diff = diffs.DiffProcessor(_diff, format='gitdiff')
 

	
 
            diff_name = '%s_vs_%s.diff' % (diff1, diff2)
 
            response.content_type = 'text/plain'
 
            response.content_disposition = 'attachment; filename=%s' \
 
                                                    % diff_name
 
            response.content_disposition = (
 
                'attachment; filename=%s' % diff_name
 
            )
 
            return diff.raw_diff()
 

	
 
        elif c.action == 'raw':
 
            _diff = diffs.get_gitdiff(node1, node2,
 
                                      ignore_whitespace=ignore_whitespace,
 
                                      context=line_context)
 
            diff = diffs.DiffProcessor(_diff, format='gitdiff')
 
            response.content_type = 'text/plain'
 
            return diff.raw_diff()
 

	
 
        else:
 
            fid = h.FID(diff2, node2.path)
 
            line_context_lcl = get_line_ctx(fid, request.GET)
 
            ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
 

	
 
            lim = request.GET.get('fulldiff') or self.cut_off_limit
 
            _, cs1, cs2, diff, st = wrapped_diff(filenode_old=node1,
 
                                         filenode_new=node2,
 
                                         cut_off_limit=lim,
 
                                         ignore_whitespace=ign_whitespace_lcl,
 
                                         line_context=line_context_lcl,
 
                                         enable_comments=False)
 

	
 
            c.changes = [('', node2, diff, cs1, cs2, st,)]
 

	
 
        return render('files/file_diff.html')
 

	
 
    def _get_node_history(self, cs, f_path):
 
        changesets = cs.get_file_history(f_path)
 
        hist_l = []
 

	
 
        changesets_group = ([], _("Changesets"))
 
        branches_group = ([], _("Branches"))
 
        tags_group = ([], _("Tags"))
 
        _hg = cs.repository.alias == 'hg'
 
        for chs in changesets:
 
            _branch = '(%s)' % chs.branch if _hg else ''
 
            n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
 
            changesets_group[0].append((chs.raw_id, n_desc,))
 

	
 
        hist_l.append(changesets_group)
 

	
 
        for name, chs in c.rhodecode_repo.branches.items():
 
            branches_group[0].append((chs, name),)
 
        hist_l.append(branches_group)
 

	
 
        for name, chs in c.rhodecode_repo.tags.items():
 
            tags_group[0].append((chs, name),)
 
        hist_l.append(tags_group)
 

	
 
        return hist_l
 

	
 
    @jsonify
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def nodelist(self, repo_name, revision, f_path):
 
        if request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            cs = self.__get_cs_or_redirect(revision, repo_name)
 
            _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
 
                                          flat=False)
 
            return _d + _f
rhodecode/templates/changeset/raw_changeset.html
Show inline comments
 
%if h.is_hg(c.scm_type):
 
# ${c.scm_type.upper()} changeset patch
 
# User ${c.changeset.author|n}
 
# Date ${c.changeset.date}
 
# Node ID ${c.changeset.raw_id}
 
${c.parent_tmpl}
 
${c.changeset.message}
 

	
 
%endif
 
${c.diffs|n}
0 comments (0 inline, 0 general)