diff --git a/rhodecode/controllers/changeset.py b/rhodecode/controllers/changeset.py --- a/rhodecode/controllers/changeset.py +++ b/rhodecode/controllers/changeset.py @@ -46,6 +46,7 @@ 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__) @@ -145,15 +146,6 @@ def _context_url(fileid=None): return h.link_to(lbl, h.url.current(**params)) -def wrap_to_table(str_): - return ''' - - - - -
%s
''' % str_ - - class ChangesetController(BaseRepoController): @LoginRequired() @@ -192,10 +184,11 @@ class ChangesetController(BaseRepoContro return redirect(url('home')) c.changes = OrderedDict() - c.sum_added = 0 - c.sum_removed = 0 - c.lines_added = 0 - c.lines_deleted = 0 + + 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 = [] @@ -220,37 +213,19 @@ class ChangesetController(BaseRepoContro # ADDED FILES #================================================================== for node in changeset.added: - - filenode_old = FileNode(node.path, '', EmptyChangeset()) - if filenode_old.is_binary or node.is_binary: - diff = wrap_to_table(_('binary file')) - st = (0, 0) - else: - # in this case node.size is good parameter since those are - # added nodes and their size defines how many changes were - # made - c.sum_added += node.size - fid = h.FID(revision, node.path) - line_context_lcl = get_line_ctx(fid, request.GET) - ignore_whitespace_lcl = get_ignore_ws(fid, request.GET) - if c.sum_added < self.cut_off_limit: - f_gitdiff = diffs.get_gitdiff(filenode_old, node, - ignore_whitespace=ignore_whitespace_lcl, - context=line_context_lcl) - d = diffs.DiffProcessor(f_gitdiff, format='gitdiff') - - st = d.stat() - diff = d.as_html(enable_comments=enable_comments) - - else: - diff = wrap_to_table(_('Changeset is to big and ' - 'was cut off, see raw ' - 'changeset instead')) - c.cut_off = True - break - - cs1 = None - cs2 = node.last_changeset.raw_id + 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) + cumulative_diff += size c.lines_added += st[0] c.lines_deleted += st[1] c.changes[changeset.raw_id].append(('added', node, diff, @@ -259,60 +234,37 @@ class ChangesetController(BaseRepoContro #================================================================== # CHANGED FILES #================================================================== - if not c.cut_off: - 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()) - - if filenode_old.is_binary or node.is_binary: - diff = wrap_to_table(_('binary file')) - st = (0, 0) - else: + 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()) - if c.sum_removed < self.cut_off_limit: - fid = h.FID(revision, node.path) - line_context_lcl = get_line_ctx(fid, request.GET) - ignore_whitespace_lcl = get_ignore_ws(fid, request.GET,) - f_gitdiff = diffs.get_gitdiff(filenode_old, node, - ignore_whitespace=ignore_whitespace_lcl, - context=line_context_lcl) - d = diffs.DiffProcessor(f_gitdiff, - format='gitdiff') - st = d.stat() - if (st[0] + st[1]) * 256 > self.cut_off_limit: - diff = wrap_to_table(_('Diff is to big ' - 'and was cut off, see ' - 'raw diff instead')) - else: - diff = d.as_html(enable_comments=enable_comments) - - if diff: - c.sum_removed += len(diff) - else: - diff = wrap_to_table(_('Changeset is to big and ' - 'was cut off, see raw ' - 'changeset instead')) - c.cut_off = True - break - - cs1 = filenode_old.last_changeset.raw_id - cs2 = node.last_changeset.raw_id - c.lines_added += st[0] - c.lines_deleted += st[1] - c.changes[changeset.raw_id].append(('changed', node, diff, - cs1, cs2, st)) + 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) + 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)) #================================================================== # REMOVED FILES #================================================================== - if not c.cut_off: - for node in changeset.removed: - c.changes[changeset.raw_id].append(('removed', node, None, - None, None, (0, 0))) + for node in changeset.removed: + c.changes[changeset.raw_id].append(('removed', node, None, + None, None, (0, 0))) # count inline comments for path, lines in c.inline_comments: diff --git a/rhodecode/controllers/files.py b/rhodecode/controllers/files.py --- a/rhodecode/controllers/files.py +++ b/rhodecode/controllers/files.py @@ -27,19 +27,18 @@ import os import logging import traceback -from os.path import join as jn - -from pylons import request, response, session, tmpl_context as c, url +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 vcs.conf import settings from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \ - EmptyRepositoryError, ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError -from vcs.nodes import FileNode, NodeKind + EmptyRepositoryError, ImproperArchiveTypeError, VCSError, \ + NodeAlreadyExistsError +from 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 @@ -47,6 +46,9 @@ from rhodecode.lib.utils import EmptyCha 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 log = logging.getLogger(__name__) @@ -105,7 +107,6 @@ class FilesController(BaseRepoController return file_node - def __get_paths(self, changeset, starting_path): """recursive walk in root dir and return a set of all path in that dir based on repository walk function @@ -128,7 +129,7 @@ class FilesController(BaseRepoController @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def index(self, repo_name, revision, f_path): - #reditect to given revision from form if given + # 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) @@ -141,7 +142,7 @@ class FilesController(BaseRepoController cur_rev = c.changeset.revision - #prev link + # 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, @@ -151,7 +152,7 @@ class FilesController(BaseRepoController except (ChangesetDoesNotExistError, VCSError): c.url_prev = '#' - #next link + # 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, @@ -161,7 +162,7 @@ class FilesController(BaseRepoController except (ChangesetDoesNotExistError, VCSError): c.url_next = '#' - #files or dirs + # files or dirs try: c.file = c.changeset.get_node(f_path) @@ -407,13 +408,17 @@ class FilesController(BaseRepoController 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') + 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) @@ -429,14 +434,14 @@ class FilesController(BaseRepoController 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)) + 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 = diffs.DiffProcessor(_diff, format='gitdiff') diff_name = '%s_vs_%s.diff' % (diff1, diff2) response.content_type = 'text/plain' @@ -448,42 +453,25 @@ class FilesController(BaseRepoController _diff = diffs.get_gitdiff(node1, node2, ignore_whitespace=ignore_whitespace, context=line_context) - diff = diffs.DiffProcessor(_diff,format='gitdiff') + diff = diffs.DiffProcessor(_diff, format='gitdiff') response.content_type = 'text/plain' return diff.raw_diff() - elif c.action == 'diff': - if node1.is_binary or node2.is_binary: - c.cur_diff = _('Binary file') - elif node1.size > self.cut_off_limit or \ - node2.size > self.cut_off_limit: - c.cur_diff = '' - c.big_diff = True - else: - _diff = diffs.get_gitdiff(node1, node2, - ignore_whitespace=ignore_whitespace, - context=line_context) - diff = diffs.DiffProcessor(_diff,format='gitdiff') - c.cur_diff = diff.as_html() 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) - #default option - if node1.is_binary or node2.is_binary: - c.cur_diff = _('Binary file') - elif node1.size > self.cut_off_limit or \ - node2.size > self.cut_off_limit: - c.cur_diff = '' - c.big_diff = True + 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) - else: - _diff = diffs.get_gitdiff(node1, node2, - ignore_whitespace=ignore_whitespace, - context=line_context) - diff = diffs.DiffProcessor(_diff,format='gitdiff') - c.cur_diff = diff.as_html() + c.changes = [('', node2, diff, cs1, cs2, st,)] - if not c.cur_diff and not c.big_diff: - c.no_changes = True return render('files/file_diff.html') def _get_node_history(self, cs, f_path): @@ -501,12 +489,10 @@ class FilesController(BaseRepoController hist_l.append(changesets_group) for name, chs in c.rhodecode_repo.branches.items(): - #chs = chs.split(':')[-1] branches_group[0].append((chs, name),) hist_l.append(branches_group) for name, chs in c.rhodecode_repo.tags.items(): - #chs = chs.split(':')[-1] tags_group[0].append((chs, name),) hist_l.append(tags_group) diff --git a/rhodecode/lib/diffs.py b/rhodecode/lib/diffs.py --- a/rhodecode/lib/diffs.py +++ b/rhodecode/lib/diffs.py @@ -27,12 +27,66 @@ import re import difflib +import markupsafe +from itertools import tee, imap -from itertools import tee, imap +from pylons.i18n.translation import _ from vcs.exceptions import VCSError from vcs.nodes import FileNode -import markupsafe + +from rhodecode.lib.utils import EmptyChangeset + + +def wrap_to_table(str_): + return ''' + + + + +
%s
''' % str_ + + +def wrapped_diff(filenode_old, filenode_new, cut_off_limit=None, + ignore_whitespace=True, line_context=3, + enable_comments=False): + """ + returns a wrapped diff into a table, checks for cut_off_limit and presents + proper message + """ + + if filenode_old is None: + filenode_old = FileNode(filenode_new.path, '', EmptyChangeset()) + + if filenode_old.is_binary or filenode_new.is_binary: + diff = wrap_to_table(_('binary file')) + stats = (0, 0) + size = 0 + + elif cut_off_limit != -1 and (cut_off_limit is None or + (filenode_old.size < cut_off_limit and filenode_new.size < cut_off_limit)): + + f_gitdiff = get_gitdiff(filenode_old, filenode_new, + ignore_whitespace=ignore_whitespace, + context=line_context) + diff_processor = DiffProcessor(f_gitdiff, format='gitdiff') + + diff = diff_processor.as_html(enable_comments=enable_comments) + stats = diff_processor.stat() + size = len(diff or '') + else: + diff = wrap_to_table(_('Changeset was to big and was cut off, use ' + 'diff menu to display this diff')) + stats = (0, 0) + size = 0 + + if not diff: + diff = wrap_to_table(_('No changes detected')) + + cs1 = filenode_old.last_changeset.raw_id + cs2 = filenode_new.last_changeset.raw_id + + return size, cs1, cs2, diff, stats def get_gitdiff(filenode_old, filenode_new, ignore_whitespace=True, context=3): @@ -263,8 +317,8 @@ class DiffProcessor(object): lines.append({ 'old_lineno': '...', 'new_lineno': '...', - 'action': 'context', - 'line': line, + 'action': 'context', + 'line': line, }) else: skipfirst = False @@ -371,34 +425,40 @@ class DiffProcessor(object): """ if condition: - return '''%(label)s''' % {'url': url, - 'label': label} + return '''%(label)s''' % { + 'url': url, + 'label': label + } else: return label diff_lines = self.prepare() _html_empty = True _html = [] - _html.append('''\n''' \ - % {'table_class': table_class}) + _html.append('''
\n''' % { + 'table_class': table_class + }) for diff in diff_lines: for line in diff['chunks']: _html_empty = False for change in line: - _html.append('''\n''' \ - % {'line_class': line_class, - 'action': change['action']}) + _html.append('''\n''' % { + 'lc': line_class, + 'action': change['action'] + }) anchor_old_id = '' anchor_new_id = '' - anchor_old = "%(filename)s_o%(oldline_no)s" % \ - {'filename': self._safe_id(diff['filename']), - 'oldline_no': change['old_lineno']} - anchor_new = "%(filename)s_n%(oldline_no)s" % \ - {'filename': self._safe_id(diff['filename']), - 'oldline_no': change['new_lineno']} - cond_old = change['old_lineno'] != '...' and \ - change['old_lineno'] - cond_new = change['new_lineno'] != '...' and \ - change['new_lineno'] + anchor_old = "%(filename)s_o%(oldline_no)s" % { + 'filename': self._safe_id(diff['filename']), + 'oldline_no': change['old_lineno'] + } + anchor_new = "%(filename)s_n%(oldline_no)s" % { + 'filename': self._safe_id(diff['filename']), + 'oldline_no': change['new_lineno'] + } + cond_old = (change['old_lineno'] != '...' and + change['old_lineno']) + cond_new = (change['new_lineno'] != '...' and + change['new_lineno']) if cond_old: anchor_old_id = 'id="%s"' % anchor_old if cond_new: @@ -406,37 +466,41 @@ class DiffProcessor(object): ########################################################### # OLD LINE NUMBER ########################################################### - _html.append('''\t\n''') ########################################################### # NEW LINE NUMBER ########################################################### - _html.append('''\t\n''') ########################################################### # CODE ########################################################### comments = '' if enable_comments else 'no-comment' - _html.append('''\t''') _html.append('''\n\n''') _html.append('''
''' \ - % {'a_id': anchor_old_id, - 'old_lineno_cls': old_lineno_class}) + _html.append('''\t''' % { + 'a_id': anchor_old_id, + 'olc': old_lineno_class + }) - _html.append('''%(link)s''' \ - % {'link': - _link_to_if(cond_old, change['old_lineno'], '#%s' \ - % anchor_old)}) + _html.append('''%(link)s''' % { + 'link': _link_to_if(True, change['old_lineno'], + '#%s' % anchor_old) + }) _html.append('''''' \ - % {'a_id': anchor_new_id, - 'new_lineno_cls': new_lineno_class}) + _html.append('''\t''' % { + 'a_id': anchor_new_id, + 'nlc': new_lineno_class + }) - _html.append('''%(link)s''' \ - % {'link': - _link_to_if(cond_new, change['new_lineno'], '#%s' \ - % anchor_new)}) + _html.append('''%(link)s''' % { + 'link': _link_to_if(True, change['new_lineno'], + '#%s' % anchor_new) + }) _html.append('''''' \ - % {'code_class': code_class, - 'in-comments': comments}) - _html.append('''\n\t\t
%(code)s
\n''' \ - % {'code': change['line']}) + _html.append('''\t
''' % { + 'cc': code_class, + 'inc': comments + }) + _html.append('''\n\t\t
%(code)s
\n''' % { + 'code': change['line'] + }) _html.append('''\t
''') diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py --- a/rhodecode/lib/helpers.py +++ b/rhodecode/lib/helpers.py @@ -40,6 +40,7 @@ from rhodecode.lib.utils import repo_nam from rhodecode.lib import str2bool, safe_unicode, safe_str, get_changeset_safe from rhodecode.lib.markup_renderer import MarkupRenderer + def _reset(name, value=None, id=NotGiven, type="reset", **attrs): """ Reset button @@ -52,11 +53,11 @@ def _reset(name, value=None, id=NotGiven reset = _reset safeid = _make_safe_id_component - -def FID(raw_id,path): + +def FID(raw_id, path): """ Creates a uniqe ID for filenode based on it's path and revision - + :param raw_id: :param path: """ @@ -116,7 +117,7 @@ class _FilesBreadCrumbs(object): paths_l = paths.split('/') for cnt, p in enumerate(paths_l): if p != '': - url_l.append(link_to(p, + url_l.append(link_to(p, url('files_home', repo_name=repo_name, revision=rev, @@ -738,14 +739,14 @@ def urlify_text(text): def rst(source): - return literal('
%s
' % + return literal('
%s
' % MarkupRenderer.rst(source)) - + def rst_w_mentions(source): """ Wrapped rst renderer with @mention highlighting :param source: """ - return literal('
%s
' % - MarkupRenderer.rst_with_mentions(source)) + return literal('
%s
' % + MarkupRenderer.rst_with_mentions(source)) diff --git a/rhodecode/model/comment.py b/rhodecode/model/comment.py --- a/rhodecode/model/comment.py +++ b/rhodecode/model/comment.py @@ -4,7 +4,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~ comments model for RhodeCode - + :created_on: Nov 11, 2011 :author: marcink :copyright: (C) 2009-2011 Marcin Kuzminski @@ -55,7 +55,7 @@ class ChangesetCommentsModel(BaseModel): line_no=None): """ Creates new comment for changeset - + :param text: :param repo_id: :param user_id: @@ -84,7 +84,7 @@ class ChangesetCommentsModel(BaseModel): if line_no: line = _('on line %s') % line_no subj = h.link_to('Re commit: %(commit_desc)s %(line)s' % \ - {'commit_desc':desc, 'line':line}, + {'commit_desc': desc, 'line': line}, h.url('changeset_home', repo_name=repo.repo_name, revision=revision, anchor='comment-%s' % comment.comment_id, @@ -114,7 +114,7 @@ class ChangesetCommentsModel(BaseModel): def delete(self, comment): """ Deletes given comment - + :param comment_id: """ comment = self.__get_changeset_comment(comment) @@ -122,7 +122,6 @@ class ChangesetCommentsModel(BaseModel): return comment - def get_comments(self, repo_id, revision): return ChangesetComment.query()\ .filter(ChangesetComment.repo_id == repo_id)\ @@ -137,7 +136,7 @@ class ChangesetCommentsModel(BaseModel): .filter(ChangesetComment.line_no != None)\ .filter(ChangesetComment.f_path != None).all() - paths = defaultdict(lambda:defaultdict(list)) + paths = defaultdict(lambda: defaultdict(list)) for co in comments: paths[co.f_path][co.line_no].append(co) diff --git a/rhodecode/templates/changeset/diff_block.html b/rhodecode/templates/changeset/diff_block.html --- a/rhodecode/templates/changeset/diff_block.html +++ b/rhodecode/templates/changeset/diff_block.html @@ -19,7 +19,7 @@ diff-menu
- %if diff: - ${diff|n} - %else: - ${_('No changes in this file')} - %endif + ${diff|n}
%endif diff --git a/rhodecode/templates/files/file_diff.html b/rhodecode/templates/files/file_diff.html --- a/rhodecode/templates/files/file_diff.html +++ b/rhodecode/templates/files/file_diff.html @@ -21,33 +21,29 @@
${self.breadcrumbs()}
-
-
-
-
- ${h.link_to(c.f_path,h.url('files_home',repo_name=c.repo_name, - revision=c.changeset_2.raw_id,f_path=c.f_path))} - » ${h.link_to(_('diff'), - h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='diff'))} - » ${h.link_to(_('raw diff'), - h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='raw'))} - » ${h.link_to(_('download diff'), - h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='download'))} -
-
-
- %if c.no_changes: - ${_('No changes')} - %elif c.big_diff: - ${_('Diff is to big to display')} ${h.link_to(_('raw diff'), - h.url.current(diff2=c.changeset_2.raw_id,diff1=c.changeset_1.raw_id,diff='raw'))} - %else: - ${c.cur_diff|n} - %endif -
-
+
+ ## diff block + <%namespace name="diff_block" file="/changeset/diff_block.html"/> + ${diff_block.diff_block(c.changes)}
+ \ No newline at end of file diff --git a/rhodecode/templates/files/files_edit.html b/rhodecode/templates/files/files_edit.html --- a/rhodecode/templates/files/files_edit.html +++ b/rhodecode/templates/files/files_edit.html @@ -59,7 +59,7 @@
${_('Editing file')}: ${c.file.path}

-				
+				
 				
${_('commit message')}
diff --git a/rhodecode/templates/files/files_source.html b/rhodecode/templates/files/files_source.html --- a/rhodecode/templates/files/files_source.html +++ b/rhodecode/templates/files/files_source.html @@ -11,7 +11,6 @@ -