From fbaf9d1d1ae0bb7b6e7ed9044945d4c9322d4c76 Mon Sep 17 00:00:00 2001 From: lhchavez Date: Sat, 4 Sep 2021 13:04:58 -0700 Subject: [PATCH] Add `Repository.CreateCommitBuffer` (#781) This commit adds the Go binding for `git_commit_create_buffer`. This will be used to support the 1.2.0 commit create callback. --- commit.go | 8 ++++++ repository.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++ repository_test.go | 54 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) diff --git a/commit.go b/commit.go index 1c546b3..3a07fa8 100644 --- a/commit.go +++ b/commit.go @@ -12,6 +12,14 @@ import ( "unsafe" ) +// MessageEncoding is the encoding of commit messages. +type MessageEncoding string + +const ( + // MessageEncodingUTF8 is the default message encoding. + MessageEncodingUTF8 MessageEncoding = "UTF-8" +) + // Commit type Commit struct { Object diff --git a/repository.go b/repository.go index cb82fc3..dc40aaf 100644 --- a/repository.go +++ b/repository.go @@ -485,6 +485,69 @@ func (v *Repository) CreateCommit( return oid, nil } +// CreateCommitBuffer creates a commit and write it into a buffer. +func (v *Repository) CreateCommitBuffer( + author, committer *Signature, + messageEncoding MessageEncoding, + message string, + tree *Tree, + parents ...*Commit, +) ([]byte, error) { + cmsg := C.CString(message) + defer C.free(unsafe.Pointer(cmsg)) + var cencoding *C.char + // Since the UTF-8 encoding is the default, pass in nil whenever UTF-8 is + // provided. That will cause the commit to not have an explicit header for + // it. + if messageEncoding != MessageEncodingUTF8 && messageEncoding != MessageEncoding("") { + cencoding = C.CString(string(messageEncoding)) + defer C.free(unsafe.Pointer(cencoding)) + } + + var cparents []*C.git_commit = nil + var parentsarg **C.git_commit = nil + + nparents := len(parents) + if nparents > 0 { + cparents = make([]*C.git_commit, nparents) + for i, v := range parents { + cparents[i] = v.cast_ptr + } + parentsarg = &cparents[0] + } + + authorSig, err := author.toC() + if err != nil { + return nil, err + } + defer C.git_signature_free(authorSig) + + committerSig, err := committer.toC() + if err != nil { + return nil, err + } + defer C.git_signature_free(committerSig) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + var buf C.git_buf + defer C.git_buf_dispose(&buf) + ret := C.git_commit_create_buffer( + &buf, v.ptr, + authorSig, committerSig, + cencoding, cmsg, tree.cast_ptr, C.size_t(nparents), parentsarg) + + runtime.KeepAlive(v) + runtime.KeepAlive(buf) + runtime.KeepAlive(parents) + if ret < 0 { + return nil, MakeGitError(ret) + } + + return C.GoBytes(unsafe.Pointer(buf.ptr), C.int(buf.size)), nil +} + func (v *Repository) CreateCommitFromIds( refname string, author, committer *Signature, message string, tree *Oid, parents ...*Oid) (*Oid, error) { diff --git a/repository_test.go b/repository_test.go index e403aa9..60758c1 100644 --- a/repository_test.go +++ b/repository_test.go @@ -5,6 +5,60 @@ import ( "time" ) +func TestCreateCommitBuffer(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) + + for encoding, expected := range map[MessageEncoding]string{ + MessageEncodingUTF8: `tree b7119b11e8ef7a1a5a34d3ac87f5b075228ac81e +author Rand Om Hacker 1362576600 +0100 +committer Rand Om Hacker 1362576600 +0100 + +This is a commit +`, + MessageEncoding("ASCII"): `tree b7119b11e8ef7a1a5a34d3ac87f5b075228ac81e +author Rand Om Hacker 1362576600 +0100 +committer Rand Om Hacker 1362576600 +0100 +encoding ASCII + +This is a commit +`, + } { + encoding := encoding + expected := expected + t.Run(string(encoding), func(t *testing.T) { + buf, err := repo.CreateCommitBuffer(sig, sig, encoding, message, tree) + checkFatal(t, err) + + if expected != string(buf) { + t.Errorf("mismatched commit buffer, expected %v, got %v", expected, string(buf)) + } + }) + } +} + func TestCreateCommitFromIds(t *testing.T) { t.Parallel() repo := createTestRepo(t)