def graphmod(self, repo): """ Simple test for running the graph_data function for profiling/testing performance. """ from kallithea.lib.graphmod import graph_data dbr = Repository.get_by_repo_name(repo) scm_inst = dbr.scm_instance collection = scm_inst.get_changesets(start=0, end=None, branch_name=None) revs = [x.revision for x in collection] jsdata = graph_data(scm_inst, revs)
class ChangesetController(BaseRepoController): def __before__(self): super(ChangesetController, self).__before__() c.affected_files_cut_off = 60 def __load_data(self): repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.user_groups_array = repo_model.get_user_groups_js() def _index(self, revision, method): 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 c.cs_repo = c.db_repo try: if len(rev_range) == 2: enable_comments = False rev_start = rev_range[0] rev_end = rev_range[1] rev_ranges = c.db_repo_scm_instance.get_changesets( start=rev_start, end=rev_end) else: rev_ranges = [c.db_repo_scm_instance.get_changeset(revision)] c.cs_ranges = list(rev_ranges) if not c.cs_ranges: raise RepositoryError('Changeset range returned empty result') except (ChangesetDoesNotExistError, ), e: log.error(traceback.format_exc()) msg = _('Such revision does not exist for this repository') h.flash(msg, 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 comments = dict() 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.db_repo.repo_id, changeset.raw_id) ]) # Changeset comments comments.update( (com.comment_id, com) for com in ChangesetCommentsModel().get_comments( c.db_repo.repo_id, revision=changeset.raw_id)) # Status change comments - mostly from pull requests comments.update(( st.changeset_comment_id, st.comment ) for st in ChangesetStatusModel().get_statuses( c.db_repo.repo_id, changeset.raw_id, with_revisions=True)) inlines = ChangesetCommentsModel()\ .get_inline_comments(c.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().raw_id context_lcl = get_line_ctx('', request.GET) ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws( '', request.GET) _diff = c.db_repo_scm_instance.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.db_repo_scm_instance.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'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] 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 in creation order c.comments = [com for com_id, com in sorted(comments.items())] # 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': self.__load_data() if len(c.cs_ranges) == 1: return render('changeset/changeset.html') else: c.cs_ranges_org = None c.cs_comments = {} revs = [ctx.revision for ctx in reversed(c.cs_ranges)] c.jsdata = json.dumps(graph_data(c.db_repo_scm_instance, revs)) return render('changeset/changeset_range.html')
def compare(self, repo_name, org_ref_type, org_ref_name, other_ref_type, other_ref_name): org_ref_name = org_ref_name.strip() other_ref_name = other_ref_name.strip() # 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 fulldiff = request.GET.get('fulldiff') # partial uses compare_cs.html template directly partial = request.environ.get('HTTP_X_PARTIAL_XHR') # is_ajax_preview puts hidden input field with changeset revisions c.is_ajax_preview = partial and request.GET.get('is_ajax_preview') # swap url for compare_diff page - never partial and never is_ajax_preview c.swap_url = h.url('compare_url', repo_name=c.cs_repo.repo_name, org_ref_type=other_ref_type, org_ref_name=other_ref_name, other_repo=c.a_repo.repo_name, other_ref_type=org_ref_type, other_ref_name=org_ref_name, merge=merge or '') # set callbacks for generating markup for icons c.ignorews_url = _ignorews_url c.context_url = _context_url ignore_whitespace = request.GET.get('ignorews') == '1' line_context = safe_int(request.GET.get('context'), 3) c.a_rev = self._get_ref_rev(c.a_repo, org_ref_type, org_ref_name, returnempty=True) c.cs_rev = self._get_ref_rev(c.cs_repo, other_ref_type, other_ref_name) c.compare_home = False c.a_ref_name = org_ref_name c.a_ref_type = org_ref_type c.cs_ref_name = other_ref_name c.cs_ref_type = other_ref_type c.cs_ranges, c.cs_ranges_org, c.ancestors = self._get_changesets( c.a_repo.scm_instance.alias, c.a_repo.scm_instance, c.a_rev, c.cs_repo.scm_instance, c.cs_rev) raw_ids = [x.raw_id for x in c.cs_ranges] c.cs_comments = c.cs_repo.get_comments(raw_ids) c.cs_statuses = c.cs_repo.statuses(raw_ids) revs = [ctx.revision for ctx in reversed(c.cs_ranges)] c.jsdata = graph_data(c.cs_repo.scm_instance, revs) if partial: return render('compare/compare_cs.html') org_repo = c.a_repo other_repo = c.cs_repo if merge: rev1 = msg = None if not c.cs_ranges: msg = _('Cannot show empty diff') elif not c.ancestors: msg = _('No ancestor found for merge diff') elif len(c.ancestors) == 1: rev1 = c.ancestors[0] else: msg = _('Multiple merge ancestors found for merge compare') if rev1 is None: h.flash(msg, category='error') log.error(msg) raise HTTPNotFound # 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_rev) log.debug('Using ancestor %s as rev1 instead of %s', rev1, c.a_rev) org_repo = other_repo else: # comparing tips, not necessarily linearly related if org_repo != other_repo: # TODO: we could do this by using hg unionrepo log.error('cannot compare across repos %s and %s', org_repo, other_repo) h.flash(_( 'Cannot compare repositories without using common ancestor' ), category='error') raise HTTPBadRequest rev1 = c.a_rev diff_limit = None if fulldiff else self.cut_off_limit log.debug('running diff between %s and %s in %s', rev1, c.cs_rev, org_repo.scm_instance.path) raw_diff = diffs.get_diff(org_repo.scm_instance, rev1=rev1, rev2=c.cs_rev, ignore_whitespace=ignore_whitespace, context=line_context) diff_processor = diffs.DiffProcessor(raw_diff, diff_limit=diff_limit) c.limited_diff = diff_processor.limited_diff c.file_diff_data = [] c.lines_added = 0 c.lines_deleted = 0 for f in diff_processor.parsed: st = f['stats'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] filename = f['filename'] fid = h.FID('', filename) html_diff = diffs.as_html(enable_comments=False, parsed_lines=[f]) c.file_diff_data.append( (fid, None, f['operation'], f['old_filename'], filename, html_diff, st)) return render('compare/compare_diff.html')
def index(self, repo_name, revision=None, f_path=None): # Fix URL after page size form submission via GET # TODO: Somehow just don't send this extra junk in the GET URL if request.GET.get('set'): request.GET.pop('set', None) if revision is None: raise HTTPFound(location=url('changelog_home', repo_name=repo_name, **request.GET)) raise HTTPFound(location=url('changelog_file_home', repo_name=repo_name, revision=revision, f_path=f_path, **request.GET)) limit = 2000 default = 100 if request.GET.get('size'): c.size = max(min(safe_int(request.GET.get('size')), limit), 1) session['changelog_size'] = c.size session.save() else: c.size = int(session.get('changelog_size', default)) # min size must be 1 c.size = max(c.size, 1) p = safe_int(request.GET.get('page', 1), 1) branch_name = request.GET.get('branch', None) if (branch_name and branch_name not in c.db_repo_scm_instance.branches and branch_name not in c.db_repo_scm_instance.closed_branches and not revision): raise HTTPFound(location=url('changelog_file_home', repo_name=c.repo_name, revision=branch_name, f_path=f_path or '')) if revision == 'tip': revision = None c.changelog_for_path = f_path try: if f_path: log.debug('generating changelog for path %s', f_path) # get the history for the file ! tip_cs = c.db_repo_scm_instance.get_changeset() try: collection = tip_cs.get_file_history(f_path) except (NodeDoesNotExistError, ChangesetError): #this node is not present at tip ! try: cs = self.__get_cs(revision, repo_name) collection = cs.get_file_history(f_path) except RepositoryError as e: h.flash(safe_str(e), category='warning') raise HTTPFound(location=h.url('changelog_home', repo_name=repo_name)) collection = list(reversed(collection)) else: collection = c.db_repo_scm_instance.get_changesets(start=0, end=revision, branch_name=branch_name) c.total_cs = len(collection) c.pagination = RepoPage(collection, page=p, item_count=c.total_cs, items_per_page=c.size, branch=branch_name,) page_revisions = [x.raw_id for x in c.pagination] c.comments = c.db_repo.get_comments(page_revisions) c.statuses = c.db_repo.statuses(page_revisions) except EmptyRepositoryError as e: h.flash(safe_str(e), category='warning') raise HTTPFound(location=url('summary_home', repo_name=c.repo_name)) except (RepositoryError, ChangesetDoesNotExistError, Exception) as e: log.error(traceback.format_exc()) h.flash(safe_str(e), category='error') raise HTTPFound(location=url('changelog_home', repo_name=c.repo_name)) c.branch_name = branch_name c.branch_filters = [('', _('None'))] + \ [(k, k) for k in c.db_repo_scm_instance.branches.keys()] if c.db_repo_scm_instance.closed_branches: prefix = _('(closed)') + ' ' c.branch_filters += [('-', '-')] + \ [(k, prefix + k) for k in c.db_repo_scm_instance.closed_branches.keys()] revs = [] if not f_path: revs = [x.revision for x in c.pagination] c.jsdata = json.dumps(graph_data(c.db_repo_scm_instance, revs)) c.revision = revision # requested revision ref c.first_revision = c.pagination[0] # pagination is never empty here! return render('changelog/changelog.html')
def index(self, repo_name, revision=None, f_path=None): # Fix URL after page size form submission via GET # TODO: Somehow just don't send this extra junk in the GET URL if request.GET.get('set'): request.GET.pop('set', None) if revision is None: raise HTTPFound(location=url( 'changelog_home', repo_name=repo_name, **request.GET)) raise HTTPFound(location=url('changelog_file_home', repo_name=repo_name, revision=revision, f_path=f_path, **request.GET)) limit = 2000 default = 100 if request.GET.get('size'): c.size = max(min(safe_int(request.GET.get('size')), limit), 1) session['changelog_size'] = c.size session.save() else: c.size = int(session.get('changelog_size', default)) # min size must be 1 c.size = max(c.size, 1) p = safe_int(request.GET.get('page'), 1) branch_name = request.GET.get('branch', None) if (branch_name and branch_name not in c.db_repo_scm_instance.branches and branch_name not in c.db_repo_scm_instance.closed_branches and not revision): raise HTTPFound(location=url('changelog_file_home', repo_name=c.repo_name, revision=branch_name, f_path=f_path or '')) if revision == 'tip': revision = None c.changelog_for_path = f_path try: if f_path: log.debug('generating changelog for path %s', f_path) # get the history for the file ! tip_cs = c.db_repo_scm_instance.get_changeset() try: collection = tip_cs.get_file_history(f_path) except (NodeDoesNotExistError, ChangesetError): #this node is not present at tip ! try: cs = self.__get_cs(revision, repo_name) collection = cs.get_file_history(f_path) except RepositoryError as e: h.flash(safe_str(e), category='warning') raise HTTPFound(location=h.url('changelog_home', repo_name=repo_name)) collection = list(reversed(collection)) else: collection = c.db_repo_scm_instance.get_changesets( start=0, end=revision, branch_name=branch_name) c.total_cs = len(collection) c.pagination = RepoPage( collection, page=p, item_count=c.total_cs, items_per_page=c.size, branch=branch_name, ) page_revisions = [x.raw_id for x in c.pagination] c.comments = c.db_repo.get_comments(page_revisions) c.statuses = c.db_repo.statuses(page_revisions) except EmptyRepositoryError as e: h.flash(safe_str(e), category='warning') raise HTTPFound( location=url('summary_home', repo_name=c.repo_name)) except (RepositoryError, ChangesetDoesNotExistError, Exception) as e: log.error(traceback.format_exc()) h.flash(safe_str(e), category='error') raise HTTPFound( location=url('changelog_home', repo_name=c.repo_name)) c.branch_name = branch_name c.branch_filters = [('', _('None'))] + \ [(k, k) for k in c.db_repo_scm_instance.branches.keys()] if c.db_repo_scm_instance.closed_branches: prefix = _('(closed)') + ' ' c.branch_filters += [('-', '-')] + \ [(k, prefix + k) for k in c.db_repo_scm_instance.closed_branches.keys()] revs = [] if not f_path: revs = [x.revision for x in c.pagination] c.jsdata = graph_data(c.db_repo_scm_instance, revs) c.revision = revision # requested revision ref c.first_revision = c.pagination[0] # pagination is never empty here! return render('changelog/changelog.html')
def _index(self, revision, method): c.pull_request = None 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 c.cs_repo = c.db_repo try: if len(rev_range) == 2: enable_comments = False rev_start = rev_range[0] rev_end = rev_range[1] rev_ranges = c.db_repo_scm_instance.get_changesets(start=rev_start, end=rev_end) else: rev_ranges = [c.db_repo_scm_instance.get_changeset(revision)] c.cs_ranges = list(rev_ranges) if not c.cs_ranges: raise RepositoryError('Changeset range returned empty result') except (ChangesetDoesNotExistError, EmptyRepositoryError): log.debug(traceback.format_exc()) msg = _('Such revision does not exist for this repository') h.flash(msg, 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 comments = dict() 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: if method == 'show': c.statuses.extend([ChangesetStatusModel().get_status( c.db_repo.repo_id, changeset.raw_id)]) # Changeset comments comments.update((com.comment_id, com) for com in ChangesetCommentsModel() .get_comments(c.db_repo.repo_id, revision=changeset.raw_id)) # Status change comments - mostly from pull requests comments.update((st.comment_id, st.comment) for st in ChangesetStatusModel() .get_statuses(c.db_repo.repo_id, changeset.raw_id, with_revisions=True) if st.comment_id is not None) inlines = ChangesetCommentsModel() \ .get_inline_comments(c.db_repo.repo_id, revision=changeset.raw_id) c.inline_comments.extend(inlines) cs2 = changeset.raw_id cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset().raw_id context_lcl = get_line_ctx('', request.GET) ign_whitespace_lcl = get_ignore_ws('', request.GET) _diff = c.db_repo_scm_instance.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.db_repo_scm_instance.alias, format='gitdiff', diff_limit=diff_limit) file_diff_data = [] 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'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] filename = f['filename'] fid = h.FID(changeset.raw_id, filename) url_fid = h.FID('', filename) diff = diff_processor.as_html(enable_comments=enable_comments, parsed_lines=[f]) file_diff_data.append((fid, url_fid, f['operation'], f['old_filename'], filename, diff, st)) else: # downloads/raw we only need RAW diff nothing else diff = diff_processor.as_raw() file_diff_data.append(('', None, None, None, diff, None)) c.changes[changeset.raw_id] = (cs1, cs2, file_diff_data) #sort comments in creation order c.comments = [com for com_id, com in sorted(comments.items())] # 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': self.__load_data() if len(c.cs_ranges) == 1: return render('changeset/changeset.html') else: c.cs_ranges_org = None c.cs_comments = {} revs = [ctx.revision for ctx in reversed(c.cs_ranges)] c.jsdata = graph_data(c.db_repo_scm_instance, revs) return render('changeset/changeset_range.html')
def _index(self, revision, method): c.pull_request = None c.anchor_url = anchor_url c.ignorews_url = _ignorews_url c.context_url = _context_url c.fulldiff = request.GET.get( 'fulldiff') # for reporting number of changed files # get ranges of revisions if preset rev_range = revision.split('...')[:2] enable_comments = True c.cs_repo = c.db_repo try: if len(rev_range) == 2: enable_comments = False rev_start = rev_range[0] rev_end = rev_range[1] rev_ranges = c.db_repo_scm_instance.get_changesets( start=rev_start, end=rev_end) else: rev_ranges = [c.db_repo_scm_instance.get_changeset(revision)] c.cs_ranges = list(rev_ranges) if not c.cs_ranges: raise RepositoryError('Changeset range returned empty result') except (ChangesetDoesNotExistError, EmptyRepositoryError): log.debug(traceback.format_exc()) msg = _('Such revision does not exist for this repository') h.flash(msg, 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 comments = dict() 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: if method == 'show': c.statuses.extend([ ChangesetStatusModel().get_status(c.db_repo.repo_id, changeset.raw_id) ]) # Changeset comments comments.update( (com.comment_id, com) for com in ChangesetCommentsModel().get_comments( c.db_repo.repo_id, revision=changeset.raw_id)) # Status change comments - mostly from pull requests comments.update(( st.comment_id, st.comment ) for st in ChangesetStatusModel().get_statuses( c.db_repo.repo_id, changeset.raw_id, with_revisions=True) if st.comment_id is not None) inlines = ChangesetCommentsModel() \ .get_inline_comments(c.db_repo.repo_id, revision=changeset.raw_id) c.inline_comments.extend(inlines) cs2 = changeset.raw_id cs1 = changeset.parents[ 0].raw_id if changeset.parents else EmptyChangeset().raw_id context_lcl = get_line_ctx('', request.GET) ign_whitespace_lcl = get_ignore_ws('', request.GET) raw_diff = diffs.get_diff(c.db_repo_scm_instance, cs1, cs2, ignore_whitespace=ign_whitespace_lcl, context=context_lcl) diff_limit = None if c.fulldiff else self.cut_off_limit file_diff_data = [] if method == 'show': diff_processor = diffs.DiffProcessor( raw_diff, vcs=c.db_repo_scm_instance.alias, diff_limit=diff_limit) c.limited_diff = diff_processor.limited_diff for f in diff_processor.parsed: st = f['stats'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] filename = f['filename'] fid = h.FID(changeset.raw_id, filename) url_fid = h.FID('', filename) html_diff = diffs.as_html(enable_comments=enable_comments, parsed_lines=[f]) file_diff_data.append( (fid, url_fid, f['operation'], f['old_filename'], filename, html_diff, st)) else: # downloads/raw we only need RAW diff nothing else file_diff_data.append(('', None, None, None, raw_diff, None)) c.changes[changeset.raw_id] = (cs1, cs2, file_diff_data) # sort comments in creation order c.comments = [com for com_id, com in sorted(comments.items())] # 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]) c.changeset_graft_source_hash = ascii_str( c.changeset.extra.get(b'source', b'')) c.changeset_transplant_source_hash = ascii_str( binascii.hexlify( c.changeset.extra.get(b'transplant_source', b''))) if method == 'download': response.content_type = 'text/plain' response.content_disposition = 'attachment; filename=%s.diff' \ % revision[:12] return raw_diff elif method == 'patch': response.content_type = 'text/plain' c.diff = safe_str(raw_diff) return render('changeset/patch_changeset.html') elif method == 'raw': response.content_type = 'text/plain' return raw_diff elif method == 'show': if len(c.cs_ranges) == 1: return render('changeset/changeset.html') else: c.cs_ranges_org = None c.cs_comments = {} revs = [ctx.revision for ctx in reversed(c.cs_ranges)] c.jsdata = graph_data(c.db_repo_scm_instance, revs) return render('changeset/changeset_range.html')
except (RepositoryError, ChangesetDoesNotExistError, Exception), e: log.error(traceback.format_exc()) h.flash(safe_str(e), category='error') return redirect(url('changelog_home', repo_name=c.repo_name)) c.branch_name = branch_name c.branch_filters = [('', _('None'))] + \ [(k, k) for k in c.db_repo_scm_instance.branches.keys()] if c.db_repo_scm_instance.closed_branches: prefix = _('(closed)') + ' ' c.branch_filters += [('-', '-')] + \ [(k, prefix + k) for k in c.db_repo_scm_instance.closed_branches.keys()] revs = [] if not f_path: revs = [x.revision for x in c.pagination] c.jsdata = json.dumps(graph_data(c.db_repo_scm_instance, revs)) c.revision = revision # requested revision ref c.first_revision = c.pagination[0] # pagination is never empty here! return render('changelog/changelog.html') @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def changelog_details(self, cs): if request.environ.get('HTTP_X_PARTIAL_XHR'): c.cs = c.db_repo_scm_instance.get_changeset(cs) return render('changelog/changelog_details.html') raise HTTPNotFound() @LoginRequired()
def show(self, repo_name, pull_request_id, extra=None): repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.user_groups_array = repo_model.get_user_groups_js() c.pull_request = PullRequest.get_or_404(pull_request_id) c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request) cc_model = ChangesetCommentsModel() cs_model = ChangesetStatusModel() # pull_requests repo_name we opened it against # ie. other_repo must match if repo_name != c.pull_request.other_repo.repo_name: raise HTTPNotFound # load compare data into template context c.cs_repo = c.pull_request.org_repo (c.cs_ref_type, c.cs_ref_name, c.cs_rev) = c.pull_request.org_ref.split(':') c.a_repo = c.pull_request.other_repo (c.a_ref_type, c.a_ref_name, c.a_rev) = c.pull_request.other_ref.split(':') # other_rev is ancestor org_scm_instance = c.cs_repo.scm_instance # property with expensive cache invalidation check!!! c.cs_repo = c.cs_repo try: c.cs_ranges = [org_scm_instance.get_changeset(x) for x in c.pull_request.revisions] except ChangesetDoesNotExistError: c.cs_ranges = [] c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ... revs = [ctx.revision for ctx in reversed(c.cs_ranges)] c.jsdata = json.dumps(graph_data(org_scm_instance, revs)) c.is_range = False if c.a_ref_type == 'rev': # this looks like a free range where target is ancestor cs_a = org_scm_instance.get_changeset(c.a_rev) root_parents = c.cs_ranges[0].parents c.is_range = cs_a in root_parents #c.merge_root = len(root_parents) > 1 # a range starting with a merge might deserve a warning avail_revs = set() avail_show = [] c.cs_branch_name = c.cs_ref_name other_scm_instance = c.a_repo.scm_instance c.update_msg = "" c.update_msg_other = "" try: if org_scm_instance.alias == 'hg' and c.a_ref_name != 'ancestor': if c.cs_ref_type != 'branch': c.cs_branch_name = org_scm_instance.get_changeset(c.cs_ref_name).branch # use ref_type ? c.a_branch_name = c.a_ref_name if c.a_ref_type != 'branch': try: c.a_branch_name = other_scm_instance.get_changeset(c.a_ref_name).branch # use ref_type ? except EmptyRepositoryError: c.a_branch_name = 'null' # not a branch name ... but close enough # candidates: descendants of old head that are on the right branch # and not are the old head itself ... # and nothing at all if old head is a descendant of target ref name if not c.is_range and other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, c.a_branch_name): c.update_msg = _('This pull request has already been merged to %s.') % c.a_branch_name elif c.pull_request.is_closed(): c.update_msg = _('This pull request has been closed and can not be updated.') else: # look for descendants of PR head on source branch in org repo avail_revs = org_scm_instance._repo.revs('%s:: & branch(%s)', revs[0], c.cs_branch_name) if len(avail_revs) > 1: # more than just revs[0] # also show changesets that not are descendants but would be merged in targethead = other_scm_instance.get_changeset(c.a_branch_name).raw_id if org_scm_instance.path != other_scm_instance.path: # Note: org_scm_instance.path must come first so all # valid revision numbers are 100% org_scm compatible # - both for avail_revs and for revset results hgrepo = unionrepo.unionrepository(org_scm_instance.baseui, org_scm_instance.path, other_scm_instance.path) else: hgrepo = org_scm_instance._repo show = set(hgrepo.revs('::%ld & !::parents(%s) & !::%s', avail_revs, revs[0], targethead)) c.update_msg = _('The following changes are available on %s:') % c.cs_branch_name else: show = set() avail_revs = set() # drop revs[0] c.update_msg = _('No changesets found for updating this pull request.') # TODO: handle branch heads that not are tip-most brevs = org_scm_instance._repo.revs('%s - %ld - %s', c.cs_branch_name, avail_revs, revs[0]) if brevs: # also show changesets that are on branch but neither ancestors nor descendants show.update(org_scm_instance._repo.revs('::%ld - ::%ld - ::%s', brevs, avail_revs, c.a_branch_name)) show.add(revs[0]) # make sure graph shows this so we can see how they relate c.update_msg_other = _('Note: Branch %s has another head: %s.') % (c.cs_branch_name, h.short_id(org_scm_instance.get_changeset((max(brevs))).raw_id)) avail_show = sorted(show, reverse=True) elif org_scm_instance.alias == 'git': c.cs_repo.scm_instance.get_changeset(c.cs_rev) # check it exists - raise ChangesetDoesNotExistError if not c.update_msg = _("Git pull requests don't support updates yet.") except ChangesetDoesNotExistError: c.update_msg = _('Error: revision %s was not found. Please create a new pull request!') % c.cs_rev c.avail_revs = avail_revs c.avail_cs = [org_scm_instance.get_changeset(r) for r in avail_show] c.avail_jsdata = json.dumps(graph_data(org_scm_instance, avail_show)) raw_ids = [x.raw_id for x in c.cs_ranges] c.cs_comments = c.cs_repo.get_comments(raw_ids) c.statuses = c.cs_repo.statuses(raw_ids) ignore_whitespace = request.GET.get('ignorews') == '1' line_context = request.GET.get('context', 3) c.ignorews_url = _ignorews_url c.context_url = _context_url c.fulldiff = request.GET.get('fulldiff') diff_limit = self.cut_off_limit if not c.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', c.a_rev, c.cs_rev, org_scm_instance.path) try: txtdiff = org_scm_instance.get_diff(rev1=safe_str(c.a_rev), rev2=safe_str(c.cs_rev), ignore_whitespace=ignore_whitespace, context=line_context) except ChangesetDoesNotExistError: txtdiff = _("The diff can't be shown - the PR revisions could not be found.") 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=True, parsed_lines=[f]) c.changes[fid] = [f['operation'], f['filename'], htmldiff] # inline comments c.inline_cnt = 0 c.inline_comments = cc_model.get_inline_comments( c.db_repo.repo_id, pull_request=pull_request_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) # comments c.comments = cc_model.get_comments(c.db_repo.repo_id, pull_request=pull_request_id) # (badly named) pull-request status calculation based on reviewer votes (c.pull_request_reviewers, c.pull_request_pending_reviewers, c.current_voting_result, ) = cs_model.calculate_pull_request_result(c.pull_request) c.changeset_statuses = ChangesetStatus.STATUSES c.as_form = False c.ancestor = None # there is one - but right here we don't know which return render('/pullrequests/pullrequest_show.html')
def compare(self, repo_name, org_ref_type, org_ref_name, other_ref_type, other_ref_name): org_ref_name = org_ref_name.strip() other_ref_name = other_ref_name.strip() org_repo = c.db_repo.repo_name 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_type, org_ref_name=other_ref_name, other_repo=org_repo, other_ref_type=org_ref_type, other_ref_name=org_ref_name, merge=merge or '') # set callbacks for generating markup for icons c.ignorews_url = _ignorews_url c.context_url = _context_url ignore_whitespace = request.GET.get('ignorews') == '1' line_context = request.GET.get('context', 3) org_repo = Repository.get_by_repo_name(org_repo) other_repo = Repository.get_by_repo_name(other_repo) if org_repo is None: msg = 'Could not find org repo %s' % org_repo log.error(msg) h.flash(msg, category='error') raise HTTPFound(location=url('compare_home', repo_name=c.repo_name)) if other_repo is None: msg = 'Could not find other repo %s' % other_repo log.error(msg) h.flash(msg, category='error') raise HTTPFound(location=url('compare_home', repo_name=c.repo_name)) if org_repo.scm_instance.alias != other_repo.scm_instance.alias: msg = 'compare of two different kind of remote repos not available' log.error(msg) h.flash(msg, category='error') raise HTTPFound(location=url('compare_home', repo_name=c.repo_name)) c.a_rev = self._get_ref_rev(org_repo, org_ref_type, org_ref_name, returnempty=True) c.cs_rev = self._get_ref_rev(other_repo, other_ref_type, other_ref_name) c.compare_home = False c.a_repo = org_repo c.a_ref_name = org_ref_name c.a_ref_type = org_ref_type c.cs_repo = other_repo c.cs_ref_name = other_ref_name c.cs_ref_type = other_ref_type c.cs_ranges, c.cs_ranges_org, c.ancestor = self._get_changesets( org_repo.scm_instance.alias, org_repo.scm_instance, c.a_rev, other_repo.scm_instance, c.cs_rev) raw_ids = [x.raw_id for x in c.cs_ranges] c.cs_comments = other_repo.get_comments(raw_ids) c.statuses = other_repo.statuses(raw_ids) revs = [ctx.revision for ctx in reversed(c.cs_ranges)] c.jsdata = json.dumps(graph_data(c.cs_repo.scm_instance, revs)) if partial: return render('compare/compare_cs.html') if merge and c.ancestor: # 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_rev) log.debug('Using ancestor %s as rev1 instead of %s', c.ancestor, c.a_rev) rev1 = c.ancestor org_repo = other_repo else: # comparing tips, not necessarily linearly related if merge: log.error('Unable to find ancestor revision') if org_repo != other_repo: # TODO: we could do this by using hg unionrepo log.error('cannot compare across repos %s and %s', org_repo, other_repo) h.flash(_('Cannot compare repositories without using common ancestor'), category='error') raise HTTPBadRequest rev1 = c.a_rev diff_limit = self.cut_off_limit if not c.fulldiff else None log.debug('running diff between %s and %s in %s', rev1, c.cs_rev, org_repo.scm_instance.path) txtdiff = org_repo.scm_instance.get_diff(rev1=rev1, rev2=c.cs_rev, ignore_whitespace=ignore_whitespace, context=line_context) 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')
def show(self, repo_name, pull_request_id, extra=None): repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.user_groups_array = repo_model.get_user_groups_js() c.pull_request = PullRequest.get_or_404(pull_request_id) c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request) cc_model = ChangesetCommentsModel() cs_model = ChangesetStatusModel() # pull_requests repo_name we opened it against # ie. other_repo must match if repo_name != c.pull_request.other_repo.repo_name: raise HTTPNotFound # load compare data into template context c.cs_repo = c.pull_request.org_repo (c.cs_ref_type, c.cs_ref_name, c.cs_rev) = c.pull_request.org_ref.split(':') c.a_repo = c.pull_request.other_repo (c.a_ref_type, c.a_ref_name, c.a_rev) = c.pull_request.other_ref.split(':') # a_rev is ancestor org_scm_instance = c.cs_repo.scm_instance # property with expensive cache invalidation check!!! try: c.cs_ranges = [org_scm_instance.get_changeset(x) for x in c.pull_request.revisions] except ChangesetDoesNotExistError: c.cs_ranges = [] h.flash(_('Revision %s not found in %s') % (x, c.cs_repo.repo_name), 'error') c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ... revs = [ctx.revision for ctx in reversed(c.cs_ranges)] c.jsdata = graph_data(org_scm_instance, revs) c.is_range = False try: if c.a_ref_type == 'rev': # this looks like a free range where target is ancestor cs_a = org_scm_instance.get_changeset(c.a_rev) root_parents = c.cs_ranges[0].parents c.is_range = cs_a in root_parents #c.merge_root = len(root_parents) > 1 # a range starting with a merge might deserve a warning except ChangesetDoesNotExistError: # probably because c.a_rev not found pass except IndexError: # probably because c.cs_ranges is empty, probably because revisions are missing pass avail_revs = set() avail_show = [] c.cs_branch_name = c.cs_ref_name c.a_branch_name = None other_scm_instance = c.a_repo.scm_instance c.update_msg = "" c.update_msg_other = "" try: if not c.cs_ranges: c.update_msg = _('Error: changesets not found when displaying pull request from %s.') % c.cs_rev elif org_scm_instance.alias == 'hg' and c.a_ref_name != 'ancestor': if c.cs_ref_type != 'branch': c.cs_branch_name = org_scm_instance.get_changeset(c.cs_ref_name).branch # use ref_type ? c.a_branch_name = c.a_ref_name if c.a_ref_type != 'branch': try: c.a_branch_name = other_scm_instance.get_changeset(c.a_ref_name).branch # use ref_type ? except EmptyRepositoryError: c.a_branch_name = 'null' # not a branch name ... but close enough # candidates: descendants of old head that are on the right branch # and not are the old head itself ... # and nothing at all if old head is a descendant of target ref name if not c.is_range and other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, c.a_branch_name): c.update_msg = _('This pull request has already been merged to %s.') % c.a_branch_name elif c.pull_request.is_closed(): c.update_msg = _('This pull request has been closed and can not be updated.') else: # look for descendants of PR head on source branch in org repo avail_revs = org_scm_instance._repo.revs('%s:: & branch(%s)', revs[0], c.cs_branch_name) if len(avail_revs) > 1: # more than just revs[0] # also show changesets that not are descendants but would be merged in targethead = other_scm_instance.get_changeset(c.a_branch_name).raw_id if org_scm_instance.path != other_scm_instance.path: # Note: org_scm_instance.path must come first so all # valid revision numbers are 100% org_scm compatible # - both for avail_revs and for revset results hgrepo = unionrepo.unionrepository(org_scm_instance.baseui, org_scm_instance.path, other_scm_instance.path) else: hgrepo = org_scm_instance._repo show = set(hgrepo.revs('::%ld & !::parents(%s) & !::%s', avail_revs, revs[0], targethead)) c.update_msg = _('The following additional changes are available on %s:') % c.cs_branch_name else: show = set() avail_revs = set() # drop revs[0] c.update_msg = _('No additional changesets found for iterating on this pull request.') # TODO: handle branch heads that not are tip-most brevs = org_scm_instance._repo.revs('%s - %ld - %s', c.cs_branch_name, avail_revs, revs[0]) if brevs: # also show changesets that are on branch but neither ancestors nor descendants show.update(org_scm_instance._repo.revs('::%ld - ::%ld - ::%s', brevs, avail_revs, c.a_branch_name)) show.add(revs[0]) # make sure graph shows this so we can see how they relate c.update_msg_other = _('Note: Branch %s has another head: %s.') % (c.cs_branch_name, h.short_id(org_scm_instance.get_changeset((max(brevs))).raw_id)) avail_show = sorted(show, reverse=True) elif org_scm_instance.alias == 'git': c.cs_repo.scm_instance.get_changeset(c.cs_rev) # check it exists - raise ChangesetDoesNotExistError if not c.update_msg = _("Git pull requests don't support iterating yet.") except ChangesetDoesNotExistError: c.update_msg = _('Error: some changesets not found when displaying pull request from %s.') % c.cs_rev c.avail_revs = avail_revs c.avail_cs = [org_scm_instance.get_changeset(r) for r in avail_show] c.avail_jsdata = graph_data(org_scm_instance, avail_show) raw_ids = [x.raw_id for x in c.cs_ranges] c.cs_comments = c.cs_repo.get_comments(raw_ids) c.statuses = c.cs_repo.statuses(raw_ids) ignore_whitespace = request.GET.get('ignorews') == '1' line_context = safe_int(request.GET.get('context'), 3) c.ignorews_url = _ignorews_url c.context_url = _context_url c.fulldiff = request.GET.get('fulldiff') diff_limit = self.cut_off_limit if not c.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', c.a_rev, c.cs_rev, org_scm_instance.path) try: txtdiff = org_scm_instance.get_diff(rev1=safe_str(c.a_rev), rev2=safe_str(c.cs_rev), ignore_whitespace=ignore_whitespace, context=line_context) except ChangesetDoesNotExistError: txtdiff = _("The diff can't be shown - the PR revisions could not be found.") 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.file_diff_data = [] 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'] filename = f['filename'] fid = h.FID('', filename) diff = diff_processor.as_html(enable_comments=True, parsed_lines=[f]) c.file_diff_data.append((fid, None, f['operation'], f['old_filename'], filename, diff, st)) # inline comments c.inline_cnt = 0 c.inline_comments = cc_model.get_inline_comments( c.db_repo.repo_id, pull_request=pull_request_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) # comments c.comments = cc_model.get_comments(c.db_repo.repo_id, pull_request=pull_request_id) # (badly named) pull-request status calculation based on reviewer votes (c.pull_request_reviewers, c.pull_request_pending_reviewers, c.current_voting_result, ) = cs_model.calculate_pull_request_result(c.pull_request) c.changeset_statuses = ChangesetStatus.STATUSES c.is_ajax_preview = False c.ancestors = None # [c.a_rev] ... but that is shown in an other way return render('/pullrequests/pullrequest_show.html')
def compare(self, repo_name, org_ref_type, org_ref_name, other_ref_type, other_ref_name): org_repo = c.db_repo.repo_name 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_type, org_ref_name=other_ref_name, other_repo=org_repo, other_ref_type=org_ref_type, other_ref_name=org_ref_name, merge=merge or '') # set callbacks for generating markup for icons c.ignorews_url = _ignorews_url c.context_url = _context_url ignore_whitespace = request.GET.get('ignorews') == '1' line_context = request.GET.get('context', 3) org_repo = Repository.get_by_repo_name(org_repo) other_repo = Repository.get_by_repo_name(other_repo) if org_repo is None: msg = 'Could not find org repo %s' % org_repo log.error(msg) h.flash(msg, category='error') return redirect(url('compare_home', repo_name=c.repo_name)) if other_repo is None: msg = 'Could not find other repo %s' % other_repo log.error(msg) h.flash(msg, category='error') return redirect(url('compare_home', repo_name=c.repo_name)) if org_repo.scm_instance.alias != other_repo.scm_instance.alias: msg = 'compare of two different kind of remote repos not available' log.error(msg) h.flash(msg, category='error') return redirect(url('compare_home', repo_name=c.repo_name)) c.a_rev = self._get_ref_rev(org_repo, org_ref_type, org_ref_name, returnempty=True) c.cs_rev = self._get_ref_rev(other_repo, other_ref_type, other_ref_name) c.compare_home = False c.a_repo = org_repo c.a_ref_name = org_ref_name c.a_ref_type = org_ref_type c.cs_repo = other_repo c.cs_ref_name = other_ref_name c.cs_ref_type = other_ref_type c.cs_ranges, c.cs_ranges_org, c.ancestor = self._get_changesets( org_repo.scm_instance.alias, org_repo.scm_instance, c.a_rev, other_repo.scm_instance, c.cs_rev) raw_ids = [x.raw_id for x in c.cs_ranges] c.cs_comments = other_repo.get_comments(raw_ids) c.statuses = other_repo.statuses(raw_ids) revs = [ctx.revision for ctx in reversed(c.cs_ranges)] c.jsdata = json.dumps(graph_data(c.cs_repo.scm_instance, revs)) if partial: return render('compare/compare_cs.html') if merge and c.ancestor: # 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_rev) log.debug('Using ancestor %s as rev1 instead of %s' % (c.ancestor, c.a_rev)) rev1 = c.ancestor org_repo = other_repo else: # comparing tips, not necessarily linearly related if merge: log.error('Unable to find ancestor revision') if org_repo != other_repo: # TODO: we could do this by using hg unionrepo log.error('cannot compare across repos %s and %s', org_repo, other_repo) h.flash(_( 'Cannot compare repositories without using common ancestor' ), category='error') raise HTTPBadRequest rev1 = c.a_rev diff_limit = self.cut_off_limit if not c.fulldiff else None log.debug('running diff between %s and %s in %s' % (rev1, c.cs_rev, org_repo.scm_instance.path)) txtdiff = org_repo.scm_instance.get_diff( rev1=rev1, rev2=c.cs_rev, ignore_whitespace=ignore_whitespace, context=line_context) 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')