Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/libgit2/git2go/remote.go')
-rw-r--r--vendor/github.com/libgit2/git2go/remote.go872
1 files changed, 872 insertions, 0 deletions
diff --git a/vendor/github.com/libgit2/git2go/remote.go b/vendor/github.com/libgit2/git2go/remote.go
new file mode 100644
index 000000000..b4b1dd727
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/remote.go
@@ -0,0 +1,872 @@
+package git
+
+/*
+#include <git2.h>
+#include <string.h>
+
+extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks);
+
+*/
+import "C"
+import (
+ "crypto/x509"
+ "reflect"
+ "runtime"
+ "strings"
+ "unsafe"
+)
+
+type TransferProgress struct {
+ 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
+type ConnectDirection uint
+
+const (
+ RemoteCompletionDownload RemoteCompletion = C.GIT_REMOTE_COMPLETION_DOWNLOAD
+ RemoteCompletionIndexing RemoteCompletion = C.GIT_REMOTE_COMPLETION_INDEXING
+ RemoteCompletionError RemoteCompletion = C.GIT_REMOTE_COMPLETION_ERROR
+
+ ConnectDirectionFetch ConnectDirection = C.GIT_DIRECTION_FETCH
+ ConnectDirectionPush ConnectDirection = C.GIT_DIRECTION_PUSH
+)
+
+type TransportMessageCallback func(str string) ErrorCode
+type CompletionCallback func(RemoteCompletion) ErrorCode
+type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (ErrorCode, *Cred)
+type TransferProgressCallback func(stats TransferProgress) ErrorCode
+type UpdateTipsCallback func(refname string, a *Oid, b *Oid) ErrorCode
+type CertificateCheckCallback func(cert *Certificate, valid bool, hostname string) ErrorCode
+type PackbuilderProgressCallback func(stage int32, current, total uint32) ErrorCode
+type PushTransferProgressCallback func(current, total uint32, bytes uint) ErrorCode
+type PushUpdateReferenceCallback func(refname, status string) ErrorCode
+
+type RemoteCallbacks struct {
+ SidebandProgressCallback TransportMessageCallback
+ CompletionCallback
+ CredentialsCallback
+ TransferProgressCallback
+ UpdateTipsCallback
+ CertificateCheckCallback
+ PackProgressCallback PackbuilderProgressCallback
+ PushTransferProgressCallback
+ PushUpdateReferenceCallback
+}
+
+type FetchPrune uint
+
+const (
+ // Use the setting from the configuration
+ FetchPruneUnspecified FetchPrune = C.GIT_FETCH_PRUNE_UNSPECIFIED
+ // Force pruning on
+ FetchPruneOn FetchPrune = C.GIT_FETCH_PRUNE
+ // Force pruning off
+ FetchNoPrune FetchPrune = C.GIT_FETCH_NO_PRUNE
+)
+
+type DownloadTags uint
+
+const (
+
+ // Use the setting from the configuration.
+ DownloadTagsUnspecified DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED
+ // Ask the server for tags pointing to objects we're already
+ // downloading.
+ DownloadTagsAuto DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_AUTO
+
+ // Don't ask for any tags beyond the refspecs.
+ DownloadTagsNone DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_NONE
+
+ // Ask for the all the tags.
+ DownloadTagsAll DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_ALL
+)
+
+type FetchOptions struct {
+ // Callbacks to use for this fetch operation
+ RemoteCallbacks RemoteCallbacks
+ // Whether to perform a prune after the fetch
+ Prune FetchPrune
+ // Whether to write the results to FETCH_HEAD. Defaults to
+ // on. Leave this default in order to behave like git.
+ UpdateFetchhead bool
+
+ // Determines how to behave regarding tags on the remote, such
+ // as auto-downloading tags for objects we're downloading or
+ // downloading all of them.
+ //
+ // The default is to auto-follow tags.
+ DownloadTags DownloadTags
+
+ // Headers are extra headers for the fetch operation.
+ Headers []string
+}
+
+type ProxyType uint
+
+const (
+ // Do not attempt to connect through a proxy
+ //
+ // If built against lbicurl, it itself may attempt to connect
+ // to a proxy if the environment variables specify it.
+ ProxyTypeNone ProxyType = C.GIT_PROXY_NONE
+
+ // Try to auto-detect the proxy from the git configuration.
+ ProxyTypeAuto ProxyType = C.GIT_PROXY_AUTO
+
+ // Connect via the URL given in the options
+ ProxyTypeSpecified ProxyType = C.GIT_PROXY_SPECIFIED
+)
+
+type ProxyOptions struct {
+ // The type of proxy to use (or none)
+ Type ProxyType
+
+ // The proxy's URL
+ Url string
+}
+
+type Remote struct {
+ ptr *C.git_remote
+ callbacks RemoteCallbacks
+ repo *Repository
+}
+
+type CertificateKind uint
+
+const (
+ CertificateX509 CertificateKind = C.GIT_CERT_X509
+ CertificateHostkey CertificateKind = C.GIT_CERT_HOSTKEY_LIBSSH2
+)
+
+// Certificate represents the two possible certificates which libgit2
+// knows it might find. If Kind is CertficateX509 then the X509 field
+// will be filled. If Kind is CertificateHostkey then the Hostkey
+// field will be fille.d
+type Certificate struct {
+ Kind CertificateKind
+ X509 *x509.Certificate
+ Hostkey HostkeyCertificate
+}
+
+type HostkeyKind uint
+
+const (
+ HostkeyMD5 HostkeyKind = C.GIT_CERT_SSH_MD5
+ HostkeySHA1 HostkeyKind = C.GIT_CERT_SSH_SHA1
+)
+
+// Server host key information. If Kind is HostkeyMD5 the MD5 field
+// will be filled. If Kind is HostkeySHA1, then HashSHA1 will be
+// filled.
+type HostkeyCertificate struct {
+ Kind HostkeyKind
+ HashMD5 [16]byte
+ HashSHA1 [20]byte
+}
+
+type PushOptions struct {
+ // Callbacks to use for this push operation
+ RemoteCallbacks RemoteCallbacks
+
+ PbParallelism uint
+
+ // Headers are extra headers for the push operation.
+ Headers []string
+}
+
+type RemoteHead struct {
+ Id *Oid
+ Name string
+}
+
+func newRemoteHeadFromC(ptr *C.git_remote_head) RemoteHead {
+ return RemoteHead{
+ Id: newOidFromC(&ptr.oid),
+ Name: C.GoString(ptr.name),
+ }
+}
+
+func untrackCalbacksPayload(callbacks *C.git_remote_callbacks) {
+ if callbacks != nil && callbacks.payload != nil {
+ pointerHandles.Untrack(callbacks.payload)
+ }
+}
+
+func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) {
+ C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
+ if callbacks == nil {
+ return
+ }
+ C._go_git_setup_callbacks(ptr)
+ ptr.payload = pointerHandles.Track(callbacks)
+}
+
+//export sidebandProgressCallback
+func sidebandProgressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int {
+ callbacks := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.SidebandProgressCallback == nil {
+ return 0
+ }
+ str := C.GoStringN(_str, _len)
+ return int(callbacks.SidebandProgressCallback(str))
+}
+
+//export completionCallback
+func completionCallback(completion_type C.git_remote_completion_type, data unsafe.Pointer) int {
+ callbacks := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.CompletionCallback == nil {
+ return 0
+ }
+ return int(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, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.CredentialsCallback == nil {
+ return C.GIT_PASSTHROUGH
+ }
+ url := C.GoString(_url)
+ username_from_url := C.GoString(_username_from_url)
+ ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
+ if cred != nil {
+ *_cred = cred.ptr
+ }
+ return int(ret)
+}
+
+//export transferProgressCallback
+func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.TransferProgressCallback == nil {
+ return 0
+ }
+ return int(callbacks.TransferProgressCallback(newTransferProgressFromC(stats)))
+}
+
+//export updateTipsCallback
+func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.UpdateTipsCallback == nil {
+ return 0
+ }
+ refname := C.GoString(_refname)
+ a := newOidFromC(_a)
+ b := newOidFromC(_b)
+ return int(callbacks.UpdateTipsCallback(refname, a, b))
+}
+
+//export certificateCheckCallback
+func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ // if there's no callback set, we need to make sure we fail if the library didn't consider this cert valid
+ if callbacks.CertificateCheckCallback == nil {
+ if _valid == 1 {
+ return 0
+ } else {
+ return C.GIT_ECERTIFICATE
+ }
+ }
+ host := C.GoString(_host)
+ valid := _valid != 0
+
+ var cert Certificate
+ if _cert.cert_type == C.GIT_CERT_X509 {
+ cert.Kind = CertificateX509
+ ccert := (*C.git_cert_x509)(unsafe.Pointer(_cert))
+ x509_certs, err := x509.ParseCertificates(C.GoBytes(ccert.data, C.int(ccert.len)))
+ if err != nil {
+ return C.GIT_EUSER
+ }
+
+ // we assume there's only one, which should hold true for any web server we want to talk to
+ cert.X509 = x509_certs[0]
+ } else if _cert.cert_type == C.GIT_CERT_HOSTKEY_LIBSSH2 {
+ cert.Kind = CertificateHostkey
+ ccert := (*C.git_cert_hostkey)(unsafe.Pointer(_cert))
+ cert.Hostkey.Kind = HostkeyKind(ccert._type)
+ C.memcpy(unsafe.Pointer(&cert.Hostkey.HashMD5[0]), unsafe.Pointer(&ccert.hash_md5[0]), C.size_t(len(cert.Hostkey.HashMD5)))
+ C.memcpy(unsafe.Pointer(&cert.Hostkey.HashSHA1[0]), unsafe.Pointer(&ccert.hash_sha1[0]), C.size_t(len(cert.Hostkey.HashSHA1)))
+ } else {
+ cstr := C.CString("Unsupported certificate type")
+ C.giterr_set_str(C.GITERR_NET, cstr)
+ C.free(unsafe.Pointer(cstr))
+ return -1 // we don't support anything else atm
+ }
+
+ return int(callbacks.CertificateCheckCallback(&cert, valid, host))
+}
+
+//export packProgressCallback
+func packProgressCallback(stage C.int, current, total C.uint, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+
+ if callbacks.PackProgressCallback == nil {
+ return 0
+ }
+
+ return int(callbacks.PackProgressCallback(int32(stage), uint32(current), uint32(total)))
+}
+
+//export pushTransferProgressCallback
+func pushTransferProgressCallback(current, total C.uint, bytes C.size_t, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.PushTransferProgressCallback == nil {
+ return 0
+ }
+
+ return int(callbacks.PushTransferProgressCallback(uint32(current), uint32(total), uint(bytes)))
+}
+
+//export pushUpdateReferenceCallback
+func pushUpdateReferenceCallback(refname, status *C.char, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+
+ if callbacks.PushUpdateReferenceCallback == nil {
+ return 0
+ }
+
+ return int(callbacks.PushUpdateReferenceCallback(C.GoString(refname), C.GoString(status)))
+}
+
+func populateProxyOptions(ptr *C.git_proxy_options, opts *ProxyOptions) {
+ C.git_proxy_init_options(ptr, C.GIT_PROXY_OPTIONS_VERSION)
+ if opts == nil {
+ return
+ }
+
+ ptr._type = C.git_proxy_t(opts.Type)
+ ptr.url = C.CString(opts.Url)
+}
+
+func freeProxyOptions(ptr *C.git_proxy_options) {
+ C.free(unsafe.Pointer(ptr.url))
+}
+
+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 (r *Remote) Free() {
+ runtime.SetFinalizer(r, nil)
+ C.git_remote_free(r.ptr)
+ r.ptr = nil
+}
+
+type RemoteCollection struct {
+ repo *Repository
+}
+
+func (c *RemoteCollection) List() ([]string, error) {
+ var r C.git_strarray
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_remote_list(&r, c.repo.ptr)
+ runtime.KeepAlive(c.repo)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ defer C.git_strarray_free(&r)
+
+ remotes := makeStringsFromCStrings(r.strings, int(r.count))
+ return remotes, nil
+}
+
+func (c *RemoteCollection) Create(name string, url string) (*Remote, error) {
+ remote := &Remote{repo: c.repo}
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create(&remote.ptr, c.repo.ptr, cname, curl)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (c *RemoteCollection) Delete(name string) error {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_delete(c.repo.ptr, cname)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch string) (*Remote, error) {
+ remote := &Remote{repo: c.repo}
+
+ 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))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create_with_fetchspec(&remote.ptr, c.repo.ptr, cname, curl, cfetch)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (c *RemoteCollection) CreateAnonymous(url string) (*Remote, error) {
+ remote := &Remote{repo: c.repo}
+
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create_anonymous(&remote.ptr, c.repo.ptr, curl)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (c *RemoteCollection) Lookup(name string) (*Remote, error) {
+ remote := &Remote{repo: c.repo}
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_lookup(&remote.ptr, c.repo.ptr, cname)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (o *Remote) Name() string {
+ s := C.git_remote_name(o.ptr)
+ runtime.KeepAlive(o)
+ return C.GoString(s)
+}
+
+func (o *Remote) Url() string {
+ s := C.git_remote_url(o.ptr)
+ runtime.KeepAlive(o)
+ return C.GoString(s)
+}
+
+func (o *Remote) PushUrl() string {
+ s := C.git_remote_pushurl(o.ptr)
+ runtime.KeepAlive(o)
+ return C.GoString(s)
+}
+
+func (c *RemoteCollection) Rename(remote, newname string) ([]string, error) {
+ cproblems := C.git_strarray{}
+ defer freeStrarray(&cproblems)
+ cnewname := C.CString(newname)
+ defer C.free(unsafe.Pointer(cnewname))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_rename(&cproblems, c.repo.ptr, cremote, cnewname)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return []string{}, MakeGitError(ret)
+ }
+
+ problems := makeStringsFromCStrings(cproblems.strings, int(cproblems.count))
+ return problems, nil
+}
+
+func (c *RemoteCollection) SetUrl(remote, url string) error {
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_set_url(c.repo.ptr, cremote, curl)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (c *RemoteCollection) SetPushUrl(remote, url string) error {
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_set_pushurl(c.repo.ptr, cremote, curl)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (c *RemoteCollection) AddFetch(remote, refspec string) error {
+ crefspec := C.CString(refspec)
+ defer C.free(unsafe.Pointer(crefspec))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_add_fetch(c.repo.ptr, cremote, crefspec)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ 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 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) FetchRefspecs() ([]string, error) {
+ crefspecs := C.git_strarray{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_get_fetch_refspecs(&crefspecs, o.ptr)
+ runtime.KeepAlive(o)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ defer C.git_strarray_free(&crefspecs)
+
+ refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
+ return refspecs, nil
+}
+
+func (c *RemoteCollection) AddPush(remote, refspec string) error {
+ crefspec := C.CString(refspec)
+ defer C.free(unsafe.Pointer(crefspec))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_add_push(c.repo.ptr, cremote, crefspec)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) PushRefspecs() ([]string, error) {
+ crefspecs := C.git_strarray{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_get_push_refspecs(&crefspecs, o.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ defer C.git_strarray_free(&crefspecs)
+ runtime.KeepAlive(o)
+
+ refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
+ return refspecs, nil
+}
+
+func (o *Remote) RefspecCount() uint {
+ count := C.git_remote_refspec_count(o.ptr)
+ runtime.KeepAlive(o)
+ return uint(count)
+}
+
+func populateFetchOptions(options *C.git_fetch_options, opts *FetchOptions) {
+ C.git_fetch_init_options(options, C.GIT_FETCH_OPTIONS_VERSION)
+ if opts == nil {
+ return
+ }
+ populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks)
+ options.prune = C.git_fetch_prune_t(opts.Prune)
+ options.update_fetchhead = cbool(opts.UpdateFetchhead)
+ options.download_tags = C.git_remote_autotag_option_t(opts.DownloadTags)
+
+ options.custom_headers = C.git_strarray{}
+ options.custom_headers.count = C.size_t(len(opts.Headers))
+ options.custom_headers.strings = makeCStringsFromStrings(opts.Headers)
+}
+
+func populatePushOptions(options *C.git_push_options, opts *PushOptions) {
+ C.git_push_init_options(options, C.GIT_PUSH_OPTIONS_VERSION)
+ if opts == nil {
+ return
+ }
+
+ options.pb_parallelism = C.uint(opts.PbParallelism)
+
+ options.custom_headers = C.git_strarray{}
+ options.custom_headers.count = C.size_t(len(opts.Headers))
+ options.custom_headers.strings = makeCStringsFromStrings(opts.Headers)
+
+ populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks)
+}
+
+// Fetch performs a fetch operation. refspecs specifies which refspecs
+// to use for this fetch, use an empty list to use the refspecs from
+// the configuration; msg specifies what to use for the reflog
+// entries. Leave "" to use defaults.
+func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error {
+ var cmsg *C.char = nil
+ if msg != "" {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+
+ crefspecs := C.git_strarray{}
+ crefspecs.count = C.size_t(len(refspecs))
+ crefspecs.strings = makeCStringsFromStrings(refspecs)
+ defer freeStrarray(&crefspecs)
+
+ coptions := (*C.git_fetch_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_fetch_options{}))))
+ defer C.free(unsafe.Pointer(coptions))
+
+ populateFetchOptions(coptions, opts)
+ defer untrackCalbacksPayload(&coptions.callbacks)
+ defer freeStrarray(&coptions.custom_headers)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_fetch(o.ptr, &crefspecs, coptions, cmsg)
+ runtime.KeepAlive(o)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
+ return o.Connect(ConnectDirectionFetch, callbacks, proxyOpts, headers)
+}
+
+func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
+ return o.Connect(ConnectDirectionPush, callbacks, proxyOpts, headers)
+}
+
+// Connect opens a connection to a remote.
+//
+// The transport is selected based on the URL. The direction argument
+// is due to a limitation of the git protocol (over TCP or SSH) which
+// starts up a specific binary which can only do the one or the other.
+//
+// 'headers' are extra HTTP headers to use in this connection.
+func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
+ var ccallbacks C.git_remote_callbacks
+ populateRemoteCallbacks(&ccallbacks, callbacks)
+
+ var cproxy C.git_proxy_options
+ populateProxyOptions(&cproxy, proxyOpts)
+ defer freeProxyOptions(&cproxy)
+
+ cheaders := C.git_strarray{}
+ cheaders.count = C.size_t(len(headers))
+ cheaders.strings = makeCStringsFromStrings(headers)
+ defer freeStrarray(&cheaders)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders)
+ runtime.KeepAlive(o)
+ if ret != 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) Disconnect() {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ C.git_remote_disconnect(o.ptr)
+ runtime.KeepAlive(o)
+}
+
+func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
+
+ var refs **C.git_remote_head
+ var length C.size_t
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_ls(&refs, &length, o.ptr)
+ runtime.KeepAlive(o)
+ if ret != 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ size := int(length)
+
+ if size == 0 {
+ return make([]RemoteHead, 0), nil
+ }
+
+ hdr := reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(refs)),
+ Len: size,
+ Cap: size,
+ }
+
+ goSlice := *(*[]*C.git_remote_head)(unsafe.Pointer(&hdr))
+
+ var heads []RemoteHead
+
+ for _, s := range goSlice {
+ head := newRemoteHeadFromC(s)
+
+ if len(filterRefs) > 0 {
+ for _, r := range filterRefs {
+ if strings.Contains(head.Name, r) {
+ heads = append(heads, head)
+ break
+ }
+ }
+ } else {
+ heads = append(heads, head)
+ }
+ }
+
+ return heads, nil
+}
+
+func (o *Remote) Push(refspecs []string, opts *PushOptions) error {
+ crefspecs := C.git_strarray{}
+ crefspecs.count = C.size_t(len(refspecs))
+ crefspecs.strings = makeCStringsFromStrings(refspecs)
+ defer freeStrarray(&crefspecs)
+
+ coptions := (*C.git_push_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_push_options{}))))
+ defer C.free(unsafe.Pointer(coptions))
+
+ populatePushOptions(coptions, opts)
+ defer untrackCalbacksPayload(&coptions.callbacks)
+ defer freeStrarray(&coptions.custom_headers)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_push(o.ptr, &crefspecs, coptions)
+ runtime.KeepAlive(o)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) PruneRefs() bool {
+ return C.git_remote_prune_refs(o.ptr) > 0
+}
+
+func (o *Remote) Prune(callbacks *RemoteCallbacks) error {
+ var ccallbacks C.git_remote_callbacks
+ populateRemoteCallbacks(&ccallbacks, callbacks)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_prune(o.ptr, &ccallbacks)
+ runtime.KeepAlive(o)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}