Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZeger-Jan van de Weg <git@zjvandeweg.nl>2019-05-16 15:03:51 +0300
committerZeger-Jan van de Weg <git@zjvandeweg.nl>2019-05-16 15:03:51 +0300
commitf8d86b0723d17120ebd42f04de33c854e5448ca7 (patch)
tree583a440d0334246b200f0a94362e41c6bc7dda20
parenta77c63fb43395205f36967795ada02468db299bc (diff)
parent9cc35a3991729ebf83a691faf4ee6be30e34fff7 (diff)
Merge branch 'remote-add-go' into 'master'
Add git2go dependency See merge request gitlab-org/gitaly!1061
-rw-r--r--.gitignore3
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--Makefile10
-rw-r--r--NOTICE23
-rw-r--r--_support/makegen.go54
-rw-r--r--changelogs/unreleased/remote-add-go.yml5
-rw-r--r--cmd/gitaly-remote/add_test.go58
-rw-r--r--cmd/gitaly-remote/main.go68
-rw-r--r--vendor/github.com/libgit2/git2go/LICENSE21
-rw-r--r--vendor/github.com/libgit2/git2go/Makefile18
-rw-r--r--vendor/github.com/libgit2/git2go/README.md69
-rw-r--r--vendor/github.com/libgit2/git2go/blame.go163
-rw-r--r--vendor/github.com/libgit2/git2go/blob.go170
-rw-r--r--vendor/github.com/libgit2/git2go/branch.go262
-rw-r--r--vendor/github.com/libgit2/git2go/checkout.go237
-rw-r--r--vendor/github.com/libgit2/git2go/cherrypick.go75
-rw-r--r--vendor/github.com/libgit2/git2go/clone.go109
-rw-r--r--vendor/github.com/libgit2/git2go/commit.go163
-rw-r--r--vendor/github.com/libgit2/git2go/config.go452
-rw-r--r--vendor/github.com/libgit2/git2go/credentials.go91
-rw-r--r--vendor/github.com/libgit2/git2go/describe.go225
-rw-r--r--vendor/github.com/libgit2/git2go/diff.go810
-rw-r--r--vendor/github.com/libgit2/git2go/features.go30
-rw-r--r--vendor/github.com/libgit2/git2go/git.go323
-rw-r--r--vendor/github.com/libgit2/git2go/git_dynamic.go14
-rw-r--r--vendor/github.com/libgit2/git2go/git_static.go17
-rw-r--r--vendor/github.com/libgit2/git2go/graph.go42
-rw-r--r--vendor/github.com/libgit2/git2go/handles.go57
-rw-r--r--vendor/github.com/libgit2/git2go/ignore.go54
-rw-r--r--vendor/github.com/libgit2/git2go/index.go586
-rw-r--r--vendor/github.com/libgit2/git2go/merge.go441
-rw-r--r--vendor/github.com/libgit2/git2go/note.go244
-rw-r--r--vendor/github.com/libgit2/git2go/object.go237
-rw-r--r--vendor/github.com/libgit2/git2go/odb.go348
-rw-r--r--vendor/github.com/libgit2/git2go/packbuilder.go170
-rw-r--r--vendor/github.com/libgit2/git2go/patch.go93
-rw-r--r--vendor/github.com/libgit2/git2go/rebase.go274
-rw-r--r--vendor/github.com/libgit2/git2go/refdb.go62
-rw-r--r--vendor/github.com/libgit2/git2go/reference.go488
-rw-r--r--vendor/github.com/libgit2/git2go/remote.go872
-rw-r--r--vendor/github.com/libgit2/git2go/repository.go543
-rw-r--r--vendor/github.com/libgit2/git2go/reset.go42
-rw-r--r--vendor/github.com/libgit2/git2go/revparse.go113
-rw-r--r--vendor/github.com/libgit2/git2go/settings.go102
-rw-r--r--vendor/github.com/libgit2/git2go/signature.go74
-rw-r--r--vendor/github.com/libgit2/git2go/stash.go342
-rw-r--r--vendor/github.com/libgit2/git2go/status.go189
-rw-r--r--vendor/github.com/libgit2/git2go/submodule.go373
-rw-r--r--vendor/github.com/libgit2/git2go/tag.go245
-rw-r--r--vendor/github.com/libgit2/git2go/tree.go212
-rw-r--r--vendor/github.com/libgit2/git2go/walk.go219
-rw-r--r--vendor/github.com/libgit2/git2go/wrapper.c183
-rw-r--r--vendor/vendor.json8
53 files changed, 10081 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index 24aefa7e6..4482aa3de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@ cmd/gitaly-ssh/gitaly-ssh
/gitaly-ssh
cmd/gitaly-wrapper/gitaly-wrapper
/gitaly-wrapper
+cmd/gitaly-remote/gitaly-remote
+/gitaly-remote
**/testdata/gitaly-libexec/
/*.deb
/_support/package/bin
@@ -20,3 +22,4 @@ git-env
/gitaly-debug
/praefect
gitaly.pid
+/vendor/github.com/libgit2/git2go/vendor
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index abf081dca..14e2ad34f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -32,6 +32,7 @@ danger-review:
stage: build
script:
- make
+ - make build-gitaly-remote
- _support/test-boot-time .
.assemble_template: &assemble_definition
@@ -71,6 +72,7 @@ danger-review:
- go version
- git version
- make test
+ - make test-gitaly-remote
verify:
<<: *ruby_definition
diff --git a/Makefile b/Makefile
index d0f9649e5..8aa7ac0fd 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,15 @@ all: build
.PHONY: build
build: prepare-build
- cd $(BUILD_DIR) && $(MAKE) install INSTALL_DEST_DIR=$(CURDIR)
+ cd $(BUILD_DIR) && $(MAKE) install INSTALL_DEST_DIR=$(CURDIR)
+
+.PHONY: build-gitaly-remote
+build-gitaly-remote: prepare-build
+ cd $(BUILD_DIR) && $(MAKE) $@
+
+.PHONY: test-gitaly-remote
+test-gitaly-remote: prepare-build
+ cd $(BUILD_DIR) && $(MAKE) $@
.PHONY: install
install: prepare-build
diff --git a/NOTICE b/NOTICE
index bb2f54e72..9920d3dca 100644
--- a/NOTICE
+++ b/NOTICE
@@ -961,6 +961,29 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LICENSE - gitlab.com/gitlab-org/gitaly/vendor/github.com/libgit2/git2go
+The MIT License
+
+Copyright (c) 2013 The git2go contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LICENSE - gitlab.com/gitlab-org/gitaly/vendor/github.com/lightstep/lightstep-tracer-go
The MIT License (MIT)
diff --git a/_support/makegen.go b/_support/makegen.go
index 146197857..d0bef95dc 100644
--- a/_support/makegen.go
+++ b/_support/makegen.go
@@ -82,6 +82,18 @@ func (gm *gitalyMake) GitlabShellDir() string {
return filepath.Join(gm.SourceDir(), gm.GitlabShellRelDir())
}
+func (gm *gitalyMake) Git2GoVendorDir() string {
+ return filepath.Join(gm.BuildDir(), "../vendor/github.com/libgit2/git2go/vendor")
+}
+
+func (gm *gitalyMake) LibGit2Version() string {
+ return filepath.Join("0.27.8")
+}
+
+func (gm *gitalyMake) LibGit2SHA() string {
+ return filepath.Join("8313873d49dc01e8b880ec334d7430ae67496a89aaa8c6e7bbd3affb47a00c76")
+}
+
// SourceDir is the location of gitaly's files, inside the _build GOPATH.
func (gm *gitalyMake) SourceDir() string { return filepath.Join(gm.BuildDir(), "src", gm.Pkg()) }
@@ -102,6 +114,10 @@ func (gm *gitalyMake) GitTestRepo() string {
return filepath.Join(gm.TestRepoStoragePath(), "gitlab-git-test.git")
}
+func (gm *gitalyMake) GitalyRemotePackage() string {
+ return filepath.Join(gm.Pkg(), "cmd", "gitaly-remote")
+}
+
func (gm *gitalyMake) CommandPackages() []string {
if len(gm.commandPackages) > 0 {
return gm.commandPackages
@@ -113,6 +129,10 @@ func (gm *gitalyMake) CommandPackages() []string {
}
for _, dir := range entries {
+ //Do not build gitaly-remote by default
+ if dir.Name() == "gitaly-remote" {
+ continue
+ }
if !dir.IsDir() {
continue
}
@@ -234,6 +254,10 @@ func (gm *gitalyMake) AllPackages() []string {
var pkgs []string
for k := range pkgMap {
+ //Do not build gitaly-remote by default
+ if k == "gitlab.com/gitlab-org/gitaly/cmd/gitaly-remote" {
+ continue
+ }
pkgs = append(pkgs, k)
}
@@ -265,6 +289,30 @@ unexport GOBIN
.PHONY: all
all: build
+{{ .Git2GoVendorDir }}/.ok:
+ rm -rf {{ .Git2GoVendorDir }}
+ mkdir -p {{ .Git2GoVendorDir }}
+
+ cd {{ .Git2GoVendorDir }} && curl -L -o libgit2.tar.gz https://github.com/libgit2/libgit2/archive/v{{ .LibGit2Version }}.tar.gz
+ cd {{ .Git2GoVendorDir }} && echo '{{ .LibGit2SHA }} libgit2.tar.gz' | shasum -a256 -c -
+ cd {{ .Git2GoVendorDir }} && tar -xvf libgit2.tar.gz
+ cd {{ .Git2GoVendorDir }} && mv libgit2-{{ .LibGit2Version }} libgit2
+
+ mkdir -p {{ .Git2GoVendorDir }}/libgit2/build
+ mkdir -p {{ .Git2GoVendorDir }}/libgit2/install/lib
+ cd {{ .Git2GoVendorDir }}/libgit2/build && cmake -DTHREADSAFE=ON -DBUILD_CLAR=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_C_FLAGS=-fPIC -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DCMAKE_INSTALL_PREFIX=../install ..
+ cd {{ .Git2GoVendorDir }}/libgit2/build && cmake --build .
+
+ touch $@
+
+.PHONY: build-gitaly-remote
+build-gitaly-remote: {{ .Git2GoVendorDir }}/.ok
+ cd {{ .SourceDir }} && go install {{ .GoLdFlags }} -tags "$(BUILD_TAGS) static" {{ .GitalyRemotePackage }}
+
+.PHONY: test-gitaly-remote
+test-gitaly-remote: prepare-tests {{ .Git2GoVendorDir }}/.ok
+ @go test -tags "$(BUILD_TAGS) static" -count=1 {{ .GitalyRemotePackage }}
+
.PHONY: build
build: ../.ruby-bundle
# go install
@@ -337,7 +385,7 @@ prepare-tests: {{ .TestRepo }} {{ .GitTestRepo }} ../.ruby-bundle
.PHONY: test
test: test-go rspec rspec-gitlab-shell
-.PHONY: test-go
+.PHONY: test-go
test-go: prepare-tests
@go test -tags "$(BUILD_TAGS)" -count=1 {{ join .AllPackages " " }} # count=1 bypasses go 1.10 test caching
@@ -389,7 +437,7 @@ format: {{ .GoImports }}
.PHONY: staticcheck
staticcheck: {{ .StaticCheck }}
# staticcheck
- @cd {{ .SourceDir }} && {{ .StaticCheck }} {{ join .AllPackages " " }}
+ @cd {{ .SourceDir }} && {{ .StaticCheck }} -tags "$(BUILD_TAGS) static" {{ join .AllPackages " " }}
# Install staticcheck
{{ .StaticCheck }}:
@@ -451,7 +499,7 @@ docker:
{{ $pkg := .Pkg }}
{{ $goLdFlags := .GoLdFlags }}
{{ range $cmd := .Commands }}
- GOOS=linux GOARCH=amd64 go build {{ $goLdFlags }} -o "docker/bin/{{ $cmd }}" {{ $pkg }}/cmd/{{ $cmd }}
+ GOOS=linux GOARCH=amd64 go build -tags "$(BUILD_TAGS)" {{ $goLdFlags }} -o "docker/bin/{{ $cmd }}" {{ $pkg }}/cmd/{{ $cmd }}
{{ end }}
cp {{ .SourceDir }}/Dockerfile docker/
docker build -t gitlab/gitaly:{{ .VersionPrefixed }} -t gitlab/gitaly:latest docker/
diff --git a/changelogs/unreleased/remote-add-go.yml b/changelogs/unreleased/remote-add-go.yml
new file mode 100644
index 000000000..e9b46d0af
--- /dev/null
+++ b/changelogs/unreleased/remote-add-go.yml
@@ -0,0 +1,5 @@
+---
+title: Add git2go dependency
+merge_request: 1061
+author: maxmati
+type: other
diff --git a/cmd/gitaly-remote/add_test.go b/cmd/gitaly-remote/add_test.go
new file mode 100644
index 000000000..1faf45721
--- /dev/null
+++ b/cmd/gitaly-remote/add_test.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+ "os"
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/internal/helper"
+ "gitlab.com/gitlab-org/gitaly/internal/testhelper"
+)
+
+func buildGitRemote() {
+ // Build the test-binary that we need
+ os.Remove("gitaly-remote")
+ testhelper.MustRunCommand(nil, nil, "go", "build", "-tags", "static gitaly_remote", "gitlab.com/gitlab-org/gitaly/cmd/gitaly-remote")
+}
+
+func TestAddRemote(t *testing.T) {
+ buildGitRemote()
+
+ testCases := []struct {
+ name string
+ remote string
+ url string
+ }{
+ {
+ name: "update-existing",
+ remote: "remote",
+ url: "https://test.server.com/test.git",
+ },
+ {
+ name: "update-existing",
+ remote: "remote",
+ url: "https://test.server.com/test.git",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ testRepo, _, cleanupFn := testhelper.NewTestRepo(t)
+ defer cleanupFn()
+
+ repoPath, err := helper.GetRepoPath(testRepo)
+ require.NoError(t, err)
+
+ cmd := exec.Command("./gitaly-remote", repoPath, tc.remote)
+ cmd.Stdin = strings.NewReader(tc.url)
+ err = cmd.Run()
+ require.NoError(t, err)
+
+ out := testhelper.MustRunCommand(t, nil, "git", "-C", repoPath, "remote", "get-url", tc.remote)
+ require.Equal(t, tc.url, strings.TrimSpace(string(out)))
+ })
+ }
+
+}
diff --git a/cmd/gitaly-remote/main.go b/cmd/gitaly-remote/main.go
new file mode 100644
index 000000000..af55e2c29
--- /dev/null
+++ b/cmd/gitaly-remote/main.go
@@ -0,0 +1,68 @@
+package main
+
+import (
+ "io/ioutil"
+ "log"
+ "os"
+
+ git "github.com/libgit2/git2go"
+)
+
+// echo "https://remote.url.com" | gitaly-remote /path/to/repository remote-name
+func main() {
+ if n := len(os.Args); n != 3 {
+ log.Fatalf("invalid number of arguments, expected 2, got %d", n-1)
+ }
+
+ repoPath := os.Args[1]
+ remoteName := os.Args[2]
+
+ remoteURLBytes, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ log.Fatalf("error while reading remote URL: %v", err)
+ }
+ remoteURL := string(remoteURLBytes)
+
+ err = addOrUpdate(repoPath, remoteName, remoteURL)
+ if err != nil {
+ log.Fatalf("error while setting remote: %v", err)
+ }
+
+}
+
+//addOrUpdate adds, or updates if exits, the remote to repository
+func addOrUpdate(repoPath string, name, url string) error {
+ if err := add(repoPath, name, url); err != nil {
+ return update(repoPath, name, url)
+ }
+
+ return nil
+}
+
+func add(repoPath string, name, url string) error {
+ git2repo, err := openGit2GoRepo(repoPath)
+ if err != nil {
+ return err
+ }
+
+ _, err = git2repo.Remotes.Create(name, url)
+ return err
+}
+
+func update(repoPath string, name, url string) error {
+ git2repo, err := openGit2GoRepo(repoPath)
+ if err != nil {
+ return err
+ }
+
+ return git2repo.Remotes.SetUrl(name, url)
+}
+
+func openGit2GoRepo(repoPath string) (*git.Repository, error) {
+ git2repo, err := git.OpenRepository(repoPath)
+ if err != nil {
+ return nil, err
+ }
+
+ return git2repo, nil
+}
diff --git a/vendor/github.com/libgit2/git2go/LICENSE b/vendor/github.com/libgit2/git2go/LICENSE
new file mode 100644
index 000000000..46a7407e7
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2013 The git2go contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/libgit2/git2go/Makefile b/vendor/github.com/libgit2/git2go/Makefile
new file mode 100644
index 000000000..cf00ceff1
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/Makefile
@@ -0,0 +1,18 @@
+default: test
+
+test: build-libgit2
+ go run script/check-MakeGitError-thread-lock.go
+ go test ./...
+
+install: build-libgit2
+ go install ./...
+
+build-libgit2:
+ ./script/build-libgit2-static.sh
+
+install-static: build-libgit2
+ go install --tags "static" ./...
+
+test-static: build-libgit2
+ go run script/check-MakeGitError-thread-lock.go
+ go test --tags "static" ./...
diff --git a/vendor/github.com/libgit2/git2go/README.md b/vendor/github.com/libgit2/git2go/README.md
new file mode 100644
index 000000000..4bd2e7ec5
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/README.md
@@ -0,0 +1,69 @@
+git2go
+======
+[![GoDoc](https://godoc.org/github.com/libgit2/git2go?status.svg)](http://godoc.org/github.com/libgit2/git2go) [![Build Status](https://travis-ci.org/libgit2/git2go.svg?branch=master)](https://travis-ci.org/libgit2/git2go)
+
+Go bindings for [libgit2](http://libgit2.github.com/).
+
+### Which branch to use
+
+The numbered branches work against the version of libgit2 as specified by their number. You can import them in your project via gopkg.in, e.g. if you have libgit2 v0.25 installed you'd import with
+
+ import "gopkg.in/libgit2/git2go.v25"
+
+which will ensure there are no sudden changes to the API.
+
+The `master` branch follows the tip of libgit2 itself (with some lag) and as such has no guarantees on its own API nor does it have expectations the stability of libgit2's. Thus this only supports statically linking against libgit2.
+
+Installing
+----------
+
+This project wraps the functionality provided by libgit2. It thus needs it in order to perform the work.
+
+This project wraps the functionality provided by libgit2. If you're using a versioned branch, install it to your system via your system's package manager and then install git2go.
+
+
+### Versioned branch, dynamic linking
+
+When linking dynamically against a released version of libgit2, install it via your system's package manager. CGo will take care of finding its pkg-config file and set up the linking. Import via gopkg.in, e.g. to work against libgit2 v0.25
+
+ import "gopkg.in/libgit2/git2go.v25"
+
+### Master branch, or static linking
+
+If using `master` or building a branch statically, we need to build libgit2 first. In order to build it, you need `cmake`, `pkg-config` and a C compiler. You will also need the development packages for OpenSSL (outside of Windows or macOS) and LibSSH2 installed if you want libgit2 to support HTTPS and SSH respectively. Note that even if libgit2 is included in the resulting binary, its dependencies will not be.
+
+Run `go get -d github.com/libgit2/git2go` to download the code and go to your `$GOPATH/src/github.com/libgit2/git2go` directory. From there, we need to build the C code and put it into the resulting go binary.
+
+ git submodule update --init # get libgit2
+ make install-static
+
+will compile libgit2, link it into git2go and install it. The `master` branch is set up to follow the specific libgit2 version that is vendored, so trying dynamic linking may or may not work depending on the exact versions involved.
+
+Parallelism and network operations
+----------------------------------
+
+libgit2 may use OpenSSL and LibSSH2 for performing encrypted network connections. For now, git2go asks libgit2 to set locking for OpenSSL. This makes HTTPS connections thread-safe, but it is fragile and will likely stop doing it soon. This may also make SSH connections thread-safe if your copy of libssh2 is linked against OpenSSL. Check libgit2's `THREADSAFE.md` for more information.
+
+Running the tests
+-----------------
+
+For the stable version, `go test` will work as usual. For the `master` branch, similarly to installing, running the tests requires building a local libgit2 library, so the Makefile provides a wrapper that makes sure it's built
+
+ make test-static
+
+Alternatively, you can build the library manually first and then run the tests
+
+ ./script/build-libgit2-static.sh
+ go test -v --tags "static" ./...
+
+License
+-------
+
+M to the I to the T. See the LICENSE file if you've never seen an MIT license before.
+
+Authors
+-------
+
+- Carlos Martín (@carlosmn)
+- Vicent Martí (@vmg)
+
diff --git a/vendor/github.com/libgit2/git2go/blame.go b/vendor/github.com/libgit2/git2go/blame.go
new file mode 100644
index 000000000..de32bb32a
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/blame.go
@@ -0,0 +1,163 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type BlameOptions struct {
+ Flags BlameOptionsFlag
+ MinMatchCharacters uint16
+ NewestCommit *Oid
+ OldestCommit *Oid
+ MinLine uint32
+ MaxLine uint32
+}
+
+func DefaultBlameOptions() (BlameOptions, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ opts := C.git_blame_options{}
+ ecode := C.git_blame_init_options(&opts, C.GIT_BLAME_OPTIONS_VERSION)
+ if ecode < 0 {
+ return BlameOptions{}, MakeGitError(ecode)
+ }
+
+ return BlameOptions{
+ Flags: BlameOptionsFlag(opts.flags),
+ MinMatchCharacters: uint16(opts.min_match_characters),
+ NewestCommit: newOidFromC(&opts.newest_commit),
+ OldestCommit: newOidFromC(&opts.oldest_commit),
+ MinLine: uint32(opts.min_line),
+ MaxLine: uint32(opts.max_line),
+ }, nil
+}
+
+type BlameOptionsFlag uint32
+
+const (
+ BlameNormal BlameOptionsFlag = C.GIT_BLAME_NORMAL
+ BlameTrackCopiesSameFile BlameOptionsFlag = C.GIT_BLAME_TRACK_COPIES_SAME_FILE
+ BlameTrackCopiesSameCommitMoves BlameOptionsFlag = C.GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES
+ BlameTrackCopiesSameCommitCopies BlameOptionsFlag = C.GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES
+ BlameTrackCopiesAnyCommitCopies BlameOptionsFlag = C.GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES
+ BlameFirstParent BlameOptionsFlag = C.GIT_BLAME_FIRST_PARENT
+)
+
+func (v *Repository) BlameFile(path string, opts *BlameOptions) (*Blame, error) {
+ var blamePtr *C.git_blame
+
+ var copts *C.git_blame_options
+ if opts != nil {
+ copts = &C.git_blame_options{
+ version: C.GIT_BLAME_OPTIONS_VERSION,
+ flags: C.uint32_t(opts.Flags),
+ min_match_characters: C.uint16_t(opts.MinMatchCharacters),
+ min_line: C.size_t(opts.MinLine),
+ max_line: C.size_t(opts.MaxLine),
+ }
+ if opts.NewestCommit != nil {
+ copts.newest_commit = *opts.NewestCommit.toC()
+ }
+ if opts.OldestCommit != nil {
+ copts.oldest_commit = *opts.OldestCommit.toC()
+ }
+ }
+
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_blame_file(&blamePtr, v.ptr, cpath, copts)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newBlameFromC(blamePtr), nil
+}
+
+type Blame struct {
+ ptr *C.git_blame
+}
+
+func (blame *Blame) HunkCount() int {
+ ret := int(C.git_blame_get_hunk_count(blame.ptr))
+ runtime.KeepAlive(blame)
+
+ return ret
+}
+
+func (blame *Blame) HunkByIndex(index int) (BlameHunk, error) {
+ ptr := C.git_blame_get_hunk_byindex(blame.ptr, C.uint32_t(index))
+ runtime.KeepAlive(blame)
+ if ptr == nil {
+ return BlameHunk{}, ErrInvalid
+ }
+ return blameHunkFromC(ptr), nil
+}
+
+func (blame *Blame) HunkByLine(lineno int) (BlameHunk, error) {
+ ptr := C.git_blame_get_hunk_byline(blame.ptr, C.size_t(lineno))
+ runtime.KeepAlive(blame)
+ if ptr == nil {
+ return BlameHunk{}, ErrInvalid
+ }
+ return blameHunkFromC(ptr), nil
+}
+
+func newBlameFromC(ptr *C.git_blame) *Blame {
+ if ptr == nil {
+ return nil
+ }
+
+ blame := &Blame{
+ ptr: ptr,
+ }
+
+ runtime.SetFinalizer(blame, (*Blame).Free)
+ return blame
+}
+
+func (blame *Blame) Free() error {
+ if blame.ptr == nil {
+ return ErrInvalid
+ }
+ runtime.SetFinalizer(blame, nil)
+ C.git_blame_free(blame.ptr)
+ blame.ptr = nil
+ return nil
+}
+
+type BlameHunk struct {
+ LinesInHunk uint16
+ FinalCommitId *Oid
+ FinalStartLineNumber uint16
+ FinalSignature *Signature
+ OrigCommitId *Oid
+ OrigPath string
+ OrigStartLineNumber uint16
+ OrigSignature *Signature
+ Boundary bool
+}
+
+func blameHunkFromC(hunk *C.git_blame_hunk) BlameHunk {
+ return BlameHunk{
+ LinesInHunk: uint16(hunk.lines_in_hunk),
+ FinalCommitId: newOidFromC(&hunk.final_commit_id),
+ FinalStartLineNumber: uint16(hunk.final_start_line_number),
+ FinalSignature: newSignatureFromC(hunk.final_signature),
+ OrigCommitId: newOidFromC(&hunk.orig_commit_id),
+ OrigPath: C.GoString(hunk.orig_path),
+ OrigStartLineNumber: uint16(hunk.orig_start_line_number),
+ OrigSignature: newSignatureFromC(hunk.orig_signature),
+ Boundary: hunk.boundary == 1,
+ }
+}
diff --git a/vendor/github.com/libgit2/git2go/blob.go b/vendor/github.com/libgit2/git2go/blob.go
new file mode 100644
index 000000000..d895449c2
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/blob.go
@@ -0,0 +1,170 @@
+package git
+
+/*
+#include <git2.h>
+#include <string.h>
+
+int _go_git_writestream_write(git_writestream *stream, const char *buffer, size_t len);
+void _go_git_writestream_free(git_writestream *stream);
+*/
+import "C"
+import (
+ "io"
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+type Blob struct {
+ Object
+ cast_ptr *C.git_blob
+}
+
+func (b *Blob) AsObject() *Object {
+ return &b.Object
+}
+
+func (v *Blob) Size() int64 {
+ ret := int64(C.git_blob_rawsize(v.cast_ptr))
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Blob) Contents() []byte {
+ size := C.int(C.git_blob_rawsize(v.cast_ptr))
+ buffer := unsafe.Pointer(C.git_blob_rawcontent(v.cast_ptr))
+
+ goBytes := C.GoBytes(buffer, size)
+ runtime.KeepAlive(v)
+
+ return goBytes
+}
+
+func (repo *Repository) CreateBlobFromBuffer(data []byte) (*Oid, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var id C.git_oid
+ var size C.size_t
+
+ // Go 1.6 added some increased checking of passing pointer to
+ // C, but its check depends on its expectations of what we
+ // pass to the C function, so unless we take the address of
+ // its contents at the call site itself, it can fail when
+ // 'data' is a slice of a slice.
+ //
+ // When we're given an empty slice, create a dummy one where 0
+ // isn't out of bounds.
+ if len(data) > 0 {
+ size = C.size_t(len(data))
+ } else {
+ data = []byte{0}
+ size = C.size_t(0)
+ }
+
+ ecode := C.git_blob_create_frombuffer(&id, repo.ptr, unsafe.Pointer(&data[0]), size)
+ runtime.KeepAlive(repo)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ return newOidFromC(&id), nil
+}
+
+type BlobChunkCallback func(maxLen int) ([]byte, error)
+
+type BlobCallbackData struct {
+ Callback BlobChunkCallback
+ Error error
+}
+
+//export blobChunkCb
+func blobChunkCb(buffer *C.char, maxLen C.size_t, handle unsafe.Pointer) int {
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*BlobCallbackData)
+ if !ok {
+ panic("could not retrieve blob callback data")
+ }
+
+ goBuf, err := data.Callback(int(maxLen))
+ if err == io.EOF {
+ return 0
+ } else if err != nil {
+ data.Error = err
+ return -1
+ }
+ C.memcpy(unsafe.Pointer(buffer), unsafe.Pointer(&goBuf[0]), C.size_t(len(goBuf)))
+ return len(goBuf)
+}
+
+func (repo *Repository) CreateFromStream(hintPath string) (*BlobWriteStream, error) {
+ var chintPath *C.char = nil
+ var stream *C.git_writestream
+
+ if len(hintPath) > 0 {
+ chintPath = C.CString(hintPath)
+ defer C.free(unsafe.Pointer(chintPath))
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_blob_create_fromstream(&stream, repo.ptr, chintPath)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newBlobWriteStreamFromC(stream, repo), nil
+}
+
+type BlobWriteStream struct {
+ ptr *C.git_writestream
+ repo *Repository
+}
+
+func newBlobWriteStreamFromC(ptr *C.git_writestream, repo *Repository) *BlobWriteStream {
+ stream := &BlobWriteStream{
+ ptr: ptr,
+ repo: repo,
+ }
+
+ runtime.SetFinalizer(stream, (*BlobWriteStream).Free)
+ return stream
+}
+
+// Implement io.Writer
+func (stream *BlobWriteStream) Write(p []byte) (int, error) {
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&p))
+ ptr := (*C.char)(unsafe.Pointer(header.Data))
+ size := C.size_t(header.Len)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C._go_git_writestream_write(stream.ptr, ptr, size)
+ runtime.KeepAlive(stream)
+ if ecode < 0 {
+ return 0, MakeGitError(ecode)
+ }
+
+ return len(p), nil
+}
+
+func (stream *BlobWriteStream) Free() {
+ runtime.SetFinalizer(stream, nil)
+ C._go_git_writestream_free(stream.ptr)
+}
+
+func (stream *BlobWriteStream) Commit() (*Oid, error) {
+ oid := C.git_oid{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_blob_create_fromstream_commit(&oid, stream.ptr)
+ runtime.KeepAlive(stream)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newOidFromC(&oid), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/branch.go b/vendor/github.com/libgit2/git2go/branch.go
new file mode 100644
index 000000000..d6e7a5323
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/branch.go
@@ -0,0 +1,262 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+type BranchType uint
+
+const (
+ BranchAll BranchType = C.GIT_BRANCH_ALL
+ BranchLocal BranchType = C.GIT_BRANCH_LOCAL
+ BranchRemote BranchType = C.GIT_BRANCH_REMOTE
+)
+
+type Branch struct {
+ *Reference
+}
+
+func (r *Reference) Branch() *Branch {
+ return &Branch{Reference: r}
+}
+
+type BranchIterator struct {
+ ptr *C.git_branch_iterator
+ repo *Repository
+}
+
+type BranchIteratorFunc func(*Branch, BranchType) error
+
+func newBranchIteratorFromC(repo *Repository, ptr *C.git_branch_iterator) *BranchIterator {
+ i := &BranchIterator{repo: repo, ptr: ptr}
+ runtime.SetFinalizer(i, (*BranchIterator).Free)
+ return i
+}
+
+func (i *BranchIterator) Next() (*Branch, BranchType, error) {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var refPtr *C.git_reference
+ var refType C.git_branch_t
+
+ ecode := C.git_branch_next(&refPtr, &refType, i.ptr)
+
+ if ecode < 0 {
+ return nil, BranchLocal, MakeGitError(ecode)
+ }
+
+ branch := newReferenceFromC(refPtr, i.repo).Branch()
+
+ return branch, BranchType(refType), nil
+}
+
+func (i *BranchIterator) Free() {
+ runtime.SetFinalizer(i, nil)
+ C.git_branch_iterator_free(i.ptr)
+}
+
+func (i *BranchIterator) ForEach(f BranchIteratorFunc) error {
+ b, t, err := i.Next()
+
+ for err == nil {
+ err = f(b, t)
+ if err == nil {
+ b, t, err = i.Next()
+ }
+ }
+
+ if err != nil && IsErrorCode(err, ErrIterOver) {
+ return nil
+ }
+
+ return err
+}
+
+func (repo *Repository) NewBranchIterator(flags BranchType) (*BranchIterator, error) {
+ refType := C.git_branch_t(flags)
+ var ptr *C.git_branch_iterator
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_branch_iterator_new(&ptr, repo.ptr, refType)
+ runtime.KeepAlive(repo)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newBranchIteratorFromC(repo, ptr), nil
+}
+
+func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool) (*Branch, error) {
+
+ var ptr *C.git_reference
+ cBranchName := C.CString(branchName)
+ defer C.free(unsafe.Pointer(cBranchName))
+ cForce := cbool(force)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_create(&ptr, repo.ptr, cBranchName, target.cast_ptr, cForce)
+ runtime.KeepAlive(repo)
+ runtime.KeepAlive(target)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newReferenceFromC(ptr, repo).Branch(), nil
+}
+
+func (b *Branch) Delete() error {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ ret := C.git_branch_delete(b.Reference.ptr)
+ runtime.KeepAlive(b.Reference)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (b *Branch) Move(newBranchName string, force bool) (*Branch, error) {
+ var ptr *C.git_reference
+ cNewBranchName := C.CString(newBranchName)
+ defer C.free(unsafe.Pointer(cNewBranchName))
+ cForce := cbool(force)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_move(&ptr, b.Reference.ptr, cNewBranchName, cForce)
+ runtime.KeepAlive(b.Reference)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newReferenceFromC(ptr, b.repo).Branch(), nil
+}
+
+func (b *Branch) IsHead() (bool, error) {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_is_head(b.Reference.ptr)
+ runtime.KeepAlive(b.Reference)
+ switch ret {
+ case 1:
+ return true, nil
+ case 0:
+ return false, nil
+ }
+ return false, MakeGitError(ret)
+
+}
+
+func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Branch, error) {
+ var ptr *C.git_reference
+
+ cName := C.CString(branchName)
+ defer C.free(unsafe.Pointer(cName))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_lookup(&ptr, repo.ptr, cName, C.git_branch_t(bt))
+ runtime.KeepAlive(repo)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newReferenceFromC(ptr, repo).Branch(), nil
+}
+
+func (b *Branch) Name() (string, error) {
+ var cName *C.char
+ defer C.free(unsafe.Pointer(cName))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_name(&cName, b.Reference.ptr)
+ runtime.KeepAlive(b.Reference)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+
+ return C.GoString(cName), nil
+}
+
+func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) {
+ cName := C.CString(canonicalBranchName)
+ defer C.free(unsafe.Pointer(cName))
+
+ nameBuf := C.git_buf{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_remote_name(&nameBuf, repo.ptr, cName)
+ runtime.KeepAlive(repo)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+ defer C.git_buf_free(&nameBuf)
+
+ return C.GoString(nameBuf.ptr), nil
+}
+
+func (b *Branch) SetUpstream(upstreamName string) error {
+ cName := C.CString(upstreamName)
+ defer C.free(unsafe.Pointer(cName))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_set_upstream(b.Reference.ptr, cName)
+ runtime.KeepAlive(b.Reference)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (b *Branch) Upstream() (*Reference, error) {
+
+ var ptr *C.git_reference
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_upstream(&ptr, b.Reference.ptr)
+ runtime.KeepAlive(b.Reference)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newReferenceFromC(ptr, b.repo), nil
+}
+
+func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) {
+ cName := C.CString(canonicalBranchName)
+ defer C.free(unsafe.Pointer(cName))
+
+ nameBuf := C.git_buf{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_branch_upstream_name(&nameBuf, repo.ptr, cName)
+ runtime.KeepAlive(repo)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+ defer C.git_buf_free(&nameBuf)
+
+ return C.GoString(nameBuf.ptr), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/checkout.go b/vendor/github.com/libgit2/git2go/checkout.go
new file mode 100644
index 000000000..db3118f15
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/checkout.go
@@ -0,0 +1,237 @@
+package git
+
+/*
+#include <git2.h>
+
+extern void _go_git_populate_checkout_cb(git_checkout_options *opts);
+*/
+import "C"
+import (
+ "os"
+ "runtime"
+ "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
+ CheckoutRecreateMissing CheckoutStrategy = C.GIT_CHECKOUT_RECREATE_MISSING // Allow checkout to recreate missing files
+ CheckoutAllowConflicts CheckoutStrategy = C.GIT_CHECKOUT_ALLOW_CONFLICTS // Allow checkout to make safe updates even if conflicts are found
+ CheckoutRemoveUntracked CheckoutStrategy = C.GIT_CHECKOUT_REMOVE_UNTRACKED // Remove untracked files not in index (that are not ignored)
+ CheckoutRemoveIgnored CheckoutStrategy = C.GIT_CHECKOUT_REMOVE_IGNORED // Remove ignored files not in index
+ CheckoutUpdateOnly CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_ONLY // Only update existing files, don't create new ones
+ CheckoutDontUpdateIndex CheckoutStrategy = C.GIT_CHECKOUT_DONT_UPDATE_INDEX // Normally checkout updates index entries as it goes; this stops that
+ CheckoutNoRefresh CheckoutStrategy = C.GIT_CHECKOUT_NO_REFRESH // Don't refresh index/config/etc before doing checkout
+ CheckoutSkipUnmerged CheckoutStrategy = C.GIT_CHECKOUT_SKIP_UNMERGED // Allow checkout to skip unmerged files
+ CheckoutUserOurs CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index
+ CheckoutUseTheirs CheckoutStrategy = C.GIT_CHECKOUT_USE_THEIRS // For unmerged files, checkout stage 3 from index
+ CheckoutDisablePathspecMatch CheckoutStrategy = C.GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH // Treat pathspec as simple list of exact match file paths
+ CheckoutSkipLockedDirectories CheckoutStrategy = C.GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES // Ignore directories in use, they will be left empty
+ CheckoutDontOverwriteIgnored CheckoutStrategy = C.GIT_CHECKOUT_DONT_OVERWRITE_IGNORED // Don't overwrite ignored files that exist in the checkout target
+ CheckoutConflictStyleMerge CheckoutStrategy = C.GIT_CHECKOUT_CONFLICT_STYLE_MERGE // Write normal merge files for conflicts
+ CheckoutConflictStyleDiff3 CheckoutStrategy = C.GIT_CHECKOUT_CONFLICT_STYLE_DIFF3 // Include common ancestor data in diff3 format files for conflicts
+ CheckoutDontRemoveExisting CheckoutStrategy = C.GIT_CHECKOUT_DONT_REMOVE_EXISTING // Don't overwrite existing files or folders
+ CheckoutDontWriteIndex CheckoutStrategy = C.GIT_CHECKOUT_DONT_WRITE_INDEX // Normally checkout writes the index upon completion; this prevents that
+ CheckoutUpdateSubmodules CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_SUBMODULES // Recursively checkout submodules with same options (NOT IMPLEMENTED)
+ 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
+ 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 {
+ opts := CheckoutOpts{}
+ opts.Strategy = CheckoutStrategy(c.checkout_strategy)
+ opts.DisableFilters = c.disable_filters != 0
+ 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)
+ }
+ return opts
+}
+
+func (opts *CheckoutOpts) toC() *C.git_checkout_options {
+ if opts == nil {
+ return nil
+ }
+ c := C.git_checkout_options{}
+ populateCheckoutOpts(&c, opts)
+ 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.
+func populateCheckoutOpts(ptr *C.git_checkout_options, opts *CheckoutOpts) *C.git_checkout_options {
+ if opts == nil {
+ return nil
+ }
+
+ C.git_checkout_init_options(ptr, 1)
+ ptr.checkout_strategy = C.uint(opts.Strategy)
+ 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)
+ }
+ if len(opts.Paths) > 0 {
+ ptr.paths.strings = makeCStringsFromStrings(opts.Paths)
+ ptr.paths.count = C.size_t(len(opts.Paths))
+ }
+
+ if opts.Baseline != nil {
+ ptr.baseline = opts.Baseline.cast_ptr
+ }
+
+ return ptr
+}
+
+func freeCheckoutOpts(ptr *C.git_checkout_options) {
+ if ptr == nil {
+ return
+ }
+ C.free(unsafe.Pointer(ptr.target_directory))
+ 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
+// the commit pointed at by HEAD. opts may be nil.
+func (v *Repository) CheckoutHead(opts *CheckoutOpts) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cOpts := opts.toC()
+ defer freeCheckoutOpts(cOpts)
+
+ ret := C.git_checkout_head(v.ptr, cOpts)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+// Updates files in the working tree to match the content of the given
+// index. If index is nil, the repository's index will be used. opts
+// may be nil.
+func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOpts) error {
+ var iptr *C.git_index = nil
+ if index != nil {
+ iptr = index.ptr
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cOpts := opts.toC()
+ defer freeCheckoutOpts(cOpts)
+
+ ret := C.git_checkout_index(v.ptr, iptr, cOpts)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (v *Repository) CheckoutTree(tree *Tree, opts *CheckoutOpts) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cOpts := opts.toC()
+ defer freeCheckoutOpts(cOpts)
+
+ ret := C.git_checkout_tree(v.ptr, tree.ptr, cOpts)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/cherrypick.go b/vendor/github.com/libgit2/git2go/cherrypick.go
new file mode 100644
index 000000000..8983a7a52
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/cherrypick.go
@@ -0,0 +1,75 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+)
+
+type CherrypickOptions struct {
+ Version uint
+ Mainline uint
+ MergeOpts MergeOptions
+ CheckoutOpts CheckoutOpts
+}
+
+func cherrypickOptionsFromC(c *C.git_cherrypick_options) CherrypickOptions {
+ opts := CherrypickOptions{
+ Version: uint(c.version),
+ Mainline: uint(c.mainline),
+ MergeOpts: mergeOptionsFromC(&c.merge_opts),
+ CheckoutOpts: checkoutOptionsFromC(&c.checkout_opts),
+ }
+ return opts
+}
+
+func (opts *CherrypickOptions) toC() *C.git_cherrypick_options {
+ if opts == nil {
+ return nil
+ }
+ c := C.git_cherrypick_options{}
+ c.version = C.uint(opts.Version)
+ c.mainline = C.uint(opts.Mainline)
+ c.merge_opts = *opts.MergeOpts.toC()
+ c.checkout_opts = *opts.CheckoutOpts.toC()
+ return &c
+}
+
+func freeCherrypickOpts(ptr *C.git_cherrypick_options) {
+ if ptr == nil {
+ return
+ }
+ freeCheckoutOpts(&ptr.checkout_opts)
+}
+
+func DefaultCherrypickOptions() (CherrypickOptions, error) {
+ c := C.git_cherrypick_options{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_cherrypick_init_options(&c, C.GIT_CHERRYPICK_OPTIONS_VERSION)
+ if ecode < 0 {
+ return CherrypickOptions{}, MakeGitError(ecode)
+ }
+ defer freeCherrypickOpts(&c)
+ return cherrypickOptionsFromC(&c), nil
+}
+
+func (v *Repository) Cherrypick(commit *Commit, opts CherrypickOptions) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cOpts := opts.toC()
+ defer freeCherrypickOpts(cOpts)
+
+ ecode := C.git_cherrypick(v.ptr, commit.cast_ptr, cOpts)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(commit)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/clone.go b/vendor/github.com/libgit2/git2go/clone.go
new file mode 100644
index 000000000..1ff51245b
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/clone.go
@@ -0,0 +1,109 @@
+package git
+
+/*
+#include <git2.h>
+
+extern void _go_git_populate_remote_cb(git_clone_options *opts);
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type RemoteCreateCallback func(repo *Repository, name, url string) (*Remote, ErrorCode)
+
+type CloneOptions struct {
+ *CheckoutOpts
+ *FetchOptions
+ Bare bool
+ CheckoutBranch string
+ RemoteCreateCallback RemoteCreateCallback
+}
+
+func Clone(url string, path string, options *CloneOptions) (*Repository, error) {
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ copts := (*C.git_clone_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_clone_options{}))))
+ populateCloneOptions(copts, options)
+ defer freeCloneOptions(copts)
+
+ if len(options.CheckoutBranch) != 0 {
+ copts.checkout_branch = C.CString(options.CheckoutBranch)
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_repository
+ ret := C.git_clone(&ptr, curl, cpath, copts)
+
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newRepositoryFromC(ptr), nil
+}
+
+//export remoteCreateCallback
+func remoteCreateCallback(cremote unsafe.Pointer, crepo unsafe.Pointer, cname, curl *C.char, payload unsafe.Pointer) C.int {
+ name := C.GoString(cname)
+ url := C.GoString(curl)
+ repo := newRepositoryFromC((*C.git_repository)(crepo))
+ // We don't own this repository, so make sure we don't try to free it
+ runtime.SetFinalizer(repo, nil)
+
+ if opts, ok := pointerHandles.Get(payload).(CloneOptions); ok {
+ remote, err := opts.RemoteCreateCallback(repo, name, url)
+ // clear finalizer as the calling C function will
+ // free the remote itself
+ runtime.SetFinalizer(remote, nil)
+
+ if err == ErrOk && remote != nil {
+ cptr := (**C.git_remote)(cremote)
+ *cptr = remote.ptr
+ } else if err == ErrOk && remote == nil {
+ panic("no remote created by callback")
+ }
+
+ return C.int(err)
+ } else {
+ panic("invalid remote create callback")
+ }
+}
+
+func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions) {
+ C.git_clone_init_options(ptr, C.GIT_CLONE_OPTIONS_VERSION)
+
+ if opts == nil {
+ return
+ }
+ populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts)
+ populateFetchOptions(&ptr.fetch_opts, opts.FetchOptions)
+ ptr.bare = cbool(opts.Bare)
+
+ if opts.RemoteCreateCallback != nil {
+ // Go v1.1 does not allow to assign a C function pointer
+ C._go_git_populate_remote_cb(ptr)
+ ptr.remote_cb_payload = pointerHandles.Track(*opts)
+ }
+}
+
+func freeCloneOptions(ptr *C.git_clone_options) {
+ if ptr == nil {
+ return
+ }
+
+ freeCheckoutOpts(&ptr.checkout_opts)
+
+ if ptr.remote_cb_payload != nil {
+ pointerHandles.Untrack(ptr.remote_cb_payload)
+ }
+
+ C.free(unsafe.Pointer(ptr.checkout_branch))
+ C.free(unsafe.Pointer(ptr))
+}
diff --git a/vendor/github.com/libgit2/git2go/commit.go b/vendor/github.com/libgit2/git2go/commit.go
new file mode 100644
index 000000000..223b093c6
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/commit.go
@@ -0,0 +1,163 @@
+package git
+
+/*
+#include <git2.h>
+
+extern int _go_git_treewalk(git_tree *tree, git_treewalk_mode mode, void *ptr);
+*/
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+// Commit
+type Commit struct {
+ Object
+ cast_ptr *C.git_commit
+}
+
+func (c *Commit) AsObject() *Object {
+ return &c.Object
+}
+
+func (c *Commit) Message() string {
+ ret := C.GoString(C.git_commit_message(c.cast_ptr))
+ runtime.KeepAlive(c)
+ return ret
+}
+
+func (c *Commit) RawMessage() string {
+ ret := C.GoString(C.git_commit_message_raw(c.cast_ptr))
+ runtime.KeepAlive(c)
+ return ret
+}
+
+func (c *Commit) ExtractSignature() (string, string, error) {
+
+ var c_signed C.git_buf
+ defer C.git_buf_free(&c_signed)
+
+ var c_signature C.git_buf
+ defer C.git_buf_free(&c_signature)
+
+ oid := c.Id()
+ repo := C.git_commit_owner(c.cast_ptr)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ ret := C.git_commit_extract_signature(&c_signature, &c_signed, repo, oid.toC(), nil)
+ runtime.KeepAlive(oid)
+ if ret < 0 {
+ return "", "", MakeGitError(ret)
+ } else {
+ return C.GoString(c_signature.ptr), C.GoString(c_signed.ptr), nil
+ }
+
+}
+
+func (c *Commit) Summary() string {
+ ret := C.GoString(C.git_commit_summary(c.cast_ptr))
+ runtime.KeepAlive(c)
+ return ret
+}
+
+func (c *Commit) Tree() (*Tree, error) {
+ var ptr *C.git_tree
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_commit_tree(&ptr, c.cast_ptr)
+ runtime.KeepAlive(c)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return allocTree(ptr, c.repo), nil
+}
+
+func (c *Commit) TreeId() *Oid {
+ ret := newOidFromC(C.git_commit_tree_id(c.cast_ptr))
+ runtime.KeepAlive(c)
+ return ret
+}
+
+func (c *Commit) Author() *Signature {
+ cast_ptr := C.git_commit_author(c.cast_ptr)
+ ret := newSignatureFromC(cast_ptr)
+ runtime.KeepAlive(c)
+ return ret
+}
+
+func (c *Commit) Committer() *Signature {
+ cast_ptr := C.git_commit_committer(c.cast_ptr)
+ ret := newSignatureFromC(cast_ptr)
+ runtime.KeepAlive(c)
+ return ret
+}
+
+func (c *Commit) Parent(n uint) *Commit {
+ var cobj *C.git_commit
+ ret := C.git_commit_parent(&cobj, c.cast_ptr, C.uint(n))
+ if ret != 0 {
+ return nil
+ }
+
+ parent := allocCommit(cobj, c.repo)
+ runtime.KeepAlive(c)
+ return parent
+}
+
+func (c *Commit) ParentId(n uint) *Oid {
+ ret := newOidFromC(C.git_commit_parent_id(c.cast_ptr, C.uint(n)))
+ runtime.KeepAlive(c)
+ return ret
+}
+
+func (c *Commit) ParentCount() uint {
+ ret := uint(C.git_commit_parentcount(c.cast_ptr))
+ runtime.KeepAlive(c)
+ return ret
+}
+
+func (c *Commit) Amend(refname string, author, committer *Signature, message string, tree *Tree) (*Oid, error) {
+ var cref *C.char
+ if refname == "" {
+ cref = nil
+ } else {
+ cref = C.CString(refname)
+ defer C.free(unsafe.Pointer(cref))
+ }
+
+ cmsg := C.CString(message)
+ defer C.free(unsafe.Pointer(cmsg))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ authorSig, err := author.toC()
+ if err != nil {
+ return nil, err
+ }
+ defer C.git_signature_free(authorSig)
+
+ committerSig, err := committer.toC()
+ if err != nil {
+ return nil, err
+ }
+ defer C.git_signature_free(committerSig)
+
+ oid := new(Oid)
+
+ cerr := C.git_commit_amend(oid.toC(), c.cast_ptr, cref, authorSig, committerSig, nil, cmsg, tree.cast_ptr)
+ runtime.KeepAlive(oid)
+ runtime.KeepAlive(c)
+ runtime.KeepAlive(tree)
+ if cerr < 0 {
+ return nil, MakeGitError(cerr)
+ }
+
+ return oid, nil
+}
diff --git a/vendor/github.com/libgit2/git2go/config.go b/vendor/github.com/libgit2/git2go/config.go
new file mode 100644
index 000000000..ab9af38ff
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/config.go
@@ -0,0 +1,452 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type ConfigLevel int
+
+const (
+ // System-wide on Windows, for compatibility with portable git
+ ConfigLevelProgramdata ConfigLevel = C.GIT_CONFIG_LEVEL_PROGRAMDATA
+
+ // System-wide configuration file; /etc/gitconfig on Linux systems
+ ConfigLevelSystem ConfigLevel = C.GIT_CONFIG_LEVEL_SYSTEM
+
+ // XDG compatible configuration file; typically ~/.config/git/config
+ ConfigLevelXDG ConfigLevel = C.GIT_CONFIG_LEVEL_XDG
+
+ // User-specific configuration file (also called Global configuration
+ // file); typically ~/.gitconfig
+ ConfigLevelGlobal ConfigLevel = C.GIT_CONFIG_LEVEL_GLOBAL
+
+ // Repository specific configuration file; $WORK_DIR/.git/config on
+ // non-bare repos
+ ConfigLevelLocal ConfigLevel = C.GIT_CONFIG_LEVEL_LOCAL
+
+ // Application specific configuration file; freely defined by applications
+ ConfigLevelApp ConfigLevel = C.GIT_CONFIG_LEVEL_APP
+
+ // Represents the highest level available config file (i.e. the most
+ // specific config file available that actually is loaded)
+ ConfigLevelHighest ConfigLevel = C.GIT_CONFIG_HIGHEST_LEVEL
+)
+
+type ConfigEntry struct {
+ Name string
+ Value string
+ Level ConfigLevel
+}
+
+func newConfigEntryFromC(centry *C.git_config_entry) *ConfigEntry {
+ return &ConfigEntry{
+ Name: C.GoString(centry.name),
+ Value: C.GoString(centry.value),
+ Level: ConfigLevel(centry.level),
+ }
+}
+
+type Config struct {
+ ptr *C.git_config
+}
+
+// NewConfig creates a new empty configuration object
+func NewConfig() (*Config, error) {
+ config := new(Config)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if ret := C.git_config_new(&config.ptr); ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return config, nil
+}
+
+// AddFile adds a file-backed backend to the config object at the specified level.
+func (c *Config) AddFile(path string, level ConfigLevel, force bool) error {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_add_file_ondisk(c.ptr, cpath, C.git_config_level_t(level), nil, cbool(force))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (c *Config) LookupInt32(name string) (int32, error) {
+ var out C.int32_t
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_get_int32(&out, c.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return 0, MakeGitError(ret)
+ }
+
+ return int32(out), nil
+}
+
+func (c *Config) LookupInt64(name string) (int64, error) {
+ var out C.int64_t
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_get_int64(&out, c.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return 0, MakeGitError(ret)
+ }
+
+ return int64(out), nil
+}
+
+func (c *Config) LookupString(name string) (string, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ valBuf := C.git_buf{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_get_string_buf(&valBuf, c.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+ defer C.git_buf_free(&valBuf)
+
+ return C.GoString(valBuf.ptr), nil
+}
+
+func (c *Config) LookupBool(name string) (bool, error) {
+ var out C.int
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_get_bool(&out, c.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+
+ return out != 0, nil
+}
+
+func (c *Config) NewMultivarIterator(name, regexp string) (*ConfigIterator, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ var cregexp *C.char
+ if regexp == "" {
+ cregexp = nil
+ } else {
+ cregexp = C.CString(regexp)
+ defer C.free(unsafe.Pointer(cregexp))
+ }
+
+ iter := &ConfigIterator{cfg: c}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_multivar_iterator_new(&iter.ptr, c.ptr, cname, cregexp)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ runtime.SetFinalizer(iter, (*ConfigIterator).Free)
+ return iter, nil
+}
+
+// NewIterator creates an iterator over each entry in the
+// configuration
+func (c *Config) NewIterator() (*ConfigIterator, error) {
+ iter := &ConfigIterator{cfg: c}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_iterator_new(&iter.ptr, c.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return iter, nil
+}
+
+// NewIteratorGlob creates an iterator over each entry in the
+// configuration whose name matches the given regular expression
+func (c *Config) NewIteratorGlob(regexp string) (*ConfigIterator, error) {
+ iter := &ConfigIterator{cfg: c}
+ cregexp := C.CString(regexp)
+ defer C.free(unsafe.Pointer(cregexp))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_iterator_glob_new(&iter.ptr, c.ptr, cregexp)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return iter, nil
+}
+
+func (c *Config) SetString(name, value string) (err error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ cvalue := C.CString(value)
+ defer C.free(unsafe.Pointer(cvalue))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_set_string(c.ptr, cname, cvalue)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (c *Config) Free() {
+ runtime.SetFinalizer(c, nil)
+ C.git_config_free(c.ptr)
+}
+
+func (c *Config) SetInt32(name string, value int32) (err error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_set_int32(c.ptr, cname, C.int32_t(value))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (c *Config) SetInt64(name string, value int64) (err error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_set_int64(c.ptr, cname, C.int64_t(value))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (c *Config) SetBool(name string, value bool) (err error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_set_bool(c.ptr, cname, cbool(value))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (c *Config) SetMultivar(name, regexp, value string) (err error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ cregexp := C.CString(regexp)
+ defer C.free(unsafe.Pointer(cregexp))
+
+ cvalue := C.CString(value)
+ defer C.free(unsafe.Pointer(cvalue))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_set_multivar(c.ptr, cname, cregexp, cvalue)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (c *Config) Delete(name string) error {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_delete_entry(c.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+// OpenLevel creates a single-level focused config object from a multi-level one
+func (c *Config) OpenLevel(parent *Config, level ConfigLevel) (*Config, error) {
+ config := new(Config)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_open_level(&config.ptr, parent.ptr, C.git_config_level_t(level))
+ runtime.KeepAlive(c)
+ runtime.KeepAlive(parent)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return config, nil
+}
+
+// OpenOndisk creates a new config instance containing a single on-disk file
+func OpenOndisk(parent *Config, path string) (*Config, error) {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ config := new(Config)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if ret := C.git_config_open_ondisk(&config.ptr, cpath); ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return config, nil
+}
+
+type ConfigIterator struct {
+ ptr *C.git_config_iterator
+ cfg *Config
+}
+
+// Next returns the next entry for this iterator
+func (iter *ConfigIterator) Next() (*ConfigEntry, error) {
+ var centry *C.git_config_entry
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_next(&centry, iter.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ entry := newConfigEntryFromC(centry)
+ runtime.KeepAlive(iter)
+
+ return entry, nil
+}
+
+func (iter *ConfigIterator) Free() {
+ runtime.SetFinalizer(iter, nil)
+ C.free(unsafe.Pointer(iter.ptr))
+}
+
+func ConfigFindGlobal() (string, error) {
+ var buf C.git_buf
+ defer C.git_buf_free(&buf)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_find_global(&buf)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+
+ return C.GoString(buf.ptr), nil
+}
+
+func ConfigFindSystem() (string, error) {
+ var buf C.git_buf
+ defer C.git_buf_free(&buf)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_find_system(&buf)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+
+ return C.GoString(buf.ptr), nil
+}
+
+func ConfigFindXDG() (string, error) {
+ var buf C.git_buf
+ defer C.git_buf_free(&buf)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_find_xdg(&buf)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+
+ return C.GoString(buf.ptr), nil
+}
+
+// ConfigFindProgramdata locate the path to the configuration file in ProgramData.
+//
+// Look for the file in %PROGRAMDATA%\Git\config used by portable git.
+func ConfigFindProgramdata() (string, error) {
+ var buf C.git_buf
+ defer C.git_buf_free(&buf)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_config_find_programdata(&buf)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+
+ return C.GoString(buf.ptr), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/credentials.go b/vendor/github.com/libgit2/git2go/credentials.go
new file mode 100644
index 000000000..4e42b6e11
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/credentials.go
@@ -0,0 +1,91 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import "unsafe"
+
+type CredType uint
+
+const (
+ CredTypeUserpassPlaintext CredType = C.GIT_CREDTYPE_USERPASS_PLAINTEXT
+ CredTypeSshKey CredType = C.GIT_CREDTYPE_SSH_KEY
+ CredTypeSshCustom CredType = C.GIT_CREDTYPE_SSH_CUSTOM
+ CredTypeDefault CredType = C.GIT_CREDTYPE_DEFAULT
+)
+
+type Cred struct {
+ ptr *C.git_cred
+}
+
+func (o *Cred) HasUsername() bool {
+ if C.git_cred_has_username(o.ptr) == 1 {
+ return true
+ }
+ return false
+}
+
+func (o *Cred) Type() CredType {
+ return (CredType)(o.ptr.credtype)
+}
+
+func credFromC(ptr *C.git_cred) *Cred {
+ return &Cred{ptr}
+}
+
+func NewCredUserpassPlaintext(username string, password string) (int, Cred) {
+ cred := Cred{}
+ 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
+}
+
+// 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(publicKeyPath)
+ defer C.free(unsafe.Pointer(cpublickey))
+ cprivatekey := C.CString(privateKeyPath)
+ defer C.free(unsafe.Pointer(cprivatekey))
+ 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
+}
+
+// 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)
+ defer C.free(unsafe.Pointer(cusername))
+ ret := C.git_cred_ssh_key_from_agent(&cred.ptr, cusername)
+ return int(ret), cred
+}
+
+func NewCredDefault() (int, Cred) {
+ cred := Cred{}
+ ret := C.git_cred_default_new(&cred.ptr)
+ return int(ret), cred
+}
diff --git a/vendor/github.com/libgit2/git2go/describe.go b/vendor/github.com/libgit2/git2go/describe.go
new file mode 100644
index 000000000..0b750760e
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/describe.go
@@ -0,0 +1,225 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+// DescribeOptions represents the describe operation configuration.
+//
+// You can use DefaultDescribeOptions() to get default options.
+type DescribeOptions struct {
+ // How many tags as candidates to consider to describe the input commit-ish.
+ // Increasing it above 10 will take slightly longer but may produce a more
+ // accurate result. 0 will cause only exact matches to be output.
+ MaxCandidatesTags uint // default: 10
+
+ // By default describe only shows annotated tags. Change this in order
+ // to show all refs from refs/tags or refs/.
+ Strategy DescribeOptionsStrategy // default: DescribeDefault
+
+ // Only consider tags matching the given glob(7) pattern, excluding
+ // the "refs/tags/" prefix. Can be used to avoid leaking private
+ // tags from the repo.
+ Pattern string
+
+ // When calculating the distance from the matching tag or
+ // reference, only walk down the first-parent ancestry.
+ OnlyFollowFirstParent bool
+
+ // If no matching tag or reference is found, the describe
+ // operation would normally fail. If this option is set, it
+ // will instead fall back to showing the full id of the commit.
+ ShowCommitOidAsFallback bool
+}
+
+// DefaultDescribeOptions returns default options for the describe operation.
+func DefaultDescribeOptions() (DescribeOptions, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ opts := C.git_describe_options{}
+ ecode := C.git_describe_init_options(&opts, C.GIT_DESCRIBE_OPTIONS_VERSION)
+ if ecode < 0 {
+ return DescribeOptions{}, MakeGitError(ecode)
+ }
+
+ return DescribeOptions{
+ MaxCandidatesTags: uint(opts.max_candidates_tags),
+ Strategy: DescribeOptionsStrategy(opts.describe_strategy),
+ }, nil
+}
+
+// DescribeFormatOptions can be used for formatting the describe string.
+//
+// You can use DefaultDescribeFormatOptions() to get default options.
+type DescribeFormatOptions struct {
+ // Size of the abbreviated commit id to use. This value is the
+ // lower bound for the length of the abbreviated string.
+ AbbreviatedSize uint // default: 7
+
+ // Set to use the long format even when a shorter name could be used.
+ AlwaysUseLongFormat bool
+
+ // If the workdir is dirty and this is set, this string will be
+ // appended to the description string.
+ DirtySuffix string
+}
+
+// DefaultDescribeFormatOptions returns default options for formatting
+// the output.
+func DefaultDescribeFormatOptions() (DescribeFormatOptions, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ opts := C.git_describe_format_options{}
+ ecode := C.git_describe_init_format_options(&opts, C.GIT_DESCRIBE_FORMAT_OPTIONS_VERSION)
+ if ecode < 0 {
+ return DescribeFormatOptions{}, MakeGitError(ecode)
+ }
+
+ return DescribeFormatOptions{
+ AbbreviatedSize: uint(opts.abbreviated_size),
+ AlwaysUseLongFormat: opts.always_use_long_format == 1,
+ }, nil
+}
+
+// DescribeOptionsStrategy behaves like the --tags and --all options
+// to git-describe, namely they say to look for any reference in
+// either refs/tags/ or refs/ respectively.
+//
+// By default it only shows annotated tags.
+type DescribeOptionsStrategy uint
+
+// Describe strategy options.
+const (
+ DescribeDefault DescribeOptionsStrategy = C.GIT_DESCRIBE_DEFAULT
+ DescribeTags DescribeOptionsStrategy = C.GIT_DESCRIBE_TAGS
+ DescribeAll DescribeOptionsStrategy = C.GIT_DESCRIBE_ALL
+)
+
+// Describe performs the describe operation on the commit.
+func (c *Commit) Describe(opts *DescribeOptions) (*DescribeResult, error) {
+ var resultPtr *C.git_describe_result
+
+ var cDescribeOpts *C.git_describe_options
+ if opts != nil {
+ var cpattern *C.char
+ if len(opts.Pattern) > 0 {
+ cpattern = C.CString(opts.Pattern)
+ defer C.free(unsafe.Pointer(cpattern))
+ }
+
+ cDescribeOpts = &C.git_describe_options{
+ version: C.GIT_DESCRIBE_OPTIONS_VERSION,
+ max_candidates_tags: C.uint(opts.MaxCandidatesTags),
+ describe_strategy: C.uint(opts.Strategy),
+ pattern: cpattern,
+ only_follow_first_parent: cbool(opts.OnlyFollowFirstParent),
+ show_commit_oid_as_fallback: cbool(opts.ShowCommitOidAsFallback),
+ }
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_describe_commit(&resultPtr, c.ptr, cDescribeOpts)
+ runtime.KeepAlive(c)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newDescribeResultFromC(resultPtr), nil
+}
+
+// DescribeWorkdir describes the working tree. It means describe HEAD
+// and appends <mark> (-dirty by default) if the working tree is dirty.
+func (repo *Repository) DescribeWorkdir(opts *DescribeOptions) (*DescribeResult, error) {
+ var resultPtr *C.git_describe_result
+
+ var cDescribeOpts *C.git_describe_options
+ if opts != nil {
+ var cpattern *C.char
+ if len(opts.Pattern) > 0 {
+ cpattern = C.CString(opts.Pattern)
+ defer C.free(unsafe.Pointer(cpattern))
+ }
+
+ cDescribeOpts = &C.git_describe_options{
+ version: C.GIT_DESCRIBE_OPTIONS_VERSION,
+ max_candidates_tags: C.uint(opts.MaxCandidatesTags),
+ describe_strategy: C.uint(opts.Strategy),
+ pattern: cpattern,
+ only_follow_first_parent: cbool(opts.OnlyFollowFirstParent),
+ show_commit_oid_as_fallback: cbool(opts.ShowCommitOidAsFallback),
+ }
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_describe_workdir(&resultPtr, repo.ptr, cDescribeOpts)
+ runtime.KeepAlive(repo)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newDescribeResultFromC(resultPtr), nil
+}
+
+// DescribeResult represents the output from the 'git_describe_commit'
+// and 'git_describe_workdir' functions in libgit2.
+//
+// Use Format() to get a string out of it.
+type DescribeResult struct {
+ ptr *C.git_describe_result
+}
+
+func newDescribeResultFromC(ptr *C.git_describe_result) *DescribeResult {
+ result := &DescribeResult{
+ ptr: ptr,
+ }
+ runtime.SetFinalizer(result, (*DescribeResult).Free)
+ return result
+}
+
+// Format prints the DescribeResult as a string.
+func (result *DescribeResult) Format(opts *DescribeFormatOptions) (string, error) {
+ resultBuf := C.git_buf{}
+
+ var cFormatOpts *C.git_describe_format_options
+ if opts != nil {
+ cDirtySuffix := C.CString(opts.DirtySuffix)
+ defer C.free(unsafe.Pointer(cDirtySuffix))
+
+ cFormatOpts = &C.git_describe_format_options{
+ version: C.GIT_DESCRIBE_FORMAT_OPTIONS_VERSION,
+ abbreviated_size: C.uint(opts.AbbreviatedSize),
+ always_use_long_format: cbool(opts.AlwaysUseLongFormat),
+ dirty_suffix: cDirtySuffix,
+ }
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_describe_format(&resultBuf, result.ptr, cFormatOpts)
+ runtime.KeepAlive(result)
+ if ecode < 0 {
+ return "", MakeGitError(ecode)
+ }
+ defer C.git_buf_free(&resultBuf)
+
+ return C.GoString(resultBuf.ptr), nil
+}
+
+// Free cleans up the C reference.
+func (result *DescribeResult) Free() {
+ runtime.SetFinalizer(result, nil)
+ C.git_describe_result_free(result.ptr)
+ result.ptr = nil
+}
diff --git a/vendor/github.com/libgit2/git2go/diff.go b/vendor/github.com/libgit2/git2go/diff.go
new file mode 100644
index 000000000..308832074
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/diff.go
@@ -0,0 +1,810 @@
+package git
+
+/*
+#include <git2.h>
+
+extern int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload);
+extern void _go_git_setup_diff_notify_callbacks(git_diff_options* opts);
+extern int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload);
+*/
+import "C"
+import (
+ "errors"
+ "runtime"
+ "unsafe"
+)
+
+type DiffFlag int
+
+const (
+ DiffFlagBinary DiffFlag = C.GIT_DIFF_FLAG_BINARY
+ DiffFlagNotBinary DiffFlag = C.GIT_DIFF_FLAG_NOT_BINARY
+ DiffFlagValidOid DiffFlag = C.GIT_DIFF_FLAG_VALID_ID
+ DiffFlagExists DiffFlag = C.GIT_DIFF_FLAG_EXISTS
+)
+
+type Delta int
+
+const (
+ DeltaUnmodified Delta = C.GIT_DELTA_UNMODIFIED
+ DeltaAdded Delta = C.GIT_DELTA_ADDED
+ DeltaDeleted Delta = C.GIT_DELTA_DELETED
+ DeltaModified Delta = C.GIT_DELTA_MODIFIED
+ DeltaRenamed Delta = C.GIT_DELTA_RENAMED
+ DeltaCopied Delta = C.GIT_DELTA_COPIED
+ DeltaIgnored Delta = C.GIT_DELTA_IGNORED
+ DeltaUntracked Delta = C.GIT_DELTA_UNTRACKED
+ DeltaTypeChange Delta = C.GIT_DELTA_TYPECHANGE
+ DeltaUnreadable Delta = C.GIT_DELTA_UNREADABLE
+ DeltaConflicted Delta = C.GIT_DELTA_CONFLICTED
+)
+
+type DiffLineType int
+
+const (
+ DiffLineContext DiffLineType = C.GIT_DIFF_LINE_CONTEXT
+ DiffLineAddition DiffLineType = C.GIT_DIFF_LINE_ADDITION
+ DiffLineDeletion DiffLineType = C.GIT_DIFF_LINE_DELETION
+ DiffLineContextEOFNL DiffLineType = C.GIT_DIFF_LINE_CONTEXT_EOFNL
+ DiffLineAddEOFNL DiffLineType = C.GIT_DIFF_LINE_ADD_EOFNL
+ DiffLineDelEOFNL DiffLineType = C.GIT_DIFF_LINE_DEL_EOFNL
+
+ DiffLineFileHdr DiffLineType = C.GIT_DIFF_LINE_FILE_HDR
+ DiffLineHunkHdr DiffLineType = C.GIT_DIFF_LINE_HUNK_HDR
+ DiffLineBinary DiffLineType = C.GIT_DIFF_LINE_BINARY
+)
+
+type DiffFile struct {
+ Path string
+ Oid *Oid
+ Size int
+ Flags DiffFlag
+ Mode uint16
+}
+
+func diffFileFromC(file *C.git_diff_file) DiffFile {
+ return DiffFile{
+ Path: C.GoString(file.path),
+ Oid: newOidFromC(&file.id),
+ Size: int(file.size),
+ Flags: DiffFlag(file.flags),
+ Mode: uint16(file.mode),
+ }
+}
+
+type DiffDelta struct {
+ Status Delta
+ Flags DiffFlag
+ Similarity uint16
+ OldFile DiffFile
+ NewFile DiffFile
+}
+
+func diffDeltaFromC(delta *C.git_diff_delta) DiffDelta {
+ return DiffDelta{
+ Status: Delta(delta.status),
+ Flags: DiffFlag(delta.flags),
+ Similarity: uint16(delta.similarity),
+ OldFile: diffFileFromC(&delta.old_file),
+ NewFile: diffFileFromC(&delta.new_file),
+ }
+}
+
+type DiffHunk struct {
+ OldStart int
+ OldLines int
+ NewStart int
+ NewLines int
+ Header string
+}
+
+func diffHunkFromC(hunk *C.git_diff_hunk) DiffHunk {
+ return DiffHunk{
+ OldStart: int(hunk.old_start),
+ OldLines: int(hunk.old_lines),
+ NewStart: int(hunk.new_start),
+ NewLines: int(hunk.new_lines),
+ Header: C.GoStringN(&hunk.header[0], C.int(hunk.header_len)),
+ }
+}
+
+type DiffLine struct {
+ Origin DiffLineType
+ OldLineno int
+ NewLineno int
+ NumLines int
+ Content string
+}
+
+func diffLineFromC(line *C.git_diff_line) DiffLine {
+ return DiffLine{
+ Origin: DiffLineType(line.origin),
+ OldLineno: int(line.old_lineno),
+ NewLineno: int(line.new_lineno),
+ NumLines: int(line.num_lines),
+ Content: C.GoStringN(line.content, C.int(line.content_len)),
+ }
+}
+
+type Diff struct {
+ ptr *C.git_diff
+ repo *Repository
+}
+
+func (diff *Diff) NumDeltas() (int, error) {
+ if diff.ptr == nil {
+ return -1, ErrInvalid
+ }
+ ret := int(C.git_diff_num_deltas(diff.ptr))
+ runtime.KeepAlive(diff)
+ return ret, nil
+}
+
+func (diff *Diff) GetDelta(index int) (DiffDelta, error) {
+ if diff.ptr == nil {
+ return DiffDelta{}, ErrInvalid
+ }
+ ptr := C.git_diff_get_delta(diff.ptr, C.size_t(index))
+ ret := diffDeltaFromC(ptr)
+ runtime.KeepAlive(diff)
+ return ret, nil
+}
+
+func newDiffFromC(ptr *C.git_diff, repo *Repository) *Diff {
+ if ptr == nil {
+ return nil
+ }
+
+ diff := &Diff{
+ ptr: ptr,
+ repo: repo,
+ }
+
+ runtime.SetFinalizer(diff, (*Diff).Free)
+ return diff
+}
+
+func (diff *Diff) Free() error {
+ if diff.ptr == nil {
+ return ErrInvalid
+ }
+ runtime.SetFinalizer(diff, nil)
+ C.git_diff_free(diff.ptr)
+ diff.ptr = nil
+ return nil
+}
+
+func (diff *Diff) FindSimilar(opts *DiffFindOptions) error {
+
+ var copts *C.git_diff_find_options
+ if opts != nil {
+ copts = &C.git_diff_find_options{
+ version: C.GIT_DIFF_FIND_OPTIONS_VERSION,
+ flags: C.uint32_t(opts.Flags),
+ rename_threshold: C.uint16_t(opts.RenameThreshold),
+ copy_threshold: C.uint16_t(opts.CopyThreshold),
+ rename_from_rewrite_threshold: C.uint16_t(opts.RenameFromRewriteThreshold),
+ break_rewrite_threshold: C.uint16_t(opts.BreakRewriteThreshold),
+ rename_limit: C.size_t(opts.RenameLimit),
+ }
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_find_similar(diff.ptr, copts)
+ runtime.KeepAlive(diff)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+
+ return nil
+}
+
+type DiffStats struct {
+ ptr *C.git_diff_stats
+}
+
+func (stats *DiffStats) Free() error {
+ if stats.ptr == nil {
+ return ErrInvalid
+ }
+ runtime.SetFinalizer(stats, nil)
+ C.git_diff_stats_free(stats.ptr)
+ stats.ptr = nil
+ return nil
+}
+
+func (stats *DiffStats) Insertions() int {
+ ret := int(C.git_diff_stats_insertions(stats.ptr))
+ runtime.KeepAlive(stats)
+ return ret
+}
+
+func (stats *DiffStats) Deletions() int {
+ ret := int(C.git_diff_stats_deletions(stats.ptr))
+ runtime.KeepAlive(stats)
+ return ret
+}
+
+func (stats *DiffStats) FilesChanged() int {
+ ret := int(C.git_diff_stats_files_changed(stats.ptr))
+ runtime.KeepAlive(stats)
+ return ret
+}
+
+type DiffStatsFormat int
+
+const (
+ DiffStatsNone DiffStatsFormat = C.GIT_DIFF_STATS_NONE
+ DiffStatsFull DiffStatsFormat = C.GIT_DIFF_STATS_FULL
+ DiffStatsShort DiffStatsFormat = C.GIT_DIFF_STATS_SHORT
+ DiffStatsNumber DiffStatsFormat = C.GIT_DIFF_STATS_NUMBER
+ DiffStatsIncludeSummary DiffStatsFormat = C.GIT_DIFF_STATS_INCLUDE_SUMMARY
+)
+
+func (stats *DiffStats) String(format DiffStatsFormat,
+ width uint) (string, error) {
+ buf := C.git_buf{}
+ defer C.git_buf_free(&buf)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_diff_stats_to_buf(&buf,
+ stats.ptr, C.git_diff_stats_format_t(format), C.size_t(width))
+ runtime.KeepAlive(stats)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+
+ return C.GoString(buf.ptr), nil
+}
+
+func (diff *Diff) Stats() (*DiffStats, error) {
+ stats := new(DiffStats)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_get_stats(&stats.ptr, diff.ptr)
+ runtime.KeepAlive(diff)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ runtime.SetFinalizer(stats, (*DiffStats).Free)
+
+ return stats, nil
+}
+
+type diffForEachData struct {
+ FileCallback DiffForEachFileCallback
+ HunkCallback DiffForEachHunkCallback
+ LineCallback DiffForEachLineCallback
+ Error error
+}
+
+type DiffForEachFileCallback func(DiffDelta, float64) (DiffForEachHunkCallback, error)
+
+type DiffDetail int
+
+const (
+ DiffDetailFiles DiffDetail = iota
+ DiffDetailHunks
+ DiffDetailLines
+)
+
+func (diff *Diff) ForEach(cbFile DiffForEachFileCallback, detail DiffDetail) error {
+ if diff.ptr == nil {
+ return ErrInvalid
+ }
+
+ intHunks := C.int(0)
+ if detail >= DiffDetailHunks {
+ intHunks = C.int(1)
+ }
+
+ intLines := C.int(0)
+ if detail >= DiffDetailLines {
+ intLines = C.int(1)
+ }
+
+ data := &diffForEachData{
+ FileCallback: cbFile,
+ }
+
+ handle := pointerHandles.Track(data)
+ defer pointerHandles.Untrack(handle)
+
+ ecode := C._go_git_diff_foreach(diff.ptr, 1, intHunks, intLines, handle)
+ runtime.KeepAlive(diff)
+ if ecode < 0 {
+ return data.Error
+ }
+ return nil
+}
+
+//export diffForEachFileCb
+func diffForEachFileCb(delta *C.git_diff_delta, progress C.float, handle unsafe.Pointer) int {
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*diffForEachData)
+ if !ok {
+ panic("could not retrieve data for handle")
+ }
+
+ data.HunkCallback = nil
+ if data.FileCallback != nil {
+ cb, err := data.FileCallback(diffDeltaFromC(delta), float64(progress))
+ if err != nil {
+ data.Error = err
+ return -1
+ }
+ data.HunkCallback = cb
+ }
+
+ return 0
+}
+
+type DiffForEachHunkCallback func(DiffHunk) (DiffForEachLineCallback, error)
+
+//export diffForEachHunkCb
+func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, handle unsafe.Pointer) int {
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*diffForEachData)
+ if !ok {
+ panic("could not retrieve data for handle")
+ }
+
+ data.LineCallback = nil
+ if data.HunkCallback != nil {
+ cb, err := data.HunkCallback(diffHunkFromC(hunk))
+ if err != nil {
+ data.Error = err
+ return -1
+ }
+ data.LineCallback = cb
+ }
+
+ return 0
+}
+
+type DiffForEachLineCallback func(DiffLine) error
+
+//export diffForEachLineCb
+func diffForEachLineCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line, handle unsafe.Pointer) int {
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*diffForEachData)
+ if !ok {
+ panic("could not retrieve data for handle")
+ }
+
+ err := data.LineCallback(diffLineFromC(line))
+ if err != nil {
+ data.Error = err
+ return -1
+ }
+
+ return 0
+}
+
+func (diff *Diff) Patch(deltaIndex int) (*Patch, error) {
+ if diff.ptr == nil {
+ return nil, ErrInvalid
+ }
+ var patchPtr *C.git_patch
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_patch_from_diff(&patchPtr, diff.ptr, C.size_t(deltaIndex))
+ runtime.KeepAlive(diff)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newPatchFromC(patchPtr), nil
+}
+
+type DiffOptionsFlag int
+
+const (
+ DiffNormal DiffOptionsFlag = C.GIT_DIFF_NORMAL
+ DiffReverse DiffOptionsFlag = C.GIT_DIFF_REVERSE
+ DiffIncludeIgnored DiffOptionsFlag = C.GIT_DIFF_INCLUDE_IGNORED
+ DiffRecurseIgnoredDirs DiffOptionsFlag = C.GIT_DIFF_RECURSE_IGNORED_DIRS
+ DiffIncludeUntracked DiffOptionsFlag = C.GIT_DIFF_INCLUDE_UNTRACKED
+ DiffRecurseUntracked DiffOptionsFlag = C.GIT_DIFF_RECURSE_UNTRACKED_DIRS
+ DiffIncludeUnmodified DiffOptionsFlag = C.GIT_DIFF_INCLUDE_UNMODIFIED
+ DiffIncludeTypeChange DiffOptionsFlag = C.GIT_DIFF_INCLUDE_TYPECHANGE
+ DiffIncludeTypeChangeTrees DiffOptionsFlag = C.GIT_DIFF_INCLUDE_TYPECHANGE_TREES
+ DiffIgnoreFilemode DiffOptionsFlag = C.GIT_DIFF_IGNORE_FILEMODE
+ DiffIgnoreSubmodules DiffOptionsFlag = C.GIT_DIFF_IGNORE_SUBMODULES
+ DiffIgnoreCase DiffOptionsFlag = C.GIT_DIFF_IGNORE_CASE
+ DiffIncludeCaseChange DiffOptionsFlag = C.GIT_DIFF_INCLUDE_CASECHANGE
+
+ DiffDisablePathspecMatch DiffOptionsFlag = C.GIT_DIFF_DISABLE_PATHSPEC_MATCH
+ DiffSkipBinaryCheck DiffOptionsFlag = C.GIT_DIFF_SKIP_BINARY_CHECK
+ DiffEnableFastUntrackedDirs DiffOptionsFlag = C.GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS
+
+ DiffForceText DiffOptionsFlag = C.GIT_DIFF_FORCE_TEXT
+ DiffForceBinary DiffOptionsFlag = C.GIT_DIFF_FORCE_BINARY
+
+ DiffIgnoreWhitespace DiffOptionsFlag = C.GIT_DIFF_IGNORE_WHITESPACE
+ DiffIgnoreWhitespaceChange DiffOptionsFlag = C.GIT_DIFF_IGNORE_WHITESPACE_CHANGE
+ DiffIgnoreWitespaceEol DiffOptionsFlag = C.GIT_DIFF_IGNORE_WHITESPACE_EOL
+
+ DiffShowUntrackedContent DiffOptionsFlag = C.GIT_DIFF_SHOW_UNTRACKED_CONTENT
+ DiffShowUnmodified DiffOptionsFlag = C.GIT_DIFF_SHOW_UNMODIFIED
+ DiffPatience DiffOptionsFlag = C.GIT_DIFF_PATIENCE
+ DiffMinimal DiffOptionsFlag = C.GIT_DIFF_MINIMAL
+ DiffShowBinary DiffOptionsFlag = C.GIT_DIFF_SHOW_BINARY
+ DiffIndentHeuristic DiffOptionsFlag = C.GIT_DIFF_INDENT_HEURISTIC
+)
+
+type DiffNotifyCallback func(diffSoFar *Diff, deltaToAdd DiffDelta, matchedPathspec string) error
+
+type DiffOptions struct {
+ Flags DiffOptionsFlag
+ IgnoreSubmodules SubmoduleIgnore
+ Pathspec []string
+ NotifyCallback DiffNotifyCallback
+
+ ContextLines uint32
+ InterhunkLines uint32
+ IdAbbrev uint16
+
+ MaxSize int
+
+ OldPrefix string
+ NewPrefix string
+}
+
+func DefaultDiffOptions() (DiffOptions, error) {
+ opts := C.git_diff_options{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_init_options(&opts, C.GIT_DIFF_OPTIONS_VERSION)
+ if ecode < 0 {
+ return DiffOptions{}, MakeGitError(ecode)
+ }
+
+ return DiffOptions{
+ Flags: DiffOptionsFlag(opts.flags),
+ IgnoreSubmodules: SubmoduleIgnore(opts.ignore_submodules),
+ Pathspec: makeStringsFromCStrings(opts.pathspec.strings, int(opts.pathspec.count)),
+ ContextLines: uint32(opts.context_lines),
+ InterhunkLines: uint32(opts.interhunk_lines),
+ IdAbbrev: uint16(opts.id_abbrev),
+ MaxSize: int(opts.max_size),
+ OldPrefix: "a",
+ NewPrefix: "b",
+ }, nil
+}
+
+type DiffFindOptionsFlag int
+
+const (
+ DiffFindByConfig DiffFindOptionsFlag = C.GIT_DIFF_FIND_BY_CONFIG
+ DiffFindRenames DiffFindOptionsFlag = C.GIT_DIFF_FIND_RENAMES
+ DiffFindRenamesFromRewrites DiffFindOptionsFlag = C.GIT_DIFF_FIND_RENAMES_FROM_REWRITES
+ DiffFindCopies DiffFindOptionsFlag = C.GIT_DIFF_FIND_COPIES
+ DiffFindCopiesFromUnmodified DiffFindOptionsFlag = C.GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED
+ DiffFindRewrites DiffFindOptionsFlag = C.GIT_DIFF_FIND_REWRITES
+ DiffFindBreakRewrites DiffFindOptionsFlag = C.GIT_DIFF_BREAK_REWRITES
+ DiffFindAndBreakRewrites DiffFindOptionsFlag = C.GIT_DIFF_FIND_AND_BREAK_REWRITES
+ DiffFindForUntracked DiffFindOptionsFlag = C.GIT_DIFF_FIND_FOR_UNTRACKED
+ DiffFindAll DiffFindOptionsFlag = C.GIT_DIFF_FIND_ALL
+ DiffFindIgnoreLeadingWhitespace DiffFindOptionsFlag = C.GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE
+ DiffFindIgnoreWhitespace DiffFindOptionsFlag = C.GIT_DIFF_FIND_IGNORE_WHITESPACE
+ DiffFindDontIgnoreWhitespace DiffFindOptionsFlag = C.GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE
+ DiffFindExactMatchOnly DiffFindOptionsFlag = C.GIT_DIFF_FIND_EXACT_MATCH_ONLY
+ DiffFindBreakRewritesForRenamesOnly DiffFindOptionsFlag = C.GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY
+ DiffFindRemoveUnmodified DiffFindOptionsFlag = C.GIT_DIFF_FIND_REMOVE_UNMODIFIED
+)
+
+//TODO implement git_diff_similarity_metric
+type DiffFindOptions struct {
+ Flags DiffFindOptionsFlag
+ RenameThreshold uint16
+ CopyThreshold uint16
+ RenameFromRewriteThreshold uint16
+ BreakRewriteThreshold uint16
+ RenameLimit uint
+}
+
+func DefaultDiffFindOptions() (DiffFindOptions, error) {
+ opts := C.git_diff_find_options{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_find_init_options(&opts, C.GIT_DIFF_FIND_OPTIONS_VERSION)
+ if ecode < 0 {
+ return DiffFindOptions{}, MakeGitError(ecode)
+ }
+
+ return DiffFindOptions{
+ Flags: DiffFindOptionsFlag(opts.flags),
+ RenameThreshold: uint16(opts.rename_threshold),
+ CopyThreshold: uint16(opts.copy_threshold),
+ RenameFromRewriteThreshold: uint16(opts.rename_from_rewrite_threshold),
+ BreakRewriteThreshold: uint16(opts.break_rewrite_threshold),
+ RenameLimit: uint(opts.rename_limit),
+ }, nil
+}
+
+var (
+ ErrDeltaSkip = errors.New("Skip delta")
+)
+
+type diffNotifyData struct {
+ Callback DiffNotifyCallback
+ Diff *Diff
+ Error error
+}
+
+//export diffNotifyCb
+func diffNotifyCb(_diff_so_far unsafe.Pointer, delta_to_add *C.git_diff_delta, matched_pathspec *C.char, handle unsafe.Pointer) int {
+ diff_so_far := (*C.git_diff)(_diff_so_far)
+
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*diffNotifyData)
+ if !ok {
+ panic("could not retrieve data for handle")
+ }
+
+ if data != nil {
+ if data.Diff == nil {
+ data.Diff = newDiffFromC(diff_so_far, nil)
+ }
+
+ err := data.Callback(data.Diff, diffDeltaFromC(delta_to_add), C.GoString(matched_pathspec))
+
+ if err == ErrDeltaSkip {
+ return 1
+ } else if err != nil {
+ data.Error = err
+ return -1
+ } else {
+ return 0
+ }
+ }
+ return 0
+}
+
+func diffOptionsToC(opts *DiffOptions) (copts *C.git_diff_options, notifyData *diffNotifyData) {
+ cpathspec := C.git_strarray{}
+ if opts != nil {
+ notifyData = &diffNotifyData{
+ Callback: opts.NotifyCallback,
+ }
+
+ if opts.Pathspec != nil {
+ cpathspec.count = C.size_t(len(opts.Pathspec))
+ cpathspec.strings = makeCStringsFromStrings(opts.Pathspec)
+ }
+
+ copts = &C.git_diff_options{
+ version: C.GIT_DIFF_OPTIONS_VERSION,
+ flags: C.uint32_t(opts.Flags),
+ ignore_submodules: C.git_submodule_ignore_t(opts.IgnoreSubmodules),
+ pathspec: cpathspec,
+ context_lines: C.uint32_t(opts.ContextLines),
+ interhunk_lines: C.uint32_t(opts.InterhunkLines),
+ id_abbrev: C.uint16_t(opts.IdAbbrev),
+ max_size: C.git_off_t(opts.MaxSize),
+ old_prefix: C.CString(opts.OldPrefix),
+ new_prefix: C.CString(opts.NewPrefix),
+ }
+
+ if opts.NotifyCallback != nil {
+ C._go_git_setup_diff_notify_callbacks(copts)
+ copts.payload = pointerHandles.Track(notifyData)
+ }
+ }
+ return
+}
+
+func freeDiffOptions(copts *C.git_diff_options) {
+ if copts != nil {
+ cpathspec := copts.pathspec
+ freeStrarray(&cpathspec)
+ C.free(unsafe.Pointer(copts.old_prefix))
+ C.free(unsafe.Pointer(copts.new_prefix))
+ if copts.payload != nil {
+ pointerHandles.Untrack(copts.payload)
+ }
+ }
+}
+
+func (v *Repository) DiffTreeToTree(oldTree, newTree *Tree, opts *DiffOptions) (*Diff, error) {
+ var diffPtr *C.git_diff
+ var oldPtr, newPtr *C.git_tree
+
+ if oldTree != nil {
+ oldPtr = oldTree.cast_ptr
+ }
+
+ if newTree != nil {
+ newPtr = newTree.cast_ptr
+ }
+
+ copts, notifyData := diffOptionsToC(opts)
+ defer freeDiffOptions(copts)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_tree_to_tree(&diffPtr, v.ptr, oldPtr, newPtr, copts)
+ runtime.KeepAlive(oldTree)
+ runtime.KeepAlive(newTree)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ if notifyData != nil && notifyData.Diff != nil {
+ return notifyData.Diff, nil
+ }
+ return newDiffFromC(diffPtr, v), nil
+}
+
+func (v *Repository) DiffTreeToWorkdir(oldTree *Tree, opts *DiffOptions) (*Diff, error) {
+ var diffPtr *C.git_diff
+ var oldPtr *C.git_tree
+
+ if oldTree != nil {
+ oldPtr = oldTree.cast_ptr
+ }
+
+ copts, notifyData := diffOptionsToC(opts)
+ defer freeDiffOptions(copts)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_tree_to_workdir(&diffPtr, v.ptr, oldPtr, copts)
+ runtime.KeepAlive(oldTree)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ if notifyData != nil && notifyData.Diff != nil {
+ return notifyData.Diff, nil
+ }
+ return newDiffFromC(diffPtr, v), nil
+}
+
+func (v *Repository) DiffTreeToIndex(oldTree *Tree, index *Index, opts *DiffOptions) (*Diff, error) {
+ var diffPtr *C.git_diff
+ var oldPtr *C.git_tree
+ var indexPtr *C.git_index
+
+ if oldTree != nil {
+ oldPtr = oldTree.cast_ptr
+ }
+
+ if index != nil {
+ indexPtr = index.ptr
+ }
+
+ copts, notifyData := diffOptionsToC(opts)
+ defer freeDiffOptions(copts)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_tree_to_index(&diffPtr, v.ptr, oldPtr, indexPtr, copts)
+ runtime.KeepAlive(oldTree)
+ runtime.KeepAlive(index)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ if notifyData != nil && notifyData.Diff != nil {
+ return notifyData.Diff, nil
+ }
+ return newDiffFromC(diffPtr, v), nil
+}
+
+func (v *Repository) DiffTreeToWorkdirWithIndex(oldTree *Tree, opts *DiffOptions) (*Diff, error) {
+ var diffPtr *C.git_diff
+ var oldPtr *C.git_tree
+
+ if oldTree != nil {
+ oldPtr = oldTree.cast_ptr
+ }
+
+ copts, notifyData := diffOptionsToC(opts)
+ defer freeDiffOptions(copts)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_tree_to_workdir_with_index(&diffPtr, v.ptr, oldPtr, copts)
+ runtime.KeepAlive(oldTree)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ if notifyData != nil && notifyData.Diff != nil {
+ return notifyData.Diff, nil
+ }
+ return newDiffFromC(diffPtr, v), nil
+}
+
+func (v *Repository) DiffIndexToWorkdir(index *Index, opts *DiffOptions) (*Diff, error) {
+ var diffPtr *C.git_diff
+ var indexPtr *C.git_index
+
+ if index != nil {
+ indexPtr = index.ptr
+ }
+
+ copts, notifyData := diffOptionsToC(opts)
+ defer freeDiffOptions(copts)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_index_to_workdir(&diffPtr, v.ptr, indexPtr, copts)
+ runtime.KeepAlive(index)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ if notifyData != nil && notifyData.Diff != nil {
+ return notifyData.Diff, nil
+ }
+ return newDiffFromC(diffPtr, v), nil
+}
+
+// DiffBlobs performs a diff between two arbitrary blobs. You can pass
+// whatever file names you'd like for them to appear as in the diff.
+func DiffBlobs(oldBlob *Blob, oldAsPath string, newBlob *Blob, newAsPath string, opts *DiffOptions, fileCallback DiffForEachFileCallback, detail DiffDetail) error {
+ data := &diffForEachData{
+ FileCallback: fileCallback,
+ }
+
+ intHunks := C.int(0)
+ if detail >= DiffDetailHunks {
+ intHunks = C.int(1)
+ }
+
+ intLines := C.int(0)
+ if detail >= DiffDetailLines {
+ intLines = C.int(1)
+ }
+
+ handle := pointerHandles.Track(data)
+ defer pointerHandles.Untrack(handle)
+
+ var oldBlobPtr, newBlobPtr *C.git_blob
+ if oldBlob != nil {
+ oldBlobPtr = oldBlob.cast_ptr
+ }
+ if newBlob != nil {
+ newBlobPtr = newBlob.cast_ptr
+ }
+
+ oldBlobPath := C.CString(oldAsPath)
+ defer C.free(unsafe.Pointer(oldBlobPath))
+ newBlobPath := C.CString(newAsPath)
+ defer C.free(unsafe.Pointer(newBlobPath))
+
+ copts, _ := diffOptionsToC(opts)
+ defer freeDiffOptions(copts)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C._go_git_diff_blobs(oldBlobPtr, oldBlobPath, newBlobPtr, newBlobPath, copts, 1, intHunks, intLines, handle)
+ runtime.KeepAlive(oldBlob)
+ runtime.KeepAlive(newBlob)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/features.go b/vendor/github.com/libgit2/git2go/features.go
new file mode 100644
index 000000000..f6474a061
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/features.go
@@ -0,0 +1,30 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+
+type Feature int
+
+const (
+ // libgit2 was built with threading support
+ FeatureThreads Feature = C.GIT_FEATURE_THREADS
+
+ // libgit2 was built with HTTPS support built-in
+ FeatureHttps Feature = C.GIT_FEATURE_HTTPS
+
+ // libgit2 was build with SSH support built-in
+ FeatureSsh Feature = C.GIT_FEATURE_SSH
+
+ // libgit2 was built with nanosecond support for files
+ FeatureNSec Feature = C.GIT_FEATURE_NSEC
+)
+
+// Features returns a bit-flag of Feature values indicating which features the
+// loaded libgit2 library has.
+func Features() Feature {
+ features := C.git_libgit2_features()
+
+ return Feature(features)
+}
diff --git a/vendor/github.com/libgit2/git2go/git.go b/vendor/github.com/libgit2/git2go/git.go
new file mode 100644
index 000000000..0925e45d8
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/git.go
@@ -0,0 +1,323 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/sys/openssl.h>
+*/
+import "C"
+import (
+ "bytes"
+ "encoding/hex"
+ "errors"
+ "runtime"
+ "strings"
+ "unsafe"
+)
+
+type ErrorClass int
+
+const (
+ ErrClassNone ErrorClass = C.GITERR_NONE
+ ErrClassNoMemory ErrorClass = C.GITERR_NOMEMORY
+ ErrClassOs ErrorClass = C.GITERR_OS
+ ErrClassInvalid ErrorClass = C.GITERR_INVALID
+ ErrClassReference ErrorClass = C.GITERR_REFERENCE
+ ErrClassZlib ErrorClass = C.GITERR_ZLIB
+ ErrClassRepository ErrorClass = C.GITERR_REPOSITORY
+ ErrClassConfig ErrorClass = C.GITERR_CONFIG
+ ErrClassRegex ErrorClass = C.GITERR_REGEX
+ ErrClassOdb ErrorClass = C.GITERR_ODB
+ ErrClassIndex ErrorClass = C.GITERR_INDEX
+ ErrClassObject ErrorClass = C.GITERR_OBJECT
+ ErrClassNet ErrorClass = C.GITERR_NET
+ ErrClassTag ErrorClass = C.GITERR_TAG
+ ErrClassTree ErrorClass = C.GITERR_TREE
+ ErrClassIndexer ErrorClass = C.GITERR_INDEXER
+ ErrClassSSL ErrorClass = C.GITERR_SSL
+ ErrClassSubmodule ErrorClass = C.GITERR_SUBMODULE
+ ErrClassThread ErrorClass = C.GITERR_THREAD
+ ErrClassStash ErrorClass = C.GITERR_STASH
+ ErrClassCheckout ErrorClass = C.GITERR_CHECKOUT
+ ErrClassFetchHead ErrorClass = C.GITERR_FETCHHEAD
+ ErrClassMerge ErrorClass = C.GITERR_MERGE
+ ErrClassSsh ErrorClass = C.GITERR_SSH
+ ErrClassFilter ErrorClass = C.GITERR_FILTER
+ ErrClassRevert ErrorClass = C.GITERR_REVERT
+ ErrClassCallback ErrorClass = C.GITERR_CALLBACK
+ ErrClassRebase ErrorClass = C.GITERR_REBASE
+)
+
+type ErrorCode int
+
+const (
+
+ // No error
+ ErrOk ErrorCode = C.GIT_OK
+
+ // Generic error
+ ErrGeneric ErrorCode = C.GIT_ERROR
+ // Requested object could not be found
+ ErrNotFound ErrorCode = C.GIT_ENOTFOUND
+ // Object exists preventing operation
+ ErrExists ErrorCode = C.GIT_EEXISTS
+ // More than one object matches
+ ErrAmbigious ErrorCode = C.GIT_EAMBIGUOUS
+ // Output buffer too short to hold data
+ ErrBuffs ErrorCode = C.GIT_EBUFS
+
+ // GIT_EUSER is a special error that is never generated by libgit2
+ // code. You can return it from a callback (e.g to stop an iteration)
+ // to know that it was generated by the callback and not by libgit2.
+ ErrUser ErrorCode = C.GIT_EUSER
+
+ // Operation not allowed on bare repository
+ ErrBareRepo ErrorCode = C.GIT_EBAREREPO
+ // HEAD refers to branch with no commits
+ ErrUnbornBranch ErrorCode = C.GIT_EUNBORNBRANCH
+ // Merge in progress prevented operation
+ ErrUnmerged ErrorCode = C.GIT_EUNMERGED
+ // Reference was not fast-forwardable
+ ErrNonFastForward ErrorCode = C.GIT_ENONFASTFORWARD
+ // Name/ref spec was not in a valid format
+ ErrInvalidSpec ErrorCode = C.GIT_EINVALIDSPEC
+ // Checkout conflicts prevented operation
+ ErrConflict ErrorCode = C.GIT_ECONFLICT
+ // Lock file prevented operation
+ ErrLocked ErrorCode = C.GIT_ELOCKED
+ // Reference value does not match expected
+ ErrModified ErrorCode = C.GIT_EMODIFIED
+ // Authentication failed
+ ErrAuth ErrorCode = C.GIT_EAUTH
+ // Server certificate is invalid
+ ErrCertificate ErrorCode = C.GIT_ECERTIFICATE
+ // Patch/merge has already been applied
+ ErrApplied ErrorCode = C.GIT_EAPPLIED
+ // The requested peel operation is not possible
+ ErrPeel ErrorCode = C.GIT_EPEEL
+ // Unexpected EOF
+ ErrEOF ErrorCode = C.GIT_EEOF
+ // Uncommitted changes in index prevented operation
+ ErrUncommitted ErrorCode = C.GIT_EUNCOMMITTED
+ // The operation is not valid for a directory
+ ErrDirectory ErrorCode = C.GIT_EDIRECTORY
+ // A merge conflict exists and cannot continue
+ ErrMergeConflict ErrorCode = C.GIT_EMERGECONFLICT
+
+ // Internal only
+ ErrPassthrough ErrorCode = C.GIT_PASSTHROUGH
+ // Signals end of iteration with iterator
+ ErrIterOver ErrorCode = C.GIT_ITEROVER
+)
+
+var (
+ ErrInvalid = errors.New("Invalid state for operation")
+)
+
+var pointerHandles *HandleList
+
+func init() {
+ pointerHandles = NewHandleList()
+
+ C.git_libgit2_init()
+
+ // Due to the multithreaded nature of Go and its interaction with
+ // calling C functions, we cannot work with a library that was not built
+ // with multi-threading support. The most likely outcome is a segfault
+ // or panic at an incomprehensible time, so let's make it easy by
+ // panicking right here.
+ if Features()&FeatureThreads == 0 {
+ panic("libgit2 was not built with threading support")
+ }
+
+ // This is not something we should be doing, as we may be
+ // stomping all over someone else's setup. The user should do
+ // this themselves or use some binding/wrapper which does it
+ // in such a way that they can be sure they're the only ones
+ // setting it up.
+ C.git_openssl_set_locking()
+}
+
+// Oid represents the id for a Git object.
+type Oid [20]byte
+
+func newOidFromC(coid *C.git_oid) *Oid {
+ if coid == nil {
+ return nil
+ }
+
+ oid := new(Oid)
+ copy(oid[0:20], C.GoBytes(unsafe.Pointer(coid), 20))
+ return oid
+}
+
+func NewOidFromBytes(b []byte) *Oid {
+ oid := new(Oid)
+ copy(oid[0:20], b[0:20])
+ return oid
+}
+
+func (oid *Oid) toC() *C.git_oid {
+ return (*C.git_oid)(unsafe.Pointer(oid))
+}
+
+func NewOid(s string) (*Oid, error) {
+ if len(s) > C.GIT_OID_HEXSZ {
+ return nil, errors.New("string is too long for oid")
+ }
+
+ o := new(Oid)
+
+ slice, error := hex.DecodeString(s)
+ if error != nil {
+ return nil, error
+ }
+
+ if len(slice) != 20 {
+ return nil, &GitError{"Invalid Oid", ErrClassNone, ErrGeneric}
+ }
+
+ copy(o[:], slice[:20])
+ return o, nil
+}
+
+func (oid *Oid) String() string {
+ return hex.EncodeToString(oid[:])
+}
+
+func (oid *Oid) Cmp(oid2 *Oid) int {
+ return bytes.Compare(oid[:], oid2[:])
+}
+
+func (oid *Oid) Copy() *Oid {
+ ret := new(Oid)
+ copy(ret[:], oid[:])
+ return ret
+}
+
+func (oid *Oid) Equal(oid2 *Oid) bool {
+ return bytes.Equal(oid[:], oid2[:])
+}
+
+func (oid *Oid) IsZero() bool {
+ for _, a := range oid {
+ if a != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+func (oid *Oid) NCmp(oid2 *Oid, n uint) int {
+ return bytes.Compare(oid[:n], oid2[:n])
+}
+
+func ShortenOids(ids []*Oid, minlen int) (int, error) {
+ shorten := C.git_oid_shorten_new(C.size_t(minlen))
+ if shorten == nil {
+ panic("Out of memory")
+ }
+ defer C.git_oid_shorten_free(shorten)
+
+ var ret C.int
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ for _, id := range ids {
+ buf := make([]byte, 41)
+ C.git_oid_fmt((*C.char)(unsafe.Pointer(&buf[0])), id.toC())
+ buf[40] = 0
+ ret = C.git_oid_shorten_add(shorten, (*C.char)(unsafe.Pointer(&buf[0])))
+ if ret < 0 {
+ return int(ret), MakeGitError(ret)
+ }
+ }
+ runtime.KeepAlive(ids)
+ return int(ret), nil
+}
+
+type GitError struct {
+ Message string
+ Class ErrorClass
+ Code ErrorCode
+}
+
+func (e GitError) Error() string {
+ return e.Message
+}
+
+func IsErrorClass(err error, c ErrorClass) bool {
+
+ if err == nil {
+ return false
+ }
+ if gitError, ok := err.(*GitError); ok {
+ return gitError.Class == c
+ }
+ return false
+}
+
+func IsErrorCode(err error, c ErrorCode) bool {
+ if err == nil {
+ return false
+ }
+ if gitError, ok := err.(*GitError); ok {
+ return gitError.Code == c
+ }
+ return false
+}
+
+func MakeGitError(errorCode C.int) error {
+
+ var errMessage string
+ var errClass ErrorClass
+ if errorCode != C.GIT_ITEROVER {
+ err := C.giterr_last()
+ if err != nil {
+ errMessage = C.GoString(err.message)
+ errClass = ErrorClass(err.klass)
+ } else {
+ errClass = ErrClassInvalid
+ }
+ }
+ return &GitError{errMessage, errClass, ErrorCode(errorCode)}
+}
+
+func MakeGitError2(err int) error {
+ return MakeGitError(C.int(err))
+}
+
+func cbool(b bool) C.int {
+ if b {
+ return C.int(1)
+ }
+ return C.int(0)
+}
+
+func ucbool(b bool) C.uint {
+ if b {
+ return C.uint(1)
+ }
+ return C.uint(0)
+}
+
+func Discover(start string, across_fs bool, ceiling_dirs []string) (string, error) {
+ ceildirs := C.CString(strings.Join(ceiling_dirs, string(C.GIT_PATH_LIST_SEPARATOR)))
+ defer C.free(unsafe.Pointer(ceildirs))
+
+ cstart := C.CString(start)
+ defer C.free(unsafe.Pointer(cstart))
+
+ var buf C.git_buf
+ defer C.git_buf_free(&buf)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_discover(&buf, cstart, cbool(across_fs), ceildirs)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+
+ return C.GoString(buf.ptr), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/git_dynamic.go b/vendor/github.com/libgit2/git2go/git_dynamic.go
new file mode 100644
index 000000000..0a977e876
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/git_dynamic.go
@@ -0,0 +1,14 @@
+// +build !static
+
+package git
+
+/*
+#include <git2.h>
+#cgo pkg-config: libgit2
+
+#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 27
+# error "Invalid libgit2 version; this git2go supports libgit2 v0.27"
+#endif
+
+*/
+import "C"
diff --git a/vendor/github.com/libgit2/git2go/git_static.go b/vendor/github.com/libgit2/git2go/git_static.go
new file mode 100644
index 000000000..63037348a
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/git_static.go
@@ -0,0 +1,17 @@
+// +build static
+
+package git
+
+/*
+#cgo CFLAGS: -I${SRCDIR}/vendor/libgit2/include
+#cgo LDFLAGS: -L${SRCDIR}/vendor/libgit2/build/ -lgit2
+#cgo windows LDFLAGS: -lwinhttp
+#cgo !windows pkg-config: --static ${SRCDIR}/vendor/libgit2/build/libgit2.pc
+#include <git2.h>
+
+#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 27
+# error "Invalid libgit2 version; this git2go supports libgit2 v0.27"
+#endif
+
+*/
+import "C"
diff --git a/vendor/github.com/libgit2/git2go/graph.go b/vendor/github.com/libgit2/git2go/graph.go
new file mode 100644
index 000000000..688818c71
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/graph.go
@@ -0,0 +1,42 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+)
+
+func (repo *Repository) DescendantOf(commit, ancestor *Oid) (bool, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_graph_descendant_of(repo.ptr, commit.toC(), ancestor.toC())
+ runtime.KeepAlive(repo)
+ runtime.KeepAlive(commit)
+ runtime.KeepAlive(ancestor)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+
+ return (ret > 0), nil
+}
+
+func (repo *Repository) AheadBehind(local, upstream *Oid) (ahead, behind int, err error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var aheadT C.size_t
+ var behindT C.size_t
+
+ ret := C.git_graph_ahead_behind(&aheadT, &behindT, repo.ptr, local.toC(), upstream.toC())
+ runtime.KeepAlive(repo)
+ runtime.KeepAlive(local)
+ runtime.KeepAlive(upstream)
+ if ret < 0 {
+ return 0, 0, MakeGitError(ret)
+ }
+
+ return int(aheadT), int(behindT), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/handles.go b/vendor/github.com/libgit2/git2go/handles.go
new file mode 100644
index 000000000..d27d3c353
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/handles.go
@@ -0,0 +1,57 @@
+package git
+
+/*
+#include <stdlib.h>
+*/
+import "C"
+import (
+ "fmt"
+ "sync"
+ "unsafe"
+)
+
+type HandleList struct {
+ sync.RWMutex
+ // stores the Go pointers
+ handles map[unsafe.Pointer]interface{}
+}
+
+func NewHandleList() *HandleList {
+ return &HandleList{
+ handles: make(map[unsafe.Pointer]interface{}),
+ }
+}
+
+// Track adds the given pointer to the list of pointers to track and
+// returns a pointer value which can be passed to C as an opaque
+// pointer.
+func (v *HandleList) Track(pointer interface{}) unsafe.Pointer {
+ handle := C.malloc(1)
+
+ v.Lock()
+ v.handles[handle] = pointer
+ v.Unlock()
+
+ return handle
+}
+
+// Untrack stops tracking the pointer given by the handle
+func (v *HandleList) Untrack(handle unsafe.Pointer) {
+ v.Lock()
+ delete(v.handles, handle)
+ C.free(handle)
+ v.Unlock()
+}
+
+// Get retrieves the pointer from the given handle
+func (v *HandleList) Get(handle unsafe.Pointer) interface{} {
+ v.RLock()
+ defer v.RUnlock()
+
+ ptr, ok := v.handles[handle]
+ if !ok {
+ panic(fmt.Sprintf("invalid pointer handle: %p", handle))
+ }
+
+ return ptr
+}
diff --git a/vendor/github.com/libgit2/git2go/ignore.go b/vendor/github.com/libgit2/git2go/ignore.go
new file mode 100644
index 000000000..c698de11a
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/ignore.go
@@ -0,0 +1,54 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+func (v *Repository) AddIgnoreRule(rules string) error {
+ crules := C.CString(rules)
+ defer C.free(unsafe.Pointer(crules))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_ignore_add_rule(v.ptr, crules)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (v *Repository) ClearInternalIgnoreRules() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_ignore_clear_internal_rules(v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (v *Repository) IsPathIgnored(path string) (bool, error) {
+ var ignored C.int
+
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_ignore_path_is_ignored(&ignored, v.ptr, cpath)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+ return ignored == 1, nil
+}
diff --git a/vendor/github.com/libgit2/git2go/index.go b/vendor/github.com/libgit2/git2go/index.go
new file mode 100644
index 000000000..5106516ce
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/index.go
@@ -0,0 +1,586 @@
+package git
+
+/*
+#include <git2.h>
+
+extern int _go_git_index_add_all(git_index*, const git_strarray*, unsigned int, void*);
+extern int _go_git_index_update_all(git_index*, const git_strarray*, void*);
+extern int _go_git_index_remove_all(git_index*, const git_strarray*, void*);
+
+*/
+import "C"
+import (
+ "fmt"
+ "runtime"
+ "unsafe"
+)
+
+type IndexMatchedPathCallback func(string, string) int
+
+type IndexAddOpts uint
+
+const (
+ IndexAddDefault IndexAddOpts = C.GIT_INDEX_ADD_DEFAULT
+ IndexAddForce IndexAddOpts = C.GIT_INDEX_ADD_FORCE
+ IndexAddDisablePathspecMatch IndexAddOpts = C.GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH
+ IndexAddCheckPathspec IndexAddOpts = C.GIT_INDEX_ADD_CHECK_PATHSPEC
+)
+
+type IndexStageOpts int
+
+const (
+ // IndexStageAny matches any index stage.
+ //
+ // Some index APIs take a stage to match; pass this value to match
+ // any entry matching the path regardless of stage.
+ IndexStageAny IndexStageOpts = C.GIT_INDEX_STAGE_ANY
+ // IndexStageNormal is a normal staged file in the index.
+ IndexStageNormal IndexStageOpts = C.GIT_INDEX_STAGE_NORMAL
+ // IndexStageAncestor is the ancestor side of a conflict.
+ IndexStageAncestor IndexStageOpts = C.GIT_INDEX_STAGE_ANCESTOR
+ // IndexStageOurs is the "ours" side of a conflict.
+ IndexStageOurs IndexStageOpts = C.GIT_INDEX_STAGE_OURS
+ // IndexStageTheirs is the "theirs" side of a conflict.
+ IndexStageTheirs IndexStageOpts = C.GIT_INDEX_STAGE_THEIRS
+)
+
+type Index struct {
+ ptr *C.git_index
+ repo *Repository
+}
+
+type IndexTime struct {
+ seconds int32
+ nanoseconds uint32
+}
+
+type IndexEntry struct {
+ Ctime IndexTime
+ Mtime IndexTime
+ Mode Filemode
+ Uid uint32
+ Gid uint32
+ Size uint32
+ Id *Oid
+ Path string
+}
+
+func newIndexEntryFromC(entry *C.git_index_entry) *IndexEntry {
+ if entry == nil {
+ return nil
+ }
+ return &IndexEntry{
+ IndexTime{int32(entry.ctime.seconds), uint32(entry.ctime.nanoseconds)},
+ IndexTime{int32(entry.mtime.seconds), uint32(entry.mtime.nanoseconds)},
+ Filemode(entry.mode),
+ uint32(entry.uid),
+ uint32(entry.gid),
+ uint32(entry.file_size),
+ newOidFromC(&entry.id),
+ C.GoString(entry.path),
+ }
+}
+
+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.mode = C.uint32_t(source.Mode)
+ dest.uid = C.uint32_t(source.Uid)
+ dest.gid = C.uint32_t(source.Gid)
+ dest.file_size = C.uint32_t(source.Size)
+ dest.id = *source.Id.toC()
+ dest.path = C.CString(source.Path)
+}
+
+func freeCIndexEntry(entry *C.git_index_entry) {
+ C.free(unsafe.Pointer(entry.path))
+}
+
+func newIndexFromC(ptr *C.git_index, repo *Repository) *Index {
+ idx := &Index{ptr, repo}
+ runtime.SetFinalizer(idx, (*Index).Free)
+ return idx
+}
+
+// NewIndex allocates a new index. It won't be associated with any
+// file on the filesystem or repository
+func NewIndex() (*Index, error) {
+ var ptr *C.git_index
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if err := C.git_index_new(&ptr); err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return newIndexFromC(ptr, nil), nil
+}
+
+// OpenIndex creates a new index at the given path. If the file does
+// not exist it will be created when Write() is called.
+func OpenIndex(path string) (*Index, error) {
+ var ptr *C.git_index
+
+ var cpath = C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if err := C.git_index_open(&ptr, cpath); err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return newIndexFromC(ptr, nil), nil
+}
+
+// Path returns the index' path on disk or an empty string if it
+// exists only in memory.
+func (v *Index) Path() string {
+ ret := C.GoString(C.git_index_path(v.ptr))
+ runtime.KeepAlive(v)
+ return ret
+}
+
+// Add adds or replaces the given entry to the index, making a copy of
+// the data
+func (v *Index) Add(entry *IndexEntry) error {
+ var centry C.git_index_entry
+
+ populateCIndexEntry(entry, &centry)
+ defer freeCIndexEntry(&centry)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_index_add(v.ptr, &centry)
+ runtime.KeepAlive(v)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
+
+func (v *Index) AddByPath(path string) error {
+ cstr := C.CString(path)
+ defer C.free(unsafe.Pointer(cstr))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_index_add_bypath(v.ptr, cstr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (v *Index) AddAll(pathspecs []string, flags IndexAddOpts, callback IndexMatchedPathCallback) error {
+ cpathspecs := C.git_strarray{}
+ cpathspecs.count = C.size_t(len(pathspecs))
+ cpathspecs.strings = makeCStringsFromStrings(pathspecs)
+ defer freeStrarray(&cpathspecs)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var handle unsafe.Pointer
+ if callback != nil {
+ handle = pointerHandles.Track(callback)
+ defer pointerHandles.Untrack(handle)
+ }
+
+ ret := C._go_git_index_add_all(
+ v.ptr,
+ &cpathspecs,
+ C.uint(flags),
+ handle,
+ )
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (v *Index) UpdateAll(pathspecs []string, callback IndexMatchedPathCallback) error {
+ cpathspecs := C.git_strarray{}
+ cpathspecs.count = C.size_t(len(pathspecs))
+ cpathspecs.strings = makeCStringsFromStrings(pathspecs)
+ defer freeStrarray(&cpathspecs)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var handle unsafe.Pointer
+ if callback != nil {
+ handle = pointerHandles.Track(callback)
+ defer pointerHandles.Untrack(handle)
+ }
+
+ ret := C._go_git_index_update_all(
+ v.ptr,
+ &cpathspecs,
+ handle,
+ )
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (v *Index) RemoveAll(pathspecs []string, callback IndexMatchedPathCallback) error {
+ cpathspecs := C.git_strarray{}
+ cpathspecs.count = C.size_t(len(pathspecs))
+ cpathspecs.strings = makeCStringsFromStrings(pathspecs)
+ defer freeStrarray(&cpathspecs)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var handle unsafe.Pointer
+ if callback != nil {
+ handle = pointerHandles.Track(callback)
+ defer pointerHandles.Untrack(handle)
+ }
+
+ ret := C._go_git_index_remove_all(
+ v.ptr,
+ &cpathspecs,
+ handle,
+ )
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+//export indexMatchedPathCallback
+func indexMatchedPathCallback(cPath, cMatchedPathspec *C.char, payload unsafe.Pointer) int {
+ if callback, ok := pointerHandles.Get(payload).(IndexMatchedPathCallback); ok {
+ return callback(C.GoString(cPath), C.GoString(cMatchedPathspec))
+ } else {
+ panic("invalid matched path callback")
+ }
+}
+
+func (v *Index) RemoveByPath(path string) error {
+ cstr := C.CString(path)
+ defer C.free(unsafe.Pointer(cstr))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_index_remove_bypath(v.ptr, cstr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ 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))
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (v *Index) WriteTreeTo(repo *Repository) (*Oid, error) {
+ oid := new(Oid)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_index_write_tree_to(oid.toC(), v.ptr, repo.ptr)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(repo)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return oid, nil
+}
+
+// ReadTree replaces the contents of the index with those of the given
+// tree
+func (v *Index) ReadTree(tree *Tree) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_index_read_tree(v.ptr, tree.cast_ptr)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(tree)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (v *Index) WriteTree() (*Oid, error) {
+ oid := new(Oid)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_index_write_tree(oid.toC(), v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return oid, nil
+}
+
+func (v *Index) Write() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_index_write(v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (v *Index) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_index_free(v.ptr)
+}
+
+func (v *Index) EntryCount() uint {
+ ret := uint(C.git_index_entrycount(v.ptr))
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Index) EntryByIndex(index uint) (*IndexEntry, error) {
+ centry := C.git_index_get_byindex(v.ptr, C.size_t(index))
+ if centry == nil {
+ return nil, fmt.Errorf("Index out of Bounds")
+ }
+ ret := newIndexEntryFromC(centry)
+ runtime.KeepAlive(v)
+ return ret, nil
+}
+
+func (v *Index) EntryByPath(path string, stage int) (*IndexEntry, error) {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ centry := C.git_index_get_bypath(v.ptr, cpath, C.int(stage))
+ if centry == nil {
+ return nil, MakeGitError(C.GIT_ENOTFOUND)
+ }
+ ret := newIndexEntryFromC(centry)
+ runtime.KeepAlive(v)
+ return ret, nil
+}
+
+func (v *Index) Find(path string) (uint, error) {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var pos C.size_t
+ ret := C.git_index_find(&pos, v.ptr, cpath)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return uint(0), MakeGitError(ret)
+ }
+ return uint(pos), nil
+}
+
+func (v *Index) FindPrefix(prefix string) (uint, error) {
+ cprefix := C.CString(prefix)
+ defer C.free(unsafe.Pointer(cprefix))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var pos C.size_t
+ ret := C.git_index_find_prefix(&pos, v.ptr, cprefix)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return uint(0), MakeGitError(ret)
+ }
+ return uint(pos), nil
+}
+
+func (v *Index) HasConflicts() bool {
+ ret := C.git_index_has_conflicts(v.ptr) != 0
+ runtime.KeepAlive(v)
+ return ret
+}
+
+// FIXME: this might return an error
+func (v *Index) CleanupConflicts() {
+ C.git_index_conflict_cleanup(v.ptr)
+ runtime.KeepAlive(v)
+}
+
+func (v *Index) AddConflict(ancestor *IndexEntry, our *IndexEntry, their *IndexEntry) error {
+
+ var cancestor *C.git_index_entry
+ var cour *C.git_index_entry
+ var ctheir *C.git_index_entry
+
+ if ancestor != nil {
+ cancestor = &C.git_index_entry{}
+ populateCIndexEntry(ancestor, cancestor)
+ defer freeCIndexEntry(cancestor)
+ }
+
+ if our != nil {
+ cour = &C.git_index_entry{}
+ populateCIndexEntry(our, cour)
+ defer freeCIndexEntry(cour)
+ }
+
+ if their != nil {
+ ctheir = &C.git_index_entry{}
+ populateCIndexEntry(their, ctheir)
+ defer freeCIndexEntry(ctheir)
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_index_conflict_add(v.ptr, cancestor, cour, ctheir)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(ancestor)
+ runtime.KeepAlive(our)
+ runtime.KeepAlive(their)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+type IndexConflict struct {
+ Ancestor *IndexEntry
+ Our *IndexEntry
+ Their *IndexEntry
+}
+
+func (v *Index) GetConflict(path string) (IndexConflict, error) {
+
+ var cancestor *C.git_index_entry
+ var cour *C.git_index_entry
+ var ctheir *C.git_index_entry
+
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_index_conflict_get(&cancestor, &cour, &ctheir, v.ptr, cpath)
+ if ecode < 0 {
+ return IndexConflict{}, MakeGitError(ecode)
+ }
+ ret := IndexConflict{
+ Ancestor: newIndexEntryFromC(cancestor),
+ Our: newIndexEntryFromC(cour),
+ Their: newIndexEntryFromC(ctheir),
+ }
+ runtime.KeepAlive(v)
+ return ret, nil
+}
+
+func (v *Index) RemoveConflict(path string) error {
+
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_index_conflict_remove(v.ptr, cpath)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+type IndexConflictIterator struct {
+ ptr *C.git_index_conflict_iterator
+ index *Index
+}
+
+func newIndexConflictIteratorFromC(index *Index, ptr *C.git_index_conflict_iterator) *IndexConflictIterator {
+ i := &IndexConflictIterator{ptr: ptr, index: index}
+ runtime.SetFinalizer(i, (*IndexConflictIterator).Free)
+ return i
+}
+
+func (v *IndexConflictIterator) Index() *Index {
+ return v.index
+}
+
+func (v *IndexConflictIterator) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_index_conflict_iterator_free(v.ptr)
+}
+
+func (v *Index) ConflictIterator() (*IndexConflictIterator, error) {
+ var i *C.git_index_conflict_iterator
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_index_conflict_iterator_new(&i, v.ptr)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ return newIndexConflictIteratorFromC(v, i), nil
+}
+
+func (v *IndexConflictIterator) Next() (IndexConflict, error) {
+ var cancestor *C.git_index_entry
+ var cour *C.git_index_entry
+ var ctheir *C.git_index_entry
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_index_conflict_next(&cancestor, &cour, &ctheir, v.ptr)
+ if ecode < 0 {
+ return IndexConflict{}, MakeGitError(ecode)
+ }
+ ret := IndexConflict{
+ Ancestor: newIndexEntryFromC(cancestor),
+ Our: newIndexEntryFromC(cour),
+ Their: newIndexEntryFromC(ctheir),
+ }
+ runtime.KeepAlive(v)
+ return ret, nil
+}
diff --git a/vendor/github.com/libgit2/git2go/merge.go b/vendor/github.com/libgit2/git2go/merge.go
new file mode 100644
index 000000000..adc521a2b
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/merge.go
@@ -0,0 +1,441 @@
+package git
+
+/*
+#include <git2.h>
+
+extern git_annotated_commit** _go_git_make_merge_head_array(size_t len);
+extern void _go_git_annotated_commit_array_set(git_annotated_commit** array, git_annotated_commit* ptr, size_t n);
+extern git_annotated_commit* _go_git_annotated_commit_array_get(git_annotated_commit** array, size_t n);
+extern int _go_git_merge_file(git_merge_file_result*, char*, size_t, char*, unsigned int, char*, size_t, char*, unsigned int, char*, size_t, char*, unsigned int, git_merge_file_options*);
+
+*/
+import "C"
+import (
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+type AnnotatedCommit struct {
+ ptr *C.git_annotated_commit
+ r *Repository
+}
+
+func newAnnotatedCommitFromC(ptr *C.git_annotated_commit, r *Repository) *AnnotatedCommit {
+ mh := &AnnotatedCommit{ptr: ptr, r: r}
+ runtime.SetFinalizer(mh, (*AnnotatedCommit).Free)
+ return mh
+}
+
+func (mh *AnnotatedCommit) Free() {
+ runtime.SetFinalizer(mh, nil)
+ C.git_annotated_commit_free(mh.ptr)
+}
+
+func (r *Repository) AnnotatedCommitFromFetchHead(branchName string, remoteURL string, oid *Oid) (*AnnotatedCommit, error) {
+ cbranchName := C.CString(branchName)
+ defer C.free(unsafe.Pointer(cbranchName))
+
+ cremoteURL := C.CString(remoteURL)
+ defer C.free(unsafe.Pointer(cremoteURL))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_annotated_commit
+ ret := C.git_annotated_commit_from_fetchhead(&ptr, r.ptr, cbranchName, cremoteURL, oid.toC())
+ runtime.KeepAlive(oid)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newAnnotatedCommitFromC(ptr, r), nil
+}
+
+func (r *Repository) LookupAnnotatedCommit(oid *Oid) (*AnnotatedCommit, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_annotated_commit
+ ret := C.git_annotated_commit_lookup(&ptr, r.ptr, oid.toC())
+ runtime.KeepAlive(oid)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newAnnotatedCommitFromC(ptr, r), nil
+}
+
+func (r *Repository) AnnotatedCommitFromRef(ref *Reference) (*AnnotatedCommit, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_annotated_commit
+ ret := C.git_annotated_commit_from_ref(&ptr, r.ptr, ref.ptr)
+ runtime.KeepAlive(r)
+ runtime.KeepAlive(ref)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newAnnotatedCommitFromC(ptr, r), nil
+}
+
+type MergeTreeFlag int
+
+const (
+ // Detect renames that occur between the common ancestor and the "ours"
+ // side or the common ancestor and the "theirs" side. This will enable
+ // the ability to merge between a modified and renamed file.
+ MergeTreeFindRenames MergeTreeFlag = C.GIT_MERGE_FIND_RENAMES
+ // If a conflict occurs, exit immediately instead of attempting to
+ // continue resolving conflicts. The merge operation will fail with
+ // GIT_EMERGECONFLICT and no index will be returned.
+ MergeTreeFailOnConflict MergeTreeFlag = C.GIT_MERGE_FAIL_ON_CONFLICT
+)
+
+type MergeOptions struct {
+ Version uint
+ TreeFlags MergeTreeFlag
+
+ RenameThreshold uint
+ TargetLimit uint
+ FileFavor MergeFileFavor
+
+ //TODO: Diff similarity metric
+}
+
+func mergeOptionsFromC(opts *C.git_merge_options) MergeOptions {
+ return MergeOptions{
+ Version: uint(opts.version),
+ TreeFlags: MergeTreeFlag(opts.flags),
+ RenameThreshold: uint(opts.rename_threshold),
+ TargetLimit: uint(opts.target_limit),
+ FileFavor: MergeFileFavor(opts.file_favor),
+ }
+}
+
+func DefaultMergeOptions() (MergeOptions, error) {
+ opts := C.git_merge_options{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_merge_init_options(&opts, C.GIT_MERGE_OPTIONS_VERSION)
+ if ecode < 0 {
+ return MergeOptions{}, MakeGitError(ecode)
+ }
+ return mergeOptionsFromC(&opts), nil
+}
+
+func (mo *MergeOptions) toC() *C.git_merge_options {
+ if mo == nil {
+ return nil
+ }
+ return &C.git_merge_options{
+ version: C.uint(mo.Version),
+ flags: C.git_merge_flag_t(mo.TreeFlags),
+ rename_threshold: C.uint(mo.RenameThreshold),
+ target_limit: C.uint(mo.TargetLimit),
+ file_favor: C.git_merge_file_favor_t(mo.FileFavor),
+ }
+}
+
+type MergeFileFavor int
+
+const (
+ MergeFileFavorNormal MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_NORMAL
+ MergeFileFavorOurs MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_OURS
+ MergeFileFavorTheirs MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_THEIRS
+ MergeFileFavorUnion MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_UNION
+)
+
+func (r *Repository) Merge(theirHeads []*AnnotatedCommit, mergeOptions *MergeOptions, checkoutOptions *CheckoutOpts) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cMergeOpts := mergeOptions.toC()
+ cCheckoutOpts := checkoutOptions.toC()
+ defer freeCheckoutOpts(cCheckoutOpts)
+
+ gmerge_head_array := make([]*C.git_annotated_commit, len(theirHeads))
+ for i := 0; i < len(theirHeads); i++ {
+ gmerge_head_array[i] = theirHeads[i].ptr
+ }
+ ptr := unsafe.Pointer(&gmerge_head_array[0])
+ err := C.git_merge(r.ptr, (**C.git_annotated_commit)(ptr), C.size_t(len(theirHeads)), cMergeOpts, cCheckoutOpts)
+ runtime.KeepAlive(theirHeads)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+ return nil
+}
+
+type MergeAnalysis int
+
+const (
+ MergeAnalysisNone MergeAnalysis = C.GIT_MERGE_ANALYSIS_NONE
+ MergeAnalysisNormal MergeAnalysis = C.GIT_MERGE_ANALYSIS_NORMAL
+ MergeAnalysisUpToDate MergeAnalysis = C.GIT_MERGE_ANALYSIS_UP_TO_DATE
+ MergeAnalysisFastForward MergeAnalysis = C.GIT_MERGE_ANALYSIS_FASTFORWARD
+ MergeAnalysisUnborn MergeAnalysis = C.GIT_MERGE_ANALYSIS_UNBORN
+)
+
+type MergePreference int
+
+const (
+ MergePreferenceNone MergePreference = C.GIT_MERGE_PREFERENCE_NONE
+ MergePreferenceNoFastForward MergePreference = C.GIT_MERGE_PREFERENCE_NO_FASTFORWARD
+ MergePreferenceFastForwardOnly MergePreference = C.GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY
+)
+
+// MergeAnalysis returns the possible actions which could be taken by
+// a 'git-merge' command. There may be multiple answers, so the first
+// return value is a bitmask of MergeAnalysis values.
+func (r *Repository) MergeAnalysis(theirHeads []*AnnotatedCommit) (MergeAnalysis, MergePreference, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ gmerge_head_array := make([]*C.git_annotated_commit, len(theirHeads))
+ for i := 0; i < len(theirHeads); i++ {
+ gmerge_head_array[i] = theirHeads[i].ptr
+ }
+ ptr := unsafe.Pointer(&gmerge_head_array[0])
+ var analysis C.git_merge_analysis_t
+ var preference C.git_merge_preference_t
+ err := C.git_merge_analysis(&analysis, &preference, r.ptr, (**C.git_annotated_commit)(ptr), C.size_t(len(theirHeads)))
+ runtime.KeepAlive(theirHeads)
+ if err < 0 {
+ return MergeAnalysisNone, MergePreferenceNone, MakeGitError(err)
+ }
+ return MergeAnalysis(analysis), MergePreference(preference), nil
+
+}
+
+func (r *Repository) MergeCommits(ours *Commit, theirs *Commit, options *MergeOptions) (*Index, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ copts := options.toC()
+
+ var ptr *C.git_index
+ ret := C.git_merge_commits(&ptr, r.ptr, ours.cast_ptr, theirs.cast_ptr, copts)
+ runtime.KeepAlive(ours)
+ runtime.KeepAlive(theirs)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newIndexFromC(ptr, r), nil
+}
+
+func (r *Repository) MergeTrees(ancestor *Tree, ours *Tree, theirs *Tree, options *MergeOptions) (*Index, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ copts := options.toC()
+
+ var ancestor_ptr *C.git_tree
+ if ancestor != nil {
+ ancestor_ptr = ancestor.cast_ptr
+ }
+ var ptr *C.git_index
+ ret := C.git_merge_trees(&ptr, r.ptr, ancestor_ptr, ours.cast_ptr, theirs.cast_ptr, copts)
+ runtime.KeepAlive(ancestor)
+ runtime.KeepAlive(ours)
+ runtime.KeepAlive(theirs)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newIndexFromC(ptr, r), nil
+}
+
+func (r *Repository) MergeBase(one *Oid, two *Oid) (*Oid, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var oid C.git_oid
+ ret := C.git_merge_base(&oid, r.ptr, one.toC(), two.toC())
+ runtime.KeepAlive(one)
+ runtime.KeepAlive(two)
+ runtime.KeepAlive(r)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newOidFromC(&oid), nil
+}
+
+// MergeBases retrieves the list of merge bases between two commits.
+//
+// If none are found, an empty slice is returned and the error is set
+// approprately
+func (r *Repository) MergeBases(one, two *Oid) ([]*Oid, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var coids C.git_oidarray
+ ret := C.git_merge_bases(&coids, r.ptr, one.toC(), two.toC())
+ runtime.KeepAlive(one)
+ runtime.KeepAlive(two)
+ if ret < 0 {
+ return make([]*Oid, 0), MakeGitError(ret)
+ }
+
+ oids := make([]*Oid, coids.count)
+ hdr := reflect.SliceHeader{
+ Data: uintptr(unsafe.Pointer(coids.ids)),
+ Len: int(coids.count),
+ Cap: int(coids.count),
+ }
+
+ goSlice := *(*[]C.git_oid)(unsafe.Pointer(&hdr))
+
+ for i, cid := range goSlice {
+ oids[i] = newOidFromC(&cid)
+ }
+
+ return oids, nil
+}
+
+//TODO: int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]);
+//TODO: GIT_EXTERN(int) git_merge_base_octopus(git_oid *out,git_repository *repo,size_t length,const git_oid input_array[]);
+
+type MergeFileResult struct {
+ Automergeable bool
+ Path string
+ Mode uint
+ Contents []byte
+ ptr *C.git_merge_file_result
+}
+
+func newMergeFileResultFromC(c *C.git_merge_file_result) *MergeFileResult {
+ var path string
+ if c.path != nil {
+ path = C.GoString(c.path)
+ }
+
+ originalBytes := C.GoBytes(unsafe.Pointer(c.ptr), C.int(c.len))
+ gobytes := make([]byte, len(originalBytes))
+ copy(gobytes, originalBytes)
+ r := &MergeFileResult{
+ Automergeable: c.automergeable != 0,
+ Path: path,
+ Mode: uint(c.mode),
+ Contents: gobytes,
+ ptr: c,
+ }
+
+ runtime.SetFinalizer(r, (*MergeFileResult).Free)
+ return r
+}
+
+func (r *MergeFileResult) Free() {
+ runtime.SetFinalizer(r, nil)
+ C.git_merge_file_result_free(r.ptr)
+}
+
+type MergeFileInput struct {
+ Path string
+ Mode uint
+ Contents []byte
+}
+
+type MergeFileFlags int
+
+const (
+ MergeFileDefault MergeFileFlags = C.GIT_MERGE_FILE_DEFAULT
+
+ MergeFileStyleMerge MergeFileFlags = C.GIT_MERGE_FILE_STYLE_MERGE
+ MergeFileStyleDiff MergeFileFlags = C.GIT_MERGE_FILE_STYLE_DIFF3
+ MergeFileStyleSimplifyAlnum MergeFileFlags = C.GIT_MERGE_FILE_SIMPLIFY_ALNUM
+)
+
+type MergeFileOptions struct {
+ AncestorLabel string
+ OurLabel string
+ TheirLabel string
+ Favor MergeFileFavor
+ Flags MergeFileFlags
+ MarkerSize uint16
+}
+
+func mergeFileOptionsFromC(c C.git_merge_file_options) MergeFileOptions {
+ return MergeFileOptions{
+ AncestorLabel: C.GoString(c.ancestor_label),
+ OurLabel: C.GoString(c.our_label),
+ TheirLabel: C.GoString(c.their_label),
+ Favor: MergeFileFavor(c.favor),
+ Flags: MergeFileFlags(c.flags),
+ MarkerSize: uint16(c.marker_size),
+ }
+}
+
+func populateCMergeFileOptions(c *C.git_merge_file_options, options MergeFileOptions) {
+ c.ancestor_label = C.CString(options.AncestorLabel)
+ c.our_label = C.CString(options.OurLabel)
+ c.their_label = C.CString(options.TheirLabel)
+ c.favor = C.git_merge_file_favor_t(options.Favor)
+ c.flags = C.git_merge_file_flag_t(options.Flags)
+ c.marker_size = C.ushort(options.MarkerSize)
+}
+
+func freeCMergeFileOptions(c *C.git_merge_file_options) {
+ C.free(unsafe.Pointer(c.ancestor_label))
+ C.free(unsafe.Pointer(c.our_label))
+ C.free(unsafe.Pointer(c.their_label))
+}
+
+func MergeFile(ancestor MergeFileInput, ours MergeFileInput, theirs MergeFileInput, options *MergeFileOptions) (*MergeFileResult, error) {
+
+ ancestorPath := C.CString(ancestor.Path)
+ defer C.free(unsafe.Pointer(ancestorPath))
+ var ancestorContents *byte
+ if len(ancestor.Contents) > 0 {
+ ancestorContents = &ancestor.Contents[0]
+ }
+
+ oursPath := C.CString(ours.Path)
+ defer C.free(unsafe.Pointer(oursPath))
+ var oursContents *byte
+ if len(ours.Contents) > 0 {
+ oursContents = &ours.Contents[0]
+ }
+
+ theirsPath := C.CString(theirs.Path)
+ defer C.free(unsafe.Pointer(theirsPath))
+ var theirsContents *byte
+ if len(theirs.Contents) > 0 {
+ theirsContents = &theirs.Contents[0]
+ }
+
+ var copts *C.git_merge_file_options
+ if options != nil {
+ copts = &C.git_merge_file_options{}
+ ecode := C.git_merge_file_init_options(copts, C.GIT_MERGE_FILE_OPTIONS_VERSION)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ populateCMergeFileOptions(copts, *options)
+ defer freeCMergeFileOptions(copts)
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var result C.git_merge_file_result
+ ecode := C._go_git_merge_file(&result,
+ (*C.char)(unsafe.Pointer(ancestorContents)), C.size_t(len(ancestor.Contents)), ancestorPath, C.uint(ancestor.Mode),
+ (*C.char)(unsafe.Pointer(oursContents)), C.size_t(len(ours.Contents)), oursPath, C.uint(ours.Mode),
+ (*C.char)(unsafe.Pointer(theirsContents)), C.size_t(len(theirs.Contents)), theirsPath, C.uint(theirs.Mode),
+ copts)
+ runtime.KeepAlive(ancestor)
+ runtime.KeepAlive(ours)
+ runtime.KeepAlive(theirs)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newMergeFileResultFromC(&result), nil
+
+}
+
+// TODO: GIT_EXTERN(int) git_merge_file_from_index(git_merge_file_result *out,git_repository *repo,const git_index_entry *ancestor, const git_index_entry *ours, const git_index_entry *theirs, const git_merge_file_options *opts);
diff --git a/vendor/github.com/libgit2/git2go/note.go b/vendor/github.com/libgit2/git2go/note.go
new file mode 100644
index 000000000..21bed57aa
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/note.go
@@ -0,0 +1,244 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+// This object represents the possible operations which can be
+// performed on the collection of notes for a repository.
+type NoteCollection struct {
+ repo *Repository
+}
+
+// Create adds a note for an object
+func (c *NoteCollection) Create(
+ ref string, author, committer *Signature, id *Oid,
+ note string, force bool) (*Oid, error) {
+
+ oid := new(Oid)
+
+ var cref *C.char
+ if ref == "" {
+ cref = nil
+ } else {
+ cref = C.CString(ref)
+ defer C.free(unsafe.Pointer(cref))
+ }
+
+ authorSig, err := author.toC()
+ if err != nil {
+ return nil, err
+ }
+ defer C.git_signature_free(authorSig)
+
+ committerSig, err := committer.toC()
+ if err != nil {
+ return nil, err
+ }
+ defer C.git_signature_free(committerSig)
+
+ cnote := C.CString(note)
+ defer C.free(unsafe.Pointer(cnote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_note_create(
+ oid.toC(), c.repo.ptr, cref, authorSig,
+ committerSig, id.toC(), cnote, cbool(force))
+ runtime.KeepAlive(c)
+ runtime.KeepAlive(id)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return oid, nil
+}
+
+// Read reads the note for an object
+func (c *NoteCollection) Read(ref string, id *Oid) (*Note, error) {
+ var cref *C.char
+ if ref == "" {
+ cref = nil
+ } else {
+ cref = C.CString(ref)
+ defer C.free(unsafe.Pointer(cref))
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_note
+ ret := C.git_note_read(&ptr, c.repo.ptr, cref, id.toC())
+ runtime.KeepAlive(c)
+ runtime.KeepAlive(id)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newNoteFromC(ptr, c.repo), nil
+}
+
+// Remove removes the note for an object
+func (c *NoteCollection) Remove(ref string, author, committer *Signature, id *Oid) error {
+ var cref *C.char
+ if ref == "" {
+ cref = nil
+ } else {
+ cref = C.CString(ref)
+ defer C.free(unsafe.Pointer(cref))
+ }
+
+ authorSig, err := author.toC()
+ if err != nil {
+ return err
+ }
+ defer C.git_signature_free(authorSig)
+
+ committerSig, err := committer.toC()
+ if err != nil {
+ return err
+ }
+ defer C.git_signature_free(committerSig)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_note_remove(c.repo.ptr, cref, authorSig, committerSig, id.toC())
+ runtime.KeepAlive(c)
+ runtime.KeepAlive(id)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+// DefaultRef returns the default notes reference for a repository
+func (c *NoteCollection) DefaultRef() (string, error) {
+ buf := C.git_buf{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_note_default_ref(&buf, c.repo.ptr)
+ runtime.KeepAlive(c)
+ if ecode < 0 {
+ return "", MakeGitError(ecode)
+ }
+
+ ret := C.GoString(buf.ptr)
+ C.git_buf_free(&buf)
+
+ return ret, nil
+}
+
+// Note
+type Note struct {
+ ptr *C.git_note
+ r *Repository
+}
+
+func newNoteFromC(ptr *C.git_note, r *Repository) *Note {
+ note := &Note{ptr: ptr, r: r}
+ runtime.SetFinalizer(note, (*Note).Free)
+ return note
+}
+
+// Free frees a git_note object
+func (n *Note) Free() error {
+ if n.ptr == nil {
+ return ErrInvalid
+ }
+ runtime.SetFinalizer(n, nil)
+ C.git_note_free(n.ptr)
+ n.ptr = nil
+ return nil
+}
+
+// Author returns the signature of the note author
+func (n *Note) Author() *Signature {
+ ptr := C.git_note_author(n.ptr)
+ return newSignatureFromC(ptr)
+}
+
+// Id returns the note object's id
+func (n *Note) Id() *Oid {
+ ptr := C.git_note_id(n.ptr)
+ runtime.KeepAlive(n)
+ return newOidFromC(ptr)
+}
+
+// Committer returns the signature of the note committer
+func (n *Note) Committer() *Signature {
+ ptr := C.git_note_committer(n.ptr)
+ runtime.KeepAlive(n)
+ return newSignatureFromC(ptr)
+}
+
+// Message returns the note message
+func (n *Note) Message() string {
+ ret := C.GoString(C.git_note_message(n.ptr))
+ runtime.KeepAlive(n)
+ return ret
+}
+
+// NoteIterator
+type NoteIterator struct {
+ ptr *C.git_note_iterator
+ r *Repository
+}
+
+// NewNoteIterator creates a new iterator for notes
+func (repo *Repository) NewNoteIterator(ref string) (*NoteIterator, error) {
+ var cref *C.char
+ if ref == "" {
+ cref = nil
+ } else {
+ cref = C.CString(ref)
+ defer C.free(unsafe.Pointer(cref))
+ }
+
+ var ptr *C.git_note_iterator
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_note_iterator_new(&ptr, repo.ptr, cref)
+ runtime.KeepAlive(repo)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ iter := &NoteIterator{ptr: ptr, r: repo}
+ runtime.SetFinalizer(iter, (*NoteIterator).Free)
+ return iter, nil
+}
+
+// Free frees the note interator
+func (v *NoteIterator) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_note_iterator_free(v.ptr)
+}
+
+// Next returns the current item (note id & annotated id) and advances the
+// iterator internally to the next item
+func (it *NoteIterator) Next() (noteId, annotatedId *Oid, err error) {
+ noteId, annotatedId = new(Oid), new(Oid)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_note_next(noteId.toC(), annotatedId.toC(), it.ptr)
+ runtime.KeepAlive(noteId)
+ runtime.KeepAlive(annotatedId)
+ runtime.KeepAlive(it)
+ if ret < 0 {
+ err = MakeGitError(ret)
+ }
+ return
+}
diff --git a/vendor/github.com/libgit2/git2go/object.go b/vendor/github.com/libgit2/git2go/object.go
new file mode 100644
index 000000000..5505e356e
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/object.go
@@ -0,0 +1,237 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "errors"
+ "fmt"
+ "runtime"
+)
+
+type ObjectType int
+
+const (
+ ObjectAny ObjectType = C.GIT_OBJ_ANY
+ ObjectBad ObjectType = C.GIT_OBJ_BAD
+ ObjectCommit ObjectType = C.GIT_OBJ_COMMIT
+ ObjectTree ObjectType = C.GIT_OBJ_TREE
+ ObjectBlob ObjectType = C.GIT_OBJ_BLOB
+ ObjectTag ObjectType = C.GIT_OBJ_TAG
+)
+
+type Object struct {
+ ptr *C.git_object
+ repo *Repository
+}
+
+// Objecter lets us accept any kind of Git object in functions.
+type Objecter interface {
+ AsObject() *Object
+}
+
+func (t ObjectType) String() string {
+ switch t {
+ case ObjectAny:
+ return "Any"
+ case ObjectBad:
+ return "Bad"
+ case ObjectCommit:
+ return "Commit"
+ case ObjectTree:
+ return "Tree"
+ case ObjectBlob:
+ return "Blob"
+ case ObjectTag:
+ return "Tag"
+ }
+ // Never reached
+ return ""
+}
+
+func (o *Object) Id() *Oid {
+ ret := newOidFromC(C.git_object_id(o.ptr))
+ runtime.KeepAlive(o)
+ return ret
+}
+
+func (o *Object) ShortId() (string, error) {
+ resultBuf := C.git_buf{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_object_short_id(&resultBuf, o.ptr)
+ runtime.KeepAlive(o)
+ if ecode < 0 {
+ return "", MakeGitError(ecode)
+ }
+ defer C.git_buf_free(&resultBuf)
+ return C.GoString(resultBuf.ptr), nil
+}
+
+func (o *Object) Type() ObjectType {
+ ret := ObjectType(C.git_object_type(o.ptr))
+ runtime.KeepAlive(o)
+ return ret
+}
+
+// Owner returns a weak reference to the repository which owns this
+// object. This won't keep the underlying repository alive.
+func (o *Object) Owner() *Repository {
+ ret := &Repository{
+ ptr: C.git_object_owner(o.ptr),
+ }
+ runtime.KeepAlive(o)
+ return ret
+}
+
+func dupObject(obj *Object, kind ObjectType) (*C.git_object, error) {
+ if obj.Type() != kind {
+ return nil, errors.New(fmt.Sprintf("object is not a %v", kind))
+ }
+
+ var cobj *C.git_object
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_object_dup(&cobj, obj.ptr)
+ runtime.KeepAlive(obj)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return cobj, nil
+}
+
+func allocTree(ptr *C.git_tree, repo *Repository) *Tree {
+ tree := &Tree{
+ Object: Object{
+ ptr: (*C.git_object)(ptr),
+ repo: repo,
+ },
+ cast_ptr: ptr,
+ }
+ runtime.SetFinalizer(tree, (*Tree).Free)
+
+ return tree
+}
+
+func (o *Object) AsTree() (*Tree, error) {
+ cobj, err := dupObject(o, ObjectTree)
+ if err != nil {
+ return nil, err
+ }
+
+ return allocTree((*C.git_tree)(cobj), o.repo), nil
+}
+
+func allocCommit(ptr *C.git_commit, repo *Repository) *Commit {
+ commit := &Commit{
+ Object: Object{
+ ptr: (*C.git_object)(ptr),
+ repo: repo,
+ },
+ cast_ptr: ptr,
+ }
+ runtime.SetFinalizer(commit, (*Commit).Free)
+
+ return commit
+}
+
+func (o *Object) AsCommit() (*Commit, error) {
+ cobj, err := dupObject(o, ObjectCommit)
+ if err != nil {
+ return nil, err
+ }
+
+ return allocCommit((*C.git_commit)(cobj), o.repo), nil
+}
+
+func allocBlob(ptr *C.git_blob, repo *Repository) *Blob {
+ blob := &Blob{
+ Object: Object{
+ ptr: (*C.git_object)(ptr),
+ repo: repo,
+ },
+ cast_ptr: ptr,
+ }
+ runtime.SetFinalizer(blob, (*Blob).Free)
+
+ return blob
+}
+
+func (o *Object) AsBlob() (*Blob, error) {
+ cobj, err := dupObject(o, ObjectBlob)
+ if err != nil {
+ return nil, err
+ }
+
+ return allocBlob((*C.git_blob)(cobj), o.repo), nil
+}
+
+func allocTag(ptr *C.git_tag, repo *Repository) *Tag {
+ tag := &Tag{
+ Object: Object{
+ ptr: (*C.git_object)(ptr),
+ repo: repo,
+ },
+ cast_ptr: ptr,
+ }
+ runtime.SetFinalizer(tag, (*Tag).Free)
+
+ return tag
+}
+
+func (o *Object) AsTag() (*Tag, error) {
+ cobj, err := dupObject(o, ObjectTag)
+ if err != nil {
+ return nil, err
+ }
+
+ return allocTag((*C.git_tag)(cobj), o.repo), nil
+}
+
+func (o *Object) Free() {
+ runtime.SetFinalizer(o, nil)
+ C.git_object_free(o.ptr)
+}
+
+// Peel recursively peels an object until an object of the specified type is met.
+//
+// If the query cannot be satisfied due to the object model, ErrInvalidSpec
+// will be returned (e.g. trying to peel a blob to a tree).
+//
+// If you pass ObjectAny as the target type, then the object will be peeled
+// until the type changes. A tag will be peeled until the referenced object
+// is no longer a tag, and a commit will be peeled to a tree. Any other object
+// type will return ErrInvalidSpec.
+//
+// If peeling a tag we discover an object which cannot be peeled to the target
+// type due to the object model, an error will be returned.
+func (o *Object) Peel(t ObjectType) (*Object, error) {
+ var cobj *C.git_object
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_object_peel(&cobj, o.ptr, C.git_otype(t))
+ runtime.KeepAlive(o)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return allocObject(cobj, o.repo), nil
+}
+
+func allocObject(cobj *C.git_object, repo *Repository) *Object {
+ obj := &Object{
+ ptr: cobj,
+ repo: repo,
+ }
+ runtime.SetFinalizer(obj, (*Object).Free)
+
+ return obj
+}
diff --git a/vendor/github.com/libgit2/git2go/odb.go b/vendor/github.com/libgit2/git2go/odb.go
new file mode 100644
index 000000000..f236fc4dc
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/odb.go
@@ -0,0 +1,348 @@
+package git
+
+/*
+#include <git2.h>
+
+extern int _go_git_odb_foreach(git_odb *db, void *payload);
+extern void _go_git_odb_backend_free(git_odb_backend *backend);
+*/
+import "C"
+import (
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+type Odb struct {
+ ptr *C.git_odb
+}
+
+type OdbBackend struct {
+ ptr *C.git_odb_backend
+}
+
+func NewOdb() (odb *Odb, err error) {
+ odb = new(Odb)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_new(&odb.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ runtime.SetFinalizer(odb, (*Odb).Free)
+ return odb, nil
+}
+
+func NewOdbBackendFromC(ptr unsafe.Pointer) (backend *OdbBackend) {
+ backend = &OdbBackend{(*C.git_odb_backend)(ptr)}
+ return backend
+}
+
+func (v *Odb) AddBackend(backend *OdbBackend, priority int) (err error) {
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_add_backend(v.ptr, backend.ptr, C.int(priority))
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ backend.Free()
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (v *Odb) ReadHeader(oid *Oid) (uint64, ObjectType, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var sz C.size_t
+ var cotype C.git_otype
+
+ ret := C.git_odb_read_header(&sz, &cotype, v.ptr, oid.toC())
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return 0, C.GIT_OBJ_BAD, MakeGitError(ret)
+ }
+
+ return uint64(sz), ObjectType(cotype), nil
+}
+
+func (v *Odb) Exists(oid *Oid) bool {
+ ret := C.git_odb_exists(v.ptr, oid.toC())
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(oid)
+ return ret != 0
+}
+
+func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {
+ oid = new(Oid)
+ var cptr unsafe.Pointer
+ if len(data) > 0 {
+ cptr = unsafe.Pointer(&data[0])
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_write(oid.toC(), v.ptr, cptr, C.size_t(len(data)), C.git_otype(otype))
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return oid, nil
+}
+
+func (v *Odb) Read(oid *Oid) (obj *OdbObject, err error) {
+ obj = new(OdbObject)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_read(&obj.ptr, v.ptr, oid.toC())
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(oid)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ runtime.SetFinalizer(obj, (*OdbObject).Free)
+ return obj, nil
+}
+
+type OdbForEachCallback func(id *Oid) error
+
+type foreachData struct {
+ callback OdbForEachCallback
+ err error
+}
+
+//export odbForEachCb
+func odbForEachCb(id *C.git_oid, handle unsafe.Pointer) int {
+ data, ok := pointerHandles.Get(handle).(*foreachData)
+
+ if !ok {
+ panic("could not retrieve handle")
+ }
+
+ err := data.callback(newOidFromC(id))
+ if err != nil {
+ data.err = err
+ return C.GIT_EUSER
+ }
+
+ return 0
+}
+
+func (v *Odb) ForEach(callback OdbForEachCallback) error {
+ data := foreachData{
+ callback: callback,
+ err: nil,
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ handle := pointerHandles.Track(&data)
+ defer pointerHandles.Untrack(handle)
+
+ ret := C._go_git_odb_foreach(v.ptr, handle)
+ runtime.KeepAlive(v)
+ if ret == C.GIT_EUSER {
+ return data.err
+ } else if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+// Hash determines the object-ID (sha1) of a data buffer.
+func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) {
+ oid = new(Oid)
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ ptr := unsafe.Pointer(header.Data)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype))
+ runtime.KeepAlive(data)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return oid, nil
+}
+
+// NewReadStream opens a read stream from the ODB. Reading from it will give you the
+// contents of the object.
+func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) {
+ stream := new(OdbReadStream)
+ var ctype C.git_otype
+ var csize C.size_t
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_open_rstream(&stream.ptr, &csize, &ctype, v.ptr, id.toC())
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(id)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ stream.Size = uint64(csize)
+ stream.Type = ObjectType(ctype)
+ runtime.SetFinalizer(stream, (*OdbReadStream).Free)
+ return stream, nil
+}
+
+// NewWriteStream opens a write stream to the ODB, which allows you to
+// create a new object in the database. The size and type must be
+// known in advance
+func (v *Odb) NewWriteStream(size int64, otype ObjectType) (*OdbWriteStream, error) {
+ stream := new(OdbWriteStream)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.git_off_t(size), C.git_otype(otype))
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ runtime.SetFinalizer(stream, (*OdbWriteStream).Free)
+ return stream, nil
+}
+
+func (v *OdbBackend) Free() {
+ C._go_git_odb_backend_free(v.ptr)
+}
+
+type OdbObject struct {
+ ptr *C.git_odb_object
+}
+
+func (v *OdbObject) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_odb_object_free(v.ptr)
+}
+
+func (object *OdbObject) Id() (oid *Oid) {
+ ret := newOidFromC(C.git_odb_object_id(object.ptr))
+ runtime.KeepAlive(object)
+ return ret
+}
+
+func (object *OdbObject) Len() (len uint64) {
+ ret := uint64(C.git_odb_object_size(object.ptr))
+ runtime.KeepAlive(object)
+ return ret
+}
+
+func (object *OdbObject) Type() ObjectType {
+ ret := ObjectType(C.git_odb_object_type(object.ptr))
+ runtime.KeepAlive(object)
+ return ret
+}
+
+// Data returns a slice pointing to the unmanaged object memory. You must make
+// sure the object is referenced for at least as long as the slice is used.
+func (object *OdbObject) Data() (data []byte) {
+ var c_blob unsafe.Pointer = C.git_odb_object_data(object.ptr)
+ var blob []byte
+
+ len := int(C.git_odb_object_size(object.ptr))
+
+ sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&blob)))
+ sliceHeader.Cap = len
+ sliceHeader.Len = len
+ sliceHeader.Data = uintptr(c_blob)
+
+ return blob
+}
+
+type OdbReadStream struct {
+ ptr *C.git_odb_stream
+ Size uint64
+ Type ObjectType
+}
+
+// Read reads from the stream
+func (stream *OdbReadStream) Read(data []byte) (int, error) {
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ ptr := (*C.char)(unsafe.Pointer(header.Data))
+ size := C.size_t(header.Cap)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_stream_read(stream.ptr, ptr, size)
+ runtime.KeepAlive(stream)
+ if ret < 0 {
+ return 0, MakeGitError(ret)
+ }
+
+ header.Len = int(ret)
+
+ return len(data), nil
+}
+
+// Close is a dummy function in order to implement the Closer and
+// ReadCloser interfaces
+func (stream *OdbReadStream) Close() error {
+ return nil
+}
+
+func (stream *OdbReadStream) Free() {
+ runtime.SetFinalizer(stream, nil)
+ C.git_odb_stream_free(stream.ptr)
+}
+
+type OdbWriteStream struct {
+ ptr *C.git_odb_stream
+ Id Oid
+}
+
+// Write writes to the stream
+func (stream *OdbWriteStream) Write(data []byte) (int, error) {
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ ptr := (*C.char)(unsafe.Pointer(header.Data))
+ size := C.size_t(header.Len)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_stream_write(stream.ptr, ptr, size)
+ runtime.KeepAlive(stream)
+ if ret < 0 {
+ return 0, MakeGitError(ret)
+ }
+
+ return len(data), nil
+}
+
+// Close signals that all the data has been written and stores the
+// resulting object id in the stream's Id field.
+func (stream *OdbWriteStream) Close() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_stream_finalize_write(stream.Id.toC(), stream.ptr)
+ runtime.KeepAlive(stream)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (stream *OdbWriteStream) Free() {
+ runtime.SetFinalizer(stream, nil)
+ C.git_odb_stream_free(stream.ptr)
+}
diff --git a/vendor/github.com/libgit2/git2go/packbuilder.go b/vendor/github.com/libgit2/git2go/packbuilder.go
new file mode 100644
index 000000000..0e04bbf5f
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/packbuilder.go
@@ -0,0 +1,170 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/pack.h>
+#include <stdlib.h>
+
+extern int _go_git_packbuilder_foreach(git_packbuilder *pb, void *payload);
+*/
+import "C"
+import (
+ "io"
+ "os"
+ "runtime"
+ "unsafe"
+)
+
+type Packbuilder struct {
+ ptr *C.git_packbuilder
+ r *Repository
+}
+
+func (repo *Repository) NewPackbuilder() (*Packbuilder, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_packbuilder
+ ret := C.git_packbuilder_new(&ptr, repo.ptr)
+ if ret != 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newPackbuilderFromC(ptr, repo), nil
+}
+
+func newPackbuilderFromC(ptr *C.git_packbuilder, r *Repository) *Packbuilder {
+ pb := &Packbuilder{ptr: ptr, r: r}
+ runtime.SetFinalizer(pb, (*Packbuilder).Free)
+ return pb
+}
+
+func (pb *Packbuilder) Free() {
+ runtime.SetFinalizer(pb, nil)
+ C.git_packbuilder_free(pb.ptr)
+}
+
+func (pb *Packbuilder) Insert(id *Oid, name string) error {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_packbuilder_insert(pb.ptr, id.toC(), cname)
+ runtime.KeepAlive(pb)
+ runtime.KeepAlive(id)
+ if ret != 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (pb *Packbuilder) InsertCommit(id *Oid) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_packbuilder_insert_commit(pb.ptr, id.toC())
+ runtime.KeepAlive(pb)
+ runtime.KeepAlive(id)
+ if ret != 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (pb *Packbuilder) InsertTree(id *Oid) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_packbuilder_insert_tree(pb.ptr, id.toC())
+ runtime.KeepAlive(pb)
+ runtime.KeepAlive(id)
+ if ret != 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (pb *Packbuilder) ObjectCount() uint32 {
+ ret := uint32(C.git_packbuilder_object_count(pb.ptr))
+ runtime.KeepAlive(pb)
+ return ret
+}
+
+func (pb *Packbuilder) WriteToFile(name string, mode os.FileMode) error {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_packbuilder_write(pb.ptr, cname, C.uint(mode.Perm()), nil, nil)
+ runtime.KeepAlive(pb)
+ if ret != 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (pb *Packbuilder) Write(w io.Writer) error {
+ return pb.ForEach(func(slice []byte) error {
+ _, err := w.Write(slice)
+ return err
+ })
+}
+
+func (pb *Packbuilder) Written() uint32 {
+ ret := uint32(C.git_packbuilder_written(pb.ptr))
+ runtime.KeepAlive(pb)
+ return ret
+}
+
+type PackbuilderForeachCallback func([]byte) error
+type packbuilderCbData struct {
+ callback PackbuilderForeachCallback
+ err error
+}
+
+//export packbuilderForEachCb
+func packbuilderForEachCb(buf unsafe.Pointer, size C.size_t, handle unsafe.Pointer) int {
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*packbuilderCbData)
+ if !ok {
+ panic("could not get packbuilder CB data")
+ }
+
+ slice := C.GoBytes(buf, C.int(size))
+
+ err := data.callback(slice)
+ if err != nil {
+ data.err = err
+ return C.GIT_EUSER
+ }
+
+ return 0
+}
+
+// ForEach repeatedly calls the callback with new packfile data until
+// there is no more data or the callback returns an error
+func (pb *Packbuilder) ForEach(callback PackbuilderForeachCallback) error {
+ data := packbuilderCbData{
+ callback: callback,
+ err: nil,
+ }
+ handle := pointerHandles.Track(&data)
+ defer pointerHandles.Untrack(handle)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C._go_git_packbuilder_foreach(pb.ptr, handle)
+ runtime.KeepAlive(pb)
+ if err == C.GIT_EUSER {
+ return data.err
+ }
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/patch.go b/vendor/github.com/libgit2/git2go/patch.go
new file mode 100644
index 000000000..7e6f71da3
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/patch.go
@@ -0,0 +1,93 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type Patch struct {
+ ptr *C.git_patch
+}
+
+func newPatchFromC(ptr *C.git_patch) *Patch {
+ if ptr == nil {
+ return nil
+ }
+
+ patch := &Patch{
+ ptr: ptr,
+ }
+
+ runtime.SetFinalizer(patch, (*Patch).Free)
+ return patch
+}
+
+func (patch *Patch) Free() error {
+ if patch.ptr == nil {
+ return ErrInvalid
+ }
+ runtime.SetFinalizer(patch, nil)
+ C.git_patch_free(patch.ptr)
+ patch.ptr = nil
+ return nil
+}
+
+func (patch *Patch) String() (string, error) {
+ if patch.ptr == nil {
+ return "", ErrInvalid
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var buf C.git_buf
+
+ ecode := C.git_patch_to_buf(&buf, patch.ptr)
+ runtime.KeepAlive(patch)
+ if ecode < 0 {
+ return "", MakeGitError(ecode)
+ }
+ defer C.git_buf_free(&buf)
+
+ return C.GoString(buf.ptr), nil
+}
+
+func toPointer(data []byte) (ptr unsafe.Pointer) {
+ if len(data) > 0 {
+ ptr = unsafe.Pointer(&data[0])
+ } else {
+ ptr = unsafe.Pointer(nil)
+ }
+ return
+}
+
+func (v *Repository) PatchFromBuffers(oldPath, newPath string, oldBuf, newBuf []byte, opts *DiffOptions) (*Patch, error) {
+ var patchPtr *C.git_patch
+
+ oldPtr := toPointer(oldBuf)
+ newPtr := toPointer(newBuf)
+
+ cOldPath := C.CString(oldPath)
+ defer C.free(unsafe.Pointer(cOldPath))
+
+ cNewPath := C.CString(newPath)
+ defer C.free(unsafe.Pointer(cNewPath))
+
+ copts, _ := diffOptionsToC(opts)
+ defer freeDiffOptions(copts)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_patch_from_buffers(&patchPtr, oldPtr, C.size_t(len(oldBuf)), cOldPath, newPtr, C.size_t(len(newBuf)), cNewPath, copts)
+ runtime.KeepAlive(oldBuf)
+ runtime.KeepAlive(newBuf)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ return newPatchFromC(patchPtr), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/rebase.go b/vendor/github.com/libgit2/git2go/rebase.go
new file mode 100644
index 000000000..5206fcae7
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/rebase.go
@@ -0,0 +1,274 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "errors"
+ "runtime"
+ "unsafe"
+)
+
+// RebaseOperationType is the type of rebase operation
+type RebaseOperationType uint
+
+const (
+ // RebaseOperationPick The given commit is to be cherry-picked. The client should commit the changes and continue if there are no conflicts.
+ RebaseOperationPick RebaseOperationType = C.GIT_REBASE_OPERATION_PICK
+ // RebaseOperationEdit The given commit is to be cherry-picked, but the client should stop to allow the user to edit the changes before committing them.
+ RebaseOperationEdit RebaseOperationType = C.GIT_REBASE_OPERATION_EDIT
+ // RebaseOperationSquash The given commit is to be squashed into the previous commit. The commit message will be merged with the previous message.
+ RebaseOperationSquash RebaseOperationType = C.GIT_REBASE_OPERATION_SQUASH
+ // RebaseOperationFixup No commit will be cherry-picked. The client should run the given command and (if successful) continue.
+ RebaseOperationFixup RebaseOperationType = C.GIT_REBASE_OPERATION_FIXUP
+ // RebaseOperationExec No commit will be cherry-picked. The client should run the given command and (if successful) continue.
+ RebaseOperationExec RebaseOperationType = C.GIT_REBASE_OPERATION_EXEC
+)
+
+// Special value indicating that there is no currently active operation
+var RebaseNoOperation uint = ^uint(0)
+
+// Error returned if there is no current rebase operation
+var ErrRebaseNoOperation = errors.New("no current rebase operation")
+
+// RebaseOperation describes a single instruction/operation to be performed during the rebase.
+type RebaseOperation struct {
+ Type RebaseOperationType
+ Id *Oid
+ Exec string
+}
+
+func newRebaseOperationFromC(c *C.git_rebase_operation) *RebaseOperation {
+ operation := &RebaseOperation{}
+ operation.Type = RebaseOperationType(c._type)
+ operation.Id = newOidFromC(&c.id)
+ operation.Exec = C.GoString(c.exec)
+
+ return operation
+}
+
+// RebaseOptions are used to tell the rebase machinery how to operate
+type RebaseOptions struct {
+ Version uint
+ Quiet int
+ InMemory int
+ RewriteNotesRef string
+ MergeOptions MergeOptions
+ CheckoutOptions CheckoutOpts
+}
+
+// DefaultRebaseOptions returns a RebaseOptions with default values.
+func DefaultRebaseOptions() (RebaseOptions, error) {
+ opts := C.git_rebase_options{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_rebase_init_options(&opts, C.GIT_REBASE_OPTIONS_VERSION)
+ if ecode < 0 {
+ return RebaseOptions{}, MakeGitError(ecode)
+ }
+ return rebaseOptionsFromC(&opts), nil
+}
+
+func rebaseOptionsFromC(opts *C.git_rebase_options) RebaseOptions {
+ return RebaseOptions{
+ Version: uint(opts.version),
+ Quiet: int(opts.quiet),
+ InMemory: int(opts.inmemory),
+ RewriteNotesRef: C.GoString(opts.rewrite_notes_ref),
+ MergeOptions: mergeOptionsFromC(&opts.merge_options),
+ CheckoutOptions: checkoutOptionsFromC(&opts.checkout_options),
+ }
+}
+
+func (ro *RebaseOptions) toC() *C.git_rebase_options {
+ if ro == nil {
+ return nil
+ }
+ return &C.git_rebase_options{
+ version: C.uint(ro.Version),
+ quiet: C.int(ro.Quiet),
+ inmemory: C.int(ro.InMemory),
+ rewrite_notes_ref: mapEmptyStringToNull(ro.RewriteNotesRef),
+ merge_options: *ro.MergeOptions.toC(),
+ checkout_options: *ro.CheckoutOptions.toC(),
+ }
+}
+
+func mapEmptyStringToNull(ref string) *C.char {
+ if ref == "" {
+ return nil
+ }
+ return C.CString(ref)
+}
+
+// Rebase is the struct representing a Rebase object.
+type Rebase struct {
+ ptr *C.git_rebase
+ r *Repository
+}
+
+// InitRebase initializes a rebase operation to rebase the changes in branch relative to upstream onto another branch.
+func (r *Repository) InitRebase(branch *AnnotatedCommit, upstream *AnnotatedCommit, onto *AnnotatedCommit, opts *RebaseOptions) (*Rebase, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if branch == nil {
+ branch = &AnnotatedCommit{ptr: nil}
+ }
+
+ if upstream == nil {
+ upstream = &AnnotatedCommit{ptr: nil}
+ }
+
+ if onto == nil {
+ onto = &AnnotatedCommit{ptr: nil}
+ }
+
+ var ptr *C.git_rebase
+ err := C.git_rebase_init(&ptr, r.ptr, branch.ptr, upstream.ptr, onto.ptr, opts.toC())
+ runtime.KeepAlive(branch)
+ runtime.KeepAlive(upstream)
+ runtime.KeepAlive(onto)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return newRebaseFromC(ptr), nil
+}
+
+// OpenRebase opens an existing rebase that was previously started by either an invocation of InitRebase or by another client.
+func (r *Repository) OpenRebase(opts *RebaseOptions) (*Rebase, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_rebase
+ err := C.git_rebase_open(&ptr, r.ptr, opts.toC())
+ runtime.KeepAlive(r)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return newRebaseFromC(ptr), nil
+}
+
+// OperationAt gets the rebase operation specified by the given index.
+func (rebase *Rebase) OperationAt(index uint) *RebaseOperation {
+ operation := C.git_rebase_operation_byindex(rebase.ptr, C.size_t(index))
+
+ return newRebaseOperationFromC(operation)
+}
+
+// CurrentOperationIndex gets the index of the rebase operation that is
+// currently being applied. There is also an error returned for API
+// compatibility.
+func (rebase *Rebase) CurrentOperationIndex() (uint, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var err error
+ operationIndex := uint(C.git_rebase_operation_current(rebase.ptr))
+ runtime.KeepAlive(rebase)
+ if operationIndex == RebaseNoOperation {
+ err = ErrRebaseNoOperation
+ }
+
+ return uint(operationIndex), err
+}
+
+// OperationCount gets the count of rebase operations that are to be applied.
+func (rebase *Rebase) OperationCount() uint {
+ ret := uint(C.git_rebase_operation_entrycount(rebase.ptr))
+ runtime.KeepAlive(rebase)
+ return ret
+}
+
+// Next performs the next rebase operation and returns the information about it.
+// If the operation is one that applies a patch (which is any operation except RebaseOperationExec)
+// then the patch will be applied and the index and working directory will be updated with the changes.
+// If there are conflicts, you will need to address those before committing the changes.
+func (rebase *Rebase) Next() (*RebaseOperation, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_rebase_operation
+ err := C.git_rebase_next(&ptr, rebase.ptr)
+ runtime.KeepAlive(rebase)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return newRebaseOperationFromC(ptr), nil
+}
+
+// Commit commits the current patch.
+// You must have resolved any conflicts that were introduced during the patch application from the Next() invocation.
+func (rebase *Rebase) Commit(ID *Oid, author, committer *Signature, message string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ authorSig, err := author.toC()
+ if err != nil {
+ return err
+ }
+ defer C.git_signature_free(authorSig)
+
+ committerSig, err := committer.toC()
+ if err != nil {
+ return err
+ }
+ defer C.git_signature_free(committerSig)
+
+ cmsg := C.CString(message)
+ defer C.free(unsafe.Pointer(cmsg))
+
+ cerr := C.git_rebase_commit(ID.toC(), rebase.ptr, authorSig, committerSig, nil, cmsg)
+ runtime.KeepAlive(ID)
+ runtime.KeepAlive(rebase)
+ if cerr < 0 {
+ return MakeGitError(cerr)
+ }
+
+ return nil
+}
+
+// Finish finishes a rebase that is currently in progress once all patches have been applied.
+func (rebase *Rebase) Finish() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_rebase_finish(rebase.ptr, nil)
+ runtime.KeepAlive(rebase)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
+
+// Abort aborts a rebase that is currently in progress, resetting the repository and working directory to their state before rebase began.
+func (rebase *Rebase) Abort() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_rebase_abort(rebase.ptr)
+ runtime.KeepAlive(rebase)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+ return nil
+}
+
+// Free frees the Rebase object.
+func (rebase *Rebase) Free() {
+ runtime.SetFinalizer(rebase, nil)
+ C.git_rebase_free(rebase.ptr)
+}
+
+func newRebaseFromC(ptr *C.git_rebase) *Rebase {
+ rebase := &Rebase{ptr: ptr}
+ runtime.SetFinalizer(rebase, (*Rebase).Free)
+ return rebase
+}
diff --git a/vendor/github.com/libgit2/git2go/refdb.go b/vendor/github.com/libgit2/git2go/refdb.go
new file mode 100644
index 000000000..578f43cc0
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/refdb.go
@@ -0,0 +1,62 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/sys/refdb_backend.h>
+
+extern void _go_git_refdb_backend_free(git_refdb_backend *backend);
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type Refdb struct {
+ ptr *C.git_refdb
+ r *Repository
+}
+
+type RefdbBackend struct {
+ ptr *C.git_refdb_backend
+}
+
+func (v *Repository) NewRefdb() (refdb *Refdb, err error) {
+ var ptr *C.git_refdb
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_refdb_new(&ptr, v.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ refdb = &Refdb{ptr: ptr, r: v}
+ runtime.SetFinalizer(refdb, (*Refdb).Free)
+ return refdb, nil
+}
+
+func NewRefdbBackendFromC(ptr unsafe.Pointer) (backend *RefdbBackend) {
+ backend = &RefdbBackend{(*C.git_refdb_backend)(ptr)}
+ return backend
+}
+
+func (v *Refdb) SetBackend(backend *RefdbBackend) (err error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_refdb_set_backend(v.ptr, backend.ptr)
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(backend)
+ if ret < 0 {
+ backend.Free()
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (v *RefdbBackend) Free() {
+ runtime.SetFinalizer(v, nil)
+ C._go_git_refdb_backend_free(v.ptr)
+}
diff --git a/vendor/github.com/libgit2/git2go/reference.go b/vendor/github.com/libgit2/git2go/reference.go
new file mode 100644
index 000000000..294c2f32e
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/reference.go
@@ -0,0 +1,488 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type ReferenceType int
+
+const (
+ ReferenceSymbolic ReferenceType = C.GIT_REF_SYMBOLIC
+ ReferenceOid ReferenceType = C.GIT_REF_OID
+)
+
+type Reference struct {
+ ptr *C.git_reference
+ repo *Repository
+}
+
+type ReferenceCollection struct {
+ repo *Repository
+}
+
+func (c *ReferenceCollection) Lookup(name string) (*Reference, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ var ptr *C.git_reference
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_reference_lookup(&ptr, c.repo.ptr, cname)
+ runtime.KeepAlive(c)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newReferenceFromC(ptr, c.repo), nil
+}
+
+func (c *ReferenceCollection) Create(name string, id *Oid, force bool, msg string) (*Reference, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ var cmsg *C.char
+ if msg == "" {
+ cmsg = nil
+ } else {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+
+ var ptr *C.git_reference
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_reference_create(&ptr, c.repo.ptr, cname, id.toC(), cbool(force), cmsg)
+ runtime.KeepAlive(c)
+ runtime.KeepAlive(id)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newReferenceFromC(ptr, c.repo), nil
+}
+
+func (c *ReferenceCollection) CreateSymbolic(name, target string, force bool, msg string) (*Reference, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ ctarget := C.CString(target)
+ defer C.free(unsafe.Pointer(ctarget))
+
+ var cmsg *C.char
+ if msg == "" {
+ cmsg = nil
+ } else {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+
+ var ptr *C.git_reference
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_reference_symbolic_create(&ptr, c.repo.ptr, cname, ctarget, cbool(force), cmsg)
+ runtime.KeepAlive(c)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newReferenceFromC(ptr, c.repo), nil
+}
+
+// EnsureLog ensures that there is a reflog for the given reference
+// name and creates an empty one if necessary.
+func (c *ReferenceCollection) EnsureLog(name string) error {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_ensure_log(c.repo.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+// HasLog returns whether there is a reflog for the given reference
+// name
+func (c *ReferenceCollection) HasLog(name string) (bool, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_has_log(c.repo.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+
+ return ret == 1, nil
+}
+
+// Dwim looks up a reference by DWIMing its short name
+func (c *ReferenceCollection) Dwim(name string) (*Reference, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_reference
+ ret := C.git_reference_dwim(&ptr, c.repo.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newReferenceFromC(ptr, c.repo), nil
+}
+
+func newReferenceFromC(ptr *C.git_reference, repo *Repository) *Reference {
+ ref := &Reference{ptr: ptr, repo: repo}
+ runtime.SetFinalizer(ref, (*Reference).Free)
+ return ref
+}
+
+func (v *Reference) SetSymbolicTarget(target string, msg string) (*Reference, error) {
+ var ptr *C.git_reference
+
+ ctarget := C.CString(target)
+ defer C.free(unsafe.Pointer(ctarget))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var cmsg *C.char
+ if msg == "" {
+ cmsg = nil
+ } else {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+
+ ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget, cmsg)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newReferenceFromC(ptr, v.repo), nil
+}
+
+func (v *Reference) SetTarget(target *Oid, msg string) (*Reference, error) {
+ var ptr *C.git_reference
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var cmsg *C.char
+ if msg == "" {
+ cmsg = nil
+ } else {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+
+ ret := C.git_reference_set_target(&ptr, v.ptr, target.toC(), cmsg)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newReferenceFromC(ptr, v.repo), nil
+}
+
+func (v *Reference) Resolve() (*Reference, error) {
+ var ptr *C.git_reference
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_resolve(&ptr, v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newReferenceFromC(ptr, v.repo), nil
+}
+
+func (v *Reference) Rename(name string, force bool, msg string) (*Reference, error) {
+ var ptr *C.git_reference
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ var cmsg *C.char
+ if msg == "" {
+ cmsg = nil
+ } else {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_rename(&ptr, v.ptr, cname, cbool(force), cmsg)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newReferenceFromC(ptr, v.repo), nil
+}
+
+func (v *Reference) Target() *Oid {
+ ret := newOidFromC(C.git_reference_target(v.ptr))
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Reference) SymbolicTarget() string {
+ var ret string
+ cstr := C.git_reference_symbolic_target(v.ptr)
+
+ if cstr != nil {
+ return C.GoString(cstr)
+ }
+
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Reference) Delete() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_delete(v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (v *Reference) Peel(t ObjectType) (*Object, error) {
+ var cobj *C.git_object
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_reference_peel(&cobj, v.ptr, C.git_otype(t))
+ runtime.KeepAlive(v)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return allocObject(cobj, v.repo), nil
+}
+
+// Owner returns a weak reference to the repository which owns this
+// reference.
+func (v *Reference) Owner() *Repository {
+ return &Repository{
+ ptr: C.git_reference_owner(v.ptr),
+ }
+}
+
+// Cmp compares v to ref2. It returns 0 on equality, otherwise a
+// stable sorting.
+func (v *Reference) Cmp(ref2 *Reference) int {
+ ret := int(C.git_reference_cmp(v.ptr, ref2.ptr))
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(ref2)
+ return ret
+}
+
+// Shorthand returns a "human-readable" short reference name.
+func (v *Reference) Shorthand() string {
+ ret := C.GoString(C.git_reference_shorthand(v.ptr))
+ runtime.KeepAlive(v)
+ return ret
+}
+
+// Name returns the full name of v.
+func (v *Reference) Name() string {
+ ret := C.GoString(C.git_reference_name(v.ptr))
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Reference) Type() ReferenceType {
+ ret := ReferenceType(C.git_reference_type(v.ptr))
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Reference) IsBranch() bool {
+ ret := C.git_reference_is_branch(v.ptr) == 1
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Reference) IsRemote() bool {
+ ret := C.git_reference_is_remote(v.ptr) == 1
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Reference) IsTag() bool {
+ ret := C.git_reference_is_tag(v.ptr) == 1
+ runtime.KeepAlive(v)
+ return ret
+}
+
+// IsNote checks if the reference is a note.
+func (v *Reference) IsNote() bool {
+ ret := C.git_reference_is_note(v.ptr) == 1
+ runtime.KeepAlive(v)
+ return ret
+}
+
+func (v *Reference) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_reference_free(v.ptr)
+}
+
+type ReferenceIterator struct {
+ ptr *C.git_reference_iterator
+ repo *Repository
+}
+
+type ReferenceNameIterator struct {
+ *ReferenceIterator
+}
+
+// NewReferenceIterator creates a new iterator over reference names
+func (repo *Repository) NewReferenceIterator() (*ReferenceIterator, error) {
+ var ptr *C.git_reference_iterator
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_iterator_new(&ptr, repo.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newReferenceIteratorFromC(ptr, repo), nil
+}
+
+// NewReferenceIterator creates a new branch iterator over reference names
+func (repo *Repository) NewReferenceNameIterator() (*ReferenceNameIterator, error) {
+ var ptr *C.git_reference_iterator
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_iterator_new(&ptr, repo.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ iter := newReferenceIteratorFromC(ptr, repo)
+ return iter.Names(), nil
+}
+
+// NewReferenceIteratorGlob creates an iterator over reference names
+// that match the speicified glob. The glob is of the usual fnmatch
+// type.
+func (repo *Repository) NewReferenceIteratorGlob(glob string) (*ReferenceIterator, error) {
+ cstr := C.CString(glob)
+ defer C.free(unsafe.Pointer(cstr))
+ var ptr *C.git_reference_iterator
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_iterator_glob_new(&ptr, repo.ptr, cstr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newReferenceIteratorFromC(ptr, repo), nil
+}
+
+func (i *ReferenceIterator) Names() *ReferenceNameIterator {
+ return &ReferenceNameIterator{i}
+}
+
+// NextName retrieves the next reference name. If the iteration is over,
+// the returned error is git.ErrIterOver
+func (v *ReferenceNameIterator) Next() (string, error) {
+ var ptr *C.char
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_next_name(&ptr, v.ptr)
+ if ret < 0 {
+ return "", MakeGitError(ret)
+ }
+
+ return C.GoString(ptr), nil
+}
+
+// Next retrieves the next reference. If the iterationis over, the
+// returned error is git.ErrIterOver
+func (v *ReferenceIterator) Next() (*Reference, error) {
+ var ptr *C.git_reference
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_reference_next(&ptr, v.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newReferenceFromC(ptr, v.repo), nil
+}
+
+func newReferenceIteratorFromC(ptr *C.git_reference_iterator, r *Repository) *ReferenceIterator {
+ return &ReferenceIterator{
+ ptr: ptr,
+ repo: r,
+ }
+}
+
+// Free the reference iterator
+func (v *ReferenceIterator) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_reference_iterator_free(v.ptr)
+}
+
+// ReferenceIsValidName ensures the reference name is well-formed.
+//
+// Valid reference names must follow one of two patterns:
+//
+// 1. Top-level names must contain only capital letters and underscores,
+// and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD").
+//
+// 2. Names prefixed with "refs/" can be almost anything. You must avoid
+// the characters '~', '^', ':', ' \ ', '?', '[', and '*', and the sequences
+// ".." and " @ {" which have special meaning to revparse.
+func ReferenceIsValidName(name string) bool {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ if C.git_reference_is_valid_name(cname) == 1 {
+ return true
+ }
+ return false
+}
diff --git a/vendor/github.com/libgit2/git2go/remote.go b/vendor/github.com/libgit2/git2go/remote.go
new file mode 100644
index 000000000..b4b1dd727
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/remote.go
@@ -0,0 +1,872 @@
+package git
+
+/*
+#include <git2.h>
+#include <string.h>
+
+extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks);
+
+*/
+import "C"
+import (
+ "crypto/x509"
+ "reflect"
+ "runtime"
+ "strings"
+ "unsafe"
+)
+
+type TransferProgress struct {
+ 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)}
+}
+
+type RemoteCompletion uint
+type ConnectDirection uint
+
+const (
+ RemoteCompletionDownload RemoteCompletion = C.GIT_REMOTE_COMPLETION_DOWNLOAD
+ RemoteCompletionIndexing RemoteCompletion = C.GIT_REMOTE_COMPLETION_INDEXING
+ RemoteCompletionError RemoteCompletion = C.GIT_REMOTE_COMPLETION_ERROR
+
+ ConnectDirectionFetch ConnectDirection = C.GIT_DIRECTION_FETCH
+ ConnectDirectionPush ConnectDirection = C.GIT_DIRECTION_PUSH
+)
+
+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
+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
+
+type RemoteCallbacks struct {
+ SidebandProgressCallback TransportMessageCallback
+ CompletionCallback
+ CredentialsCallback
+ TransferProgressCallback
+ UpdateTipsCallback
+ CertificateCheckCallback
+ PackProgressCallback PackbuilderProgressCallback
+ PushTransferProgressCallback
+ PushUpdateReferenceCallback
+}
+
+type FetchPrune uint
+
+const (
+ // Use the setting from the configuration
+ FetchPruneUnspecified FetchPrune = C.GIT_FETCH_PRUNE_UNSPECIFIED
+ // Force pruning on
+ FetchPruneOn FetchPrune = C.GIT_FETCH_PRUNE
+ // Force pruning off
+ FetchNoPrune FetchPrune = C.GIT_FETCH_NO_PRUNE
+)
+
+type DownloadTags uint
+
+const (
+
+ // Use the setting from the configuration.
+ DownloadTagsUnspecified DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED
+ // Ask the server for tags pointing to objects we're already
+ // downloading.
+ DownloadTagsAuto DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_AUTO
+
+ // Don't ask for any tags beyond the refspecs.
+ DownloadTagsNone DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_NONE
+
+ // Ask for the all the tags.
+ DownloadTagsAll DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_ALL
+)
+
+type FetchOptions struct {
+ // Callbacks to use for this fetch operation
+ RemoteCallbacks RemoteCallbacks
+ // Whether to perform a prune after the fetch
+ Prune FetchPrune
+ // Whether to write the results to FETCH_HEAD. Defaults to
+ // on. Leave this default in order to behave like git.
+ UpdateFetchhead bool
+
+ // Determines how to behave regarding tags on the remote, such
+ // as auto-downloading tags for objects we're downloading or
+ // downloading all of them.
+ //
+ // The default is to auto-follow tags.
+ DownloadTags DownloadTags
+
+ // Headers are extra headers for the fetch operation.
+ Headers []string
+}
+
+type ProxyType uint
+
+const (
+ // Do not attempt to connect through a proxy
+ //
+ // If built against lbicurl, it itself may attempt to connect
+ // to a proxy if the environment variables specify it.
+ ProxyTypeNone ProxyType = C.GIT_PROXY_NONE
+
+ // Try to auto-detect the proxy from the git configuration.
+ ProxyTypeAuto ProxyType = C.GIT_PROXY_AUTO
+
+ // Connect via the URL given in the options
+ ProxyTypeSpecified ProxyType = C.GIT_PROXY_SPECIFIED
+)
+
+type ProxyOptions struct {
+ // The type of proxy to use (or none)
+ Type ProxyType
+
+ // The proxy's URL
+ Url string
+}
+
+type Remote struct {
+ ptr *C.git_remote
+ callbacks RemoteCallbacks
+ repo *Repository
+}
+
+type CertificateKind uint
+
+const (
+ CertificateX509 CertificateKind = C.GIT_CERT_X509
+ CertificateHostkey CertificateKind = C.GIT_CERT_HOSTKEY_LIBSSH2
+)
+
+// 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
+ HostkeySHA1 HostkeyKind = C.GIT_CERT_SSH_SHA1
+)
+
+// 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
+}
+
+type PushOptions struct {
+ // Callbacks to use for this push operation
+ RemoteCallbacks RemoteCallbacks
+
+ PbParallelism uint
+
+ // Headers are extra headers for the push operation.
+ Headers []string
+}
+
+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),
+ }
+}
+
+func untrackCalbacksPayload(callbacks *C.git_remote_callbacks) {
+ if callbacks != nil && callbacks.payload != nil {
+ pointerHandles.Untrack(callbacks.payload)
+ }
+}
+
+func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) {
+ C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
+ if callbacks == nil {
+ return
+ }
+ C._go_git_setup_callbacks(ptr)
+ ptr.payload = pointerHandles.Track(callbacks)
+}
+
+//export sidebandProgressCallback
+func sidebandProgressCallback(_str *C.char, _len C.int, data unsafe.Pointer) int {
+ callbacks := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.SidebandProgressCallback == nil {
+ return 0
+ }
+ str := C.GoStringN(_str, _len)
+ return int(callbacks.SidebandProgressCallback(str))
+}
+
+//export completionCallback
+func completionCallback(completion_type C.git_remote_completion_type, data unsafe.Pointer) int {
+ callbacks := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.CompletionCallback == nil {
+ return 0
+ }
+ return int(callbacks.CompletionCallback(RemoteCompletion(completion_type)))
+}
+
+//export credentialsCallback
+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 C.GIT_PASSTHROUGH
+ }
+ url := C.GoString(_url)
+ username_from_url := C.GoString(_username_from_url)
+ ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
+ if cred != nil {
+ *_cred = cred.ptr
+ }
+ return int(ret)
+}
+
+//export transferProgressCallback
+func transferProgressCallback(stats *C.git_transfer_progress, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.TransferProgressCallback == nil {
+ return 0
+ }
+ return int(callbacks.TransferProgressCallback(newTransferProgressFromC(stats)))
+}
+
+//export updateTipsCallback
+func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ if callbacks.UpdateTipsCallback == nil {
+ return 0
+ }
+ refname := C.GoString(_refname)
+ a := newOidFromC(_a)
+ b := newOidFromC(_b)
+ return int(callbacks.UpdateTipsCallback(refname, a, b))
+}
+
+//export certificateCheckCallback
+func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ // if there's no callback set, we need to make sure we fail if the library didn't consider this cert valid
+ if callbacks.CertificateCheckCallback == nil {
+ if _valid == 1 {
+ return 0
+ } else {
+ return C.GIT_ECERTIFICATE
+ }
+ }
+ host := C.GoString(_host)
+ valid := _valid != 0
+
+ var cert Certificate
+ if _cert.cert_type == C.GIT_CERT_X509 {
+ cert.Kind = CertificateX509
+ ccert := (*C.git_cert_x509)(unsafe.Pointer(_cert))
+ x509_certs, err := x509.ParseCertificates(C.GoBytes(ccert.data, C.int(ccert.len)))
+ if err != nil {
+ return C.GIT_EUSER
+ }
+
+ // we assume there's only one, which should hold true for any web server we want to talk to
+ 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
+ }
+
+ return int(callbacks.CertificateCheckCallback(&cert, valid, host))
+}
+
+//export packProgressCallback
+func packProgressCallback(stage C.int, current, total C.uint, data unsafe.Pointer) int {
+ callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+
+ 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, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+ 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, _ := pointerHandles.Get(data).(*RemoteCallbacks)
+
+ if callbacks.PushUpdateReferenceCallback == nil {
+ return 0
+ }
+
+ return int(callbacks.PushUpdateReferenceCallback(C.GoString(refname), C.GoString(status)))
+}
+
+func populateProxyOptions(ptr *C.git_proxy_options, opts *ProxyOptions) {
+ C.git_proxy_init_options(ptr, C.GIT_PROXY_OPTIONS_VERSION)
+ if opts == nil {
+ return
+ }
+
+ ptr._type = C.git_proxy_t(opts.Type)
+ ptr.url = C.CString(opts.Url)
+}
+
+func freeProxyOptions(ptr *C.git_proxy_options) {
+ C.free(unsafe.Pointer(ptr.url))
+}
+
+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
+}
+
+func (r *Remote) Free() {
+ runtime.SetFinalizer(r, nil)
+ C.git_remote_free(r.ptr)
+ r.ptr = nil
+}
+
+type RemoteCollection struct {
+ repo *Repository
+}
+
+func (c *RemoteCollection) List() ([]string, error) {
+ var r C.git_strarray
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_remote_list(&r, c.repo.ptr)
+ runtime.KeepAlive(c.repo)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ defer C.git_strarray_free(&r)
+
+ remotes := makeStringsFromCStrings(r.strings, int(r.count))
+ return remotes, nil
+}
+
+func (c *RemoteCollection) Create(name string, url string) (*Remote, error) {
+ remote := &Remote{repo: c.repo}
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create(&remote.ptr, c.repo.ptr, cname, curl)
+ 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))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_delete(c.repo.ptr, cname)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch string) (*Remote, error) {
+ remote := &Remote{repo: c.repo}
+
+ 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))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create_with_fetchspec(&remote.ptr, c.repo.ptr, cname, curl, cfetch)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (c *RemoteCollection) CreateAnonymous(url string) (*Remote, error) {
+ remote := &Remote{repo: c.repo}
+
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_create_anonymous(&remote.ptr, c.repo.ptr, curl)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (c *RemoteCollection) Lookup(name string) (*Remote, error) {
+ remote := &Remote{repo: c.repo}
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_lookup(&remote.ptr, c.repo.ptr, cname)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(remote, (*Remote).Free)
+ return remote, nil
+}
+
+func (o *Remote) Name() string {
+ s := C.git_remote_name(o.ptr)
+ runtime.KeepAlive(o)
+ return C.GoString(s)
+}
+
+func (o *Remote) Url() string {
+ s := C.git_remote_url(o.ptr)
+ runtime.KeepAlive(o)
+ return C.GoString(s)
+}
+
+func (o *Remote) PushUrl() string {
+ s := C.git_remote_pushurl(o.ptr)
+ runtime.KeepAlive(o)
+ return C.GoString(s)
+}
+
+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)
+ runtime.KeepAlive(c.repo)
+ 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))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_set_url(c.repo.ptr, cremote, curl)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (c *RemoteCollection) SetPushUrl(remote, url string) error {
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_set_pushurl(c.repo.ptr, cremote, curl)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (c *RemoteCollection) AddFetch(remote, refspec string) error {
+ crefspec := C.CString(refspec)
+ defer C.free(unsafe.Pointer(crefspec))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_add_fetch(c.repo.ptr, cremote, crefspec)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+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
+}
+
+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))
+}
+
+func (o *Remote) FetchRefspecs() ([]string, error) {
+ crefspecs := C.git_strarray{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_get_fetch_refspecs(&crefspecs, o.ptr)
+ runtime.KeepAlive(o)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ defer C.git_strarray_free(&crefspecs)
+
+ refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
+ return refspecs, nil
+}
+
+func (c *RemoteCollection) AddPush(remote, refspec string) error {
+ crefspec := C.CString(refspec)
+ defer C.free(unsafe.Pointer(crefspec))
+ cremote := C.CString(remote)
+ defer C.free(unsafe.Pointer(cremote))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_add_push(c.repo.ptr, cremote, crefspec)
+ runtime.KeepAlive(c.repo)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) PushRefspecs() ([]string, error) {
+ crefspecs := C.git_strarray{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_get_push_refspecs(&crefspecs, o.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ defer C.git_strarray_free(&crefspecs)
+ runtime.KeepAlive(o)
+
+ refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
+ return refspecs, nil
+}
+
+func (o *Remote) RefspecCount() uint {
+ count := C.git_remote_refspec_count(o.ptr)
+ runtime.KeepAlive(o)
+ return uint(count)
+}
+
+func populateFetchOptions(options *C.git_fetch_options, opts *FetchOptions) {
+ C.git_fetch_init_options(options, C.GIT_FETCH_OPTIONS_VERSION)
+ if opts == nil {
+ return
+ }
+ populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks)
+ options.prune = C.git_fetch_prune_t(opts.Prune)
+ options.update_fetchhead = cbool(opts.UpdateFetchhead)
+ options.download_tags = C.git_remote_autotag_option_t(opts.DownloadTags)
+
+ options.custom_headers = C.git_strarray{}
+ options.custom_headers.count = C.size_t(len(opts.Headers))
+ options.custom_headers.strings = makeCStringsFromStrings(opts.Headers)
+}
+
+func populatePushOptions(options *C.git_push_options, opts *PushOptions) {
+ C.git_push_init_options(options, C.GIT_PUSH_OPTIONS_VERSION)
+ if opts == nil {
+ return
+ }
+
+ options.pb_parallelism = C.uint(opts.PbParallelism)
+
+ options.custom_headers = C.git_strarray{}
+ options.custom_headers.count = C.size_t(len(opts.Headers))
+ options.custom_headers.strings = makeCStringsFromStrings(opts.Headers)
+
+ populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks)
+}
+
+// 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; msg specifies what to use for the reflog
+// entries. Leave "" to use defaults.
+func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error {
+ var cmsg *C.char = nil
+ if msg != "" {
+ cmsg = C.CString(msg)
+ defer C.free(unsafe.Pointer(cmsg))
+ }
+
+ crefspecs := C.git_strarray{}
+ crefspecs.count = C.size_t(len(refspecs))
+ crefspecs.strings = makeCStringsFromStrings(refspecs)
+ defer freeStrarray(&crefspecs)
+
+ coptions := (*C.git_fetch_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_fetch_options{}))))
+ defer C.free(unsafe.Pointer(coptions))
+
+ populateFetchOptions(coptions, opts)
+ defer untrackCalbacksPayload(&coptions.callbacks)
+ defer freeStrarray(&coptions.custom_headers)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_fetch(o.ptr, &crefspecs, coptions, cmsg)
+ runtime.KeepAlive(o)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
+ return o.Connect(ConnectDirectionFetch, callbacks, proxyOpts, headers)
+}
+
+func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
+ return o.Connect(ConnectDirectionPush, callbacks, proxyOpts, headers)
+}
+
+// Connect opens a connection to a remote.
+//
+// The transport is selected based on the URL. The direction argument
+// is due to a limitation of the git protocol (over TCP or SSH) which
+// starts up a specific binary which can only do the one or the other.
+//
+// 'headers' are extra HTTP headers to use in this connection.
+func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
+ var ccallbacks C.git_remote_callbacks
+ populateRemoteCallbacks(&ccallbacks, callbacks)
+
+ var cproxy C.git_proxy_options
+ populateProxyOptions(&cproxy, proxyOpts)
+ defer freeProxyOptions(&cproxy)
+
+ cheaders := C.git_strarray{}
+ cheaders.count = C.size_t(len(headers))
+ cheaders.strings = makeCStringsFromStrings(headers)
+ defer freeStrarray(&cheaders)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders)
+ runtime.KeepAlive(o)
+ if ret != 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) Disconnect() {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ C.git_remote_disconnect(o.ptr)
+ runtime.KeepAlive(o)
+}
+
+func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
+
+ var refs **C.git_remote_head
+ var length C.size_t
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_ls(&refs, &length, o.ptr)
+ runtime.KeepAlive(o)
+ if 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
+
+ for _, s := range goSlice {
+ head := newRemoteHeadFromC(s)
+
+ if len(filterRefs) > 0 {
+ for _, r := range filterRefs {
+ if strings.Contains(head.Name, r) {
+ heads = append(heads, head)
+ break
+ }
+ }
+ } else {
+ heads = append(heads, head)
+ }
+ }
+
+ return heads, nil
+}
+
+func (o *Remote) Push(refspecs []string, opts *PushOptions) error {
+ crefspecs := C.git_strarray{}
+ crefspecs.count = C.size_t(len(refspecs))
+ crefspecs.strings = makeCStringsFromStrings(refspecs)
+ defer freeStrarray(&crefspecs)
+
+ coptions := (*C.git_push_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_push_options{}))))
+ defer C.free(unsafe.Pointer(coptions))
+
+ populatePushOptions(coptions, opts)
+ defer untrackCalbacksPayload(&coptions.callbacks)
+ defer freeStrarray(&coptions.custom_headers)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_push(o.ptr, &crefspecs, coptions)
+ runtime.KeepAlive(o)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (o *Remote) PruneRefs() bool {
+ return C.git_remote_prune_refs(o.ptr) > 0
+}
+
+func (o *Remote) Prune(callbacks *RemoteCallbacks) error {
+ var ccallbacks C.git_remote_callbacks
+ populateRemoteCallbacks(&ccallbacks, callbacks)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_prune(o.ptr, &ccallbacks)
+ runtime.KeepAlive(o)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/repository.go b/vendor/github.com/libgit2/git2go/repository.go
new file mode 100644
index 000000000..d8de97a6d
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/repository.go
@@ -0,0 +1,543 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/sys/repository.h>
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+// Repository
+type Repository struct {
+ ptr *C.git_repository
+ // Remotes represents the collection of remotes and can be
+ // used to add, remove and configure remotes for this
+ // repository.
+ Remotes RemoteCollection
+ // Submodules represents the collection of submodules and can
+ // be used to add, remove and configure submodules in this
+ // repository.
+ Submodules SubmoduleCollection
+ // References represents the collection of references and can
+ // be used to create, remove or update references for this repository.
+ References ReferenceCollection
+ // Notes represents the collection of notes and can be used to
+ // read, write and delete notes from this repository.
+ Notes NoteCollection
+ // Tags represents the collection of tags and can be used to create,
+ // list, iterate and remove tags in this repository.
+ Tags TagsCollection
+ // Stashes represents the collection of stashes and can be used to
+ // save, apply and iterate over stash states in this repository.
+ Stashes StashCollection
+}
+
+func newRepositoryFromC(ptr *C.git_repository) *Repository {
+ repo := &Repository{ptr: ptr}
+
+ repo.Remotes.repo = repo
+ repo.Submodules.repo = repo
+ repo.References.repo = repo
+ repo.Notes.repo = repo
+ repo.Tags.repo = repo
+ repo.Stashes.repo = repo
+
+ runtime.SetFinalizer(repo, (*Repository).Free)
+
+ return repo
+}
+
+func OpenRepository(path string) (*Repository, error) {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_repository
+ ret := C.git_repository_open(&ptr, cpath)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newRepositoryFromC(ptr), nil
+}
+
+type RepositoryOpenFlag int
+
+const (
+ RepositoryOpenNoSearch RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_NO_SEARCH
+ RepositoryOpenCrossFs RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_CROSS_FS
+ RepositoryOpenBare RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_BARE
+ RepositoryOpenFromEnv RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_FROM_ENV
+ RepositoryOpenNoDotGit RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_NO_DOTGIT
+)
+
+func OpenRepositoryExtended(path string, flags RepositoryOpenFlag, ceiling string) (*Repository, error) {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ var cceiling *C.char = nil
+ if len(ceiling) > 0 {
+ cceiling = C.CString(ceiling)
+ defer C.free(unsafe.Pointer(cceiling))
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_repository
+ ret := C.git_repository_open_ext(&ptr, cpath, C.uint(flags), cceiling)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newRepositoryFromC(ptr), nil
+}
+
+func InitRepository(path string, isbare bool) (*Repository, error) {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_repository
+ ret := C.git_repository_init(&ptr, cpath, ucbool(isbare))
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newRepositoryFromC(ptr), nil
+}
+
+func NewRepositoryWrapOdb(odb *Odb) (repo *Repository, err error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_repository
+ ret := C.git_repository_wrap_odb(&ptr, odb.ptr)
+ runtime.KeepAlive(odb)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newRepositoryFromC(ptr), nil
+}
+
+func (v *Repository) SetRefdb(refdb *Refdb) {
+ C.git_repository_set_refdb(v.ptr, refdb.ptr)
+ runtime.KeepAlive(v)
+}
+
+func (v *Repository) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_repository_free(v.ptr)
+}
+
+func (v *Repository) Config() (*Config, error) {
+ config := new(Config)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_config(&config.ptr, v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ runtime.SetFinalizer(config, (*Config).Free)
+ return config, nil
+}
+
+func (v *Repository) Index() (*Index, error) {
+ var ptr *C.git_index
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_index(&ptr, v.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newIndexFromC(ptr, v), nil
+}
+
+func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
+ var ptr *C.git_object
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t))
+ runtime.KeepAlive(id)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return allocObject(ptr, v), nil
+}
+
+func (v *Repository) Lookup(id *Oid) (*Object, error) {
+ return v.lookupType(id, ObjectAny)
+}
+
+func (v *Repository) LookupTree(id *Oid) (*Tree, error) {
+ obj, err := v.lookupType(id, ObjectTree)
+ if err != nil {
+ return nil, err
+ }
+
+ return obj.AsTree()
+}
+
+func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
+ obj, err := v.lookupType(id, ObjectCommit)
+ if err != nil {
+ return nil, err
+ }
+
+ return obj.AsCommit()
+}
+
+func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
+ obj, err := v.lookupType(id, ObjectBlob)
+ if err != nil {
+ return nil, err
+ }
+
+ return obj.AsBlob()
+}
+
+func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
+ obj, err := v.lookupType(id, ObjectTag)
+ if err != nil {
+ return nil, err
+ }
+
+ return obj.AsTag()
+}
+
+func (v *Repository) Head() (*Reference, error) {
+ var ptr *C.git_reference
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_repository_head(&ptr, v.ptr)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newReferenceFromC(ptr, v), nil
+}
+
+func (v *Repository) SetHead(refname string) error {
+ cname := C.CString(refname)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_repository_set_head(v.ptr, cname)
+ runtime.KeepAlive(v)
+ if ecode != 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *Repository) SetHeadDetached(id *Oid) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_repository_set_head_detached(v.ptr, id.toC())
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(id)
+ if ecode != 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *Repository) IsHeadDetached() (bool, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_head_detached(v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+
+ return ret != 0, nil
+}
+
+func (v *Repository) IsHeadUnborn() (bool, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_head_unborn(v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+ return ret != 0, nil
+}
+
+func (v *Repository) IsEmpty() (bool, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_is_empty(v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+
+ return ret != 0, nil
+}
+
+func (v *Repository) IsShallow() (bool, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_is_shallow(v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+ return ret != 0, nil
+}
+
+func (v *Repository) Walk() (*RevWalk, error) {
+
+ var walkPtr *C.git_revwalk
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revwalk_new(&walkPtr, v.ptr)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return revWalkFromC(v, walkPtr), nil
+}
+
+func (v *Repository) CreateCommit(
+ refname string, author, committer *Signature,
+ message string, tree *Tree, parents ...*Commit) (*Oid, error) {
+
+ oid := new(Oid)
+
+ var cref *C.char
+ if refname == "" {
+ cref = nil
+ } else {
+ cref = C.CString(refname)
+ defer C.free(unsafe.Pointer(cref))
+ }
+
+ cmsg := C.CString(message)
+ defer C.free(unsafe.Pointer(cmsg))
+
+ var cparents []*C.git_commit = nil
+ var parentsarg **C.git_commit = nil
+
+ nparents := len(parents)
+ if nparents > 0 {
+ cparents = make([]*C.git_commit, nparents)
+ for i, v := range parents {
+ cparents[i] = v.cast_ptr
+ }
+ parentsarg = &cparents[0]
+ }
+
+ authorSig, err := author.toC()
+ if err != nil {
+ return nil, err
+ }
+ defer C.git_signature_free(authorSig)
+
+ committerSig, err := committer.toC()
+ if err != nil {
+ return nil, err
+ }
+ defer C.git_signature_free(committerSig)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_commit_create(
+ oid.toC(), v.ptr, cref,
+ authorSig, committerSig,
+ nil, cmsg, tree.cast_ptr, C.size_t(nparents), parentsarg)
+
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(oid)
+ runtime.KeepAlive(parents)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return oid, nil
+}
+
+func (v *Odb) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_odb_free(v.ptr)
+}
+
+func (v *Refdb) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_refdb_free(v.ptr)
+}
+
+func (v *Repository) Odb() (odb *Odb, err error) {
+ odb = new(Odb)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_odb(&odb.ptr, v.ptr)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ runtime.SetFinalizer(odb, (*Odb).Free)
+ return odb, nil
+}
+
+func (repo *Repository) Path() string {
+ s := C.GoString(C.git_repository_path(repo.ptr))
+ runtime.KeepAlive(repo)
+ return s
+}
+
+func (repo *Repository) IsBare() bool {
+ ret := C.git_repository_is_bare(repo.ptr) != 0
+ runtime.KeepAlive(repo)
+ return ret
+}
+
+func (repo *Repository) Workdir() string {
+ s := C.GoString(C.git_repository_workdir(repo.ptr))
+ runtime.KeepAlive(repo)
+ return s
+}
+
+func (repo *Repository) SetWorkdir(workdir string, updateGitlink bool) error {
+ cstr := C.CString(workdir)
+ defer C.free(unsafe.Pointer(cstr))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if ret := C.git_repository_set_workdir(repo.ptr, cstr, cbool(updateGitlink)); ret < 0 {
+ return MakeGitError(ret)
+ }
+ runtime.KeepAlive(repo)
+
+ return nil
+}
+
+func (v *Repository) TreeBuilder() (*TreeBuilder, error) {
+ bld := new(TreeBuilder)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, nil); ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ runtime.SetFinalizer(bld, (*TreeBuilder).Free)
+
+ bld.repo = v
+ return bld, nil
+}
+
+func (v *Repository) TreeBuilderFromTree(tree *Tree) (*TreeBuilder, error) {
+ bld := new(TreeBuilder)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if ret := C.git_treebuilder_new(&bld.ptr, v.ptr, tree.cast_ptr); ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ runtime.SetFinalizer(bld, (*TreeBuilder).Free)
+
+ bld.repo = v
+ return bld, nil
+}
+
+type RepositoryState int
+
+const (
+ RepositoryStateNone RepositoryState = C.GIT_REPOSITORY_STATE_NONE
+ RepositoryStateMerge RepositoryState = C.GIT_REPOSITORY_STATE_MERGE
+ RepositoryStateRevert RepositoryState = C.GIT_REPOSITORY_STATE_REVERT
+ RepositoryStateCherrypick RepositoryState = C.GIT_REPOSITORY_STATE_CHERRYPICK
+ RepositoryStateBisect RepositoryState = C.GIT_REPOSITORY_STATE_BISECT
+ RepositoryStateRebase RepositoryState = C.GIT_REPOSITORY_STATE_REBASE
+ RepositoryStateRebaseInteractive RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_INTERACTIVE
+ RepositoryStateRebaseMerge RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_MERGE
+ RepositoryStateApplyMailbox RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX
+ RepositoryStateApplyMailboxOrRebase RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE
+)
+
+func (r *Repository) State() RepositoryState {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := RepositoryState(C.git_repository_state(r.ptr))
+ runtime.KeepAlive(r)
+
+ return ret
+}
+
+func (r *Repository) StateCleanup() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cErr := C.git_repository_state_cleanup(r.ptr)
+ runtime.KeepAlive(r)
+ if cErr < 0 {
+ return MakeGitError(cErr)
+ }
+ return nil
+}
+
+func (r *Repository) AddGitIgnoreRules(rules string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ crules := C.CString(rules)
+ defer C.free(unsafe.Pointer(crules))
+ ret := C.git_ignore_add_rule(r.ptr, crules)
+ runtime.KeepAlive(r)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (r *Repository) ClearGitIgnoreRules() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_ignore_clear_internal_rules(r.ptr)
+ runtime.KeepAlive(r)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/reset.go b/vendor/github.com/libgit2/git2go/reset.go
new file mode 100644
index 000000000..031f5bd12
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/reset.go
@@ -0,0 +1,42 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import "runtime"
+
+type ResetType int
+
+const (
+ ResetSoft ResetType = C.GIT_RESET_SOFT
+ ResetMixed ResetType = C.GIT_RESET_MIXED
+ ResetHard ResetType = C.GIT_RESET_HARD
+)
+
+func (r *Repository) ResetToCommit(commit *Commit, resetType ResetType, opts *CheckoutOpts) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ ret := C.git_reset(r.ptr, commit.ptr, C.git_reset_t(resetType), opts.toC())
+
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (r *Repository) ResetDefaultToCommit(commit *Commit, pathspecs []string) error {
+ cpathspecs := C.git_strarray{}
+ cpathspecs.count = C.size_t(len(pathspecs))
+ cpathspecs.strings = makeCStringsFromStrings(pathspecs)
+ defer freeStrarray(&cpathspecs)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+ ret := C.git_reset_default(r.ptr, commit.ptr, &cpathspecs)
+
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/revparse.go b/vendor/github.com/libgit2/git2go/revparse.go
new file mode 100644
index 000000000..950932b8f
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/revparse.go
@@ -0,0 +1,113 @@
+package git
+
+/*
+#include <git2.h>
+
+extern void _go_git_revspec_free(git_revspec *revspec);
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+type RevparseFlag int
+
+const (
+ RevparseSingle RevparseFlag = C.GIT_REVPARSE_SINGLE
+ RevparseRange RevparseFlag = C.GIT_REVPARSE_RANGE
+ RevparseMergeBase RevparseFlag = C.GIT_REVPARSE_MERGE_BASE
+)
+
+type Revspec struct {
+ to *Object
+ from *Object
+ flags RevparseFlag
+}
+
+func (rs *Revspec) To() *Object {
+ return rs.to
+}
+
+func (rs *Revspec) From() *Object {
+ return rs.from
+}
+
+func (rs *Revspec) Flags() RevparseFlag {
+ return rs.flags
+}
+
+func newRevspecFromC(ptr *C.git_revspec, repo *Repository) *Revspec {
+ var to *Object
+ var from *Object
+
+ if ptr.to != nil {
+ to = allocObject(ptr.to, repo)
+ }
+
+ if ptr.from != nil {
+ from = allocObject(ptr.from, repo)
+ }
+
+ return &Revspec{
+ to: to,
+ from: from,
+ flags: RevparseFlag(ptr.flags),
+ }
+}
+
+func (r *Repository) Revparse(spec string) (*Revspec, error) {
+ cspec := C.CString(spec)
+ defer C.free(unsafe.Pointer(cspec))
+
+ var crevspec C.git_revspec
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revparse(&crevspec, r.ptr, cspec)
+ if ecode != 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newRevspecFromC(&crevspec, r), nil
+}
+
+func (v *Repository) RevparseSingle(spec string) (*Object, error) {
+ cspec := C.CString(spec)
+ defer C.free(unsafe.Pointer(cspec))
+
+ var ptr *C.git_object
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revparse_single(&ptr, v.ptr, cspec)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return allocObject(ptr, v), nil
+}
+
+func (r *Repository) RevparseExt(spec string) (*Object, *Reference, error) {
+ cspec := C.CString(spec)
+ defer C.free(unsafe.Pointer(cspec))
+
+ var obj *C.git_object
+ var ref *C.git_reference
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revparse_ext(&obj, &ref, r.ptr, cspec)
+ if ecode != 0 {
+ return nil, nil, MakeGitError(ecode)
+ }
+
+ if ref == nil {
+ return allocObject(obj, r), nil, nil
+ }
+
+ return allocObject(obj, r), newReferenceFromC(ref, r), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/settings.go b/vendor/github.com/libgit2/git2go/settings.go
new file mode 100644
index 000000000..c7f1850ef
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/settings.go
@@ -0,0 +1,102 @@
+package git
+
+/*
+#include <git2.h>
+
+int _go_git_opts_get_search_path(int level, git_buf *buf)
+{
+ return git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, level, buf);
+}
+
+int _go_git_opts_set_search_path(int level, const char *path)
+{
+ return git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, level, path);
+}
+
+int _go_git_opts_set_size_t(int opt, size_t val)
+{
+ return git_libgit2_opts(opt, val);
+}
+
+int _go_git_opts_get_size_t(int opt, size_t *val)
+{
+ return git_libgit2_opts(opt, val);
+}
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+func SearchPath(level ConfigLevel) (string, error) {
+ var buf C.git_buf
+ defer C.git_buf_free(&buf)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C._go_git_opts_get_search_path(C.int(level), &buf)
+ if err < 0 {
+ return "", MakeGitError(err)
+ }
+
+ return C.GoString(buf.ptr), nil
+}
+
+func SetSearchPath(level ConfigLevel, path string) error {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C._go_git_opts_set_search_path(C.int(level), cpath)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
+
+func MwindowSize() (int, error) {
+ return getSizet(C.GIT_OPT_GET_MWINDOW_SIZE)
+}
+
+func SetMwindowSize(size int) error {
+ return setSizet(C.GIT_OPT_SET_MWINDOW_SIZE, size)
+}
+
+func MwindowMappedLimit() (int, error) {
+ return getSizet(C.GIT_OPT_GET_MWINDOW_MAPPED_LIMIT)
+}
+
+func SetMwindowMappedLimit(size int) error {
+ return setSizet(C.GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size)
+}
+
+func getSizet(opt C.int) (int, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var val C.size_t
+ err := C._go_git_opts_get_size_t(opt, &val)
+ if err < 0 {
+ return 0, MakeGitError(err)
+ }
+
+ return int(val), nil
+}
+
+func setSizet(opt C.int, val int) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cval := C.size_t(val)
+ err := C._go_git_opts_set_size_t(opt, cval)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/signature.go b/vendor/github.com/libgit2/git2go/signature.go
new file mode 100644
index 000000000..16964d231
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/signature.go
@@ -0,0 +1,74 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+ "time"
+ "unsafe"
+)
+
+type Signature struct {
+ Name string
+ Email string
+ When time.Time
+}
+
+func newSignatureFromC(sig *C.git_signature) *Signature {
+ // git stores minutes, go wants seconds
+ loc := time.FixedZone("", int(sig.when.offset)*60)
+ return &Signature{
+ C.GoString(sig.name),
+ C.GoString(sig.email),
+ time.Unix(int64(sig.when.time), 0).In(loc),
+ }
+}
+
+// the offset in mintes, which is what git wants
+func (v *Signature) Offset() int {
+ _, offset := v.When.Zone()
+ return offset / 60
+}
+
+func (sig *Signature) toC() (*C.git_signature, error) {
+ if sig == nil {
+ return nil, nil
+ }
+
+ var out *C.git_signature
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ name := C.CString(sig.Name)
+ defer C.free(unsafe.Pointer(name))
+
+ email := C.CString(sig.Email)
+ defer C.free(unsafe.Pointer(email))
+
+ ret := C.git_signature_new(&out, name, email, C.git_time_t(sig.When.Unix()), C.int(sig.Offset()))
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return out, nil
+}
+
+func (repo *Repository) DefaultSignature() (*Signature, error) {
+ var out *C.git_signature
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cErr := C.git_signature_default(&out, repo.ptr)
+ runtime.KeepAlive(repo)
+ if cErr < 0 {
+ return nil, MakeGitError(cErr)
+ }
+
+ defer C.git_signature_free(out)
+
+ return newSignatureFromC(out), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/stash.go b/vendor/github.com/libgit2/git2go/stash.go
new file mode 100644
index 000000000..8743da89e
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/stash.go
@@ -0,0 +1,342 @@
+package git
+
+/*
+#include <git2.h>
+
+extern void _go_git_setup_stash_apply_progress_callbacks(git_stash_apply_options *opts);
+extern int _go_git_stash_foreach(git_repository *repo, void *payload);
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+// StashFlag are flags that affect the stash save operation.
+type StashFlag int
+
+const (
+ // StashDefault represents no option, default.
+ StashDefault StashFlag = C.GIT_STASH_DEFAULT
+
+ // StashKeepIndex leaves all changes already added to the
+ // index intact in the working directory.
+ StashKeepIndex StashFlag = C.GIT_STASH_KEEP_INDEX
+
+ // StashIncludeUntracked means all untracked files are also
+ // stashed and then cleaned up from the working directory.
+ StashIncludeUntracked StashFlag = C.GIT_STASH_INCLUDE_UNTRACKED
+
+ // StashIncludeIgnored means all ignored files are also
+ // stashed and then cleaned up from the working directory.
+ StashIncludeIgnored StashFlag = C.GIT_STASH_INCLUDE_IGNORED
+)
+
+// StashCollection represents the possible operations that can be
+// performed on the collection of stashes for a repository.
+type StashCollection struct {
+ repo *Repository
+}
+
+// Save saves the local modifications to a new stash.
+//
+// Stasher is the identity of the person performing the stashing.
+// Message is the optional description along with the stashed state.
+// Flags control the stashing process and are given as bitwise OR.
+func (c *StashCollection) Save(
+ stasher *Signature, message string, flags StashFlag) (*Oid, error) {
+
+ oid := new(Oid)
+
+ stasherC, err := stasher.toC()
+ if err != nil {
+ return nil, err
+ }
+ defer C.git_signature_free(stasherC)
+
+ messageC := C.CString(message)
+ defer C.free(unsafe.Pointer(messageC))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_stash_save(
+ oid.toC(), c.repo.ptr,
+ stasherC, messageC, C.uint32_t(flags))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return oid, nil
+}
+
+// StashApplyFlag are flags that affect the stash apply operation.
+type StashApplyFlag int
+
+const (
+ // StashApplyDefault is the default.
+ StashApplyDefault StashApplyFlag = C.GIT_STASH_APPLY_DEFAULT
+
+ // StashApplyReinstateIndex will try to reinstate not only the
+ // working tree's changes, but also the index's changes.
+ StashApplyReinstateIndex StashApplyFlag = C.GIT_STASH_APPLY_REINSTATE_INDEX
+)
+
+// StashApplyProgress are flags describing the progress of the apply operation.
+type StashApplyProgress int
+
+const (
+ // StashApplyProgressNone means loading the stashed data from the object store.
+ StashApplyProgressNone StashApplyProgress = C.GIT_STASH_APPLY_PROGRESS_NONE
+
+ // StashApplyProgressLoadingStash means the stored index is being analyzed.
+ StashApplyProgressLoadingStash StashApplyProgress = C.GIT_STASH_APPLY_PROGRESS_LOADING_STASH
+
+ // StashApplyProgressAnalyzeIndex means the stored index is being analyzed.
+ StashApplyProgressAnalyzeIndex StashApplyProgress = C.GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX
+
+ // StashApplyProgressAnalyzeModified means the modified files are being analyzed.
+ StashApplyProgressAnalyzeModified StashApplyProgress = C.GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED
+
+ // StashApplyProgressAnalyzeUntracked means the untracked and ignored files are being analyzed.
+ StashApplyProgressAnalyzeUntracked StashApplyProgress = C.GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED
+
+ // StashApplyProgressCheckoutUntracked means the untracked files are being written to disk.
+ StashApplyProgressCheckoutUntracked StashApplyProgress = C.GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED
+
+ // StashApplyProgressCheckoutModified means the modified files are being written to disk.
+ StashApplyProgressCheckoutModified StashApplyProgress = C.GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED
+
+ // StashApplyProgressDone means the stash was applied successfully.
+ StashApplyProgressDone StashApplyProgress = C.GIT_STASH_APPLY_PROGRESS_DONE
+)
+
+// StashApplyProgressCallback is the apply operation notification callback.
+type StashApplyProgressCallback func(progress StashApplyProgress) error
+
+type stashApplyProgressData struct {
+ Callback StashApplyProgressCallback
+ Error error
+}
+
+//export stashApplyProgressCb
+func stashApplyProgressCb(progress C.git_stash_apply_progress_t, handle unsafe.Pointer) int {
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*stashApplyProgressData)
+ if !ok {
+ panic("could not retrieve data for handle")
+ }
+
+ if data != nil {
+ err := data.Callback(StashApplyProgress(progress))
+ if err != nil {
+ data.Error = err
+ return C.GIT_EUSER
+ }
+ }
+ return 0
+}
+
+// StashApplyOptions represents options to control the apply operation.
+type StashApplyOptions struct {
+ Flags StashApplyFlag
+ CheckoutOptions CheckoutOpts // options to use when writing files to the working directory
+ ProgressCallback StashApplyProgressCallback // optional callback to notify the consumer of application progress
+}
+
+// DefaultStashApplyOptions initializes the structure with default values.
+func DefaultStashApplyOptions() (StashApplyOptions, error) {
+ optsC := C.git_stash_apply_options{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_stash_apply_init_options(&optsC, C.GIT_STASH_APPLY_OPTIONS_VERSION)
+ if ecode < 0 {
+ return StashApplyOptions{}, MakeGitError(ecode)
+ }
+ return StashApplyOptions{
+ Flags: StashApplyFlag(optsC.flags),
+ CheckoutOptions: checkoutOptionsFromC(&optsC.checkout_options),
+ }, nil
+}
+
+func (opts *StashApplyOptions) toC() (
+ optsC *C.git_stash_apply_options, progressData *stashApplyProgressData) {
+
+ if opts != nil {
+ progressData = &stashApplyProgressData{
+ Callback: opts.ProgressCallback,
+ }
+
+ optsC = &C.git_stash_apply_options{
+ version: C.GIT_STASH_APPLY_OPTIONS_VERSION,
+ flags: C.git_stash_apply_flags(opts.Flags),
+ }
+ populateCheckoutOpts(&optsC.checkout_options, &opts.CheckoutOptions)
+ if opts.ProgressCallback != nil {
+ C._go_git_setup_stash_apply_progress_callbacks(optsC)
+ optsC.progress_payload = pointerHandles.Track(progressData)
+ }
+ }
+ return
+}
+
+// should be called after every call to toC() as deferred.
+func untrackStashApplyOptionsCallback(optsC *C.git_stash_apply_options) {
+ if optsC != nil && optsC.progress_payload != nil {
+ pointerHandles.Untrack(optsC.progress_payload)
+ }
+}
+
+func freeStashApplyOptions(optsC *C.git_stash_apply_options) {
+ if optsC != nil {
+ freeCheckoutOpts(&optsC.checkout_options)
+ }
+}
+
+// Apply applies a single stashed state from the stash list.
+//
+// If local changes in the working directory conflict with changes in the
+// stash then ErrConflict will be returned. In this case, the index
+// will always remain unmodified and all files in the working directory will
+// remain unmodified. However, if you are restoring untracked files or
+// ignored files and there is a conflict when applying the modified files,
+// then those files will remain in the working directory.
+//
+// If passing the StashApplyReinstateIndex flag and there would be conflicts
+// when reinstating the index, the function will return ErrConflict
+// and both the working directory and index will be left unmodified.
+//
+// Note that a minimum checkout strategy of 'CheckoutSafe' is implied.
+//
+// 'index' is the position within the stash list. 0 points to the most
+// recent stashed state.
+//
+// Returns error code ErrNotFound if there's no stashed state for the given
+// index, error code ErrConflict if local changes in the working directory
+// conflict with changes in the stash, the user returned error from the
+// StashApplyProgressCallback, if any, or other error code.
+//
+// Error codes can be interogated with IsErrorCode(err, ErrNotFound).
+func (c *StashCollection) Apply(index int, opts StashApplyOptions) error {
+ optsC, progressData := opts.toC()
+ defer untrackStashApplyOptionsCallback(optsC)
+ defer freeStashApplyOptions(optsC)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_stash_apply(c.repo.ptr, C.size_t(index), optsC)
+ runtime.KeepAlive(c)
+ if ret == C.GIT_EUSER {
+ return progressData.Error
+ }
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+// StashCallback is called per entry when interating over all
+// the stashed states.
+//
+// 'index' is the position of the current stash in the stash list,
+// 'message' is the message used when creating the stash and 'id'
+// is the commit id of the stash.
+type StashCallback func(index int, message string, id *Oid) error
+
+type stashCallbackData struct {
+ Callback StashCallback
+ Error error
+}
+
+//export stashForeachCb
+func stashForeachCb(index C.size_t, message *C.char, id *C.git_oid, handle unsafe.Pointer) int {
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*stashCallbackData)
+ if !ok {
+ panic("could not retrieve data for handle")
+ }
+
+ err := data.Callback(int(index), C.GoString(message), newOidFromC(id))
+ if err != nil {
+ data.Error = err
+ return C.GIT_EUSER
+ }
+ return 0
+}
+
+// Foreach loops over all the stashed states and calls the callback
+// for each one.
+//
+// If callback returns an error, this will stop looping.
+func (c *StashCollection) Foreach(callback StashCallback) error {
+ data := stashCallbackData{
+ Callback: callback,
+ }
+
+ handle := pointerHandles.Track(&data)
+ defer pointerHandles.Untrack(handle)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C._go_git_stash_foreach(c.repo.ptr, handle)
+ runtime.KeepAlive(c)
+ if ret == C.GIT_EUSER {
+ return data.Error
+ }
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+// Drop removes a single stashed state from the stash list.
+//
+// 'index' is the position within the stash list. 0 points
+// to the most recent stashed state.
+//
+// Returns error code ErrNotFound if there's no stashed
+// state for the given index.
+func (c *StashCollection) Drop(index int) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_stash_drop(c.repo.ptr, C.size_t(index))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+// Pop applies a single stashed state from the stash list
+// and removes it from the list if successful.
+//
+// 'index' is the position within the stash list. 0 points
+// to the most recent stashed state.
+//
+// 'opts' controls how stashes are applied.
+//
+// Returns error code ErrNotFound if there's no stashed
+// state for the given index.
+func (c *StashCollection) Pop(index int, opts StashApplyOptions) error {
+ optsC, progressData := opts.toC()
+ defer untrackStashApplyOptionsCallback(optsC)
+ defer freeStashApplyOptions(optsC)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_stash_pop(c.repo.ptr, C.size_t(index), optsC)
+ runtime.KeepAlive(c)
+ if ret == C.GIT_EUSER {
+ return progressData.Error
+ }
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/status.go b/vendor/github.com/libgit2/git2go/status.go
new file mode 100644
index 000000000..e37a96d53
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/status.go
@@ -0,0 +1,189 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+type Status int
+
+const (
+ StatusCurrent Status = C.GIT_STATUS_CURRENT
+ StatusIndexNew Status = C.GIT_STATUS_INDEX_NEW
+ StatusIndexModified Status = C.GIT_STATUS_INDEX_MODIFIED
+ StatusIndexDeleted Status = C.GIT_STATUS_INDEX_DELETED
+ StatusIndexRenamed Status = C.GIT_STATUS_INDEX_RENAMED
+ StatusIndexTypeChange Status = C.GIT_STATUS_INDEX_TYPECHANGE
+ StatusWtNew Status = C.GIT_STATUS_WT_NEW
+ StatusWtModified Status = C.GIT_STATUS_WT_MODIFIED
+ StatusWtDeleted Status = C.GIT_STATUS_WT_DELETED
+ StatusWtTypeChange Status = C.GIT_STATUS_WT_TYPECHANGE
+ StatusWtRenamed Status = C.GIT_STATUS_WT_RENAMED
+ StatusIgnored Status = C.GIT_STATUS_IGNORED
+ StatusConflicted Status = C.GIT_STATUS_CONFLICTED
+)
+
+type StatusEntry struct {
+ Status Status
+ HeadToIndex DiffDelta
+ IndexToWorkdir DiffDelta
+}
+
+func statusEntryFromC(statusEntry *C.git_status_entry) StatusEntry {
+ var headToIndex DiffDelta = DiffDelta{}
+ var indexToWorkdir DiffDelta = DiffDelta{}
+
+ // Based on the libgit2 status example, head_to_index can be null in some cases
+ if statusEntry.head_to_index != nil {
+ headToIndex = diffDeltaFromC(statusEntry.head_to_index)
+ }
+ if statusEntry.index_to_workdir != nil {
+ indexToWorkdir = diffDeltaFromC(statusEntry.index_to_workdir)
+ }
+
+ return StatusEntry{
+ Status: Status(statusEntry.status),
+ HeadToIndex: headToIndex,
+ IndexToWorkdir: indexToWorkdir,
+ }
+}
+
+type StatusList struct {
+ ptr *C.git_status_list
+ r *Repository
+}
+
+func newStatusListFromC(ptr *C.git_status_list, r *Repository) *StatusList {
+ if ptr == nil {
+ return nil
+ }
+
+ statusList := &StatusList{
+ ptr: ptr,
+ r: r,
+ }
+
+ runtime.SetFinalizer(statusList, (*StatusList).Free)
+ return statusList
+}
+
+func (statusList *StatusList) Free() {
+ if statusList.ptr == nil {
+ return
+ }
+ runtime.SetFinalizer(statusList, nil)
+ C.git_status_list_free(statusList.ptr)
+ statusList.ptr = nil
+}
+
+func (statusList *StatusList) ByIndex(index int) (StatusEntry, error) {
+ if statusList.ptr == nil {
+ return StatusEntry{}, ErrInvalid
+ }
+ ptr := C.git_status_byindex(statusList.ptr, C.size_t(index))
+ entry := statusEntryFromC(ptr)
+ runtime.KeepAlive(statusList)
+
+ return entry, nil
+}
+
+func (statusList *StatusList) EntryCount() (int, error) {
+ if statusList.ptr == nil {
+ return -1, ErrInvalid
+ }
+ ret := int(C.git_status_list_entrycount(statusList.ptr))
+ runtime.KeepAlive(statusList)
+
+ return ret, nil
+}
+
+type StatusOpt int
+
+const (
+ StatusOptIncludeUntracked StatusOpt = C.GIT_STATUS_OPT_INCLUDE_UNTRACKED
+ StatusOptIncludeIgnored StatusOpt = C.GIT_STATUS_OPT_INCLUDE_IGNORED
+ StatusOptIncludeUnmodified StatusOpt = C.GIT_STATUS_OPT_INCLUDE_UNMODIFIED
+ StatusOptExcludeSubmodules StatusOpt = C.GIT_STATUS_OPT_EXCLUDE_SUBMODULES
+ StatusOptRecurseUntrackedDirs StatusOpt = C.GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
+ StatusOptDisablePathspecMatch StatusOpt = C.GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
+ StatusOptRecurseIgnoredDirs StatusOpt = C.GIT_STATUS_OPT_RECURSE_IGNORED_DIRS
+ StatusOptRenamesHeadToIndex StatusOpt = C.GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
+ StatusOptRenamesIndexToWorkdir StatusOpt = C.GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
+ StatusOptSortCaseSensitively StatusOpt = C.GIT_STATUS_OPT_SORT_CASE_SENSITIVELY
+ StatusOptSortCaseInsensitively StatusOpt = C.GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
+ StatusOptRenamesFromRewrites StatusOpt = C.GIT_STATUS_OPT_RENAMES_FROM_REWRITES
+ StatusOptNoRefresh StatusOpt = C.GIT_STATUS_OPT_NO_REFRESH
+ StatusOptUpdateIndex StatusOpt = C.GIT_STATUS_OPT_UPDATE_INDEX
+)
+
+type StatusShow int
+
+const (
+ StatusShowIndexAndWorkdir StatusShow = C.GIT_STATUS_SHOW_INDEX_AND_WORKDIR
+ StatusShowIndexOnly StatusShow = C.GIT_STATUS_SHOW_INDEX_ONLY
+ StatusShowWorkdirOnly StatusShow = C.GIT_STATUS_SHOW_WORKDIR_ONLY
+)
+
+type StatusOptions struct {
+ Show StatusShow
+ Flags StatusOpt
+ Pathspec []string
+}
+
+func (v *Repository) StatusList(opts *StatusOptions) (*StatusList, error) {
+ var ptr *C.git_status_list
+ var copts *C.git_status_options
+
+ if opts != nil {
+ cpathspec := C.git_strarray{}
+ if opts.Pathspec != nil {
+ cpathspec.count = C.size_t(len(opts.Pathspec))
+ cpathspec.strings = makeCStringsFromStrings(opts.Pathspec)
+ defer freeStrarray(&cpathspec)
+ }
+
+ copts = &C.git_status_options{
+ version: C.GIT_STATUS_OPTIONS_VERSION,
+ show: C.git_status_show_t(opts.Show),
+ flags: C.uint(opts.Flags),
+ pathspec: cpathspec,
+ }
+ } else {
+ copts = &C.git_status_options{}
+ ret := C.git_status_init_options(copts, C.GIT_STATUS_OPTIONS_VERSION)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_status_list_new(&ptr, v.ptr, copts)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newStatusListFromC(ptr, v), nil
+}
+
+func (v *Repository) StatusFile(path string) (Status, error) {
+ var statusFlags C.uint
+ cPath := C.CString(path)
+ defer C.free(unsafe.Pointer(cPath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_status_file(&statusFlags, v.ptr, cPath)
+ runtime.KeepAlive(v)
+ if ret < 0 {
+ return 0, MakeGitError(ret)
+ }
+ return Status(statusFlags), nil
+}
diff --git a/vendor/github.com/libgit2/git2go/submodule.go b/vendor/github.com/libgit2/git2go/submodule.go
new file mode 100644
index 000000000..f4b4f15e3
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/submodule.go
@@ -0,0 +1,373 @@
+package git
+
+/*
+#include <git2.h>
+
+extern int _go_git_visit_submodule(git_repository *repo, void *fct);
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+// SubmoduleUpdateOptions
+type SubmoduleUpdateOptions struct {
+ *CheckoutOpts
+ *FetchOptions
+}
+
+// Submodule
+type Submodule struct {
+ ptr *C.git_submodule
+ r *Repository
+}
+
+func newSubmoduleFromC(ptr *C.git_submodule, r *Repository) *Submodule {
+ s := &Submodule{ptr: ptr, r: r}
+ runtime.SetFinalizer(s, (*Submodule).Free)
+ return s
+}
+
+func (sub *Submodule) Free() {
+ runtime.SetFinalizer(sub, nil)
+ C.git_submodule_free(sub.ptr)
+}
+
+type SubmoduleUpdate int
+
+const (
+ SubmoduleUpdateCheckout SubmoduleUpdate = C.GIT_SUBMODULE_UPDATE_CHECKOUT
+ SubmoduleUpdateRebase SubmoduleUpdate = C.GIT_SUBMODULE_UPDATE_REBASE
+ SubmoduleUpdateMerge SubmoduleUpdate = C.GIT_SUBMODULE_UPDATE_MERGE
+ SubmoduleUpdateNone SubmoduleUpdate = C.GIT_SUBMODULE_UPDATE_NONE
+)
+
+type SubmoduleIgnore int
+
+const (
+ SubmoduleIgnoreNone SubmoduleIgnore = C.GIT_SUBMODULE_IGNORE_NONE
+ SubmoduleIgnoreUntracked SubmoduleIgnore = C.GIT_SUBMODULE_IGNORE_UNTRACKED
+ SubmoduleIgnoreDirty SubmoduleIgnore = C.GIT_SUBMODULE_IGNORE_DIRTY
+ SubmoduleIgnoreAll SubmoduleIgnore = C.GIT_SUBMODULE_IGNORE_ALL
+)
+
+type SubmoduleStatus int
+
+const (
+ SubmoduleStatusInHead SubmoduleStatus = C.GIT_SUBMODULE_STATUS_IN_HEAD
+ SubmoduleStatusInIndex SubmoduleStatus = C.GIT_SUBMODULE_STATUS_IN_INDEX
+ SubmoduleStatusInConfig SubmoduleStatus = C.GIT_SUBMODULE_STATUS_IN_CONFIG
+ SubmoduleStatusInWd SubmoduleStatus = C.GIT_SUBMODULE_STATUS_IN_WD
+ SubmoduleStatusIndexAdded SubmoduleStatus = C.GIT_SUBMODULE_STATUS_INDEX_ADDED
+ SubmoduleStatusIndexDeleted SubmoduleStatus = C.GIT_SUBMODULE_STATUS_INDEX_DELETED
+ SubmoduleStatusIndexModified SubmoduleStatus = C.GIT_SUBMODULE_STATUS_INDEX_MODIFIED
+ SubmoduleStatusWdUninitialized SubmoduleStatus = C.GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
+ SubmoduleStatusWdAdded SubmoduleStatus = C.GIT_SUBMODULE_STATUS_WD_ADDED
+ SubmoduleStatusWdDeleted SubmoduleStatus = C.GIT_SUBMODULE_STATUS_WD_DELETED
+ SubmoduleStatusWdModified SubmoduleStatus = C.GIT_SUBMODULE_STATUS_WD_MODIFIED
+ SubmoduleStatusWdIndexModified SubmoduleStatus = C.GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED
+ SubmoduleStatusWdWdModified SubmoduleStatus = C.GIT_SUBMODULE_STATUS_WD_WD_MODIFIED
+ SubmoduleStatusWdUntracked SubmoduleStatus = C.GIT_SUBMODULE_STATUS_WD_UNTRACKED
+)
+
+type SubmoduleRecurse int
+
+const (
+ SubmoduleRecurseNo SubmoduleRecurse = C.GIT_SUBMODULE_RECURSE_NO
+ SubmoduleRecurseYes SubmoduleRecurse = C.GIT_SUBMODULE_RECURSE_YES
+ SubmoduleRecurseOndemand SubmoduleRecurse = C.GIT_SUBMODULE_RECURSE_ONDEMAND
+)
+
+type SubmoduleCollection struct {
+ repo *Repository
+}
+
+func SubmoduleStatusIsUnmodified(status int) bool {
+ o := SubmoduleStatus(status) & ^(SubmoduleStatusInHead | SubmoduleStatusInIndex |
+ SubmoduleStatusInConfig | SubmoduleStatusInWd)
+ return o == 0
+}
+
+func (c *SubmoduleCollection) Lookup(name string) (*Submodule, error) {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ var ptr *C.git_submodule
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_lookup(&ptr, c.repo.ptr, cname)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return newSubmoduleFromC(ptr, c.repo), nil
+}
+
+type SubmoduleCbk func(sub *Submodule, name string) int
+
+//export SubmoduleVisitor
+func SubmoduleVisitor(csub unsafe.Pointer, name *C.char, handle unsafe.Pointer) C.int {
+ sub := &Submodule{(*C.git_submodule)(csub), nil}
+
+ if callback, ok := pointerHandles.Get(handle).(SubmoduleCbk); ok {
+ return (C.int)(callback(sub, C.GoString(name)))
+ } else {
+ panic("invalid submodule visitor callback")
+ }
+}
+
+func (c *SubmoduleCollection) Foreach(cbk SubmoduleCbk) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ handle := pointerHandles.Track(cbk)
+ defer pointerHandles.Untrack(handle)
+
+ ret := C._go_git_visit_submodule(c.repo.ptr, handle)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (c *SubmoduleCollection) Add(url, path string, use_git_link bool) (*Submodule, error) {
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_submodule
+ ret := C.git_submodule_add_setup(&ptr, c.repo.ptr, curl, cpath, cbool(use_git_link))
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newSubmoduleFromC(ptr, c.repo), nil
+}
+
+func (sub *Submodule) FinalizeAdd() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_add_finalize(sub.ptr)
+ runtime.KeepAlive(sub)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (sub *Submodule) AddToIndex(write_index bool) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_add_to_index(sub.ptr, cbool(write_index))
+ runtime.KeepAlive(sub)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (sub *Submodule) Name() string {
+ n := C.GoString(C.git_submodule_name(sub.ptr))
+ runtime.KeepAlive(sub)
+ return n
+}
+
+func (sub *Submodule) Path() string {
+ n := C.GoString(C.git_submodule_path(sub.ptr))
+ runtime.KeepAlive(sub)
+ return n
+}
+
+func (sub *Submodule) Url() string {
+ n := C.GoString(C.git_submodule_url(sub.ptr))
+ runtime.KeepAlive(sub)
+ return n
+}
+
+func (c *SubmoduleCollection) SetUrl(submodule, url string) error {
+ csubmodule := C.CString(submodule)
+ defer C.free(unsafe.Pointer(csubmodule))
+ curl := C.CString(url)
+ defer C.free(unsafe.Pointer(curl))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_set_url(c.repo.ptr, csubmodule, curl)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (sub *Submodule) IndexId() *Oid {
+ var id *Oid
+ idx := C.git_submodule_index_id(sub.ptr)
+ if idx != nil {
+ id = newOidFromC(idx)
+ }
+ runtime.KeepAlive(sub)
+ return id
+}
+
+func (sub *Submodule) HeadId() *Oid {
+ var id *Oid
+ idx := C.git_submodule_head_id(sub.ptr)
+ if idx != nil {
+ id = newOidFromC(idx)
+ }
+ runtime.KeepAlive(sub)
+ return id
+}
+
+func (sub *Submodule) WdId() *Oid {
+ var id *Oid
+ idx := C.git_submodule_wd_id(sub.ptr)
+ if idx != nil {
+ id = newOidFromC(idx)
+ }
+ runtime.KeepAlive(sub)
+ return id
+}
+
+func (sub *Submodule) Ignore() SubmoduleIgnore {
+ o := C.git_submodule_ignore(sub.ptr)
+ runtime.KeepAlive(sub)
+ return SubmoduleIgnore(o)
+}
+
+func (c *SubmoduleCollection) SetIgnore(submodule string, ignore SubmoduleIgnore) error {
+ csubmodule := C.CString(submodule)
+ defer C.free(unsafe.Pointer(csubmodule))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_set_ignore(c.repo.ptr, csubmodule, C.git_submodule_ignore_t(ignore))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (sub *Submodule) UpdateStrategy() SubmoduleUpdate {
+ o := C.git_submodule_update_strategy(sub.ptr)
+ runtime.KeepAlive(sub)
+ return SubmoduleUpdate(o)
+}
+
+func (c *SubmoduleCollection) SetUpdate(submodule string, update SubmoduleUpdate) error {
+ csubmodule := C.CString(submodule)
+ defer C.free(unsafe.Pointer(csubmodule))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_set_update(c.repo.ptr, csubmodule, C.git_submodule_update_t(update))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func (sub *Submodule) FetchRecurseSubmodules() SubmoduleRecurse {
+ return SubmoduleRecurse(C.git_submodule_fetch_recurse_submodules(sub.ptr))
+}
+
+func (c *SubmoduleCollection) SetFetchRecurseSubmodules(submodule string, recurse SubmoduleRecurse) error {
+ csubmodule := C.CString(submodule)
+ defer C.free(unsafe.Pointer(csubmodule))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_set_fetch_recurse_submodules(c.repo.ptr, csubmodule, C.git_submodule_recurse_t(recurse))
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(C.int(ret))
+ }
+ return nil
+}
+
+func (sub *Submodule) Init(overwrite bool) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_init(sub.ptr, cbool(overwrite))
+ runtime.KeepAlive(sub)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (sub *Submodule) Sync() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_sync(sub.ptr)
+ runtime.KeepAlive(sub)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
+func (sub *Submodule) Open() (*Repository, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_repository
+ ret := C.git_submodule_open(&ptr, sub.ptr)
+ runtime.KeepAlive(sub)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ return newRepositoryFromC(ptr), nil
+}
+
+func (sub *Submodule) Update(init bool, opts *SubmoduleUpdateOptions) error {
+ var copts C.git_submodule_update_options
+ err := populateSubmoduleUpdateOptions(&copts, opts)
+ if err != nil {
+ return err
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_submodule_update(sub.ptr, cbool(init), &copts)
+ runtime.KeepAlive(sub)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+func populateSubmoduleUpdateOptions(ptr *C.git_submodule_update_options, opts *SubmoduleUpdateOptions) error {
+ C.git_submodule_update_init_options(ptr, C.GIT_SUBMODULE_UPDATE_OPTIONS_VERSION)
+
+ if opts == nil {
+ return nil
+ }
+
+ populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts)
+ populateFetchOptions(&ptr.fetch_opts, opts.FetchOptions)
+
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/tag.go b/vendor/github.com/libgit2/git2go/tag.go
new file mode 100644
index 000000000..4debdb7a2
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/tag.go
@@ -0,0 +1,245 @@
+package git
+
+/*
+#include <git2.h>
+
+extern int _go_git_tag_foreach(git_repository *repo, void *payload);
+*/
+import "C"
+import (
+ "runtime"
+ "unsafe"
+)
+
+// Tag
+type Tag struct {
+ Object
+ cast_ptr *C.git_tag
+}
+
+func (t *Tag) AsObject() *Object {
+ return &t.Object
+}
+
+func (t Tag) Message() string {
+ ret := C.GoString(C.git_tag_message(t.cast_ptr))
+ runtime.KeepAlive(t)
+ return ret
+}
+
+func (t Tag) Name() string {
+ ret := C.GoString(C.git_tag_name(t.cast_ptr))
+ runtime.KeepAlive(t)
+ return ret
+}
+
+func (t Tag) Tagger() *Signature {
+ cast_ptr := C.git_tag_tagger(t.cast_ptr)
+ ret := newSignatureFromC(cast_ptr)
+ runtime.KeepAlive(t)
+ return ret
+}
+
+func (t Tag) Target() *Object {
+ var ptr *C.git_object
+ ret := C.git_tag_target(&ptr, t.cast_ptr)
+ runtime.KeepAlive(t)
+ if ret != 0 {
+ return nil
+ }
+
+ return allocObject(ptr, t.repo)
+}
+
+func (t Tag) TargetId() *Oid {
+ ret := newOidFromC(C.git_tag_target_id(t.cast_ptr))
+ runtime.KeepAlive(t)
+ return ret
+}
+
+func (t Tag) TargetType() ObjectType {
+ ret := ObjectType(C.git_tag_target_type(t.cast_ptr))
+ runtime.KeepAlive(t)
+ return ret
+}
+
+type TagsCollection struct {
+ repo *Repository
+}
+
+func (c *TagsCollection) Create(name string, obj Objecter, tagger *Signature, message string) (*Oid, error) {
+
+ oid := new(Oid)
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ cmessage := C.CString(message)
+ defer C.free(unsafe.Pointer(cmessage))
+
+ taggerSig, err := tagger.toC()
+ if err != nil {
+ return nil, err
+ }
+ defer C.git_signature_free(taggerSig)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ o := obj.AsObject()
+ ret := C.git_tag_create(oid.toC(), c.repo.ptr, cname, o.ptr, taggerSig, cmessage, 0)
+ runtime.KeepAlive(c)
+ runtime.KeepAlive(obj)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ return oid, nil
+}
+
+func (c *TagsCollection) Remove(name string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ ret := C.git_tag_delete(c.repo.ptr, cname)
+ runtime.KeepAlive(c)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+
+ return nil
+}
+
+// CreateLightweight creates a new lightweight tag pointing to an object
+// and returns the id of the target object.
+//
+// The name of the tag is validated for consistency (see git_tag_create() for the rules
+// https://libgit2.github.com/libgit2/#HEAD/group/tag/git_tag_create) and should
+// not conflict with an already existing tag name.
+//
+// If force is true and a reference already exists with the given name, it'll be replaced.
+//
+// The created tag is a simple reference and can be queried using
+// repo.References.Lookup("refs/tags/<name>"). The name of the tag (eg "v1.0.0")
+// is queried with ref.Shorthand().
+func (c *TagsCollection) CreateLightweight(name string, obj Objecter, force bool) (*Oid, error) {
+
+ oid := new(Oid)
+
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ o := obj.AsObject()
+ err := C.git_tag_create_lightweight(oid.toC(), c.repo.ptr, cname, o.ptr, cbool(force))
+ runtime.KeepAlive(c)
+ runtime.KeepAlive(obj)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return oid, nil
+}
+
+// List returns the names of all the tags in the repository,
+// eg: ["v1.0.1", "v2.0.0"].
+func (c *TagsCollection) List() ([]string, error) {
+ var strC C.git_strarray
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_tag_list(&strC, c.repo.ptr)
+ runtime.KeepAlive(c)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ defer C.git_strarray_free(&strC)
+
+ tags := makeStringsFromCStrings(strC.strings, int(strC.count))
+ return tags, nil
+}
+
+// ListWithMatch returns the names of all the tags in the repository
+// that match a given pattern.
+//
+// The pattern is a standard fnmatch(3) pattern http://man7.org/linux/man-pages/man3/fnmatch.3.html
+func (c *TagsCollection) ListWithMatch(pattern string) ([]string, error) {
+ var strC C.git_strarray
+
+ patternC := C.CString(pattern)
+ defer C.free(unsafe.Pointer(patternC))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_tag_list_match(&strC, patternC, c.repo.ptr)
+ runtime.KeepAlive(c)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ defer C.git_strarray_free(&strC)
+
+ tags := makeStringsFromCStrings(strC.strings, int(strC.count))
+ return tags, nil
+}
+
+// TagForeachCallback is called for each tag in the repository.
+//
+// The name is the full ref name eg: "refs/tags/v1.0.0".
+//
+// Note that the callback is called for lightweight tags as well,
+// so repo.LookupTag() will return an error for these tags. Use
+// repo.References.Lookup() instead.
+type TagForeachCallback func(name string, id *Oid) error
+type tagForeachData struct {
+ callback TagForeachCallback
+ err error
+}
+
+//export gitTagForeachCb
+func gitTagForeachCb(name *C.char, id *C.git_oid, handle unsafe.Pointer) int {
+ payload := pointerHandles.Get(handle)
+ data, ok := payload.(*tagForeachData)
+ if !ok {
+ panic("could not retrieve tag foreach CB handle")
+ }
+
+ err := data.callback(C.GoString(name), newOidFromC(id))
+ if err != nil {
+ data.err = err
+ return C.GIT_EUSER
+ }
+
+ return 0
+}
+
+// Foreach calls the callback for each tag in the repository.
+func (c *TagsCollection) Foreach(callback TagForeachCallback) error {
+ data := tagForeachData{
+ callback: callback,
+ err: nil,
+ }
+
+ handle := pointerHandles.Track(&data)
+ defer pointerHandles.Untrack(handle)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C._go_git_tag_foreach(c.repo.ptr, handle)
+ runtime.KeepAlive(c)
+ if err == C.GIT_EUSER {
+ return data.err
+ }
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/libgit2/git2go/tree.go b/vendor/github.com/libgit2/git2go/tree.go
new file mode 100644
index 000000000..02507d2c9
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/tree.go
@@ -0,0 +1,212 @@
+package git
+
+/*
+#include <git2.h>
+
+extern int _go_git_treewalk(git_tree *tree, git_treewalk_mode mode, void *ptr);
+*/
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+type Filemode int
+
+const (
+ FilemodeTree Filemode = C.GIT_FILEMODE_TREE
+ FilemodeBlob Filemode = C.GIT_FILEMODE_BLOB
+ FilemodeBlobExecutable Filemode = C.GIT_FILEMODE_BLOB_EXECUTABLE
+ FilemodeLink Filemode = C.GIT_FILEMODE_LINK
+ FilemodeCommit Filemode = C.GIT_FILEMODE_COMMIT
+)
+
+type Tree struct {
+ Object
+ cast_ptr *C.git_tree
+}
+
+func (t *Tree) AsObject() *Object {
+ return &t.Object
+}
+
+type TreeEntry struct {
+ Name string
+ Id *Oid
+ Type ObjectType
+ Filemode Filemode
+}
+
+func newTreeEntry(entry *C.git_tree_entry) *TreeEntry {
+ return &TreeEntry{
+ C.GoString(C.git_tree_entry_name(entry)),
+ newOidFromC(C.git_tree_entry_id(entry)),
+ ObjectType(C.git_tree_entry_type(entry)),
+ Filemode(C.git_tree_entry_filemode(entry)),
+ }
+}
+
+func (t Tree) EntryByName(filename string) *TreeEntry {
+ cname := C.CString(filename)
+ defer C.free(unsafe.Pointer(cname))
+
+ entry := C.git_tree_entry_byname(t.cast_ptr, cname)
+ if entry == nil {
+ return nil
+ }
+
+ goEntry := newTreeEntry(entry)
+ runtime.KeepAlive(t)
+ return goEntry
+}
+
+// EntryById performs a lookup for a tree entry with the given SHA value.
+//
+// It returns a *TreeEntry that is owned by the Tree. You don't have to
+// free it, but you must not use it after the Tree is freed.
+//
+// Warning: this must examine every entry in the tree, so it is not fast.
+func (t Tree) EntryById(id *Oid) *TreeEntry {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ entry := C.git_tree_entry_byid(t.cast_ptr, id.toC())
+ runtime.KeepAlive(id)
+ if entry == nil {
+ return nil
+ }
+
+ goEntry := newTreeEntry(entry)
+ runtime.KeepAlive(t)
+ return goEntry
+}
+
+// EntryByPath looks up an entry by its full path, recursing into
+// deeper trees if necessary (i.e. if there are slashes in the path)
+func (t Tree) EntryByPath(path string) (*TreeEntry, error) {
+ cpath := C.CString(path)
+ defer C.free(unsafe.Pointer(cpath))
+ var entry *C.git_tree_entry
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_tree_entry_bypath(&entry, t.cast_ptr, cpath)
+ runtime.KeepAlive(t)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ defer C.git_tree_entry_free(entry)
+
+ return newTreeEntry(entry), nil
+}
+
+func (t Tree) EntryByIndex(index uint64) *TreeEntry {
+ entry := C.git_tree_entry_byindex(t.cast_ptr, C.size_t(index))
+ if entry == nil {
+ return nil
+ }
+
+ goEntry := newTreeEntry(entry)
+ runtime.KeepAlive(t)
+ return goEntry
+}
+
+func (t Tree) EntryCount() uint64 {
+ num := C.git_tree_entrycount(t.cast_ptr)
+ runtime.KeepAlive(t)
+ return uint64(num)
+}
+
+type TreeWalkCallback func(string, *TreeEntry) int
+
+//export CallbackGitTreeWalk
+func CallbackGitTreeWalk(_root *C.char, _entry unsafe.Pointer, ptr unsafe.Pointer) C.int {
+ root := C.GoString(_root)
+ entry := (*C.git_tree_entry)(_entry)
+
+ if callback, ok := pointerHandles.Get(ptr).(TreeWalkCallback); ok {
+ return C.int(callback(root, newTreeEntry(entry)))
+ } else {
+ panic("invalid treewalk callback")
+ }
+}
+
+func (t Tree) Walk(callback TreeWalkCallback) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ptr := pointerHandles.Track(callback)
+ defer pointerHandles.Untrack(ptr)
+
+ err := C._go_git_treewalk(
+ t.cast_ptr,
+ C.GIT_TREEWALK_PRE,
+ ptr,
+ )
+ runtime.KeepAlive(t)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
+
+type TreeBuilder struct {
+ ptr *C.git_treebuilder
+ repo *Repository
+}
+
+func (v *TreeBuilder) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_treebuilder_free(v.ptr)
+}
+
+func (v *TreeBuilder) Insert(filename string, id *Oid, filemode Filemode) error {
+ cfilename := C.CString(filename)
+ defer C.free(unsafe.Pointer(cfilename))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_treebuilder_insert(nil, v.ptr, cfilename, id.toC(), C.git_filemode_t(filemode))
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(id)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
+
+func (v *TreeBuilder) Remove(filename string) error {
+ cfilename := C.CString(filename)
+ defer C.free(unsafe.Pointer(cfilename))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_treebuilder_remove(v.ptr, cfilename)
+ runtime.KeepAlive(v)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
+
+func (v *TreeBuilder) Write() (*Oid, error) {
+ oid := new(Oid)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_treebuilder_write(oid.toC(), v.ptr)
+ runtime.KeepAlive(v)
+ if err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return oid, nil
+}
diff --git a/vendor/github.com/libgit2/git2go/walk.go b/vendor/github.com/libgit2/git2go/walk.go
new file mode 100644
index 000000000..287edb631
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/walk.go
@@ -0,0 +1,219 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+// RevWalk
+
+type SortType uint
+
+const (
+ SortNone SortType = C.GIT_SORT_NONE
+ SortTopological SortType = C.GIT_SORT_TOPOLOGICAL
+ SortTime SortType = C.GIT_SORT_TIME
+ SortReverse SortType = C.GIT_SORT_REVERSE
+)
+
+type RevWalk struct {
+ ptr *C.git_revwalk
+ repo *Repository
+}
+
+func revWalkFromC(repo *Repository, c *C.git_revwalk) *RevWalk {
+ v := &RevWalk{ptr: c, repo: repo}
+ runtime.SetFinalizer(v, (*RevWalk).Free)
+ return v
+}
+
+func (v *RevWalk) Reset() {
+ C.git_revwalk_reset(v.ptr)
+ runtime.KeepAlive(v)
+}
+
+func (v *RevWalk) Push(id *Oid) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revwalk_push(v.ptr, id.toC())
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(id)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) PushGlob(glob string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cstr := C.CString(glob)
+ defer C.free(unsafe.Pointer(cstr))
+
+ ecode := C.git_revwalk_push_glob(v.ptr, cstr)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) PushRange(r string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cstr := C.CString(r)
+ defer C.free(unsafe.Pointer(cstr))
+
+ ecode := C.git_revwalk_push_range(v.ptr, cstr)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) PushRef(r string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cstr := C.CString(r)
+ defer C.free(unsafe.Pointer(cstr))
+
+ ecode := C.git_revwalk_push_ref(v.ptr, cstr)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) PushHead() (err error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revwalk_push_head(v.ptr)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ err = MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) Hide(id *Oid) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revwalk_hide(v.ptr, id.toC())
+ runtime.KeepAlive(v)
+ runtime.KeepAlive(id)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) HideGlob(glob string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cstr := C.CString(glob)
+ defer C.free(unsafe.Pointer(cstr))
+
+ ecode := C.git_revwalk_hide_glob(v.ptr, cstr)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) HideRef(r string) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ cstr := C.CString(r)
+ defer C.free(unsafe.Pointer(cstr))
+
+ ecode := C.git_revwalk_hide_ref(v.ptr, cstr)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) HideHead() (err error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revwalk_hide_head(v.ptr)
+ runtime.KeepAlive(v)
+ if ecode < 0 {
+ err = MakeGitError(ecode)
+ }
+ return nil
+}
+
+func (v *RevWalk) Next(id *Oid) (err error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_revwalk_next(id.toC(), v.ptr)
+ runtime.KeepAlive(v)
+ switch {
+ case ret < 0:
+ err = MakeGitError(ret)
+ }
+
+ return
+}
+
+type RevWalkIterator func(commit *Commit) bool
+
+func (v *RevWalk) Iterate(fun RevWalkIterator) (err error) {
+ oid := new(Oid)
+ for {
+ err = v.Next(oid)
+ if IsErrorCode(err, ErrIterOver) {
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+
+ commit, err := v.repo.LookupCommit(oid)
+ if err != nil {
+ return err
+ }
+
+ cont := fun(commit)
+ if !cont {
+ break
+ }
+ }
+
+ return nil
+}
+
+func (v *RevWalk) SimplifyFirstParent() {
+ C.git_revwalk_simplify_first_parent(v.ptr)
+ runtime.KeepAlive(v)
+}
+
+func (v *RevWalk) Sorting(sm SortType) {
+ C.git_revwalk_sorting(v.ptr, C.uint(sm))
+ runtime.KeepAlive(v)
+}
+
+func (v *RevWalk) Free() {
+ runtime.SetFinalizer(v, nil)
+ C.git_revwalk_free(v.ptr)
+}
diff --git a/vendor/github.com/libgit2/git2go/wrapper.c b/vendor/github.com/libgit2/git2go/wrapper.c
new file mode 100644
index 000000000..11c2f3242
--- /dev/null
+++ b/vendor/github.com/libgit2/git2go/wrapper.c
@@ -0,0 +1,183 @@
+#include "_cgo_export.h"
+#include <git2.h>
+#include <git2/sys/odb_backend.h>
+#include <git2/sys/refdb_backend.h>
+
+typedef int (*gogit_submodule_cbk)(git_submodule *sm, const char *name, void *payload);
+
+void _go_git_populate_remote_cb(git_clone_options *opts)
+{
+ 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);
+}
+
+int _go_git_treewalk(git_tree *tree, git_treewalk_mode mode, void *ptr)
+{
+ return git_tree_walk(tree, mode, (git_treewalk_cb)&CallbackGitTreeWalk, ptr);
+}
+
+int _go_git_packbuilder_foreach(git_packbuilder *pb, void *payload)
+{
+ return git_packbuilder_foreach(pb, (git_packbuilder_foreach_cb)&packbuilderForEachCb, payload);
+}
+
+int _go_git_odb_foreach(git_odb *db, void *payload)
+{
+ return git_odb_foreach(db, (git_odb_foreach_cb)&odbForEachCb, payload);
+}
+
+void _go_git_odb_backend_free(git_odb_backend *backend)
+{
+ if (backend->free)
+ backend->free(backend);
+
+ return;
+}
+
+void _go_git_refdb_backend_free(git_refdb_backend *backend)
+{
+ if (backend->free)
+ backend->free(backend);
+
+ return;
+}
+
+int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload)
+{
+ git_diff_file_cb fcb = NULL;
+ git_diff_hunk_cb hcb = NULL;
+ git_diff_line_cb lcb = NULL;
+
+ if (eachFile) {
+ fcb = (git_diff_file_cb)&diffForEachFileCb;
+ }
+
+ if (eachHunk) {
+ hcb = (git_diff_hunk_cb)&diffForEachHunkCb;
+ }
+
+ if (eachLine) {
+ lcb = (git_diff_line_cb)&diffForEachLineCb;
+ }
+
+ return git_diff_foreach(diff, fcb, NULL, hcb, lcb, payload);
+}
+
+int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload)
+{
+ git_diff_file_cb fcb = NULL;
+ git_diff_hunk_cb hcb = NULL;
+ git_diff_line_cb lcb = NULL;
+
+ if (eachFile) {
+ fcb = (git_diff_file_cb)&diffForEachFileCb;
+ }
+
+ if (eachHunk) {
+ hcb = (git_diff_hunk_cb)&diffForEachHunkCb;
+ }
+
+ if (eachLine) {
+ lcb = (git_diff_line_cb)&diffForEachLineCb;
+ }
+
+ return git_diff_blobs(old, old_path, new, new_path, opts, fcb, NULL, hcb, lcb, payload);
+}
+
+void _go_git_setup_diff_notify_callbacks(git_diff_options *opts) {
+ opts->notify_cb = (git_diff_notify_cb)diffNotifyCb;
+}
+
+void _go_git_setup_callbacks(git_remote_callbacks *callbacks) {
+ typedef int (*completion_cb)(git_remote_completion_type type, void *data);
+ typedef int (*update_tips_cb)(const char *refname, const git_oid *a, const git_oid *b, void *data);
+ typedef int (*push_update_reference_cb)(const char *refname, const char *status, void *data);
+
+ callbacks->sideband_progress = (git_transport_message_cb)sidebandProgressCallback;
+ callbacks->completion = (completion_cb)completionCallback;
+ callbacks->credentials = (git_cred_acquire_cb)credentialsCallback;
+ callbacks->transfer_progress = (git_transfer_progress_cb)transferProgressCallback;
+ callbacks->update_tips = (update_tips_cb)updateTipsCallback;
+ callbacks->certificate_check = (git_transport_certificate_check_cb) certificateCheckCallback;
+ callbacks->pack_progress = (git_packbuilder_progress) packProgressCallback;
+ callbacks->push_transfer_progress = (git_push_transfer_progress) pushTransferProgressCallback;
+ callbacks->push_update_reference = (push_update_reference_cb) pushUpdateReferenceCallback;
+}
+
+int _go_git_index_add_all(git_index *index, const git_strarray *pathspec, unsigned int flags, void *callback) {
+ git_index_matched_path_cb cb = callback ? (git_index_matched_path_cb) &indexMatchedPathCallback : NULL;
+ return git_index_add_all(index, pathspec, flags, cb, callback);
+}
+
+int _go_git_index_update_all(git_index *index, const git_strarray *pathspec, void *callback) {
+ git_index_matched_path_cb cb = callback ? (git_index_matched_path_cb) &indexMatchedPathCallback : NULL;
+ return git_index_update_all(index, pathspec, cb, callback);
+}
+
+int _go_git_index_remove_all(git_index *index, const git_strarray *pathspec, void *callback) {
+ git_index_matched_path_cb cb = callback ? (git_index_matched_path_cb) &indexMatchedPathCallback : NULL;
+ return git_index_remove_all(index, pathspec, cb, callback);
+}
+
+int _go_git_tag_foreach(git_repository *repo, void *payload)
+{
+ return git_tag_foreach(repo, (git_tag_foreach_cb)&gitTagForeachCb, payload);
+}
+
+int _go_git_merge_file(git_merge_file_result* out, char* ancestorContents, size_t ancestorLen, char* ancestorPath, unsigned int ancestorMode, char* oursContents, size_t oursLen, char* oursPath, unsigned int oursMode, char* theirsContents, size_t theirsLen, char* theirsPath, unsigned int theirsMode, git_merge_file_options* copts) {
+ git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT;
+ git_merge_file_input ours = GIT_MERGE_FILE_INPUT_INIT;
+ git_merge_file_input theirs = GIT_MERGE_FILE_INPUT_INIT;
+
+ ancestor.ptr = ancestorContents;
+ ancestor.size = ancestorLen;
+ ancestor.path = ancestorPath;
+ ancestor.mode = ancestorMode;
+
+ ours.ptr = oursContents;
+ ours.size = oursLen;
+ ours.path = oursPath;
+ ours.mode = oursMode;
+
+ theirs.ptr = theirsContents;
+ theirs.size = theirsLen;
+ theirs.path = theirsPath;
+ theirs.mode = theirsMode;
+
+ return git_merge_file(out, &ancestor, &ours, &theirs, copts);
+}
+
+void _go_git_setup_stash_apply_progress_callbacks(git_stash_apply_options *opts) {
+ opts->progress_cb = (git_stash_apply_progress_cb)stashApplyProgressCb;
+}
+
+int _go_git_stash_foreach(git_repository *repo, void *payload) {
+ return git_stash_foreach(repo, (git_stash_cb)&stashForeachCb, payload);
+}
+
+int _go_git_writestream_write(git_writestream *stream, const char *buffer, size_t len)
+{
+ return stream->write(stream, buffer, len);
+}
+
+int _go_git_writestream_close(git_writestream *stream)
+{
+ return stream->close(stream);
+}
+
+void _go_git_writestream_free(git_writestream *stream)
+{
+ stream->free(stream);
+}
+
+/* EOF */
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 2aec4dc99..5f4027f65 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -271,6 +271,14 @@
"versionExact": "v1.0.1"
},
{
+ "checksumSHA1": "kQcyh4PCOZIhOH/KFfYYW+M7eCU=",
+ "path": "github.com/libgit2/git2go",
+ "revision": "ecaeb7a21d479b7966311760a2e8bd734f8f0eef",
+ "revisionTime": "2019-01-04T13:40:18Z",
+ "version": "v27",
+ "versionExact": "v27"
+ },
+ {
"checksumSHA1": "++h3LjgqASQ5dGLM2WOZmwYp+mU=",
"path": "github.com/lightstep/lightstep-tracer-go",
"revision": "c9cafc033badd91d4e27900874429fc30a5ffdc2",