Skip to content

Commit f037074

Browse files
committed
Merge remote-tracking branch 'origin/next'
2 parents b8a9efd + 5d0a4c7 commit f037074

19 files changed

+781
-66
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "vendor/libgit2"]
2+
path = vendor/libgit2
3+
url = https://github.com/libgit2/libgit2

.travis.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ sudo: required
55
install: ./script/install-libgit2.sh
66

77
go:
8-
- 1.1
9-
- 1.2
10-
- 1.3
11-
- 1.4
128
- 1.5
139
- 1.6
1410
- 1.7

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
default: test
22

3-
test:
3+
build-libgit2:
4+
./script/build-libgit2-static.sh
5+
6+
test: build-libgit2
47
go run script/check-MakeGitError-thread-lock.go
58
go test ./...
69

7-
install:
10+
install: build-libgit2
811
go install ./...

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ to use a version of git2go which will work against libgit2 v0.22 and dynamically
2222

2323
import "github.com/libgit2/git2go"
2424

25-
to use the version which works against the latest release.
25+
to use the 'master' branch, which works against the latest release of libgit2, whichever that one is at the time.
2626

2727
### From `next`
2828

@@ -44,15 +44,14 @@ libgit2 uses OpenSSL and LibSSH2 for performing encrypted network connections. F
4444
Running the tests
4545
-----------------
4646

47-
For the stable version, `go test` will work as usual. For the `next` branch, similarly to installing, running the tests requires linking against the local libgit2 library, so the Makefile provides a wrapper
47+
For the stable version, `go test` will work as usual. For the `next` 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
4848

4949
make test
5050

51-
Alternatively, if you want to pass arguments to `go test`, you can use the script that sets it all up
51+
Alternatively, you can build the library manually first and then run the tests
5252

53-
./script/with-static.sh go test -v
54-
55-
which will run the specified arguments with the correct environment variables.
53+
./script/build-libgit2-static.sh
54+
go test -v
5655

5756
License
5857
-------

blob.go

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ package git
44
#include <git2.h>
55
#include <string.h>
66
7-
extern int _go_git_blob_create_fromchunks(git_oid *id,
8-
git_repository *repo,
9-
const char *hintpath,
10-
void *payload);
11-
7+
int _go_git_writestream_write(git_writestream *stream, const char *buffer, size_t len);
8+
void _go_git_writestream_free(git_writestream *stream);
129
*/
1310
import "C"
1411
import (
1512
"io"
13+
"reflect"
1614
"runtime"
1715
"unsafe"
1816
)
@@ -87,27 +85,71 @@ func blobChunkCb(buffer *C.char, maxLen C.size_t, handle unsafe.Pointer) int {
8785
return len(goBuf)
8886
}
8987

