def __init__(self, diff_file, chunk_index=None, highlighting=False, collapse_all=True, lines_of_context=None, extra_context=None, allow_caching=True, template_name='diffviewer/diff_file_fragment.html'): self.diff_file = diff_file self.chunk_index = chunk_index self.highlighting = highlighting self.collapse_all = collapse_all self.lines_of_context = lines_of_context self.extra_context = extra_context or {} self.allow_caching = allow_caching self.template_name = template_name if self.lines_of_context and len(self.lines_of_context) == 1: # If we only have one value, then assume it represents before # and after the collapsed header area. self.lines_of_context.append(self.lines_of_context[0]) if self.chunk_index is not None: assert not self.lines_of_context or self.collapse_all self.num_chunks = len(self.diff_file['chunks']) if self.chunk_index < 0 or self.chunk_index >= self.num_chunks: raise UserVisibleError( _('Invalid chunk index %s specified.') % self.chunk_index)
def render_to_string_uncached(self, request): """Renders a diff to a string without caching. This is a potentially expensive operation, and so is meant to be called only as often as necessary. render_to_string will call this if it's not already in the cache. """ if not self.diff_file.get('chunks_loaded', False): populate_diff_chunks([self.diff_file], self.highlighting, request=request) if self.chunk_index is not None: assert not self.lines_of_context or self.collapse_all self.num_chunks = len(self.diff_file['chunks']) if self.chunk_index < 0 or self.chunk_index >= self.num_chunks: raise UserVisibleError( _('Invalid chunk index %s specified.') % self.chunk_index) return render_to_string(template_name=self.template_name, context=self.make_context())
def process_diffset_info(self, diffset_or_id, filediff_id, interfilediff_id=None, interdiffset_or_id=None, **kwargs): """Process and return information on the desired diff. The diff IDs and other data passed to the view can be processed and converted into DiffSets. A dictionary with the DiffSet and FileDiff information will be returned. A subclass may instead return a HttpResponse to indicate an error with the DiffSets. """ # Depending on whether we're invoked from a URL or from a wrapper # with precomputed diffsets, we may be working with either IDs or # actual objects. If they're objects, just use them as-is. Otherwise, # if they're IDs, we want to grab them both (if both are provided) # in one go, to save on an SQL query. diffset = None interdiffset = None diffset_ids = [] if isinstance(diffset_or_id, DiffSet): diffset = diffset_or_id else: diffset_ids.append(diffset_or_id) if interdiffset_or_id: if isinstance(interdiffset_or_id, DiffSet): interdiffset = interdiffset_or_id else: diffset_ids.append(interdiffset_or_id) if diffset_ids: diffsets = DiffSet.objects.filter(pk__in=diffset_ids) if len(diffsets) != len(diffset_ids): raise Http404 for temp_diffset in diffsets: if temp_diffset.pk == diffset_or_id: diffset = temp_diffset elif temp_diffset.pk == interdiffset_or_id: interdiffset = temp_diffset else: assert False filediff = get_object_or_404(FileDiff, pk=filediff_id, diffset=diffset) if interfilediff_id: interfilediff = get_object_or_404(FileDiff, pk=interfilediff_id, diffset=interdiffset) else: interfilediff = None # Store this so we don't end up causing an SQL query later when looking # this up. filediff.diffset = diffset diff_file = self._get_requested_diff_file(diffset, filediff, interdiffset, interfilediff) if not diff_file: raise UserVisibleError( _('Internal error. Unable to locate file record for ' 'filediff %s') % filediff.pk) return { 'diffset': diffset, 'interdiffset': interdiffset, 'filediff': filediff, 'diff_file': diff_file, }
def view_diff_fragment( request, diffset_or_id, filediff_id, base_url, interdiffset_or_id=None, chunkindex=None, template_name='diffviewer/diff_file_fragment.html', error_template_name='diffviewer/diff_fragment_error.html'): """View which renders a specific fragment from a diff.""" def get_requested_diff_file(get_chunks=True): files = get_diff_files(diffset, filediff, interdiffset, request=request) if get_chunks: populate_diff_chunks(files, highlighting, request=request) if files: assert len(files) == 1 file = files[0] if 'index' in request.GET: file['index'] = request.GET.get('index') return file return None # Depending on whether we're invoked from a URL or from a wrapper # with precomputed diffsets, we may be working with either IDs or # actual objects. If they're objects, just use them as-is. Otherwise, # if they're IDs, we want to grab them both (if both are provided) # in one go, to save on an SQL query. diffset_ids = [] diffset = None interdiffset = None if isinstance(diffset_or_id, DiffSet): diffset = diffset_or_id else: diffset_ids.append(diffset_or_id) if interdiffset_or_id: if isinstance(interdiffset_or_id, DiffSet): interdiffset = interdiffset_or_id else: diffset_ids.append(interdiffset_or_id) if diffset_ids: diffsets = DiffSet.objects.filter(pk__in=diffset_ids) if len(diffsets) != len(diffset_ids): raise Http404 for temp_diffset in diffsets: if temp_diffset.pk == diffset_or_id: diffset = temp_diffset elif temp_diffset.pk == interdiffset_or_id: interdiffset = temp_diffset else: assert False filediff = get_object_or_404(FileDiff, pk=filediff_id, diffset=diffset) # Store this so we don't end up causing an SQL query later when looking # this up. filediff.diffset = diffset highlighting = get_enable_highlighting(request.user) try: lines_of_context = request.GET.get('lines-of-context', '') lines_of_context = [int(i) for i in lines_of_context.split(',', 1)] except (TypeError, ValueError): lines_of_context = None if chunkindex is not None: try: chunkindex = int(chunkindex) except (TypeError, ValueError): chunkindex = None if lines_of_context: collapseall = True elif chunkindex: # If we're currently expanding part of a chunk, we want to render # the entire chunk without any lines collapsed. In the case of showing # a range of lines, we're going to get all chunks and then only show # the range. This is so that we won't have separate cached entries for # each range. collapseall = False else: collapseall = get_collapse_diff(request) try: diff_file = get_requested_diff_file() if diff_file: renderer = get_diff_renderer(diff_file, chunk_index=chunkindex, highlighting=highlighting, collapse_all=collapseall, lines_of_context=lines_of_context, extra_context={ 'base_url': base_url, }, template_name=template_name) return renderer.render_to_response() raise UserVisibleError( _(u"Internal error. Unable to locate file record for filediff %s") % filediff.id) except Exception, e: return exception_traceback( request, e, error_template_name, extra_context={'file': get_requested_diff_file(False)})
def create_renderer(self, context, diffset_or_id, filediff_id, interdiffset_or_id=None, chunkindex=None, *args, **kwargs): """Creates the renderer for the diff. This calculates all the state and data needed for rendering, and constructs a DiffRenderer with that data. That renderer is then returned, ready for rendering. If there's an error in looking up the necessary information, this may raise a UserVisibleError (best case), or some other form of Exception. """ # Depending on whether we're invoked from a URL or from a wrapper # with precomputed diffsets, we may be working with either IDs or # actual objects. If they're objects, just use them as-is. Otherwise, # if they're IDs, we want to grab them both (if both are provided) # in one go, to save on an SQL query. self.diffset = None self.interdiffset = None diffset_ids = [] if isinstance(diffset_or_id, DiffSet): self.diffset = diffset_or_id else: diffset_ids.append(diffset_or_id) if interdiffset_or_id: if isinstance(interdiffset_or_id, DiffSet): self.interdiffset = interdiffset_or_id else: diffset_ids.append(interdiffset_or_id) if diffset_ids: diffsets = DiffSet.objects.filter(pk__in=diffset_ids) if len(diffsets) != len(diffset_ids): raise Http404 for temp_diffset in diffsets: if temp_diffset.pk == diffset_or_id: self.diffset = temp_diffset elif temp_diffset.pk == interdiffset_or_id: self.interdiffset = temp_diffset else: assert False self.highlighting = get_enable_highlighting(self.request.user) self.filediff = get_object_or_404(FileDiff, pk=filediff_id, diffset=self.diffset) # Store this so we don't end up causing an SQL query later when looking # this up. self.filediff.diffset = self.diffset try: lines_of_context = self.request.GET.get('lines-of-context', '') lines_of_context = [int(i) for i in lines_of_context.split(',', 1)] except (TypeError, ValueError): lines_of_context = None if chunkindex is not None: try: chunkindex = int(chunkindex) except (TypeError, ValueError): chunkindex = None if lines_of_context: collapseall = True elif chunkindex is not None: # If we're currently expanding part of a chunk, we want to render # the entire chunk without any lines collapsed. In the case of showing # a range of lines, we're going to get all chunks and then only show # the range. This is so that we won't have separate cached entries for # each range. collapseall = False else: collapseall = get_collapse_diff(self.request) self.diff_file = self._get_requested_diff_file() if not self.diff_file: raise UserVisibleError( _('Internal error. Unable to locate file record for ' 'filediff %s') % self.filediff.pk) return get_diff_renderer(self.diff_file, chunk_index=chunkindex, highlighting=self.highlighting, collapse_all=collapseall, lines_of_context=lines_of_context, extra_context=context, template_name=self.template_name)