Merge pull request #348 from MagicalTux/git2go_issue_314
Make New*BackendFromC take unsafe.Pointer as argument
diff --git a/branch.go b/branch.go
index a869054..d381c23 100644
--- a/branch.go
+++ b/branch.go
@@ -73,6 +73,10 @@
}
}
+ if err != nil && IsErrorCode(err, ErrIterOver) {
+ return nil
+ }
+
return err
}
diff --git a/checkout.go b/checkout.go
index a2e312b..f5822c9 100644
--- a/checkout.go
+++ b/checkout.go
@@ -2,6 +2,8 @@
/*
#include <git2.h>
+
+extern void _go_git_populate_checkout_cb(git_checkout_options *opts);
*/
import "C"
import (
@@ -10,9 +12,18 @@
"unsafe"
)
+type CheckoutNotifyType uint
type CheckoutStrategy uint
const (
+ CheckoutNotifyNone CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_NONE
+ CheckoutNotifyConflict CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_CONFLICT
+ CheckoutNotifyDirty CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_DIRTY
+ CheckoutNotifyUpdated CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_UPDATED
+ CheckoutNotifyUntracked CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_UNTRACKED
+ CheckoutNotifyIgnored CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_IGNORED
+ CheckoutNotifyAll CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_ALL
+
CheckoutNone CheckoutStrategy = C.GIT_CHECKOUT_NONE // Dry run, no actual updates
CheckoutSafe CheckoutStrategy = C.GIT_CHECKOUT_SAFE // Allow safe updates that cannot overwrite uncommitted data
CheckoutForce CheckoutStrategy = C.GIT_CHECKOUT_FORCE // Allow all updates to force working directory to look like index
@@ -37,15 +48,21 @@
CheckoutUpdateSubmodulesIfChanged CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED // Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED)
)
+type CheckoutNotifyCallback func(why CheckoutNotifyType, path string, baseline, target, workdir DiffFile) ErrorCode
+type CheckoutProgressCallback func(path string, completed, total uint) ErrorCode
+
type CheckoutOpts struct {
- Strategy CheckoutStrategy // Default will be a dry run
- DisableFilters bool // Don't apply filters like CRLF conversion
- DirMode os.FileMode // Default is 0755
- FileMode os.FileMode // Default is 0644 or 0755 as dictated by blob
- FileOpenFlags int // Default is O_CREAT | O_TRUNC | O_WRONLY
- TargetDirectory string // Alternative checkout path to workdir
- Paths []string
- Baseline *Tree
+ Strategy CheckoutStrategy // Default will be a dry run
+ DisableFilters bool // Don't apply filters like CRLF conversion
+ DirMode os.FileMode // Default is 0755
+ FileMode os.FileMode // Default is 0644 or 0755 as dictated by blob
+ FileOpenFlags int // Default is O_CREAT | O_TRUNC | O_WRONLY
+ NotifyFlags CheckoutNotifyType // Default will be none
+ NotifyCallback CheckoutNotifyCallback
+ ProgressCallback CheckoutProgressCallback
+ TargetDirectory string // Alternative checkout path to workdir
+ Paths []string
+ Baseline *Tree
}
func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts {
@@ -55,6 +72,13 @@
opts.DirMode = os.FileMode(c.dir_mode)
opts.FileMode = os.FileMode(c.file_mode)
opts.FileOpenFlags = int(c.file_open_flags)
+ opts.NotifyFlags = CheckoutNotifyType(c.notify_flags)
+ if c.notify_payload != nil {
+ opts.NotifyCallback = pointerHandles.Get(c.notify_payload).(*CheckoutOpts).NotifyCallback
+ }
+ if c.progress_payload != nil {
+ opts.ProgressCallback = pointerHandles.Get(c.progress_payload).(*CheckoutOpts).ProgressCallback
+ }
if c.target_directory != nil {
opts.TargetDirectory = C.GoString(c.target_directory)
}
@@ -70,6 +94,38 @@
return &c
}
+//export checkoutNotifyCallback
+func checkoutNotifyCallback(why C.git_checkout_notify_t, cpath *C.char, cbaseline, ctarget, cworkdir, data unsafe.Pointer) int {
+ if data == nil {
+ return 0
+ }
+ path := C.GoString(cpath)
+ var baseline, target, workdir DiffFile
+ if cbaseline != nil {
+ baseline = diffFileFromC((*C.git_diff_file)(cbaseline))
+ }
+ if ctarget != nil {
+ target = diffFileFromC((*C.git_diff_file)(ctarget))
+ }
+ if cworkdir != nil {
+ workdir = diffFileFromC((*C.git_diff_file)(cworkdir))
+ }
+ opts := pointerHandles.Get(data).(*CheckoutOpts)
+ if opts.NotifyCallback == nil {
+ return 0
+ }
+ return int(opts.NotifyCallback(CheckoutNotifyType(why), path, baseline, target, workdir))
+}
+
+//export checkoutProgressCallback
+func checkoutProgressCallback(path *C.char, completed_steps, total_steps C.size_t, data unsafe.Pointer) int {
+ opts := pointerHandles.Get(data).(*CheckoutOpts)
+ if opts.ProgressCallback == nil {
+ return 0
+ }
+ return int(opts.ProgressCallback(C.GoString(path), uint(completed_steps), uint(total_steps)))
+}
+
// Convert the CheckoutOpts struct to the corresponding
// C-struct. Returns a pointer to ptr, or nil if opts is nil, in order
// to help with what to pass.
@@ -83,6 +139,17 @@
ptr.disable_filters = cbool(opts.DisableFilters)
ptr.dir_mode = C.uint(opts.DirMode.Perm())
ptr.file_mode = C.uint(opts.FileMode.Perm())
+ ptr.notify_flags = C.uint(opts.NotifyFlags)
+ if opts.NotifyCallback != nil || opts.ProgressCallback != nil {
+ C._go_git_populate_checkout_cb(ptr)
+ }
+ payload := pointerHandles.Track(opts)
+ if opts.NotifyCallback != nil {
+ ptr.notify_payload = payload
+ }
+ if opts.ProgressCallback != nil {
+ ptr.progress_payload = payload
+ }
if opts.TargetDirectory != "" {
ptr.target_directory = C.CString(opts.TargetDirectory)
}
@@ -106,6 +173,9 @@
if ptr.paths.count > 0 {
freeStrarray(&ptr.paths)
}
+ if ptr.notify_payload != nil {
+ pointerHandles.Untrack(ptr.notify_payload)
+ }
}
// Updates files in the index and the working tree to match the content of
diff --git a/clone.go b/clone.go
index e80d14d..1ff5124 100644
--- a/clone.go
+++ b/clone.go
@@ -41,7 +41,6 @@
var ptr *C.git_repository
ret := C.git_clone(&ptr, curl, cpath, copts)
- freeCheckoutOpts(&copts.checkout_opts)
if ret < 0 {
return nil, MakeGitError(ret)
diff --git a/credentials.go b/credentials.go
index bb0ec41..4e42b6e 100644
--- a/credentials.go
+++ b/credentials.go
@@ -44,13 +44,15 @@
return int(ret), cred
}
-func NewCredSshKey(username string, publickey string, privatekey string, passphrase string) (int, Cred) {
+// 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{}
cusername := C.CString(username)
defer C.free(unsafe.Pointer(cusername))
- cpublickey := C.CString(publickey)
+ cpublickey := C.CString(publicKeyPath)
defer C.free(unsafe.Pointer(cpublickey))
- cprivatekey := C.CString(privatekey)
+ cprivatekey := C.CString(privateKeyPath)
defer C.free(unsafe.Pointer(cprivatekey))
cpassphrase := C.CString(passphrase)
defer C.free(unsafe.Pointer(cpassphrase))
@@ -58,6 +60,22 @@
return int(ret), cred
}
+// 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{}
+ cusername := C.CString(username)
+ defer C.free(unsafe.Pointer(cusername))
+ cpublickey := C.CString(publicKey)
+ defer C.free(unsafe.Pointer(cpublickey))
+ cprivatekey := C.CString(privateKey)
+ defer C.free(unsafe.Pointer(cprivatekey))
+ 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
+}
+
func NewCredSshKeyFromAgent(username string) (int, Cred) {
cred := Cred{}
cusername := C.CString(username)
diff --git a/git_test.go b/git_test.go
index bdb6837..3385a72 100644
--- a/git_test.go
+++ b/git_test.go
@@ -58,6 +58,8 @@
checkFatal(t, err)
err = idx.AddByPath("README")
checkFatal(t, err)
+ err = idx.Write()
+ checkFatal(t, err)
treeId, err := idx.WriteTree()
checkFatal(t, err)
diff --git a/index.go b/index.go
index ae94864..2afdcdf 100644
--- a/index.go
+++ b/index.go
@@ -278,6 +278,22 @@
return nil
}
+// RemoveDirectory removes all entries from the index under a given directory.
+func (v *Index) RemoveDirectory(dir string, stage int) error {
+ cstr := C.CString(dir)
+ defer C.free(unsafe.Pointer(cstr))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_index_remove_directory(v.ptr, cstr, C.int(stage))
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
func (v *Index) WriteTreeTo(repo *Repository) (*Oid, error) {
oid := new(Oid)
diff --git a/index_test.go b/index_test.go
index 600b8b1..f47dace 100644
--- a/index_test.go
+++ b/index_test.go
@@ -109,6 +109,46 @@
}
}
+func TestIndexRemoveDirectory(t *testing.T) {
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ odb, err := repo.Odb()
+ checkFatal(t, err)
+
+ blobID, err := odb.Write([]byte("fou\n"), ObjectBlob)
+ checkFatal(t, err)
+
+ idx, err := NewIndex()
+ checkFatal(t, err)
+
+ entryCount := idx.EntryCount()
+ if entryCount != 0 {
+ t.Fatal("Index should count 0 entry")
+ }
+
+ entry := IndexEntry{
+ Path: "path/to/LISEZ_MOI",
+ Id: blobID,
+ Mode: FilemodeBlob,
+ }
+
+ err = idx.Add(&entry)
+ checkFatal(t, err)
+
+ entryCount = idx.EntryCount()
+ if entryCount != 1 {
+ t.Fatal("Index should count 1 entry")
+ }
+
+ err = idx.RemoveDirectory("path", 0)
+
+ entryCount = idx.EntryCount()
+ if entryCount != 0 {
+ t.Fatal("Index should count 0 entry")
+ }
+}
+
func TestIndexAddAllNoCallback(t *testing.T) {
t.Parallel()
repo := createTestRepo(t)
diff --git a/remote.go b/remote.go
index 8a57280..c537932 100644
--- a/remote.go
+++ b/remote.go
@@ -215,7 +215,7 @@
func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C.char, allowed_types uint, data unsafe.Pointer) int {
callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
if callbacks.CredentialsCallback == nil {
- return 0
+ return C.GIT_PASSTHROUGH
}
url := C.GoString(_url)
username_from_url := C.GoString(_username_from_url)
@@ -454,6 +454,26 @@
return C.GoString(C.git_remote_pushurl(o.ptr))
}
+func (c *RemoteCollection) Rename(remote, newname string) ([]string, error) {
+ cproblems := C.git_strarray{}
+ defer freeStrarray(&cproblems)
+ cnewname := C.CString(newname)
+ defer C.free(unsafe.Pointer(cnewname))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_rename(&cproblems, c.repo.ptr, cremote, cnewname)
+ if ret < 0 {
+ return []string{}, MakeGitError(ret)
+ }
+
+ problems := makeStringsFromCStrings(cproblems.strings, int(cproblems.count))
+ return problems, nil
+}
+
func (c *RemoteCollection) SetUrl(remote, url string) error {
curl := C.CString(url)
defer C.free(unsafe.Pointer(curl))
@@ -687,6 +707,13 @@
return nil
}
+func (o *Remote) Disconnect() {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ C.git_remote_disconnect(o.ptr)
+}
+
func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
var refs **C.git_remote_head
diff --git a/walk.go b/walk.go
index 60e618d..ab1de61 100644
--- a/walk.go
+++ b/walk.go
@@ -173,10 +173,6 @@
return nil
}
if err != nil {
- if err.(GitError).Code == ErrIterOver {
- err = nil
- }
-
return err
}
diff --git a/wrapper.c b/wrapper.c
index a0688c0..f4b4ecc 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -10,6 +10,12 @@
opts->remote_cb = (git_remote_create_cb)remoteCreateCallback;
}
+void _go_git_populate_checkout_cb(git_checkout_options *opts)
+{
+ opts->notify_cb = (git_checkout_notify_cb)checkoutNotifyCallback;
+ opts->progress_cb = (git_checkout_progress_cb)checkoutProgressCallback;
+}
+
int _go_git_visit_submodule(git_repository *repo, void *fct)
{
return git_submodule_foreach(repo, (gogit_submodule_cbk)&SubmoduleVisitor, fct);