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
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)
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)
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)
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))
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
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
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)