summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Ezell <[email protected]>2014-02-27 16:36:44 -0800
committerJesse Ezell <[email protected]>2014-02-27 16:36:44 -0800
commit374e2112dfc298fa5ecb0805624d75b3500cc345 (patch)
tree9da99d97412bee3ad8a5c0afdd97873f979b514b
parente2db9b16cda4aec7c94efc19cf2379578bef1b48 (diff)
add push, refine remotes
-rw-r--r--git_test.go15
-rw-r--r--push.go181
-rw-r--r--push_test.go56
-rw-r--r--remote.go99
-rw-r--r--wrapper.c12
5 files changed, 310 insertions, 53 deletions
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..0694fe3
--- /dev/null
+++ b/push.go
@@ -0,0 +1,181 @@
+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 {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_push_unpack_ok(p.ptr)
+ if ret == 0 {
+ return false
+ } else {
+ 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))
+ }
+
+ 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
index 38c1d47..ab2e174 100644
--- a/remote.go
+++ b/remote.go
@@ -40,27 +40,7 @@ type RemoteCallbacks struct {
UpdateTipsCallback
}
-type Remote interface {
- Save() error
- Owner() Repository
- Name() string
- Url() string
- PushUrl() string
-
- SetUrl(url string) error
- SetPushUrl(url string) error
-
- AddFetch(refspec string) error
- GetFetchRefspecs() ([]string, error)
- SetFetchRefspecs(refspecs []string) error
- AddPush(refspec string) error
- GetPushRefspecs() ([]string, error)
- SetPushRefspecs(refspecs []string) error
- ClearRefspecs()
- RefspecCount() uint
-}
-
-type gitRemote struct {
+type Remote struct {
ptr *C.git_remote
}
@@ -161,13 +141,13 @@ func RemoteIsValidName(name string) bool {
return false
}
-func freeRemote(o *gitRemote) {
- C.git_remote_free(o.ptr)
+func (r *Remote) Free() {
+ runtime.SetFinalizer(r, nil)
+ C.git_remote_free(r.ptr)
}
-func CreateRemote(repo *Repository, name string, url string) (Remote, error) {
- remote := &gitRemote{}
- runtime.SetFinalizer(remote, freeRemote)
+func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
+ remote := &Remote{}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
@@ -181,12 +161,12 @@ func CreateRemote(repo *Repository, name string, url string) (Remote, error) {
if ret < 0 {
return nil, MakeGitError(ret)
}
+ runtime.SetFinalizer(remote, (*Remote).Free)
return remote, nil
}
-func CreateRemoteWithFetchspec(repo *Repository, name string, url string, fetch string) (Remote, error) {
- remote := &gitRemote{}
- runtime.SetFinalizer(remote, freeRemote)
+func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch string) (*Remote, error) {
+ remote := &Remote{}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
@@ -202,12 +182,12 @@ func CreateRemoteWithFetchspec(repo *Repository, name string, url string, fetch
if ret < 0 {
return nil, MakeGitError(ret)
}
+ runtime.SetFinalizer(remote, (*Remote).Free)
return remote, nil
}
-func CreateRemoteInMemory(repo *Repository, fetch string, url string) (Remote, error) {
- remote := &gitRemote{}
- runtime.SetFinalizer(remote, freeRemote)
+func (repo *Repository) CreateRemoteInMemory(fetch string, url string) (*Remote, error) {
+ remote := &Remote{}
curl := C.CString(url)
defer C.free(unsafe.Pointer(curl))
@@ -221,12 +201,12 @@ func CreateRemoteInMemory(repo *Repository, fetch string, url string) (Remote, e
if ret < 0 {
return nil, MakeGitError(ret)
}
+ runtime.SetFinalizer(remote, (*Remote).Free)
return remote, nil
}
-func LoadRemote(repo *Repository, name string) (Remote, error) {
- remote := &gitRemote{}
- runtime.SetFinalizer(remote, freeRemote)
+func (repo *Repository) LoadRemote(name string) (*Remote, error) {
+ remote := &Remote{}
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
@@ -238,10 +218,11 @@ func LoadRemote(repo *Repository, name string) (Remote, error) {
if ret < 0 {
return nil, MakeGitError(ret)
}
+ runtime.SetFinalizer(remote, (*Remote).Free)
return remote, nil
}
-func (o *gitRemote) Save() error {
+func (o *Remote) Save() error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -253,23 +234,23 @@ func (o *gitRemote) Save() error {
return nil
}
-func (o *gitRemote) Owner() Repository {
+func (o *Remote) Owner() Repository {
return Repository{C.git_remote_owner(o.ptr)}
}
-func (o *gitRemote) Name() string {
+func (o *Remote) Name() string {
return C.GoString(C.git_remote_name(o.ptr))
}
-func (o *gitRemote) Url() string {
+func (o *Remote) Url() string {
return C.GoString(C.git_remote_url(o.ptr))
}
-func (o *gitRemote) PushUrl() string {
+func (o *Remote) PushUrl() string {
return C.GoString(C.git_remote_pushurl(o.ptr))
}
-func (o *gitRemote) SetUrl(url string) error {
+func (o *Remote) SetUrl(url string) error {
curl := C.CString(url)
defer C.free(unsafe.Pointer(curl))
@@ -283,7 +264,7 @@ func (o *gitRemote) SetUrl(url string) error {
return nil
}
-func (o *gitRemote) SetPushUrl(url string) error {
+func (o *Remote) SetPushUrl(url string) error {
curl := C.CString(url)
defer C.free(unsafe.Pointer(curl))
@@ -297,7 +278,7 @@ func (o *gitRemote) SetPushUrl(url string) error {
return nil
}
-func (o *gitRemote) AddFetch(refspec string) error {
+func (o *Remote) AddFetch(refspec string) error {
crefspec := C.CString(refspec)
defer C.free(unsafe.Pointer(crefspec))
@@ -311,7 +292,7 @@ func (o *gitRemote) AddFetch(refspec string) error {
return nil
}
-func (o *gitRemote) GetFetchRefspecs() ([]string, error) {
+func (o *Remote) GetFetchRefspecs() ([]string, error) {
crefspecs := C.git_strarray{}
runtime.LockOSThread()
@@ -330,7 +311,7 @@ func (o *gitRemote) GetFetchRefspecs() ([]string, error) {
return refspecs, nil
}
-func (o *gitRemote) SetFetchRefspecs(refspecs []string) error {
+func (o *Remote) SetFetchRefspecs(refspecs []string) error {
crefspecs := C.git_strarray{}
crefspecs.count = C.size_t(len(refspecs))
crefspecs.strings = (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(crefspecs.count))))
@@ -349,7 +330,7 @@ func (o *gitRemote) SetFetchRefspecs(refspecs []string) error {
return nil
}
-func (o *gitRemote) AddPush(refspec string) error {
+func (o *Remote) AddPush(refspec string) error {
crefspec := C.CString(refspec)
defer C.free(unsafe.Pointer(crefspec))
@@ -363,7 +344,7 @@ func (o *gitRemote) AddPush(refspec string) error {
return nil
}
-func (o *gitRemote) GetPushRefspecs() ([]string, error) {
+func (o *Remote) GetPushRefspecs() ([]string, error) {
crefspecs := C.git_strarray{}
runtime.LockOSThread()
@@ -382,7 +363,7 @@ func (o *gitRemote) GetPushRefspecs() ([]string, error) {
return refspecs, nil
}
-func (o *gitRemote) SetPushRefspecs(refspecs []string) error {
+func (o *Remote) SetPushRefspecs(refspecs []string) error {
crefspecs := C.git_strarray{}
crefspecs.count = C.size_t(len(refspecs))
crefspecs.strings = (**C.char)(C.malloc(C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)) * uintptr(crefspecs.count))))
@@ -401,10 +382,28 @@ func (o *gitRemote) SetPushRefspecs(refspecs []string) error {
return nil
}
-func (o *gitRemote) ClearRefspecs() {
+func (o *Remote) ClearRefspecs() {
C.git_remote_clear_refspecs(o.ptr)
}
-func (o *gitRemote) RefspecCount() uint {
+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))
+ }
+
+ 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/wrapper.c b/wrapper.c
index 7519a96..9e193ca 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -51,4 +51,16 @@ char *_go_git_get_strarray_n(git_strarray *array, size_t n) {
return array->strings[n];
}
+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);
+}
+
/* EOF */