예제 #1
0
    def get_chunks_uncached(self):
        """Yield the list of chunks, bypassing the cache."""
        old = get_original_file(self.filediff, self.request, self.encoding_list)
        new = get_patched_file(old, self.filediff, self.request)

        if self.filediff.orig_sha1 is None:
            self.filediff.extra_data.update(
                {"orig_sha1": self._get_checksum(old), "patched_sha1": self._get_checksum(new)}
            )
            self.filediff.save(update_fields=["extra_data"])

        if self.interfilediff:
            old = new
            interdiff_orig = get_original_file(self.interfilediff, self.request, self.encoding_list)
            new = get_patched_file(interdiff_orig, self.interfilediff, self.request)

            if self.interfilediff.orig_sha1 is None:
                self.interfilediff.extra_data.update(
                    {"orig_sha1": self._get_checksum(interdiff_orig), "patched_sha1": self._get_checksum(new)}
                )
                self.interfilediff.save(update_fields=["extra_data"])
        elif self.force_interdiff:
            # Basically, revert the change.
            old, new = new, old

        if self.interfilediff:
            log_timer = log_timed(
                "Generating diff chunks for interdiff ids %s-%s (%s)"
                % (self.filediff.id, self.interfilediff.id, self.filediff.source_file),
                request=self.request,
            )
        else:
            log_timer = log_timed(
                "Generating diff chunks for self.filediff id %s (%s)" % (self.filediff.id, self.filediff.source_file),
                request=self.request,
            )

        for chunk in self.generate_chunks(old, new):
            yield chunk

        log_timer.done()

        if not self.interfilediff and not self.force_interdiff:
            insert_count = self.counts["insert"]
            delete_count = self.counts["delete"]
            replace_count = self.counts["replace"]
            equal_count = self.counts["equal"]

            self.filediff.set_line_counts(
                insert_count=insert_count,
                delete_count=delete_count,
                replace_count=replace_count,
                equal_count=equal_count,
                total_line_count=(insert_count + delete_count + replace_count + equal_count),
            )
예제 #2
0
    def get(self, request, *args, **kwargs):
        """Returns the patched file.

        The file is returned as :mimetype:`text/plain` and is the result
        of applying the patch to the original file.
        """
        result = self.get_filediff(request, *args, **kwargs)

        if isinstance(result, FileDiff):
            filediff = result
        elif isinstance(result, WebAPIError):
            return result
        else:
            raise ValueError('Unexpected result from get_filediff')

        if filediff.deleted:
            return DOES_NOT_EXIST

        try:
            orig_file = get_original_file(filediff=filediff, request=request)
        except Exception as e:
            logging.error(
                '%s: Error retrieving original file for FileDiff '
                '%s: %s',
                self.__class__.__name__,
                filediff.pk,
                e,
                exc_info=1,
                request=request)
            return FILE_RETRIEVAL_ERROR

        try:
            patched_file = get_patched_file(source_data=orig_file,
                                            filediff=filediff,
                                            request=request)
        except Exception as e:
            logging.error(
                '%s: Error retrieving patched file for FileDiff '
                '%s: %s',
                self.__class__.__name__,
                filediff.pk,
                e,
                exc_info=1,
                request=request)
            return FILE_RETRIEVAL_ERROR

        resp = HttpResponse(patched_file, content_type='text/plain')
        filename = urllib_quote(filediff.dest_file)
        resp['Content-Disposition'] = 'inline; filename=%s' % filename
        set_last_modified(resp, filediff.diffset.timestamp)

        return resp
