From 313e1126dd0c974910de74f1b6bbc0fdcbbfd06b Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Thu, 2 Jan 2014 23:33:08 +0000 Subject: add git_submodule_recurse_t type --- submodule.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/submodule.go b/submodule.go index 48ea151..dadc785 100644 --- a/submodule.go +++ b/submodule.go @@ -56,6 +56,13 @@ const ( SubmoduleStatusWdUntracked = C.GIT_SUBMODULE_STATUS_WD_UNTRACKED ) +type SubmoduleRecurse int +const ( + SubmoduleRecurseNo SubmoduleRecurse = C.GIT_SUBMODULE_RECURSE_NO + SubmoduleRecurseYes = C.GIT_SUBMODULE_RECURSE_YES + SubmoduleRecurseOnDemand = C.GIT_SUBMODULE_RECURSE_ONDEMAND +) + func SubmoduleStatusIsUnmodified(status int) bool { o := SubmoduleStatus(status) & ^(SubmoduleStatusInHead | SubmoduleStatusInIndex | SubmoduleStatusInConfig | SubmoduleStatusInWd) @@ -236,11 +243,11 @@ func (sub *Submodule) FetchRecurseSubmodules() bool { return true } -func (sub *Submodule) SetFetchRecurseSubmodules(v bool) error { +func (sub *Submodule) SetFetchRecurseSubmodules(v SubmoduleRecurse) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, cbool(v)) + ret := C.git_submodule_set_fetch_recurse_submodules(sub.ptr, C.git_submodule_recurse_t(v)) if ret < 0 { return LastError() } -- cgit v1.2.3 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 +++++++++++++++++++++++++++++++++++++++++++++++++++ git.go | 2 +- remote.go | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wrapper.c | 14 +++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 clone.go create mode 100644 remote.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 + } +} + diff --git a/git.go b/git.go index 28196c8..07892e4 100644 --- a/git.go +++ b/git.go @@ -1,7 +1,7 @@ package git /* -#cgo pkg-config: libgit2 +#cgo pkg-config: --static libgit2 #include #include */ diff --git a/remote.go b/remote.go new file mode 100644 index 0000000..47866ed --- /dev/null +++ b/remote.go @@ -0,0 +1,85 @@ +package git + +/* +#include +#include + +static git_remote_callbacks git_remote_callbacks_init() { + git_remote_callbacks ret = GIT_REMOTE_CALLBACKS_INIT; + return ret; +} + +extern void _setup_callbacks(git_remote_callbacks *callbacks); + +*/ +import "C" +import ( + "unsafe" +) + +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 uint) int // FIXME +type TransferProgressCallback func() int // FIXME +type UpdateTipsCallback func(refname string, a *Oid, b *Oid) int + +//export progressCallback +func progressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + 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) + 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) + //cred := C.GoString(_cred) + url := C.GoString(_url) + username_from_url := C.GoString(_username_from_url) + return callbacks.CredentialsCallback(url, username_from_url, allowed_types) +} + +//export transferProgressCallback +func transferProgressCallback(stats C.git_transfer_progress, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + return callbacks.TransferProgressCallback() +} + +//export updateTipsCallback +func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int { + callbacks := (*RemoteCallbacks)(data) + refname := C.GoString(_refname) + a := newOidFromC(_a) + b := newOidFromC(_b) + return callbacks.UpdateTipsCallback(refname, a, b) +} + +type RemoteCallbacks struct { + ProgressCallback + CompletionCallback + CredentialsCallback + TransferProgressCallback + UpdateTipsCallback +} + +func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { + *ptr = C.git_remote_callbacks_init() + if callbacks == nil { + return + } + C._setup_callbacks(ptr) + ptr.payload = unsafe.Pointer(callbacks) +} diff --git a/wrapper.c b/wrapper.c index 2af3974..ef05c2d 100644 --- a/wrapper.c +++ b/wrapper.c @@ -24,4 +24,18 @@ int _go_git_odb_foreach(git_odb *db, void *payload) { return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload); } + +void _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; +} + /* EOF */ -- cgit v1.2.3 From 5d8a14d108ac963a4865cd03e20e56b28ee9626e Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Sun, 5 Jan 2014 20:55:32 +0000 Subject: wrappers for git_cred, git_transfer_progress. don't call nil callbacks. --- remote.go | 90 ++++++++++++++++++++++++++++++++++++++++++++---------------- transport.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 transport.go diff --git a/remote.go b/remote.go index 47866ed..ebf1fd4 100644 --- a/remote.go +++ b/remote.go @@ -13,9 +13,11 @@ extern void _setup_callbacks(git_remote_callbacks *callbacks); */ import "C" -import ( - "unsafe" -) +import "unsafe" + +type TransferProgress struct { + ptr *C.git_transfer_progress +} type RemoteCompletion uint const ( @@ -26,60 +28,102 @@ const ( type ProgressCallback func(str string) int type CompletionCallback func(RemoteCompletion) int -type CredentialsCallback func(url string, username_from_url string, allowed_types uint) int // FIXME -type TransferProgressCallback func() int // FIXME +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 +} + +func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { + *ptr = C.git_remote_callbacks_init() + if callbacks == nil { + return + } + C._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) - str := C.GoStringN(_str, _len) + 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) - //cred := C.GoString(_cred) + if callbacks.CredentialsCallback == nil { + return 0 + } url := C.GoString(_url) username_from_url := C.GoString(_username_from_url) - return callbacks.CredentialsCallback(url, username_from_url, allowed_types) + ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types)) + if gcred, ok := cred.(gitCred); ok { + *_cred = gcred.ptr + } + return ret } //export transferProgressCallback -func transferProgressCallback(stats C.git_transfer_progress, data unsafe.Pointer) int { +func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointer) int { callbacks := (*RemoteCallbacks)(data) - return callbacks.TransferProgressCallback() + if callbacks.TransferProgressCallback == nil { + return 0 + } + return callbacks.TransferProgressCallback(TransferProgress{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) } -type RemoteCallbacks struct { - ProgressCallback - CompletionCallback - CredentialsCallback - TransferProgressCallback - UpdateTipsCallback +func (o TransferProgress) TotalObjects() uint { + return uint(o.ptr.total_objects) } -func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { - *ptr = C.git_remote_callbacks_init() - if callbacks == nil { - return - } - C._setup_callbacks(ptr) - ptr.payload = unsafe.Pointer(callbacks) +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) } diff --git a/transport.go b/transport.go new file mode 100644 index 0000000..e97a70c --- /dev/null +++ b/transport.go @@ -0,0 +1,79 @@ +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 +} + -- cgit v1.2.3 From d1245446685ccdc632b6a9cee65391cbe4eac4df Mon Sep 17 00:00:00 2001 From: Jason Toffaletti Date: Mon, 6 Jan 2014 16:55:29 +0000 Subject: minor --- remote.go | 12 ++++-------- wrapper.c | 7 ++++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/remote.go b/remote.go index ebf1fd4..0645291 100644 --- a/remote.go +++ b/remote.go @@ -4,12 +4,8 @@ package git #include #include -static git_remote_callbacks git_remote_callbacks_init() { - git_remote_callbacks ret = GIT_REMOTE_CALLBACKS_INIT; - return ret; -} - -extern void _setup_callbacks(git_remote_callbacks *callbacks); +extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks); +extern git_remote_callbacks _go_git_remote_callbacks_init(); */ import "C" @@ -41,11 +37,11 @@ type RemoteCallbacks struct { } func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) { - *ptr = C.git_remote_callbacks_init() + *ptr = C._go_git_remote_callbacks_init() if callbacks == nil { return } - C._setup_callbacks(ptr) + C._go_git_setup_callbacks(ptr) ptr.payload = unsafe.Pointer(callbacks) } diff --git a/wrapper.c b/wrapper.c index ef05c2d..4543822 100644 --- a/wrapper.c +++ b/wrapper.c @@ -25,7 +25,7 @@ int _go_git_odb_foreach(git_odb *db, void *payload) return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload); } -void _setup_callbacks(git_remote_callbacks *callbacks) { +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); @@ -38,4 +38,9 @@ void _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; +} + /* EOF */ -- 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(+) 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 374e2112dfc298fa5ecb0805624d75b3500cc345 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 27 Feb 2014 16:36:44 -0800 Subject: add push, refine remotes --- git_test.go | 15 ++++- push.go | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ push_test.go | 56 ++++++++++++++++++ remote.go | 99 ++++++++++++++++---------------- wrapper.c | 12 ++++ 5 files changed, 310 insertions(+), 53 deletions(-) create mode 100644 push.go create mode 100644 push_test.go 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 +#include + +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: "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() +} 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 */ -- cgit v1.2.3 From 9fb7a746e0103ceff2fd8eb9845e782711a87535 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 28 Feb 2014 10:58:53 -0800 Subject: fix handling of msg to treat empty str as nil --- push.go | 9 +++++++-- remote.go | 10 +++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/push.go b/push.go index 0694fe3..d1742e3 100644 --- a/push.go +++ b/push.go @@ -79,8 +79,13 @@ func (p *Push) UpdateTips(sig *Signature, msg string) error { defer C.free(unsafe.Pointer(csig)) } - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) + var cmsg *C.char + if msg == "" { + cmsg = nil + } else { + cmsg = C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + } runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/remote.go b/remote.go index ab2e174..900a314 100644 --- a/remote.go +++ b/remote.go @@ -398,9 +398,13 @@ func (o *Remote) Fetch(sig *Signature, msg string) error { defer C.free(unsafe.Pointer(csig)) } - cmsg := C.CString(msg) - defer C.free(unsafe.Pointer(cmsg)) - + 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) -- 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 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(-) 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 From 0a172478dcba23f73f7f1991c6b39c62ee23f172 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 11 Mar 2014 13:45:27 -0700 Subject: fix return for old go versions / travis --- push.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/push.go b/push.go index 8b205c7..5fb7f07 100644 --- a/push.go +++ b/push.go @@ -62,9 +62,8 @@ func (p *Push) UnpackOk() bool { ret := C.git_push_unpack_ok(p.ptr) if ret == 0 { return false - } else { - return true } + return true } -- cgit v1.2.3 From 51aa76d6f7170bba60ab2252b74a3cab0276996f Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 11 Mar 2014 16:25:22 -0700 Subject: remove strarray wrappers --- remote.go | 48 +++++++++++++++++++++++++++++------------------- wrapper.c | 8 -------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/remote.go b/remote.go index 3621b5f..da688e7 100644 --- a/remote.go +++ b/remote.go @@ -5,8 +5,6 @@ package git #include extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks); -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" @@ -280,6 +278,31 @@ func (o *Remote) AddFetch(refspec string) error { 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{} @@ -291,21 +314,15 @@ func (o *Remote) GetFetchRefspecs() ([]string, error) { return nil, MakeGitError(ret) } 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))) - } + 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 = (**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)) - } + crefspecs.strings = makeCStringsFromStrings(refspecs) defer C.git_strarray_free(&crefspecs) runtime.LockOSThread() @@ -343,21 +360,14 @@ func (o *Remote) GetPushRefspecs() ([]string, error) { return nil, MakeGitError(ret) } 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))) - } + 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 = (**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)) - } + crefspecs.strings = makeCStringsFromStrings(refspecs) defer C.git_strarray_free(&crefspecs) runtime.LockOSThread() diff --git a/wrapper.c b/wrapper.c index bc69cd5..0fa6c48 100644 --- a/wrapper.c +++ b/wrapper.c @@ -38,14 +38,6 @@ void _go_git_setup_callbacks(git_remote_callbacks *callbacks) { callbacks->update_tips = (update_tips_cb)updateTipsCallback; } -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]; -} - typedef int (*status_foreach_cb)(const char *ref, const char *msg, void *data); int _go_git_push_status_foreach(git_push *push, void *data) -- cgit v1.2.3 From 663c2a69c9ad2f88a6c2a06d7fea82a60392f2fe Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Sun, 16 Mar 2014 22:09:12 -0700 Subject: fix chunk create logic --- blob.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blob.go b/blob.go index ced2cb1..4cee876 100644 --- a/blob.go +++ b/blob.go @@ -55,13 +55,13 @@ func blobChunkCb(buffer *C.char, maxLen C.size_t, payload unsafe.Pointer) int { data := (*BlobCallbackData)(payload) goBuf, err := data.Callback(int(maxLen)) if err == io.EOF { - return 1 + return 0 } else if err != nil { data.Error = err return -1 } - C.memcpy(unsafe.Pointer(buffer), unsafe.Pointer(&goBuf), C.size_t(len(goBuf))) - return 0 + C.memcpy(unsafe.Pointer(buffer), unsafe.Pointer(&goBuf[0]), C.size_t(len(goBuf))) + return len(goBuf) } func (repo *Repository) CreateBlobFromChunks(hintPath string, callback BlobChunkCallback) (*Oid, error) { -- cgit v1.2.3 From d1e7ee53d53d050d5d5be475f98f51e28a88840c Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 18 Mar 2014 18:23:33 -0700 Subject: fix clone options init --- clone.go | 1 - 1 file changed, 1 deletion(-) diff --git a/clone.go b/clone.go index c2abbe5..1bc3261 100644 --- a/clone.go +++ b/clone.go @@ -55,7 +55,6 @@ 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, C.GIT_CLONE_OPTIONS_VERSION) if opts == nil { -- cgit v1.2.3 From 3d7f737481e02fd8fb787916ade475b3dd6dc78d Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 18 Mar 2014 18:24:31 -0700 Subject: add simple clone test --- clone_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 clone_test.go diff --git a/clone_test.go b/clone_test.go new file mode 100644 index 0000000..27e824b --- /dev/null +++ b/clone_test.go @@ -0,0 +1,19 @@ +package git + +import ( + "io/ioutil" + "testing" +) + +func Test_Clone(t *testing.T) { + + repo := createTestRepo(t) + seedTestRepo(t, repo) + + path, err := ioutil.TempDir("", "git2go") + checkFatal(t, err) + + _, err = Clone(repo.Path(), path, &CloneOptions{Bare: true}) + + checkFatal(t, err) +} -- cgit v1.2.3 From f1f0fa7335f6ec3285eae32f84d143edffd73ef5 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Tue, 18 Mar 2014 19:38:02 -0700 Subject: fix naming on test --- clone_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clone_test.go b/clone_test.go index 27e824b..6145228 100644 --- a/clone_test.go +++ b/clone_test.go @@ -5,7 +5,7 @@ import ( "testing" ) -func Test_Clone(t *testing.T) { +func TestClone(t *testing.T) { repo := createTestRepo(t) seedTestRepo(t, repo) -- cgit v1.2.3 From b6703d47671b3a736e8b93ff0447da45e688865c Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Tue, 18 Mar 2014 04:54:40 +0100 Subject: Oid: make the type directly [20]byte There is no need for a struct with a single field. An Oid is 20 bytes which hold the binary representation of the hash, so let's use that directly. Go lets us have methods on this new type just the same. --- git.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/git.go b/git.go index db9522b..8f543b5 100644 --- a/git.go +++ b/git.go @@ -29,9 +29,7 @@ func init() { } // Oid -type Oid struct { - bytes [20]byte -} +type Oid [20]byte func newOidFromC(coid *C.git_oid) *Oid { if coid == nil { @@ -39,18 +37,18 @@ func newOidFromC(coid *C.git_oid) *Oid { } oid := new(Oid) - copy(oid.bytes[0:20], C.GoBytes(unsafe.Pointer(coid), 20)) + copy(oid[0:20], C.GoBytes(unsafe.Pointer(coid), 20)) return oid } func NewOid(b []byte) *Oid { oid := new(Oid) - copy(oid.bytes[0:20], b[0:20]) + copy(oid[0:20], b[0:20]) return oid } func (oid *Oid) toC() *C.git_oid { - return (*C.git_oid)(unsafe.Pointer(&oid.bytes)) + return (*C.git_oid)(unsafe.Pointer(oid)) } func NewOidFromString(s string) (*Oid, error) { @@ -75,25 +73,25 @@ func (oid *Oid) String() string { } func (oid *Oid) Bytes() []byte { - return oid.bytes[0:] + return oid[0:] } func (oid *Oid) Cmp(oid2 *Oid) int { - return bytes.Compare(oid.bytes[:], oid2.bytes[:]) + return bytes.Compare(oid[:], oid2[:]) } func (oid *Oid) Copy() *Oid { ret := new(Oid) - copy(ret.bytes[:], oid.bytes[:]) + copy(ret[:], oid[:]) return ret } func (oid *Oid) Equal(oid2 *Oid) bool { - return bytes.Equal(oid.bytes[:], oid2.bytes[:]) + return bytes.Equal(oid[:], oid2[:]) } func (oid *Oid) IsZero() bool { - for _, a := range oid.bytes { + for _, a := range oid { if a != '0' { return false } @@ -102,7 +100,7 @@ func (oid *Oid) IsZero() bool { } func (oid *Oid) NCmp(oid2 *Oid, n uint) int { - return bytes.Compare(oid.bytes[:n], oid2.bytes[:n]) + return bytes.Compare(oid[:n], oid2[:n]) } func ShortenOids(ids []*Oid, minlen int) (int, error) { -- cgit v1.2.3 From c9c7c1e77942f88955af0dc3bdfb58d5e7d7f121 Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Tue, 18 Mar 2014 05:04:26 +0100 Subject: Oid: make NewOid take a string This is the most common way of having an id that's not in Oid form, so let's make it the "default" and rename to NewOidFromBytes() the one that takes []byte. --- git.go | 4 ++-- odb_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/git.go b/git.go index 8f543b5..f3fb7e1 100644 --- a/git.go +++ b/git.go @@ -41,7 +41,7 @@ func newOidFromC(coid *C.git_oid) *Oid { return oid } -func NewOid(b []byte) *Oid { +func NewOidFromBytes(b []byte) *Oid { oid := new(Oid) copy(oid[0:20], b[0:20]) return oid @@ -51,7 +51,7 @@ func (oid *Oid) toC() *C.git_oid { return (*C.git_oid)(unsafe.Pointer(oid)) } -func NewOidFromString(s string) (*Oid, error) { +func NewOid(s string) (*Oid, error) { o := new(Oid) cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) diff --git a/odb_test.go b/odb_test.go index a4f8943..17b3ad2 100644 --- a/odb_test.go +++ b/odb_test.go @@ -27,7 +27,7 @@ func TestOdbStream(t *testing.T) { error = stream.Close() checkFatal(t, error) - expectedId, error := NewOidFromString("30f51a3fba5274d53522d0f19748456974647b4f") + expectedId, error := NewOid("30f51a3fba5274d53522d0f19748456974647b4f") checkFatal(t, error) if stream.Id.Cmp(expectedId) != 0 { t.Fatal("Wrong data written") @@ -59,4 +59,4 @@ Initial commit.`; if oid.Cmp(coid) != 0 { t.Fatal("Hash and write Oids are different") } -} \ No newline at end of file +} -- cgit v1.2.3 From c243c31f7d428680579a1dd20273cd3888c730e4 Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Wed, 19 Mar 2014 03:11:41 +0100 Subject: Oid: remove Bytes() This is not needed. We can do id[:] to get a slice. --- git.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/git.go b/git.go index f3fb7e1..9e1d3e7 100644 --- a/git.go +++ b/git.go @@ -28,7 +28,7 @@ func init() { C.git_threads_init() } -// Oid +// Oid represents the id for a Git object. type Oid [20]byte func newOidFromC(coid *C.git_oid) *Oid { @@ -72,10 +72,6 @@ func (oid *Oid) String() string { return string(buf) } -func (oid *Oid) Bytes() []byte { - return oid[0:] -} - func (oid *Oid) Cmp(oid2 *Oid) int { return bytes.Compare(oid[:], oid2[:]) } -- cgit v1.2.3 From 0bb73e43a8f26be8608cdd304d73cacb05753417 Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Wed, 19 Mar 2014 03:39:34 +0100 Subject: Oid: use Go's conversion functions Go already has all the necessary pieces for encoding and decoding hex strings. Using them let's us avoid going into C land. Benchmarks show this takes about half the time as using libgit2's functions. --- git.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/git.go b/git.go index 9e1d3e7..e5fe812 100644 --- a/git.go +++ b/git.go @@ -8,6 +8,7 @@ package git import "C" import ( "bytes" + "encoding/hex" "errors" "runtime" "strings" @@ -52,24 +53,23 @@ func (oid *Oid) toC() *C.git_oid { } func NewOid(s string) (*Oid, error) { - o := new(Oid) - cs := C.CString(s) - defer C.free(unsafe.Pointer(cs)) + if len(s) > C.GIT_OID_HEXSZ { + return nil, errors.New("string is too long for oid") + } - runtime.LockOSThread() - defer runtime.UnlockOSThread() + o := new(Oid) - if ret := C.git_oid_fromstr(o.toC(), cs); ret < 0 { - return nil, MakeGitError(ret) + slice, error := hex.DecodeString(s) + if error != nil { + return nil, error } + copy(o[:], slice[:20]) return o, nil } func (oid *Oid) String() string { - buf := make([]byte, 40) - C.git_oid_fmt((*C.char)(unsafe.Pointer(&buf[0])), oid.toC()) - return string(buf) + return hex.EncodeToString(oid[:]) } func (oid *Oid) Cmp(oid2 *Oid) int { -- cgit v1.2.3 From b82a72a9ce4701a4560288c4ebf1511ffb415b80 Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Wed, 19 Mar 2014 03:51:59 +0100 Subject: Oid: fix IsZero() We need to compare against the number zero, not its ASCII value. --- git.go | 2 +- git_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/git.go b/git.go index e5fe812..b20f993 100644 --- a/git.go +++ b/git.go @@ -88,7 +88,7 @@ func (oid *Oid) Equal(oid2 *Oid) bool { func (oid *Oid) IsZero() bool { for _, a := range oid { - if a != '0' { + if a != 0 { return false } } diff --git a/git_test.go b/git_test.go index fff3c6c..6542ca0 100644 --- a/git_test.go +++ b/git_test.go @@ -54,3 +54,11 @@ func seedTestRepo(t *testing.T, repo *Repository) (*Oid, *Oid) { return commitId, treeId } + +func TestOidZero(t *testing.T) { + var zeroId Oid + + if !zeroId.IsZero() { + t.Error("Zero Oid is not zero") + } +} -- cgit v1.2.3 From ad128bdefb58927762798a5b708a63bff43b627e Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Wed, 19 Mar 2014 07:54:52 +0100 Subject: Remote: don't mix allocators We cannot ask libgit2 to free the memory we have allocated ourselves, as it cannot know how to do it. Let's free the strarray ourselves. --- remote.go | 17 +++++++++++++++-- remote_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 remote_test.go diff --git a/remote.go b/remote.go index da688e7..3e01ce1 100644 --- a/remote.go +++ b/remote.go @@ -303,6 +303,19 @@ func makeCStringsFromStrings(s []string) **C.char { return x } +func freeStrarray(arr *C.git_strarray) { + count := int(arr.count) + size := unsafe.Sizeof(unsafe.Pointer(nil)) + + i := 0 + for p := uintptr(unsafe.Pointer(arr.strings)); i < count; p += size { + C.free(unsafe.Pointer(sptr(p))) + i++ + } + + C.free(unsafe.Pointer(arr.strings)) +} + func (o *Remote) GetFetchRefspecs() ([]string, error) { crefspecs := C.git_strarray{} @@ -323,7 +336,7 @@ 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) + defer freeStrarray(&crefspecs) runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -368,7 +381,7 @@ 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) + defer freeStrarray(&crefspecs) runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/remote_test.go b/remote_test.go new file mode 100644 index 0000000..16675fc --- /dev/null +++ b/remote_test.go @@ -0,0 +1,27 @@ +package git + +import ( + "os" + "testing" +) + +func TestRefspecs(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + remote, err := repo.CreateRemoteInMemory("refs/heads/*:refs/heads/*", "git://foo/bar") + checkFatal(t, err) + + expected := []string{ + "refs/heads/*:refs/remotes/origin/*", + "refs/pull/*/head:refs/remotes/origin/*", + } + + err = remote.SetFetchRefspecs(expected) + checkFatal(t, err) + + actual, err := remote.GetFetchRefspecs() + checkFatal(t, err) + + compareStringList(t, expected, actual) +} -- cgit v1.2.3 From 3ae9813fca2837601e5a7c801972396a59e1eb59 Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Wed, 19 Mar 2014 08:03:21 +0100 Subject: Clean up after the tests --- clone_test.go | 4 ++++ push_test.go | 3 +++ 2 files changed, 7 insertions(+) diff --git a/clone_test.go b/clone_test.go index 6145228..97366bf 100644 --- a/clone_test.go +++ b/clone_test.go @@ -2,18 +2,22 @@ package git import ( "io/ioutil" + "os" "testing" ) func TestClone(t *testing.T) { repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + seedTestRepo(t, repo) path, err := ioutil.TempDir("", "git2go") checkFatal(t, err) _, err = Clone(repo.Path(), path, &CloneOptions{Bare: true}) + defer os.RemoveAll(path) checkFatal(t, err) } diff --git a/push_test.go b/push_test.go index dfd4af7..c1e6a22 100644 --- a/push_test.go +++ b/push_test.go @@ -2,13 +2,16 @@ package git import ( "log" + "os" "testing" "time" ) func Test_Push_ToRemote(t *testing.T) { repo := createBareTestRepo(t) + defer os.RemoveAll(repo.Path()) repo2 := createTestRepo(t) + defer os.RemoveAll(repo2.Workdir()) remote, err := repo2.CreateRemote("test_push", repo.Path()) checkFatal(t, err) -- cgit v1.2.3 From 574f0dd12da2eae6f26ae35f197b2ec7a9328249 Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Thu, 20 Mar 2014 03:29:54 +0100 Subject: Remote: remove Get prefix from refspecs Idiomatic Go is to omit the Get from the getter methods. --- remote.go | 4 ++-- remote_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/remote.go b/remote.go index 3e01ce1..d556f99 100644 --- a/remote.go +++ b/remote.go @@ -316,7 +316,7 @@ func freeStrarray(arr *C.git_strarray) { C.free(unsafe.Pointer(arr.strings)) } -func (o *Remote) GetFetchRefspecs() ([]string, error) { +func (o *Remote) FetchRefspecs() ([]string, error) { crefspecs := C.git_strarray{} runtime.LockOSThread() @@ -362,7 +362,7 @@ func (o *Remote) AddPush(refspec string) error { return nil } -func (o *Remote) GetPushRefspecs() ([]string, error) { +func (o *Remote) PushRefspecs() ([]string, error) { crefspecs := C.git_strarray{} runtime.LockOSThread() diff --git a/remote_test.go b/remote_test.go index 16675fc..04b3a57 100644 --- a/remote_test.go +++ b/remote_test.go @@ -20,7 +20,7 @@ func TestRefspecs(t *testing.T) { err = remote.SetFetchRefspecs(expected) checkFatal(t, err) - actual, err := remote.GetFetchRefspecs() + actual, err := remote.FetchRefspecs() checkFatal(t, err) compareStringList(t, expected, actual) -- cgit v1.2.3 From 99d7f66477aa09915821659087da8b91e593f4eb Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 20 Mar 2014 02:06:56 -0700 Subject: add remote list --- remote.go | 12 ++++++++++++ remote_test.go | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/remote.go b/remote.go index d556f99..d675ab8 100644 --- a/remote.go +++ b/remote.go @@ -132,6 +132,18 @@ func (r *Remote) Free() { C.git_remote_free(r.ptr) } +func (repo *Repository) ListRemotes() ([]string, error) { + var r C.git_strarray + ecode := C.git_remote_list(&r, repo.ptr) + if ecode < 0 { + return make([]string, 0), MakeGitError(ecode) + } + defer C.git_strarray_free(&r) + + remotes := makeStringsFromCStrings(r.strings, int(r.count)) + return remotes, nil +} + func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) { remote := &Remote{} diff --git a/remote_test.go b/remote_test.go index 04b3a57..90e24ae 100644 --- a/remote_test.go +++ b/remote_test.go @@ -8,6 +8,7 @@ import ( func TestRefspecs(t *testing.T) { repo := createTestRepo(t) defer os.RemoveAll(repo.Workdir()) + defer repo.Free() remote, err := repo.CreateRemoteInMemory("refs/heads/*:refs/heads/*", "git://foo/bar") checkFatal(t, err) @@ -25,3 +26,22 @@ func TestRefspecs(t *testing.T) { compareStringList(t, expected, actual) } + +func TestListRemotes(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + defer repo.Free() + + _, err := repo.CreateRemote("test", "git://foo/bar") + + checkFatal(t, err) + + expected := []string{ + "test", + } + + actual, err := repo.ListRemotes() + checkFatal(t, err) + + compareStringList(t, expected, actual) +} -- cgit v1.2.3 From 5d8db7f9362a314cf56747cf23605aec8640e92e Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 20 Mar 2014 20:24:29 -0700 Subject: return nil instead of empty array on error --- remote.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote.go b/remote.go index d675ab8..66097b8 100644 --- a/remote.go +++ b/remote.go @@ -136,7 +136,7 @@ func (repo *Repository) ListRemotes() ([]string, error) { var r C.git_strarray ecode := C.git_remote_list(&r, repo.ptr) if ecode < 0 { - return make([]string, 0), MakeGitError(ecode) + return nil, MakeGitError(ecode) } defer C.git_strarray_free(&r) -- cgit v1.2.3 From 1f3f8adda8d6df5053faa63487e70cb3f29f2673 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 20 Mar 2014 20:49:05 -0700 Subject: Add index WriteTreeTo + test --- index.go | 18 ++++++++++++++++-- index_test.go | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/index.go b/index.go index 6da3c98..7336249 100644 --- a/index.go +++ b/index.go @@ -23,7 +23,7 @@ type IndexEntry struct { Uid uint Gid uint Size uint - Id *Oid + Id *Oid Path string } @@ -48,6 +48,20 @@ func (v *Index) AddByPath(path string) error { return nil } +func (v *Index) WriteTreeTo(repo *Repository) (*Oid, error) { + oid := new(Oid) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_index_write_tree_to(oid.toC(), v.ptr, repo.ptr) + if ret < 0 { + return nil, MakeGitError(ret) + } + + return oid, nil +} + func (v *Index) WriteTree() (*Oid, error) { oid := new(Oid) @@ -62,7 +76,7 @@ func (v *Index) WriteTree() (*Oid, error) { return oid, nil } -func (v *Index) Write() (error) { +func (v *Index) Write() error { runtime.LockOSThread() defer runtime.UnlockOSThread() diff --git a/index_test.go b/index_test.go index 9828d0f..5920b93 100644 --- a/index_test.go +++ b/index_test.go @@ -22,6 +22,25 @@ func TestCreateRepoAndStage(t *testing.T) { } } +func TestIndexWriteTreeTo(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + repo2 := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + idx, err := repo.Index() + checkFatal(t, err) + err = idx.AddByPath("README") + checkFatal(t, err) + treeId, err := idx.WriteTreeTo(repo2) + checkFatal(t, err) + + if treeId.String() != "b7119b11e8ef7a1a5a34d3ac87f5b075228ac81e" { + t.Fatalf("%v", treeId.String()) + } +} + func checkFatal(t *testing.T, err error) { if err == nil { return -- cgit v1.2.3