diff options
author | Sebastian Thiel <byronimo@gmail.com> | 2015-01-09 13:15:09 +0100 |
---|---|---|
committer | Sebastian Thiel <byronimo@gmail.com> | 2015-01-09 17:16:35 +0100 |
commit | 18caa610d50b92331485013584f5373804dd0416 (patch) | |
tree | 4ff1e44d7451a99d10ea1d2acf78764698c16229 | |
parent | 0d9f1495004710b77767393a29f33df76d7b0fb5 (diff) | |
download | gitpython-18caa610d50b92331485013584f5373804dd0416.tar.gz |
Added test to verify binary diffs are working as well.
Related to #74
-rw-r--r-- | git/diff.py | 30 | ||||
-rw-r--r-- | git/objects/base.py | 3 | ||||
-rw-r--r-- | git/test/fixtures/diff_index_patch | 100 | ||||
-rw-r--r-- | git/test/test_diff.py | 12 |
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 |