internal/git/rawdiff/rawdiff.go (54 lines of code) (raw):

package rawdiff import ( "bufio" "fmt" "io" ) // Diff represents a `git diff --raw` entry. type Diff struct { // The naming of the fields below follows the "RAW DIFF FORMAT" of `git // diff`. SrcMode string DstMode string SrcSHA string DstSHA string Status string SrcPath string DstPath string // optional! } // Parser is a parser for the "-z" variant of the "RAW DIFF FORMAT" // documented in `git help diff`. type Parser struct { r *bufio.Reader } // NewParser returns a new Parser instance. The reader must contain // output from `git diff --raw -z`. func NewParser(r io.Reader) *Parser { return &Parser{r: bufio.NewReader(r)} } // NextDiff returns the next raw diff. If there are no more diffs, the // error is io.EOF. func (p *Parser) NextDiff() (*Diff, error) { c, err := p.r.ReadByte() if err != nil { return nil, err } if c != ':' { return nil, fmt.Errorf("expected leading colon in raw diff line") } d := &Diff{} for _, field := range []*string{&d.SrcMode, &d.DstMode, &d.SrcSHA, &d.DstSHA} { if *field, err = p.readStringChop(' '); err != nil { return nil, err } } for _, field := range []*string{&d.Status, &d.SrcPath} { if *field, err = p.readStringChop(0); err != nil { return nil, err } } if len(d.Status) > 0 && (d.Status[0] == 'C' || d.Status[0] == 'R') { if d.DstPath, err = p.readStringChop(0); err != nil { return nil, err } } return d, nil } // readStringChop combines bufio.Reader.ReadString with removing the // trailing delimiter. func (p *Parser) readStringChop(delim byte) (string, error) { s, err := p.r.ReadString(delim) if err != nil { return "", fmt.Errorf("read raw diff: %w", err) } return s[:len(s)-1], nil }