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);