Example #1
0
    def create(self, diff_file, parent_diff_file=None, diffset_history=None):
        tool = self.repository.get_scmtool()

        # Grab the base directory if there is one.
        if not tool.get_diffs_use_absolute_paths():
            try:
                basedir = smart_unicode(self.cleaned_data['basedir'])
            except AttributeError:
                raise NoBaseDirError(_('The "Base Diff Path" field is required'))
        else:
            basedir = ''

        # Parse the diff
        files = list(self._process_files(
            diff_file, basedir, check_existance=(parent_diff_file is not None)))

        if len(files) == 0:
            raise EmptyDiffError(_("The diff file is empty"))

        # Sort the files so that header files come before implementation.
        files.sort(cmp=self._compare_files, key=lambda f: f.origFile)

        # Parse the parent diff
        parent_files = {}

        if parent_diff_file:
            # If the user supplied a base diff, we need to parse it and
            # later apply each of the files that are in the main diff
            for f in self._process_files(parent_diff_file, basedir,
                                         check_existance=True):
                parent_files[f.origFile] = f

        diffset = DiffSet(name=diff_file.name, revision=0,
                          history=diffset_history,
                          diffcompat=DEFAULT_DIFF_COMPAT_VERSION)
        diffset.repository = self.repository
        diffset.save()

        for f in files:
            if f.origFile in parent_files:
                parent_file = parent_files[f.origFile]
                parent_content = parent_file.data
                source_rev = parent_file.origInfo
            else:
                parent_content = ""
                source_rev = f.origInfo

            dest_file = os.path.join(basedir, f.newFile).replace("\\", "/")

            filediff = FileDiff(diffset=diffset,
                                source_file=f.origFile,
                                dest_file=dest_file,
                                source_revision=smart_unicode(source_rev),
                                dest_detail=f.newInfo,
                                diff=f.data,
                                parent_diff=parent_content,
                                binary=f.binary)
            filediff.save()

        return diffset
Example #2
0
    def test_update_revision_from_history_with_revision_already_set(self):
        """Testing DiffSet.update_revision_from_history with revision
        already set
        """
        diffset_history = DiffSetHistory.objects.create()
        diffset = DiffSet(revision=1)

        with self.assertRaises(ValueError):
            diffset.update_revision_from_history(diffset_history)
Example #3
0
    def test_update_revision_from_history_with_revision_already_set(self):
        """Testing DiffSet.update_revision_from_history with revision
        already set
        """
        diffset_history = DiffSetHistory.objects.create()
        diffset = DiffSet(revision=1)

        with self.assertRaises(ValueError):
            diffset.update_revision_from_history(diffset_history)
Example #4
0
    def test_update_revision_from_history_without_diffsets(self):
        """Testing DiffSet.update_revision_from_history without existing
        diffsets
        """
        diffset_history = DiffSetHistory.objects.create()

        diffset = DiffSet()
        diffset.update_revision_from_history(diffset_history)

        self.assertEqual(diffset.revision, 1)
Example #5
0
    def test_update_revision_from_history_without_diffsets(self):
        """Testing DiffSet.update_revision_from_history without existing
        diffsets
        """
        diffset_history = DiffSetHistory.objects.create()

        diffset = DiffSet()
        diffset.update_revision_from_history(diffset_history)

        self.assertEqual(diffset.revision, 1)
Example #6
0
    def test_update_revision_from_history_with_diffsets(self):
        """Testing DiffSet.update_revision_from_history with existing diffsets
        """
        repository = self.create_repository(tool_name='Test')
        diffset_history = DiffSetHistory.objects.create()
        diffset_history.diffsets.add(
            self.create_diffset(repository=repository))

        diffset = DiffSet()
        diffset.update_revision_from_history(diffset_history)

        self.assertEqual(diffset.revision, 2)
Example #7
0
    def test_update_revision_from_history_with_diffsets(self):
        """Testing DiffSet.update_revision_from_history with existing diffsets
        """
        repository = self.create_repository(tool_name='Test')
        diffset_history = DiffSetHistory.objects.create()
        diffset_history.diffsets.add(
            self.create_diffset(repository=repository))

        diffset = DiffSet()
        diffset.update_revision_from_history(diffset_history)

        self.assertEqual(diffset.revision, 2)
