this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Restructure fragment parsing to support binary

Binary patch support is still unimplemented, but the functions are
stubbed and the overall structure seems to make sense. This also renames
the existing fragment functions to have "Text" in their names (for
clarity) and moves the parsing of fragment lines to a new "chunk"
function, which will match how binary parsing works.

+41 -37
+37 -33
gitdiff/parser.go
··· 30 30 break 31 31 } 32 32 33 - if err = p.ParseFragments(file); err != nil { 34 - return files, err 33 + for _, fn := range []func(*File) (int, error){ 34 + p.ParseTextFragments, 35 + p.ParseBinaryFragment, 36 + } { 37 + n, err := fn(file) 38 + if err != nil { 39 + return files, err 40 + } 41 + if n > 0 { 42 + break 43 + } 35 44 } 36 - 45 + // file has fragment(s) from above or the patch is empty or invalid 37 46 files = append(files, file) 38 47 } 39 48 ··· 66 75 var file *File 67 76 for { 68 77 // check for disconnected fragment headers (corrupt patch) 69 - frag, err := p.ParseFragmentHeader() 78 + frag, err := p.ParseTextFragmentHeader() 70 79 if err != nil { 71 80 // not a valid header, nothing to worry about 72 81 goto NextLine ··· 104 113 return nil, nil 105 114 } 106 115 107 - // ParseFragments parses fragments until the next file header or the end of the 108 - // stream and attaches them to the given file. 109 - func (p *parser) ParseFragments(f *File) error { 116 + // ParseTextFragments parses text fragments until the next file header or the 117 + // end of the stream and attaches them to the given file. It returns the number 118 + // of fragments that were added. 119 + func (p *parser) ParseTextFragments(f *File) (n int, err error) { 110 120 for { 111 - frag, err := p.ParseFragment() 121 + frag, err := p.ParseTextFragmentHeader() 112 122 if err != nil { 113 - return err 123 + return n, err 114 124 } 115 125 if frag == nil { 116 - // TODO(bkeyes): this could mean several things: 117 - // - binary patch 118 - // - reached the next file header 119 - // - reached the end of the patch 120 - return nil 126 + return n, nil 121 127 } 122 128 123 - lines := int64(len(frag.Lines) + 1) // +1 for the header 124 129 if f.IsNew && frag.OldLines > 0 { 125 - return p.Errorf(-lines, "new file depends on old contents") 130 + return n, p.Errorf(-1, "new file depends on old contents") 126 131 } 127 132 if f.IsDelete && frag.NewLines > 0 { 128 - return p.Errorf(-lines, "deleted file still has contents") 133 + return n, p.Errorf(-1, "deleted file still has contents") 134 + } 135 + 136 + if err := p.ParseTextChunk(frag); err != nil { 137 + return n, nil 129 138 } 130 139 131 140 f.Fragments = append(f.Fragments, frag) 141 + n++ 132 142 } 133 143 } 134 144 ··· 182 192 return fmt.Errorf("gitdiff: line %d: %s", p.lineno+delta, fmt.Sprintf(msg, args...)) 183 193 } 184 194 185 - func (p *parser) ParseFragmentHeader() (*Fragment, error) { 195 + func (p *parser) ParseTextFragmentHeader() (*Fragment, error) { 186 196 const ( 187 197 startMark = "@@ -" 188 198 endMark = " @@" ··· 220 230 return f, nil 221 231 } 222 232 223 - func (p *parser) ParseFragment() (*Fragment, error) { 224 - frag, err := p.ParseFragmentHeader() 225 - if err != nil { 226 - return nil, err 227 - } 228 - if frag == nil { 229 - return nil, nil 230 - } 233 + func (p *parser) ParseTextChunk(frag *Fragment) error { 231 234 if p.Line(0) == "" { 232 - return nil, p.Errorf(0, "no content following fragment header") 235 + return p.Errorf(0, "no content following fragment header") 233 236 } 234 237 235 238 oldLines, newLines := frag.OldLines, frag.NewLines ··· 250 253 case '-': 251 254 frag.LinesDeleted++ 252 255 oldLines-- 253 - frag.TrailingContext = 0 254 256 frag.Lines = append(frag.Lines, FragmentLine{OpDelete, line[1:]}) 255 257 case '+': 256 258 frag.LinesAdded++ 257 259 newLines-- 258 - frag.TrailingContext = 0 259 260 frag.Lines = append(frag.Lines, FragmentLine{OpAdd, line[1:]}) 260 261 default: 261 262 // this could be "\ No newline at end of file", which we allow ··· 264 265 if len(line) >= 12 && strings.HasPrefix("\\ ", line) { 265 266 break 266 267 } 267 - return nil, p.Errorf(0, "invalid fragment line") 268 + return p.Errorf(0, "invalid fragment line") 268 269 } 269 270 270 271 if err := p.Next(); err != nil { 271 272 if err == io.EOF { 272 273 break 273 274 } 274 - return nil, err 275 + return err 275 276 } 276 277 } 277 278 278 279 if oldLines != 0 || newLines != 0 { 279 - return nil, p.Errorf(0, "invalid fragment: remaining lines: %d old, %d new", oldLines, newLines) 280 + return p.Errorf(0, "invalid fragment: remaining lines: %d old, %d new", oldLines, newLines) 280 281 } 282 + return nil 283 + } 281 284 282 - return frag, nil 285 + func (p *parser) ParseBinaryFragment(f *File) (n int, err error) { 286 + panic("TODO(bkeyes): unimplemented") 283 287 } 284 288 285 289 func parseRange(s string) (start int64, end int64, err error) {
+4 -4
gitdiff/parser_test.go
··· 105 105 }, 106 106 EndLine: "@@ -1,2 +1,3 @@\n", 107 107 }, 108 - "ParseFragmentHeader": { 108 + "ParseTextFragmentHeader": { 109 109 Input: `@@ -1,2 +1,3 @@ 110 110 context line 111 111 `, 112 112 Parse: func(p *parser) error { 113 - _, err := p.ParseFragmentHeader() 113 + _, err := p.ParseTextFragmentHeader() 114 114 return err 115 115 }, 116 116 EndLine: "context line\n", ··· 133 133 } 134 134 } 135 135 136 - func TestParseFragmentHeader(t *testing.T) { 136 + func TestParseTextFragmentHeader(t *testing.T) { 137 137 tests := map[string]struct { 138 138 Input string 139 139 Output *Fragment ··· 182 182 p := &parser{r: bufio.NewReader(strings.NewReader(test.Input))} 183 183 p.Next() 184 184 185 - frag, err := p.ParseFragmentHeader() 185 + frag, err := p.ParseTextFragmentHeader() 186 186 if test.Err { 187 187 if err == nil { 188 188 t.Fatalf("expected error parsing header, but got nil")