From e825d66fba2cb4169c7f3b0a43c491cf9e8c0738 Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Sat, 4 Jan 2014 00:40:21 +0000 Subject: work in progress wrapping git_clone --- clone.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 clone.go (limited to 'clone.go') diff --git a/clone.go b/clone.go new file mode 100644 index 0000000..672c325 --- /dev/null +++ b/clone.go @@ -0,0 +1,69 @@ +package git + +/* +#include +#include + +static git_clone_options git_clone_options_init() { + git_clone_options ret = GIT_CLONE_OPTIONS_INIT; + return ret; +} + +*/ +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) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_clone(&repo.ptr, curl, cpath, &copts) + if ret < 0 { + return nil, LastError() + } + + runtime.SetFinalizer(repo, (*Repository).Free) + return repo, nil +} + +func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) { + *ptr = C.git_clone_options_init() + 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 + } +} + -- cgit v1.2.3 From 32bf5f0a234e0c3cd00dc8eec349ee820f765f19 Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Mon, 6 Jan 2014 20:05:35 +0000 Subject: wip wrapping git_remote --- clone.go | 11 ++++ remote.go | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wrapper.c | 8 +++ 3 files changed, 212 insertions(+) (limited to 'clone.go') diff --git a/clone.go b/clone.go index 672c325..425e179 100644 --- a/clone.go +++ b/clone.go @@ -37,6 +37,17 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) 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) diff --git a/remote.go b/remote.go index 0645291..5300c42 100644 --- a/remote.go +++ b/remote.go @@ -6,10 +6,13 @@ package git extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks); extern git_remote_callbacks _go_git_remote_callbacks_init(); +extern void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n); +extern char *_go_git_get_strarray_n(git_strarray *array, size_t n); */ import "C" import "unsafe" +import "runtime" type TransferProgress struct { ptr *C.git_transfer_progress @@ -36,6 +39,30 @@ type RemoteCallbacks struct { UpdateTipsCallback } +type Remote interface { + Save() int + Owner() Repository + Name() string + Url() string + PushUrl() string + + SetUrl(url string) int + SetPushUrl(url string) int + + AddFetch(refspec string) int + GetFetchRefspecs() (err int, refspecs []string) + SetFetchRefspecs(refspecs []string) int + AddPush(refspec string) int + GetPushRefspecs() (err int, refspecs []string) + SetPushRefspecs(refspecs []string) int + ClearRefspecs() + RefspecCount() uint +} + +type gitRemote struct { + ptr *C.git_remote +} + func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { *ptr = C._go_git_remote_callbacks_init() if callbacks == nil { @@ -123,3 +150,169 @@ func (o TransferProgress) TotalDeltas() uint { func (o TransferProgress) ReceivedBytes() uint { return uint(o.ptr.received_bytes) } + +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 freeRemote(o *gitRemote) { + C.git_remote_free(o.ptr) +} + +func CreateRemote(repo *Repository, name string, url string) (int, Remote) { + remote := &gitRemote{} + runtime.SetFinalizer(remote, freeRemote) + + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + + ret := C.git_remote_create(&remote.ptr, repo.ptr, cname, curl) + return int(ret), remote +} + +func CreateRemoteWithFetchspec(repo *Repository, name string, url string, fetch string) (int, Remote) { + remote := &gitRemote{} + runtime.SetFinalizer(remote, freeRemote) + + 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)) + + ret := C.git_remote_create_with_fetchspec(&remote.ptr, repo.ptr, cname, curl, cfetch) + return int(ret), remote +} + +func CreateRemoteInMemory(repo *Repository, fetch string, url string) (int, Remote) { + remote := &gitRemote{} + runtime.SetFinalizer(remote, freeRemote) + + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + cfetch := C.CString(fetch) + defer C.free(unsafe.Pointer(cfetch)) + + ret := C.git_remote_create_inmemory(&remote.ptr, repo.ptr, cfetch, curl) + return int(ret), remote +} + +func LoadRemote(repo *Repository, name string) (int, Remote) { + remote := &gitRemote{} + runtime.SetFinalizer(remote, freeRemote) + + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + ret := C.git_remote_load(&remote.ptr, repo.ptr, cname) + return int(ret), remote +} + +func (o *gitRemote) Save() int { + return int(C.git_remote_save(o.ptr)) +} + +func (o *gitRemote) Owner() Repository { + return Repository{C.git_remote_owner(o.ptr)} +} + +func (o *gitRemote) Name() string { + return C.GoString(C.git_remote_name(o.ptr)) +} + +func (o *gitRemote) Url() string { + return C.GoString(C.git_remote_url(o.ptr)) +} + +func (o *gitRemote) PushUrl() string { + return C.GoString(C.git_remote_pushurl(o.ptr)) +} + +func (o *gitRemote) SetUrl(url string) int { + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + return int(C.git_remote_set_url(o.ptr, curl)) +} + +func (o *gitRemote) SetPushUrl(url string) int { + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + return int(C.git_remote_set_pushurl(o.ptr, curl)) +} + +func (o *gitRemote) AddFetch(refspec string) int { + crefspec := C.CString(refspec) + defer C.free(unsafe.Pointer(crefspec)) + return int(C.git_remote_add_fetch(o.ptr, crefspec)) +} + +func (o *gitRemote) GetFetchRefspecs() (err int, refspecs []string) { + crefspecs := C.git_strarray{} + err = int(C.git_remote_get_fetch_refspecs(&crefspecs, o.ptr)) + defer C.git_strarray_free(&crefspecs) + refspecs = make([]string, crefspecs.count) + + for i := 0; i < int(crefspecs.count); i++ { + refspecs[i] = C.GoString(C._go_git_get_strarray_n(&crefspecs, C.size_t(i))) + } + return +} + +func (o *gitRemote) SetFetchRefspecs(refspecs []string) int { + 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)))) + for i, refspec := range refspecs { + C._go_git_set_strarray_n(&crefspecs, C.CString(refspec), C.size_t(i)) + } + defer C.git_strarray_free(&crefspecs) + + return int(C.git_remote_set_fetch_refspecs(o.ptr, &crefspecs)) +} + +func (o *gitRemote) AddPush(refspec string) int { + crefspec := C.CString(refspec) + defer C.free(unsafe.Pointer(crefspec)) + return int(C.git_remote_add_push(o.ptr, crefspec)) +} + +func (o *gitRemote) GetPushRefspecs() (err int, refspecs []string) { + crefspecs := C.git_strarray{} + err = int(C.git_remote_get_push_refspecs(&crefspecs, o.ptr)) + defer C.git_strarray_free(&crefspecs) + refspecs = make([]string, crefspecs.count) + + for i := 0; i < int(crefspecs.count); i++ { + refspecs[i] = C.GoString(C._go_git_get_strarray_n(&crefspecs, C.size_t(i))) + } + return +} + +func (o *gitRemote) SetPushRefspecs(refspecs []string) int { + 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)))) + for i, refspec := range refspecs { + C._go_git_set_strarray_n(&crefspecs, C.CString(refspec), C.size_t(i)) + } + defer C.git_strarray_free(&crefspecs) + + return int(C.git_remote_set_push_refspecs(o.ptr, &crefspecs)) +} + +func (o *gitRemote) ClearRefspecs() { + C.git_remote_clear_refspecs(o.ptr) +} + +func (o *gitRemote) RefspecCount() uint { + return uint(C.git_remote_refspec_count(o.ptr)) +} + diff --git a/wrapper.c b/wrapper.c index 4543822..7519a96 100644 --- a/wrapper.c +++ b/wrapper.c @@ -43,4 +43,12 @@ git_remote_callbacks _go_git_remote_callbacks_init() { return ret; } +void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n) { + array->strings[n] = str; +} + +char *_go_git_get_strarray_n(git_strarray *array, size_t n) { + return array->strings[n]; +} + /* EOF */ -- cgit v1.2.3 From d560b9e9bd7162334f7122dadd02cd0a075e22ab Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 11 Mar 2014 13:19:12 -0700 Subject: cleanup clone code --- clone.go | 9 +++---- credentials.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ push.go | 3 --- remote.go | 52 +++++++++++++++----------------------- transport.go | 79 ---------------------------------------------------------- wrapper.c | 5 ---- 6 files changed, 97 insertions(+), 125 deletions(-) create mode 100644 credentials.go delete mode 100644 transport.go (limited to 'clone.go') diff --git a/clone.go b/clone.go index 630c343..51dbd65 100644 --- a/clone.go +++ b/clone.go @@ -4,11 +4,6 @@ package git #include #include -static git_clone_options git_clone_options_init() { - git_clone_options ret = GIT_CLONE_OPTIONS_INIT; - return ret; -} - */ import "C" import ( @@ -60,7 +55,9 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) } func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) { - *ptr = C.git_clone_options_init() + ptr = &C.git_clone_options{} + C.git_clone_init_options(ptr, 1) + if opts == nil { return } 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 +#include +*/ +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/push.go b/push.go index d1742e3..8b205c7 100644 --- a/push.go +++ b/push.go @@ -59,9 +59,6 @@ func (p *Push) Finish() error { func (p *Push) UnpackOk() bool { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - ret := C.git_push_unpack_ok(p.ptr) if ret == 0 { return false diff --git a/remote.go b/remote.go index 900a314..3621b5f 100644 --- a/remote.go +++ b/remote.go @@ -5,7 +5,6 @@ package git #include extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks); -extern git_remote_callbacks _go_git_remote_callbacks_init(); extern void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n); extern char *_go_git_get_strarray_n(git_strarray *array, size_t n); @@ -15,7 +14,22 @@ import "unsafe" import "runtime" type TransferProgress struct { - ptr *C.git_transfer_progress + 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 @@ -28,7 +42,7 @@ const ( 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 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 @@ -45,7 +59,7 @@ type Remote struct { } func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { - *ptr = C._go_git_remote_callbacks_init() + C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION) if callbacks == nil { return } @@ -81,9 +95,7 @@ func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C url := C.GoString(_url) username_from_url := C.GoString(_username_from_url) ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types)) - if gcred, ok := cred.(gitCred); ok { - *_cred = gcred.ptr - } + *_cred = cred.ptr return ret } @@ -93,7 +105,7 @@ func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointe if callbacks.TransferProgressCallback == nil { return 0 } - return callbacks.TransferProgressCallback(TransferProgress{stats}) + return callbacks.TransferProgressCallback(newTransferProgressFromC(stats)) } //export updateTipsCallback @@ -108,30 +120,6 @@ func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data uns return callbacks.UpdateTipsCallback(refname, a, b) } -func (o TransferProgress) TotalObjects() uint { - return uint(o.ptr.total_objects) -} - -func (o TransferProgress) IndexedObjects() uint { - return uint(o.ptr.indexed_objects) -} - -func (o TransferProgress) ReceivedObjects() uint { - return uint(o.ptr.received_objects) -} - -func (o TransferProgress) LocalObjects() uint { - return uint(o.ptr.local_objects) -} - -func (o TransferProgress) TotalDeltas() uint { - return uint(o.ptr.total_deltas) -} - -func (o TransferProgress) ReceivedBytes() uint { - return uint(o.ptr.received_bytes) -} - func RemoteIsValidName(name string) bool { cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) diff --git a/transport.go b/transport.go deleted file mode 100644 index e97a70c..0000000 --- a/transport.go +++ /dev/null @@ -1,79 +0,0 @@ -package git - -/* -#include -#include -*/ -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 interface { - HasUsername() bool - Type() CredType -} - -type gitCred struct { - ptr *C.git_cred -} - -func (o gitCred) HasUsername() bool { - if C.git_cred_has_username(o.ptr) == 1 { - return true - } - return false -} - -func (o gitCred) Type() CredType { - return (CredType)(o.ptr.credtype); -} - -func credFromC(ptr *C.git_cred) Cred { - return gitCred{ptr} -} - -func NewCredUserpassPlaintext(username string, password string) (int, Cred) { - cred := gitCred{} - 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 := gitCred{} - 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 := gitCred{} - 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 := gitCred{} - ret := C.git_cred_default_new(&cred.ptr) - return int(ret), cred -} - diff --git a/wrapper.c b/wrapper.c index 8e337df..bc69cd5 100644 --- a/wrapper.c +++ b/wrapper.c @@ -38,11 +38,6 @@ void _go_git_setup_callbacks(git_remote_callbacks *callbacks) { callbacks->update_tips = (update_tips_cb)updateTipsCallback; } -git_remote_callbacks _go_git_remote_callbacks_init() { - git_remote_callbacks ret = GIT_REMOTE_CALLBACKS_INIT; - return ret; -} - void _go_git_set_strarray_n(git_strarray *array, char *str, size_t n) { array->strings[n] = str; } -- cgit v1.2.3 From 2f531968667f96fd573590f2609589cbdb14a480 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 11 Mar 2014 13:22:00 -0700 Subject: clean up clone code --- clone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'clone.go') diff --git a/clone.go b/clone.go index 51dbd65..c2abbe5 100644 --- a/clone.go +++ b/clone.go @@ -56,7 +56,7 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) { ptr = &C.git_clone_options{} - C.git_clone_init_options(ptr, 1) + C.git_clone_init_options(ptr, C.GIT_CLONE_OPTIONS_VERSION) if opts == nil { return -- cgit v1.2.3