Example #8
0
    def test_get_line_changed_regions(self):
        """Testing DiffChunkGenerator._get_line_changed_regions"""
        def deep_equal(A, B):
            typea, typeb = type(A), type(B)
            self.assertEqual(typea, typeb)
            if typea is tuple or typea is list:
                for a, b in zip_longest(A, B):
                    deep_equal(a, b)
            else:
                self.assertEqual(A, B)

        filediff = FileDiff(source_file='foo', diffset=DiffSet())
        generator = DiffChunkGenerator(None, filediff)

        deep_equal(generator._get_line_changed_regions(None, None),
                   (None, None))

        old = 'submitter = models.ForeignKey(Person, verbose_name="Submitter")'
        new = 'submitter = models.ForeignKey(User, verbose_name="Submitter")'
        regions = generator._get_line_changed_regions(old, new)
        deep_equal(regions, ([(30, 36)], [(30, 34)]))

        old = '-from reviews.models import ReviewRequest, Person, Group'
        new = '+from .reviews.models import ReviewRequest, Group'
        regions = generator._get_line_changed_regions(old, new)
        deep_equal(regions, ([(0, 1), (6, 6), (43, 51)], [(0, 1), (6, 7),
                                                          (44, 44)]))

        old = 'abcdefghijklm'
        new = 'nopqrstuvwxyz'
        regions = generator._get_line_changed_regions(old, new)
        deep_equal(regions, (None, None))
Example #9
0
    def create(self, diff_file, parent_diff_file=None, diffset_history=None):
        tool = self.repository.get_scmtool()

        siteconfig = SiteConfiguration.objects.get_current()
        max_diff_size = siteconfig.get('diffviewer_max_diff_size')

        if max_diff_size > 0:
            if diff_file.size > max_diff_size:
                raise DiffTooBigError(_('The supplied diff file is too large'),
                                      max_diff_size=max_diff_size)

            if parent_diff_file and parent_diff_file.size > max_diff_size:
                raise DiffTooBigError(
                    _('The supplied parent diff file is too large'),
                    max_diff_size=max_diff_size)

        # Grab the base directory if there is one.
        if not tool.get_diffs_use_absolute_paths():
            try:
                basedir = smart_unicode(self.cleaned_data['basedir'].strip())
            except AttributeError:
                raise NoBaseDirError(
                    _('The "Base Diff Path" field is required'))
        else:
            basedir = ''

        # Parse the diff
        files = list(
            self._process_files(diff_file,
                                basedir,
                                check_existance=(not parent_diff_file)))

        if len(files) == 0:
            raise EmptyDiffError(_("The diff file is empty"))

        # Sort the files so that header files come before implementation.
        files.sort(cmp=self._compare_files, key=lambda f: f.origFile)

        # Parse the parent diff
        parent_files = {}

        # This is used only for tools like Mercurial that use atomic changeset
        # IDs to identify all file versions but not individual file version
        # IDs.
        parent_changeset_id = None

        if parent_diff_file:
            diff_filenames = set([f.origFile for f in files])

            # If the user supplied a base diff, we need to parse it and
            # later apply each of the files that are in the main diff
            for f in self._process_files(parent_diff_file,
                                         basedir,
                                         check_existance=True,
                                         limit_to=diff_filenames):
                parent_files[f.origFile] = f

                # Store the original changeset ID if we have it; this should
                # be the same for all files.
                if f.origChangesetId:
                    parent_changeset_id = f.origChangesetId

        diffset = DiffSet(name=diff_file.name,
                          revision=0,
                          basedir=basedir,
                          history=diffset_history,
                          diffcompat=DEFAULT_DIFF_COMPAT_VERSION)
        diffset.repository = self.repository
        diffset.save()

        for f in files:
            if f.origFile in parent_files:
                parent_file = parent_files[f.origFile]
                parent_content = parent_file.data
                source_rev = parent_file.origInfo
            else:
                parent_content = ""

                if (tool.diff_uses_changeset_ids and parent_changeset_id
                        and f.origInfo != PRE_CREATION):
                    source_rev = parent_changeset_id
                else:
                    source_rev = f.origInfo

            dest_file = os.path.join(basedir, f.newFile).replace("\\", "/")

            if f.deleted:
                status = FileDiff.DELETED
            elif f.moved:
                status = FileDiff.MOVED
            else:
                status = FileDiff.MODIFIED

            filediff = FileDiff(diffset=diffset,
                                source_file=f.origFile,
                                dest_file=dest_file,
                                source_revision=smart_unicode(source_rev),
                                dest_detail=f.newInfo,
                                diff=f.data,
                                parent_diff=parent_content,
                                binary=f.binary,
                                status=status)
            filediff.set_line_counts(f.insert_count, f.delete_count)
            filediff.save()

        return diffset
