summaryrefslogtreecommitdiff
path: root/remote.go
diff options
context:
space:
mode:
Diffstat (limited to 'remote.go')
-rw-r--r--remote.go386
1 files changed, 237 insertions, 149 deletions
diff --git a/remote.go b/remote.go
index 0635608..d3f437d 100644
--- a/remote.go
+++ b/remote.go
@@ -69,6 +69,78 @@ type RemoteCallbacks struct {
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
@@ -108,7 +180,13 @@ type HostkeyCertificate struct {
}
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 {
@@ -123,6 +201,12 @@ func newRemoteHeadFromC(ptr *C.git_remote_head) RemoteHead {
}
}
+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 {
@@ -155,12 +239,14 @@ func completionCallback(completion_type C.git_remote_completion_type, data unsaf
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 0
+ 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))
- *_cred = cred.ptr
+ if cred != nil {
+ *_cred = cred.ptr
+ }
return int(ret)
}
@@ -258,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))
@@ -267,41 +367,22 @@ func RemoteIsValidName(name string) bool {
return false
}
-func (r *Remote) SetCallbacks(callbacks *RemoteCallbacks) error {
- r.callbacks = *callbacks
-
- var ccallbacks C.git_remote_callbacks
- populateRemoteCallbacks(&ccallbacks, &r.callbacks)
-
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
-
- ecode := C.git_remote_set_callbacks(r.ptr, &ccallbacks)
- if ecode < 0 {
- return MakeGitError(ecode)
- }
-
- return nil
-}
-
func (r *Remote) Free() {
runtime.SetFinalizer(r, nil)
-
- callbacks := C.git_remote_get_callbacks(r.ptr)
- if callbacks != nil && callbacks.payload != nil {
- pointerHandles.Untrack(callbacks.payload)
- }
-
C.git_remote_free(r.ptr)
}
-func (repo *Repository) ListRemotes() ([]string, error) {
+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, repo.ptr)
+ ecode := C.git_remote_list(&r, c.repo.ptr)
if ecode < 0 {
return nil, MakeGitError(ecode)
}
@@ -311,7 +392,7 @@ func (repo *Repository) ListRemotes() ([]string, error) {
return remotes, nil
}
-func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
+func (c *RemoteCollection) Create(name string, url string) (*Remote, error) {
remote := &Remote{}
cname := C.CString(name)
@@ -322,7 +403,7 @@ func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_remote_create(&remote.ptr, repo.ptr, cname, curl)
+ ret := C.git_remote_create(&remote.ptr, c.repo.ptr, cname, curl)
if ret < 0 {
return nil, MakeGitError(ret)
}
@@ -330,21 +411,21 @@ func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
return remote, nil
}
-func (repo *Repository) DeleteRemote(name string) error {
+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(repo.ptr, cname)
+ ret := C.git_remote_delete(c.repo.ptr, cname)
if ret < 0 {
return MakeGitError(ret)
}
return nil
}
-func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch string) (*Remote, error) {
+func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch string) (*Remote, error) {
remote := &Remote{}
cname := C.CString(name)
@@ -357,7 +438,7 @@ func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_remote_create_with_fetchspec(&remote.ptr, repo.ptr, cname, curl, cfetch)
+ ret := C.git_remote_create_with_fetchspec(&remote.ptr, c.repo.ptr, cname, curl, cfetch)
if ret < 0 {
return nil, MakeGitError(ret)
}
@@ -365,18 +446,16 @@ func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch
return remote, nil
}
-func (repo *Repository) CreateAnonymousRemote(url, fetch string) (*Remote, error) {
+func (c *RemoteCollection) CreateAnonymous(url string) (*Remote, error) {
remote := &Remote{}
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_anonymous(&remote.ptr, repo.ptr, curl, cfetch)
+ ret := C.git_remote_create_anonymous(&remote.ptr, c.repo.ptr, curl)
if ret < 0 {
return nil, MakeGitError(ret)
}
@@ -384,7 +463,7 @@ func (repo *Repository) CreateAnonymousRemote(url, fetch string) (*Remote, error
return remote, nil
}
-func (repo *Repository) LookupRemote(name string) (*Remote, error) {
+func (c *RemoteCollection) Lookup(name string) (*Remote, error) {
remote := &Remote{}
cname := C.CString(name)
@@ -393,7 +472,7 @@ func (repo *Repository) LookupRemote(name string) (*Remote, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_remote_lookup(&remote.ptr, repo.ptr, cname)
+ ret := C.git_remote_lookup(&remote.ptr, c.repo.ptr, cname)
if ret < 0 {
return nil, MakeGitError(ret)
}
@@ -401,22 +480,6 @@ func (repo *Repository) LookupRemote(name string) (*Remote, error) {
return remote, nil
}
-func (o *Remote) Save() error {
-
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
-
- ret := C.git_remote_save(o.ptr)
- if ret < 0 {
- return MakeGitError(ret)
- }
- return nil
-}
-
-func (o *Remote) Owner() Repository {
- return Repository{C.git_remote_owner(o.ptr)}
-}
-
func (o *Remote) Name() string {
return C.GoString(C.git_remote_name(o.ptr))
}
@@ -429,42 +492,68 @@ func (o *Remote) PushUrl() string {
return C.GoString(C.git_remote_pushurl(o.ptr))
}
-func (o *Remote) SetUrl(url string) error {
+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)
+ 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(o.ptr, curl)
+ ret := C.git_remote_set_url(c.repo.ptr, cremote, curl)
if ret < 0 {
return MakeGitError(ret)
}
return nil
}
-func (o *Remote) SetPushUrl(url string) error {
+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(o.ptr, curl)
+ ret := C.git_remote_set_pushurl(c.repo.ptr, cremote, curl)
if ret < 0 {
return MakeGitError(ret)
}
return nil
}
-func (o *Remote) AddFetch(refspec string) error {
+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(o.ptr, crefspec)
+ ret := C.git_remote_add_fetch(c.repo.ptr, cremote, crefspec)
if ret < 0 {
return MakeGitError(ret)
}
@@ -525,30 +614,16 @@ func (o *Remote) FetchRefspecs() ([]string, error) {
return refspecs, nil
}
-func (o *Remote) SetFetchRefspecs(refspecs []string) error {
- crefspecs := C.git_strarray{}
- crefspecs.count = C.size_t(len(refspecs))
- crefspecs.strings = makeCStringsFromStrings(refspecs)
- defer freeStrarray(&crefspecs)
-
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
-
- ret := C.git_remote_set_fetch_refspecs(o.ptr, &crefspecs)
- if ret < 0 {
- return MakeGitError(ret)
- }
- return nil
-}
-
-func (o *Remote) AddPush(refspec string) error {
+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(o.ptr, crefspec)
+ ret := C.git_remote_add_push(c.repo.ptr, cremote, crefspec)
if ret < 0 {
return MakeGitError(ret)
}
@@ -570,53 +645,45 @@ func (o *Remote) PushRefspecs() ([]string, error) {
return refspecs, nil
}
-func (o *Remote) SetPushRefspecs(refspecs []string) error {
- crefspecs := C.git_strarray{}
- crefspecs.count = C.size_t(len(refspecs))
- crefspecs.strings = makeCStringsFromStrings(refspecs)
- defer freeStrarray(&crefspecs)
-
- runtime.LockOSThread()
- defer runtime.UnlockOSThread()
+func (o *Remote) RefspecCount() uint {
+ return uint(C.git_remote_refspec_count(o.ptr))
+}
- ret := C.git_remote_set_push_refspecs(o.ptr, &crefspecs)
- if ret < 0 {
- return MakeGitError(ret)
+func populateFetchOptions(options *C.git_fetch_options, opts *FetchOptions) {
+ C.git_fetch_init_options(options, C.GIT_FETCH_OPTIONS_VERSION)
+ if opts == nil {
+ return
}
- return nil
-}
+ 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)
-func (o *Remote) ClearRefspecs() {
- C.git_remote_clear_refspecs(o.ptr)
+ options.custom_headers = C.git_strarray{}
+ options.custom_headers.count = C.size_t(len(opts.Headers))
+ options.custom_headers.strings = makeCStringsFromStrings(opts.Headers)
}
-func (o *Remote) RefspecCount() uint {
- return uint(C.git_remote_refspec_count(o.ptr))
-}
+func populatePushOptions(options *C.git_push_options, opts *PushOptions) {
+ C.git_push_init_options(options, C.GIT_PUSH_OPTIONS_VERSION)
+ if opts == nil {
+ return
+ }
-func (o *Remote) SetUpdateFetchHead(val bool) {
- C.git_remote_set_update_fetchhead(o.ptr, cbool(val))
-}
+ options.pb_parallelism = C.uint(opts.PbParallelism)
-func (o *Remote) UpdateFetchHead() bool {
- return C.git_remote_update_fetchhead(o.ptr) > 0
+ 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; sig and msg specify what to use for the reflog
-// entries. Leave nil and "" to use defaults.
-func (o *Remote) Fetch(refspecs []string, sig *Signature, msg string) error {
-
- var csig *C.git_signature = nil
- if sig != nil {
- csig, err := sig.toC()
- if err != nil {
- return err
- }
- defer C.git_signature_free(csig)
- }
-
+// 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)
@@ -628,34 +695,68 @@ func (o *Remote) Fetch(refspecs []string, sig *Signature, msg string) error {
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, csig, cmsg)
+ ret := C.git_remote_fetch(o.ptr, &crefspecs, coptions, cmsg)
if ret < 0 {
return MakeGitError(ret)
}
return nil
}
-func (o *Remote) ConnectFetch() error {
- return o.Connect(ConnectDirectionFetch)
+func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
+ return o.Connect(ConnectDirectionFetch, callbacks, proxyOpts, headers)
}
-func (o *Remote) ConnectPush() error {
- return o.Connect(ConnectDirectionPush)
+func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
+ return o.Connect(ConnectDirectionPush, callbacks, proxyOpts, headers)
}
-func (o *Remote) Connect(direction ConnectDirection) error {
+// 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()
- if ret := C.git_remote_connect(o.ptr, C.git_direction(direction)); ret != 0 {
+ if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders); ret != 0 {
return MakeGitError(ret)
}
return nil
}
+func (o *Remote) Disconnect() {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ C.git_remote_disconnect(o.ptr)
+}
+
func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
var refs **C.git_remote_head
@@ -702,39 +803,23 @@ func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
return heads, nil
}
-func (o *Remote) Push(refspecs []string, opts *PushOptions, sig *Signature, msg string) error {
- var csig *C.git_signature = nil
- if sig != nil {
- csig, err := sig.toC()
- if err != nil {
- return err
- }
- defer C.git_signature_free(csig)
- }
-
- var cmsg *C.char
- if msg == "" {
- cmsg = nil
- } else {
- cmsg = C.CString(msg)
- defer C.free(unsafe.Pointer(cmsg))
- }
-
- var copts C.git_push_options
- C.git_push_init_options(&copts, C.GIT_PUSH_OPTIONS_VERSION)
- if opts != nil {
- copts.pb_parallelism = C.uint(opts.PbParallelism)
- }
-
+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, &copts, csig, cmsg)
+ ret := C.git_remote_push(o.ptr, &crefspecs, coptions)
if ret < 0 {
return MakeGitError(ret)
}
@@ -745,11 +830,14 @@ func (o *Remote) PruneRefs() bool {
return C.git_remote_prune_refs(o.ptr) > 0
}
-func (o *Remote) Prune() error {
+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)
+ ret := C.git_remote_prune(o.ptr, &ccallbacks)
if ret < 0 {
return MakeGitError(ret)
}