| 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 |
| } |
| |
| 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) |
| } |
| |
| 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) |
| 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{} |
| |
| 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) |
| if ret < 0 { |
| return MakeGitError(ret) |
| } |
| return nil |
| } |
| |
| func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch string) (*Remote, error) { |
| remote := &Remote{} |
| |
| 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{} |
| |
| 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{} |
| |
| 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 { |
| return C.GoString(C.git_remote_name(o.ptr)) |
| } |
| |
| func (o *Remote) Url() string { |
| return C.GoString(C.git_remote_url(o.ptr)) |
| } |
| |
| func (o *Remote) PushUrl() string { |
| return C.GoString(C.git_remote_pushurl(o.ptr)) |
| } |
| |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count)) |
| return refspecs, nil |
| } |
| |
| func (o *Remote) RefspecCount() uint { |
| return uint(C.git_remote_refspec_count(o.ptr)) |
| } |
| |
| 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) |
| 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() |
| |
| if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders); ret != 0 { |
| return MakeGitError(ret) |
| } |
| return nil |
| } |
| |
| func (o *Remote) Disconnect() { |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| C.git_remote_disconnect(o.ptr) |
| } |
| |
| func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) { |
| |
| var refs **C.git_remote_head |
| var length C.size_t |
| |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| if ret := C.git_remote_ls(&refs, &length, o.ptr); 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) |
| 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) |
| if ret < 0 { |
| return MakeGitError(ret) |
| } |
| return nil |
| } |