Allow diff.ForEach to enumerate files, hunks, and lines with single call. Support use of closures for enumeration.

This commit is contained in:
Jesse Ezell 2014-03-21 17:20:48 -07:00
parent aea899e877
commit f85c38ce22
2 changed files with 88 additions and 45 deletions

78
diff.go
View File

@ -151,22 +151,34 @@ func (diff *Diff) Free() error {
return nil return nil
} }
type DiffForEachFileCallback func(*DiffDelta) error type diffForEachData struct {
FileCallback DiffForEachFileCallback
type diffForEachFileData struct { HunkCallback DiffForEachHunkCallback
Callback DiffForEachFileCallback LineCallback DiffForEachLineCallback
Error error Error error
} }
func (diff *Diff) ForEachFile(cb DiffForEachFileCallback) error { type DiffForEachFileCallback func(*DiffDelta, float64) (DiffForEachHunkCallback, error)
func (diff *Diff) ForEach(cbFile DiffForEachFileCallback, diffHunks bool, diffLines bool) error {
if diff.ptr == nil { if diff.ptr == nil {
return ErrInvalid return ErrInvalid
} }
data := &diffForEachFileData{ intHunks := C.int(0)
Callback: cb, if diffHunks {
intHunks = C.int(1)
} }
ecode := C._go_git_diff_foreach(diff.ptr, 1, 0, 0, unsafe.Pointer(data))
intLines := C.int(0)
if diffLines {
intLines = C.int(1)
}
data := &diffForEachData{
FileCallback: cbFile,
}
ecode := C._go_git_diff_foreach(diff.ptr, 1, intHunks, intLines, unsafe.Pointer(data))
if ecode < 0 { if ecode < 0 {
return data.Error return data.Error
} }
@ -175,32 +187,37 @@ func (diff *Diff) ForEachFile(cb DiffForEachFileCallback) error {
//export diffForEachFileCb //export diffForEachFileCb
func diffForEachFileCb(delta *C.git_diff_delta, progress C.float, payload unsafe.Pointer) int { func diffForEachFileCb(delta *C.git_diff_delta, progress C.float, payload unsafe.Pointer) int {
data := (*diffForEachFileData)(payload) data := (*diffForEachData)(payload)
err := data.Callback(newDiffDeltaFromC(delta)) data.HunkCallback = nil
if data.FileCallback != nil {
cb, err := data.FileCallback(newDiffDeltaFromC(delta), float64(progress))
if err != nil { if err != nil {
data.Error = err data.Error = err
return -1 return -1
} }
data.HunkCallback = cb
}
return 0 return 0
} }
type diffForEachHunkData struct { type DiffForEachHunkCallback func(*DiffHunk) (DiffForEachLineCallback, error)
Callback DiffForEachHunkCallback
Error error
}
type DiffForEachHunkCallback func(*DiffHunk) error func (diff *Diff) ForEachHunk(cb DiffForEachHunkCallback, diffLines bool) error {
func (diff *Diff) ForEachHunk(cb DiffForEachHunkCallback) error {
if diff.ptr == nil { if diff.ptr == nil {
return ErrInvalid return ErrInvalid
} }
data := &diffForEachHunkData{ data := &diffForEachData{
Callback: cb, HunkCallback: cb,
} }
ecode := C._go_git_diff_foreach(diff.ptr, 0, 1, 0, unsafe.Pointer(data))
intLines := C.int(0)
if diffLines {
intLines = C.int(1)
}
ecode := C._go_git_diff_foreach(diff.ptr, 0, 1, intLines, unsafe.Pointer(data))
if ecode < 0 { if ecode < 0 {
return data.Error return data.Error
} }
@ -209,22 +226,21 @@ func (diff *Diff) ForEachHunk(cb DiffForEachHunkCallback) error {
//export diffForEachHunkCb //export diffForEachHunkCb
func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, payload unsafe.Pointer) int { func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, payload unsafe.Pointer) int {
data := (*diffForEachHunkData)(payload) data := (*diffForEachData)(payload)
err := data.Callback(newDiffHunkFromC(delta, hunk)) data.LineCallback = nil
if data.HunkCallback != nil {
cb, err := data.HunkCallback(newDiffHunkFromC(delta, hunk))
if err != nil { if err != nil {
data.Error = err data.Error = err
return -1 return -1
} }
data.LineCallback = cb
}
return 0 return 0
} }
type diffForEachLineData struct {
Callback DiffForEachLineCallback
Error error
}
type DiffForEachLineCallback func(*DiffLine) error type DiffForEachLineCallback func(*DiffLine) error
func (diff *Diff) ForEachLine(cb DiffForEachLineCallback) error { func (diff *Diff) ForEachLine(cb DiffForEachLineCallback) error {
@ -232,8 +248,8 @@ func (diff *Diff) ForEachLine(cb DiffForEachLineCallback) error {
return ErrInvalid return ErrInvalid
} }
data := &diffForEachLineData{ data := &diffForEachData{
Callback: cb, LineCallback: cb,
} }
ecode := C._go_git_diff_foreach(diff.ptr, 0, 0, 1, unsafe.Pointer(data)) ecode := C._go_git_diff_foreach(diff.ptr, 0, 0, 1, unsafe.Pointer(data))
@ -246,9 +262,9 @@ func (diff *Diff) ForEachLine(cb DiffForEachLineCallback) error {
//export diffForEachLineCb //export diffForEachLineCb
func diffForEachLineCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line, payload unsafe.Pointer) int { func diffForEachLineCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line, payload unsafe.Pointer) int {
data := (*diffForEachLineData)(payload) data := (*diffForEachData)(payload)
err := data.Callback(newDiffLineFromC(delta, hunk, line)) err := data.LineCallback(newDiffLineFromC(delta, hunk, line))
if err != nil { if err != nil {
data.Error = err data.Error = err
return -1 return -1

View File

@ -28,11 +28,18 @@ func TestDiffTreeToTree(t *testing.T) {
} }
files := make([]string, 0) files := make([]string, 0)
hunks := make([]*DiffHunk, 0)
err = diff.ForEachFile(func(file *DiffDelta) error { lines := make([]*DiffLine, 0)
err = diff.ForEach(func(file *DiffDelta, progress float64) (DiffForEachHunkCallback, error) {
files = append(files, file.OldFile.Path) files = append(files, file.OldFile.Path)
return func(hunk *DiffHunk) (DiffForEachLineCallback, error) {
hunks = append(hunks, hunk)
return func(line *DiffLine) error {
lines = append(lines, line)
return nil return nil
}) }, nil
}, nil
}, true, true)
checkFatal(t, err) checkFatal(t, err)
@ -44,11 +51,31 @@ func TestDiffTreeToTree(t *testing.T) {
t.Fatal("File in diff was expected to be README") t.Fatal("File in diff was expected to be README")
} }
if len(hunks) != 1 {
t.Fatal("Incorrect number of hunks in diff")
}
if hunks[0].OldStart != 1 || hunks[0].NewStart != 1 {
t.Fatal("Incorrect hunk")
}
if len(lines) != 2 {
t.Fatal("Incorrect number of lines in diff")
}
if lines[0].Content != "foo\n" {
t.Fatal("Incorrect lines in diff")
}
if lines[1].Content != "file changed\n" {
t.Fatal("Incorrect lines in diff")
}
errTest := errors.New("test error") errTest := errors.New("test error")
err = diff.ForEachFile(func(file *DiffDelta) error { err = diff.ForEach(func(file *DiffDelta, progress float64) (DiffForEachHunkCallback, error) {
return errTest return nil, errTest
}) }, false, false)
if err != errTest { if err != errTest {
t.Fatal("Expected custom error to be returned") t.Fatal("Expected custom error to be returned")