blob: b4b1dd727effea00c8dd0702c10e015efdde3649 [file] [log] [blame]
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
}