summaryrefslogtreecommitdiff
path: root/rebase.go
diff options
context:
space:
mode:
authorlhchavez <[email protected]>2021-09-03 06:40:31 -0700
committerlhchavez <[email protected]>2021-09-05 18:52:01 -0700
commit018647fd481a7eb4af97d5f61afc0fddfe76fc24 (patch)
tree06f4af28f0298ffe4bd93d2061f7eb8c52518bc2 /rebase.go
parentb78bde3d74b1617d5b635723552aaec0583eb054 (diff)
libgit2 v1.2.0 #major
This commit introduces libgit2 v1.2.0 to git2go, which brings a large number of [bugfixes and features](https://github.com/libgit2/libgit2/releases/tag/v1.2.0). This also marks the start of the v32 release.
Diffstat (limited to 'rebase.go')
-rw-r--r--rebase.go145
1 files changed, 106 insertions, 39 deletions
diff --git a/rebase.go b/rebase.go
index a61e8e7..58c0b6f 100644
--- a/rebase.go
+++ b/rebase.go
@@ -9,6 +9,7 @@ import "C"
import (
"errors"
"fmt"
+ "reflect"
"runtime"
"unsafe"
)
@@ -71,75 +72,140 @@ func newRebaseOperationFromC(c *C.git_rebase_operation) *RebaseOperation {
return operation
}
-//export commitSigningCallback
-func commitSigningCallback(errorMessage **C.char, _signature *C.git_buf, _signature_field *C.git_buf, _commit_content *C.char, handle unsafe.Pointer) C.int {
+//export commitCreateCallback
+func commitCreateCallback(
+ errorMessage **C.char,
+ _out *C.git_oid,
+ _author, _committer *C.git_signature,
+ _message_encoding, _message *C.char,
+ _tree *C.git_tree,
+ _parent_count C.size_t,
+ _parents **C.git_commit,
+ handle unsafe.Pointer,
+) C.int {
data, ok := pointerHandles.Get(handle).(*rebaseOptionsData)
if !ok {
panic("invalid sign payload")
}
- if data.options.CommitSigningCallback == nil {
+ if data.options.CommitCreateCallback == nil && data.options.CommitSigningCallback == nil {
return C.int(ErrorCodePassthrough)
}
- commitContent := C.GoString(_commit_content)
+ messageEncoding := MessageEncodingUTF8
+ if _message_encoding != nil {
+ messageEncoding = MessageEncoding(C.GoString(_message_encoding))
+ }
+ tree := &Tree{
+ Object: Object{
+ ptr: (*C.git_object)(_tree),
+ repo: data.repo,
+ },
+ cast_ptr: _tree,
+ }
- signature, signatureField, err := data.options.CommitSigningCallback(commitContent)
- if err != nil {
- if data.errorTarget != nil {
- *data.errorTarget = err
+ var goParents []*C.git_commit
+ if _parent_count > 0 {
+ hdr := reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(_parents)),
+ Len: int(_parent_count),
+ Cap: int(_parent_count),
}
- return setCallbackError(errorMessage, err)
+ goParents = *(*[]*C.git_commit)(unsafe.Pointer(&hdr))
}
- fillBuf := func(bufData string, buf *C.git_buf) error {
- clen := C.size_t(len(bufData))
- cstr := unsafe.Pointer(C.CString(bufData))
- defer C.free(cstr)
-
- // libgit2 requires the contents of the buffer to be NULL-terminated.
- // C.CString() guarantees that the returned buffer will be
- // NULL-terminated, so we can safely copy the terminator.
- if int(C.git_buf_set(buf, cstr, clen+1)) != 0 {
- return errors.New("could not set buffer")
+ parents := make([]*Commit, int(_parent_count))
+ for i, p := range goParents {
+ parents[i] = &Commit{
+ Object: Object{
+ ptr: (*C.git_object)(p),
+ repo: data.repo,
+ },
+ cast_ptr: p,
}
-
- return nil
}
- if signatureField != "" {
- err := fillBuf(signatureField, _signature_field)
+ if data.options.CommitCreateCallback != nil {
+ oid, err := data.options.CommitCreateCallback(
+ newSignatureFromC(_author),
+ newSignatureFromC(_committer),
+ messageEncoding,
+ C.GoString(_message),
+ tree,
+ parents...,
+ )
+ if err != nil {
+ if data.errorTarget != nil {
+ *data.errorTarget = err
+ }
+ return setCallbackError(errorMessage, err)
+ }
+ if oid == nil {
+ return C.int(ErrorCodePassthrough)
+ }
+ *_out = *oid.toC()
+ } else if data.options.CommitSigningCallback != nil {
+ commitContent, err := data.repo.CreateCommitBuffer(
+ newSignatureFromC(_author),
+ newSignatureFromC(_committer),
+ messageEncoding,
+ C.GoString(_message),
+ tree,
+ parents...,
+ )
if err != nil {
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
}
- }
- err = fillBuf(signature, _signature)
- if err != nil {
- if data.errorTarget != nil {
- *data.errorTarget = err
+ signature, signatureField, err := data.options.CommitSigningCallback(string(commitContent))
+ if err != nil {
+ if data.errorTarget != nil {
+ *data.errorTarget = err
+ }
+ return setCallbackError(errorMessage, err)
+ }
+
+ oid, err := data.repo.CreateCommitWithSignature(string(commitContent), signature, signatureField)
+ if err != nil {
+ if data.errorTarget != nil {
+ *data.errorTarget = err
+ }
+ return setCallbackError(errorMessage, err)
}
- return setCallbackError(errorMessage, err)
+ *_out = *oid.toC()
}
return C.int(ErrorCodeOK)
}
-// RebaseOptions are used to tell the rebase machinery how to operate
+// RebaseOptions are used to tell the rebase machinery how to operate.
type RebaseOptions struct {
- Quiet int
- InMemory int
- RewriteNotesRef string
- MergeOptions MergeOptions
- CheckoutOptions CheckoutOptions
+ Quiet int
+ InMemory int
+ RewriteNotesRef string
+ MergeOptions MergeOptions
+ CheckoutOptions CheckoutOptions
+ // CommitCreateCallback is an optional callback that allows users to override
+ // commit creation when rebasing. If specified, users can create
+ // their own commit and provide the commit ID, which may be useful for
+ // signing commits or otherwise customizing the commit creation. If this
+ // callback returns a nil Oid, then the rebase will continue to create the
+ // commit.
+ CommitCreateCallback CommitCreateCallback
+ // Deprecated: CommitSigningCallback is an optional callback that will be
+ // called with the commit content, allowing a signature to be added to the
+ // rebase commit. This field is only used when rebasing. This callback is
+ // not invoked if a CommitCreateCallback is specified. CommitCreateCallback
+ // should be used instead of this.
CommitSigningCallback CommitSigningCallback
}
type rebaseOptionsData struct {
options *RebaseOptions
+ repo *Repository
errorTarget *error
}
@@ -167,7 +233,7 @@ func rebaseOptionsFromC(opts *C.git_rebase_options) RebaseOptions {
}
}
-func populateRebaseOptions(copts *C.git_rebase_options, opts *RebaseOptions, errorTarget *error) *C.git_rebase_options {
+func populateRebaseOptions(copts *C.git_rebase_options, opts *RebaseOptions, repo *Repository, errorTarget *error) *C.git_rebase_options {
C.git_rebase_options_init(copts, C.GIT_REBASE_OPTIONS_VERSION)
if opts == nil {
return nil
@@ -179,9 +245,10 @@ func populateRebaseOptions(copts *C.git_rebase_options, opts *RebaseOptions, err
populateMergeOptions(&copts.merge_options, &opts.MergeOptions)
populateCheckoutOptions(&copts.checkout_options, &opts.CheckoutOptions, errorTarget)
- if opts.CommitSigningCallback != nil {
+ if opts.CommitCreateCallback != nil || opts.CommitSigningCallback != nil {
data := &rebaseOptionsData{
options: opts,
+ repo: repo,
errorTarget: errorTarget,
}
C._go_git_populate_rebase_callbacks(copts)
@@ -237,7 +304,7 @@ func (r *Repository) InitRebase(branch *AnnotatedCommit, upstream *AnnotatedComm
var ptr *C.git_rebase
var err error
- cOpts := populateRebaseOptions(&C.git_rebase_options{}, opts, &err)
+ cOpts := populateRebaseOptions(&C.git_rebase_options{}, opts, r, &err)
ret := C.git_rebase_init(&ptr, r.ptr, branch.ptr, upstream.ptr, onto.ptr, cOpts)
runtime.KeepAlive(branch)
runtime.KeepAlive(upstream)
@@ -261,7 +328,7 @@ func (r *Repository) OpenRebase(opts *RebaseOptions) (*Rebase, error) {
var ptr *C.git_rebase
var err error
- cOpts := populateRebaseOptions(&C.git_rebase_options{}, opts, &err)
+ cOpts := populateRebaseOptions(&C.git_rebase_options{}, opts, r, &err)
ret := C.git_rebase_open(&ptr, r.ptr, cOpts)
runtime.KeepAlive(r)
if ret == C.int(ErrorCodeUser) && err != nil {