Skip to content

Commit 45f0055

Browse files
committed
Fix parsing of non-extended file headers and lines starting with --
This fixes #54 by making the detection of non-extended file headers (which start with `---` directly) that was introduced in #53 more robust. Instead of simply aborting when the current line starts with `---` (which is a valid hunk line, if you, say, remove a line starting with `--`), we confirm that the next line also starts with `+++` by peeking a bit ahead. That's also what `git` does: https://sourcegraph.com/github.com/git/git/-/blob/apply.c#L1574-1576
1 parent 96789e3 commit 45f0055

File tree

3 files changed

+33
-3
lines changed

3 files changed

+33
-3
lines changed

diff/diff_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ func TestParseHunksAndPrintHunks(t *testing.T) {
7373
{filename: "empty_new.diff"},
7474
{filename: "oneline_hunk.diff"},
7575
{filename: "empty.diff"},
76+
{filename: "sample_hunk_lines_start_with_minuses.diff"},
7677
}
7778
for _, test := range tests {
7879
diffData, err := ioutil.ReadFile(filepath.Join("testdata", test.filename))

diff/parse.go

+27-3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ func (r *MultiFileDiffReader) ReadFile() (*FileDiff, error) {
6161
if e.Err == ErrNoFileHeader || e.Err == ErrExtendedHeadersEOF {
6262
return nil, io.EOF
6363
}
64+
return nil, err
6465

6566
case OverflowError:
6667
r.nextFileFirstLine = []byte(e)
@@ -513,9 +514,22 @@ func (r *HunksReader) ReadHunk() (*Hunk, error) {
513514
r.hunk.Section = section
514515
} else {
515516
// Read hunk body line.
517+
518+
// If the line starts with `---` and the next one with `+++` we're
519+
// looking at a non-extended file header and need to abort.
520+
if bytes.HasPrefix(line, []byte("---")) {
521+
ok, err := nextLineHasPrefix(r.reader, []byte("+++"))
522+
if err != nil {
523+
return r.hunk, err
524+
}
525+
if ok {
526+
return r.hunk, &ParseError{r.line, r.offset, &ErrBadHunkLine{Line: line}}
527+
}
528+
}
529+
530+
// If the line starts with the hunk prefix, this hunk is complete.
516531
if bytes.HasPrefix(line, hunkPrefix) {
517-
// Saw start of new hunk, so this hunk is
518-
// complete. But we've already read in the next hunk's
532+
// But we've already read in the next hunk's
519533
// header, so we need to be sure that the next call to
520534
// ReadHunk starts with that header.
521535
r.nextHunkHeaderLine = line
@@ -527,7 +541,7 @@ func (r *HunksReader) ReadHunk() (*Hunk, error) {
527541
return r.hunk, nil
528542
}
529543

530-
if len(line) >= 1 && (!linePrefix(line[0]) || bytes.HasPrefix(line, []byte("--- "))) {
544+
if len(line) >= 1 && !linePrefix(line[0]) {
531545
// Bad hunk header line. If we're reading a multi-file
532546
// diff, this may be the end of the current
533547
// file. Return a "rich" error that lets our caller
@@ -579,6 +593,16 @@ func linePrefix(c byte) bool {
579593
return false
580594
}
581595

596+
// nextLineHasPrefix peeks into the given reader to check whether the next
597+
// bytes match the given prefix.
598+
func nextLineHasPrefix(reader *bufio.Reader, prefix []byte) (bool, error) {
599+
next, err := reader.Peek(len(prefix))
600+
if err != nil {
601+
return false, err
602+
}
603+
return bytes.HasPrefix(next, prefix), nil
604+
}
605+
582606
// normalizeHeader takes a header of the form:
583607
// "@@ -linestart[,chunksize] +linestart[,chunksize] @@ section"
584608
// and returns two strings, with the first in the form:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@@ -1,4 +1,3 @@
2+
select 1;
3+
--- this is my query
4+
select 2;
5+
select 3;

0 commit comments

Comments
 (0)