Skip to content

Commit 651a81d

Browse files
committed
refactor; add failing test to validate #1210
1 parent 14fc8bd commit 651a81d

File tree

4 files changed

+62
-54
lines changed

4 files changed

+62
-54
lines changed

git/diff.py

+54-53
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,58 @@ def _index_from_patch_format(cls, repo: 'Repo', proc: TBD) -> DiffIndex:
490490

491491
return index
492492

493+
@staticmethod
494+
def _handle_diff_line(lines_bytes: bytes, repo: 'Repo', index: TBD) -> None:
495+
lines = lines_bytes.decode(defenc)
496+
497+
for line in lines.split(':')[1:]:
498+
meta, _, path = line.partition('\x00')
499+
path = path.rstrip('\x00')
500+
a_blob_id, b_blob_id = None, None # Type: Optional[str]
501+
old_mode, new_mode, a_blob_id, b_blob_id, _change_type = meta.split(None, 4)
502+
# Change type can be R100
503+
# R: status letter
504+
# 100: score (in case of copy and rename)
505+
change_type = _change_type[0]
506+
score_str = ''.join(_change_type[1:])
507+
score = int(score_str) if score_str.isdigit() else None
508+
path = path.strip()
509+
a_path = path.encode(defenc)
510+
b_path = path.encode(defenc)
511+
deleted_file = False
512+
new_file = False
513+
copied_file = False
514+
rename_from = None
515+
rename_to = None
516+
517+
# NOTE: We cannot conclude from the existence of a blob to change type
518+
# as diffs with the working do not have blobs yet
519+
if change_type == 'D':
520+
b_blob_id = None # Optional[str]
521+
deleted_file = True
522+
elif change_type == 'A':
523+
a_blob_id = None
524+
new_file = True
525+
elif change_type == 'C':
526+
copied_file = True
527+
a_path_str, b_path_str = path.split('\x00', 1)
528+
a_path = a_path_str.encode(defenc)
529+
b_path = b_path_str.encode(defenc)
530+
elif change_type == 'R':
531+
a_path_str, b_path_str = path.split('\x00', 1)
532+
a_path = a_path_str.encode(defenc)
533+
b_path = b_path_str.encode(defenc)
534+
rename_from, rename_to = a_path, b_path
535+
elif change_type == 'T':
536+
# Nothing to do
537+
pass
538+
# END add/remove handling
539+
540+
diff = Diff(repo, a_path, b_path, a_blob_id, b_blob_id, old_mode, new_mode,
541+
new_file, deleted_file, copied_file, rename_from, rename_to,
542+
'', change_type, score)
543+
index.append(diff)
544+
493545
@classmethod
494546
def _index_from_raw_format(cls, repo: 'Repo', proc: TBD) -> DiffIndex:
495547
"""Create a new DiffIndex from the given stream which must be in raw format.
@@ -498,58 +550,7 @@ def _index_from_raw_format(cls, repo: 'Repo', proc: TBD) -> DiffIndex:
498550
# :100644 100644 687099101... 37c5e30c8... M .gitignore
499551

500552
index = DiffIndex()
501-
502-
def handle_diff_line(lines_bytes: bytes) -> None:
503-
lines = lines_bytes.decode(defenc)
504-
505-
for line in lines.split(':')[1:]:
506-
meta, _, path = line.partition('\x00')
507-
path = path.rstrip('\x00')
508-
a_blob_id, b_blob_id = None, None # Type: Optional[str]
509-
old_mode, new_mode, a_blob_id, b_blob_id, _change_type = meta.split(None, 4)
510-
# Change type can be R100
511-
# R: status letter
512-
# 100: score (in case of copy and rename)
513-
change_type = _change_type[0]
514-
score_str = ''.join(_change_type[1:])
515-
score = int(score_str) if score_str.isdigit() else None
516-
path = path.strip()
517-
a_path = path.encode(defenc)
518-
b_path = path.encode(defenc)
519-
deleted_file = False
520-
new_file = False
521-
copied_file = False
522-
rename_from = None
523-
rename_to = None
524-
525-
# NOTE: We cannot conclude from the existence of a blob to change type
526-
# as diffs with the working do not have blobs yet
527-
if change_type == 'D':
528-
b_blob_id = None # Optional[str]
529-
deleted_file = True
530-
elif change_type == 'A':
531-
a_blob_id = None
532-
new_file = True
533-
elif change_type == 'C':
534-
copied_file = True
535-
a_path_str, b_path_str = path.split('\x00', 1)
536-
a_path = a_path_str.encode(defenc)
537-
b_path = b_path_str.encode(defenc)
538-
elif change_type == 'R':
539-
a_path_str, b_path_str = path.split('\x00', 1)
540-
a_path = a_path_str.encode(defenc)
541-
b_path = b_path_str.encode(defenc)
542-
rename_from, rename_to = a_path, b_path
543-
elif change_type == 'T':
544-
# Nothing to do
545-
pass
546-
# END add/remove handling
547-
548-
diff = Diff(repo, a_path, b_path, a_blob_id, b_blob_id, old_mode, new_mode,
549-
new_file, deleted_file, copied_file, rename_from, rename_to,
550-
'', change_type, score)
551-
index.append(diff)
552-
553-
handle_process_output(proc, handle_diff_line, None, finalize_process, decode_streams=False)
553+
handle_process_output(proc, lambda bytes: cls._handle_diff_line(
554+
bytes, repo, index), None, finalize_process, decode_streams=False)
554555

555556
return index

test/fixtures/diff_file_with_colon

351 Bytes
Binary file not shown.

test/test_diff.py

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import ddt
88
import shutil
99
import tempfile
10+
import unittest
1011
from git import (
1112
Repo,
1213
GitCommandError,
@@ -220,6 +221,12 @@ def test_diff_index_raw_format(self):
220221
self.assertIsNotNone(res[0].deleted_file)
221222
self.assertIsNone(res[0].b_path,)
222223

224+
@unittest.skip("This currently fails and would need someone to improve diff parsing")
225+
def test_diff_file_with_colon(self):
226+
output = fixture('diff_file_with_colon')
227+
res = []
228+
Diff._handle_diff_line(output, None, res)
229+
223230
def test_diff_initial_commit(self):
224231
initial_commit = self.rorepo.commit('33ebe7acec14b25c5f84f35a664803fcab2f7781')
225232

0 commit comments

Comments
 (0)