Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suppress unified_diff for files deemed to be "binary". #78

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 27 additions & 8 deletions dulwich/patch.py
Expand Up @@ -31,6 +31,9 @@
S_ISGITLINK,
)

FIRST_FEW_BYTES = 8000


def write_commit_patch(f, commit, contents, progress, version=None):
"""Write a individual file patch.

Expand Down Expand Up @@ -103,6 +106,11 @@ def unified_diff(a, b, fromfile='', tofile='', n=3):
yield '+' + line


def is_binary(content):
"""See if the first few bytes contains any null characters."""
return '\0' in content[:FIRST_FEW_BYTES]


def write_object_diff(f, store, (old_path, old_mode, old_id),
(new_path, new_mode, new_id)):
"""Write the diff for an object.
Expand All @@ -119,13 +127,21 @@ def shortid(hexsha):
return "0" * 7
else:
return hexsha[:7]
def lines(mode, hexsha):

def content(mode, hexsha):
if hexsha is None:
return []
return ''
elif S_ISGITLINK(mode):
return ["Submodule commit " + hexsha + "\n"]
return "Submodule commit " + hexsha + "\n"
else:
return store[hexsha].data.splitlines(True)
return store[hexsha].data

def lines(content):
if not content:
return []
else:
return content.splitlines(True)

if old_path is None:
old_path = "/dev/null"
else:
Expand All @@ -146,10 +162,13 @@ def lines(mode, hexsha):
if new_mode is not None:
f.write(" %o" % new_mode)
f.write("\n")
old_contents = lines(old_mode, old_id)
new_contents = lines(new_mode, new_id)
f.writelines(unified_diff(old_contents, new_contents,
old_path, new_path))
old_content = content(old_mode, old_id)
new_content = content(new_mode, new_id)
if is_binary(old_content) or is_binary(new_content):
f.write("Binary files %s and %s differ\n" % (old_path, new_path))
else:
f.writelines(unified_diff(lines(old_content), lines(new_content),
old_path, new_path))


def write_blob_diff(f, (old_path, old_mode, old_blob),
Expand Down
51 changes: 51 additions & 0 deletions dulwich/tests/test_patch.py
Expand Up @@ -369,6 +369,57 @@ def test_object_diff_remove_blob(self):
'-same'
], f.getvalue().splitlines())

def test_object_diff_bin_blob(self):
f = StringIO()
# Prepare two slightly different PNG headers
b1 = Blob.from_string(
"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52"
"\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b")
b2 = Blob.from_string(
"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52"
"\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3")
store = MemoryObjectStore()
store.add_objects([(b1, None), (b2, None)])
write_object_diff(f, store, ('foo.png', 0644, b1.id),
('bar.png', 0644, b2.id))
self.assertEqual([
'diff --git a/foo.png b/bar.png',
'index f73e47d..06364b7 644',
'Binary files a/foo.png and b/bar.png differ'
], f.getvalue().splitlines())

def test_object_diff_add_bin_blob(self):
f = StringIO()
b2 = Blob.from_string(
'\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52'
'\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3')
store = MemoryObjectStore()
store.add_object(b2)
write_object_diff(f, store, (None, None, None),
('bar.png', 0644, b2.id))
self.assertEqual([
'diff --git /dev/null b/bar.png',
'new mode 644',
'index 0000000..06364b7 644',
'Binary files /dev/null and b/bar.png differ'
], f.getvalue().splitlines())

def test_object_diff_remove_bin_blob(self):
f = StringIO()
b1 = Blob.from_string(
'\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52'
'\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b')
store = MemoryObjectStore()
store.add_object(b1)
write_object_diff(f, store, ('foo.png', 0644, b1.id),
(None, None, None))
self.assertEqual([
'diff --git a/foo.png /dev/null',
'deleted mode 644',
'index f73e47d..0000000',
'Binary files a/foo.png and /dev/null differ'
], f.getvalue().splitlines())

def test_object_diff_kind_change(self):
f = StringIO()
b1 = Blob.from_string("new\nsame\n")
Expand Down