summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/backport.yml2
-rw-r--r--.github/workflows/ci.yml3
-rw-r--r--Build_bundled_static.go5
-rw-r--r--Build_system_dynamic.go5
-rw-r--r--Build_system_static.go5
-rw-r--r--README.md15
-rw-r--r--commit.go23
-rw-r--r--deprecated.go16
-rw-r--r--go.mod2
-rw-r--r--rebase.go145
-rw-r--r--reference.go14
-rw-r--r--reference_test.go10
-rw-r--r--remote.go14
m---------vendor/libgit20
-rw-r--r--wrapper.c28
15 files changed, 210 insertions, 77 deletions
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 17f6ed4..9f18fac 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- branch: [ 'release-1.0', 'release-0.28', 'release-0.27' ]
+ branch: [ 'release-1.1', 'release-1.0', 'release-0.28', 'release-0.27' ]
runs-on: ubuntu-20.04
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d5d7034..50e5e14 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -62,8 +62,7 @@ jobs:
fail-fast: false
matrix:
libgit2:
- - 'v1.1.0'
- - 'v1.2.0'
+ - '109b4c887ffb63962c7017a66fc4a1f48becb48e' # v1.2.0 with a fixed symbol
name: Go (system-wide, dynamic)
runs-on: ubuntu-20.04
diff --git a/Build_bundled_static.go b/Build_bundled_static.go
index 85ed739..09ed0f5 100644
--- a/Build_bundled_static.go
+++ b/Build_bundled_static.go
@@ -1,3 +1,4 @@
+//go:build static && !system_libgit2
// +build static,!system_libgit2
package git
@@ -9,8 +10,8 @@ package git
#cgo CFLAGS: -DLIBGIT2_STATIC
#include <git2.h>
-#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 1 || LIBGIT2_VER_MINOR > 2
-# error "Invalid libgit2 version; this git2go supports libgit2 between v1.1.0 and v1.2.0"
+#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
+# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
#endif
*/
import "C"
diff --git a/Build_system_dynamic.go b/Build_system_dynamic.go
index 348cdc8..9500188 100644
--- a/Build_system_dynamic.go
+++ b/Build_system_dynamic.go
@@ -1,3 +1,4 @@
+//go:build !static
// +build !static
package git
@@ -7,8 +8,8 @@ package git
#cgo CFLAGS: -DLIBGIT2_DYNAMIC
#include <git2.h>
-#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 1 || LIBGIT2_VER_MINOR > 2
-# error "Invalid libgit2 version; this git2go supports libgit2 between v1.1.0 and v1.2.0"
+#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
+# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
#endif
*/
import "C"
diff --git a/Build_system_static.go b/Build_system_static.go
index c1a8292..309369d 100644
--- a/Build_system_static.go
+++ b/Build_system_static.go
@@ -1,3 +1,4 @@
+//go:build static && system_libgit2
// +build static,system_libgit2
package git
@@ -7,8 +8,8 @@ package git
#cgo CFLAGS: -DLIBGIT2_STATIC
#include <git2.h>
-#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 1 || LIBGIT2_VER_MINOR > 2
-# error "Invalid libgit2 version; this git2go supports libgit2 between v1.1.0 and v1.2.0"
+#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
+# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
#endif
*/
import "C"
diff --git a/README.md b/README.md
index d05c4c1..7cc36eb 100644
--- a/README.md
+++ b/README.md
@@ -10,20 +10,21 @@ Due to the fact that Go 1.11 module versions have semantic meaning and don't nec
| libgit2 | git2go |
|---------|---------------|
-| main | (will be v32) |
+| main | (will be v33) |
+| 1.2 | v32 |
| 1.1 | v31 |
| 1.0 | v30 |
| 0.99 | v29 |
| 0.28 | v28 |
| 0.27 | v27 |
-You can import them in your project with the version's major number as a suffix. For example, if you have libgit2 v1.1 installed, you'd import git2go v31 with:
+You can import them in your project with the version's major number as a suffix. For example, if you have libgit2 v1.2 installed, you'd import git2go v32 with:
```sh
-go get github.com/libgit2/git2go/v31
+go get github.com/libgit2/git2go/v32
```
```go
-import "github.com/libgit2/git2go/v31"
+import "github.com/libgit2/git2go/v32"
```
which will ensure there are no sudden changes to the API.
@@ -44,10 +45,10 @@ This project wraps the functionality provided by libgit2. If you're using a vers
### Versioned branch, dynamic linking
-When linking dynamically against a released version of libgit2, install it via your system's package manager. CGo will take care of finding its pkg-config file and set up the linking. Import via Go modules, e.g. to work against libgit2 v1.1
+When linking dynamically against a released version of libgit2, install it via your system's package manager. CGo will take care of finding its pkg-config file and set up the linking. Import via Go modules, e.g. to work against libgit2 v1.2
```go
-import "github.com/libgit2/git2go/v31"
+import "github.com/libgit2/git2go/v32"
```
### Versioned branch, static linking
@@ -77,7 +78,7 @@ In order to let Go pass the correct flags to `pkg-config`, `-tags static` needs
One thing to take into account is that since Go expects the `pkg-config` file to be within the same directory where `make install-static` was called, so the `go.mod` file may need to have a [`replace` directive](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) so that the correct setup is achieved. So if `git2go` is checked out at `$GOPATH/src/github.com/libgit2/git2go` and your project at `$GOPATH/src/github.com/my/project`, the `go.mod` file of `github.com/my/project` might need to have a line like
- replace github.com/libgit2/git2go/v31 ../../libgit2/git2go
+ replace github.com/libgit2/git2go/v32 ../../libgit2/git2go
Parallelism and network operations
----------------------------------
diff --git a/commit.go b/commit.go
index 0869ef2..9a09fe7 100644
--- a/commit.go
+++ b/commit.go
@@ -37,10 +37,14 @@ func (c *Commit) Message() string {
return ret
}
-func (c *Commit) MessageEncoding() string {
- ret := C.GoString(C.git_commit_message_encoding(c.cast_ptr))
+func (c *Commit) MessageEncoding() MessageEncoding {
+ ptr := C.git_commit_message_encoding(c.cast_ptr)
+ if ptr == nil {
+ return MessageEncodingUTF8
+ }
+ ret := C.GoString(ptr)
runtime.KeepAlive(c)
- return ret
+ return MessageEncoding(ret)
}
func (c *Commit) RawMessage() string {
@@ -64,6 +68,19 @@ func (c *Commit) ContentToSign() string {
// CommitSigningCallback defines a function type that takes some data to sign and returns (signature, signature_field, error)
type CommitSigningCallback func(string) (signature, signatureField string, err error)
+// CommitCreateCallback defines a function type that is called when another
+// function is going to create commits (for example, Rebase) to allow callers
+// to override the commit creation behavior. For example, users may wish to
+// sign commits by providing this information to Repository.CreateCommitBuffer,
+// signing that buffer, then calling Repository.CreateCommitWithSignature.
+type CommitCreateCallback func(
+ author, committer *Signature,
+ messageEncoding MessageEncoding,
+ message string,
+ tree *Tree,
+ parents ...*Commit,
+) (oid *Oid, err error)
+
// WithSignatureUsing creates a new signed commit from this one using the given signing callback
func (c *Commit) WithSignatureUsing(f CommitSigningCallback) (*Oid, error) {
signature, signatureField, err := f(c.ContentToSign())
diff --git a/deprecated.go b/deprecated.go
index 5e69a51..01253ee 100644
--- a/deprecated.go
+++ b/deprecated.go
@@ -237,6 +237,22 @@ func SubmoduleVisitor(csub unsafe.Pointer, name *C.char, handle unsafe.Pointer)
return C.int(ErrorCodeOK)
}
+// reference.go
+
+// Deprecated: ReferenceIsValidName is a deprecated alias of ReferenceNameIsValid.
+func ReferenceIsValidName(name string) bool {
+ valid, _ := ReferenceNameIsValid(name)
+ return valid
+}
+
+// remote.go
+
+// Deprecated: RemoteIsValidName is a deprecated alias of RemoteNameIsValid.
+func RemoteIsValidName(name string) bool {
+ valid, _ := RemoteNameIsValid(name)
+ return valid
+}
+
// tree.go
// Deprecated: CallbackGitTreeWalk is not used.
diff --git a/go.mod b/go.mod
index df3b1fb..db1ea19 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/libgit2/git2go/v31
+module github.com/libgit2/git2go/v32
go 1.13
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 {
diff --git a/reference.go b/reference.go
index ae49c21..46e9b48 100644
--- a/reference.go
+++ b/reference.go
@@ -476,7 +476,7 @@ func (v *ReferenceIterator) Free() {
C.git_reference_iterator_free(v.ptr)
}
-// ReferenceIsValidName returns whether the reference name is well-formed.
+// ReferenceNameIsValid returns whether the reference name is well-formed.
//
// Valid reference names must follow one of two patterns:
//
@@ -486,11 +486,19 @@ func (v *ReferenceIterator) Free() {
// 2. Names prefixed with "refs/" can be almost anything. You must avoid
// the characters '~', '^', ':', ' \ ', '?', '[', and '*', and the sequences
// ".." and " @ {" which have special meaning to revparse.
-func ReferenceIsValidName(name string) bool {
+func ReferenceNameIsValid(name string) (bool, error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
- return C.git_reference_is_valid_name(cname) == 1
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var valid C.int
+ ret := C.git_reference_name_is_valid(&valid, cname)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+ return valid == 1, nil
}
const (
diff --git a/reference_test.go b/reference_test.go
index 285adb5..46c9e7f 100644
--- a/reference_test.go
+++ b/reference_test.go
@@ -214,12 +214,16 @@ func TestIsNote(t *testing.T) {
}
}
-func TestReferenceIsValidName(t *testing.T) {
+func TestReferenceNameIsValid(t *testing.T) {
t.Parallel()
- if !ReferenceIsValidName("HEAD") {
+ valid, err := ReferenceNameIsValid("HEAD")
+ checkFatal(t, err)
+ if !valid {
t.Errorf("HEAD should be a valid reference name")
}
- if ReferenceIsValidName("HEAD1") {
+ valid, err = ReferenceNameIsValid("HEAD1")
+ checkFatal(t, err)
+ if valid {
t.Errorf("HEAD1 should not be a valid reference name")
}
}
diff --git a/remote.go b/remote.go
index e312a3a..2696e20 100644
--- a/remote.go
+++ b/remote.go
@@ -564,12 +564,20 @@ func freeProxyOptions(copts *C.git_proxy_options) {
C.free(unsafe.Pointer(copts.url))
}
-// RemoteIsValidName returns whether the remote name is well-formed.
-func RemoteIsValidName(name string) bool {
+// RemoteNameIsValid returns whether the remote name is well-formed.
+func RemoteNameIsValid(name string) (bool, error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
- return C.git_remote_is_valid_name(cname) == 1
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var valid C.int
+ ret := C.git_remote_name_is_valid(&valid, cname)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+ return valid == 1, nil
}
// free releases the resources of the Remote.
diff --git a/vendor/libgit2 b/vendor/libgit2
-Subproject 7f4fa178629d559c037a1f72f79f79af9c1ef8c
+Subproject 109b4c887ffb63962c7017a66fc4a1f48becb48
diff --git a/wrapper.c b/wrapper.c
index 6f65f71..e999136 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -116,18 +116,28 @@ void _go_git_populate_apply_callbacks(git_apply_options *options)
options->hunk_cb = (git_apply_hunk_cb)&hunkApplyCallback;
}
-static int commit_signing_callback(
- git_buf *signature,
- git_buf *signature_field,
- const char *commit_contents,
+static int commit_create_callback(
+ git_oid *out,
+ const git_signature *author,
+ const git_signature *committer,
+ const char *message_encoding,
+ const char *message,
+ const git_tree *tree,
+ size_t parent_count,
+ const git_commit *parents[],
void *payload)
{
char *error_message = NULL;
- const int ret = commitSigningCallback(
+ const int ret = commitCreateCallback(
&error_message,
- signature,
- signature_field,
- (char *)commit_contents,
+ out,
+ (git_signature *)author,
+ (git_signature *)committer,
+ (char *)message_encoding,
+ (char *)message,
+ (git_tree *)tree,
+ parent_count,
+ (git_commit **)parents,
payload
);
return set_callback_error(error_message, ret);
@@ -135,7 +145,7 @@ static int commit_signing_callback(
void _go_git_populate_rebase_callbacks(git_rebase_options *opts)
{
- opts->signing_cb = commit_signing_callback;
+ opts->commit_create_cb = commit_create_callback;
}
void _go_git_populate_clone_callbacks(git_clone_options *opts)