diff --git a/gitdiff/gitdiff.go b/gitdiff/gitdiff.go new file mode 100644 index 0000000..b1c5d4c --- /dev/null +++ b/gitdiff/gitdiff.go @@ -0,0 +1,10 @@ +package gitdiff + +// File describes changes to a single file. It can be either a text file or a +// binary file. +type File struct { + Fragments []*Fragment +} + +// Fragment describes changed lines starting at a specific line in a text file. +type Fragment struct{} diff --git a/gitdiff/parser.go b/gitdiff/parser.go new file mode 100644 index 0000000..7a85fd5 --- /dev/null +++ b/gitdiff/parser.go @@ -0,0 +1,80 @@ +package gitdiff + +import ( + "bufio" + "fmt" + "io" +) + +// Parse parses a patch with changes for one or more files. Any content +// preceding the first file header is ignored. If an error occurs while +// parsing, files will contain all files parsed before the error. +func Parse(r io.Reader) (files []*File, err error) { + p := &parser{r: bufio.NewReader(r)} + + var file *File + for { + file, err = p.ParseNextFileHeader() + if err != nil { + return + } + if file == nil { + break + } + + err = p.ParseFileChanges(file) + if err != nil { + return + } + + files = append(files, file) + } + + return files, nil +} + +type parser struct { + r *bufio.Reader + lineno int64 + nextLine string +} + +// ParseNextFileHeader finds and parses the next file header in the stream. It +// returns nil if no headers are found before the end of the stream. +func (p *parser) ParseNextFileHeader() (*File, error) { + panic("unimplemented") +} + +// ParseFileChanges parses file changes until the next file header or the end +// of the stream and attaches them to the given file. +func (p *parser) ParseFileChanges(f *File) error { + panic("unimplemented") +} + +// Line reads and returns the next line. +func (p *parser) Line() (line string, err error) { + if p.nextLine != "" { + line = p.nextLine + p.nextLine = "" + } else { + line, err = p.r.ReadString('\n') + } + p.lineno++ + return +} + +// PeekLine reads and returns the next line without advancing the parser. +func (p *parser) PeekLine() (line string, err error) { + if p.nextLine != "" { + line = p.nextLine + } else { + line, err = p.r.ReadString('\n') + } + p.nextLine = line + return +} + +// Errorf generates an error and appends the current line information. +func (p *parser) Errorf(msg string, args ...interface{}) error { + return fmt.Errorf("gitdiff: line %d: %s", p.lineno, fmt.Sprintf(msg, args...)) +}