@@ -10,22 +10,24 @@ import (
10
10
"time"
11
11
)
12
12
13
- // ParseMultiFileDiff parses a multi-file unified diff.
13
+ // ParseMultiFileDiff parses a multi-file unified diff. It returns an error if parsing failed as a whole, but does its
14
+ // best to parse as many files in the case of per-file errors. In the case of non-fatal per-file errors, the error
15
+ // return value is null and the Errs field in the returned MultiFileDiff is set.
14
16
func ParseMultiFileDiff (diff []byte ) ([]* FileDiff , error ) {
15
17
return NewMultiFileDiffReader (bytes .NewReader (diff )).ReadAllFiles ()
16
18
}
17
19
18
20
// NewMultiFileDiffReader returns a new MultiFileDiffReader that reads
19
21
// a multi-file unified diff from r.
20
22
func NewMultiFileDiffReader (r io.Reader ) * MultiFileDiffReader {
21
- return & MultiFileDiffReader {scanner : bufio .NewScanner (r )}
23
+ return & MultiFileDiffReader {reader : bufio .NewReader (r )}
22
24
}
23
25
24
26
// MultiFileDiffReader reads a multi-file unified diff.
25
27
type MultiFileDiffReader struct {
26
- line int
27
- offset int64
28
- scanner * bufio.Scanner
28
+ line int
29
+ offset int64
30
+ reader * bufio.Reader
29
31
30
32
// TODO(sqs): line and offset tracking in multi-file diffs is broken; add tests and fix
31
33
@@ -44,7 +46,7 @@ func (r *MultiFileDiffReader) ReadFile() (*FileDiff, error) {
44
46
fr := & FileDiffReader {
45
47
line : r .line ,
46
48
offset : r .offset ,
47
- scanner : r . scanner ,
49
+ reader : r . reader ,
48
50
fileHeaderLine : r .nextFileFirstLine ,
49
51
}
50
52
r .nextFileFirstLine = nil
@@ -66,11 +68,11 @@ func (r *MultiFileDiffReader) ReadFile() (*FileDiff, error) {
66
68
// caused by the lack of any hunks, or a malformatted hunk, so we
67
69
// need to perform the check here.
68
70
hr := fr .HunksReader ()
69
- ok := r .scanner . Scan ( )
70
- if ! ok {
71
- return d , r . scanner . Err ()
71
+ line , err := r .reader . ReadBytes ( '\n' )
72
+ if err != nil && ! ( err == io . EOF && len ( line ) > 0 ) {
73
+ return d , err
72
74
}
73
- line := r . scanner . Bytes ( )
75
+ line = bytes . TrimSuffix ( line , [] byte { '\n' } )
74
76
if bytes .HasPrefix (line , hunkPrefix ) {
75
77
hr .nextHunkHeaderLine = line
76
78
d .Hunks , err = hr .ReadAllHunks ()
@@ -122,14 +124,14 @@ func ParseFileDiff(diff []byte) (*FileDiff, error) {
122
124
// NewFileDiffReader returns a new FileDiffReader that reads a file
123
125
// unified diff.
124
126
func NewFileDiffReader (r io.Reader ) * FileDiffReader {
125
- return & FileDiffReader {scanner : bufio .NewScanner (r )}
127
+ return & FileDiffReader {reader : bufio .NewReader (r )}
126
128
}
127
129
128
130
// FileDiffReader reads a unified file diff.
129
131
type FileDiffReader struct {
130
- line int
131
- offset int64
132
- scanner * bufio.Scanner
132
+ line int
133
+ offset int64
134
+ reader * bufio.Reader
133
135
134
136
// fileHeaderLine is the first file header line, set by:
135
137
//
@@ -184,9 +186,9 @@ func (r *FileDiffReader) ReadAllHeaders() (*FileDiff, error) {
184
186
// correct position information).
185
187
func (r * FileDiffReader ) HunksReader () * HunksReader {
186
188
return & HunksReader {
187
- line : r .line ,
188
- offset : r .offset ,
189
- scanner : r .scanner ,
189
+ line : r .line ,
190
+ offset : r .offset ,
191
+ reader : r .reader ,
190
192
}
191
193
}
192
194
@@ -213,14 +215,16 @@ func (r *FileDiffReader) readOneFileHeader(prefix []byte) (filename string, time
213
215
var line []byte
214
216
215
217
if r .fileHeaderLine == nil {
216
- ok := r .scanner .Scan ()
217
- if ! ok {
218
- return "" , nil , & ParseError {r .line , r .offset , ErrNoFileHeader }
219
- }
220
- if err := r .scanner .Err (); err != nil {
218
+ var err error
219
+ line , err = r .reader .ReadBytes ('\n' )
220
+ if err == io .EOF {
221
+ if len (line ) == 0 {
222
+ return "" , nil , & ParseError {r .line , r .offset , ErrNoFileHeader }
223
+ }
224
+ } else if err != nil {
221
225
return "" , nil , err
222
226
}
223
- line = r . scanner . Bytes ( )
227
+ line = bytes . TrimSuffix ( line , [] byte { '\n' } )
224
228
} else {
225
229
line = r .fileHeaderLine
226
230
r .fileHeaderLine = nil
@@ -258,14 +262,16 @@ func (r *FileDiffReader) ReadExtendedHeaders() ([]string, error) {
258
262
for {
259
263
var line []byte
260
264
if r .fileHeaderLine == nil {
261
- ok := r .scanner .Scan ()
262
- if ! ok {
263
- return xheaders , & ParseError {r .line , r .offset , ErrExtendedHeadersEOF }
264
- }
265
- if err := r .scanner .Err (); err != nil {
265
+ var err error
266
+ line , err = r .reader .ReadBytes ('\n' )
267
+ if err == io .EOF {
268
+ if len (line ) == 0 {
269
+ return xheaders , & ParseError {r .line , r .offset , ErrExtendedHeadersEOF }
270
+ }
271
+ } else if err != nil {
266
272
return xheaders , err
267
273
}
268
- line = r . scanner . Bytes ( )
274
+ line = bytes . TrimSuffix ( line , [] byte { '\n' } )
269
275
} else {
270
276
line = r .fileHeaderLine
271
277
r .fileHeaderLine = nil
@@ -311,15 +317,15 @@ func ParseHunks(diff []byte) ([]*Hunk, error) {
311
317
// NewHunksReader returns a new HunksReader that reads unified diff hunks
312
318
// from r.
313
319
func NewHunksReader (r io.Reader ) * HunksReader {
314
- return & HunksReader {scanner : bufio .NewScanner (r )}
320
+ return & HunksReader {reader : bufio .NewReader (r )}
315
321
}
316
322
317
323
// A HunksReader reads hunks from a unified diff.
318
324
type HunksReader struct {
319
- line int
320
- offset int64
321
- hunk * Hunk
322
- scanner * bufio.Scanner
325
+ line int
326
+ offset int64
327
+ hunk * Hunk
328
+ reader * bufio.Reader
323
329
324
330
nextHunkHeaderLine []byte
325
331
}
@@ -330,18 +336,22 @@ func (r *HunksReader) ReadHunk() (*Hunk, error) {
330
336
r .hunk = nil
331
337
lastLineFromOrig := true
332
338
var line []byte
339
+ var err error
333
340
for {
334
341
if r .nextHunkHeaderLine != nil {
335
342
// Use stored hunk header line that was scanned in at the
336
343
// completion of the previous hunk's ReadHunk.
337
344
line = r .nextHunkHeaderLine
338
345
r .nextHunkHeaderLine = nil
339
346
} else {
340
- ok := r .scanner .Scan ()
341
- if ! ok {
342
- break
347
+ line , err = r .reader .ReadBytes ('\n' )
348
+ if err != nil {
349
+ if err == io .EOF && r .hunk != nil {
350
+ return r .hunk , nil
351
+ }
352
+ return nil , err
343
353
}
344
- line = r . scanner . Bytes ( )
354
+ line = bytes . TrimSuffix ( line , [] byte { '\n' } )
345
355
}
346
356
347
357
// Record position.
@@ -422,9 +432,6 @@ func (r *HunksReader) ReadHunk() (*Hunk, error) {
422
432
r .hunk .Body = append (r .hunk .Body , '\n' )
423
433
}
424
434
}
425
- if err := r .scanner .Err (); err != nil {
426
- return nil , err
427
- }
428
435
429
436
// Final hunk is complete. But if we never saw a hunk in this call to ReadHunk, then it means we hit EOF.
430
437
if r .hunk != nil {
0 commit comments