package git /* #cgo pkg-config: libgit2 #include #include 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 }