Repository: libgit2/git2go (go)

Issue:
Support git_repository_set_config
It would be nice to support https://github.com/libgit2/libgit2/blob/v1.1.0/include/git2/sys/repository.h#L86 which is introduced in v0.16.0 . Thank you! 

Pull request:
Implement git_repository_set_config (#735)
Closes #732

(cherry picked from commit 2fd0495c43c4a54a02e2bbfca886687621f83f9f)

Patch:
diff --git a/git.go b/git.go
index cdcf6bb..d672d77 100644
--- a/git.go
+++ b/git.go
@@ -200,9 +200,9 @@ func NewOid(s string) (*Oid, error) {
 
 	o := new(Oid)
 
-	slice, error := hex.DecodeString(s)
-	if error != nil {
-		return nil, error
+	slice, err := hex.DecodeString(s)
+	if err != nil {
+		return nil, err
 	}
 
 	if len(slice) != 20 {
diff --git a/index.go b/index.go
index 4960a73..31f1a96 100644
--- a/index.go
+++ b/index.go
@@ -57,8 +57,8 @@ type Index struct {
 }
 
 type IndexTime struct {
-	seconds     int32
-	nanoseconds uint32
+	Seconds     int32
+	Nanoseconds uint32
 }
 
 type IndexEntry struct {
@@ -89,10 +89,10 @@ func newIndexEntryFromC(entry *C.git_index_entry) *IndexEntry {
 }
 
 func populateCIndexEntry(source *IndexEntry, dest *C.git_index_entry) {
-	dest.ctime.seconds = C.int32_t(source.Ctime.seconds)
-	dest.ctime.nanoseconds = C.uint32_t(source.Ctime.nanoseconds)
-	dest.mtime.seconds = C.int32_t(source.Mtime.seconds)
-	dest.mtime.nanoseconds = C.uint32_t(source.Mtime.nanoseconds)
+	dest.ctime.seconds = C.int32_t(source.Ctime.Seconds)
+	dest.ctime.nanoseconds = C.uint32_t(source.Ctime.Nanoseconds)
+	dest.mtime.seconds = C.int32_t(source.Mtime.Seconds)
+	dest.mtime.nanoseconds = C.uint32_t(source.Mtime.Nanoseconds)
 	dest.mode = C.uint32_t(source.Mode)
 	dest.uid = C.uint32_t(source.Uid)
 	dest.gid = C.uint32_t(source.Gid)
diff --git a/remote.go b/remote.go
index 122c74d..8fc430c 100644
--- a/remote.go
+++ b/remote.go
@@ -17,6 +17,23 @@ import (
 	"unsafe"
 )
 
+// RemoteCreateOptionsFlag is Remote creation options flags
+type RemoteCreateOptionsFlag uint
+
+const (
+	// Ignore the repository apply.insteadOf configuration
+	RemoteCreateSkipInsteadof RemoteCreateOptionsFlag = C.GIT_REMOTE_CREATE_SKIP_INSTEADOF
+	// Don't build a fetchspec from the name if none is set
+	RemoteCreateSkipDefaultFetchspec RemoteCreateOptionsFlag = C.GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC
+)
+
+// RemoteCreateOptions contains options for creating a remote
+type RemoteCreateOptions struct {
+	Name       string
+	FetchSpec  string
+	Flags      RemoteCreateOptionsFlag
+}
+
 type TransferProgress struct {
 	TotalObjects    uint
 	IndexedObjects  uint
@@ -537,6 +554,28 @@ func (c *RemoteCollection) Create(name string, url string) (*Remote, error) {
 	return remote, nil
 }
 
+//CreateWithOptions Creates a repository object with extended options.
+func (c *RemoteCollection) CreateWithOptions(url string, option *RemoteCreateOptions) (*Remote, error) {
+	remote := &Remote{repo: c.repo}
+
+	curl := C.CString(url)
+	defer C.free(unsafe.Pointer(curl))
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	copts := populateRemoteCreateOptions(&C.git_remote_create_options{}, option, c.repo)
+	defer freeRemoteCreateOptions(copts)
+	ret := C.git_remote_create_with_opts(&remote.ptr, curl, copts)
+	runtime.KeepAlive(c.repo)
+	if ret < 0 {
+		return nil, MakeGitError(ret)
+	}
+
+	runtime.SetFinalizer(remote, (*Remote).Free)
+	return remote, nil
+}
+
 func (c *RemoteCollection) Delete(name string) error {
 	cname := C.CString(name)
 	defer C.free(unsafe.Pointer(cname))
@@ -1025,3 +1064,45 @@ func (o *Remote) Prune(callbacks *RemoteCallbacks) error {
 	}
 	return nil
 }
+
+// DefaultApplyOptions returns default options for remote create
+func DefaultRemoteCreateOptions() (*RemoteCreateOptions, error) {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	opts := C.git_remote_create_options{}
+	ecode := C.git_remote_create_init_options(&opts, C.GIT_REMOTE_CREATE_OPTIONS_VERSION)
+	if ecode < 0 {
+		return nil, MakeGitError(ecode)
+	}
+
+	return &RemoteCreateOptions{
+		Flags: RemoteCreateOptionsFlag(opts.flags),
+	}, nil
+}
+
+func populateRemoteCreateOptions(copts *C.git_remote_create_options, opts *RemoteCreateOptions, repo *Repository) *C.git_remote_create_options {
+	C.git_remote_create_init_options(copts, C.GIT_REMOTE_CREATE_OPTIONS_VERSION)
+	if opts == nil {
+		return nil
+	}
+
+	var cRepository *C.git_repository
+	if repo != nil {
+		cRepository = repo.ptr
+	}
+	copts.repository = cRepository
+	copts.name = C.CString(opts.Name)
+	copts.fetchspec = C.CString(opts.FetchSpec)
+	copts.flags = C.uint(opts.Flags)
+
+	return copts
+}
+
+func freeRemoteCreateOptions(ptr *C.git_remote_create_options) {
+	if ptr == nil {
+		return
+	}
+	C.free(unsafe.Pointer(ptr.name))
+	C.free(unsafe.Pointer(ptr.fetchspec))
+}
diff --git a/repository.go b/repository.go
index bba5700..3113b3c 100644
--- a/repository.go
+++ b/repository.go
@@ -165,6 +165,17 @@ func (v *Repository) Config() (*Config, error) {
 	return config, nil
 }
 
+// SetConfig sets the configuration file for this repository.
+//
+// This configuration file will be used for all configuration queries involving
+// this repository.
+func (v *Repository) SetConfig(c *Config) error {
+	C.git_repository_set_config(v.ptr, c.ptr)
+	runtime.KeepAlive(v)
+	runtime.KeepAlive(c)
+	return nil
+}
+
 func (v *Repository) Index() (*Index, error) {
 	var ptr *C.git_index
 


Test patch:
diff --git a/odb_test.go b/odb_test.go
index cb3ab55..ed5c24c 100644
--- a/odb_test.go
+++ b/odb_test.go
@@ -61,31 +61,31 @@ func TestOdbStream(t *testing.T) {
 
 	_, _ = seedTestRepo(t, repo)
 
-	odb, error := repo.Odb()
-	checkFatal(t, error)
+	odb, err := repo.Odb()
+	checkFatal(t, err)
 
 	str := "hello, world!"
 
-	writeStream, error := odb.NewWriteStream(int64(len(str)), ObjectBlob)
-	checkFatal(t, error)
-	n, error := io.WriteString(writeStream, str)
-	checkFatal(t, error)
+	writeStream, err := odb.NewWriteStream(int64(len(str)), ObjectBlob)
+	checkFatal(t, err)
+	n, err := io.WriteString(writeStream, str)
+	checkFatal(t, err)
 	if n != len(str) {
 		t.Fatalf("Bad write length %v != %v", n, len(str))
 	}
 
-	error = writeStream.Close()
-	checkFatal(t, error)
+	err = writeStream.Close()
+	checkFatal(t, err)
 
-	expectedId, error := NewOid("30f51a3fba5274d53522d0f19748456974647b4f")
-	checkFatal(t, error)
+	expectedId, err := NewOid("30f51a3fba5274d53522d0f19748456974647b4f")
+	checkFatal(t, err)
 	if writeStream.Id.Cmp(expectedId) != 0 {
 		t.Fatal("Wrong data written")
 	}
 
-	readStream, error := odb.NewReadStream(&writeStream.Id)
-	checkFatal(t, error)
-	data, error := ioutil.ReadAll(readStream)
+	readStream, err := odb.NewReadStream(&writeStream.Id)
+	checkFatal(t, err)
+	data, err := ioutil.ReadAll(readStream)
 	if str != string(data) {
 		t.Fatalf("Wrong data read %v != %v", str, string(data))
 	}
@@ -98,8 +98,8 @@ func TestOdbHash(t *testing.T) {
 
 	_, _ = seedTestRepo(t, repo)
 
-	odb, error := repo.Odb()
-	checkFatal(t, error)
+	odb, err := repo.Odb()
+	checkFatal(t, err)
 
 	str := `tree 115fcae49287c82eb55bb275cbbd4556fbed72b7
 parent 66e1c476199ebcd3e304659992233132c5a52c6c
@@ -109,11 +109,11 @@ committer John Doe <john@doe.com> 1390682018 +0000
 Initial commit.`
 
 	for _, data := range [][]byte{[]byte(str), doublePointerBytes()} {
-		oid, error := odb.Hash(data, ObjectCommit)
-		checkFatal(t, error)
+		oid, err := odb.Hash(data, ObjectCommit)
+		checkFatal(t, err)
 
-		coid, error := odb.Write(data, ObjectCommit)
-		checkFatal(t, error)
+		coid, err := odb.Write(data, ObjectCommit)
+		checkFatal(t, err)
 
 		if oid.Cmp(coid) != 0 {
 			t.Fatal("Hash and write Oids are different")
diff --git a/remote_test.go b/remote_test.go
index ccd436a..259957e 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -80,6 +80,28 @@ func TestRemoteConnect(t *testing.T) {
 	checkFatal(t, err)
 }
 
+func TestRemoteConnectOption(t *testing.T) {
+	t.Parallel()
+	repo := createTestRepo(t)
+	defer cleanupTestRepo(t, repo)
+
+	config, err := repo.Config()
+	checkFatal(t, err)
+	err = config.SetString("url.git@github.com:.insteadof", "https://github.com/")
+	checkFatal(t, err)
+
+	option, err := DefaultRemoteCreateOptions()
+	checkFatal(t, err)
+	option.Name = "origin"
+	option.Flags = RemoteCreateSkipInsteadof
+
+	remote, err := repo.Remotes.CreateWithOptions("https://github.com/libgit2/TestGitRepository", option)
+	checkFatal(t, err)
+
+	err = remote.ConnectFetch(nil, nil, nil)
+	checkFatal(t, err)
+}
+
 func TestRemoteLs(t *testing.T) {
 	t.Parallel()
 	repo := createTestRepo(t)
diff --git a/repository_test.go b/repository_test.go
index 1950c69..5a0f920 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -40,3 +40,55 @@ func TestCreateCommitFromIds(t *testing.T) {
 		t.Errorf("mismatched commit ids, expected %v, got %v", expectedCommitId.String(), commitId.String())
 	}
 }
+
+func TestRepositorySetConfig(t *testing.T) {
+	repo := createTestRepo(t)
+	defer cleanupTestRepo(t, repo)
+
+	loc, err := time.LoadLocation("Europe/Berlin")
+	checkFatal(t, err)
+	sig := &Signature{
+		Name:  "Rand Om Hacker",
+		Email: "random@hacker.com",
+		When:  time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
+	}
+
+	idx, err := repo.Index()
+	checkFatal(t, err)
+	err = idx.AddByPath("README")
+
+	treeId, err := idx.WriteTree()
+	checkFatal(t, err)
+
+	message := "This is a commit\n"
+	tree, err := repo.LookupTree(treeId)
+	checkFatal(t, err)
+	_, err = repo.CreateCommit("HEAD", sig, sig, message, tree)
+	checkFatal(t, err)
+
+	repoConfig, err := repo.Config()
+	checkFatal(t, err)
+
+	temp := Config{}
+	localConfig, err := temp.OpenLevel(repoConfig, ConfigLevelLocal)
+	checkFatal(t, err)
+	repoConfig = nil
+
+	err = repo.SetConfig(localConfig)
+	checkFatal(t, err)
+
+	configFieldName := "core.filemode"
+	err = localConfig.SetBool(configFieldName, true)
+	checkFatal(t, err)
+
+	localConfig = nil
+
+	repoConfig, err = repo.Config()
+	checkFatal(t, err)
+
+	result, err := repoConfig.LookupBool(configFieldName)
+	checkFatal(t, err)
+	if result != true {
+		t.Fatal("result must be true")
+	}
+}