summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clone.go76
-rw-r--r--credentials.go74
-rw-r--r--git.go2
-rw-r--r--git_test.go15
-rw-r--r--push.go182
-rw-r--r--push_test.go56
-rw-r--r--remote.go411
-rw-r--r--submodule.go2
-rw-r--r--wrapper.c25
9 files changed, 838 insertions, 5 deletions
diff --git a/clone.go b/clone.go
new file mode 100644
index 0000000..c2abbe5
--- /dev/null
+++ b/clone.go
@@ -0,0 +1,76 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/errors.h>
+
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type CloneOptions struct {
+ *CheckoutOpts
+ *RemoteCallbacks
+ Bare bool
+ IgnoreCertErrors bool
+ RemoteName string
+ CheckoutBranch string
+}
+
+func Clone(url string, path string, options *CloneOptions) (*Repository, error) {
+ repo := new(Repository)
+
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ var copts C.git_clone_options
+ populateCloneOptions(&copts, options)
+
+ // finish populating clone options here so we can defer CString free
+ if len(options.RemoteName) != 0 {
+ copts.remote_name = C.CString(options.RemoteName)
+ defer C.free(unsafe.Pointer(copts.remote_name))
+ }
+
+ 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)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ runtime.SetFinalizer(repo, (*Repository).Free)
+ return repo, nil
+}
+
+func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) {
+ ptr = &C.git_clone_options{}
+ C.git_clone_init_options(ptr, C.GIT_CLONE_OPTIONS_VERSION)
+
+ if opts == nil {
+ return
+ }
+ populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts)
+ populateRemoteCallbacks(&ptr.remote_callbacks, opts.RemoteCallbacks)
+ if opts.Bare {
+ ptr.bare = 1
+ } else {
+ ptr.bare = 0
+ }
+ if opts.IgnoreCertErrors {
+ ptr.ignore_cert_errors = 1
+ } else {
+ ptr.ignore_cert_errors = 0
+ }
+}
diff --git a/credentials.go b/credentials.go
new file mode 100644
index 0000000..c5ed055
--- /dev/null
+++ b/credentials.go
@@ -0,0 +1,74 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/errors.h>
+*/
+import "C"
+import "unsafe"
+
+type CredType uint
+
+const (
+ CredTypeUserpassPlaintext CredType = C.GIT_CREDTYPE_USERPASS_PLAINTEXT
+ CredTypeSshKey = C.GIT_CREDTYPE_SSH_KEY
+ CredTypeSshCustom = C.GIT_CREDTYPE_SSH_CUSTOM
+ CredTypeDefault = C.GIT_CREDTYPE_DEFAULT
+)
+
+type Cred struct {
+ ptr *C.git_cred
+}
+
+func (o *Cred) HasUsername() bool {
+ if C.git_cred_has_username(o.ptr) == 1 {
+ return true
+ }
+ return false
+}
+
+func (o *Cred) Type() CredType {
+ return (CredType)(o.ptr.credtype)
+}
+
+func credFromC(ptr *C.git_cred) *Cred {
+ return &Cred{ptr}
+}
+
+func NewCredUserpassPlaintext(username string, password string) (int, Cred) {
+ cred := Cred{}
+ cusername := C.CString(username)
+ defer C.free(unsafe.Pointer(cusername))
+ cpassword := C.CString(password)
+ defer C.free(unsafe.Pointer(cpassword))
+ ret := C.git_cred_userpass_plaintext_new(&cred.ptr, cusername, cpassword)
+ return int(ret), cred
+}
+
+func NewCredSshKey(username string, publickey string, privatekey string, passphrase string) (int, Cred) {
+ cred := Cred{}
+ cusername := C.CString(username)
+ defer C.free(unsafe.Pointer(cusername))
+ cpublickey := C.CString(publickey)
+ defer C.free(unsafe.Pointer(cpublickey))
+ cprivatekey := C.CString(privatekey)
+ defer C.free(unsafe.Pointer(cprivatekey))
+ cpassphrase := C.CString(passphrase)
+ defer C.free(unsafe.Pointer(cpassphrase))
+ ret := C.git_cred_ssh_key_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase)
+ return int(ret), cred
+}
+
+func NewCredSshKeyFromAgent(username string) (int, Cred) {
+ cred := Cred{}
+ cusername := C.CString(username)
+ defer C.free(unsafe.Pointer(cusername))
+ ret := C.git_cred_ssh_key_from_agent(&cred.ptr, cusername)
+ return int(ret), cred
+}
+
+func NewCredDefault() (int, Cred) {
+ cred := Cred{}
+ ret := C.git_cred_default_new(&cred.ptr)
+ return int(ret), cred
+}
diff --git a/git.go b/git.go
index 7c76c30..db9522b 100644
--- a/git.go
+++ b/git.go
@@ -10,8 +10,8 @@ import (
"bytes"
"errors"
"runtime"
- "unsafe"
"strings"
+ "unsafe"
)
const (
diff --git a/git_test.go b/git_test.go
index 52aea1d..fff3c6c 100644
--- a/git_test.go
+++ b/git_test.go
@@ -1,8 +1,8 @@
package git
import (
- "testing"
"io/ioutil"
+ "testing"
"time"
)
@@ -14,7 +14,17 @@ func createTestRepo(t *testing.T) *Repository {
checkFatal(t, err)
tmpfile := "README"
- err = ioutil.WriteFile(path + "/" + tmpfile, []byte("foo\n"), 0644)
+ err = ioutil.WriteFile(path+"/"+tmpfile, []byte("foo\n"), 0644)
+ checkFatal(t, err)
+
+ return repo
+}
+
+func createBareTestRepo(t *testing.T) *Repository {
+ // figure out where we can create the test repo
+ path, err := ioutil.TempDir("", "git2go")
+ checkFatal(t, err)
+ repo, err := InitRepository(path, true)
checkFatal(t, err)
return repo
@@ -44,4 +54,3 @@ func seedTestRepo(t *testing.T, repo *Repository) (*Oid, *Oid) {
return commitId, treeId
}
-
diff --git a/push.go b/push.go
new file mode 100644
index 0000000..5fb7f07
--- /dev/null
+++ b/push.go
@@ -0,0 +1,182 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/errors.h>
+
+int _go_git_push_status_foreach(git_push *push, void *data);
+int _go_git_push_set_callbacks(git_push *push, void *packbuilder_progress_data, void *transfer_progress_data);
+
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type Push struct {
+ ptr *C.git_push
+
+ packbuilderProgress *PackbuilderProgressCallback
+ transferProgress *PushTransferProgressCallback
+}
+
+func newPushFromC(cpush *C.git_push) *Push {
+ p := &Push{ptr: cpush}
+ runtime.SetFinalizer(p, (*Push).Free)
+ return p
+}
+
+func (p *Push) Free() {
+ runtime.SetFinalizer(p, nil)
+ C.git_push_free(p.ptr)
+}
+
+func (remote *Remote) NewPush() (*Push, error) {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var cpush *C.git_push
+ ret := C.git_push_new(&cpush, remote.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newPushFromC(cpush), nil
+}
+
+func (p *Push) Finish() error {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_push_finish(p.ptr)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (p *Push) UnpackOk() bool {
+
+ ret := C.git_push_unpack_ok(p.ptr)
+ if ret == 0 {
+ return false
+ }
+ return true
+
+}
+
+func (p *Push) UpdateTips(sig *Signature, msg string) error {
+
+ var csig *C.git_signature = nil
+ if sig != nil {
+ csig = sig.toC()
+ defer C.free(unsafe.Pointer(csig))
+ }
+
+ var cmsg *C.char
+ if msg == "" {
+ cmsg = nil
+ } else {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_push_update_tips(p.ptr, csig, cmsg)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (p *Push) AddRefspec(refspec string) error {
+
+ crefspec := C.CString(refspec)
+ defer C.free(unsafe.Pointer(crefspec))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_push_add_refspec(p.ptr, crefspec)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+type PushOptions struct {
+ Version uint
+ PbParallelism uint
+}
+
+func (p *Push) SetOptions(opts PushOptions) error {
+ copts := C.git_push_options{version: C.uint(opts.Version), pb_parallelism: C.uint(opts.PbParallelism)}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_push_set_options(p.ptr, &copts)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+type StatusForeachFunc func(ref string, msg string) int
+
+//export statusForeach
+func statusForeach(_ref *C.char, _msg *C.char, _data unsafe.Pointer) C.int {
+ ref := C.GoString(_ref)
+ msg := C.GoString(_msg)
+
+ cb := (*StatusForeachFunc)(_data)
+
+ return C.int((*cb)(ref, msg))
+}
+
+func (p *Push) StatusForeach(callback StatusForeachFunc) error {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C._go_git_push_status_foreach(p.ptr, unsafe.Pointer(&callback))
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+
+}
+
+type PushCallbacks struct {
+ PackbuilderProgress *PackbuilderProgressCallback
+ TransferProgress *PushTransferProgressCallback
+}
+
+type PackbuilderProgressCallback func(stage int, current uint, total uint) int
+type PushTransferProgressCallback func(current uint, total uint, bytes uint) int
+
+//export packbuilderProgress
+func packbuilderProgress(stage C.int, current C.uint, total C.uint, data unsafe.Pointer) C.int {
+ return C.int((*(*PackbuilderProgressCallback)(data))(int(stage), uint(current), uint(total)))
+}
+
+//export pushTransferProgress
+func pushTransferProgress(current C.uint, total C.uint, bytes C.size_t, data unsafe.Pointer) C.int {
+ return C.int((*(*PushTransferProgressCallback)(data))(uint(current), uint(total), uint(bytes)))
+}
+
+func (p *Push) SetCallbacks(callbacks PushCallbacks) {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ // save callbacks so they don't get GC'd
+ p.packbuilderProgress = callbacks.PackbuilderProgress
+ p.transferProgress = callbacks.TransferProgress
+
+ C._go_git_push_set_callbacks(p.ptr, unsafe.Pointer(p.packbuilderProgress), unsafe.Pointer(p.transferProgress))
+}
diff --git a/push_test.go b/push_test.go
new file mode 100644
index 0000000..dfd4af7
--- /dev/null
+++ b/push_test.go
@@ -0,0 +1,56 @@
+package git
+
+import (
+ "log"
+ "testing"
+ "time"
+)
+
+func Test_Push_ToRemote(t *testing.T) {
+ repo := createBareTestRepo(t)
+ repo2 := createTestRepo(t)
+
+ remote, err := repo2.CreateRemote("test_push", repo.Path())
+ checkFatal(t, err)
+
+ index, err := repo2.Index()
+ checkFatal(t, err)
+
+ index.AddByPath("README")
+
+ err = index.Write()
+ checkFatal(t, err)
+
+ newTreeId, err := index.WriteTree()
+ checkFatal(t, err)
+
+ tree, err := repo2.LookupTree(newTreeId)
+ checkFatal(t, err)
+
+ sig := &Signature{Name: "Rand Om Hacker", Email: "[email protected]", When: time.Now()}
+ // this should cause master branch to be created if it does not already exist
+ _, err = repo2.CreateCommit("HEAD", sig, sig, "message", tree)
+ checkFatal(t, err)
+
+ push, err := remote.NewPush()
+ checkFatal(t, err)
+
+ err = push.AddRefspec("refs/heads/master")
+ checkFatal(t, err)
+
+ err = push.Finish()
+ checkFatal(t, err)
+
+ err = push.StatusForeach(func(ref string, msg string) int {
+ log.Printf("%s -> %s", ref, msg)
+ return 0
+ })
+ checkFatal(t, err)
+
+ if !push.UnpackOk() {
+ t.Fatalf("unable to unpack")
+ }
+
+ defer remote.Free()
+ defer repo.Free()
+}
diff --git a/remote.go b/remote.go
new file mode 100644
index 0000000..da688e7
--- /dev/null
+++ b/remote.go
@@ -0,0 +1,411 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/errors.h>
+
+extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks);
+
+*/
+import "C"
+import "unsafe"
+import "runtime"
+
+type TransferProgress struct {
+ TotalObjects uint
+ IndexedObjects uint
+ ReceivedObjects uint
+ LocalObjects uint
+ TotalDeltas uint
+ ReceivedBytes uint
+}
+
+func newTransferProgressFromC(c *C.git_transfer_progress) TransferProgress {
+ return TransferProgress{
+ TotalObjects: uint(c.total_objects),
+ IndexedObjects: uint(c.indexed_objects),
+ ReceivedObjects: uint(c.received_objects),
+ LocalObjects: uint(c.local_objects),
+ TotalDeltas: uint(c.total_deltas),
+ ReceivedBytes: uint(c.received_bytes)}
+}
+
+type RemoteCompletion uint
+
+const (
+ RemoteCompletionDownload RemoteCompletion = C.GIT_REMOTE_COMPLETION_DOWNLOAD
+ RemoteCompletionIndexing = C.GIT_REMOTE_COMPLETION_INDEXING
+ RemoteCompletionError = C.GIT_REMOTE_COMPLETION_ERROR
+)
+
+type ProgressCallback func(str string) int
+type CompletionCallback func(RemoteCompletion) int
+type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (int, *Cred)
+type TransferProgressCallback func(stats TransferProgress) int
+type UpdateTipsCallback func(refname string, a *Oid, b *Oid) int
+
+type RemoteCallbacks struct {
+ ProgressCallback
+ CompletionCallback
+ CredentialsCallback
+ TransferProgressCallback
+ UpdateTipsCallback
+}
+
+type Remote struct {
+ ptr *C.git_remote
+}
+
+func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) {
+ C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
+ if callbacks == nil {
+ return
+ }
+ C._go_git_setup_callbacks(ptr)
+ ptr.payload = unsafe.Pointer(callbacks)
+}
+
+//export progressCallback
+func progressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int {
+ callbacks := (*RemoteCallbacks)(data)
+ if callbacks.ProgressCallback == nil {
+ return 0
+ }
+ str := C.GoStringN(_str, _len)
+ return callbacks.ProgressCallback(str)
+}
+
+//export completionCallback
+func completionCallback(completion_type C.git_remote_completion_type, data unsafe.Pointer) int {
+ callbacks := (*RemoteCallbacks)(data)
+ if callbacks.CompletionCallback == nil {
+ return 0
+ }
+ return callbacks.CompletionCallback((RemoteCompletion)(completion_type))
+}
+
+//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)
+ if callbacks.CredentialsCallback == nil {
+ return 0
+ }
+ url := C.GoString(_url)
+ username_from_url := C.GoString(_username_from_url)
+ ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
+ *_cred = cred.ptr
+ return ret
+}
+
+//export transferProgressCallback
+func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointer) int {
+ callbacks := (*RemoteCallbacks)(data)
+ if callbacks.TransferProgressCallback == nil {
+ return 0
+ }
+ return callbacks.TransferProgressCallback(newTransferProgressFromC(stats))
+}
+
+//export updateTipsCallback
+func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int {
+ callbacks := (*RemoteCallbacks)(data)
+ if callbacks.UpdateTipsCallback == nil {
+ return 0
+ }
+ refname := C.GoString(_refname)
+ a := newOidFromC(_a)
+ b := newOidFromC(_b)
+ return callbacks.UpdateTipsCallback(refname, a, b)
+}
+
+func RemoteIsValidName(name string) bool {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ if C.git_remote_is_valid_name(cname) == 1 {
+ return true
+ }
+ return false
+}
+
+func (r *Remote) Free() {
+ runtime.SetFinalizer(r, nil)
+ C.git_remote_free(r.ptr)
+}
+
+func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
+ remote := &Remote{}
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create(&remote.ptr, repo.ptr, cname, curl)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch string) (*Remote, error) {
+ remote := &Remote{}
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+ cfetch := C.CString(fetch)
+ defer C.free(unsafe.Pointer(cfetch))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create_with_fetchspec(&remote.ptr, repo.ptr, cname, curl, cfetch)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (repo *Repository) CreateRemoteInMemory(fetch string, url string) (*Remote, error) {
+ remote := &Remote{}
+
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+ cfetch := C.CString(fetch)
+ defer C.free(unsafe.Pointer(cfetch))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create_inmemory(&remote.ptr, repo.ptr, cfetch, curl)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (repo *Repository) LoadRemote(name string) (*Remote, error) {
+ remote := &Remote{}
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_load(&remote.ptr, repo.ptr, cname)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (o *Remote) Save() error {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_save(o.ptr)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) Owner() Repository {
+ return Repository{C.git_remote_owner(o.ptr)}
+}
+
+func (o *Remote) Name() string {
+ return C.GoString(C.git_remote_name(o.ptr))
+}
+
+func (o *Remote) Url() string {
+ return C.GoString(C.git_remote_url(o.ptr))
+}
+
+func (o *Remote) PushUrl() string {
+ return C.GoString(C.git_remote_pushurl(o.ptr))
+}
+
+func (o *Remote) SetUrl(url string) error {
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_set_url(o.ptr, curl)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) SetPushUrl(url string) error {
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_set_pushurl(o.ptr, curl)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) AddFetch(refspec string) error {
+ crefspec := C.CString(refspec)
+ defer C.free(unsafe.Pointer(crefspec))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_add_fetch(o.ptr, crefspec)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func sptr(p uintptr) *C.char {
+ return *(**C.char)(unsafe.Pointer(p))
+}
+
+func makeStringsFromCStrings(x **C.char, l int) []string {
+ s := make([]string, l)
+ i := 0
+ for p := uintptr(unsafe.Pointer(x)); i < l; p += unsafe.Sizeof(uintptr(0)) {
+ s[i] = C.GoString(sptr(p))
+ i++
+ }
+ return s
+}
+
+func makeCStringsFromStrings(s []string) **C.char {
+ l := len(s)
+ x := (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(l))))
+ i := 0
+ for p := uintptr(unsafe.Pointer(x)); i < l; p += unsafe.Sizeof(uintptr(0)) {
+ *(**C.char)(unsafe.Pointer(p)) = C.CString(s[i])
+ i++
+ }
+ return x
+}
+
+func (o *Remote) GetFetchRefspecs() ([]string, error) {
+ crefspecs := C.git_strarray{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_get_fetch_refspecs(&crefspecs, o.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ defer C.git_strarray_free(&crefspecs)
+
+ refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
+ return refspecs, nil
+}
+
+func (o *Remote) SetFetchRefspecs(refspecs []string) error {
+ crefspecs := C.git_strarray{}
+ crefspecs.count = C.size_t(len(refspecs))
+ crefspecs.strings = makeCStringsFromStrings(refspecs)
+ defer C.git_strarray_free(&crefspecs)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_set_fetch_refspecs(o.ptr, &crefspecs)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) AddPush(refspec string) error {
+ crefspec := C.CString(refspec)
+ defer C.free(unsafe.Pointer(crefspec))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_add_push(o.ptr, crefspec)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) GetPushRefspecs() ([]string, error) {
+ crefspecs := C.git_strarray{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_get_push_refspecs(&crefspecs, o.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ defer C.git_strarray_free(&crefspecs)
+ refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
+ return refspecs, nil
+}
+
+func (o *Remote) SetPushRefspecs(refspecs []string) error {
+ crefspecs := C.git_strarray{}
+ crefspecs.count = C.size_t(len(refspecs))
+ crefspecs.strings = makeCStringsFromStrings(refspecs)
+ defer C.git_strarray_free(&crefspecs)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_set_push_refspecs(o.ptr, &crefspecs)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) ClearRefspecs() {
+ C.git_remote_clear_refspecs(o.ptr)
+}
+
+func (o *Remote) RefspecCount() uint {
+ return uint(C.git_remote_refspec_count(o.ptr))
+}
+
+func (o *Remote) Fetch(sig *Signature, msg string) error {
+
+ var csig *C.git_signature = nil
+ if sig != nil {
+ csig = sig.toC()
+ defer C.free(unsafe.Pointer(csig))
+ }
+
+ var cmsg *C.char
+ if msg == "" {
+ cmsg = nil
+ } else {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+ ret := C.git_remote_fetch(o.ptr, csig, cmsg)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
diff --git a/submodule.go b/submodule.go
index dcc4723..a94afd4 100644
--- a/submodule.go
+++ b/submodule.go
@@ -238,7 +238,7 @@ func (sub *Submodule) SetUpdate(update SubmoduleUpdate) SubmoduleUpdate {
}
func (sub *Submodule) FetchRecurseSubmodules() SubmoduleRecurse {
- return SubmoduleRecurse(C.git_submodule_fetch_recurse_submodules(sub.ptr));
+ return SubmoduleRecurse(C.git_submodule_fetch_recurse_submodules(sub.ptr))
}
func (sub *Submodule) SetFetchRecurseSubmodules(recurse SubmoduleRecurse) error {
diff --git a/wrapper.c b/wrapper.c
index 4ce4c5c..0fa6c48 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -25,6 +25,31 @@ int _go_git_odb_foreach(git_odb *db, void *payload)
return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload);
}
+void _go_git_setup_callbacks(git_remote_callbacks *callbacks) {
+ typedef int (*progress_cb)(const char *str, int len, void *data);
+ typedef int (*completion_cb)(git_remote_completion_type type, void *data);
+ typedef int (*credentials_cb)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data);
+ typedef int (*transfer_progress_cb)(const git_transfer_progress *stats, void *data);
+ typedef int (*update_tips_cb)(const char *refname, const git_oid *a, const git_oid *b, void *data);
+ callbacks->progress = (progress_cb)progressCallback;
+ callbacks->completion = (completion_cb)completionCallback;
+ callbacks->credentials = (credentials_cb)credentialsCallback;
+ callbacks->transfer_progress = (transfer_progress_cb)transferProgressCallback;
+ callbacks->update_tips = (update_tips_cb)updateTipsCallback;
+}
+
+typedef int (*status_foreach_cb)(const char *ref, const char *msg, void *data);
+
+int _go_git_push_status_foreach(git_push *push, void *data)
+{
+ return git_push_status_foreach(push, (status_foreach_cb)statusForeach, data);
+}
+
+int _go_git_push_set_callbacks(git_push *push, void *packbuilder_progress_data, void *transfer_progress_data)
+{
+ return git_push_set_callbacks(push, packbuilderProgress, packbuilder_progress_data, pushTransferProgress, transfer_progress_data);
+}
+
int _go_blob_chunk_cb(char *buffer, size_t maxLen, void *payload)
{
return blobChunkCb(buffer, maxLen, payload);