예제 #3
0
    def get(self, request, diffset_id=None, *args, **kwargs):
        """Returns the patched file.

        The file is returned as :mimetype:`text/plain` and is the result
        of applying the patch to the original file.
        """
        try:
            attached_diffset = DiffSet.objects.filter(pk=diffset_id,
                                                      history__isnull=True)

            if attached_diffset.exists():
                filediff_resource = resources.filediff
            else:
                filediff_resource = resources.draft_filediff

            filediff = filediff_resource.get_object(request,
                                                    diffset=diffset_id,
                                                    *args,
                                                    **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if filediff.deleted:
            return DOES_NOT_EXIST

        try:
            orig_file = get_original_file(
                filediff, request,
                filediff.diffset.repository.get_encoding_list())
        except Exception as e:
            logging.error("Error retrieving original file: %s",
                          e,
                          exc_info=1,
                          request=request)
            return FILE_RETRIEVAL_ERROR

        try:
            patched_file = get_patched_file(orig_file, filediff, request)
        except Exception as e:
            logging.error("Error retrieving patched file: %s",
                          e,
                          exc_info=1,
                          request=request)
            return FILE_RETRIEVAL_ERROR

        resp = HttpResponse(patched_file, mimetype='text/plain')
        filename = urllib_quote(filediff.dest_file)
        resp['Content-Disposition'] = 'inline; filename=%s' % filename
        set_last_modified(resp, filediff.diffset.timestamp)

        return resp
예제 #4
0
    def get(self, request, *args, **kwargs):
        """Returns the patched file.

        The file is returned as :mimetype:`text/plain` and is the result
        of applying the patch to the original file.
        """
        result = self.get_filediff(request, *args, **kwargs)

        if isinstance(result, FileDiff):
            filediff = result
        elif isinstance(result, WebAPIError):
            return result
        else:
            raise ValueError("Unexpected result from get_filediff")

        if filediff.deleted:
            return DOES_NOT_EXIST

        try:
            orig_file = get_original_file(filediff, request, filediff.diffset.repository.get_encoding_list())
        except Exception as e:
            logging.error(
                "%s: Error retrieving original file for FileDiff " "%s: %s",
                self.__class__.__name__,
                filediff.pk,
                e,
                exc_info=1,
                request=request,
            )
            return FILE_RETRIEVAL_ERROR

        try:
            patched_file = get_patched_file(orig_file, filediff, request)
        except Exception as e:
            logging.error(
                "%s: Error retrieving patched file for FileDiff %" "%s: %s",
                self.__class__.__name__,
                filediff.pk,
                e,
                exc_info=1,
                request=request,
            )
            return FILE_RETRIEVAL_ERROR

        resp = HttpResponse(patched_file, content_type="text/plain")
        filename = urllib_quote(filediff.dest_file)
        resp["Content-Disposition"] = "inline; filename=%s" % filename
        set_last_modified(resp, filediff.diffset.timestamp)

        return resp
예제 #5
0
    def get(self, request, diffset_id=None, *args, **kwargs):
        """Returns the patched file.

        The file is returned as :mimetype:`text/plain` and is the result
        of applying the patch to the original file.
        """
        try:
            attached_diffset = DiffSet.objects.filter(pk=diffset_id,
                                                      history__isnull=True)

            if attached_diffset.exists():
                filediff_resource = resources.filediff
            else:
                filediff_resource = resources.draft_filediff

            filediff = filediff_resource.get_object(
                request, diffset=diffset_id, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if filediff.deleted:
            return DOES_NOT_EXIST

        try:
            orig_file = get_original_file(
                filediff, request,
                filediff.diffset.repository.get_encoding_list())
        except Exception as e:
            logging.error("Error retrieving original file: %s", e, exc_info=1,
                          request=request)
            return FILE_RETRIEVAL_ERROR

        try:
            patched_file = get_patched_file(orig_file, filediff, request)
        except Exception as e:
            logging.error("Error retrieving patched file: %s", e, exc_info=1,
                          request=request)
            return FILE_RETRIEVAL_ERROR

        resp = HttpResponse(patched_file, mimetype='text/plain')
        filename = urllib_quote(filediff.dest_file)
        resp['Content-Disposition'] = 'inline; filename=%s' % filename
        set_last_modified(resp, filediff.diffset.timestamp)

        return resp
예제 #6
0
class PatchedFileResource(WebAPIResource):
    """Provides the patched file corresponding to a file diff."""
    name = 'patched_file'
    singleton = True
    allowed_item_mimetypes = ['text/plain']

    @webapi_check_login_required
    def get(self, request, *args, **kwargs):
        """Returns the patched file.

        The file is returned as :mimetype:`text/plain` and is the result
        of applying the patch to the original file.
        """
        try:
            filediff = resources.filediff.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if filediff.deleted:
            return DOES_NOT_EXIST

        try:
            orig_file = get_original_file(filediff, request=request)
        except Exception, e:
            logging.error("Error retrieving original file: %s",
                          e,
                          exc_info=1,
                          request=request)
            return FILE_RETRIEVAL_ERROR

        try:
            patched_file = get_patched_file(orig_file,
                                            filediff,
                                            request=request)
        except Exception, e:
            logging.error("Error retrieving patched file: %s",
                          e,
                          exc_info=1,
                          request=request)
            return FILE_RETRIEVAL_ERROR
예제 #7
0
    def _get_chunks_uncached(self):
        """Returns the list of chunks, bypassing the cache."""
        old = get_original_file(self.filediff, self.request)
        new = get_patched_file(old, self.filediff, self.request)

        if self.interfilediff:
            old = new
            interdiff_orig = get_original_file(self.interfilediff,
                                               self.request)
            new = get_patched_file(interdiff_orig, self.interfilediff,
                                   self.request)
        elif self.force_interdiff:
            # Basically, revert the change.
            old, new = new, old

        encoding = self.diffset.repository.encoding or 'iso-8859-15'
        old = self._convert_to_utf8(old, encoding)
        new = self._convert_to_utf8(new, encoding)

        # Normalize the input so that if there isn't a trailing newline, we add
        # it.
        if old and old[-1] != '\n':
            old += '\n'

        if new and new[-1] != '\n':
            new += '\n'

        a = self.NEWLINES_RE.split(old or '')
        b = self.NEWLINES_RE.split(new or '')

        # Remove the trailing newline, now that we've split this. This will
        # prevent a duplicate line number at the end of the diff.
        del a[-1]
        del b[-1]

        a_num_lines = len(a)
        b_num_lines = len(b)

        markup_a = markup_b = None

        if self._get_enable_syntax_highlighting(old, new, a, b):
            repository = self.filediff.diffset.repository
            tool = repository.get_scmtool()
            source_file = \
                tool.normalize_path_for_display(self.filediff.source_file)
            dest_file = \
                tool.normalize_path_for_display(self.filediff.dest_file)

            try:
                # TODO: Try to figure out the right lexer for these files
                #       once instead of twice.
                markup_a = self._apply_pygments(old or '', source_file)
                markup_b = self._apply_pygments(new or '', dest_file)
            except:
                pass

        if not markup_a:
            markup_a = self.NEWLINES_RE.split(escape(old))

        if not markup_b:
            markup_b = self.NEWLINES_RE.split(escape(new))

        siteconfig = SiteConfiguration.objects.get_current()
        ignore_space = True

        for pattern in siteconfig.get('diffviewer_include_space_patterns'):
            if fnmatch.fnmatch(self.filename, pattern):
                ignore_space = False
                break

        self.differ = get_differ(a, b, ignore_space=ignore_space,
                                 compat_version=self.diffset.diffcompat)
        self.differ.add_interesting_lines_for_headers(self.filename)

        context_num_lines = siteconfig.get("diffviewer_context_num_lines")
        collapse_threshold = 2 * context_num_lines + 3

        if self.interfilediff:
            log_timer = log_timed(
                "Generating diff chunks for interdiff ids %s-%s (%s)" %
                (self.filediff.id, self.interfilediff.id,
                 self.filediff.source_file),
                request=self.request)
        else:
            log_timer = log_timed(
                "Generating diff chunks for self.filediff id %s (%s)" %
                (self.filediff.id, self.filediff.source_file),
                request=self.request)

        line_num = 1
        opcodes_generator = get_diff_opcode_generator(self.differ,
                                                      self.filediff,
                                                      self.interfilediff)

        for tag, i1, i2, j1, j2, meta in opcodes_generator:
            old_lines = markup_a[i1:i2]
            new_lines = markup_b[j1:j2]
            num_lines = max(len(old_lines), len(new_lines))

            self._cur_meta = meta
            lines = map(self._diff_line,
                        range(line_num, line_num + num_lines),
                        range(i1 + 1, i2 + 1), range(j1 + 1, j2 + 1),
                        a[i1:i2], b[j1:j2], old_lines, new_lines)
            self._cur_meta = None

            if tag == 'equal' and num_lines > collapse_threshold:
                last_range_start = num_lines - context_num_lines

                if line_num == 1:
                    yield self._new_chunk(lines, 0, last_range_start, True)
                    yield self._new_chunk(lines, last_range_start, num_lines)
                else:
                    yield self._new_chunk(lines, 0, context_num_lines)

                    if i2 == a_num_lines and j2 == b_num_lines:
                        yield self._new_chunk(lines, context_num_lines,
                                              num_lines, True)
                    else:
                        yield self._new_chunk(lines, context_num_lines,
                                              last_range_start, True)
                        yield self._new_chunk(lines, last_range_start,
                                              num_lines)
            else:
                yield self._new_chunk(lines, 0, num_lines, False, tag, meta)

            line_num += num_lines

        log_timer.done()
예제 #8
0
    def get_chunks_uncached(self):
        """Yield the list of chunks, bypassing the cache."""
        base_filediff = self.base_filediff
        filediff = self.filediff
        interfilediff = self.interfilediff
        request = self.request

        old = get_original_file(filediff=filediff, request=request)
        new = get_patched_file(source_data=old,
                               filediff=filediff,
                               request=request)

        old_encoding_list = get_filediff_encodings(filediff)
        new_encoding_list = old_encoding_list

        if base_filediff is not None:
            # The diff is against a commit that:
            #
            # 1. Follows the first commit in a series (the first won't have
            #    a base_commit/base_filediff that can be looked up)
            #
            # 2. Follows a commit that modifies this file, or is the base
            #    commit that modifies this file.
            #
            # We'll be diffing against the patched version of this commit's
            # version of the file.
            old = get_original_file(filediff=base_filediff, request=request)
            old = get_patched_file(source_data=old,
                                   filediff=base_filediff,
                                   request=request)
            old_encoding_list = get_filediff_encodings(base_filediff)
        elif filediff.commit_id:
            # This diff is against a commit, but no previous FileDiff
            # modifying this file could be found. As per the above comment,
            # this could end up being the very first commit in a series, or
            # it might not have been modified in the base commit or any
            # previous commit.
            #
            # We'll need to fetch the first ancestor of this file in the
            # commit history, if we can find one. We'll base the "old" version
            # of the file on the original version of this commit, meaning that
            # this commit and all modifications since will be shown as "new".
            # Basically, viewing the upstream of the file, before any commits.
            #
            # This should be safe because, without a base_filediff, there
            # should be no older commit containing modifications that we want
            # to diff against. This would be the first one, and we're using
            # its upstream changes.
            ancestors = filediff.get_ancestors(minimal=True)

            if ancestors:
                ancestor_filediff = ancestors[0]
                old = get_original_file(filediff=ancestor_filediff,
                                        request=request)
                old_encoding_list = get_filediff_encodings(ancestor_filediff)

        # Check whether we have a SHA256 checksum first. They were introduced
        # in Review Board 4.0, long after SHA1 checksums. If we already have
        # a SHA256 checksum, then we'll also have a SHA1 checksum, but the
        # inverse is not true.
        if filediff.orig_sha256 is None:
            if filediff.orig_sha1 is None:
                filediff.extra_data.update({
                    'orig_sha1': self._get_sha1(old),
                    'patched_sha1': self._get_sha1(new),
                })

            filediff.extra_data.update({
                'orig_sha256': self._get_sha256(old),
                'patched_sha256': self._get_sha256(new),
            })
            filediff.save(update_fields=['extra_data'])

        if interfilediff:
            old = new
            old_encoding_list = new_encoding_list

            interdiff_orig = get_original_file(filediff=interfilediff,
                                               request=request)
            new = get_patched_file(source_data=interdiff_orig,
                                   filediff=interfilediff,
                                   request=request)
            new_encoding_list = get_filediff_encodings(interfilediff)

            # Check whether we have a SHA256 checksum first. They were
            # introduced in Review Board 4.0, long after SHA1 checksums. If we
            # already have a SHA256 checksum, then we'll also have a SHA1
            # checksum, but the inverse is not true.
            if interfilediff.orig_sha256 is None:
                if interfilediff.orig_sha1 is None:
                    interfilediff.extra_data.update({
                        'orig_sha1':
                        self._get_sha1(interdiff_orig),
                        'patched_sha1':
                        self._get_sha1(new),
                    })

                interfilediff.extra_data.update({
                    'orig_sha256':
                    self._get_sha256(interdiff_orig),
                    'patched_sha256':
                    self._get_sha256(new),
                })
                interfilediff.save(update_fields=['extra_data'])
        elif self.force_interdiff:
            # Basically, revert the change.
            old, new = new, old
            old_encoding_list, new_encoding_list = \
                new_encoding_list, old_encoding_list

        if interfilediff:
            log_timer = log_timed(
                "Generating diff chunks for interdiff ids %s-%s (%s)" %
                (filediff.id, interfilediff.id, filediff.source_file),
                request=request)
        else:
            log_timer = log_timed(
                "Generating diff chunks for filediff id %s (%s)" %
                (filediff.id, filediff.source_file),
                request=request)

        for chunk in self.generate_chunks(old=old,
                                          new=new,
                                          old_encoding_list=old_encoding_list,
                                          new_encoding_list=new_encoding_list):
            yield chunk

        log_timer.done()

        if (not interfilediff and not self.base_filediff
                and not self.force_interdiff):
            insert_count = self.counts['insert']
            delete_count = self.counts['delete']
            replace_count = self.counts['replace']
            equal_count = self.counts['equal']

            filediff.set_line_counts(
                insert_count=insert_count,
                delete_count=delete_count,
                replace_count=replace_count,
                equal_count=equal_count,
                total_line_count=(insert_count + delete_count + replace_count +
                                  equal_count))
예제 #9
0
    def _get_chunks_uncached(self):
        """Returns the list of chunks, bypassing the cache."""
        old = get_original_file(self.filediff, self.request)
        new = get_patched_file(old, self.filediff, self.request)

        if self.interfilediff:
            old = new
            interdiff_orig = get_original_file(self.interfilediff,
                                               self.request)
            new = get_patched_file(interdiff_orig, self.interfilediff,
                                   self.request)
        elif self.force_interdiff:
            # Basically, revert the change.
            old, new = new, old

        encoding = self.diffset.repository.encoding or 'iso-8859-15'
        old = self._convert_to_utf8(old, encoding)
        new = self._convert_to_utf8(new, encoding)

        # Normalize the input so that if there isn't a trailing newline, we add
        # it.
        if old and old[-1] != '\n':
            old += '\n'

        if new and new[-1] != '\n':
            new += '\n'

        a = self.NEWLINES_RE.split(old or '')
        b = self.NEWLINES_RE.split(new or '')

        # Remove the trailing newline, now that we've split this. This will
        # prevent a duplicate line number at the end of the diff.
        del a[-1]
        del b[-1]

        a_num_lines = len(a)
        b_num_lines = len(b)

        markup_a = markup_b = None

        if self._get_enable_syntax_highlighting(old, new, a, b):
            repository = self.filediff.diffset.repository
            tool = repository.get_scmtool()
            source_file = \
                tool.normalize_path_for_display(self.filediff.source_file)
            dest_file = \
                tool.normalize_path_for_display(self.filediff.dest_file)

            try:
                # TODO: Try to figure out the right lexer for these files
                #       once instead of twice.
                markup_a = self._apply_pygments(old or '', source_file)
                markup_b = self._apply_pygments(new or '', dest_file)
            except:
                pass

        if not markup_a:
            markup_a = self.NEWLINES_RE.split(escape(old))

        if not markup_b:
            markup_b = self.NEWLINES_RE.split(escape(new))

        siteconfig = SiteConfiguration.objects.get_current()
        ignore_space = True

        for pattern in siteconfig.get('diffviewer_include_space_patterns'):
            if fnmatch.fnmatch(self.filename, pattern):
                ignore_space = False
                break

        self.differ = get_differ(a,
                                 b,
                                 ignore_space=ignore_space,
                                 compat_version=self.diffset.diffcompat)
        self.differ.add_interesting_lines_for_headers(self.filename)

        context_num_lines = siteconfig.get("diffviewer_context_num_lines")
        collapse_threshold = 2 * context_num_lines + 3

        if self.interfilediff:
            log_timer = log_timed(
                "Generating diff chunks for interdiff ids %s-%s (%s)" %
                (self.filediff.id, self.interfilediff.id,
                 self.filediff.source_file),
                request=self.request)
        else:
            log_timer = log_timed(
                "Generating diff chunks for self.filediff id %s (%s)" %
                (self.filediff.id, self.filediff.source_file),
                request=self.request)

        line_num = 1
        opcodes_generator = get_diff_opcode_generator(self.differ,
                                                      self.filediff,
                                                      self.interfilediff)

        for tag, i1, i2, j1, j2, meta in opcodes_generator:
            old_lines = markup_a[i1:i2]
            new_lines = markup_b[j1:j2]
            num_lines = max(len(old_lines), len(new_lines))

            self._cur_meta = meta
            lines = map(self._diff_line, xrange(line_num,
                                                line_num + num_lines),
                        xrange(i1 + 1, i2 + 1), xrange(j1 + 1, j2 + 1),
                        a[i1:i2], b[j1:j2], old_lines, new_lines)
            self._cur_meta = None

            if tag == 'equal' and num_lines > collapse_threshold:
                last_range_start = num_lines - context_num_lines

                if line_num == 1:
                    yield self._new_chunk(lines, 0, last_range_start, True)
                    yield self._new_chunk(lines, last_range_start, num_lines)
                else:
                    yield self._new_chunk(lines, 0, context_num_lines)

                    if i2 == a_num_lines and j2 == b_num_lines:
                        yield self._new_chunk(lines, context_num_lines,
                                              num_lines, True)
                    else:
                        yield self._new_chunk(lines, context_num_lines,
                                              last_range_start, True)
                        yield self._new_chunk(lines, last_range_start,
                                              num_lines)
            else:
                yield self._new_chunk(lines, 0, num_lines, False, tag, meta)

            line_num += num_lines

        log_timer.done()
예제 #10
0
    def get_chunks_uncached(self):
        """Yield the list of chunks, bypassing the cache."""
        old = get_original_file(self.filediff, self.request,
                                self.encoding_list)
        new = get_patched_file(old, self.filediff, self.request)

        if self.filediff.orig_sha1 is None:
            self.filediff.extra_data.update({
                'orig_sha1':
                self._get_checksum(old),
                'patched_sha1':
                self._get_checksum(new),
            })
            self.filediff.save(update_fields=['extra_data'])

        if self.interfilediff:
            old = new
            interdiff_orig = get_original_file(self.interfilediff,
                                               self.request,
                                               self.encoding_list)
            new = get_patched_file(interdiff_orig, self.interfilediff,
                                   self.request)

            if self.interfilediff.orig_sha1 is None:
                self.interfilediff.extra_data.update({
                    'orig_sha1':
                    self._get_checksum(interdiff_orig),
                    'patched_sha1':
                    self._get_checksum(new),
                })
                self.interfilediff.save(update_fields=['extra_data'])
        elif self.force_interdiff:
            # Basically, revert the change.
            old, new = new, old

        if self.interfilediff:
            log_timer = log_timed(
                "Generating diff chunks for interdiff ids %s-%s (%s)" %
                (self.filediff.id, self.interfilediff.id,
                 self.filediff.source_file),
                request=self.request)
        else:
            log_timer = log_timed(
                "Generating diff chunks for self.filediff id %s (%s)" %
                (self.filediff.id, self.filediff.source_file),
                request=self.request)

        for chunk in self.generate_chunks(old, new):
            yield chunk

        log_timer.done()

        if not self.interfilediff:
            insert_count = self.counts['insert']
            delete_count = self.counts['delete']
            replace_count = self.counts['replace']
            equal_count = self.counts['equal']

            self.filediff.set_line_counts(
                insert_count=insert_count,
                delete_count=delete_count,
                replace_count=replace_count,
                equal_count=equal_count,
                total_line_count=(insert_count + delete_count + replace_count +
                                  equal_count))
예제 #11
0
    def test_create_with_parent_filediff_with_move_and_change(self):
        """Testing UploadDiffForm.create with a parent diff consisting of a
        move/rename with content change
        """
        revisions = [
            b'93e6b3e8944c48737cb11a1e52b046fa30aea7a9',
            b'4839fc480f47ca59cf05a9c39410ea744d1e17a2',
            b'04861c126cfebd7e7cb93045ab0bff4a7acc4cf2',
        ]

        parent_diff = SimpleUploadedFile('parent_diff',
                                         (b'diff --git a/foo b/bar\n'
                                          b'similarity index 55%%\n'
                                          b'rename from foo\n'
                                          b'rename to bar\n'
                                          b'index %s..%s 100644\n'
                                          b'--- a/foo\n'
                                          b'+++ b/bar\n'
                                          b'@@ -1,2 +1,3 @@\n'
                                          b' Foo\n'
                                          b'+Bar\n') %
                                         (revisions[0], revisions[1]),
                                         content_type='text/x-patch')

        diff = SimpleUploadedFile('diff',
                                  (b'diff --git a/bar b/bar\n'
                                   b'index %s..%s 100644\n'
                                   b'--- a/bar\n'
                                   b'+++ b/bar\n'
                                   b'@@ -1,3 +1,4 @@\n'
                                   b' Foo\n'
                                   b' Bar\n'
                                   b'+Baz\n') % (revisions[1], revisions[2]),
                                  content_type='text/x-patch')

        repository = self.create_repository(tool_name='Test')
        self.spy_on(repository.get_file_exists,
                    call_fake=lambda *args, **kwargs: True)

        # We will only be making one call to get_file and we can fake it out.
        self.spy_on(repository.get_file,
                    call_fake=lambda *args, **kwargs: b'Foo\n')
        self.spy_on(patch)

        form = UploadDiffForm(repository=repository,
                              data={
                                  'basedir': '/',
                              },
                              files={
                                  'path': diff,
                                  'parent_diff_path': parent_diff,
                              })
        self.assertTrue(form.is_valid())

        diffset = form.create()
        self.assertEqual(diffset.files.count(), 1)

        f = diffset.files.get()
        self.assertEqual(f.source_revision, revisions[0])
        self.assertEqual(f.dest_detail, revisions[2])

        original_file = get_original_file(f, None, ['ascii'])
        self.assertEqual(original_file, b'Foo\nBar\n')
        self.assertTrue(patch.spy.called)

        patched_file = get_patched_file(original_file, f, None)
        self.assertEqual(patched_file, b'Foo\nBar\nBaz\n')
        self.assertEqual(len(patch.spy.calls), 2)
예제 #12
0
    def test_create_with_parent_filediff_with_move_and_no_change(self):
        """Testing UploadDiffForm.create with a parent diff consisting only
        of a move/rename without content change
        """
        revisions = [
            b'93e6b3e8944c48737cb11a1e52b046fa30aea7a9',
            b'4839fc480f47ca59cf05a9c39410ea744d1e17a2',
        ]

        parent_diff = SimpleUploadedFile('parent_diff',
                                         (b'diff --git a/foo b/bar\n'
                                          b'similarity index 100%%\n'
                                          b'rename from foo\n'
                                          b'rename to bar\n'),
                                         content_type='text/x-patch')

        diff = SimpleUploadedFile('diff',
                                  (b'diff --git a/bar b/bar\n'
                                   b'index %s..%s 100644\n'
                                   b'--- a/bar\n'
                                   b'+++ b/bar\n'
                                   b'@@ -1,2 +1,3 @@\n'
                                   b' Foo\n'
                                   b'+Bar\n') % (revisions[0], revisions[1]),
                                  content_type='text/x-patch')

        repository = self.create_repository(tool_name='Test')
        self.spy_on(repository.get_file_exists,
                    call_fake=lambda *args, **kwargs: True)

        # We will only be making one call to get_file and we can fake it out.
        self.spy_on(repository.get_file,
                    call_fake=lambda *args, **kwargs: b'Foo\n')
        self.spy_on(patch)

        form = UploadDiffForm(repository=repository,
                              data={
                                  'basedir': '/',
                              },
                              files={
                                  'path': diff,
                                  'parent_diff_path': parent_diff,
                              })
        self.assertTrue(form.is_valid())

        diffset = form.create()
        self.assertEqual(diffset.files.count(), 1)

        f = diffset.files.get()
        self.assertEqual(f.source_revision, revisions[0].decode('utf-8'))
        self.assertEqual(f.dest_detail, revisions[1].decode('utf-8'))

        # We shouldn't call out to patch because the parent diff is just a
        # rename.
        original_file = get_original_file(filediff=f,
                                          request=None,
                                          encoding_list=['ascii'])
        self.assertEqual(original_file, b'Foo\n')
        self.assertFalse(patch.spy.called)

        patched_file = get_patched_file(source_data=original_file, filediff=f)
        self.assertEqual(patched_file, b'Foo\nBar\n')
        self.assertTrue(patch.spy.called)
예제 #13
0
    def test_create_with_parent_filediff_with_new_file(self):
        """Testing UploadDiffForm.create with a parent diff consisting of a
        newly-introduced file
        """
        revisions = [
            b'0000000000000000000000000000000000000000',
            b'9b32edcd37a88c6ada91efc562afa637ccfdad36',
            b'8a567d328293f85d68332bc693b0a98869b23b47',
        ]

        parent_diff = SimpleUploadedFile('parent_diff',
                                         (b'diff --git a/foo b/foo\n'
                                          b'new file mode 100644\n'
                                          b'index %s..%s\n'
                                          b'--- /dev/null\n'
                                          b'+++ b/foo\n'
                                          b'@@ -0,0 +1,2 @@\n'
                                          b'+Foo\n'
                                          b'+Bar\n') %
                                         (revisions[0], revisions[1]),
                                         content_type='text/x-patch')

        diff = SimpleUploadedFile('diff',
                                  (b'diff --git a/foo b/foo\n'
                                   b'index %s..%s 100644\n'
                                   b'--- a/foo\n'
                                   b'+++ b/foo\n'
                                   b'@@ -1,3 +1,4 @@\n'
                                   b' Foo\n'
                                   b' Bar\n'
                                   b'+Baz\n') % (revisions[1], revisions[2]),
                                  content_type='text/x-patch')

        repository = self.create_repository(tool_name='Test')
        self.spy_on(repository.get_file_exists,
                    call_fake=lambda *args, **kwargs: True)

        # We will only be making one call to get_file and we can fake it out.
        self.spy_on(repository.get_file,
                    call_fake=lambda *args, **kwargs: b'Foo\n')
        self.spy_on(patch)

        form = UploadDiffForm(repository=repository,
                              data={
                                  'basedir': '/',
                              },
                              files={
                                  'parent_diff_path': parent_diff,
                                  'path': diff,
                              })
        self.assertTrue(form.is_valid())

        diffset = form.create()
        self.assertEqual(diffset.files.count(), 1)

        filediff = diffset.files.get()
        self.assertEqual(filediff.source_file, 'foo')
        self.assertEqual(filediff.dest_file, 'foo')
        self.assertEqual(filediff.source_revision,
                         revisions[1].decode('utf-8'))
        self.assertEqual(filediff.dest_detail, revisions[2].decode('utf-8'))
        self.assertEqual(
            filediff.extra_data, {
                '__parent_diff_empty': False,
                'is_symlink': False,
                'new_unix_mode': '100644',
                'old_unix_mode': '100644',
                'parent_source_filename': '/foo',
                'parent_source_revision': 'PRE-CREATION',
                'raw_delete_count': 0,
                'raw_insert_count': 1,
            })

        # Double-check the types.
        self.assertIsInstance(filediff.extra_data['parent_source_filename'],
                              str)
        self.assertIsInstance(filediff.extra_data['parent_source_revision'],
                              str)

        original_file = get_original_file(filediff=filediff,
                                          request=None,
                                          encoding_list=['ascii'])
        self.assertEqual(original_file, b'Foo\nBar\n')
        self.assertSpyCalled(patch)

        patched_file = get_patched_file(source_data=original_file,
                                        filediff=filediff)
        self.assertEqual(patched_file, b'Foo\nBar\nBaz\n')
        self.assertEqual(len(patch.calls), 2)
예제 #14
0
    def test_create_with_parent_filediff_with_move_and_change(self):
        """Testing UploadDiffForm.create with a parent diff consisting of a
        move/rename with content change
        """
        revisions = [
            b'5d36b88bb697a2d778f024048bafabd443d74503',
            b'9b32edcd37a88c6ada91efc562afa637ccfdad36',
            b'8a567d328293f85d68332bc693b0a98869b23b47',
        ]

        parent_diff = SimpleUploadedFile('parent_diff',
                                         (b'diff --git a/foo b/bar\n'
                                          b'similarity index 55%%\n'
                                          b'rename from foo\n'
                                          b'rename to bar\n'
                                          b'index %s..%s 100644\n'
                                          b'--- a/foo\n'
                                          b'+++ b/bar\n'
                                          b'@@ -1,2 +1,3 @@\n'
                                          b' Foo\n'
                                          b'+Bar\n') %
                                         (revisions[0], revisions[1]),
                                         content_type='text/x-patch')

        diff = SimpleUploadedFile('diff',
                                  (b'diff --git a/bar b/bar\n'
                                   b'index %s..%s 100644\n'
                                   b'--- a/bar\n'
                                   b'+++ b/bar\n'
                                   b'@@ -1,3 +1,4 @@\n'
                                   b' Foo\n'
                                   b' Bar\n'
                                   b'+Baz\n') % (revisions[1], revisions[2]),
                                  content_type='text/x-patch')

        repository = self.create_repository(tool_name='Test')
        self.spy_on(repository.get_file_exists,
                    call_fake=lambda *args, **kwargs: True)

        # We will only be making one call to get_file and we can fake it out.
        self.spy_on(repository.get_file,
                    call_fake=lambda *args, **kwargs: b'Foo\n')
        self.spy_on(patch)

        form = UploadDiffForm(repository=repository,
                              data={
                                  'basedir': '/',
                              },
                              files={
                                  'path': diff,
                                  'parent_diff_path': parent_diff,
                              })
        self.assertTrue(form.is_valid())

        diffset = form.create()
        self.assertEqual(diffset.files.count(), 1)

        filediff = diffset.files.get()
        self.assertEqual(filediff.source_file, 'bar')
        self.assertEqual(filediff.dest_file, 'bar')
        self.assertEqual(filediff.source_revision,
                         revisions[1].decode('utf-8'))
        self.assertEqual(filediff.dest_detail, revisions[2].decode('utf-8'))
        self.assertEqual(
            filediff.extra_data, {
                '__parent_diff_empty': False,
                'is_symlink': False,
                'new_unix_mode': '100644',
                'old_unix_mode': '100644',
                'parent_moved': True,
                'parent_source_filename': '/foo',
                'parent_source_revision': revisions[0].decode('utf-8'),
                'raw_delete_count': 0,
                'raw_insert_count': 1,
            })

        original_file = get_original_file(filediff=filediff,
                                          request=None,
                                          encoding_list=['ascii'])
        self.assertEqual(original_file, b'Foo\nBar\n')
        self.assertTrue(patch.spy.called)

        patched_file = get_patched_file(source_data=original_file,
                                        filediff=filediff)
        self.assertEqual(patched_file, b'Foo\nBar\nBaz\n')
        self.assertEqual(len(patch.spy.calls), 2)
예제 #15
0
    def get_chunks_uncached(self):
        """Yield the list of chunks, bypassing the cache."""
        old = get_original_file(self.filediff, self.request,
                                self.encoding_list)
        new = get_patched_file(old, self.filediff, self.request)

        if self.base_filediff is not None:
            # The diff is against a commit that:
            #
            # 1. Follows the first commit in a series (the first won't have
            #    a base_commit/base_filediff that can be looked up)
            #
            # 2. Follows a commit that modifies this file, or is the base
            #    commit that modifies this file.
            #
            # We'll be diffing against the patched version of this commit's
            # version of the file.
            old = get_original_file(self.base_filediff, self.request,
                                    self.encoding_list)
            old = get_patched_file(old, self.base_filediff, self.request)
        elif self.filediff.commit_id:
            # This diff is against a commit, but no previous FileDiff
            # modifying this file could be found. As per the above comment,
            # this could end up being the very first commit in a series, or
            # it might not have been modified in the base commit or any
            # previous commit.
            #
            # We'll need to fetch the first ancestor of this file in the
            # commit history, if we can find one. We'll base the "old" version
            # of the file on the original version of this commit, meaning that
            # this commit and all modifications since will be shown as "new".
            # Basically, viewing the upstream of the file, before any commits.
            #
            # This should be safe because, without a base_filediff, there
            # should be no older commit containing modifications that we want
            # to diff against. This would be the first one, and we're using
            # its upstream changes.
            ancestors = self.filediff.get_ancestors(minimal=True)

            if ancestors:
                old = get_original_file(ancestors[0],
                                        self.request,
                                        self.encoding_list)

        if self.filediff.orig_sha1 is None:
            self.filediff.extra_data.update({
                'orig_sha1': self._get_checksum(old),
                'patched_sha1': self._get_checksum(new),
            })
            self.filediff.save(update_fields=['extra_data'])

        if self.interfilediff:
            old = new
            interdiff_orig = get_original_file(self.interfilediff,
                                               self.request,
                                               self.encoding_list)
            new = get_patched_file(interdiff_orig, self.interfilediff,
                                   self.request)

            if self.interfilediff.orig_sha1 is None:
                self.interfilediff.extra_data.update({
                    'orig_sha1': self._get_checksum(interdiff_orig),
                    'patched_sha1': self._get_checksum(new),
                })
                self.interfilediff.save(update_fields=['extra_data'])
        elif self.force_interdiff:
            # Basically, revert the change.
            old, new = new, old

        if self.interfilediff:
            log_timer = log_timed(
                "Generating diff chunks for interdiff ids %s-%s (%s)" %
                (self.filediff.id, self.interfilediff.id,
                 self.filediff.source_file),
                request=self.request)
        else:
            log_timer = log_timed(
                "Generating diff chunks for self.filediff id %s (%s)" %
                (self.filediff.id, self.filediff.source_file),
                request=self.request)

        for chunk in self.generate_chunks(old, new):
            yield chunk

        log_timer.done()

        if (not self.interfilediff and
            not self.base_filediff and
            not self.force_interdiff):
            insert_count = self.counts['insert']
            delete_count = self.counts['delete']
            replace_count = self.counts['replace']
            equal_count = self.counts['equal']

            self.filediff.set_line_counts(
                insert_count=insert_count,
                delete_count=delete_count,
                replace_count=replace_count,
                equal_count=equal_count,
                total_line_count=(insert_count + delete_count +
                                  replace_count + equal_count))
예제 #16
0
    def test_create_with_parent_filediff_with_move_and_change(self):
        """Testing UploadDiffForm.create with a parent diff consisting of a
        move/rename with content change
        """
        revisions = [
            b'93e6b3e8944c48737cb11a1e52b046fa30aea7a9',
            b'4839fc480f47ca59cf05a9c39410ea744d1e17a2',
            b'04861c126cfebd7e7cb93045ab0bff4a7acc4cf2',
        ]

        parent_diff = SimpleUploadedFile(
            'parent_diff',
            (b'diff --git a/foo b/bar\n'
             b'similarity index 55%%\n'
             b'rename from foo\n'
             b'rename to bar\n'
             b'index %s..%s 100644\n'
             b'--- a/foo\n'
             b'+++ b/bar\n'
             b'@@ -1,2 +1,3 @@\n'
             b' Foo\n'
             b'+Bar\n') % (revisions[0], revisions[1]),
            content_type='text/x-patch')

        diff = SimpleUploadedFile(
            'diff',
            (b'diff --git a/bar b/bar\n'
             b'index %s..%s 100644\n'
             b'--- a/bar\n'
             b'+++ b/bar\n'
             b'@@ -1,3 +1,4 @@\n'
             b' Foo\n'
             b' Bar\n'
             b'+Baz\n') % (revisions[1], revisions[2]),
            content_type='text/x-patch')

        repository = self.create_repository(tool_name='Test')
        self.spy_on(repository.get_file_exists,
                    call_fake=lambda *args, **kwargs: True)

        # We will only be making one call to get_file and we can fake it out.
        self.spy_on(repository.get_file,
                    call_fake=lambda *args, **kwargs: b'Foo\n')
        self.spy_on(patch)

        form = UploadDiffForm(
            repository=repository,
            data={
                'basedir': '/',
            },
            files={
                'path': diff,
                'parent_diff_path': parent_diff,
            })
        self.assertTrue(form.is_valid())

        diffset = form.create()
        self.assertEqual(diffset.files.count(), 1)

        f = diffset.files.get()
        self.assertEqual(f.source_revision, revisions[0])
        self.assertEqual(f.dest_detail, revisions[2])

        original_file = get_original_file(f, None, ['ascii'])
        self.assertEqual(original_file, b'Foo\nBar\n')
        self.assertTrue(patch.spy.called)

        patched_file = get_patched_file(original_file, f, None)
        self.assertEqual(patched_file, b'Foo\nBar\nBaz\n')
        self.assertEqual(len(patch.spy.calls), 2)