···11+package gitdiff
22+33+// File describes changes to a single file. It can be either a text file or a
44+// binary file.
55+type File struct {
66+ Fragments []*Fragment
77+}
88+99+// Fragment describes changed lines starting at a specific line in a text file.
1010+type Fragment struct{}
+80
gitdiff/parser.go
···11+package gitdiff
22+33+import (
44+ "bufio"
55+ "fmt"
66+ "io"
77+)
88+99+// Parse parses a patch with changes for one or more files. Any content
1010+// preceding the first file header is ignored. If an error occurs while
1111+// parsing, files will contain all files parsed before the error.
1212+func Parse(r io.Reader) (files []*File, err error) {
1313+ p := &parser{r: bufio.NewReader(r)}
1414+1515+ var file *File
1616+ for {
1717+ file, err = p.ParseNextFileHeader()
1818+ if err != nil {
1919+ return
2020+ }
2121+ if file == nil {
2222+ break
2323+ }
2424+2525+ err = p.ParseFileChanges(file)
2626+ if err != nil {
2727+ return
2828+ }
2929+3030+ files = append(files, file)
3131+ }
3232+3333+ return files, nil
3434+}
3535+3636+type parser struct {
3737+ r *bufio.Reader
3838+ lineno int64
3939+ nextLine string
4040+}
4141+4242+// ParseNextFileHeader finds and parses the next file header in the stream. It
4343+// returns nil if no headers are found before the end of the stream.
4444+func (p *parser) ParseNextFileHeader() (*File, error) {
4545+ panic("unimplemented")
4646+}
4747+4848+// ParseFileChanges parses file changes until the next file header or the end
4949+// of the stream and attaches them to the given file.
5050+func (p *parser) ParseFileChanges(f *File) error {
5151+ panic("unimplemented")
5252+}
5353+5454+// Line reads and returns the next line.
5555+func (p *parser) Line() (line string, err error) {
5656+ if p.nextLine != "" {
5757+ line = p.nextLine
5858+ p.nextLine = ""
5959+ } else {
6060+ line, err = p.r.ReadString('\n')
6161+ }
6262+ p.lineno++
6363+ return
6464+}
6565+6666+// PeekLine reads and returns the next line without advancing the parser.
6767+func (p *parser) PeekLine() (line string, err error) {
6868+ if p.nextLine != "" {
6969+ line = p.nextLine
7070+ } else {
7171+ line, err = p.r.ReadString('\n')
7272+ }
7373+ p.nextLine = line
7474+ return
7575+}
7676+7777+// Errorf generates an error and appends the current line information.
7878+func (p *parser) Errorf(msg string, args ...interface{}) error {
7979+ return fmt.Errorf("gitdiff: line %d: %s", p.lineno, fmt.Sprintf(msg, args...))
8080+}