def diff_2way(self, repo_name, f_path): diff1 = request.GET.get('diff1', '') diff2 = request.GET.get('diff2', '') nodes = [] unknown_commits = [] for commit in [diff1, diff2]: try: nodes.append(self._get_file_node(commit, f_path)) except (RepositoryError, NodeError): log.exception('%(commit)s does not exist' % {'commit': commit}) unknown_commits.append(commit) h.flash(h.literal( _('Commit %(commit)s does not exist.') % {'commit': commit}), category='error') if unknown_commits: return redirect( url('files_home', repo_name=c.repo_name, f_path=f_path)) if all(isinstance(node.commit, EmptyCommit) for node in nodes): raise HTTPNotFound node1, node2 = nodes f_gitdiff = diffs.get_gitdiff(node1, node2, ignore_whitespace=False) diff_processor = diffs.DiffProcessor(f_gitdiff, format='gitdiff') diff_data = diff_processor.prepare() if not diff_data or diff_data[0]['raw_diff'] == '': h.flash(h.literal( _('%(file_path)s has not changed ' 'between %(commit_1)s and %(commit_2)s.') % { 'file_path': f_path, 'commit_1': node1.commit.id, 'commit_2': node2.commit.id }), category='error') return redirect( url('files_home', repo_name=c.repo_name, f_path=f_path)) c.diff_data = diff_data[0] c.FID = h.FID(diff2, node2.path) # cleanup some unneeded data del c.diff_data['raw_diff'] del c.diff_data['chunks'] c.node1 = node1 c.commit_1 = node1.commit c.node2 = node2 c.commit_2 = node2.commit return render('files/diff_2way.html')
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] = [] #special case if we want a show rev only, it's impl here #to reduce JS and callbacks if request.GET.get('show_rev'): if str2bool(request.GET.get('annotate', 'False')): _url = url('files_annotate_home', repo_name=c.repo_name, revision=diff1, f_path=c.f_path) else: _url = url('files_home', repo_name=c.repo_name, revision=diff1, f_path=c.f_path) return redirect(_url) try: if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]: c.changeset_1 = c.rhodecode_repo.get_changeset(diff1) try: node1 = c.changeset_1.get_node(f_path) if node1.is_dir(): raise NodeError('%s path is a %s not a file' % (node1, type(node1))) except NodeDoesNotExistError: c.changeset_1 = EmptyChangeset(cs=diff1, revision=c.changeset_1.revision, repo=c.rhodecode_repo) node1 = FileNode(f_path, '', changeset=c.changeset_1) else: c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo) node1 = FileNode(f_path, '', changeset=c.changeset_1) if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]: c.changeset_2 = c.rhodecode_repo.get_changeset(diff2) try: node2 = c.changeset_2.get_node(f_path) if node2.is_dir(): raise NodeError('%s path is a %s not a file' % (node2, type(node2))) except NodeDoesNotExistError: c.changeset_2 = EmptyChangeset(cs=diff2, revision=c.changeset_2.revision, repo=c.rhodecode_repo) node2 = FileNode(f_path, '', changeset=c.changeset_2) else: c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo) node2 = FileNode(f_path, '', changeset=c.changeset_2) except (RepositoryError, NodeError): log.error(traceback.format_exc()) 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 ) return diff.as_raw() 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.as_raw() 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 = diffs.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) op = '' filename = node1.path cs_changes = { 'fid': [cs1, cs2, op, filename, diff, st] } c.changes = cs_changes return render('files/file_diff.html')
def compare(self, repo_name, source_ref_type, source_ref, target_ref_type, target_ref): # source_ref will be evaluated in source_repo source_repo_name = c.rhodecode_db_repo.repo_name source_path, source_id = parse_path_ref(source_ref) # target_ref will be evaluated in target_repo target_repo_name = request.GET.get('target_repo', source_repo_name) target_path, target_id = parse_path_ref(target_ref) c.commit_statuses = ChangesetStatus.STATUSES # if merge is True # Show what changes since the shared ancestor commit of target/source # the source would get if it was merged with target. Only commits # which are in target but not in source will be shown. merge = str2bool(request.GET.get('merge')) # if merge is False # Show a raw diff of source/target refs even if no ancestor exists # c.fulldiff disables cut_off_limit c.fulldiff = str2bool(request.GET.get('fulldiff')) # if partial, returns just compare_commits.html (commits log) partial = request.is_xhr # swap url for compare_diff page c.swap_url = h.url('compare_url', repo_name=target_repo_name, source_ref_type=target_ref_type, source_ref=target_ref, target_repo=source_repo_name, target_ref_type=source_ref_type, target_ref=source_ref, merge=merge and '1' or '') source_repo = Repository.get_by_repo_name(source_repo_name) target_repo = Repository.get_by_repo_name(target_repo_name) if source_repo is None: msg = _('Could not find the original repo: %(repo)s') % { 'repo': source_repo } log.error(msg) h.flash(msg, category='error') return redirect(url('compare_home', repo_name=c.repo_name)) if target_repo is None: msg = _('Could not find the other repo: %(repo)s') % { 'repo': target_repo_name } log.error(msg) h.flash(msg, category='error') return redirect(url('compare_home', repo_name=c.repo_name)) source_alias = source_repo.scm_instance().alias target_alias = target_repo.scm_instance().alias if source_alias != target_alias: msg = _('The comparison of two different kinds of remote repos ' 'is not available') log.error(msg) h.flash(msg, category='error') return redirect(url('compare_home', repo_name=c.repo_name)) source_commit = self._get_commit_or_redirect(ref=source_id, ref_type=source_ref_type, repo=source_repo, partial=partial) target_commit = self._get_commit_or_redirect(ref=target_id, ref_type=target_ref_type, repo=target_repo, partial=partial) c.compare_home = False c.source_repo = source_repo c.target_repo = target_repo c.source_ref = source_ref c.target_ref = target_ref c.source_ref_type = source_ref_type c.target_ref_type = target_ref_type source_scm = source_repo.scm_instance() target_scm = target_repo.scm_instance() pre_load = ["author", "branch", "date", "message"] c.ancestor = None try: c.commit_ranges = source_scm.compare(source_commit.raw_id, target_commit.raw_id, target_scm, merge, pre_load=pre_load) if merge: c.ancestor = source_scm.get_common_ancestor( source_commit.raw_id, target_commit.raw_id, target_scm) except RepositoryRequirementError: msg = _('Could not compare repos with different ' 'large file settings') log.error(msg) if partial: return msg h.flash(msg, category='error') return redirect(url('compare_home', repo_name=c.repo_name)) c.statuses = c.rhodecode_db_repo.statuses( [x.raw_id for x in c.commit_ranges]) if partial: # for PR ajax commits loader if not c.ancestor: return '' # cannot merge if there is no ancestor return render('compare/compare_commits.html') if c.ancestor: # case we want a simple diff without incoming commits, # previewing what will be merged. # Make the diff on target repo (which is known to have target_ref) log.debug('Using ancestor %s as source_ref instead of %s' % (c.ancestor, source_ref)) source_repo = target_repo source_commit = target_repo.get_commit(commit_id=c.ancestor) # diff_limit will cut off the whole diff if the limit is applied # otherwise it will just hide the big files from the front-end diff_limit = self.cut_off_limit_diff file_limit = self.cut_off_limit_file log.debug( 'calculating diff between ' 'source_ref:%s and target_ref:%s for repo `%s`', source_commit, target_commit, safe_unicode(source_repo.scm_instance().path)) if source_commit.repository != target_commit.repository: msg = _( "Repositories unrelated. " "Cannot compare commit %(commit1)s from repository %(repo1)s " "with commit %(commit2)s from repository %(repo2)s.") % { 'commit1': h.show_id(source_commit), 'repo1': source_repo.repo_name, 'commit2': h.show_id(target_commit), 'repo2': target_repo.repo_name, } h.flash(msg, category='error') raise HTTPBadRequest() txtdiff = source_repo.scm_instance().get_diff(commit1=source_commit, commit2=target_commit, path1=source_path, path=target_path) diff_processor = diffs.DiffProcessor(txtdiff, format='gitdiff', diff_limit=diff_limit, file_limit=file_limit, show_full_diff=c.fulldiff) _parsed = diff_processor.prepare() c.limited_diff = False if isinstance(_parsed, diffs.LimitedDiffContainer): c.limited_diff = True c.files = [] c.changes = {} c.lines_added = 0 c.lines_deleted = 0 for f in _parsed: st = f['stats'] if not st['binary']: c.lines_added += st['added'] c.lines_deleted += st['deleted'] fid = h.FID('', f['filename']) c.files.append([fid, f['operation'], f['filename'], f['stats'], f]) htmldiff = diff_processor.as_html(enable_comments=False, parsed_lines=[f]) c.changes[fid] = [f['operation'], f['filename'], htmldiff, f] c.preview_mode = merge return render('compare/compare_diff.html')
def anchor_url(revision, path, GET): fid = h.FID(revision, path) return h.url.current(anchor=fid, **dict(GET))
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 limit_off = request.GET.get('fulldiff') #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 if limit_off is None else None 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)) #================================================================== # 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 if limit_off is None else None 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 #================================================================== 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: 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')
class ChangesetController(BaseRepoController): @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def __before__(self): super(ChangesetController, self).__before__() c.affected_files_cut_off = 60 repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() def index(self, revision, method='show'): c.anchor_url = anchor_url c.ignorews_url = _ignorews_url c.context_url = _context_url c.fulldiff = fulldiff = request.GET.get('fulldiff') #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='error') raise HTTPNotFound() c.changes = OrderedDict() c.lines_added = 0 # count of lines added c.lines_deleted = 0 # count of lines removes c.changeset_statuses = ChangesetStatus.STATUSES c.comments = [] c.statuses = [] c.inline_comments = [] c.inline_cnt = 0 # Iterate over ranges (default changeset view is always one changeset) for changeset in c.cs_ranges: inlines = [] if method == 'show': c.statuses.extend([ChangesetStatusModel().get_status( c.rhodecode_db_repo.repo_id, changeset.raw_id)]) c.comments.extend(ChangesetCommentsModel()\ .get_comments(c.rhodecode_db_repo.repo_id, revision=changeset.raw_id)) #comments from PR st = ChangesetStatusModel().get_statuses( c.rhodecode_db_repo.repo_id, changeset.raw_id, with_revisions=True) # from associated statuses, check the pull requests, and # show comments from them prs = set([x.pull_request for x in filter(lambda x: x.pull_request != None, st)]) for pr in prs: c.comments.extend(pr.comments) inlines = ChangesetCommentsModel()\ .get_inline_comments(c.rhodecode_db_repo.repo_id, revision=changeset.raw_id) c.inline_comments.extend(inlines) c.changes[changeset.raw_id] = [] cs2 = changeset.raw_id cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset() context_lcl = get_line_ctx('', request.GET) ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET) _diff = c.rhodecode_repo.get_diff(cs1, cs2, ignore_whitespace=ign_whitespace_lcl, context=context_lcl) diff_limit = self.cut_off_limit if not fulldiff else None diff_processor = diffs.DiffProcessor(_diff, vcs=c.rhodecode_repo.alias, format='gitdiff', diff_limit=diff_limit) cs_changes = OrderedDict() if method == 'show': _parsed = diff_processor.prepare() c.limited_diff = False if isinstance(_parsed, LimitedDiffContainer): c.limited_diff = True for f in _parsed: st = f['stats'] if st[0] != 'b': c.lines_added += st[0] c.lines_deleted += st[1] fid = h.FID(changeset.raw_id, f['filename']) diff = diff_processor.as_html(enable_comments=enable_comments, parsed_lines=[f]) cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'], diff, st] else: # downloads/raw we only need RAW diff nothing else diff = diff_processor.as_raw() cs_changes[''] = [None, None, None, None, diff, None] c.changes[changeset.raw_id] = cs_changes #sort comments by how they were generated c.comments = sorted(c.comments, key=lambda x: x.comment_id) # count inline comments for __, 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.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id for x in c.changeset.parents]) if method == 'download': response.content_type = 'text/plain' response.content_disposition = 'attachment; filename=%s.diff' \ % revision[:12] return diff elif method == 'patch': response.content_type = 'text/plain' c.diff = safe_unicode(diff) return render('changeset/patch_changeset.html') elif method == 'raw': response.content_type = 'text/plain' return diff elif method == 'show': if len(c.cs_ranges) == 1: return render('changeset/changeset.html') else: return render('changeset/changeset_range.html')
def _load_compare_data(self, pull_request, enable_comments=True): """ Load context data needed for generating compare diff :param pull_request: """ 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 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 ] 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] diff_limit = self.cut_off_limit if not fulldiff else None # we swap org/other ref since we run a simple diff on one repo log.debug('running diff between %s and %s in %s' % (other_ref, org_ref, org_repo.scm_instance.path)) txtdiff = org_repo.scm_instance.get_diff(rev1=safe_str(other_ref[1]), rev2=safe_str(org_ref[1])) diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff', diff_limit=diff_limit) _parsed = diff_processor.prepare() c.limited_diff = False if isinstance(_parsed, LimitedDiffContainer): c.limited_diff = True c.files = [] c.changes = {} c.lines_added = 0 c.lines_deleted = 0 for f in _parsed: st = f['stats'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] fid = h.FID('', f['filename']) c.files.append([fid, f['operation'], f['filename'], f['stats']]) htmldiff = diff_processor.as_html(enable_comments=enable_comments, parsed_lines=[f]) c.changes[fid] = [f['operation'], f['filename'], htmldiff]
def _index(self, commit_id_range, method): c.ignorews_url = _ignorews_url c.context_url = _context_url c.fulldiff = fulldiff = request.GET.get('fulldiff') # get ranges of commit ids if preset commit_range = commit_id_range.split('...')[:2] enable_comments = True try: pre_load = [ 'affected_files', 'author', 'branch', 'date', 'message', 'parents' ] if len(commit_range) == 2: enable_comments = False commits = c.rhodecode_repo.get_commits( start_id=commit_range[0], end_id=commit_range[1], pre_load=pre_load) commits = list(commits) else: commits = [ c.rhodecode_repo.get_commit(commit_id=commit_id_range, pre_load=pre_load) ] c.commit_ranges = commits if not c.commit_ranges: raise RepositoryError( 'The commit range returned an empty result') except CommitDoesNotExistError: msg = _('No such commit exists for this repository') h.flash(msg, category='error') raise HTTPNotFound() except Exception: log.exception("General failure") raise HTTPNotFound() c.changes = OrderedDict() c.lines_added = 0 c.lines_deleted = 0 c.commit_statuses = ChangesetStatus.STATUSES c.comments = [] c.statuses = [] c.inline_comments = [] c.inline_cnt = 0 c.files = [] # Iterate over ranges (default commit view is always one commit) for commit in c.commit_ranges: if method == 'show': c.statuses.extend([ ChangesetStatusModel().get_status( c.rhodecode_db_repo.repo_id, commit.raw_id) ]) c.comments.extend(ChangesetCommentsModel().get_comments( c.rhodecode_db_repo.repo_id, revision=commit.raw_id)) # comments from PR st = ChangesetStatusModel().get_statuses( c.rhodecode_db_repo.repo_id, commit.raw_id, with_revisions=True) # from associated statuses, check the pull requests, and # show comments from them prs = set( x.pull_request for x in filter(lambda x: x.pull_request is not None, st)) for pr in prs: c.comments.extend(pr.comments) inlines = ChangesetCommentsModel().get_inline_comments( c.rhodecode_db_repo.repo_id, revision=commit.raw_id) c.inline_comments.extend(inlines.iteritems()) c.changes[commit.raw_id] = [] commit2 = commit commit1 = commit.parents[0] if commit.parents else EmptyCommit() # fetch global flags of ignore ws or context lines context_lcl = get_line_ctx('', request.GET) ign_whitespace_lcl = get_ignore_ws('', request.GET) _diff = c.rhodecode_repo.get_diff( commit1, commit2, ignore_whitespace=ign_whitespace_lcl, context=context_lcl) # diff_limit will cut off the whole diff if the limit is applied # otherwise it will just hide the big files from the front-end diff_limit = self.cut_off_limit_diff file_limit = self.cut_off_limit_file diff_processor = diffs.DiffProcessor(_diff, format='gitdiff', diff_limit=diff_limit, file_limit=file_limit, show_full_diff=fulldiff) commit_changes = OrderedDict() if method == 'show': _parsed = diff_processor.prepare() c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer) for f in _parsed: c.files.append(f) st = f['stats'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] fid = h.FID(commit.raw_id, f['filename']) diff = diff_processor.as_html( enable_comments=enable_comments, parsed_lines=[f]) commit_changes[fid] = [ commit1.raw_id, commit2.raw_id, f['operation'], f['filename'], diff, st, f ] else: # downloads/raw we only need RAW diff nothing else diff = diff_processor.as_raw() commit_changes[''] = [None, None, None, None, diff, None, None] c.changes[commit.raw_id] = commit_changes # sort comments by how they were generated c.comments = sorted(c.comments, key=lambda x: x.comment_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) if len(c.commit_ranges) == 1: c.commit = c.commit_ranges[0] c.parent_tmpl = ''.join('# Parent %s\n' % x.raw_id for x in c.commit.parents) if method == 'download': response.content_type = 'text/plain' response.content_disposition = ('attachment; filename=%s.diff' % commit_id_range[:12]) return diff elif method == 'patch': response.content_type = 'text/plain' c.diff = safe_unicode(diff) return render('changeset/patch_changeset.html') elif method == 'raw': response.content_type = 'text/plain' return diff elif method == 'show': if len(c.commit_ranges) == 1: return render('changeset/changeset.html') else: c.ancestor = None c.target_repo = c.rhodecode_db_repo return render('changeset/changeset_range.html')
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) 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 = diffs.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 _load_compare_data(self, pull_request, enable_comments=True): """ Load context data needed for generating compare diff :param pull_request: object related to the request :param enable_comments: flag to determine if comments are included """ source_repo = pull_request.source_repo source_ref_id = pull_request.source_ref_parts.commit_id target_repo = pull_request.target_repo target_ref_id = pull_request.target_ref_parts.commit_id # despite opening commits for bookmarks/branches/tags, we always # convert this to rev to prevent changes after bookmark or branch change c.source_ref_type = 'rev' c.source_ref = source_ref_id c.target_ref_type = 'rev' c.target_ref = target_ref_id c.source_repo = source_repo c.target_repo = target_repo c.fulldiff = bool(request.GET.get('fulldiff')) # diff_limit is the old behavior, will cut off the whole diff # if the limit is applied otherwise will just hide the # big files from the front-end diff_limit = self.cut_off_limit_diff file_limit = self.cut_off_limit_file pre_load = ["author", "branch", "date", "message"] c.commit_ranges = [] source_commit = EmptyCommit() target_commit = EmptyCommit() c.missing_requirements = False try: c.commit_ranges = [ source_repo.get_commit(commit_id=rev, pre_load=pre_load) for rev in pull_request.revisions ] c.statuses = source_repo.statuses( [x.raw_id for x in c.commit_ranges]) target_commit = source_repo.get_commit( commit_id=safe_str(target_ref_id)) source_commit = source_repo.get_commit( commit_id=safe_str(source_ref_id)) except RepositoryRequirementError: c.missing_requirements = True c.missing_commits = False if (c.missing_requirements or isinstance(source_commit, EmptyCommit) or source_commit == target_commit): _parsed = [] c.missing_commits = True else: vcs_diff = PullRequestModel().get_diff(pull_request) diff_processor = diffs.DiffProcessor(vcs_diff, format='gitdiff', diff_limit=diff_limit, file_limit=file_limit, show_full_diff=c.fulldiff) _parsed = diff_processor.prepare() c.limited_diff = isinstance(_parsed, LimitedDiffContainer) c.files = [] c.changes = {} c.lines_added = 0 c.lines_deleted = 0 c.included_files = [] c.deleted_files = [] for f in _parsed: st = f['stats'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] fid = h.FID('', f['filename']) c.files.append([fid, f['operation'], f['filename'], f['stats']]) c.included_files.append(f['filename']) html_diff = diff_processor.as_html(enable_comments=enable_comments, parsed_lines=[f]) c.changes[fid] = [f['operation'], f['filename'], html_diff, f]
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', '') path1, diff1 = parse_path_ref(diff1, default_path=f_path) 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.ignorews_url = _ignorews_url c.context_url = _context_url c.changes = OrderedDict() c.changes[diff2] = [] if not any((diff1, diff2)): h.flash( 'Need query parameter "diff1" or "diff2" to generate a diff.', category='error') raise HTTPBadRequest() # special case if we want a show commit_id only, it's impl here # to reduce JS and callbacks if request.GET.get('show_rev') and diff1: if str2bool(request.GET.get('annotate', 'False')): _url = url('files_annotate_home', repo_name=c.repo_name, revision=diff1, f_path=path1) else: _url = url('files_home', repo_name=c.repo_name, revision=diff1, f_path=path1) return redirect(_url) try: node1 = self._get_file_node(diff1, path1) node2 = self._get_file_node(diff2, f_path) except (RepositoryError, NodeError): log.exception("Exception while trying to get node from repository") return redirect( url('files_home', repo_name=c.repo_name, f_path=f_path)) if all( isinstance(node.commit, EmptyCommit) for node in (node1, node2)): raise HTTPNotFound c.commit_1 = node1.commit c.commit_2 = node2.commit 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, )) charset = self._get_default_encoding() if charset: response.charset = charset return diff.as_raw() 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' charset = self._get_default_encoding() if charset: response.charset = charset return diff.as_raw() 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) __, commit1, commit2, diff, st, data = diffs.wrapped_diff( filenode_old=node1, filenode_new=node2, diff_limit=self.cut_off_limit_diff, file_limit=self.cut_off_limit_file, show_full_diff=request.GET.get('fulldiff'), ignore_whitespace=ign_whitespace_lcl, line_context=line_context_lcl, ) c.lines_added = data['stats']['added'] if data else 0 c.lines_deleted = data['stats']['deleted'] if data else 0 c.files = [data] c.commit_ranges = [c.commit_1, c.commit_2] c.ancestor = None c.statuses = [] c.target_repo = c.rhodecode_db_repo c.filename1 = node1.path c.filename = node2.path c.binary_file = node1.is_binary or node2.is_binary operation = data['operation'] if data else '' commit_changes = { # TODO: it's passing the old file to the diff to keep the # standard but this is not being used for this template, # but might need both files in the future or a more standard # way to work with that 'fid': [commit1, commit2, operation, c.filename, diff, st, data] } c.changes = commit_changes return render('files/file_diff.html')
def index(self, org_ref_type, org_ref, other_ref_type, other_ref): # 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') # 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], merge=merge or '') org_repo = Repository.get_by_repo_name(org_repo) other_repo = Repository.get_by_repo_name(other_repo) if org_repo is None: log.error('Could not find org repo %s' % org_repo) raise HTTPNotFound if other_repo is None: log.error('Could not find other repo %s' % other_repo) raise HTTPNotFound if org_repo != other_repo and h.is_git(org_repo): log.error( 'compare of two remote repos not available for GIT REPOS') raise HTTPNotFound if org_repo.scm_instance.alias != other_repo.scm_instance.alias: log.error( 'compare of two different kind of remote repos not available') raise HTTPNotFound org_rev = self.__get_rev_or_redirect(ref=org_ref, repo=org_repo, partial=partial) other_rev = self.__get_rev_or_redirect(ref=other_ref, repo=other_repo, partial=partial) c.org_repo = org_repo 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] c.cs_ranges, c.ancestor = self._get_changesets( org_repo.scm_instance.alias, org_repo.scm_instance, org_rev, other_repo.scm_instance, other_rev, merge) c.statuses = c.rhodecode_db_repo.statuses( [x.raw_id for x in c.cs_ranges]) if merge and not c.ancestor: log.error('Unable to find ancestor revision') if partial: return render('compare/compare_cs.html') if c.ancestor: assert merge # case we want a simple diff without incoming changesets, # previewing what will be merged. # 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' % (c.ancestor, org_ref)) org_rev = c.ancestor org_repo = other_repo diff_limit = self.cut_off_limit if not c.fulldiff else None log.debug('running diff between %s and %s in %s' % (org_rev, other_rev, org_repo.scm_instance.path)) txtdiff = org_repo.scm_instance.get_diff(rev1=org_rev, rev2=other_rev) diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff', diff_limit=diff_limit) _parsed = diff_processor.prepare() c.limited_diff = False if isinstance(_parsed, LimitedDiffContainer): c.limited_diff = True c.files = [] c.changes = {} c.lines_added = 0 c.lines_deleted = 0 for f in _parsed: st = f['stats'] if not st['binary']: c.lines_added += st['added'] c.lines_deleted += st['deleted'] fid = h.FID('', f['filename']) c.files.append([fid, f['operation'], f['filename'], f['stats']]) htmldiff = diff_processor.as_html(enable_comments=False, parsed_lines=[f]) c.changes[fid] = [f['operation'], f['filename'], htmldiff] return render('compare/compare_diff.html')