Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
|
b60db7feec | |
|
82b24a762c | |
|
09f2361ba6 | |
|
f33c856845 | |
|
516586d2e7 | |
|
ee7e153ff8 | |
|
7b9e3895da |
4
git.go
4
git.go
|
@ -42,6 +42,10 @@ func newOidFromC(coid *C.git_oid) *Oid {
|
||||||
return oid
|
return oid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CopyOid(oid *Oid, coid *C.git_oid) {
|
||||||
|
copy(oid.bytes[0:20], C.GoBytes(unsafe.Pointer(coid), 20))
|
||||||
|
}
|
||||||
|
|
||||||
func NewOid(b []byte) *Oid {
|
func NewOid(b []byte) *Oid {
|
||||||
oid := new(Oid)
|
oid := new(Oid)
|
||||||
copy(oid.bytes[0:20], b[0:20])
|
copy(oid.bytes[0:20], b[0:20])
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRemoteLs(t *testing.T) {
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
remote, err := repo.CreateRemote("origin", "git://github.com/libgit2/TestGitRepository")
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
err = remote.Connect(RemoteDirectionFetch)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if remote.IsConnected() != true {
|
||||||
|
t.Fatal("Connected but not connected")
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []string{
|
||||||
|
"HEAD",
|
||||||
|
"refs/heads/first-merge",
|
||||||
|
"refs/heads/master",
|
||||||
|
"refs/heads/no-parent",
|
||||||
|
"refs/tags/annotated_tag",
|
||||||
|
"refs/tags/annotated_tag^{}",
|
||||||
|
"refs/tags/blob",
|
||||||
|
"refs/tags/commit_tree",
|
||||||
|
"refs/tags/nearly-dangling",
|
||||||
|
}
|
||||||
|
|
||||||
|
refs, err := remote.Ls()
|
||||||
|
for i, s := range expected {
|
||||||
|
if refs[i].Name != s {
|
||||||
|
t.Fatal("remote refs not as expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoteProgress(t *testing.T) {
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
remote, err := repo.CreateRemote("origin", "git://github.com/libgit2/TestGitRepository")
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
called := false
|
||||||
|
remote.Progress = func(bytes []byte) int {
|
||||||
|
called = true
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
remote.Connect(RemoteDirectionFetch)
|
||||||
|
err = remote.Download()
|
||||||
|
if !called {
|
||||||
|
t.Fatal("Callback not called")
|
||||||
|
}
|
||||||
|
}
|
|
@ -125,6 +125,23 @@ func (v *Repository) LookupReference(name string) (*Reference, error) {
|
||||||
return newReferenceFromC(ptr), nil
|
return newReferenceFromC(ptr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Repository) LookupRemote(name string) (*Remote, error) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
|
||||||
|
var remote *C.git_remote
|
||||||
|
ecode := C.git_remote_load(&remote, v.ptr, cname)
|
||||||
|
if ecode < 0 {
|
||||||
|
return nil, LastError()
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRemoteFromC(remote), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (v *Repository) CreateReference(name string, oid *Oid, force bool) (*Reference, error) {
|
func (v *Repository) CreateReference(name string, oid *Oid, force bool) (*Reference, error) {
|
||||||
cname := C.CString(name)
|
cname := C.CString(name)
|
||||||
defer C.free(unsafe.Pointer(cname))
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
@ -207,6 +224,22 @@ func (v *Repository) CreateCommit(
|
||||||
return oid, nil
|
return oid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Repository) CreateRemote(name, url string) (*Remote, error) {
|
||||||
|
cname := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
|
||||||
|
curl := C.CString(url)
|
||||||
|
defer C.free(unsafe.Pointer(curl))
|
||||||
|
|
||||||
|
var remote *C.git_remote
|
||||||
|
ret := C.git_remote_create(&remote, v.ptr, cname, curl)
|
||||||
|
if ret < 0 {
|
||||||
|
return nil, LastError()
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRemoteFromC(remote), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (v *Odb) Free() {
|
func (v *Odb) Free() {
|
||||||
runtime.SetFinalizer(v, nil)
|
runtime.SetFinalizer(v, nil)
|
||||||
C.git_odb_free(v.ptr)
|
C.git_odb_free(v.ptr)
|
||||||
|
|
26
wrapper.c
26
wrapper.c
|
@ -2,6 +2,7 @@
|
||||||
#include "git2.h"
|
#include "git2.h"
|
||||||
#include "git2/submodule.h"
|
#include "git2/submodule.h"
|
||||||
#include "git2/pack.h"
|
#include "git2/pack.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
typedef int (*gogit_submodule_cbk)(git_submodule *sm, const char *name, void *payload);
|
typedef int (*gogit_submodule_cbk)(git_submodule *sm, const char *name, void *payload);
|
||||||
|
|
||||||
|
@ -24,4 +25,29 @@ int _go_git_odb_foreach(git_odb *db, void *payload)
|
||||||
{
|
{
|
||||||
return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload);
|
return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _go_git_remote_set_callbacks(git_remote *remote, void *payload)
|
||||||
|
{
|
||||||
|
git_remote_callbacks cbs = GIT_REMOTE_CALLBACKS_INIT;
|
||||||
|
|
||||||
|
cbs.progress = remoteProgress;
|
||||||
|
cbs.transfer_progress = remoteTransferProgress;
|
||||||
|
cbs.update_tips = remoteUpdateTips;
|
||||||
|
cbs.payload = payload;
|
||||||
|
|
||||||
|
git_remote_set_callbacks(remote, &cbs);
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue