summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2015-01-09 13:15:09 +0100
committerSebastian Thiel <byronimo@gmail.com>2015-01-09 17:16:35 +0100
commit18caa610d50b92331485013584f5373804dd0416 (patch)
tree4ff1e44d7451a99d10ea1d2acf78764698c16229
parent0d9f1495004710b77767393a29f33df76d7b0fb5 (diff)
downloadgitpython-18caa610d50b92331485013584f5373804dd0416.tar.gz
Added test to verify binary diffs are working as well.
Related to #74
-rw-r--r--git/diff.py30
-rw-r--r--git/objects/base.py3
-rw-r--r--git/test/fixtures/diff_index_patch100
-rw-r--r--git/test/test_diff.py12
4 files changed, 134 insertions, 11 deletions
diff --git a/git/diff.py b/git/diff.py
index 24e47bad..f10bd1cd 100644
--- a/git/diff.py
+++ b/git/diff.py
@@ -183,8 +183,8 @@ class Diff(object):
# precompiled regex
re_header = re.compile(r"""
- #^diff[ ]--git
- [ ]a/(?P<a_path>.+?)[ ]b/(?P<b_path>.+?)\n
+ ^diff[ ]--git
+ [ ](?:a/)?(?P<a_path>.+?)[ ](?:b/)?(?P<b_path>.+?)\n
(?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
^rename[ ]from[ ](?P<rename_from>\S+)\n
^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
@@ -298,20 +298,30 @@ class Diff(object):
# for now, we have to bake the stream
text = stream.read().decode(defenc)
index = DiffIndex()
-
- diff_header = cls.re_header.match
- for diff in ('\n' + text).split('\ndiff --git')[1:]:
- header = diff_header(diff)
- assert header is not None, "Failed to parse diff header from " % diff
-
+ previous_header = None
+ for header in cls.re_header.finditer(text):
a_path, b_path, similarity_index, rename_from, rename_to, \
old_mode, new_mode, new_file_mode, deleted_file_mode, \
a_blob_id, b_blob_id, b_mode = header.groups()
new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode)
+ # Our only means to find the actual text is to see what has not been matched by our regex,
+ # and then retro-actively assin it to our index
+ if previous_header is not None:
+ index[-1].diff = text[previous_header.end():header.start()]
+ # end assign actual diff
+
+ # Make sure the mode is set if the path is set. Otherwise the resulting blob is invalid
+ # We just use the one mode we should have parsed
index.append(Diff(repo, a_path, b_path, a_blob_id, b_blob_id,
- old_mode or deleted_file_mode, new_mode or new_file_mode or b_mode,
- new_file, deleted_file, rename_from, rename_to, diff[header.end():]))
+ old_mode or deleted_file_mode or b_mode, new_mode or new_file_mode or b_mode,
+ new_file, deleted_file, rename_from, rename_to, None))
+
+ previous_header = header
+ # end for each header we parse
+ if index:
+ index[-1].diff = text[header.end():]
+ # end assign last diff
return index
diff --git a/git/objects/base.py b/git/objects/base.py
index 3f595d9d..eb59b0a9 100644
--- a/git/objects/base.py
+++ b/git/objects/base.py
@@ -158,7 +158,8 @@ class IndexObject(Object):
if attr in IndexObject.__slots__:
# they cannot be retrieved lateron ( not without searching for them )
raise AttributeError(
- "path and mode attributes must have been set during %s object creation" % type(self).__name__)
+ "Attribute '%s' unset: path and mode attributes must have been set during %s object creation"
+ % (attr, type(self).__name__))
else:
super(IndexObject, self)._set_cache_(attr)
# END hanlde slot attribute
diff --git a/git/test/fixtures/diff_index_patch b/git/test/fixtures/diff_index_patch
new file mode 100644
index 00000000..a5a8cff2
--- /dev/null
+++ b/git/test/fixtures/diff_index_patch
@@ -0,0 +1,100 @@
+diff --git a/etc/sublime-text/git-python.sublime-project b/etc/sublime-text/git-python.sublime-project
+index 3dab9f6562ecb0408d9ece8dd63cc4461d280113..9c99a2cff7dc918fbbb61cd57d5d98750a1ef6c5 100644
+--- a/etc/sublime-text/git-python.sublime-project
++++ b/etc/sublime-text/git-python.sublime-project
+@@ -23,7 +23,7 @@
+ ]
+ },
+ // GITDB
+- ////////
++ // ////////
+ {
+ "follow_symlinks": true,
+ "path": "../../git/ext/gitdb",
+@@ -42,8 +42,8 @@
+ ".tox",
+ ]
+ },
+- // // SMMAP
+- // ////////
++ // // // SMMAP
++ // // ////////
+ {
+ "follow_symlinks": true,
+ "path": "../../git/ext/gitdb/gitdb/ext/smmap",
+diff --git a/git/diff.py b/git/diff.py
+index 24e47bad9d79534d3cf474fec4f79e6fef122bb1..c1ad532e0217e293906bcfef43c523d6a8e21568 100644
+--- a/git/diff.py
++++ b/git/diff.py
+@@ -302,13 +302,21 @@ class Diff(object):
+ diff_header = cls.re_header.match
+ for diff in ('\n' + text).split('\ndiff --git')[1:]:
+ header = diff_header(diff)
+- assert header is not None, "Failed to parse diff header from " % diff
++ assert header is not None, "Failed to parse diff header from '%s'" % diff
+
+ a_path, b_path, similarity_index, rename_from, rename_to, \
+ old_mode, new_mode, new_file_mode, deleted_file_mode, \
+ a_blob_id, b_blob_id, b_mode = header.groups()
+ new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode)
+
++ # if a_path.startswith('a/'):
++ # a_path = a_path[2:]
++ # if b_path.startswith('b/'):
++ # b_path = b_path[2:]
++
++ for item in (a_path, b_path, a_blob_id, b_blob_id, old_mode, deleted_file_mode, new_mode, new_file_mode, b_mode, new_file, deleted_file, rename_from, rename_to, diff[header.end():]):
++ print( "####")
++ print(item)
+ index.append(Diff(repo, a_path, b_path, a_blob_id, b_blob_id,
+ old_mode or deleted_file_mode, new_mode or new_file_mode or b_mode,
+ new_file, deleted_file, rename_from, rename_to, diff[header.end():]))
+diff --git a/git/ext/gitdb b/git/ext/gitdb
+index f2233fbf40f3f69309ce5cc714e99fcbdcd33ec3..a88a777df3909a61be97f1a7b1194dad6de25702 160000
+--- a/git/ext/gitdb
++++ b/git/ext/gitdb
+@@ -1 +1 @@
+-Subproject commit f2233fbf40f3f69309ce5cc714e99fcbdcd33ec3
++Subproject commit a88a777df3909a61be97f1a7b1194dad6de25702-dirty
+diff --git a/git/test/fixtures/diff_patch_binary b/git/test/fixtures/diff_patch_binary
+new file mode 100644
+index 0000000000000000000000000000000000000000..c92ccd6ebc92a871d38ad7cb8a48bcdb1a5dbc33
+--- /dev/null
++++ b/git/test/fixtures/diff_patch_binary
+@@ -0,0 +1,3 @@
++diff --git a/rps b/rps
++index f4567df37451b230b1381b1bc9c2bcad76e08a3c..736bd596a36924d30b480942e9475ce0d734fa0d 100755
++Binary files a/rps and b/rps differ
+diff --git a/git/test/fixtures/diff_raw_binary b/git/test/fixtures/diff_raw_binary
+new file mode 100644
+index 0000000000000000000000000000000000000000..d4673fa41ee8413384167fc7b9f25e4daf18a53a
+--- /dev/null
++++ b/git/test/fixtures/diff_raw_binary
+@@ -0,0 +1 @@
++:100755 100755 f4567df37451b230b1381b1bc9c2bcad76e08a3c 736bd596a36924d30b480942e9475ce0d734fa0d M rps
+diff --git a/git/test/test_diff.py b/git/test/test_diff.py
+index ce0f64f2261bd8de063233108caac1f26742c1fd..4de26f8884fd048ac7f10007f2bf7c7fa3fa60f4 100644
+--- a/git/test/test_diff.py
++++ b/git/test/test_diff.py
+@@ -65,6 +65,21 @@ class TestDiff(TestBase):
+ assert diff.rename_to == 'that'
+ assert len(list(diffs.iter_change_type('R'))) == 1
+
++ def test_binary_diff(self):
++ for method, file_name in ((Diff._index_from_patch_format, 'diff_patch_binary'),
++ (Diff._index_from_raw_format, 'diff_raw_binary')):
++ res = method(None, StringProcessAdapter(fixture(file_name)).stdout)
++ assert len(res) == 1
++ assert len(list(res.iter_change_type('M'))) == 1
++ if res[0].diff:
++ assert res[0].diff == "Binary files a/rps and b/rps differ\n", "in patch mode, we get a diff text"
++ assert isinstance(str(res[0]), str), "This call should just work"
++ # end for each method to test
++
++ def test_diff_index(self):
++ res = self.rorepo.index.diff('17f5d13a7a741dcbb2a30e147bdafe929cff4697', create_patch=True)
++ assert len(res) == 3
++
+ def test_diff_patch_format(self):
+ # test all of the 'old' format diffs for completness - it should at least
+ # be able to deal with it
diff --git a/git/test/test_diff.py b/git/test/test_diff.py
index ebf9527a..c59117ef 100644
--- a/git/test/test_diff.py
+++ b/git/test/test_diff.py
@@ -73,8 +73,20 @@ class TestDiff(TestBase):
assert len(list(res.iter_change_type('M'))) == 1
if res[0].diff:
assert res[0].diff == "Binary files a/rps and b/rps differ\n", "in patch mode, we get a diff text"
+ assert isinstance(str(res[0]), str), "This call should just work"
# end for each method to test
+ def test_diff_index(self):
+ output = StringProcessAdapter(fixture('diff_index_patch'))
+ res = Diff._index_from_patch_format(None, output.stdout)
+ assert len(res) == 6
+ for dr in res:
+ assert dr.diff
+ # end for each diff
+
+ dr = res[3]
+ assert dr.diff.endswith("+Binary files a/rps and b/rps differ\n")
+
def test_diff_patch_format(self):
# test all of the 'old' format diffs for completness - it should at least
# be able to deal with it