Skip to content

Commit 59ad906

Browse files
thetwojByron
authored andcommitted
Adding diff support for copied files, still working on test
1 parent 43564d2 commit 59ad906

File tree

5 files changed

+48
-8
lines changed

5 files changed

+48
-8
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ Contributors are:
3434
-Stefan Stancu <stefan.stancu _at_ gmail.com>
3535
-César Izurieta <cesar _at_ caih.org>
3636
-Arthur Milchior <arthur _at_ milchior.fr>
37+
-JJ Graham <thetwoj _at_ gmail.com>
3738

3839
Portions derived from other open source works and are clearly marked.

git/diff.py

+21-8
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ def iter_change_type(self, change_type):
193193
yield diff
194194
elif change_type == "D" and diff.deleted_file:
195195
yield diff
196+
elif change_type == "C" and diff.copied_file:
197+
yield diff
196198
elif change_type == "R" and diff.renamed:
197199
yield diff
198200
elif change_type == "M" and diff.a_blob and diff.b_blob and diff.a_blob != diff.b_blob:
@@ -243,6 +245,7 @@ class Diff(object):
243245
^rename[ ]to[ ](?P<rename_to>.*)(?:\n|$))?
244246
(?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
245247
(?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
248+
(?:^copied[ ]file[ ]mode[ ](?P<copied_file_mode>.+)(?:\n|$))?
246249
(?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
247250
\.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
248251
(?:^---[ ](?P<a_path>[^\t\n\r\f\v]*)[\t\r\f\v]*(?:\n|$))?
@@ -253,11 +256,11 @@ class Diff(object):
253256
NULL_BIN_SHA = b"\0" * 20
254257

255258
__slots__ = ("a_blob", "b_blob", "a_mode", "b_mode", "a_rawpath", "b_rawpath",
256-
"new_file", "deleted_file", "raw_rename_from", "raw_rename_to",
257-
"diff", "change_type", "score")
259+
"new_file", "deleted_file", "copied_file", "raw_rename_from",
260+
"raw_rename_to", "diff", "change_type", "score")
258261

259262
def __init__(self, repo, a_rawpath, b_rawpath, a_blob_id, b_blob_id, a_mode,
260-
b_mode, new_file, deleted_file, raw_rename_from,
263+
b_mode, new_file, deleted_file, copied_file, raw_rename_from,
261264
raw_rename_to, diff, change_type, score):
262265

263266
self.a_mode = a_mode
@@ -285,6 +288,7 @@ def __init__(self, repo, a_rawpath, b_rawpath, a_blob_id, b_blob_id, a_mode,
285288

286289
self.new_file = new_file
287290
self.deleted_file = deleted_file
291+
self.copied_file = copied_file
288292

289293
# be clear and use None instead of empty strings
290294
assert raw_rename_from is None or isinstance(raw_rename_from, binary_type)
@@ -336,6 +340,8 @@ def __str__(self):
336340
msg += '\nfile deleted in rhs'
337341
if self.new_file:
338342
msg += '\nfile added in rhs'
343+
if self.copied_file:
344+
msg += '\nfile %r copied from %r' % (self.b_path, self.a_path)
339345
if self.rename_from:
340346
msg += '\nfile renamed from %r' % self.rename_from
341347
if self.rename_to:
@@ -419,11 +425,12 @@ def _index_from_patch_format(cls, repo, proc):
419425
a_path_fallback, b_path_fallback, \
420426
old_mode, new_mode, \
421427
rename_from, rename_to, \
422-
new_file_mode, deleted_file_mode, \
428+
new_file_mode, deleted_file_mode, copied_file_mode, \
423429
a_blob_id, b_blob_id, b_mode, \
424430
a_path, b_path = header.groups()
425431

426-
new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode)
432+
new_file, deleted_file, copied_file = \
433+
bool(new_file_mode), bool(deleted_file_mode), bool(copied_file_mode)
427434

428435
a_path = cls._pick_best_path(a_path, rename_from, a_path_fallback)
429436
b_path = cls._pick_best_path(b_path, rename_to, b_path_fallback)
@@ -445,7 +452,7 @@ def _index_from_patch_format(cls, repo, proc):
445452
b_blob_id and b_blob_id.decode(defenc),
446453
a_mode and a_mode.decode(defenc),
447454
b_mode and b_mode.decode(defenc),
448-
new_file, deleted_file,
455+
new_file, deleted_file, copied_file,
449456
rename_from,
450457
rename_to,
451458
None, None, None))
@@ -485,6 +492,7 @@ def handle_diff_line(line):
485492
b_path = path.encode(defenc)
486493
deleted_file = False
487494
new_file = False
495+
copied_file = False
488496
rename_from = None
489497
rename_to = None
490498

@@ -496,6 +504,11 @@ def handle_diff_line(line):
496504
elif change_type == 'A':
497505
a_blob_id = None
498506
new_file = True
507+
elif change_type == 'C':
508+
copied_file = True
509+
a_path, b_path = path.split('\t', 1)
510+
a_path = a_path.encode(defenc)
511+
b_path = b_path.encode(defenc)
499512
elif change_type == 'R':
500513
a_path, b_path = path.split('\t', 1)
501514
a_path = a_path.encode(defenc)
@@ -507,8 +520,8 @@ def handle_diff_line(line):
507520
# END add/remove handling
508521

509522
diff = Diff(repo, a_path, b_path, a_blob_id, b_blob_id, old_mode, new_mode,
510-
new_file, deleted_file, rename_from, rename_to, '',
511-
change_type, score)
523+
new_file, deleted_file, copied_file, rename_from, rename_to,
524+
'', change_type, score)
512525
index.append(diff)
513526

514527
handle_process_output(proc, handle_diff_line, None, finalize_process, decode_streams=False)

git/test/fixtures/diff_copied_mode

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
diff --git a/test1.txt b/test2.txt
2+
similarity index 100%
3+
copy from test1.txt
4+
copy to test2.txt
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:100644 100644 cfe9dea cfe9dea C100 test1.txt test2.txt

git/test/test_diff.py

+21
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,27 @@ def test_diff_with_rename(self):
112112
self.assertEqual(diff.score, 100)
113113
self.assertEqual(len(list(diffs.iter_change_type('R'))), 1)
114114

115+
def test_diff_with_copied_file(self):
116+
output = StringProcessAdapter(fixture('diff_copied_mode'))
117+
diffs = Diff._index_from_patch_format(self.rorepo, output)
118+
self._assert_diff_format(diffs)
119+
120+
assert_equal(1, len(diffs))
121+
122+
diff = diffs[0]
123+
print(diff)
124+
assert_true(diff.copied_file)
125+
assert isinstance(str(diff), str)
126+
127+
output = StringProcessAdapter(fixture('diff_copied_mode_raw'))
128+
diffs = Diff._index_from_raw_format(self.rorepo, output)
129+
self.assertEqual(len(diffs), 1)
130+
diff = diffs[0]
131+
self.assertEqual(diff.change_type, 'C')
132+
self.assertEqual(diff.score, 100)
133+
self.assertEqual(len(list(diffs.iter_change_type('C'))), 1)
134+
135+
115136
def test_diff_with_change_in_type(self):
116137
output = StringProcessAdapter(fixture('diff_change_in_type'))
117138
diffs = Diff._index_from_patch_format(self.rorepo, output)

0 commit comments

Comments
 (0)