Example #10
0
    def create(self, diff_file, parent_diff_file=None, diffset_history=None):
        tool = self.repository.get_scmtool()

        siteconfig = SiteConfiguration.objects.get_current()
        max_diff_size = siteconfig.get('diffviewer_max_diff_size')

        if max_diff_size > 0:
            if diff_file.size > max_diff_size:
                raise DiffTooBigError(
                    _('The supplied diff file is too large'),
                    max_diff_size=max_diff_size)

            if parent_diff_file and parent_diff_file.size > max_diff_size:
                raise DiffTooBigError(
                    _('The supplied parent diff file is too large'),
                    max_diff_size=max_diff_size)

        # Grab the base directory if there is one.
        if not tool.get_diffs_use_absolute_paths():
            try:
                basedir = smart_unicode(self.cleaned_data['basedir'].strip())
            except AttributeError:
                raise NoBaseDirError(
                    _('The "Base Diff Path" field is required'))
        else:
            basedir = ''

        # Parse the diff
        files = list(self._process_files(
            diff_file, basedir, check_existance=(not parent_diff_file)))

        if len(files) == 0:
            raise EmptyDiffError(_("The diff file is empty"))

        # Sort the files so that header files come before implementation.
        files.sort(cmp=self._compare_files, key=lambda f: f.origFile)

        # Parse the parent diff
        parent_files = {}

        # This is used only for tools like Mercurial that use atomic changeset
        # IDs to identify all file versions but not individual file version
        # IDs.
        parent_changeset_id = None

        if parent_diff_file:
            # If the user supplied a base diff, we need to parse it and
            # later apply each of the files that are in the main diff
            for f in self._process_files(parent_diff_file, basedir,
                                         check_existance=True):
                parent_files[f.origFile] = f

                # Store the original changeset ID if we have it; this should
                # be the same for all files.
                if f.origChangesetId:
                    parent_changeset_id = f.origChangesetId

        diffset = DiffSet(name=diff_file.name, revision=0,
                          basedir=basedir,
                          history=diffset_history,
                          diffcompat=DEFAULT_DIFF_COMPAT_VERSION)
        diffset.repository = self.repository
        diffset.save()

        for f in files:
            if f.origFile in parent_files:
                parent_file = parent_files[f.origFile]
                parent_content = parent_file.data
                source_rev = parent_file.origInfo
            else:
                parent_content = ""

                if (tool.diff_uses_changeset_ids and
                    parent_changeset_id and
                    f.origInfo != PRE_CREATION):
                    source_rev = parent_changeset_id
                else:
                    source_rev = f.origInfo

            dest_file = os.path.join(basedir, f.newFile).replace("\\", "/")

            if f.deleted:
                status = FileDiff.DELETED
            elif f.moved:
                status = FileDiff.MOVED
            else:
                status = FileDiff.MODIFIED

            filediff = FileDiff(diffset=diffset,
                                source_file=f.origFile,
                                dest_file=dest_file,
                                source_revision=smart_unicode(source_rev),
                                dest_detail=f.newInfo,
                                diff=f.data,
                                parent_diff=parent_content,
                                binary=f.binary,
                                status=status)
            filediff.save()

        return diffset
Example #11
0
    def validate_diff(self):
        """Validate the DiffCommit.

        This will attempt to parse the given diff (and optionally parent
        diff) into :py:class:`FileDiffs
        <reviewboard.diffviewer.models.filediff.FileDiff>`. This will not
        result in anything being committed to the database.

        Returns:
            tuple:
            A 2-tuple containing the following:

            * A list of the created FileDiffs.
            * A list of the parent FileDiffs, or ``None``.

        Raises:
            reviewboard.diffviewer.errors.DiffParserError:
                The diff could not be parsed.

            reviewboard.diffviewer.errors.DiffTooBigError:
                The diff was too big.

            reviewboard.diffviewer.errors.EmptyDiffError:
                The diff did not contain any changes.

            reviewboard.scmtools.errors.FileNotFoundError:
                A file was not found in the repository.

            reviewboard.scmtools.errors.SCMError:
                An error occurred within the SCMTool.
        """
        assert self.is_valid()

        diff_file = self.cleaned_data['diff']
        parent_diff_file = self.cleaned_data.get('parent_diff')
        validation_info = self.cleaned_data.get('validation_info')

        check_diff_size(diff_file, parent_diff_file)

        if parent_diff_file:
            parent_diff_file_contents = parent_diff_file.read()
        else:
            parent_diff_file_contents = None

        base_commit_id = self.cleaned_data['base_commit_id']

        diffset = DiffSet(name='diff',
                          revision=0,
                          basedir='',
                          repository=self.repository,
                          diffcompat=DiffCompatVersion.DEFAULT,
                          base_commit_id=base_commit_id)

        get_file_exists = partial(get_file_exists_in_history, validation_info
                                  or {}, self.repository,
                                  self.cleaned_data['parent_id'])

        return create_filediffs(
            diff_file_contents=diff_file.read(),
            parent_diff_file_contents=parent_diff_file_contents,
            repository=self.repository,
            basedir='',
            base_commit_id=base_commit_id,
            get_file_exists=get_file_exists,
            diffset=diffset,
            request=self.request,
            diffcommit=None,
            validate_only=True)