blob: 529bc3968925cf64d05e4bc9c16150c31db20481 [file] [log] [blame]
package git
/*
#cgo pkg-config: libgit2
#include <git2.h>
#include <git2/errors.h>
extern int _go_git_remote_set_callbacks(git_remote *remote, void *payload);
*/
import "C"
import (
"reflect"
"runtime"
"unsafe"
)
type RemoteDirection int
const (
RemoteDirectionFetch RemoteDirection = C.GIT_DIRECTION_FETCH
RemoteDirectionPush = C.GIT_DIRECTION_PUSH
)
type AutotagOption int
const (
AutotagAuto AutotagOption = C.GIT_REMOTE_DOWNLOAD_TAGS_AUTO
AutotagNone = C.GIT_REMOTE_DOWNLOAD_TAGS_NONE
AutotagAll = C.GIT_REMOTE_DOWNLOAD_TAGS_ALL
)
type ProgressCb func([]byte) int
type TransferProgressCb func(*TransferProgress) int
type UpdateTipsCb func(string, *Oid, *Oid) int
type Remote struct {
Name string
Url string
// callbacks
Progress ProgressCb
TransferProgress TransferProgressCb
UpdateTips UpdateTipsCb
ptr *C.git_remote
}
func (r *Remote) Connect(direction RemoteDirection) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ret := C.git_remote_connect(r.ptr, C.git_direction(direction))
if ret < 0 {
return LastError()
}
return nil
}
func (r *Remote) IsConnected() bool {
return C.git_remote_connected(r.ptr) != 0
}
func (r *Remote) Disconnect() {
C.git_remote_disconnect(r.ptr)
}
func (r *Remote) Autotag() AutotagOption {
return AutotagOption(C.git_remote_autotag(r.ptr))
}
func (r *Remote) SetAutotag(opt AutotagOption) {
C.git_remote_set_autotag(r.ptr, C.git_remote_autotag_option_t(opt))
}
func (r *Remote) Stop() {
C.git_remote_stop(r.ptr)
}
func (r *Remote) Save() error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ret := C.git_remote_save(r.ptr)
if ret < 0 {
return LastError()
}
return nil
}
func (r *Remote) Ls() ([]*RemoteHead, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
var cheads **C.git_remote_head
var slice []*C.git_remote_head
var csize C.size_t
ret := C.git_remote_ls(&cheads, &csize, r.ptr)
if ret < 0 {
return nil, LastError()
}
sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&slice)))
sliceHeader.Cap = int(csize)
sliceHeader.Len = int(csize)
sliceHeader.Data = uintptr(unsafe.Pointer(cheads))
heads := make([]*RemoteHead, csize)
for i, h := range slice {
heads[i] = newRemoteHeadFromC(h)
}
return heads, nil
}
func (r *Remote) Download() error {
ret := C.git_remote_download(r.ptr)
if ret < 0 {
LastError()
}
return nil
}
func (r *Remote) Fetch() error {
ret := C.git_remote_fetch(r.ptr)
if ret < 0 {
LastError()
}
return nil
}
//export remoteProgress
func remoteProgress(str *C.char, length C.int, data unsafe.Pointer) int {
remote := (*Remote)(data)
if remote.Progress != nil {
return remote.Progress(C.GoBytes(unsafe.Pointer(str), length))
}
return 0
}
//export remoteTransferProgress
func remoteTransferProgress(ptr *C.git_transfer_progress, data unsafe.Pointer) int {
remote := (*Remote)(data)
if remote.TransferProgress != nil {
return remote.TransferProgress(newTransferProgressFromC(ptr))
}
return 0
}
//export remoteUpdateTips
func remoteUpdateTips(str *C.char, a, b *C.git_oid, data unsafe.Pointer) int {
remote := (*Remote)(data)
if remote.UpdateTips != nil {
var goa, gob Oid
CopyOid(&goa, a)
CopyOid(&gob, b)
return remote.UpdateTips(C.GoString(str), &goa, &gob)
}
return 0
}
type headlistData struct {
slice []*RemoteHead
}
func remoteHeadlistCb(rhead *C.git_remote_head, dataptr unsafe.Pointer) int {
data := (*headlistData)(dataptr)
head := newRemoteHeadFromC(rhead)
data.slice = append(data.slice, head)
return 0
}
func (r *Remote) Free() {
runtime.SetFinalizer(r, nil)
C.git_remote_free(r.ptr)
}
func newRemoteFromC(ptr *C.git_remote) *Remote {
remote := &Remote{
ptr: ptr,
Name: C.GoString(C.git_remote_name(ptr)),
Url: C.GoString(C.git_remote_url(ptr)),
}
// allways set the callbacks, we'll decide whether to call
// them once we're back in go-land
C._go_git_remote_set_callbacks(remote.ptr, unsafe.Pointer(remote))
runtime.SetFinalizer(remote, (*Remote).Free)
return remote
}
// transfer progress
type TransferProgress struct {
TotalObjects uint
IndexedObjects uint
ReceivedObjects uint
ReceivedBytes uint64
}
func newTransferProgressFromC(ptr *C.git_transfer_progress) *TransferProgress {
return &TransferProgress{
TotalObjects: uint(ptr.total_objects),
IndexedObjects: uint(ptr.indexed_objects),
ReceivedObjects: uint(ptr.received_objects),
ReceivedBytes: uint64(ptr.received_bytes),
}
}
// remote heads
// RemoteHead represents a reference available in the remote repository.
type RemoteHead struct {
Local bool
Oid Oid
Loid Oid
Name string
}
func newRemoteHeadFromC(ptr *C.git_remote_head) *RemoteHead {
head := &RemoteHead {
Local: ptr.local != 0,
Name: C.GoString(ptr.name),
}
CopyOid(&head.Oid, &ptr.oid)
CopyOid(&head.Loid, &ptr.loid)
return head
}
// These belong to the git_remote namespace but don't require any remote
func UrlIsValid(url string) bool {
curl := C.CString(url)
defer C.free(unsafe.Pointer(curl))
return C.git_remote_valid_url(curl) != 0
}
func UrlIsSupported(url string) bool {
curl := C.CString(url)
defer C.free(unsafe.Pointer(curl))
return C.git_remote_supported_url(curl) != 0
}