diff options
Diffstat (limited to 'vendor/github.com/libgit2/git2go/clone.go')
-rw-r--r-- | vendor/github.com/libgit2/git2go/clone.go | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/vendor/github.com/libgit2/git2go/clone.go b/vendor/github.com/libgit2/git2go/clone.go new file mode 100644 index 000000000..1ff51245b --- /dev/null +++ b/vendor/github.com/libgit2/git2go/clone.go @@ -0,0 +1,109 @@ +package git + +/* +#include <git2.h> + +extern void _go_git_populate_remote_cb(git_clone_options *opts); +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +type RemoteCreateCallback func(repo *Repository, name, url string) (*Remote, ErrorCode) + +type CloneOptions struct { + *CheckoutOpts + *FetchOptions + Bare bool + CheckoutBranch string + RemoteCreateCallback RemoteCreateCallback +} + +func Clone(url string, path string, options *CloneOptions) (*Repository, error) { + curl := C.CString(url) + defer C.free(unsafe.Pointer(curl)) + + cpath := C.CString(path) + defer C.free(unsafe.Pointer(cpath)) + + copts := (*C.git_clone_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_clone_options{})))) + populateCloneOptions(copts, options) + defer freeCloneOptions(copts) + + if len(options.CheckoutBranch) != 0 { + copts.checkout_branch = C.CString(options.CheckoutBranch) + } + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + var ptr *C.git_repository + ret := C.git_clone(&ptr, curl, cpath, copts) + + if ret < 0 { + return nil, MakeGitError(ret) + } + + return newRepositoryFromC(ptr), nil +} + +//export remoteCreateCallback +func remoteCreateCallback(cremote unsafe.Pointer, crepo unsafe.Pointer, cname, curl *C.char, payload unsafe.Pointer) C.int { + name := C.GoString(cname) + url := C.GoString(curl) + repo := newRepositoryFromC((*C.git_repository)(crepo)) + // We don't own this repository, so make sure we don't try to free it + runtime.SetFinalizer(repo, nil) + + if opts, ok := pointerHandles.Get(payload).(CloneOptions); ok { + remote, err := opts.RemoteCreateCallback(repo, name, url) + // clear finalizer as the calling C function will + // free the remote itself + runtime.SetFinalizer(remote, nil) + + if err == ErrOk && remote != nil { + cptr := (**C.git_remote)(cremote) + *cptr = remote.ptr + } else if err == ErrOk && remote == nil { + panic("no remote created by callback") + } + + return C.int(err) + } else { + panic("invalid remote create callback") + } +} + +func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) { + C.git_clone_init_options(ptr, C.GIT_CLONE_OPTIONS_VERSION) + + if opts == nil { + return + } + populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts) + populateFetchOptions(&ptr.fetch_opts, opts.FetchOptions) + ptr.bare = cbool(opts.Bare) + + if opts.RemoteCreateCallback != nil { + // Go v1.1 does not allow to assign a C function pointer + C._go_git_populate_remote_cb(ptr) + ptr.remote_cb_payload = pointerHandles.Track(*opts) + } +} + +func freeCloneOptions(ptr *C.git_clone_options) { + if ptr == nil { + return + } + + freeCheckoutOpts(&ptr.checkout_opts) + + if ptr.remote_cb_payload != nil { + pointerHandles.Untrack(ptr.remote_cb_payload) + } + + C.free(unsafe.Pointer(ptr.checkout_branch)) + C.free(unsafe.Pointer(ptr)) +} |