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 create_filediff(self, diffset, source_file='/test-file',
dest_file='/test-file', source_revision='123',
dest_detail='124', status=FileDiff.MODIFIED,
diff=DEFAULT_FILEDIFF_DATA, save=True):
"""Create a FileDiff for testing.
The FileDiff is tied to the given DiffSet. It's populated with
default data that can be overridden by the caller.
Args:
diffset (reviewboard.diffviewer.models.DiffSet):
The parent diff set that will own this file.
source_file (unicode, optional):
The source filename.
dest_file (unicode, optional):
The destination filename, which will be the same as
``source_file`` unless the file was moved/renamed/copied.
source_revision (unicode, optional):
The source revision.
dest_detail (unicode, optional):
The destination revision or other detail as found in the
parsed diff. This may be a timestamp or some other value.
status (unicode, optional):
The status of the file. This is the operation performed
as indicated in the diff.
diff (bytes, optional):
The diff contents.
save (bool, optional):
Whether to automatically save the resulting object.
Returns:
reviewboard.diffviewer.models.FileDiff:
The resulting FileDiff.
"""
filediff = FileDiff(
diffset=diffset,
source_file=source_file,
dest_file=dest_file,
source_revision=source_revision,
dest_detail=dest_detail,
status=status,
diff=diff)
if save:
filediff.save()
return filediff
def test_diff_hashes(self):
"""
Testing that uploading two of the same diff will result in only
one database entry.
"""
repository = self.create_repository()
diffset = DiffSet.objects.create(name='test',
revision=1,
repository=repository)
with open(os.path.join(self.PREFIX, "diffs", "context",
"foo.c.diff")) as f:
data = f.read()
filediff1 = FileDiff(diff=data,
diffset=diffset)
filediff1.save()
filediff2 = FileDiff(diff=data,
diffset=diffset)
filediff2.save()
self.assertEquals(filediff1.diff_hash, filediff2.diff_hash)
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 create_from_data(self, repository, diff_file_name, diff_file_contents,
parent_diff_file_name, parent_diff_file_contents,
diffset_history, basedir, request, save=True):
"""Create a DiffSet from raw diff data.
The diff_file_contents and parent_diff_file_contents parameters are
strings with the actual diff contents.
"""
from reviewboard.diffviewer.models import FileDiff
tool = repository.get_scmtool()
files = list(self._process_files(
diff_file_contents, basedir, repository, request,
check_existence=(not parent_diff_file_contents)))
# Parse the diff
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_contents:
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_contents, basedir,
repository, request,
check_existence=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 = super(DiffSetManager, self).create(
name=diff_file_name, revision=0,
basedir=basedir,
history=diffset_history,
repository=repository,
diffcompat=DEFAULT_DIFF_COMPAT_VERSION)
if save:
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)
if save:
filediff.save()
return diffset
def create_filediffs(diff_file_contents, parent_diff_file_contents,
repository, basedir, base_commit_id, diffset,
request=None, check_existence=True, get_file_exists=None,
diffcommit=None, validate_only=False):
"""Create FileDiffs from the given data.
Args:
diff_file_contents (bytes):
The contents of the diff file.
parent_diff_file_contents (bytes):
The contents of the parent diff file.
repository (reviewboard.scmtools.models.Repository):
The repository the diff is being posted against.
basedir (unicode):
The base directory to prepend to all file paths in the diff.
base_commit_id (unicode):
The ID of the commit that the diff is based upon. This is
needed by some SCMs or hosting services to properly look up
files, if the diffs represent blob IDs instead of commit IDs
and the service doesn't support those lookups.
diffset (reviewboard.diffviewer.models.diffset.DiffSet):
The DiffSet to attach the created FileDiffs to.
request (django.http.HttpRequest, optional):
The current HTTP request.
check_existence (bool, optional):
Whether or not existence checks should be performed against
the upstream repository.
This argument defaults to ``True``.
get_file_exists (callable, optional):
A callable that is used to determine if a file exists.
This must be provided if ``check_existence`` is ``True``.
diffcommit (reviewboard.diffviewer.models.diffcommit.DiffCommit,
optional):
The Diffcommit to attach the created FileDiffs to.
validate_only (bool, optional):
Whether to just validate and not save. If ``True``, then this
won't populate the database at all and will return ``None``
upon success. This defaults to ``False``.
Returns:
list of reviewboard.diffviewer.models.filediff.FileDiff:
The created FileDiffs.
If ``validate_only`` is ``True``, the returned list will be empty.
"""
from reviewboard.diffviewer.diffutils import convert_to_unicode
from reviewboard.diffviewer.models import FileDiff
files, parser, parent_commit_id, parent_files = _prepare_file_list(
diff_file_contents=diff_file_contents,
parent_diff_file_contents=parent_diff_file_contents,
repository=repository,
request=request,
basedir=basedir,
check_existence=check_existence,
get_file_exists=get_file_exists,
base_commit_id=base_commit_id)
encoding_list = repository.get_encoding_list()
filediffs = []
for f in files:
parent_file = None
orig_rev = None
parent_content = b''
if f.origFile in parent_files:
parent_file = parent_files[f.origFile]
parent_content = parent_file.data
orig_rev = parent_file.origInfo
# If there is a parent file there is not necessarily an original
# revision for the parent file in the case of a renamed file in
# git.
if not orig_rev:
if parent_commit_id and f.origInfo != PRE_CREATION:
orig_rev = parent_commit_id
else:
orig_rev = f.origInfo
orig_file = convert_to_unicode(f.origFile, encoding_list)[1]
dest_file = convert_to_unicode(f.newFile, encoding_list)[1]
if f.deleted:
status = FileDiff.DELETED
elif f.moved:
status = FileDiff.MOVED
elif f.copied:
#.........这里部分代码省略.........
def create_from_data(self, repository, diff_file_name, diff_file_contents,
parent_diff_file_name, parent_diff_file_contents,
diffset_history, basedir, request,
base_commit_id=None, save=True):
"""Create a DiffSet from raw diff data.
The diff_file_contents and parent_diff_file_contents parameters are
strings with the actual diff contents.
"""
from reviewboard.diffviewer.diffutils import convert_to_unicode
from reviewboard.diffviewer.models import FileDiff
tool = repository.get_scmtool()
encoding, diff_text = convert_to_unicode(
diff_file_contents, repository.get_encoding_list())
parser = tool.get_parser(diff_text)
files = list(self._process_files(
parser,
basedir,
repository,
base_commit_id,
request,
check_existence=(not parent_diff_file_contents)))
# Parse the diff
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_commit_id = None
if parent_diff_file_contents:
diff_filenames = set([f.origFile for f in files])
parent_parser = tool.get_parser(
convert_to_unicode(parent_diff_file_contents, [encoding])[1])
# 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_parser, basedir,
repository, base_commit_id, request,
check_existence=True,
limit_to=diff_filenames):
parent_files[f.origFile] = f
# This will return a non-None value only for tools that use
# commit IDs to identify file versions as opposed to file revision
# IDs.
parent_commit_id = parent_parser.get_orig_commit_id()
diffset = super(DiffSetManager, self).create(
name=diff_file_name, revision=0,
basedir=basedir,
history=diffset_history,
repository=repository,
diffcompat=DiffCompatVersion.DEFAULT,
base_commit_id=base_commit_id)
if save:
diffset.save()
for f in files:
if f.origFile in parent_files:
parent_file = parent_files[f.origFile]
parent_content = parent_file.data.encode(encoding)
source_rev = parent_file.origInfo
else:
parent_content = b""
if parent_commit_id and f.origInfo != PRE_CREATION:
source_rev = parent_commit_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
elif f.copied:
status = FileDiff.COPIED
else:
status = FileDiff.MODIFIED
filediff = FileDiff(
diffset=diffset,
source_file=parser.normalize_diff_filename(f.origFile),
dest_file=parser.normalize_diff_filename(dest_file),
source_revision=smart_unicode(source_rev),
#.........这里部分代码省略.........
请发表评论