90-
func (repo *Repository) CreateBlobFromChunks(hintPath string, callback BlobChunkCallback) (*Oid, error) {
91-
runtime.LockOSThread()
92-
defer runtime.UnlockOSThread()
93-
88+
func (repo *Repository) CreateFromStream(hintPath string) (*BlobWriteStream, error) {
9489
var chintPath *C.char = nil
90+
var stream *C.git_writestream
91+
9592
if len(hintPath) > 0 {
9693
chintPath = C.CString(hintPath)
9794
defer C.free(unsafe.Pointer(chintPath))
9895
}
99-
oid := C.git_oid{}
10096

101-
payload := &BlobCallbackData{Callback: callback}
102-
handle := pointerHandles.Track(payload)
103-
defer pointerHandles.Untrack(handle)
97+
runtime.LockOSThread()
98+
defer runtime.UnlockOSThread()
99+
100+
ecode := C.git_blob_create_fromstream(&stream, repo.ptr, chintPath)
101+
if ecode < 0 {
102+
return nil, MakeGitError(ecode)
103+
}
104+
105+
return newBlobWriteStreamFromC(stream), nil
106+
}
107+
108+
type BlobWriteStream struct {
109+
ptr *C.git_writestream
110+
}
111+
112+
func newBlobWriteStreamFromC(ptr *C.git_writestream) *BlobWriteStream {
113+
stream := &BlobWriteStream{
114+
ptr: ptr,
115+
}
116+
117+
runtime.SetFinalizer(stream, (*BlobWriteStream).Free)
118+
return stream
119+
}
120+
121+
// Implement io.Writer
122+
func (stream *BlobWriteStream) Write(p []byte) (int, error) {
123+
header := (*reflect.SliceHeader)(unsafe.Pointer(&p))
124+
ptr := (*C.char)(unsafe.Pointer(header.Data))
125+
size := C.size_t(header.Len)
104126

105-
ecode := C._go_git_blob_create_fromchunks(&oid, repo.ptr, chintPath, handle)
106-
if payload.Error != nil {
107-
return nil, payload.Error
127+
runtime.LockOSThread()
128+
defer runtime.UnlockOSThread()
129+
130+
ecode := C._go_git_writestream_write(stream.ptr, ptr, size)
131+
if ecode < 0 {
132+
return 0, MakeGitError(ecode)
108133
}
134+
135+
return len(p), nil
136+
}
137+
138+
func (stream *BlobWriteStream) Free() {
139+
runtime.SetFinalizer(stream, nil)
140+
C._go_git_writestream_free(stream.ptr)
141+
}
142+
143+
func (stream *BlobWriteStream) Commit() (*Oid, error) {
144+
oid := C.git_oid{}
145+
146+
runtime.LockOSThread()
147+
defer runtime.UnlockOSThread()
148+
149+
ecode := C.git_blob_create_fromstream_commit(&oid, stream.ptr)
109150
if ecode < 0 {
110151
return nil, MakeGitError(ecode)
111152
}
153+
112154
return newOidFromC(&oid), nil
113155
}

commit.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ func (c Commit) Message() string {
2222
return C.GoString(C.git_commit_message(c.cast_ptr))
2323
}
2424

25+
func (c Commit) RawMessage() string {
26+
return C.GoString(C.git_commit_message_raw(c.cast_ptr))
27+
}
28+
2529
func (c Commit) Summary() string {
2630
return C.GoString(C.git_commit_summary(c.cast_ptr))
2731
}

diff.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const (
2020
DiffFlagBinary DiffFlag = C.GIT_DIFF_FLAG_BINARY
2121
DiffFlagNotBinary DiffFlag = C.GIT_DIFF_FLAG_NOT_BINARY
2222
DiffFlagValidOid DiffFlag = C.GIT_DIFF_FLAG_VALID_ID
23+
DiffFlagExists DiffFlag = C.GIT_DIFF_FLAG_EXISTS
2324
)
2425

2526
type Delta int
@@ -34,6 +35,8 @@ const (
3435
DeltaIgnored Delta = C.GIT_DELTA_IGNORED
3536
DeltaUntracked Delta = C.GIT_DELTA_UNTRACKED
3637
DeltaTypeChange Delta = C.GIT_DELTA_TYPECHANGE
38+
DeltaUnreadable Delta = C.GIT_DELTA_UNREADABLE
39+
DeltaConflicted Delta = C.GIT_DELTA_CONFLICTED
3740
)
3841

3942
type DiffLineType int
@@ -399,6 +402,7 @@ const (
399402
DiffIgnoreFilemode DiffOptionsFlag = C.GIT_DIFF_IGNORE_FILEMODE
400403
DiffIgnoreSubmodules DiffOptionsFlag = C.GIT_DIFF_IGNORE_SUBMODULES
401404
DiffIgnoreCase DiffOptionsFlag = C.GIT_DIFF_IGNORE_CASE
405+
DiffIncludeCaseChange DiffOptionsFlag = C.GIT_DIFF_INCLUDE_CASECHANGE
402406

403407
DiffDisablePathspecMatch DiffOptionsFlag = C.GIT_DIFF_DISABLE_PATHSPEC_MATCH
404408
DiffSkipBinaryCheck DiffOptionsFlag = C.GIT_DIFF_SKIP_BINARY_CHECK

features.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package git
2+
3+
/*
4+
#include <git2.h>
5+
*/
6+
import "C"
7+
8+
type Feature int
9+
10+
const (
11+
// libgit2 was built with threading support
12+
FeatureThreads Feature = C.GIT_FEATURE_THREADS
13+
14+
// libgit2 was built with HTTPS support built-in
15+
FeatureHttps Feature = C.GIT_FEATURE_HTTPS
16+
17+
// libgit2 was build with SSH support built-in
18+
FeatureSsh Feature = C.GIT_FEATURE_SSH
19+
20+
// libgit2 was built with nanosecond support for files
21+
FeatureNSec Feature = C.GIT_FEATURE_NSEC
22+
)
23+
24+
// Features returns a bit-flag of Feature values indicating which features the
25+
// loaded libgit2 library has.
26+
func Features() Feature {
27+
features := C.git_libgit2_features()
28+
29+
return Feature(features)
30+
}

git.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package git
22

33
/*
4+
#cgo CFLAGS: -I${SRCDIR}/vendor/libgit2/include
5+
#cgo LDFLAGS: -L${SRCDIR}/vendor/libgit2/build/ -lgit2
6+
#cgo windows LDFLAGS: -lwinhttp
7+
#cgo !windows pkg-config: --static ${SRCDIR}/vendor/libgit2/build/libgit2.pc
48
#include <git2.h>
59
#include <git2/sys/openssl.h>
6-
#cgo pkg-config: libgit2
710
8-
#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 24
9-
# error "Invalid libgit2 version; this git2go supports libgit2 v0.24"
11+
#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 25
12+
# error "Invalid libgit2 version; this git2go supports libgit2 v0.25"
1013
#endif
1114
1215
*/
@@ -125,6 +128,15 @@ func init() {
125128

126129
C.git_libgit2_init()
127130

131+
// Due to the multithreaded nature of Go and its interaction with
132+
// calling C functions, we cannot work with a library that was not built
133+
// with multi-threading support. The most likely outcome is a segfault
134+
// or panic at an incomprehensible time, so let's make it easy by
135+
// panicking right here.
136+
if Features()&FeatureThreads == 0 {
137+
panic("libgit2 was not built with threading support")
138+
}
139+
128140
// This is not something we should be doing, as we may be
129141
// stomping all over someone else's setup. The user should do
130142
// this themselves or use some binding/wrapper which does it

git_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ func updateReadme(t *testing.T, repo *Repository, content string) (*Oid, *Oid) {
9393
checkFatal(t, err)
9494
err = idx.AddByPath("README")
9595
checkFatal(t, err)
96+
err = idx.Write()
97+
checkFatal(t, err)
9698
treeId, err := idx.WriteTree()
9799
checkFatal(t, err)
98100

odb.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ func (object *OdbObject) Len() (len uint64) {
226226
return uint64(C.git_odb_object_size(object.ptr))
227227
}
228228

229+
func (object *OdbObject) Type() ObjectType {
230+
return ObjectType(C.git_odb_object_type(object.ptr))
231+
}
232+
229233
func (object *OdbObject) Data() (data []byte) {
230234
var c_blob unsafe.Pointer = C.git_odb_object_data(object.ptr)
231235
var blob []byte

remote.go

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,30 @@ type FetchOptions struct {
117117
Headers []string
118118
}
119119

120+
type ProxyType uint
121+
122+
const (
123+
// Do not attempt to connect through a proxy
124+
//
125+
// If built against lbicurl, it itself may attempt to connect
126+
// to a proxy if the environment variables specify it.
127+
ProxyTypeNone ProxyType = C.GIT_PROXY_NONE
128+
129+
// Try to auto-detect the proxy from the git configuration.
130+
ProxyTypeAuto ProxyType = C.GIT_PROXY_AUTO
131+
132+
// Connect via the URL given in the options
133+
ProxyTypeSpecified ProxyType = C.GIT_PROXY_SPECIFIED
134+
)
135+
136+
type ProxyOptions struct {
137+
// The type of proxy to use (or none)
138+
Type ProxyType
139+
140+
// The proxy's URL
141+
Url string
142+
}
143+
120144
type Remote struct {
121145
ptr *C.git_remote
122146
callbacks RemoteCallbacks
@@ -320,6 +344,20 @@ func pushUpdateReferenceCallback(refname, status *C.char, data unsafe.Pointer) i
320344
return int(callbacks.PushUpdateReferenceCallback(C.GoString(refname), C.GoString(status)))
321345
}
322346

347+
func populateProxyOptions(ptr *C.git_proxy_options, opts *ProxyOptions) {
348+
C.git_proxy_init_options(ptr, C.GIT_PROXY_OPTIONS_VERSION)
349+
if opts == nil {
350+
return
351+
}
352+
353+
ptr._type = C.git_proxy_t(opts.Type)
354+
ptr.url = C.CString(opts.Url)
355+
}
356+
357+
func freeProxyOptions(ptr *C.git_proxy_options) {
358+
C.free(unsafe.Pointer(ptr.url))
359+
}
360+
323361
func RemoteIsValidName(name string) bool {
324362
cname := C.CString(name)
325363
defer C.free(unsafe.Pointer(cname))
@@ -674,12 +712,12 @@ func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error
674712
return nil
675713
}
676714

677-
func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks, headers []string) error {
678-
return o.Connect(ConnectDirectionFetch, callbacks, headers)
715+
func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
716+
return o.Connect(ConnectDirectionFetch, callbacks, proxyOpts, headers)
679717
}
680718

681-
func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, headers []string) error {
682-
return o.Connect(ConnectDirectionPush, callbacks, headers)
719+
func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
720+
return o.Connect(ConnectDirectionPush, callbacks, proxyOpts, headers)
683721
}
684722

685723
// Connect opens a connection to a remote.
@@ -689,19 +727,24 @@ func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, headers []string) error
689727
// starts up a specific binary which can only do the one or the other.
690728
//
691729
// 'headers' are extra HTTP headers to use in this connection.
692-
func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks, headers []string) error {
730+
func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
693731
var ccallbacks C.git_remote_callbacks
694732
populateRemoteCallbacks(&ccallbacks, callbacks)
695733

734+
var cproxy C.git_proxy_options
735+
populateProxyOptions(&cproxy, proxyOpts)
736+
defer freeProxyOptions(&cproxy)
737+
696738
cheaders := C.git_strarray{}
697739
cheaders.count = C.size_t(len(headers))
698740
cheaders.strings = makeCStringsFromStrings(headers)
699741
defer freeStrarray(&cheaders)
700742

743+
701744
runtime.LockOSThread()
702745
defer runtime.UnlockOSThread()
703746

704-
if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cheaders); ret != 0 {
747+
if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders); ret != 0 {
705748
return MakeGitError(ret)
706749
}
707750
return nil

0 commit comments

Comments
 (0)