From 42914c81df5d742efd98d951a0cc3806a1249c8b Mon Sep 17 00:00:00 2001 From: Billy Keyes Date: Sun, 10 Mar 2019 21:48:59 -0700 Subject: [PATCH] Create parser skeleton and utilities --- gitdiff/gitdiff.go | 10 ++++++ gitdiff/parser.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 gitdiff/gitdiff.go create mode 100644 gitdiff/parser.go 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...)) +}