diff options
| -rw-r--r-- | blob.go | 15 | ||||
| -rw-r--r-- | branch.go | 6 | ||||
| -rw-r--r-- | clone.go | 12 | ||||
| -rw-r--r-- | diff.go | 103 | ||||
| -rw-r--r-- | diff_test.go | 47 | ||||
| -rw-r--r-- | git.go | 6 | ||||
| -rw-r--r-- | handles.go | 84 | ||||
| -rw-r--r-- | index.go | 66 | ||||
| -rw-r--r-- | index_test.go | 63 | ||||
| -rw-r--r-- | odb.go | 13 | ||||
| -rw-r--r-- | odb_test.go | 2 | ||||
| -rw-r--r-- | packbuilder.go | 13 | ||||
| -rw-r--r-- | reference.go | 6 | ||||
| -rw-r--r-- | reference_test.go | 3 | ||||
| -rw-r--r-- | remote.go | 30 | ||||
| -rw-r--r-- | repository.go | 8 | ||||
| -rw-r--r-- | submodule.go | 15 | ||||
| -rw-r--r-- | submodule_test.go | 2 | ||||
| -rw-r--r-- | tree.go | 16 | ||||
| -rw-r--r-- | wrapper.c | 21 |
20 files changed, 454 insertions, 77 deletions
@@ -60,8 +60,13 @@ type BlobCallbackData struct { } //export blobChunkCb -func blobChunkCb(buffer *C.char, maxLen C.size_t, payload unsafe.Pointer) int { - data := (*BlobCallbackData)(payload) +func blobChunkCb(buffer *C.char, maxLen C.size_t, handle unsafe.Pointer) int { + payload := pointerHandles.Get(handle) + data, ok := payload.(*BlobCallbackData) + if !ok { + panic("could not retrieve blob callback data") + } + goBuf, err := data.Callback(int(maxLen)) if err == io.EOF { return 0 @@ -83,8 +88,12 @@ func (repo *Repository) CreateBlobFromChunks(hintPath string, callback BlobChunk defer C.free(unsafe.Pointer(chintPath)) } oid := C.git_oid{} + payload := &BlobCallbackData{Callback: callback} - ecode := C._go_git_blob_create_fromchunks(&oid, repo.ptr, chintPath, unsafe.Pointer(payload)) + handle := pointerHandles.Track(payload) + defer pointerHandles.Untrack(handle) + + ecode := C._go_git_blob_create_fromchunks(&oid, repo.ptr, chintPath, handle) if payload.Error != nil { return nil, payload.Error } @@ -92,7 +92,7 @@ func (repo *Repository) NewBranchIterator(flags BranchType) (*BranchIterator, er func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, msg string) (*Branch, error) { - ref := new(Reference) + var ptr *C.git_reference cBranchName := C.CString(branchName) cForce := cbool(force) @@ -113,11 +113,11 @@ func (repo *Repository) CreateBranch(branchName string, target *Commit, force bo runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_create(&ref.ptr, repo.ptr, cBranchName, target.cast_ptr, cForce, cSignature, cmsg) + ret := C.git_branch_create(&ptr, repo.ptr, cBranchName, target.cast_ptr, cForce, cSignature, cmsg) if ret < 0 { return nil, MakeGitError(ret) } - return ref.Branch(), nil + return newReferenceFromC(ptr, repo).Branch(), nil } func (b *Branch) Delete() error { @@ -28,18 +28,20 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) cpath := C.CString(path) defer C.free(unsafe.Pointer(cpath)) - var copts C.git_clone_options - populateCloneOptions(&copts, options) - defer freeCheckoutOpts(&copts.checkout_opts) + copts := (*C.git_clone_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_clone_options{})))) + populateCloneOptions(copts, options) if len(options.CheckoutBranch) != 0 { copts.checkout_branch = C.CString(options.CheckoutBranch) - defer C.free(unsafe.Pointer(copts.checkout_branch)) } runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_clone(&repo.ptr, curl, cpath, &copts) + ret := C.git_clone(&repo.ptr, curl, cpath, copts) + freeCheckoutOpts(&copts.checkout_opts) + C.free(unsafe.Pointer(copts.checkout_branch)) + C.free(unsafe.Pointer(copts)) + if ret < 0 { return nil, MakeGitError(ret) } @@ -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 ( @@ -94,7 +95,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 +113,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), @@ -265,7 +266,11 @@ func (diff *Diff) ForEach(cbFile DiffForEachFileCallback, detail DiffDetail) err data := &diffForEachData{ FileCallback: cbFile, } - ecode := C._go_git_diff_foreach(diff.ptr, 1, intHunks, intLines, unsafe.Pointer(data)) + + handle := pointerHandles.Track(data) + defer pointerHandles.Untrack(handle) + + ecode := C._go_git_diff_foreach(diff.ptr, 1, intHunks, intLines, handle) if ecode < 0 { return data.Error } @@ -273,8 +278,12 @@ func (diff *Diff) ForEach(cbFile DiffForEachFileCallback, detail DiffDetail) err } //export diffForEachFileCb -func diffForEachFileCb(delta *C.git_diff_delta, progress C.float, payload unsafe.Pointer) int { - data := (*diffForEachData)(payload) +func diffForEachFileCb(delta *C.git_diff_delta, progress C.float, handle unsafe.Pointer) int { + payload := pointerHandles.Get(handle) + data, ok := payload.(*diffForEachData) + if !ok { + panic("could not retrieve data for handle") + } data.HunkCallback = nil if data.FileCallback != nil { @@ -292,12 +301,16 @@ func diffForEachFileCb(delta *C.git_diff_delta, progress C.float, payload unsafe type DiffForEachHunkCallback func(DiffHunk) (DiffForEachLineCallback, error) //export diffForEachHunkCb -func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, payload unsafe.Pointer) int { - data := (*diffForEachData)(payload) +func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, handle unsafe.Pointer) int { + payload := pointerHandles.Get(handle) + data, ok := payload.(*diffForEachData) + if !ok { + panic("could not retrieve data for handle") + } 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 @@ -311,11 +324,14 @@ func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, payload u type DiffForEachLineCallback func(DiffLine) error //export diffForEachLineCb -func diffForEachLineCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line, payload unsafe.Pointer) int { - - data := (*diffForEachData)(payload) +func diffForEachLineCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line, handle unsafe.Pointer) int { + payload := pointerHandles.Get(handle) + data, ok := payload.(*diffForEachData) + if !ok { + 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 @@ -479,9 +495,15 @@ type diffNotifyData struct { } //export diffNotifyCb -func diffNotifyCb(_diff_so_far unsafe.Pointer, delta_to_add *C.git_diff_delta, matched_pathspec *C.char, payload unsafe.Pointer) int { +func diffNotifyCb(_diff_so_far unsafe.Pointer, delta_to_add *C.git_diff_delta, matched_pathspec *C.char, handle unsafe.Pointer) int { diff_so_far := (*C.git_diff)(_diff_so_far) - data := (*diffNotifyData)(payload) + + payload := pointerHandles.Get(handle) + data, ok := payload.(*diffNotifyData) + if !ok { + panic("could not retrieve data for handle") + } + if data != nil { if data.Diff == nil { data.Diff = newDiffFromC(diff_so_far) @@ -507,6 +529,7 @@ func diffOptionsToC(opts *DiffOptions) (copts *C.git_diff_options, notifyData *d notifyData = &diffNotifyData{ Callback: opts.NotifyCallback, } + if opts.Pathspec != nil { cpathspec.count = C.size_t(len(opts.Pathspec)) cpathspec.strings = makeCStringsFromStrings(opts.Pathspec) @@ -527,7 +550,7 @@ func diffOptionsToC(opts *DiffOptions) (copts *C.git_diff_options, notifyData *d if opts.NotifyCallback != nil { C._go_git_setup_diff_notify_callbacks(copts) - copts.notify_payload = unsafe.Pointer(notifyData) + copts.notify_payload = pointerHandles.Track(notifyData) } } return @@ -539,6 +562,9 @@ func freeDiffOptions(copts *C.git_diff_options) { freeStrarray(&cpathspec) C.free(unsafe.Pointer(copts.old_prefix)) C.free(unsafe.Pointer(copts.new_prefix)) + if copts.notify_payload != nil { + pointerHandles.Untrack(copts.notify_payload) + } } } @@ -645,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") + } +} @@ -87,13 +87,19 @@ const ( ErrPassthrough ErrorCode = C.GIT_PASSTHROUGH // Signals end of iteration with iterator ErrIterOver ErrorCode = C.GIT_ITEROVER + // Authentication failed + ErrAuth ErrorCode = C.GIT_EAUTH ) var ( ErrInvalid = errors.New("Invalid state for operation") ) +var pointerHandles *HandleList + func init() { + pointerHandles = NewHandleList() + C.git_libgit2_init() // This is not something we should be doing, as we may be diff --git a/handles.go b/handles.go new file mode 100644 index 0000000..ec62a48 --- /dev/null +++ b/handles.go @@ -0,0 +1,84 @@ +package git + +import ( + "fmt" + "sync" + "unsafe" +) + +type HandleList struct { + sync.RWMutex + // stores the Go pointers + handles []interface{} + // indicates which indices are in use + set map[int]bool +} + +func NewHandleList() *HandleList { + return &HandleList{ + handles: make([]interface{}, 5), + set: make(map[int]bool), + } +} + +// findUnusedSlot finds the smallest-index empty space in our +// list. You must only run this function while holding a write lock. +func (v *HandleList) findUnusedSlot() int { + for i := 1; i < len(v.handles); i++ { + isUsed := v.set[i] + if !isUsed { + return i + } + } + + // reaching here means we've run out of entries so append and + // return the new index, which is equal to the old length. + slot := len(v.handles) + v.handles = append(v.handles, nil) + + return slot +} + +// Track adds the given pointer to the list of pointers to track and +// returns a pointer value which can be passed to C as an opaque +// pointer. +func (v *HandleList) Track(pointer interface{}) unsafe.Pointer { + v.Lock() + + slot := v.findUnusedSlot() + v.handles[slot] = pointer + v.set[slot] = true + + v.Unlock() + + return unsafe.Pointer(&slot) +} + +// Untrack stops tracking the pointer given by the handle +func (v *HandleList) Untrack(handle unsafe.Pointer) { + slot := *(*int)(handle) + + v.Lock() + + v.handles[slot] = nil + delete(v.set, slot) + + v.Unlock() +} + +// Get retrieves the pointer from the given handle +func (v *HandleList) Get(handle unsafe.Pointer) interface{} { + slot := *(*int)(handle) + + v.RLock() + + if _, ok := v.set[slot]; !ok { + panic(fmt.Sprintf("invalid pointer handle: %p", handle)) + } + + ptr := v.handles[slot] + + v.RUnlock() + + return ptr +} @@ -96,6 +96,30 @@ func NewIndex() (*Index, error) { return &Index{ptr: ptr}, nil } +// OpenIndex creates a new index at the given path. If the file does +// not exist it will be created when Write() is called. +func OpenIndex(path string) (*Index, error) { + var ptr *C.git_index + + var cpath = C.CString(path) + defer C.free(unsafe.Pointer(cpath)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if err := C.git_index_open(&ptr, cpath); err < 0 { + return nil, MakeGitError(err) + } + + return &Index{ptr: ptr}, nil +} + +// Path returns the index' path on disk or an empty string if it +// exists only in memory. +func (v *Index) Path() string { + return C.GoString(C.git_index_path(v.ptr)) +} + // Add adds or replaces the given entry to the index, making a copy of // the data func (v *Index) Add(entry *IndexEntry) error { @@ -138,16 +162,17 @@ func (v *Index) AddAll(pathspecs []string, flags IndexAddOpts, callback IndexMat runtime.LockOSThread() defer runtime.UnlockOSThread() - var cb *IndexMatchedPathCallback + var handle unsafe.Pointer if callback != nil { - cb = &callback + handle = pointerHandles.Track(callback) + defer pointerHandles.Untrack(handle) } ret := C._go_git_index_add_all( v.ptr, &cpathspecs, C.uint(flags), - unsafe.Pointer(cb), + handle, ) if ret < 0 { return MakeGitError(ret) @@ -164,15 +189,16 @@ func (v *Index) UpdateAll(pathspecs []string, callback IndexMatchedPathCallback) runtime.LockOSThread() defer runtime.UnlockOSThread() - var cb *IndexMatchedPathCallback + var handle unsafe.Pointer if callback != nil { - cb = &callback + handle = pointerHandles.Track(callback) + defer pointerHandles.Untrack(handle) } ret := C._go_git_index_update_all( v.ptr, &cpathspecs, - unsafe.Pointer(cb), + handle, ) if ret < 0 { return MakeGitError(ret) @@ -189,15 +215,16 @@ func (v *Index) RemoveAll(pathspecs []string, callback IndexMatchedPathCallback) runtime.LockOSThread() defer runtime.UnlockOSThread() - var cb *IndexMatchedPathCallback + var handle unsafe.Pointer if callback != nil { - cb = &callback + handle = pointerHandles.Track(callback) + defer pointerHandles.Untrack(handle) } ret := C._go_git_index_remove_all( v.ptr, &cpathspecs, - unsafe.Pointer(cb), + handle, ) if ret < 0 { return MakeGitError(ret) @@ -207,8 +234,11 @@ func (v *Index) RemoveAll(pathspecs []string, callback IndexMatchedPathCallback) //export indexMatchedPathCallback func indexMatchedPathCallback(cPath, cMatchedPathspec *C.char, payload unsafe.Pointer) int { - callback := (*IndexMatchedPathCallback)(payload) - return (*callback)(C.GoString(cPath), C.GoString(cMatchedPathspec)) + if callback, ok := pointerHandles.Get(payload).(IndexMatchedPathCallback); ok { + return callback(C.GoString(cPath), C.GoString(cMatchedPathspec)) + } else { + panic("invalid matched path callback") + } } func (v *Index) RemoveByPath(path string) error { @@ -240,6 +270,20 @@ func (v *Index) WriteTreeTo(repo *Repository) (*Oid, error) { return oid, nil } +// ReadTree replaces the contents of the index with those of the given +// tree +func (v *Index) ReadTree(tree *Tree) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_index_read_tree(v.ptr, tree.cast_ptr); + if ret < 0 { + return MakeGitError(ret) + } + + return nil +} + func (v *Index) WriteTree() (*Oid, error) { oid := new(Oid) diff --git a/index_test.go b/index_test.go index 647a0b8..7c65f4f 100644 --- a/index_test.go +++ b/index_test.go @@ -2,6 +2,7 @@ package git import ( "io/ioutil" + "os" "runtime" "testing" ) @@ -22,6 +23,34 @@ func TestCreateRepoAndStage(t *testing.T) { } } +func TestIndexReadTree(t *testing.T) { + repo := createTestRepo(t) + defer cleanupTestRepo(t, repo) + + _, _ = seedTestRepo(t, repo) + + ref, err := repo.Head() + checkFatal(t, err) + + obj, err := ref.Peel(ObjectTree); + checkFatal(t, err) + + tree := obj.(*Tree) + + idx, err := NewIndex() + checkFatal(t, err) + + err = idx.ReadTree(tree) + checkFatal(t, err) + + id, err := idx.WriteTreeTo(repo) + checkFatal(t, err) + + if tree.Id().Cmp(id) != 0 { + t.Fatalf("Read and written trees are not the same") + } +} + func TestIndexWriteTreeTo(t *testing.T) { repo := createTestRepo(t) defer cleanupTestRepo(t, repo) @@ -54,6 +83,10 @@ func TestIndexAddAndWriteTreeTo(t *testing.T) { idx, err := NewIndex() checkFatal(t, err) + if idx.Path() != "" { + t.Fatal("in-memory repo has a path") + } + entry := IndexEntry{ Path: "README", Id: blobID, @@ -120,6 +153,33 @@ func TestIndexAddAllCallback(t *testing.T) { } } +func TestIndexOpen(t *testing.T) { + repo := createTestRepo(t) + defer cleanupTestRepo(t, repo) + + path := repo.Workdir() + "/heyindex" + + _, err := os.Stat(path) + if !os.IsNotExist(err) { + t.Fatal("new index file already exists") + } + + idx, err := OpenIndex(path) + checkFatal(t, err) + + if path != idx.Path() { + t.Fatalf("mismatched index paths, expected %v, got %v", path, idx.Path()) + } + + err = idx.Write() + checkFatal(t, err) + + _, err = os.Stat(path) + if os.IsNotExist(err) { + t.Fatal("new index file did not get written") + } +} + func checkFatal(t *testing.T, err error) { if err == nil { return @@ -128,8 +188,7 @@ func checkFatal(t *testing.T, err error) { // The failure happens at wherever we were called, not here _, file, line, ok := runtime.Caller(1) if !ok { - t.Fatal() + t.Fatalf("Unable to get caller") } - t.Fatalf("Fail at %v:%v; %v", file, line, err) } @@ -98,8 +98,12 @@ type foreachData struct { } //export odbForEachCb -func odbForEachCb(id *C.git_oid, payload unsafe.Pointer) int { - data := (*foreachData)(payload) +func odbForEachCb(id *C.git_oid, handle unsafe.Pointer) int { + data, ok := pointerHandles.Get(handle).(*foreachData) + + if !ok { + panic("could not retrieve handle") + } err := data.callback(newOidFromC(id)) if err != nil { @@ -119,7 +123,10 @@ func (v *Odb) ForEach(callback OdbForEachCallback) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C._go_git_odb_foreach(v.ptr, unsafe.Pointer(&data)) + handle := pointerHandles.Track(&data) + defer pointerHandles.Untrack(handle) + + ret := C._go_git_odb_foreach(v.ptr, handle) if ret == C.GIT_EUSER { return data.err } else if ret < 0 { diff --git a/odb_test.go b/odb_test.go index 55ed297..2fb6840 100644 --- a/odb_test.go +++ b/odb_test.go @@ -81,7 +81,7 @@ func TestOdbForeach(t *testing.T) { checkFatal(t, err) if count != expect { - t.Fatalf("Expected %v objects, got %v") + t.Fatalf("Expected %v objects, got %v", expect, count) } expect = 1 diff --git a/packbuilder.go b/packbuilder.go index 54a8390..4dc352c 100644 --- a/packbuilder.go +++ b/packbuilder.go @@ -110,8 +110,13 @@ type packbuilderCbData struct { } //export packbuilderForEachCb -func packbuilderForEachCb(buf unsafe.Pointer, size C.size_t, payload unsafe.Pointer) int { - data := (*packbuilderCbData)(payload) +func packbuilderForEachCb(buf unsafe.Pointer, size C.size_t, handle unsafe.Pointer) int { + payload := pointerHandles.Get(handle) + data, ok := payload.(*packbuilderCbData) + if !ok { + panic("could not get packbuilder CB data") + } + slice := C.GoBytes(buf, C.int(size)) err := data.callback(slice) @@ -130,11 +135,13 @@ func (pb *Packbuilder) ForEach(callback PackbuilderForeachCallback) error { callback: callback, err: nil, } + handle := pointerHandles.Track(&data) + defer pointerHandles.Untrack(handle) runtime.LockOSThread() defer runtime.UnlockOSThread() - err := C._go_git_packbuilder_foreach(pb.ptr, unsafe.Pointer(&data)) + err := C._go_git_packbuilder_foreach(pb.ptr, handle) if err == C.GIT_EUSER { return data.err } diff --git a/reference.go b/reference.go index ef12d0b..ac3580c 100644 --- a/reference.go +++ b/reference.go @@ -40,7 +40,7 @@ func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string) if err != nil { return nil, err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) var cmsg *C.char if msg == "" { @@ -68,7 +68,7 @@ func (v *Reference) SetTarget(target *Oid, sig *Signature, msg string) (*Referen if err != nil { return nil, err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) var cmsg *C.char if msg == "" { @@ -109,7 +109,7 @@ func (v *Reference) Rename(name string, force bool, sig *Signature, msg string) if err != nil { return nil, err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) var cmsg *C.char if msg == "" { diff --git a/reference_test.go b/reference_test.go index d6b5f22..5720a66 100644 --- a/reference_test.go +++ b/reference_test.go @@ -199,8 +199,7 @@ func checkRefType(t *testing.T, ref *Reference, kind ReferenceType) { // The failure happens at wherever we were called, not here _, file, line, ok := runtime.Caller(1) if !ok { - t.Fatal() + t.Fatalf("Unable to get caller") } - t.Fatalf("Wrong ref type at %v:%v; have %v, expected %v", file, line, ref.Type(), kind) } @@ -129,12 +129,12 @@ func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallb return } C._go_git_setup_callbacks(ptr) - ptr.payload = unsafe.Pointer(callbacks) + ptr.payload = pointerHandles.Track(callbacks) } //export sidebandProgressCallback func sidebandProgressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.SidebandProgressCallback == nil { return 0 } @@ -144,7 +144,7 @@ func sidebandProgressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int //export completionCallback func completionCallback(completion_type C.git_remote_completion_type, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.CompletionCallback == nil { return 0 } @@ -153,7 +153,7 @@ func completionCallback(completion_type C.git_remote_completion_type, data unsaf //export credentialsCallback func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C.char, allowed_types uint, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.CredentialsCallback == nil { return 0 } @@ -166,7 +166,7 @@ func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C //export transferProgressCallback func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.TransferProgressCallback == nil { return 0 } @@ -175,7 +175,7 @@ func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointe //export updateTipsCallback func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.UpdateTipsCallback == nil { return 0 } @@ -187,7 +187,7 @@ func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data uns //export certificateCheckCallback func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) // if there's no callback set, we need to make sure we fail if the library didn't consider this cert valid if callbacks.CertificateCheckCallback == nil { if _valid == 1 { @@ -228,7 +228,7 @@ func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, da //export packProgressCallback func packProgressCallback(stage C.int, current, total C.uint, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.PackProgressCallback == nil { return 0 @@ -239,7 +239,7 @@ func packProgressCallback(stage C.int, current, total C.uint, data unsafe.Pointe //export pushTransferProgressCallback func pushTransferProgressCallback(current, total C.uint, bytes C.size_t, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.PushTransferProgressCallback == nil { return 0 } @@ -249,7 +249,7 @@ func pushTransferProgressCallback(current, total C.uint, bytes C.size_t, data un //export pushUpdateReferenceCallback func pushUpdateReferenceCallback(refname, status *C.char, data unsafe.Pointer) int { - callbacks := (*RemoteCallbacks)(data) + callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.PushUpdateReferenceCallback == nil { return 0 @@ -286,6 +286,12 @@ func (r *Remote) SetCallbacks(callbacks *RemoteCallbacks) error { func (r *Remote) Free() { runtime.SetFinalizer(r, nil) + + callbacks := C.git_remote_get_callbacks(r.ptr) + if callbacks != nil && callbacks.payload != nil { + pointerHandles.Untrack(callbacks.payload) + } + C.git_remote_free(r.ptr) } @@ -608,7 +614,7 @@ func (o *Remote) Fetch(refspecs []string, sig *Signature, msg string) error { if err != nil { return err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) } var cmsg *C.char = nil @@ -703,7 +709,7 @@ func (o *Remote) Push(refspecs []string, opts *PushOptions, sig *Signature, msg if err != nil { return err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) } var cmsg *C.char diff --git a/repository.go b/repository.go index b6c75ef..c271ea6 100644 --- a/repository.go +++ b/repository.go @@ -214,7 +214,7 @@ func (v *Repository) SetHead(refname string, sig *Signature, msg string) error { if err != nil { return err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) var cmsg *C.char if msg != "" { @@ -237,7 +237,7 @@ func (v *Repository) SetHeadDetached(id *Oid, sig *Signature, msg string) error if err != nil { return err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) var cmsg *C.char if msg != "" { @@ -277,7 +277,7 @@ func (v *Repository) CreateReference(name string, id *Oid, force bool, sig *Sign if err != nil { return nil, err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) var cmsg *C.char if msg == "" { @@ -311,7 +311,7 @@ func (v *Repository) CreateSymbolicReference(name, target string, force bool, si if err != nil { return nil, err } - defer C.free(unsafe.Pointer(csig)) + defer C.git_signature_free(csig) var cmsg *C.char if msg == "" { diff --git a/submodule.go b/submodule.go index 7c6c922..3882462 100644 --- a/submodule.go +++ b/submodule.go @@ -97,17 +97,24 @@ func (repo *Repository) LookupSubmodule(name string) (*Submodule, error) { type SubmoduleCbk func(sub *Submodule, name string) int //export SubmoduleVisitor -func SubmoduleVisitor(csub unsafe.Pointer, name *C.char, cfct unsafe.Pointer) C.int { +func SubmoduleVisitor(csub unsafe.Pointer, name *C.char, handle unsafe.Pointer) C.int { sub := &Submodule{(*C.git_submodule)(csub)} - fct := *(*SubmoduleCbk)(cfct) - return (C.int)(fct(sub, C.GoString(name))) + + if callback, ok := pointerHandles.Get(handle).(SubmoduleCbk); ok { + return (C.int)(callback(sub, C.GoString(name))) + } else { + panic("invalid submodule visitor callback") + } } func (repo *Repository) ForeachSubmodule(cbk SubmoduleCbk) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C._go_git_visit_submodule(repo.ptr, unsafe.Pointer(&cbk)) + handle := pointerHandles.Track(cbk) + defer pointerHandles.Untrack(handle) + + ret := C._go_git_visit_submodule(repo.ptr, handle) if ret < 0 { return MakeGitError(ret) } diff --git a/submodule_test.go b/submodule_test.go index ee75d53..27bc193 100644 --- a/submodule_test.go +++ b/submodule_test.go @@ -21,6 +21,6 @@ func TestSubmoduleForeach(t *testing.T) { checkFatal(t, err) if i != 1 { - t.Fatalf("expected one submodule found but got %i", i) + t.Fatalf("expected one submodule found but got %d", i) } } @@ -90,22 +90,28 @@ func (t Tree) EntryCount() uint64 { type TreeWalkCallback func(string, *TreeEntry) int //export CallbackGitTreeWalk -func CallbackGitTreeWalk(_root unsafe.Pointer, _entry unsafe.Pointer, ptr unsafe.Pointer) C.int { - root := C.GoString((*C.char)(_root)) +func CallbackGitTreeWalk(_root *C.char, _entry unsafe.Pointer, ptr unsafe.Pointer) C.int { + root := C.GoString(_root) entry := (*C.git_tree_entry)(_entry) - callback := *(*TreeWalkCallback)(ptr) - return C.int(callback(root, newTreeEntry(entry))) + if callback, ok := pointerHandles.Get(ptr).(TreeWalkCallback); ok { + return C.int(callback(root, newTreeEntry(entry))) + } else { + panic("invalid treewalk callback") + } } func (t Tree) Walk(callback TreeWalkCallback) error { runtime.LockOSThread() defer runtime.UnlockOSThread() + ptr := pointerHandles.Track(callback) + defer pointerHandles.Untrack(ptr) + err := C._go_git_treewalk( t.cast_ptr, C.GIT_TREEWALK_PRE, - unsafe.Pointer(&callback), + ptr, ) if err < 0 { @@ -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; } |
