def view_diff_fragment(request, diffset_id, filediff_id, interdiffset_id=None, chunkindex=None, collapseall=False, template_name='diffviewer/diff_file_fragment.html'): diffset = get_object_or_404(DiffSet, pk=diffset_id) filediff = get_object_or_404(FileDiff, pk=filediff_id, diffset=diffset) interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id) highlighting = get_enable_highlighting(request.user) try: files = get_diff_files(diffset, filediff, interdiffset, highlighting) if files: assert len(files) == 1 file = files[0] context = { 'standalone': True, } return HttpResponse( build_diff_fragment(request, file, chunkindex, highlighting, collapseall, context, template_name)) raise UserVisibleError( _(u"Internal error. Unable to locate file record for filediff %s") % \ filediff.id) except Exception, e: return exception_traceback(request, e, template_name, {'standalone': True})
def _get_requested_diff_file(self, diffset, filediff, interdiffset, interfilediff): """Fetches information on the requested diff. This will look up information on the diff that's to be rendered and return it, if found. It may also augment it with additional data. The file will not contain chunk information. That must be specifically populated later. """ files = get_diff_files(diffset=diffset, interdiffset=interdiffset, filediff=filediff, interfilediff=interfilediff, request=self.request) if files: file = files[0] if 'index' in self.request.GET: try: file['index'] = int(self.request.GET.get('index')) except ValueError: pass return file return None
def _get_requested_diff_file(self, diffset, filediff, interdiffset): """Fetches information on the requested diff. This will look up information on the diff that's to be rendered and return it, if found. It may also augment it with additional data. The file will not contain chunk information. That must be specifically populated later. """ files = get_diff_files(diffset, filediff, interdiffset, request=self.request) if files: assert len(files) == 1 file = files[0] if "index" in self.request.GET: try: file["index"] = int(self.request.GET.get("index")) except ValueError: pass return file return None
def _get_requested_diff_file(self, get_chunks=True): """Fetches information on the requested diff. This will look up information on the diff that's to be rendered and return it, if found. It may also augment it with additional data. If get_chunks is True, the diff file information will include chunks for rendering. Otherwise, it will just contain generic information from the database. """ files = get_diff_files(self.diffset, self.filediff, self.interdiffset, request=self.request) if get_chunks: populate_diff_chunks(files, self.highlighting, request=self.request) if files: assert len(files) == 1 file = files[0] if 'index' in self.request.GET: file['index'] = self.request.GET.get('index') return file return None
def _get_requested_diff_file(self, diffset, filediff, interdiffset, interfilediff, base_filediff): """Fetches information on the requested diff. This will look up information on the diff that's to be rendered and return it, if found. It may also augment it with additional data. The file will not contain chunk information. That must be specifically populated later. """ files = get_diff_files(diffset=diffset, interdiffset=interdiffset, filediff=filediff, interfilediff=interfilediff, base_filediff=base_filediff, request=self.request) if files: diff_file = files[0] try: diff_file['index'] = int(self.request.GET['index']) except (KeyError, ValueError): pass return diff_file return None
def view_diff_fragment(request, diffset_id, filediff_id, interdiffset_id=None, chunkindex=None, collapseall=False, template_name='diffviewer/diff_file_fragment.html'): diffset = get_object_or_404(DiffSet, pk=diffset_id) filediff = get_object_or_404(FileDiff, pk=filediff_id, diffset=diffset) interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id) highlighting = get_enable_highlighting(request.user) try: files = get_diff_files(diffset, filediff, interdiffset, highlighting) if files: assert len(files) == 1 file = files[0] context = { 'standalone': True, } return HttpResponse(build_diff_fragment(request, file, chunkindex, highlighting, collapseall, context, template_name)) raise UserVisibleError( _(u"Internal error. Unable to locate file record for filediff %s") % \ filediff.id) except Exception, e: return exception_traceback(request, e, template_name, {'standalone': True})
def get_context_data(self, diffset, interdiffset, extra_context={}, **kwargs): """Calculates and returns data used for rendering the diff viewer. This handles all the hard work of generating the data backing the side-by-side diff, handling pagination, and more. The data is collected into a context dictionary and returned for rendering. """ files = get_diff_files(diffset, None, interdiffset, request=self.request) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get('diffviewer_paginate_by'), siteconfig.get('diffviewer_paginate_orphans')) page_num = int(self.request.GET.get('page', 1)) if self.request.GET.get('file', False): file_id = int(self.request.GET['file']) for i, f in enumerate(files): if f['filediff'].pk == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) return dict( { 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), 'files': page.object_list, 'collapseall': self.collapse_diffs, # Add the pagination context 'is_paginated': page.has_other_pages(), 'page': page.number, 'pages': paginator.num_pages, 'page_numbers': paginator.page_range, 'has_next': page.has_next(), 'next_page': page.next_page_number(), 'has_previous': page.has_previous(), 'previous_page': page.previous_page_number(), 'page_start_index': page.start_index(), }, **extra_context)
def add_urls_from_datagrid(urls, datagrid, view, group=None): datagrid.load_state() datagrid_params = "view=%s" % view if group: datagrid_params += "&group=%s" % group datagrid_url = "%s%s?%s" % (url_prefix, reverse("dashboard"), datagrid_params) urls.append({"url": datagrid_url, "matchQuery": {"hasAll": datagrid_params}}) highlighting = get_enable_highlighting(request.user) for obj_info in datagrid.rows: review_request = obj_info["object"] assert isinstance(review_request, ReviewRequest) if review_request.id in found_review_requests: continue found_review_requests[review_request.id] = True # Grab the latest activity timestamp. # TODO: Make this common between here and review_detail. timestamp = get_last_activity_timestamp(review_request) if not info["latest_timestamp"] or timestamp > info["latest_timestamp"]: info["latest_timestamp"] = timestamp urls.append({"url": url_prefix + review_request.get_absolute_url()}) try: diffset = review_request.diffset_history.diffsets.latest() view_diff_url = url_prefix + reverse("view_diff", args=[review_request.id]) urls += [{"url": view_diff_url}, {"url": url_prefix + reverse("raw_diff", args=[review_request.id])}] files = get_diff_files(diffset, None, None, highlighting, False) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator( files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans") ) for pagenum in paginator.page_range: urls.append({"url": "%s?page=%d" % (view_diff_url, pagenum)}) except DiffSet.DoesNotExist: pass for screenshot in review_request.screenshots.all(): urls += [ {"url": url_prefix + screenshot.get_absolute_url()}, {"url": url_prefix + screenshot.image.url}, {"url": url_prefix + screenshot.get_thumbnail_url()}, ]
def get_context_data(self, diffset, interdiffset, extra_context={}, **kwargs): """Calculates and returns data used for rendering the diff viewer. This handles all the hard work of generating the data backing the side-by-side diff, handling pagination, and more. The data is collected into a context dictionary and returned for rendering. """ files = get_diff_files(diffset, None, interdiffset, request=self.request) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get('diffviewer_paginate_by'), siteconfig.get('diffviewer_paginate_orphans')) page_num = int(self.request.GET.get('page', 1)) if self.request.GET.get('file', False): file_id = int(self.request.GET['file']) for i, f in enumerate(files): if f['filediff'].pk == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) return dict({ 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), 'files': page.object_list, 'collapseall': self.collapse_diffs, # Add the pagination context 'is_paginated': page.has_other_pages(), 'page': page.number, 'pages': paginator.num_pages, 'page_numbers': paginator.page_range, 'has_next': page.has_next(), 'next_page': page.next_page_number(), 'has_previous': page.has_previous(), 'previous_page': page.previous_page_number(), 'page_start_index': page.start_index(), }, **extra_context)
def get_requested_diff_file(get_chunks=True): files = get_diff_files(diffset, filediff, interdiffset, highlighting, get_chunks) if files: assert len(files) == 1 file = files[0] if "index" in request.GET: file["index"] = request.GET.get("index") return file return None
def get_requested_diff_file(get_chunks=True): files = get_diff_files(diffset, filediff, interdiffset, highlighting, get_chunks) if files: assert len(files) == 1 file = files[0] if 'index' in request.GET: file['index'] = request.GET.get('index') return file return None
def _get_requested_diff_file(self, diffset, filediff, interdiffset, interfilediff): """Fetches information on the requested diff. This will look up information on the diff that's to be rendered and return it, if found. It may also augment it with additional data. The file will not contain chunk information. That must be specifically populated later. """ base_commit_id = None base_commit = None if diffset.commit_count > 0 and not interdiffset: raw_base_commit_id = self.request.GET.get('base-commit-id') if raw_base_commit_id is not None: try: base_commit_id = int(raw_base_commit_id) except ValueError: pass base_commit, tip_commit = get_base_and_tip_commits( base_commit_id=base_commit_id, tip_commit_id=None, diffset=diffset) # The tip commit is not required since we are requesting get_diff_files # with a FileDiff. files = get_diff_files(diffset=diffset, interdiffset=interdiffset, filediff=filediff, interfilediff=interfilediff, request=self.request, base_commit=base_commit) if files: diff_file = files[0] try: diff_file['index'] = int(self.request.GET['index']) except (KeyError, ValueError): pass return diff_file return None
def get_requested_diff_file(get_chunks=True): files = get_diff_files(diffset, filediff, interdiffset) if get_chunks: populate_diff_chunks(files, highlighting) if files: assert len(files) == 1 file = files[0] if 'index' in request.GET: file['index'] = request.GET.get('index') return file return None
def _get_diff_data(self, request, mimetype, *args, **kwargs): try: resources.review_request.get_object(request, *args, **kwargs) filediff = self.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST highlighting = request.GET.get('syntax-highlighting', False) files = get_diff_files(diffset=filediff.diffset, filediff=filediff, request=request) populate_diff_chunks(files, highlighting, request=request) if not files: # This may not be the right error here. return DOES_NOT_EXIST assert len(files) == 1 f = files[0] payload = { 'diff_data': { 'binary': f['binary'], 'chunks': f['chunks'], 'num_changes': f['num_changes'], 'changed_chunk_indexes': f['changed_chunk_indexes'], 'new_file': f['newfile'], } } # XXX: Kind of a hack. api_format = mimetype.split('+')[-1] resp = WebAPIResponse(request, payload, api_format=api_format) set_last_modified(resp, filediff.diffset.timestamp) return resp
def view_diff(request, diffset_id, interdiffset_id=None, extra_context={}, template_name='diffviewer/view_diff.html'): #import dbgp.client #dbgp.client.brk(port=9004) diffset = get_object_or_404(DiffSet, pk=diffset_id) interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id) highlighting = get_enable_highlighting(request.user) try: if interdiffset_id: logging.debug("Generating diff viewer page for interdiffset ids " "%s-%s", diffset_id, interdiffset_id) else: logging.debug("Generating diff viewer page for filediff id %s", diffset_id) files = get_diff_files(diffset, None, interdiffset, highlighting) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans")) page_num = int(request.GET.get('page', 1)) if request.GET.get('file', False): file_id = int(request.GET['file']) for i, f in enumerate(files): if f['filediff'].id == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) if request.GET.get('expand', False): collapseall = False elif request.GET.get('collapse', False): collapseall = True elif request.COOKIES.has_key('collapsediffs'): collapseall = (request.COOKIES['collapsediffs'] == "True") else: collapseall = True context = { 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), } context.update(extra_context) # XXX We can probably make this even more awesome and completely skip # the get_diff_files call, caching basically the entire context. for file in page.object_list: file['fragment'] = mark_safe(build_diff_fragment(request, file, None, highlighting, collapseall, context)) context['files'] = page.object_list # Add the pagination context context['is_paginated'] = page.has_other_pages() context['page'] = page.number context['pages'] = paginator.num_pages context['page_numbers'] = paginator.page_range context['has_next'] = page.has_next() context['next_page'] = page.next_page_number() context['has_previous'] = page.has_previous() context['previous_page'] = page.previous_page_number() context['page_start_index'] = page.start_index() response = render_to_response(template_name, RequestContext(request, context)) response.set_cookie('collapsediffs', collapseall) if interdiffset_id: logging.debug("Done generating diff viewer page for interdiffset " "ids %s-%s", diffset_id, interdiffset_id) else: logging.debug("Done generating diff viewer page for filediff " "id %s", diffset_id) return response except Exception, e: return exception_traceback(request, e, template_name)
def get_context_data(self, diffset, interdiffset, extra_context={}, **kwargs): """Calculates and returns data used for rendering the diff viewer. This handles all the hard work of generating the data backing the side-by-side diff, handling pagination, and more. The data is collected into a context dictionary and returned for rendering. """ try: filename_patterns = \ re.split(',+\s*', self.request.GET['filenames'].strip()) except KeyError: filename_patterns = [] files = get_diff_files(diffset=diffset, interdiffset=interdiffset, request=self.request, filename_patterns=filename_patterns) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get('diffviewer_paginate_by'), siteconfig.get('diffviewer_paginate_orphans')) page_num = int(self.request.GET.get('page', 1)) if self.request.GET.get('file', False): file_id = int(self.request.GET['file']) for i, f in enumerate(files): if f['filediff'].pk == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break try: page = paginator.page(page_num) except InvalidPage: page = paginator.page(paginator.num_pages) diff_context = { 'filename_patterns': list(filename_patterns), 'revision': { 'revision': diffset.revision, 'is_interdiff': interdiffset is not None, 'interdiff_revision': (interdiffset.revision if interdiffset else None), }, 'pagination': { 'is_paginated': page.has_other_pages(), 'current_page': page.number, 'pages': paginator.num_pages, 'page_numbers': paginator.page_range, 'has_next': page.has_next(), 'has_previous': page.has_previous(), }, } if page.has_next(): diff_context['pagination']['next_page'] = page.next_page_number() if page.has_previous(): diff_context['pagination']['previous_page'] = \ page.previous_page_number() context = dict( { 'diff_context': diff_context, 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), 'files': page.object_list, 'collapseall': self.collapse_diffs, }, **extra_context) return context
def view_diff(request, diffset_id, interdiffset_id=None, extra_context={}, template_name="diffviewer/view_diff.html"): diffset = get_object_or_404(DiffSet, pk=diffset_id) interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id) highlighting = get_enable_highlighting(request.user) try: if interdiffset_id: logging.debug("Generating diff viewer page for interdiffset ids " "%s-%s", diffset_id, interdiffset_id) else: logging.debug("Generating diff viewer page for filediff id %s", diffset_id) files = get_diff_files(diffset, None, interdiffset, highlighting, False) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator( files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans") ) page_num = int(request.GET.get("page", 1)) if request.GET.get("file", False): file_id = int(request.GET["file"]) for i, f in enumerate(files): if f["filediff"].id == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) collapse_diffs = get_collapse_diff(request) context = { "diffset": diffset, "interdiffset": interdiffset, "diffset_pair": (diffset, interdiffset), "files": page.object_list, "collapseall": collapse_diffs, # Add the pagination context "is_paginated": page.has_other_pages(), "page": page.number, "pages": paginator.num_pages, "page_numbers": paginator.page_range, "has_next": page.has_next(), "next_page": page.next_page_number(), "has_previous": page.has_previous(), "previous_page": page.previous_page_number(), "page_start_index": page.start_index(), } context.update(extra_context) # Attempt to preload the first file before rendering any part of # the page. This helps to remove the perception that the diff viewer # takes longer to load now that we have progressive diffs. Users were # seeing the page itself load quickly, but didn't see that first # diff immediately and instead saw a spinner, making them feel it was # taking longer than it used to to load a page. We just trick the # user by providing that first file. if page.object_list: first_file = page.object_list[0] else: first_file = None if first_file: filediff = first_file["filediff"] if filediff.diffset == interdiffset: temp_files = get_diff_files(interdiffset, filediff, None, highlighting, True) else: temp_files = get_diff_files(diffset, filediff, interdiffset, highlighting, True) if temp_files: file_temp = temp_files[0] file_temp["index"] = first_file["index"] first_file["fragment"] = build_diff_fragment( request, file_temp, None, highlighting, collapse_diffs, context, "diffviewer/diff_file_fragment.html", ) response = render_to_response(template_name, RequestContext(request, context)) response.set_cookie("collapsediffs", collapse_diffs) if interdiffset_id: logging.debug("Done generating diff viewer page for interdiffset " "ids %s-%s", diffset_id, interdiffset_id) else: logging.debug("Done generating diff viewer page for filediff " "id %s", diffset_id) return response except Exception, e: return exception_traceback(request, e, template_name)
def get_context_data(self, diffset, interdiffset, extra_context={}, **kwargs): """Calculates and returns data used for rendering the diff viewer. This handles all the hard work of generating the data backing the side-by-side diff, handling pagination, and more. The data is collected into a context dictionary and returned for rendering. """ try: filename_patterns = \ re.split(',+\s*', self.request.GET['filenames'].strip()) except KeyError: filename_patterns = [] files = get_diff_files(diffset=diffset, interdiffset=interdiffset, request=self.request, filename_patterns=filename_patterns) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get('diffviewer_paginate_by'), siteconfig.get('diffviewer_paginate_orphans')) page_num = int(self.request.GET.get('page', 1)) if self.request.GET.get('file', False): file_id = int(self.request.GET['file']) for i, f in enumerate(files): if f['filediff'].pk == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break try: page = paginator.page(page_num) except InvalidPage: page = paginator.page(paginator.num_pages) diff_context = { 'filename_patterns': list(filename_patterns), 'revision': { 'revision': diffset.revision, 'is_interdiff': interdiffset is not None, 'interdiff_revision': (interdiffset.revision if interdiffset else None), }, 'pagination': { 'is_paginated': page.has_other_pages(), 'current_page': page.number, 'pages': paginator.num_pages, 'page_numbers': paginator.page_range, 'has_next': page.has_next(), 'has_previous': page.has_previous(), }, } if page.has_next(): diff_context['pagination']['next_page'] = page.next_page_number() if page.has_previous(): diff_context['pagination']['previous_page'] = \ page.previous_page_number() context = dict({ 'diff_context': diff_context, 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), 'files': page.object_list, 'collapseall': self.collapse_diffs, }, **extra_context) return context
def get_context_data(self, diffset, interdiffset, extra_context={}, **kwargs): """Calculates and returns data used for rendering the diff viewer. This handles all the hard work of generating the data backing the side-by-side diff, handling pagination, and more. The data is collected into a context dictionary and returned for rendering. """ try: filename_patterns = \ re.split(',+\s*', self.request.GET['filenames'].strip()) except KeyError: filename_patterns = [] base_commit_id = None base_commit = None tip_commit_id = None tip_commit = None commits_by_diffset_id = {} if diffset.commit_count > 0: diffset_pks = [diffset.pk] if interdiffset: diffset_pks.append(interdiffset.pk) commits = DiffCommit.objects.filter(diffset_id__in=diffset_pks) for commit in commits: commits_by_diffset_id.setdefault(commit.diffset_id, []).append( commit) # Base and tip commit selection is not supported in interdiffs. if not interdiffset: raw_base_commit_id = self.request.GET.get('base-commit-id') raw_tip_commit_id = self.request.GET.get('tip-commit-id') if raw_base_commit_id is not None: try: base_commit_id = int(raw_base_commit_id) except ValueError: pass if raw_tip_commit_id is not None: try: tip_commit_id = int(raw_tip_commit_id) except ValueError: pass base_commit, tip_commit = get_base_and_tip_commits( base_commit_id, tip_commit_id, commits=commits_by_diffset_id[diffset.pk]) files = get_diff_files(diffset=diffset, interdiffset=interdiffset, request=self.request, filename_patterns=filename_patterns, base_commit=base_commit, tip_commit=tip_commit) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get('diffviewer_paginate_by'), siteconfig.get('diffviewer_paginate_orphans')) page_num = int(self.request.GET.get('page', 1)) if self.request.GET.get('file', False): file_id = int(self.request.GET['file']) for i, f in enumerate(files): if f['filediff'].pk == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break try: page = paginator.page(page_num) except InvalidPage: page = paginator.page(paginator.num_pages) diff_context = { 'commits': None, 'commit_history_diff': None, 'filename_patterns': list(filename_patterns), 'revision': { 'revision': diffset.revision, 'is_interdiff': interdiffset is not None, 'interdiff_revision': (interdiffset.revision if interdiffset else None), }, 'pagination': { 'is_paginated': page.has_other_pages(), 'current_page': page.number, 'pages': paginator.num_pages, 'page_numbers': paginator.page_range, 'has_next': page.has_next(), 'has_previous': page.has_previous(), }, } if page.has_next(): diff_context['pagination']['next_page'] = page.next_page_number() if page.has_previous(): diff_context['pagination']['previous_page'] = \ page.previous_page_number() if diffset.commit_count > 0: if interdiffset: diff_context['commit_history_diff'] = [ entry.serialize() for entry in diff_histories( commits_by_diffset_id[diffset.pk], commits_by_diffset_id[interdiffset.pk]) ] all_commits = [ commit for pk in commits_by_diffset_id for commit in commits_by_diffset_id[pk] ] diff_context['commits'] = [ commit.serialize() for commit in sorted(all_commits, key=lambda commit: commit.pk) ] revision_context = diff_context['revision'] revision_context.update({ 'base_commit_id': base_commit_id, 'tip_commit_id': tip_commit_id, }) context = dict({ 'diff_context': diff_context, 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), 'files': page.object_list, 'collapseall': self.collapse_diffs, }, **extra_context) return context
def get_file_chunks_in_range_custom(context, filediff, interfilediff, first_line, num_lines): """ A generator that yields chunks within a range of lines in the specified filediff/interfilediff. This function was mostly copied from the Review Board source code. The main modification is to always set syntax highlighting to False so that plain code is returned in the chunks instead of html. This is primarily intended for use with templates. It takes a RequestContext for looking up the user and for caching file lists, in order to improve performance and reduce lookup times for files that have already been fetched. Each returned chunk is a dictionary with the following fields: ============= ======================================================== Variable Description ============= ======================================================== ``change`` The change type ("equal", "replace", "insert", "delete") ``numlines`` The number of lines in the chunk. ``lines`` The list of lines in the chunk. ``meta`` A dictionary containing metadata on the chunk ============= ======================================================== Each line in the list of lines is an array with the following data: ======== ============================================================= Index Description ======== ============================================================= 0 Virtual line number (union of the original and patched files) 1 Real line number in the original file 2 HTML markup of the original file 3 Changed regions of the original line (for "replace" chunks) 4 Real line number in the patched file 5 HTML markup of the patched file 6 Changed regions of the patched line (for "replace" chunks) 7 True if line consists of only whitespace changes ======== ============================================================= """ def find_header(headers): for header in reversed(headers): if header[0] < first_line: return { 'line': header[0], 'text': header[1], } interdiffset = None key = "_diff_files_%s_%s" % (filediff.diffset.id, filediff.id) if interfilediff: key += "_%s" % (interfilediff.id) interdiffset = interfilediff.diffset if key in context: files = context[key] else: assert 'user' in context request = context.get('request', None) files = get_diff_files(filediff.diffset, filediff, interdiffset, request=request) populate_diff_chunks(files, False, request=request) context[key] = files if not files: raise StopIteration assert len(files) == 1 last_header = [None, None] for chunk in files[0]['chunks']: if ('headers' in chunk['meta'] and (chunk['meta']['headers'][0] or chunk['meta']['headers'][1])): last_header = chunk['meta']['headers'] lines = chunk['lines'] if lines[-1][0] >= first_line >= lines[0][0]: start_index = first_line - lines[0][0] if first_line + num_lines <= lines[-1][0]: last_index = start_index + num_lines else: last_index = len(lines) new_chunk = { 'lines': chunk['lines'][start_index:last_index], 'numlines': last_index - start_index, 'change': chunk['change'], 'meta': chunk.get('meta', {}), } if 'left_headers' in chunk['meta']: left_header = find_header(chunk['meta']['left_headers']) right_header = find_header(chunk['meta']['right_headers']) del new_chunk['meta']['left_headers'] del new_chunk['meta']['right_headers'] if left_header or right_header: header = (left_header, right_header) else: header = last_header new_chunk['meta']['headers'] = header yield new_chunk first_line += new_chunk['numlines'] num_lines -= new_chunk['numlines'] assert num_lines >= 0 if num_lines == 0: break
def get_context_data(self, diffset, interdiffset, extra_context={}, **kwargs): """Calculates and returns data used for rendering the diff viewer. This handles all the hard work of generating the data backing the side-by-side diff, handling pagination, and more. The data is collected into a context dictionary and returned for rendering. """ files = get_diff_files(diffset, None, interdiffset, request=self.request) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator( files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans") ) page_num = int(self.request.GET.get("page", 1)) if self.request.GET.get("file", False): file_id = int(self.request.GET["file"]) for i, f in enumerate(files): if f["filediff"].pk == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break try: page = paginator.page(page_num) except InvalidPage: page = paginator.page(paginator.num_pages) diff_context = { "revision": { "revision": diffset.revision, "is_interdiff": interdiffset is not None, "interdiff_revision": (interdiffset.revision if interdiffset else None), }, "pagination": { "is_paginated": page.has_other_pages(), "current_page": page.number, "pages": paginator.num_pages, "page_numbers": paginator.page_range, "has_next": page.has_next(), "has_previous": page.has_previous(), }, } if page.has_next(): diff_context["pagination"]["next_page"] = page.next_page_number() if page.has_previous(): diff_context["pagination"]["previous_page"] = page.previous_page_number() context = dict( { "diff_context": diff_context, "diffset": diffset, "interdiffset": interdiffset, "diffset_pair": (diffset, interdiffset), "files": page.object_list, "collapseall": self.collapse_diffs, }, **extra_context ) return context
def view_diff(request, diffset, interdiffset=None, extra_context={}, template_name='diffviewer/view_diff.html'): highlighting = get_enable_highlighting(request.user) try: if interdiffset: logging.debug("Generating diff viewer page for interdiffset ids " "%s-%s", diffset.id, interdiffset.id, request=request) else: logging.debug("Generating diff viewer page for filediff id %s", diffset.id, request=request) files = get_diff_files(diffset, None, interdiffset, request=request) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans")) page_num = int(request.GET.get('page', 1)) if request.GET.get('file', False): file_id = int(request.GET['file']) for i, f in enumerate(files): if f['filediff'].id == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) collapse_diffs = get_collapse_diff(request) context = { 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), 'files': page.object_list, 'collapseall': collapse_diffs, # Add the pagination context 'is_paginated': page.has_other_pages(), 'page': page.number, 'pages': paginator.num_pages, 'page_numbers': paginator.page_range, 'has_next': page.has_next(), 'next_page': page.next_page_number(), 'has_previous': page.has_previous(), 'previous_page': page.previous_page_number(), 'page_start_index': page.start_index(), } context.update(extra_context) # Attempt to preload the first file before rendering any part of # the page. This helps to remove the perception that the diff viewer # takes longer to load now that we have progressive diffs. Users were # seeing the page itself load quickly, but didn't see that first # diff immediately and instead saw a spinner, making them feel it was # taking longer than it used to to load a page. We just trick the # user by providing that first file. if page.object_list: first_file = page.object_list[0] else: first_file = None if first_file: filediff = first_file['filediff'] if filediff.diffset == interdiffset: temp_files = get_diff_files(interdiffset, filediff, None, request=request) else: temp_files = get_diff_files(diffset, filediff, interdiffset, request=request) if temp_files: try: populate_diff_chunks(temp_files, highlighting, request=request) except Exception, e: file_temp = temp_files[0] file_temp['index'] = first_file['index'] first_file['fragment'] = \ exception_traceback(request, e, 'diffviewer/diff_fragment_error.html', extra_context={'file': file_temp}) else: file_temp = temp_files[0] file_temp['index'] = first_file['index'] first_file['fragment'] = build_diff_fragment( request, file_temp, None, highlighting, collapse_diffs, None, context=context, template_name='diffviewer/diff_file_fragment.html') response = render_to_response(template_name, RequestContext(request, context)) response.set_cookie('collapsediffs', collapse_diffs) if interdiffset: logging.debug("Done generating diff viewer page for interdiffset " "ids %s-%s", diffset.id, interdiffset.id, request=request) else: logging.debug("Done generating diff viewer page for filediff " "id %s", diffset.id, request=request) return response
def view_diff(request, diffset_id, interdiffset_id=None, extra_context={}, template_name='diffviewer/view_diff.html'): #import dbgp.client #dbgp.client.brk(port=9004) diffset = get_object_or_404(DiffSet, pk=diffset_id) interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id) highlighting = get_enable_highlighting(request.user) try: if interdiffset_id: logging.debug( "Generating diff viewer page for interdiffset ids " "%s-%s", diffset_id, interdiffset_id) else: logging.debug("Generating diff viewer page for filediff id %s", diffset_id) files = get_diff_files(diffset, None, interdiffset, highlighting) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans")) page_num = int(request.GET.get('page', 1)) if request.GET.get('file', False): file_id = int(request.GET['file']) for i, f in enumerate(files): if f['filediff'].id == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) if request.GET.get('expand', False): collapseall = False elif request.GET.get('collapse', False): collapseall = True elif request.COOKIES.has_key('collapsediffs'): collapseall = (request.COOKIES['collapsediffs'] == "True") else: collapseall = True context = { 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), } context.update(extra_context) # XXX We can probably make this even more awesome and completely skip # the get_diff_files call, caching basically the entire context. for file in page.object_list: file['fragment'] = mark_safe( build_diff_fragment(request, file, None, highlighting, collapseall, context)) context['files'] = page.object_list # Add the pagination context context['is_paginated'] = page.has_other_pages() context['page'] = page.number context['pages'] = paginator.num_pages context['page_numbers'] = paginator.page_range context['has_next'] = page.has_next() context['next_page'] = page.next_page_number() context['has_previous'] = page.has_previous() context['previous_page'] = page.previous_page_number() context['page_start_index'] = page.start_index() response = render_to_response(template_name, RequestContext(request, context)) response.set_cookie('collapsediffs', collapseall) if interdiffset_id: logging.debug( "Done generating diff viewer page for interdiffset " "ids %s-%s", diffset_id, interdiffset_id) else: logging.debug( "Done generating diff viewer page for filediff " "id %s", diffset_id) return response except Exception, e: return exception_traceback(request, e, template_name)