From f505e39c9eac64264d6341cc925c5fa7f67b56cf Mon Sep 17 00:00:00 2001 From: lhchavez Date: Sat, 5 Jan 2019 20:13:01 +0000 Subject: [PATCH] Add a test and some comments as to the ugly pointer arithmetic --- repository.go | 11 +++++++++-- repository_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 repository_test.go diff --git a/repository.go b/repository.go index a430751..30673a7 100644 --- a/repository.go +++ b/repository.go @@ -412,12 +412,19 @@ func (v *Repository) CreateCommitFromIds( nparents := len(parents) if nparents > 0 { - parentsarg = (**C.git_oid)(C.malloc(C.size_t(unsafe.Sizeof(uintptr(0)) * uintptr(nparents)))) + // All this awful pointer arithmetic is needed to avoid passing a Go + // pointer to Go pointer into C. Other methods (like CreateCommits) are + // fine without this workaround because they are just passing Go pointers + // to C pointers, but arrays-of-pointers-to-git_oid are a bit special since + // both the array and the objects are allocated from Go. + var emptyOidPtr *C.git_oid + sizeofOidPtr := unsafe.Sizeof(emptyOidPtr) + parentsarg = (**C.git_oid)(C.calloc(C.size_t(uintptr(nparents)), C.size_t(sizeofOidPtr))) defer C.free(unsafe.Pointer(parentsarg)) parentsptr := uintptr(unsafe.Pointer(parentsarg)) for _, v := range parents { *(**C.git_oid)(unsafe.Pointer(parentsptr)) = v.toC() - parentsptr += unsafe.Sizeof(uintptr(0)) + parentsptr += sizeofOidPtr } } diff --git a/repository_test.go b/repository_test.go new file mode 100644 index 0000000..1950c69 --- /dev/null +++ b/repository_test.go @@ -0,0 +1,42 @@ +package git + +import ( + "testing" + "time" +) + +func TestCreateCommitFromIds(t *testing.T) { + t.Parallel() + repo := createTestRepo(t) + defer cleanupTestRepo(t, repo) + + loc, err := time.LoadLocation("Europe/Berlin") + checkFatal(t, err) + sig := &Signature{ + Name: "Rand Om Hacker", + Email: "random@hacker.com", + When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc), + } + + idx, err := repo.Index() + checkFatal(t, err) + err = idx.AddByPath("README") + checkFatal(t, err) + err = idx.Write() + checkFatal(t, err) + treeId, err := idx.WriteTree() + checkFatal(t, err) + + message := "This is a commit\n" + tree, err := repo.LookupTree(treeId) + checkFatal(t, err) + expectedCommitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree) + checkFatal(t, err) + + commitId, err := repo.CreateCommitFromIds("", sig, sig, message, treeId) + checkFatal(t, err) + + if !expectedCommitId.Equal(commitId) { + t.Errorf("mismatched commit ids, expected %v, got %v", expectedCommitId.String(), commitId.String()) + } +}