245 lines
4.9 KiB
Go
245 lines
4.9 KiB
Go
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
|
|
}
|
|
|
|
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
|
|
}
|