diff --git a/blob.go b/blob.go index 1a86e60..2daebe9 100644 --- a/blob.go +++ b/blob.go @@ -4,15 +4,13 @@ package git #include #include -extern int _go_git_blob_create_fromchunks(git_oid *id, - git_repository *repo, - const char *hintpath, - void *payload); - +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" ) @@ -78,27 +76,71 @@ func blobChunkCb(buffer *C.char, maxLen C.size_t, handle unsafe.Pointer) int { return len(goBuf) } -func (repo *Repository) CreateBlobFromChunks(hintPath string, callback BlobChunkCallback) (*Oid, error) { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - +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)) } - oid := C.git_oid{} - payload := &BlobCallbackData{Callback: callback} - handle := pointerHandles.Track(payload) - defer pointerHandles.Untrack(handle) + runtime.LockOSThread() + defer runtime.UnlockOSThread() - ecode := C._go_git_blob_create_fromchunks(&oid, repo.ptr, chintPath, handle) - if payload.Error != nil { - return nil, payload.Error - } + ecode := C.git_blob_create_fromstream(&stream, repo.ptr, chintPath) if ecode < 0 { return nil, MakeGitError(ecode) } + + return newBlobWriteStreamFromC(stream), nil +} + +type BlobWriteStream struct { + ptr *C.git_writestream +} + +func newBlobWriteStreamFromC(ptr *C.git_writestream) *BlobWriteStream { + stream := &BlobWriteStream{ + ptr: ptr, + } + + 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) + 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) + if ecode < 0 { + return nil, MakeGitError(ecode) + } + return newOidFromC(&oid), nil } diff --git a/remote.go b/remote.go index 8a57280..bacdfa3 100644 --- a/remote.go +++ b/remote.go @@ -117,6 +117,30 @@ type FetchOptions struct { 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 @@ -320,6 +344,20 @@ func pushUpdateReferenceCallback(refname, status *C.char, data unsafe.Pointer) i 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)) @@ -654,12 +692,12 @@ func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error return nil } -func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks, headers []string) error { - return o.Connect(ConnectDirectionFetch, callbacks, headers) +func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error { + return o.Connect(ConnectDirectionFetch, callbacks, proxyOpts, headers) } -func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, headers []string) error { - return o.Connect(ConnectDirectionPush, callbacks, 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. @@ -669,19 +707,24 @@ func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, headers []string) error // 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, headers []string) error { +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() - if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cheaders); ret != 0 { + if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders); ret != 0 { return MakeGitError(ret) } return nil diff --git a/remote_test.go b/remote_test.go index 978b803..539b4b1 100644 --- a/remote_test.go +++ b/remote_test.go @@ -58,7 +58,7 @@ func TestRemoteConnect(t *testing.T) { remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository") checkFatal(t, err) - err = remote.ConnectFetch(nil, nil) + err = remote.ConnectFetch(nil, nil, nil) checkFatal(t, err) } @@ -69,7 +69,7 @@ func TestRemoteLs(t *testing.T) { remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository") checkFatal(t, err) - err = remote.ConnectFetch(nil, nil) + err = remote.ConnectFetch(nil, nil, nil) checkFatal(t, err) heads, err := remote.Ls() @@ -87,7 +87,7 @@ func TestRemoteLsFiltering(t *testing.T) { remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository") checkFatal(t, err) - err = remote.ConnectFetch(nil, nil) + err = remote.ConnectFetch(nil, nil, nil) checkFatal(t, err) heads, err := remote.Ls("master") @@ -166,7 +166,7 @@ func TestRemotePrune(t *testing.T) { rr, err := repo.Remotes.Lookup("origin") checkFatal(t, err) - err = rr.ConnectFetch(nil, nil) + err = rr.ConnectFetch(nil, nil, nil) checkFatal(t, err) err = rr.Prune(nil) diff --git a/vendor/libgit2 b/vendor/libgit2 index 785d8c4..1dc4491 160000 --- a/vendor/libgit2 +++ b/vendor/libgit2 @@ -1 +1 @@ -Subproject commit 785d8c48ea8725691da3c50e7dae8751523d4c30 +Subproject commit 1dc449105b329ea4f8ea9982bc2da869d231c04a diff --git a/wrapper.c b/wrapper.c index e39665a..7407611 100644 --- a/wrapper.c +++ b/wrapper.c @@ -108,19 +108,6 @@ void _go_git_setup_callbacks(git_remote_callbacks *callbacks) { callbacks->push_update_reference = (push_update_reference_cb) pushUpdateReferenceCallback; } -int _go_blob_chunk_cb(char *buffer, size_t maxLen, void *payload) -{ - return blobChunkCb(buffer, maxLen, payload); -} - -int _go_git_blob_create_fromchunks(git_oid *id, - git_repository *repo, - const char *hintpath, - void *payload) -{ - return git_blob_create_fromchunks(id, repo, hintpath, _go_blob_chunk_cb, payload); -} - 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); @@ -172,4 +159,19 @@ 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 */