Fix the Cred interface

This change adds Cred.Free() and finalizers to prevent memory leaks. It
also makes the interface for Cred more idiomatic and return actual
errors intead of ints.
This commit is contained in:
lhchavez 2019-01-12 20:56:16 +00:00
parent 45097a857c
commit 37f732a833
2 changed files with 73 additions and 21 deletions

View File

@ -7,7 +7,10 @@ package git
git_credtype_t _go_git_cred_credtype(git_cred *cred);
*/
import "C"
import "unsafe"
import (
"runtime"
"unsafe"
)
type CredType uint
@ -22,6 +25,12 @@ type Cred struct {
ptr *C.git_cred
}
func newCred() *Cred {
cred := &Cred{}
runtime.SetFinalizer(cred, (*Cred).Free)
return cred
}
func (o *Cred) HasUsername() bool {
if C.git_cred_has_username(o.ptr) == 1 {
return true
@ -33,24 +42,36 @@ func (o *Cred) Type() CredType {
return (CredType)(C._go_git_cred_credtype(o.ptr))
}
func credFromC(ptr *C.git_cred) *Cred {
return &Cred{ptr}
func (o *Cred) Free() {
C.git_cred_free(o.ptr)
runtime.SetFinalizer(o, nil)
o.ptr = nil
}
func NewCredUserpassPlaintext(username string, password string) (int, Cred) {
cred := Cred{}
func NewCredUserpassPlaintext(username string, password string) (*Cred, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
cred := newCred()
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
cpassword := C.CString(password)
defer C.free(unsafe.Pointer(cpassword))
ret := C.git_cred_userpass_plaintext_new(&cred.ptr, cusername, cpassword)
return int(ret), cred
if ret != 0 {
cred.Free()
return nil, MakeGitError(ret)
}
return cred, nil
}
// NewCredSshKey creates new ssh credentials reading the public and private keys
// from the file system.
func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, passphrase string) (int, Cred) {
cred := Cred{}
func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, passphrase string) (*Cred, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
cred := newCred()
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
cpublickey := C.CString(publicKeyPath)
@ -60,13 +81,20 @@ func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string,
cpassphrase := C.CString(passphrase)
defer C.free(unsafe.Pointer(cpassphrase))
ret := C.git_cred_ssh_key_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase)
return int(ret), cred
if ret != 0 {
cred.Free()
return nil, MakeGitError(ret)
}
return cred, nil
}
// NewCredSshKeyFromMemory creates new ssh credentials using the publicKey and privateKey
// arguments as the values for the public and private keys.
func NewCredSshKeyFromMemory(username string, publicKey string, privateKey string, passphrase string) (int, Cred) {
cred := Cred{}
func NewCredSshKeyFromMemory(username string, publicKey string, privateKey string, passphrase string) (*Cred, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
cred := newCred()
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
cpublickey := C.CString(publicKey)
@ -76,19 +104,37 @@ func NewCredSshKeyFromMemory(username string, publicKey string, privateKey strin
cpassphrase := C.CString(passphrase)
defer C.free(unsafe.Pointer(cpassphrase))
ret := C.git_cred_ssh_key_memory_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase)
return int(ret), cred
if ret != 0 {
cred.Free()
return nil, MakeGitError(ret)
}
return cred, nil
}
func NewCredSshKeyFromAgent(username string) (int, Cred) {
cred := Cred{}
func NewCredSshKeyFromAgent(username string) (*Cred, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
cred := newCred()
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
ret := C.git_cred_ssh_key_from_agent(&cred.ptr, cusername)
return int(ret), cred
if ret != 0 {
cred.Free()
return nil, MakeGitError(ret)
}
return cred, nil
}
func NewCredDefault() (int, Cred) {
cred := Cred{}
func NewCredDefault() (*Cred, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
cred := newCred()
ret := C.git_cred_default_new(&cred.ptr)
return int(ret), cred
if ret != 0 {
cred.Free()
return nil, MakeGitError(ret)
}
return cred, nil
}

View File

@ -51,7 +51,7 @@ const (
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 CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (*Cred, error)
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
@ -246,11 +246,17 @@ func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C
}
url := C.GoString(_url)
username_from_url := C.GoString(_username_from_url)
ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
cred, err := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
if err != nil {
if gitError, ok := err.(*GitError); ok {
return int(gitError.Code)
}
return C.GIT_EUSER
}
if cred != nil {
*_cred = cred.ptr
}
return int(ret)
return 0
}
//export transferProgressCallback