aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStuart Jansen <sjansen@buscaluz.org>2019-10-13 14:25:56 -0600
committerStuart Jansen <sjansen@buscaluz.org>2019-10-13 15:16:02 -0600
commit883ed6f63e9a92cb1d25266df5074982774cec8a (patch)
tree0d190415e0dde3bce6fe27bffbc06ab1901c237e
parent8d20cc5916edf7cfa6a9c5ed069f0640dc823c12 (diff)
downloadgo-git-883ed6f63e9a92cb1d25266df5074982774cec8a.tar.gz
format: diff, Handle no newline at end of file. Fixes #936
Signed-off-by: Stuart Jansen <sjansen@buscaluz.org>
-rw-r--r--plumbing/format/diff/unified_encoder.go23
-rw-r--r--plumbing/format/diff/unified_encoder_test.go90
-rw-r--r--utils/diff/diff_ext_test.go31
3 files changed, 114 insertions, 30 deletions
diff --git a/plumbing/format/diff/unified_encoder.go b/plumbing/format/diff/unified_encoder.go
index 169242d..ce3bc7c 100644
--- a/plumbing/format/diff/unified_encoder.go
+++ b/plumbing/format/diff/unified_encoder.go
@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"io"
+ "regexp"
"strings"
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -25,9 +26,10 @@ const (
tPath = "+++ %s\n"
binary = "Binary files %s and %s differ\n"
- addLine = "+%s\n"
- deleteLine = "-%s\n"
- equalLine = " %s\n"
+ addLine = "+%s%s"
+ deleteLine = "-%s%s"
+ equalLine = " %s%s"
+ noNewLine = "\n\\ No newline at end of file\n"
oldMode = "old mode %o\n"
newMode = "new mode %o\n"
@@ -216,7 +218,7 @@ func (c *hunksGenerator) processHunk(i int, op Operation) {
linesBefore = c.ctxLines
}
- c.current = &hunk{ctxPrefix: ctxPrefix}
+ c.current = &hunk{ctxPrefix: strings.TrimSuffix(ctxPrefix, "\n")}
c.current.AddOp(Equal, c.beforeContext...)
switch op {
@@ -279,12 +281,13 @@ func (c *hunksGenerator) processEqualsLines(ls []string, i int) {
}
}
+var splitLinesRE = regexp.MustCompile(`[^\n]*(\n|$)`)
+
func splitLines(s string) []string {
- out := strings.Split(s, "\n")
+ out := splitLinesRE.FindAllString(s, -1)
if out[len(out)-1] == "" {
out = out[:len(out)-1]
}
-
return out
}
@@ -346,7 +349,7 @@ type op struct {
}
func (o *op) String() string {
- var prefix string
+ var prefix, suffix string
switch o.t {
case Add:
prefix = addLine
@@ -355,6 +358,10 @@ func (o *op) String() string {
case Equal:
prefix = equalLine
}
+ n := len(o.text)
+ if n > 0 && o.text[n-1] != '\n' {
+ suffix = noNewLine
+ }
- return fmt.Sprintf(prefix, o.text)
+ return fmt.Sprintf(prefix, o.text, suffix)
}
diff --git a/plumbing/format/diff/unified_encoder_test.go b/plumbing/format/diff/unified_encoder_test.go
index 7736af1..091a96a 100644
--- a/plumbing/format/diff/unified_encoder_test.go
+++ b/plumbing/format/diff/unified_encoder_test.go
@@ -83,7 +83,7 @@ var oneChunkPatch Patch = testPatch{
content: "A\n",
op: Delete,
}, {
- content: "B\nC\nD\nE\nF\nG",
+ content: "B\nC\nD\nE\nF\nG\n",
op: Equal,
}, {
content: "H\n",
@@ -125,7 +125,7 @@ var oneChunkPatchInverted Patch = testPatch{
content: "A\n",
op: Add,
}, {
- content: "B\nC\nD\nE\nF\nG",
+ content: "B\nC\nD\nE\nF\nG\n",
op: Equal,
}, {
content: "H\n",
@@ -164,13 +164,13 @@ var fixtures []*fixture = []*fixture{{
seed: "hello\nbug\n",
},
chunks: []testChunk{{
- content: "hello",
+ content: "hello\n",
op: Equal,
}, {
- content: "world",
+ content: "world\n",
op: Delete,
}, {
- content: "bug",
+ content: "bug\n",
op: Add,
}},
}},
@@ -239,18 +239,18 @@ rename to test1.txt
from: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test",
+ seed: "test\n",
},
to: &testFile{
mode: filemode.Regular,
path: "test1.txt",
- seed: "test1",
+ seed: "test1\n",
},
chunks: []testChunk{{
- content: "test",
+ content: "test\n",
op: Delete,
}, {
- content: "test1",
+ content: "test1\n",
op: Add,
}},
}},
@@ -260,7 +260,7 @@ rename to test1.txt
diff: `diff --git a/test.txt b/test1.txt
rename from test.txt
rename to test1.txt
-index 30d74d258442c7c65512eafab474568dd706c430..f079749c42ffdcc5f52ed2d3a6f15b09307e975e 100644
+index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..a5bce3fd2565d8f458555a0c6f42d0504a848bd5 100644
--- a/test.txt
+++ b/test1.txt
@@ -1 +1 @@
@@ -299,19 +299,19 @@ rename to test1.txt
from: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test",
+ seed: "test\n",
},
to: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test2",
+ seed: "test2\n",
},
chunks: []testChunk{{
- content: "test",
+ content: "test\n",
op: Delete,
}, {
- content: "test2",
+ content: "test2\n",
op: Add,
}},
}},
@@ -320,7 +320,7 @@ rename to test1.txt
desc: "one line change",
context: 1,
diff: `diff --git a/test.txt b/test.txt
-index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d55b2ae9d 100644
+index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..180cf8328022becee9aaa2577a8f84ea2b9f3827 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
@@ -334,19 +334,19 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
from: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test",
+ seed: "test\n",
},
to: &testFile{
mode: filemode.Regular,
path: "test.txt",
- seed: "test2",
+ seed: "test2\n",
},
chunks: []testChunk{{
- content: "test",
+ content: "test\n",
op: Delete,
}, {
- content: "test2",
+ content: "test2\n",
op: Add,
}},
}},
@@ -356,7 +356,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
context: 1,
diff: `this is the message
diff --git a/test.txt b/test.txt
-index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d55b2ae9d 100644
+index 9daeafb9864cf43055ae93beb0afd6c7d144bfa4..180cf8328022becee9aaa2577a8f84ea2b9f3827 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
@@ -397,7 +397,9 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
+++ b/test.txt
@@ -1 +1 @@
-test
+\ No newline at end of file
+test2
+\ No newline at end of file
`,
}, {
patch: testPatch{
@@ -407,7 +409,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
to: &testFile{
mode: filemode.Regular,
path: "new.txt",
- seed: "test\ntest2\test3",
+ seed: "test\ntest2\ntest3",
},
chunks: []testChunk{{
@@ -421,13 +423,14 @@ index 30d74d258442c7c65512eafab474568dd706c430..d606037cb232bfda7788a8322492312d
context: 1,
diff: `diff --git a/new.txt b/new.txt
new file mode 100644
-index 0000000000000000000000000000000000000000..65c8dd02a42273038658a22b1cb29c8d9457ca12
+index 0000000000000000000000000000000000000000..3ceaab5442b64a0c2b33dd25fae67ccdb4fd1ea8
--- /dev/null
+++ b/new.txt
@@ -0,0 +1,3 @@
+test
+test2
+test3
+\ No newline at end of file
`,
}, {
patch: testPatch{
@@ -456,6 +459,7 @@ index 30d74d258442c7c65512eafab474568dd706c430..00000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-test
+\ No newline at end of file
`,
}, {
patch: oneChunkPatch,
@@ -548,6 +552,7 @@ index ab5eed5d4a2c33aeef67e0188ee79bed666bde6f..0adddcde4fd38042c354518351820eb0
X
Y
Z
+\ No newline at end of file
`,
}, {
patch: oneChunkPatch,
@@ -813,6 +818,47 @@ index 0adddcde4fd38042c354518351820eb06c417c82..553ae669c7a9303cf848fcc749a25692
+++ b/onechunk.txt
@@ -23 +22,0 @@ Y
-Z
+\ No newline at end of file
+`,
+}, {
+ patch: testPatch{
+ message: "",
+ filePatches: []testFilePatch{{
+ from: &testFile{
+ mode: filemode.Regular,
+ path: "onechunk.txt",
+ seed: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ",
+ },
+ to: &testFile{
+ mode: filemode.Regular,
+ path: "onechunk.txt",
+ seed: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY",
+ },
+
+ chunks: []testChunk{{
+ content: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\n",
+ op: Equal,
+ }, {
+ content: "Y\nZ",
+ op: Delete,
+ }, {
+ content: "Y",
+ op: Add,
+ }},
+ }},
+ },
+ desc: "remove last letter and no newline at end of file",
+ context: 0,
+ diff: `diff --git a/onechunk.txt b/onechunk.txt
+index 0adddcde4fd38042c354518351820eb06c417c82..d39ae38aad7ba9447b5e7998b2e4714f26c9218d 100644
+--- a/onechunk.txt
++++ b/onechunk.txt
+@@ -22,2 +21 @@ X
+-Y
+-Z
+\ No newline at end of file
++Y
+\ No newline at end of file
`,
}}
diff --git a/utils/diff/diff_ext_test.go b/utils/diff/diff_ext_test.go
index adda276..c6c7e90 100644
--- a/utils/diff/diff_ext_test.go
+++ b/utils/diff/diff_ext_test.go
@@ -99,6 +99,37 @@ var doTests = [...]struct {
{Type: 1, Text: "111\nBCD\n"},
},
},
+ {
+ src: "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nÑ\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ",
+ dst: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ",
+ exp: []diffmatchpatch.Diff{
+ {Type: -1, Text: "A\n"},
+ {Type: 0, Text: "B\nC\nD\nE\nF\nG\n"},
+ {Type: -1, Text: "H\n"},
+ {Type: 0, Text: "I\nJ\nK\nL\nM\nN\n"},
+ {Type: -1, Text: "Ñ\n"},
+ {Type: 0, Text: "O\nP\nQ\nR\nS\nT\n"},
+ {Type: -1, Text: "U\n"},
+ {Type: 0, Text: "V\nW\nX\nY\nZ"},
+ },
+ },
+ {
+ src: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ",
+ dst: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\n",
+ exp: []diffmatchpatch.Diff{
+ {Type: 0, Text: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\n"},
+ {Type: -1, Text: "Z"},
+ },
+ },
+ {
+ src: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY\nZ",
+ dst: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\nY",
+ exp: []diffmatchpatch.Diff{
+ {Type: 0, Text: "B\nC\nD\nE\nF\nG\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nV\nW\nX\n"},
+ {Type: -1, Text: "Y\nZ"},
+ {Type: 1, Text: "Y"},
+ },
+ },
}
func (s *suiteCommon) TestDo(c *C) {