예제 #1
0
    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)
예제 #2
0
    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())
예제 #3
0
    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,
        }
예제 #4
0
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)})
예제 #5
0
    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)