summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blob.go15
-rw-r--r--branch.go6
-rw-r--r--clone.go12
-rw-r--r--diff.go103
-rw-r--r--diff_test.go47
-rw-r--r--git.go6
-rw-r--r--handles.go84
-rw-r--r--index.go66
-rw-r--r--index_test.go63
-rw-r--r--odb.go13
-rw-r--r--odb_test.go2
-rw-r--r--packbuilder.go13
-rw-r--r--reference.go6
-rw-r--r--reference_test.go3
-rw-r--r--remote.go30
-rw-r--r--repository.go8
-rw-r--r--submodule.go15
-rw-r--r--submodule_test.go2
-rw-r--r--tree.go16
-rw-r--r--wrapper.c21
20 files changed, 454 insertions, 77 deletions
diff --git a/blob.go b/blob.go
index 5a33bd8..b1fc78a 100644
--- a/blob.go
+++ b/blob.go
@@ -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
}
diff --git a/branch.go b/branch.go
index 22b767e..42e1216 100644
--- a/branch.go
+++ b/branch.go
@@ -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 {
diff --git a/clone.go b/clone.go
index b796b6e..4de4aea 100644
--- a/clone.go
+++ b/clone.go
@@ -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)
}
diff --git a/diff.go b/diff.go
index 23469f2..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 (
@@ -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")
+ }
+}
diff --git a/git.go b/git.go
index 9496d2d..a44459f 100644
--- a/git.go
+++ b/git.go
@@ -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
+}
diff --git a/index.go b/index.go
index 9f37f33..c1bfb74 100644
--- a/index.go
+++ b/index.go
@@ -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)
}
diff --git a/odb.go b/odb.go
index ba03860..6b21329 100644
--- a/odb.go
+++ b/odb.go
@@ -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)
}
diff --git a/remote.go b/remote.go
index 84750d3..0635608 100644
--- a/remote.go
+++ b/remote.go
@@ -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)
}
}
diff --git a/tree.go b/tree.go
index c18d02a..aad2c8d 100644
--- a/tree.go
+++ b/tree.go
@@ -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 {
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;
}