2014-01-03 18:40:21 -06:00
|
|
|
package git
|
|
|
|
|
|
|
|
/*
|
|
|
|
#include <git2.h>
|
2014-10-15 10:10:35 -05:00
|
|
|
#include <string.h>
|
2014-01-03 18:40:21 -06:00
|
|
|
|
2014-01-06 10:55:29 -06:00
|
|
|
extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks);
|
2014-01-03 18:40:21 -06:00
|
|
|
|
|
|
|
*/
|
|
|
|
import "C"
|
2014-10-15 08:43:02 -05:00
|
|
|
import (
|
|
|
|
"crypto/x509"
|
2014-10-24 14:12:07 -05:00
|
|
|
"reflect"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
"unsafe"
|
2014-10-15 08:43:02 -05:00
|
|
|
)
|
2014-01-05 14:55:32 -06:00
|
|
|
|
|
|
|
type TransferProgress struct {
|
2014-03-11 15:19:12 -05:00
|
|
|
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)}
|
2014-01-05 14:55:32 -06:00
|
|
|
}
|
2014-01-03 18:40:21 -06:00
|
|
|
|
|
|
|
type RemoteCompletion uint
|
2014-10-27 11:08:05 -05:00
|
|
|
type ConnectDirection uint
|
2014-02-26 12:41:20 -06:00
|
|
|
|
2014-01-03 18:40:21 -06:00
|
|
|
const (
|
|
|
|
RemoteCompletionDownload RemoteCompletion = C.GIT_REMOTE_COMPLETION_DOWNLOAD
|
2014-10-27 09:12:18 -05:00
|
|
|
RemoteCompletionIndexing RemoteCompletion = C.GIT_REMOTE_COMPLETION_INDEXING
|
|
|
|
RemoteCompletionError RemoteCompletion = C.GIT_REMOTE_COMPLETION_ERROR
|
2014-10-27 11:08:05 -05:00
|
|
|
|
|
|
|
ConnectDirectionFetch ConnectDirection = C.GIT_DIRECTION_FETCH
|
2014-10-27 09:12:18 -05:00
|
|
|
ConnectDirectionPush ConnectDirection = C.GIT_DIRECTION_PUSH
|
2014-01-03 18:40:21 -06:00
|
|
|
)
|
|
|
|
|
2014-10-27 09:12:18 -05:00
|
|
|
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
|
2014-12-12 18:23:40 -06:00
|
|
|
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
|
2014-01-03 18:40:21 -06:00
|
|
|
|
2014-01-05 14:55:32 -06:00
|
|
|
type RemoteCallbacks struct {
|
2014-04-26 11:43:22 -05:00
|
|
|
SidebandProgressCallback TransportMessageCallback
|
2014-01-05 14:55:32 -06:00
|
|
|
CompletionCallback
|
|
|
|
CredentialsCallback
|
|
|
|
TransferProgressCallback
|
|
|
|
UpdateTipsCallback
|
2014-10-15 08:43:02 -05:00
|
|
|
CertificateCheckCallback
|
2014-12-12 18:23:40 -06:00
|
|
|
PackProgressCallback PackbuilderProgressCallback
|
|
|
|
PushTransferProgressCallback
|
|
|
|
PushUpdateReferenceCallback
|
2014-01-05 14:55:32 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
type Remote struct {
|
2014-10-24 14:12:07 -05:00
|
|
|
ptr *C.git_remote
|
2014-10-15 08:43:02 -05:00
|
|
|
callbacks RemoteCallbacks
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-10-15 09:57:32 -05:00
|
|
|
type CertificateKind uint
|
|
|
|
|
|
|
|
const (
|
|
|
|
CertificateX509 CertificateKind = C.GIT_CERT_X509
|
2014-10-27 09:12:18 -05:00
|
|
|
CertificateHostkey CertificateKind = C.GIT_CERT_HOSTKEY_LIBSSH2
|
2014-10-15 09:57:32 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
2014-10-27 09:12:18 -05:00
|
|
|
HostkeySHA1 HostkeyKind = C.GIT_CERT_SSH_SHA1
|
2014-10-15 09:57:32 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2015-01-04 11:05:11 -06:00
|
|
|
type PushOptions struct {
|
|
|
|
PbParallelism uint
|
|
|
|
}
|
|
|
|
|
2014-10-24 14:12:07 -05:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-05 14:55:32 -06:00
|
|
|
func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) {
|
2014-03-11 15:19:12 -05:00
|
|
|
C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
|
2014-01-05 14:55:32 -06:00
|
|
|
if callbacks == nil {
|
|
|
|
return
|
|
|
|
}
|
2014-01-06 10:55:29 -06:00
|
|
|
C._go_git_setup_callbacks(ptr)
|
2014-01-05 14:55:32 -06:00
|
|
|
ptr.payload = unsafe.Pointer(callbacks)
|
|
|
|
}
|
|
|
|
|
2014-04-26 11:43:22 -05:00
|
|
|
//export sidebandProgressCallback
|
|
|
|
func sidebandProgressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int {
|
2014-01-03 18:40:21 -06:00
|
|
|
callbacks := (*RemoteCallbacks)(data)
|
2014-04-26 11:43:22 -05:00
|
|
|
if callbacks.SidebandProgressCallback == nil {
|
2014-01-05 14:55:32 -06:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
str := C.GoStringN(_str, _len)
|
2014-10-27 09:12:18 -05:00
|
|
|
return int(callbacks.SidebandProgressCallback(str))
|
2014-01-03 18:40:21 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//export completionCallback
|
|
|
|
func completionCallback(completion_type C.git_remote_completion_type, data unsafe.Pointer) int {
|
|
|
|
callbacks := (*RemoteCallbacks)(data)
|
2014-01-05 14:55:32 -06:00
|
|
|
if callbacks.CompletionCallback == nil {
|
|
|
|
return 0
|
|
|
|
}
|
2014-10-27 09:12:18 -05:00
|
|
|
return int(callbacks.CompletionCallback(RemoteCompletion(completion_type)))
|
2014-01-03 18:40:21 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//export credentialsCallback
|
|
|
|
func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C.char, allowed_types uint, data unsafe.Pointer) int {
|
|
|
|
callbacks := (*RemoteCallbacks)(data)
|
2014-01-05 14:55:32 -06:00
|
|
|
if callbacks.CredentialsCallback == nil {
|
|
|
|
return 0
|
|
|
|
}
|
2014-01-03 18:40:21 -06:00
|
|
|
url := C.GoString(_url)
|
|
|
|
username_from_url := C.GoString(_username_from_url)
|
2014-01-05 14:55:32 -06:00
|
|
|
ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
|
2014-03-11 15:19:12 -05:00
|
|
|
*_cred = cred.ptr
|
2014-10-27 09:12:18 -05:00
|
|
|
return int(ret)
|
2014-01-03 18:40:21 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//export transferProgressCallback
|
2014-01-05 14:55:32 -06:00
|
|
|
func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointer) int {
|
2014-01-03 18:40:21 -06:00
|
|
|
callbacks := (*RemoteCallbacks)(data)
|
2014-01-05 14:55:32 -06:00
|
|
|
if callbacks.TransferProgressCallback == nil {
|
|
|
|
return 0
|
|
|
|
}
|
2014-10-27 09:12:18 -05:00
|
|
|
return int(callbacks.TransferProgressCallback(newTransferProgressFromC(stats)))
|
2014-01-03 18:40:21 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//export updateTipsCallback
|
|
|
|
func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int {
|
|
|
|
callbacks := (*RemoteCallbacks)(data)
|
2014-01-05 14:55:32 -06:00
|
|
|
if callbacks.UpdateTipsCallback == nil {
|
|
|
|
return 0
|
|
|
|
}
|
2014-01-03 18:40:21 -06:00
|
|
|
refname := C.GoString(_refname)
|
|
|
|
a := newOidFromC(_a)
|
|
|
|
b := newOidFromC(_b)
|
2014-10-27 09:12:18 -05:00
|
|
|
return int(callbacks.UpdateTipsCallback(refname, a, b))
|
2014-01-03 18:40:21 -06:00
|
|
|
}
|
|
|
|
|
2014-10-15 08:43:02 -05:00
|
|
|
//export certificateCheckCallback
|
2014-10-15 09:57:32 -05:00
|
|
|
func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, data unsafe.Pointer) int {
|
2014-10-15 08:43:02 -05:00
|
|
|
callbacks := (*RemoteCallbacks)(data)
|
2014-10-19 07:35:22 -05:00
|
|
|
// if there's no callback set, we need to make sure we fail if the library didn't consider this cert valid
|
2014-10-15 08:43:02 -05:00
|
|
|
if callbacks.CertificateCheckCallback == nil {
|
2014-10-19 07:35:22 -05:00
|
|
|
if _valid == 1 {
|
|
|
|
return 0
|
|
|
|
} else {
|
|
|
|
return C.GIT_ECERTIFICATE
|
|
|
|
}
|
2014-10-15 08:43:02 -05:00
|
|
|
}
|
|
|
|
host := C.GoString(_host)
|
|
|
|
valid := _valid != 0
|
|
|
|
|
2014-10-15 09:57:32 -05:00
|
|
|
var cert Certificate
|
2014-10-15 08:43:02 -05:00
|
|
|
if _cert.cert_type == C.GIT_CERT_X509 {
|
2014-10-15 09:57:32 -05:00
|
|
|
cert.Kind = CertificateX509
|
2014-10-15 08:43:02 -05:00
|
|
|
ccert := (*C.git_cert_x509)(unsafe.Pointer(_cert))
|
|
|
|
x509_certs, err := x509.ParseCertificates(C.GoBytes(ccert.data, C.int(ccert.len)))
|
|
|
|
if err != nil {
|
2014-10-15 09:57:32 -05:00
|
|
|
return C.GIT_EUSER
|
2014-10-15 08:43:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// we assume there's only one, which should hold true for any web server we want to talk to
|
2014-10-15 09:57:32 -05:00
|
|
|
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
|
2014-10-15 08:43:02 -05:00
|
|
|
}
|
|
|
|
|
2014-10-27 09:12:18 -05:00
|
|
|
return int(callbacks.CertificateCheckCallback(&cert, valid, host))
|
2014-10-15 08:43:02 -05:00
|
|
|
}
|
|
|
|
|
2014-12-12 18:23:40 -06:00
|
|
|
//export packProgressCallback
|
|
|
|
func packProgressCallback(stage C.int, current, total C.uint, data unsafe.Pointer) int {
|
|
|
|
callbacks := (*RemoteCallbacks)(data)
|
|
|
|
|
|
|
|
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 := (*RemoteCallbacks)(data)
|
|
|
|
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 := (*RemoteCallbacks)(data)
|
|
|
|
|
|
|
|
if callbacks.PushUpdateReferenceCallback == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(callbacks.PushUpdateReferenceCallback(C.GoString(refname), C.GoString(status)))
|
|
|
|
}
|
|
|
|
|
2014-01-06 14:05:35 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2014-04-04 11:51:46 -05:00
|
|
|
func (r *Remote) SetCallbacks(callbacks *RemoteCallbacks) error {
|
2014-10-15 08:43:02 -05:00
|
|
|
r.callbacks = *callbacks
|
2014-04-04 11:51:46 -05:00
|
|
|
|
2014-10-15 08:43:02 -05:00
|
|
|
var ccallbacks C.git_remote_callbacks
|
|
|
|
populateRemoteCallbacks(&ccallbacks, &r.callbacks)
|
2014-04-04 11:51:46 -05:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ecode := C.git_remote_set_callbacks(r.ptr, &ccallbacks)
|
|
|
|
if ecode < 0 {
|
|
|
|
return MakeGitError(ecode)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (r *Remote) Free() {
|
|
|
|
runtime.SetFinalizer(r, nil)
|
|
|
|
C.git_remote_free(r.ptr)
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-03-20 04:06:56 -05:00
|
|
|
func (repo *Repository) ListRemotes() ([]string, error) {
|
|
|
|
var r C.git_strarray
|
2014-12-05 19:44:57 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-03-20 04:06:56 -05:00
|
|
|
ecode := C.git_remote_list(&r, repo.ptr)
|
|
|
|
if ecode < 0 {
|
2014-03-20 22:24:29 -05:00
|
|
|
return nil, MakeGitError(ecode)
|
2014-03-20 04:06:56 -05:00
|
|
|
}
|
|
|
|
defer C.git_strarray_free(&r)
|
|
|
|
|
|
|
|
remotes := makeStringsFromCStrings(r.strings, int(r.count))
|
|
|
|
return remotes, nil
|
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
|
|
|
|
remote := &Remote{}
|
2014-02-26 12:41:20 -06:00
|
|
|
|
2014-01-06 14:05:35 -06:00
|
|
|
cname := C.CString(name)
|
|
|
|
defer C.free(unsafe.Pointer(cname))
|
|
|
|
curl := C.CString(url)
|
|
|
|
defer C.free(unsafe.Pointer(curl))
|
|
|
|
|
2014-02-26 12:41:20 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-01-06 14:05:35 -06:00
|
|
|
ret := C.git_remote_create(&remote.ptr, repo.ptr, cname, curl)
|
2014-02-26 12:41:20 -06:00
|
|
|
if ret < 0 {
|
|
|
|
return nil, MakeGitError(ret)
|
|
|
|
}
|
2014-02-27 18:36:44 -06:00
|
|
|
runtime.SetFinalizer(remote, (*Remote).Free)
|
2014-02-26 12:41:20 -06:00
|
|
|
return remote, nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-11-26 15:05:21 -06:00
|
|
|
func (repo *Repository) DeleteRemote(name string) error {
|
|
|
|
cname := C.CString(name)
|
|
|
|
defer C.free(unsafe.Pointer(cname))
|
2015-01-05 13:58:36 -06:00
|
|
|
|
2014-11-26 15:05:21 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_delete(repo.ptr, cname)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch string) (*Remote, error) {
|
|
|
|
remote := &Remote{}
|
2014-01-06 14:05:35 -06:00
|
|
|
|
|
|
|
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))
|
|
|
|
|
2014-02-26 12:41:20 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-01-06 14:05:35 -06:00
|
|
|
ret := C.git_remote_create_with_fetchspec(&remote.ptr, repo.ptr, cname, curl, cfetch)
|
2014-02-26 12:41:20 -06:00
|
|
|
if ret < 0 {
|
|
|
|
return nil, MakeGitError(ret)
|
|
|
|
}
|
2014-02-27 18:36:44 -06:00
|
|
|
runtime.SetFinalizer(remote, (*Remote).Free)
|
2014-02-26 12:41:20 -06:00
|
|
|
return remote, nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-04-01 13:10:20 -05:00
|
|
|
func (repo *Repository) CreateAnonymousRemote(url, fetch string) (*Remote, error) {
|
2014-02-27 18:36:44 -06:00
|
|
|
remote := &Remote{}
|
2014-01-06 14:05:35 -06:00
|
|
|
|
|
|
|
curl := C.CString(url)
|
|
|
|
defer C.free(unsafe.Pointer(curl))
|
|
|
|
cfetch := C.CString(fetch)
|
|
|
|
defer C.free(unsafe.Pointer(cfetch))
|
|
|
|
|
2014-02-26 12:41:20 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-04-01 13:10:20 -05:00
|
|
|
ret := C.git_remote_create_anonymous(&remote.ptr, repo.ptr, curl, cfetch)
|
2014-02-26 12:41:20 -06:00
|
|
|
if ret < 0 {
|
|
|
|
return nil, MakeGitError(ret)
|
|
|
|
}
|
2014-02-27 18:36:44 -06:00
|
|
|
runtime.SetFinalizer(remote, (*Remote).Free)
|
2014-02-26 12:41:20 -06:00
|
|
|
return remote, nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-12-02 18:50:37 -06:00
|
|
|
func (repo *Repository) LookupRemote(name string) (*Remote, error) {
|
2014-02-27 18:36:44 -06:00
|
|
|
remote := &Remote{}
|
2014-01-06 14:05:35 -06:00
|
|
|
|
|
|
|
cname := C.CString(name)
|
|
|
|
defer C.free(unsafe.Pointer(cname))
|
|
|
|
|
2014-02-26 12:41:20 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-12-02 18:50:37 -06:00
|
|
|
ret := C.git_remote_lookup(&remote.ptr, repo.ptr, cname)
|
2014-02-26 12:41:20 -06:00
|
|
|
if ret < 0 {
|
|
|
|
return nil, MakeGitError(ret)
|
|
|
|
}
|
2014-02-27 18:36:44 -06:00
|
|
|
runtime.SetFinalizer(remote, (*Remote).Free)
|
2014-02-26 12:41:20 -06:00
|
|
|
return remote, nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) Save() error {
|
2014-02-26 12:41:20 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_save(o.ptr)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) Owner() Repository {
|
2014-01-06 14:05:35 -06:00
|
|
|
return Repository{C.git_remote_owner(o.ptr)}
|
2014-02-26 12:41:20 -06:00
|
|
|
}
|
2014-01-06 14:05:35 -06:00
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) Name() string {
|
2014-01-06 14:05:35 -06:00
|
|
|
return C.GoString(C.git_remote_name(o.ptr))
|
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) Url() string {
|
2014-01-06 14:05:35 -06:00
|
|
|
return C.GoString(C.git_remote_url(o.ptr))
|
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) PushUrl() string {
|
2014-01-06 14:05:35 -06:00
|
|
|
return C.GoString(C.git_remote_pushurl(o.ptr))
|
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) SetUrl(url string) error {
|
2014-01-06 14:05:35 -06:00
|
|
|
curl := C.CString(url)
|
|
|
|
defer C.free(unsafe.Pointer(curl))
|
2014-02-26 12:41:20 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_set_url(o.ptr, curl)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) SetPushUrl(url string) error {
|
2014-01-06 14:05:35 -06:00
|
|
|
curl := C.CString(url)
|
|
|
|
defer C.free(unsafe.Pointer(curl))
|
2014-02-26 12:41:20 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_set_pushurl(o.ptr, curl)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) AddFetch(refspec string) error {
|
2014-01-06 14:05:35 -06:00
|
|
|
crefspec := C.CString(refspec)
|
|
|
|
defer C.free(unsafe.Pointer(crefspec))
|
2014-02-26 12:41:20 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_add_fetch(o.ptr, crefspec)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-03-11 18:25:22 -05:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2014-03-19 01:54:52 -05:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2014-03-19 21:29:54 -05:00
|
|
|
func (o *Remote) FetchRefspecs() ([]string, error) {
|
2014-01-06 14:05:35 -06:00
|
|
|
crefspecs := C.git_strarray{}
|
2014-02-26 12:41:20 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_get_fetch_refspecs(&crefspecs, o.ptr)
|
|
|
|
if ret < 0 {
|
|
|
|
return nil, MakeGitError(ret)
|
|
|
|
}
|
2014-01-06 14:05:35 -06:00
|
|
|
defer C.git_strarray_free(&crefspecs)
|
|
|
|
|
2014-03-11 18:25:22 -05:00
|
|
|
refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
|
2014-02-26 12:41:20 -06:00
|
|
|
return refspecs, nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) SetFetchRefspecs(refspecs []string) error {
|
2014-01-06 14:05:35 -06:00
|
|
|
crefspecs := C.git_strarray{}
|
|
|
|
crefspecs.count = C.size_t(len(refspecs))
|
2014-03-11 18:25:22 -05:00
|
|
|
crefspecs.strings = makeCStringsFromStrings(refspecs)
|
2014-03-19 01:54:52 -05:00
|
|
|
defer freeStrarray(&crefspecs)
|
2014-01-06 14:05:35 -06:00
|
|
|
|
2014-02-26 12:41:20 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_set_fetch_refspecs(o.ptr, &crefspecs)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) AddPush(refspec string) error {
|
2014-01-06 14:05:35 -06:00
|
|
|
crefspec := C.CString(refspec)
|
|
|
|
defer C.free(unsafe.Pointer(crefspec))
|
2014-02-26 12:41:20 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_add_push(o.ptr, crefspec)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-03-19 21:29:54 -05:00
|
|
|
func (o *Remote) PushRefspecs() ([]string, error) {
|
2014-01-06 14:05:35 -06:00
|
|
|
crefspecs := C.git_strarray{}
|
2014-02-26 12:41:20 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_get_push_refspecs(&crefspecs, o.ptr)
|
|
|
|
if ret < 0 {
|
|
|
|
return nil, MakeGitError(ret)
|
|
|
|
}
|
2014-01-06 14:05:35 -06:00
|
|
|
defer C.git_strarray_free(&crefspecs)
|
2014-03-11 18:25:22 -05:00
|
|
|
refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
|
2014-02-26 12:41:20 -06:00
|
|
|
return refspecs, nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) SetPushRefspecs(refspecs []string) error {
|
2014-01-06 14:05:35 -06:00
|
|
|
crefspecs := C.git_strarray{}
|
|
|
|
crefspecs.count = C.size_t(len(refspecs))
|
2014-03-11 18:25:22 -05:00
|
|
|
crefspecs.strings = makeCStringsFromStrings(refspecs)
|
2014-03-19 01:54:52 -05:00
|
|
|
defer freeStrarray(&crefspecs)
|
2014-01-06 14:05:35 -06:00
|
|
|
|
2014-02-26 12:41:20 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_set_push_refspecs(o.ptr, &crefspecs)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
2014-01-06 14:05:35 -06:00
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) ClearRefspecs() {
|
2014-01-06 14:05:35 -06:00
|
|
|
C.git_remote_clear_refspecs(o.ptr)
|
|
|
|
}
|
|
|
|
|
2014-02-27 18:36:44 -06:00
|
|
|
func (o *Remote) RefspecCount() uint {
|
2014-01-06 14:05:35 -06:00
|
|
|
return uint(C.git_remote_refspec_count(o.ptr))
|
|
|
|
}
|
2014-02-27 18:36:44 -06:00
|
|
|
|
2014-10-13 10:57:26 -05:00
|
|
|
func (o *Remote) SetUpdateFetchHead(val bool) {
|
2014-10-15 09:57:32 -05:00
|
|
|
C.git_remote_set_update_fetchhead(o.ptr, cbool(val))
|
2014-10-13 10:57:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Remote) UpdateFetchHead() bool {
|
2014-10-15 09:57:32 -05:00
|
|
|
return C.git_remote_update_fetchhead(o.ptr) > 0
|
2014-10-13 10:57:26 -05:00
|
|
|
}
|
|
|
|
|
2014-10-15 08:43:02 -05:00
|
|
|
// 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; sig and msg specify what to use for the reflog
|
|
|
|
// entries. Leave nil and "" to use defaults.
|
|
|
|
func (o *Remote) Fetch(refspecs []string, sig *Signature, msg string) error {
|
2014-02-27 18:36:44 -06:00
|
|
|
|
|
|
|
var csig *C.git_signature = nil
|
|
|
|
if sig != nil {
|
|
|
|
csig = sig.toC()
|
|
|
|
defer C.free(unsafe.Pointer(csig))
|
|
|
|
}
|
|
|
|
|
2014-10-15 08:43:02 -05:00
|
|
|
var cmsg *C.char = nil
|
|
|
|
if msg != "" {
|
2014-02-28 12:58:53 -06:00
|
|
|
cmsg = C.CString(msg)
|
|
|
|
defer C.free(unsafe.Pointer(cmsg))
|
|
|
|
}
|
2014-10-15 08:43:02 -05:00
|
|
|
|
|
|
|
crefspecs := C.git_strarray{}
|
|
|
|
crefspecs.count = C.size_t(len(refspecs))
|
|
|
|
crefspecs.strings = makeCStringsFromStrings(refspecs)
|
|
|
|
defer freeStrarray(&crefspecs)
|
|
|
|
|
2014-12-05 19:44:57 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-10-15 08:43:02 -05:00
|
|
|
ret := C.git_remote_fetch(o.ptr, &crefspecs, csig, cmsg)
|
2014-02-27 18:36:44 -06:00
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2014-10-24 14:12:07 -05:00
|
|
|
|
2014-10-27 10:29:42 -05:00
|
|
|
func (o *Remote) ConnectFetch() error {
|
2014-10-27 11:08:05 -05:00
|
|
|
return o.Connect(ConnectDirectionFetch)
|
2014-10-27 10:29:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Remote) ConnectPush() error {
|
2014-10-27 11:08:05 -05:00
|
|
|
return o.Connect(ConnectDirectionPush)
|
2014-10-27 10:29:42 -05:00
|
|
|
}
|
|
|
|
|
2014-10-27 11:08:05 -05:00
|
|
|
func (o *Remote) Connect(direction ConnectDirection) error {
|
2014-10-27 10:29:42 -05:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-10-27 11:08:05 -05:00
|
|
|
if ret := C.git_remote_connect(o.ptr, C.git_direction(direction)); ret != 0 {
|
2014-10-27 10:29:42 -05:00
|
|
|
return MakeGitError(ret)
|
2014-10-24 14:12:07 -05:00
|
|
|
}
|
2014-10-27 10:29:42 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
|
2014-10-24 14:12:07 -05:00
|
|
|
|
|
|
|
var refs **C.git_remote_head
|
|
|
|
var length C.size_t
|
|
|
|
|
2014-12-05 19:58:28 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-10-24 14:12:07 -05:00
|
|
|
if ret := C.git_remote_ls(&refs, &length, o.ptr); 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
|
|
|
|
|
2014-10-27 10:32:50 -05:00
|
|
|
for _, s := range goSlice {
|
|
|
|
head := newRemoteHeadFromC(s)
|
2014-10-24 14:12:07 -05:00
|
|
|
|
2014-10-27 10:32:50 -05:00
|
|
|
if len(filterRefs) > 0 {
|
2014-10-24 14:12:07 -05:00
|
|
|
for _, r := range filterRefs {
|
|
|
|
if strings.Contains(head.Name, r) {
|
|
|
|
heads = append(heads, head)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2014-10-27 10:32:50 -05:00
|
|
|
} else {
|
|
|
|
heads = append(heads, head)
|
2014-10-24 14:12:07 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return heads, nil
|
|
|
|
}
|
2014-12-12 17:25:11 -06:00
|
|
|
|
|
|
|
func (o *Remote) Push(refspecs []string, opts *PushOptions, sig *Signature, msg string) error {
|
|
|
|
var csig *C.git_signature = nil
|
|
|
|
if sig != nil {
|
|
|
|
csig = sig.toC()
|
|
|
|
defer C.free(unsafe.Pointer(csig))
|
|
|
|
}
|
|
|
|
|
|
|
|
var cmsg *C.char
|
|
|
|
if msg == "" {
|
|
|
|
cmsg = nil
|
|
|
|
} else {
|
|
|
|
cmsg = C.CString(msg)
|
|
|
|
defer C.free(unsafe.Pointer(cmsg))
|
|
|
|
}
|
|
|
|
|
|
|
|
var copts C.git_push_options
|
|
|
|
C.git_push_init_options(&copts, C.GIT_PUSH_OPTIONS_VERSION)
|
|
|
|
if opts != nil {
|
|
|
|
copts.pb_parallelism = C.uint(opts.PbParallelism)
|
|
|
|
}
|
|
|
|
|
|
|
|
crefspecs := C.git_strarray{}
|
|
|
|
crefspecs.count = C.size_t(len(refspecs))
|
|
|
|
crefspecs.strings = makeCStringsFromStrings(refspecs)
|
|
|
|
defer freeStrarray(&crefspecs)
|
|
|
|
|
2015-01-05 13:58:36 -06:00
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
2014-12-12 17:25:11 -06:00
|
|
|
|
|
|
|
ret := C.git_remote_push(o.ptr, &crefspecs, &copts, csig, cmsg)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2015-01-05 13:58:36 -06:00
|
|
|
|
|
|
|
func (o *Remote) PruneRefs() bool {
|
|
|
|
return C.git_remote_prune_refs(o.ptr) > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Remote) Prune() error {
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
|
|
|
ret := C.git_remote_prune(o.ptr)
|
|
|
|
if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|