add push, refine remotes

This commit is contained in:
Jesse Ezell 2014-02-27 16:36:44 -08:00
parent e2db9b16cd
commit 374e2112df
5 changed files with 310 additions and 53 deletions

View File

@ -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
}

181
push.go Normal file
View File

@ -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))
}

56
push_test.go Normal file
View File

@ -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: "random@hacker.com", 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()
}

View File

@ -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
}

View File

@ -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 */