Compare commits
11 Commits
main
...
cherry-pic
Author | SHA1 | Date |
---|---|---|
lhchavez | 7c1ecf79b4 | |
github-actions[bot] | a53cd8b512 | |
github-actions[bot] | a7dc7d41b9 | |
Dylan Richardson | 8230ed934e | |
github-actions[bot] | 9dfdab765a | |
github-actions[bot] | a3f32b93cd | |
lhchavez | a964575453 | |
lhchavez | a6446ac047 | |
github-actions[bot] | 3033505879 | |
github-actions[bot] | bacde67336 | |
lhchavez | 37d4d3ddf8 |
|
@ -63,6 +63,7 @@ jobs:
|
|||
matrix:
|
||||
libgit2:
|
||||
- '109b4c887ffb63962c7017a66fc4a1f48becb48e' # v1.2.0 with a fixed symbol
|
||||
- 'v1.3.0'
|
||||
name: Go (system-wide, dynamic)
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
@ -105,3 +106,26 @@ jobs:
|
|||
sudo ./script/build-libgit2.sh --static --system
|
||||
- name: Test
|
||||
run: go test --count=1 --tags "static,system_libgit2" ./...
|
||||
|
||||
check-generate:
|
||||
name: Check generated files were not modified
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '1.17'
|
||||
id: go
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
- name: Install libgit2 build dependencies
|
||||
run: |
|
||||
git submodule update --init
|
||||
sudo apt-get install -y --no-install-recommends libssh2-1-dev
|
||||
go install golang.org/x/tools/cmd/stringer@latest
|
||||
- name: Generate files
|
||||
run: |
|
||||
export PATH=$(go env GOPATH)/bin:$PATH
|
||||
make generate
|
||||
- name: Check nothing changed
|
||||
run: git diff --quiet --exit-code || (echo "detected changes after generate" ; git status ; exit 1)
|
||||
|
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
- name: Bump version and push tag
|
||||
id: bump-version
|
||||
uses: anothrNick/github-tag-action@9aaabdb5e989894e95288328d8b17a6347217ae3
|
||||
uses: anothrNick/github-tag-action@43ed073f5c1445ca8b80d920ce2f8fa550ae4e8d
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
WITH_V: true
|
||||
|
|
|
@ -10,8 +10,8 @@ package git
|
|||
#cgo CFLAGS: -DLIBGIT2_STATIC
|
||||
#include <git2.h>
|
||||
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 3
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.3.0"
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -8,8 +8,8 @@ package git
|
|||
#cgo CFLAGS: -DLIBGIT2_DYNAMIC
|
||||
#include <git2.h>
|
||||
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 3
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.3.0"
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -8,8 +8,8 @@ package git
|
|||
#cgo CFLAGS: -DLIBGIT2_STATIC
|
||||
#include <git2.h>
|
||||
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 3
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.3.0"
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
|
|
4
Makefile
4
Makefile
|
@ -2,6 +2,10 @@ TEST_ARGS ?= --count=1
|
|||
|
||||
default: test
|
||||
|
||||
|
||||
generate: static-build/install/lib/libgit2.a
|
||||
go generate --tags "static" ./...
|
||||
|
||||
# System library
|
||||
# ==============
|
||||
# This uses whatever version of libgit2 can be found in the system.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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=main)](https://travis-ci.org/libgit2/git2go)
|
||||
[![GoDoc](https://godoc.org/github.com/libgit2/git2go?status.svg)](http://godoc.org/github.com/libgit2/git2go/v32) [![Build Status](https://travis-ci.org/libgit2/git2go.svg?branch=main)](https://travis-ci.org/libgit2/git2go)
|
||||
|
||||
Go bindings for [libgit2](http://libgit2.github.com/).
|
||||
|
||||
|
@ -78,7 +78,7 @@ In order to let Go pass the correct flags to `pkg-config`, `-tags static` needs
|
|||
|
||||
One thing to take into account is that since Go expects the `pkg-config` file to be within the same directory where `make install-static` was called, so the `go.mod` file may need to have a [`replace` directive](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) so that the correct setup is achieved. So if `git2go` is checked out at `$GOPATH/src/github.com/libgit2/git2go` and your project at `$GOPATH/src/github.com/my/project`, the `go.mod` file of `github.com/my/project` might need to have a line like
|
||||
|
||||
replace github.com/libgit2/git2go/v32 ../../libgit2/git2go
|
||||
replace github.com/libgit2/git2go/v32 => ../../libgit2/git2go
|
||||
|
||||
Parallelism and network operations
|
||||
----------------------------------
|
||||
|
|
|
@ -2,6 +2,7 @@ package git
|
|||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -70,3 +71,17 @@ func TestCloneWithCallback(t *testing.T) {
|
|||
}
|
||||
defer remote.Free()
|
||||
}
|
||||
|
||||
// TestCloneWithExternalHTTPUrl
|
||||
func TestCloneWithExternalHTTPUrl(t *testing.T) {
|
||||
|
||||
path, err := ioutil.TempDir("", "git2go")
|
||||
defer os.RemoveAll(path)
|
||||
|
||||
// clone the repo
|
||||
url := "https://github.com/libgit2/TestGitRepository"
|
||||
_, err = Clone(url, path, &CloneOptions{})
|
||||
if err != nil {
|
||||
t.Fatal("cannot clone remote repo via https, error: ", err)
|
||||
}
|
||||
}
|
||||
|
|
2
git.go
2
git.go
|
@ -14,6 +14,7 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
//go:generate stringer -type ErrorClass -trimprefix ErrorClass -tags static
|
||||
type ErrorClass int
|
||||
|
||||
const (
|
||||
|
@ -48,6 +49,7 @@ const (
|
|||
ErrorClassPatch ErrorClass = C.GIT_ERROR_PATCH
|
||||
)
|
||||
|
||||
//go:generate stringer -type ErrorCode -trimprefix ErrorCode -tags static
|
||||
type ErrorCode int
|
||||
|
||||
const (
|
||||
|
|
29
rebase.go
29
rebase.go
|
@ -318,7 +318,7 @@ func (r *Repository) InitRebase(branch *AnnotatedCommit, upstream *AnnotatedComm
|
|||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return newRebaseFromC(ptr, cOpts), nil
|
||||
return newRebaseFromC(ptr, r, cOpts), nil
|
||||
}
|
||||
|
||||
// OpenRebase opens an existing rebase that was previously started by either an invocation of InitRebase or by another client.
|
||||
|
@ -340,7 +340,7 @@ func (r *Repository) OpenRebase(opts *RebaseOptions) (*Rebase, error) {
|
|||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return newRebaseFromC(ptr, cOpts), nil
|
||||
return newRebaseFromC(ptr, r, cOpts), nil
|
||||
}
|
||||
|
||||
// OperationAt gets the rebase operation specified by the given index.
|
||||
|
@ -392,6 +392,27 @@ func (rebase *Rebase) Next() (*RebaseOperation, error) {
|
|||
return newRebaseOperationFromC(ptr), nil
|
||||
}
|
||||
|
||||
// InmemoryIndex gets the index produced by the last operation, which is the
|
||||
// result of `Next()` and which will be committed by the next invocation of
|
||||
// `Commit()`. This is useful for resolving conflicts in an in-memory rebase
|
||||
// before committing them.
|
||||
//
|
||||
// This is only applicable for in-memory rebases; for rebases within a working
|
||||
// directory, the changes were applied to the repository's index.
|
||||
func (rebase *Rebase) InmemoryIndex() (*Index, error) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var ptr *C.git_index
|
||||
err := C.git_rebase_inmemory_index(&ptr, rebase.ptr)
|
||||
runtime.KeepAlive(rebase)
|
||||
if err < 0 {
|
||||
return nil, MakeGitError(err)
|
||||
}
|
||||
|
||||
return newIndexFromC(ptr, rebase.r), 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 {
|
||||
|
@ -457,8 +478,8 @@ func (r *Rebase) Free() {
|
|||
freeRebaseOptions(r.options)
|
||||
}
|
||||
|
||||
func newRebaseFromC(ptr *C.git_rebase, opts *C.git_rebase_options) *Rebase {
|
||||
rebase := &Rebase{ptr: ptr, options: opts}
|
||||
func newRebaseFromC(ptr *C.git_rebase, repo *Repository, opts *C.git_rebase_options) *Rebase {
|
||||
rebase := &Rebase{ptr: ptr, r: repo, options: opts}
|
||||
runtime.SetFinalizer(rebase, (*Rebase).Free)
|
||||
return rebase
|
||||
}
|
||||
|
|
|
@ -14,6 +14,80 @@ import (
|
|||
|
||||
// Tests
|
||||
|
||||
func TestRebaseInMemoryWithConflict(t *testing.T) {
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
// Create two branches with common history, where both modify "common-file"
|
||||
// in a conflicting way.
|
||||
_, err := commitSomething(repo, "common-file", "a\nb\nc\n", commitOptions{})
|
||||
checkFatal(t, err)
|
||||
checkFatal(t, createBranch(repo, "branch-a"))
|
||||
checkFatal(t, createBranch(repo, "branch-b"))
|
||||
|
||||
checkFatal(t, repo.SetHead("refs/heads/branch-a"))
|
||||
_, err = commitSomething(repo, "common-file", "1\nb\nc\n", commitOptions{})
|
||||
checkFatal(t, err)
|
||||
|
||||
checkFatal(t, repo.SetHead("refs/heads/branch-b"))
|
||||
_, err = commitSomething(repo, "common-file", "x\nb\nc\n", commitOptions{})
|
||||
checkFatal(t, err)
|
||||
|
||||
branchA, err := repo.LookupBranch("branch-a", BranchLocal)
|
||||
checkFatal(t, err)
|
||||
onto, err := repo.AnnotatedCommitFromRef(branchA.Reference)
|
||||
checkFatal(t, err)
|
||||
|
||||
// We then rebase "branch-b" onto "branch-a" in-memory, which should result
|
||||
// in a conflict.
|
||||
rebase, err := repo.InitRebase(nil, nil, onto, &RebaseOptions{InMemory: 1})
|
||||
checkFatal(t, err)
|
||||
|
||||
_, err = rebase.Next()
|
||||
checkFatal(t, err)
|
||||
|
||||
index, err := rebase.InmemoryIndex()
|
||||
checkFatal(t, err)
|
||||
|
||||
// We simply resolve the conflict and commit the rebase.
|
||||
if !index.HasConflicts() {
|
||||
t.Fatal("expected index to have conflicts")
|
||||
}
|
||||
|
||||
conflict, err := index.Conflict("common-file")
|
||||
checkFatal(t, err)
|
||||
|
||||
resolvedBlobID, err := repo.CreateBlobFromBuffer([]byte("resolved contents"))
|
||||
checkFatal(t, err)
|
||||
|
||||
resolvedEntry := *conflict.Our
|
||||
resolvedEntry.Id = resolvedBlobID
|
||||
checkFatal(t, index.Add(&resolvedEntry))
|
||||
checkFatal(t, index.RemoveConflict("common-file"))
|
||||
|
||||
var commitID Oid
|
||||
checkFatal(t, rebase.Commit(&commitID, signature(), signature(), "rebased message"))
|
||||
checkFatal(t, rebase.Finish())
|
||||
|
||||
// And then assert that we can look up the new merge commit, and that the
|
||||
// "common-file" has the expected contents.
|
||||
commit, err := repo.LookupCommit(&commitID)
|
||||
checkFatal(t, err)
|
||||
if commit.Message() != "rebased message" {
|
||||
t.Fatalf("unexpected commit message %q", commit.Message())
|
||||
}
|
||||
|
||||
tree, err := commit.Tree()
|
||||
checkFatal(t, err)
|
||||
|
||||
blob, err := repo.LookupBlob(tree.EntryByName("common-file").Id)
|
||||
checkFatal(t, err)
|
||||
if string(blob.Contents()) != "resolved contents" {
|
||||
t.Fatalf("unexpected resolved blob contents %q", string(blob.Contents()))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRebaseAbort(t *testing.T) {
|
||||
// TEST DATA
|
||||
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
package git
|
||||
|
||||
/*
|
||||
#include <git2.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Refspec struct {
|
||||
doNotCompare
|
||||
ptr *C.git_refspec
|
||||
}
|
||||
|
||||
// ParseRefspec parses a given refspec string
|
||||
func ParseRefspec(input string, isFetch bool) (*Refspec, error) {
|
||||
var ptr *C.git_refspec
|
||||
|
||||
cinput := C.CString(input)
|
||||
defer C.free(unsafe.Pointer(cinput))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_refspec_parse(&ptr, cinput, cbool(isFetch))
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
spec := &Refspec{ptr: ptr}
|
||||
runtime.SetFinalizer(spec, (*Refspec).Free)
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
// Free releases a refspec object which has been created by ParseRefspec
|
||||
func (s *Refspec) Free() {
|
||||
runtime.SetFinalizer(s, nil)
|
||||
C.git_refspec_free(s.ptr)
|
||||
}
|
||||
|
||||
// Direction returns the refspec's direction
|
||||
func (s *Refspec) Direction() ConnectDirection {
|
||||
direction := C.git_refspec_direction(s.ptr)
|
||||
return ConnectDirection(direction)
|
||||
}
|
||||
|
||||
// Src returns the refspec's source specifier
|
||||
func (s *Refspec) Src() string {
|
||||
var ret string
|
||||
cstr := C.git_refspec_src(s.ptr)
|
||||
|
||||
if cstr != nil {
|
||||
ret = C.GoString(cstr)
|
||||
}
|
||||
|
||||
runtime.KeepAlive(s)
|
||||
return ret
|
||||
}
|
||||
|
||||
// Dst returns the refspec's destination specifier
|
||||
func (s *Refspec) Dst() string {
|
||||
var ret string
|
||||
cstr := C.git_refspec_dst(s.ptr)
|
||||
|
||||
if cstr != nil {
|
||||
ret = C.GoString(cstr)
|
||||
}
|
||||
|
||||
runtime.KeepAlive(s)
|
||||
return ret
|
||||
}
|
||||
|
||||
// Force returns the refspec's force-update setting
|
||||
func (s *Refspec) Force() bool {
|
||||
force := C.git_refspec_force(s.ptr)
|
||||
return force != 0
|
||||
}
|
||||
|
||||
// String returns the refspec's string representation
|
||||
func (s *Refspec) String() string {
|
||||
var ret string
|
||||
cstr := C.git_refspec_string(s.ptr)
|
||||
|
||||
if cstr != nil {
|
||||
ret = C.GoString(cstr)
|
||||
}
|
||||
|
||||
runtime.KeepAlive(s)
|
||||
return ret
|
||||
}
|
||||
|
||||
// SrcMatches checks if a refspec's source descriptor matches a reference
|
||||
func (s *Refspec) SrcMatches(refname string) bool {
|
||||
cname := C.CString(refname)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
matches := C.git_refspec_src_matches(s.ptr, cname)
|
||||
return matches != 0
|
||||
}
|
||||
|
||||
// SrcMatches checks if a refspec's destination descriptor matches a reference
|
||||
func (s *Refspec) DstMatches(refname string) bool {
|
||||
cname := C.CString(refname)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
matches := C.git_refspec_dst_matches(s.ptr, cname)
|
||||
return matches != 0
|
||||
}
|
||||
|
||||
// Transform a reference to its target following the refspec's rules
|
||||
func (s *Refspec) Transform(refname string) (string, error) {
|
||||
buf := C.git_buf{}
|
||||
|
||||
cname := C.CString(refname)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_refspec_transform(&buf, s.ptr, cname)
|
||||
if ret < 0 {
|
||||
return "", MakeGitError(ret)
|
||||
}
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
return C.GoString(buf.ptr), nil
|
||||
}
|
||||
|
||||
// Rtransform converts a target reference to its source reference following the
|
||||
// refspec's rules
|
||||
func (s *Refspec) Rtransform(refname string) (string, error) {
|
||||
buf := C.git_buf{}
|
||||
|
||||
cname := C.CString(refname)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_refspec_rtransform(&buf, s.ptr, cname)
|
||||
if ret < 0 {
|
||||
return "", MakeGitError(ret)
|
||||
}
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
return C.GoString(buf.ptr), nil
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRefspec(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
input = "+refs/heads/*:refs/remotes/origin/*"
|
||||
mainLocal = "refs/heads/main"
|
||||
mainRemote = "refs/remotes/origin/main"
|
||||
)
|
||||
|
||||
refspec, err := ParseRefspec(input, true)
|
||||
checkFatal(t, err)
|
||||
|
||||
// Accessors
|
||||
|
||||
s := refspec.String()
|
||||
if s != input {
|
||||
t.Errorf("expected string %q, got %q", input, s)
|
||||
}
|
||||
|
||||
if d := refspec.Direction(); d != ConnectDirectionFetch {
|
||||
t.Errorf("expected fetch refspec, got direction %v", d)
|
||||
}
|
||||
|
||||
if pat, expected := refspec.Src(), "refs/heads/*"; pat != expected {
|
||||
t.Errorf("expected refspec src %q, got %q", expected, pat)
|
||||
}
|
||||
|
||||
if pat, expected := refspec.Dst(), "refs/remotes/origin/*"; pat != expected {
|
||||
t.Errorf("expected refspec dst %q, got %q", expected, pat)
|
||||
}
|
||||
|
||||
if !refspec.Force() {
|
||||
t.Error("expected refspec force flag")
|
||||
}
|
||||
|
||||
// SrcMatches
|
||||
|
||||
if !refspec.SrcMatches(mainLocal) {
|
||||
t.Errorf("refspec source did not match %q", mainLocal)
|
||||
}
|
||||
|
||||
if refspec.SrcMatches("refs/tags/v1.0") {
|
||||
t.Error("refspec source matched under refs/tags")
|
||||
}
|
||||
|
||||
// DstMatches
|
||||
|
||||
if !refspec.DstMatches(mainRemote) {
|
||||
t.Errorf("refspec destination did not match %q", mainRemote)
|
||||
}
|
||||
|
||||
if refspec.DstMatches("refs/tags/v1.0") {
|
||||
t.Error("refspec destination matched under refs/tags")
|
||||
}
|
||||
|
||||
// Transforms
|
||||
|
||||
fromLocal, err := refspec.Transform(mainLocal)
|
||||
checkFatal(t, err)
|
||||
if fromLocal != mainRemote {
|
||||
t.Errorf("transform by refspec returned %s; expected %s", fromLocal, mainRemote)
|
||||
}
|
||||
|
||||
fromRemote, err := refspec.Rtransform(mainRemote)
|
||||
checkFatal(t, err)
|
||||
if fromRemote != mainLocal {
|
||||
t.Errorf("rtransform by refspec returned %s; expected %s", fromRemote, mainLocal)
|
||||
}
|
||||
}
|
20
remote.go
20
remote.go
|
@ -182,6 +182,9 @@ type Remote struct {
|
|||
ptr *C.git_remote
|
||||
callbacks RemoteCallbacks
|
||||
repo *Repository
|
||||
// weak indicates that a remote is a weak pointer and should not be
|
||||
// freed.
|
||||
weak bool
|
||||
}
|
||||
|
||||
type remotePointerList struct {
|
||||
|
@ -288,6 +291,9 @@ type PushOptions struct {
|
|||
|
||||
// Headers are extra headers for the push operation.
|
||||
Headers []string
|
||||
|
||||
// Proxy options to use for this push operation
|
||||
ProxyOptions ProxyOptions
|
||||
}
|
||||
|
||||
type RemoteHead struct {
|
||||
|
@ -602,6 +608,9 @@ func (r *Remote) free() {
|
|||
// Free releases the resources of the Remote.
|
||||
func (r *Remote) Free() {
|
||||
r.repo.Remotes.untrackRemote(r)
|
||||
if r.weak {
|
||||
return
|
||||
}
|
||||
r.free()
|
||||
}
|
||||
|
||||
|
@ -995,6 +1004,7 @@ func populatePushOptions(copts *C.git_push_options, opts *PushOptions, errorTarg
|
|||
strings: makeCStringsFromStrings(opts.Headers),
|
||||
}
|
||||
populateRemoteCallbacks(&copts.callbacks, &opts.RemoteCallbacks, errorTarget)
|
||||
populateProxyOptions(&copts.proxy_opts, &opts.ProxyOptions)
|
||||
return copts
|
||||
}
|
||||
|
||||
|
@ -1004,6 +1014,7 @@ func freePushOptions(copts *C.git_push_options) {
|
|||
}
|
||||
untrackCallbacksPayload(&copts.callbacks)
|
||||
freeStrarray(&copts.custom_headers)
|
||||
freeProxyOptions(&copts.proxy_opts)
|
||||
}
|
||||
|
||||
// Fetch performs a fetch operation. refspecs specifies which refspecs
|
||||
|
@ -1231,3 +1242,12 @@ func freeRemoteCreateOptions(ptr *C.git_remote_create_options) {
|
|||
C.free(unsafe.Pointer(ptr.name))
|
||||
C.free(unsafe.Pointer(ptr.fetchspec))
|
||||
}
|
||||
|
||||
// createNewEmptyRemote used to get a new empty object of *Remote
|
||||
func createNewEmptyRemote() *Remote {
|
||||
return &Remote{
|
||||
callbacks: RemoteCallbacks{},
|
||||
repo: nil,
|
||||
weak: false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,6 +101,14 @@ func EnableStrictHashVerification(enabled bool) error {
|
|||
}
|
||||
}
|
||||
|
||||
func EnableFsyncGitDir(enabled bool) error {
|
||||
if enabled {
|
||||
return setSizet(C.GIT_OPT_ENABLE_FSYNC_GITDIR, 1)
|
||||
} else {
|
||||
return setSizet(C.GIT_OPT_ENABLE_FSYNC_GITDIR, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func CachedMemory() (current int, allowed int, err error) {
|
||||
return getSizetSizet(C.GIT_OPT_GET_CACHED_MEMORY)
|
||||
}
|
||||
|
|
|
@ -65,6 +65,14 @@ func TestEnableStrictHashVerification(t *testing.T) {
|
|||
checkFatal(t, err)
|
||||
}
|
||||
|
||||
func TestEnableFsyncGitDir(t *testing.T) {
|
||||
err := EnableFsyncGitDir(false)
|
||||
checkFatal(t, err)
|
||||
|
||||
err = EnableFsyncGitDir(true)
|
||||
checkFatal(t, err)
|
||||
}
|
||||
|
||||
func TestCachedMemory(t *testing.T) {
|
||||
current, allowed, err := CachedMemory()
|
||||
checkFatal(t, err)
|
||||
|
|
12
ssh.go
12
ssh.go
|
@ -17,6 +17,7 @@ import (
|
|||
"net"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
@ -74,6 +75,13 @@ func (t *sshSmartSubtransport) Action(urlString string, action SmartServiceActio
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Escape \ and '.
|
||||
uPath := strings.Replace(u.Path, `\`, `\\`, -1)
|
||||
uPath = strings.Replace(uPath, `'`, `\'`, -1)
|
||||
|
||||
// TODO: Add percentage decode similar to libgit2.
|
||||
// Refer: https://github.com/libgit2/libgit2/blob/358a60e1b46000ea99ef10b4dd709e92f75ff74b/src/str.c#L455-L481
|
||||
|
||||
var cmd string
|
||||
switch action {
|
||||
case SmartServiceActionUploadpackLs, SmartServiceActionUploadpack:
|
||||
|
@ -83,7 +91,7 @@ func (t *sshSmartSubtransport) Action(urlString string, action SmartServiceActio
|
|||
}
|
||||
t.Close()
|
||||
}
|
||||
cmd = fmt.Sprintf("git-upload-pack %q", u.Path)
|
||||
cmd = fmt.Sprintf("git-upload-pack '%s'", uPath)
|
||||
|
||||
case SmartServiceActionReceivepackLs, SmartServiceActionReceivepack:
|
||||
if t.currentStream != nil {
|
||||
|
@ -92,7 +100,7 @@ func (t *sshSmartSubtransport) Action(urlString string, action SmartServiceActio
|
|||
}
|
||||
t.Close()
|
||||
}
|
||||
cmd = fmt.Sprintf("git-receive-pack %q", u.Path)
|
||||
cmd = fmt.Sprintf("git-receive-pack '%s'", uPath)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected action: %v", action)
|
||||
|
|
|
@ -22,7 +22,6 @@ void _go_git_setup_smart_subtransport_stream(_go_managed_smart_subtransport_stre
|
|||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
@ -306,8 +305,10 @@ func smartTransportCallback(
|
|||
registeredSmartTransport := pointerHandles.Get(handle).(*RegisteredSmartTransport)
|
||||
remote, ok := remotePointers.get(owner)
|
||||
if !ok {
|
||||
err := errors.New("remote pointer not found")
|
||||
return setCallbackError(errorMessage, err)
|
||||
// create a new empty remote and set it
|
||||
// as a weak pointer, so that control stays in golang
|
||||
remote = createNewEmptyRemote()
|
||||
remote.weak = true
|
||||
}
|
||||
|
||||
managed := &managedSmartSubtransport{
|
||||
|
|
Loading…
Reference in New Issue