From 327758709de9235bee3a625a3d5a8e3f7b8bf8b6 Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Tue, 26 May 2020 16:36:32 +0200 Subject: [PATCH 1/3] Add basic support for binary diffs --- diff/diff_test.go | 70 +++++++++++++++++++++++++ diff/parse.go | 6 +-- diff/testdata/sample_binary_inline.diff | 33 ++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 diff/testdata/sample_binary_inline.diff diff --git a/diff/diff_test.go b/diff/diff_test.go index 442f0f4..6ce0571 100644 --- a/diff/diff_test.go +++ b/diff/diff_test.go @@ -388,6 +388,76 @@ func TestParseMultiFileDiffHeaders(t *testing.T) { }, }, }, + { + filename: "sample_binary_inline.diff", + wantDiffs: []*FileDiff{ + { + OrigName: "a/logo-old.png", + OrigTime: nil, + NewName: "/dev/null", + NewTime: nil, + Extended: []string{ + "diff --git a/logo-old.png b/logo-old.png", + "deleted file mode 100644", + "index d29d0e9757e0d9b854a8ed58f170bcb454cc1ae3..0000000000000000000000000000000000000000", + "GIT binary patch", + "literal 0", + "HcmV?d00001", + "", + "literal 0", + "HcmV?d00001", + "", + }, + }, + { + OrigName: "a/logo-old.png", + OrigTime: nil, + NewName: "b/logo-old.png", + NewTime: nil, + Extended: []string{ + "diff --git a/logo-old.png b/logo-old.png", + "index ff82e793467f2050d731d75b4968d2e6b9c5d33b..d29d0e9757e0d9b854a8ed58f170bcb454cc1ae3 100644", + "GIT binary patch", + "literal 0", + "HcmV?d00001", + "", + "literal 0", + "HcmV?d00001", + "", + }, + }, + { + OrigName: "a/logo.png", + OrigTime: nil, + NewName: "b/logo-old.png", + NewTime: nil, + Extended: []string{ + "diff --git a/logo.png b/logo-old.png", + "similarity index 100%", + "rename from logo.png", + "rename to logo-old.png", + }, + }, + { + OrigName: "/dev/null", + OrigTime: nil, + NewName: "b/logo.png", + NewTime: nil, + Extended: []string{ + "diff --git a/logo.png b/logo.png", + "new file mode 100644", + "index 0000000000000000000000000000000000000000..ff82e793467f2050d731d75b4968d2e6b9c5d33b", + "GIT binary patch", + "literal 0", + "HcmV?d00001", + "", + "literal 0", + "HcmV?d00001", + "", + }, + }, + }, + }, { filename: "sample_multi_file_new_win.diff", wantDiffs: []*FileDiff{ diff --git a/diff/parse.go b/diff/parse.go index f788e7e..edf2e4e 100644 --- a/diff/parse.go +++ b/diff/parse.go @@ -341,7 +341,7 @@ func (r *FileDiffReader) ReadExtendedHeaders() ([]string, error) { func handleEmpty(fd *FileDiff) (wasEmpty bool) { var err error switch { - case (len(fd.Extended) == 3 || len(fd.Extended) == 4 && strings.HasPrefix(fd.Extended[3], "Binary files ")) && + case (len(fd.Extended) == 3 || len(fd.Extended) == 4 && strings.HasPrefix(fd.Extended[3], "Binary files ") || len(fd.Extended) > 4 && strings.HasPrefix(fd.Extended[3], "GIT binary patch")) && strings.HasPrefix(fd.Extended[1], "new file mode ") && strings.HasPrefix(fd.Extended[0], "diff --git "): names := strings.SplitN(fd.Extended[0][len("diff --git "):], " ", 2) @@ -351,7 +351,7 @@ func handleEmpty(fd *FileDiff) (wasEmpty bool) { fd.NewName = names[1] } return true - case (len(fd.Extended) == 3 || len(fd.Extended) == 4 && strings.HasPrefix(fd.Extended[3], "Binary files ")) && + case (len(fd.Extended) == 3 || len(fd.Extended) == 4 && strings.HasPrefix(fd.Extended[3], "Binary files ") || len(fd.Extended) > 4 && strings.HasPrefix(fd.Extended[3], "GIT binary patch")) && strings.HasPrefix(fd.Extended[1], "deleted file mode ") && strings.HasPrefix(fd.Extended[0], "diff --git "): names := strings.SplitN(fd.Extended[0][len("diff --git "):], " ", 2) @@ -372,7 +372,7 @@ func handleEmpty(fd *FileDiff) (wasEmpty bool) { fd.NewName = names[1] } return true - case len(fd.Extended) == 3 && strings.HasPrefix(fd.Extended[2], "Binary files ") && strings.HasPrefix(fd.Extended[0], "diff --git "): + case (len(fd.Extended) == 3 && strings.HasPrefix(fd.Extended[2], "Binary files ") || len(fd.Extended) > 3 && strings.HasPrefix(fd.Extended[2], "GIT binary patch")) && strings.HasPrefix(fd.Extended[0], "diff --git "): names := strings.SplitN(fd.Extended[0][len("diff --git "):], " ", 2) fd.OrigName, err = strconv.Unquote(names[0]) if err != nil { diff --git a/diff/testdata/sample_binary_inline.diff b/diff/testdata/sample_binary_inline.diff new file mode 100644 index 0000000..10fca65 --- /dev/null +++ b/diff/testdata/sample_binary_inline.diff @@ -0,0 +1,33 @@ +diff --git a/logo-old.png b/logo-old.png +deleted file mode 100644 +index d29d0e9757e0d9b854a8ed58f170bcb454cc1ae3..0000000000000000000000000000000000000000 +GIT binary patch +literal 0 +HcmV?d00001 + +literal 0 +HcmV?d00001 + +diff --git a/logo-old.png b/logo-old.png +index ff82e793467f2050d731d75b4968d2e6b9c5d33b..d29d0e9757e0d9b854a8ed58f170bcb454cc1ae3 100644 +GIT binary patch +literal 0 +HcmV?d00001 + +literal 0 +HcmV?d00001 + +diff --git a/logo.png b/logo-old.png +similarity index 100% +rename from logo.png +rename to logo-old.png +diff --git a/logo.png b/logo.png +new file mode 100644 +index 0000000000000000000000000000000000000000..ff82e793467f2050d731d75b4968d2e6b9c5d33b +GIT binary patch +literal 0 +HcmV?d00001 + +literal 0 +HcmV?d00001 + From 6e43c897f818deab0ea3ce76013589670b024c87 Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Tue, 26 May 2020 19:33:30 +0200 Subject: [PATCH 2/3] Simplify expressions --- diff/parse.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/diff/parse.go b/diff/parse.go index edf2e4e..45e058e 100644 --- a/diff/parse.go +++ b/diff/parse.go @@ -340,9 +340,13 @@ func (r *FileDiffReader) ReadExtendedHeaders() ([]string, error) { // that follow. It updates fd fields from the parsed extended headers. func handleEmpty(fd *FileDiff) (wasEmpty bool) { var err error + lineCount := len(fd.Extended) + if lineCount > 0 && !strings.HasPrefix(fd.Extended[0], "diff --git ") { + return false + } switch { - case (len(fd.Extended) == 3 || len(fd.Extended) == 4 && strings.HasPrefix(fd.Extended[3], "Binary files ") || len(fd.Extended) > 4 && strings.HasPrefix(fd.Extended[3], "GIT binary patch")) && - strings.HasPrefix(fd.Extended[1], "new file mode ") && strings.HasPrefix(fd.Extended[0], "diff --git "): + case (lineCount == 3 || lineCount == 4 && strings.HasPrefix(fd.Extended[3], "Binary files ") || lineCount > 4 && strings.HasPrefix(fd.Extended[3], "GIT binary patch")) && + strings.HasPrefix(fd.Extended[1], "new file mode "): names := strings.SplitN(fd.Extended[0][len("diff --git "):], " ", 2) fd.OrigName = "/dev/null" @@ -351,8 +355,8 @@ func handleEmpty(fd *FileDiff) (wasEmpty bool) { fd.NewName = names[1] } return true - case (len(fd.Extended) == 3 || len(fd.Extended) == 4 && strings.HasPrefix(fd.Extended[3], "Binary files ") || len(fd.Extended) > 4 && strings.HasPrefix(fd.Extended[3], "GIT binary patch")) && - strings.HasPrefix(fd.Extended[1], "deleted file mode ") && strings.HasPrefix(fd.Extended[0], "diff --git "): + case (lineCount == 3 || lineCount == 4 && strings.HasPrefix(fd.Extended[3], "Binary files ") || lineCount > 4 && strings.HasPrefix(fd.Extended[3], "GIT binary patch")) && + strings.HasPrefix(fd.Extended[1], "deleted file mode "): names := strings.SplitN(fd.Extended[0][len("diff --git "):], " ", 2) fd.OrigName, err = strconv.Unquote(names[0]) @@ -361,7 +365,7 @@ func handleEmpty(fd *FileDiff) (wasEmpty bool) { } fd.NewName = "/dev/null" return true - case len(fd.Extended) == 4 && strings.HasPrefix(fd.Extended[2], "rename from ") && strings.HasPrefix(fd.Extended[3], "rename to ") && strings.HasPrefix(fd.Extended[0], "diff --git "): + case lineCount == 4 && strings.HasPrefix(fd.Extended[2], "rename from ") && strings.HasPrefix(fd.Extended[3], "rename to "): names := strings.SplitN(fd.Extended[0][len("diff --git "):], " ", 2) fd.OrigName, err = strconv.Unquote(names[0]) if err != nil { @@ -372,7 +376,7 @@ func handleEmpty(fd *FileDiff) (wasEmpty bool) { fd.NewName = names[1] } return true - case (len(fd.Extended) == 3 && strings.HasPrefix(fd.Extended[2], "Binary files ") || len(fd.Extended) > 3 && strings.HasPrefix(fd.Extended[2], "GIT binary patch")) && strings.HasPrefix(fd.Extended[0], "diff --git "): + case lineCount == 3 && strings.HasPrefix(fd.Extended[2], "Binary files ") || lineCount > 3 && strings.HasPrefix(fd.Extended[2], "GIT binary patch"): names := strings.SplitN(fd.Extended[0][len("diff --git "):], " ", 2) fd.OrigName, err = strconv.Unquote(names[0]) if err != nil { From 75d7ce26e4fd0d30e9694de7e510d65b91c2cc90 Mon Sep 17 00:00:00 2001 From: Erik Seliger Date: Tue, 26 May 2020 19:51:24 +0200 Subject: [PATCH 3/3] Don't skip parsing when hunk is the last in file --- diff/parse.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diff/parse.go b/diff/parse.go index 45e058e..08cba66 100644 --- a/diff/parse.go +++ b/diff/parse.go @@ -80,7 +80,7 @@ func (r *MultiFileDiffReader) ReadFile() (*FileDiff, error) { // need to perform the check here. hr := fr.HunksReader() line, err := readLine(r.reader) - if err != nil { + if err != nil && err != io.EOF { return fd, err } line = bytes.TrimSuffix(line, []byte{'\n'})