From 86e9917919afd0f71340c0a2ebc8ee28f2030790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 12 Jun 2015 17:45:11 +0200 Subject: [PATCH 1/2] diff: remove unnecessary args to Hunk and Line ctors --- diff.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/diff.go b/diff.go index 5e03175..aa422fc 100644 --- a/diff.go +++ b/diff.go @@ -94,7 +94,7 @@ type DiffHunk struct { Header string } -func diffHunkFromC(delta *C.git_diff_delta, hunk *C.git_diff_hunk) DiffHunk { +func diffHunkFromC(hunk *C.git_diff_hunk) DiffHunk { return DiffHunk{ OldStart: int(hunk.old_start), OldLines: int(hunk.old_lines), @@ -112,7 +112,7 @@ type DiffLine struct { Content string } -func diffLineFromC(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line) DiffLine { +func diffLineFromC(line *C.git_diff_line) DiffLine { return DiffLine{ Origin: DiffLineType(line.origin), OldLineno: int(line.old_lineno), @@ -309,7 +309,7 @@ func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, handle un data.LineCallback = nil if data.HunkCallback != nil { - cb, err := data.HunkCallback(diffHunkFromC(delta, hunk)) + cb, err := data.HunkCallback(diffHunkFromC(hunk)) if err != nil { data.Error = err return -1 @@ -330,7 +330,7 @@ func diffForEachLineCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.g panic("could not retrieve data for handle") } - err := data.LineCallback(diffLineFromC(delta, hunk, line)) + err := data.LineCallback(diffLineFromC(line)) if err != nil { data.Error = err return -1 From e066d24efba9587a66cf9eb6221b4a38c513c26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 12 Jun 2015 19:10:00 +0200 Subject: [PATCH 2/2] Add DiffBlobs This lets you diff two arbitrary blobs with arbitrary names. --- diff.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ diff_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ wrapper.c | 21 +++++++++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/diff.go b/diff.go index aa422fc..de56374 100644 --- a/diff.go +++ b/diff.go @@ -5,6 +5,7 @@ package git extern int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload); extern void _go_git_setup_diff_notify_callbacks(git_diff_options* opts); +extern int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload); */ import "C" import ( @@ -670,3 +671,50 @@ func (v *Repository) DiffIndexToWorkdir(index *Index, opts *DiffOptions) (*Diff, } return newDiffFromC(diffPtr), nil } + +// DiffBlobs performs a diff between two arbitrary blobs. You can pass +// whatever file names you'd like for them to appear as in the diff. +func DiffBlobs(oldBlob *Blob, oldAsPath string, newBlob *Blob, newAsPath string, opts *DiffOptions, fileCallback DiffForEachFileCallback, detail DiffDetail) error { + data := &diffForEachData{ + FileCallback: fileCallback, + } + + intHunks := C.int(0) + if detail >= DiffDetailHunks { + intHunks = C.int(1) + } + + intLines := C.int(0) + if detail >= DiffDetailLines { + intLines = C.int(1) + } + + handle := pointerHandles.Track(data) + defer pointerHandles.Untrack(handle) + + var oldBlobPtr, newBlobPtr *C.git_blob + if oldBlob != nil { + oldBlobPtr = oldBlob.cast_ptr + } + if newBlob != nil { + newBlobPtr = newBlob.cast_ptr + } + + oldBlobPath := C.CString(oldAsPath) + defer C.free(unsafe.Pointer(oldBlobPath)) + newBlobPath := C.CString(newAsPath) + defer C.free(unsafe.Pointer(newBlobPath)) + + copts, _ := diffOptionsToC(opts) + defer freeDiffOptions(copts) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C._go_git_diff_blobs(oldBlobPtr, oldBlobPath, newBlobPtr, newBlobPath, copts, 1, intHunks, intLines, handle) + if ecode < 0 { + return MakeGitError(ecode) + } + + return nil +} diff --git a/diff_test.go b/diff_test.go index 464fae6..850ed8e 100644 --- a/diff_test.go +++ b/diff_test.go @@ -187,3 +187,50 @@ func createTestTrees(t *testing.T, repo *Repository) (originalTree *Tree, newTre return originalTree, newTree } + +func TestDiffBlobs(t *testing.T) { + repo := createTestRepo(t) + defer cleanupTestRepo(t, repo) + + odb, err := repo.Odb() + checkFatal(t, err) + + id1, err := odb.Write([]byte("hello\nhello\n"), ObjectBlob) + checkFatal(t, err) + + id2, err := odb.Write([]byte("hallo\nhallo\n"), ObjectBlob) + checkFatal(t, err) + + blob1, err := repo.LookupBlob(id1) + checkFatal(t, err) + + blob2, err := repo.LookupBlob(id2) + checkFatal(t, err) + + var files, hunks, lines int + err = DiffBlobs(blob1, "hi", blob2, "hi", nil, + func(delta DiffDelta, progress float64) (DiffForEachHunkCallback, error) { + files++ + return func(hunk DiffHunk) (DiffForEachLineCallback, error) { + hunks++ + return func(line DiffLine) error { + lines++ + return nil + }, nil + }, nil + }, + DiffDetailLines) + + if files != 1 { + t.Fatal("Bad number of files iterated") + } + + if hunks != 1 { + t.Fatal("Bad number of hunks iterated") + } + + // two removals, two additions + if lines != 4 { + t.Fatalf("Bad number of lines iterated") + } +} diff --git a/wrapper.c b/wrapper.c index 938fd17..017168d 100644 --- a/wrapper.c +++ b/wrapper.c @@ -62,6 +62,27 @@ int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLin return git_diff_foreach(diff, fcb, hcb, lcb, payload); } +int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload) +{ + git_diff_file_cb fcb = NULL; + git_diff_hunk_cb hcb = NULL; + git_diff_line_cb lcb = NULL; + + if (eachFile) { + fcb = (git_diff_file_cb)&diffForEachFileCb; + } + + if (eachHunk) { + hcb = (git_diff_hunk_cb)&diffForEachHunkCb; + } + + if (eachLine) { + lcb = (git_diff_line_cb)&diffForEachLineCb; + } + + return git_diff_blobs(old, old_path, new, new_path, opts, fcb, hcb, lcb, payload); +} + void _go_git_setup_diff_notify_callbacks(git_diff_options *opts) { opts->notify_cb = (git_diff_notify_cb)diffNotifyCb; }