More callback refactoring (#713)

This change:

* Gets rid of the `.toC()` functions for Options objects, since they
  were redundant with the `populateXxxOptions()`.
* Adds support for `errorTarget` to the `RemoteOptions`, since they are
  used in the same stack for some functions (like `Fetch()`). Now for
  those cases, the error returned by the callback will be preserved
  as-is.
This commit is contained in:
lhchavez 2020-12-10 07:19:41 -08:00 committed by GitHub
parent e28cce87c7
commit 10c67474a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 453 additions and 362 deletions

View File

@ -87,13 +87,6 @@ func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOptions {
return opts return opts
} }
func (opts *CheckoutOptions) toC(errorTarget *error) *C.git_checkout_options {
if opts == nil {
return nil
}
return populateCheckoutOptions(&C.git_checkout_options{}, opts, errorTarget)
}
type checkoutCallbackData struct { type checkoutCallbackData struct {
options *CheckoutOptions options *CheckoutOptions
errorTarget *error errorTarget *error
@ -144,61 +137,61 @@ func checkoutProgressCallback(
data.options.ProgressCallback(C.GoString(path), uint(completed_steps), uint(total_steps)) data.options.ProgressCallback(C.GoString(path), uint(completed_steps), uint(total_steps))
} }
// Convert the CheckoutOptions struct to the corresponding // populateCheckoutOptions populates the provided C-struct with the contents of
// C-struct. Returns a pointer to ptr, or nil if opts is nil, in order // the provided CheckoutOptions struct. Returns copts, or nil if opts is nil,
// to help with what to pass. // in order to help with what to pass.
func populateCheckoutOptions(ptr *C.git_checkout_options, opts *CheckoutOptions, errorTarget *error) *C.git_checkout_options { func populateCheckoutOptions(copts *C.git_checkout_options, opts *CheckoutOptions, errorTarget *error) *C.git_checkout_options {
C.git_checkout_options_init(copts, C.GIT_CHECKOUT_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return nil return nil
} }
C.git_checkout_options_init(ptr, 1) copts.checkout_strategy = C.uint(opts.Strategy)
ptr.checkout_strategy = C.uint(opts.Strategy) copts.disable_filters = cbool(opts.DisableFilters)
ptr.disable_filters = cbool(opts.DisableFilters) copts.dir_mode = C.uint(opts.DirMode.Perm())
ptr.dir_mode = C.uint(opts.DirMode.Perm()) copts.file_mode = C.uint(opts.FileMode.Perm())
ptr.file_mode = C.uint(opts.FileMode.Perm()) copts.notify_flags = C.uint(opts.NotifyFlags)
ptr.notify_flags = C.uint(opts.NotifyFlags)
if opts.NotifyCallback != nil || opts.ProgressCallback != nil { if opts.NotifyCallback != nil || opts.ProgressCallback != nil {
C._go_git_populate_checkout_callbacks(ptr) C._go_git_populate_checkout_callbacks(copts)
data := &checkoutCallbackData{ data := &checkoutCallbackData{
options: opts, options: opts,
errorTarget: errorTarget, errorTarget: errorTarget,
} }
payload := pointerHandles.Track(data) payload := pointerHandles.Track(data)
if opts.NotifyCallback != nil { if opts.NotifyCallback != nil {
ptr.notify_payload = payload copts.notify_payload = payload
} }
if opts.ProgressCallback != nil { if opts.ProgressCallback != nil {
ptr.progress_payload = payload copts.progress_payload = payload
} }
} }
if opts.TargetDirectory != "" { if opts.TargetDirectory != "" {
ptr.target_directory = C.CString(opts.TargetDirectory) copts.target_directory = C.CString(opts.TargetDirectory)
} }
if len(opts.Paths) > 0 { if len(opts.Paths) > 0 {
ptr.paths.strings = makeCStringsFromStrings(opts.Paths) copts.paths.strings = makeCStringsFromStrings(opts.Paths)
ptr.paths.count = C.size_t(len(opts.Paths)) copts.paths.count = C.size_t(len(opts.Paths))
} }
if opts.Baseline != nil { if opts.Baseline != nil {
ptr.baseline = opts.Baseline.cast_ptr copts.baseline = opts.Baseline.cast_ptr
} }
return ptr return copts
} }
func freeCheckoutOptions(ptr *C.git_checkout_options) { func freeCheckoutOptions(copts *C.git_checkout_options) {
if ptr == nil { if copts == nil {
return return
} }
C.free(unsafe.Pointer(ptr.target_directory)) C.free(unsafe.Pointer(copts.target_directory))
if ptr.paths.count > 0 { if copts.paths.count > 0 {
freeStrarray(&ptr.paths) freeStrarray(&copts.paths)
} }
if ptr.notify_payload != nil { if copts.notify_payload != nil {
pointerHandles.Untrack(ptr.notify_payload) pointerHandles.Untrack(copts.notify_payload)
} else if ptr.progress_payload != nil { } else if copts.progress_payload != nil {
pointerHandles.Untrack(ptr.progress_payload) pointerHandles.Untrack(copts.progress_payload)
} }
} }
@ -209,7 +202,7 @@ func (v *Repository) CheckoutHead(opts *CheckoutOptions) error {
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cOpts := opts.toC(&err) cOpts := populateCheckoutOptions(&C.git_checkout_options{}, opts, &err)
defer freeCheckoutOptions(cOpts) defer freeCheckoutOptions(cOpts)
ret := C.git_checkout_head(v.ptr, cOpts) ret := C.git_checkout_head(v.ptr, cOpts)
@ -238,7 +231,7 @@ func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOptions) error {
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cOpts := opts.toC(&err) cOpts := populateCheckoutOptions(&C.git_checkout_options{}, opts, &err)
defer freeCheckoutOptions(cOpts) defer freeCheckoutOptions(cOpts)
ret := C.git_checkout_index(v.ptr, iptr, cOpts) ret := C.git_checkout_index(v.ptr, iptr, cOpts)
@ -258,7 +251,7 @@ func (v *Repository) CheckoutTree(tree *Tree, opts *CheckoutOptions) error {
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cOpts := opts.toC(&err) cOpts := populateCheckoutOptions(&C.git_checkout_options{}, opts, &err)
defer freeCheckoutOptions(cOpts) defer freeCheckoutOptions(cOpts)
ret := C.git_checkout_tree(v.ptr, tree.ptr, cOpts) ret := C.git_checkout_tree(v.ptr, tree.ptr, cOpts)

View File

@ -25,24 +25,23 @@ func cherrypickOptionsFromC(c *C.git_cherrypick_options) CherrypickOptions {
return opts return opts
} }
func (opts *CherrypickOptions) toC(errorTarget *error) *C.git_cherrypick_options { func populateCherrypickOptions(copts *C.git_cherrypick_options, opts *CherrypickOptions, errorTarget *error) *C.git_cherrypick_options {
C.git_cherrypick_options_init(copts, C.GIT_CHERRYPICK_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return nil return nil
} }
c := C.git_cherrypick_options{} copts.mainline = C.uint(opts.Mainline)
c.version = C.uint(opts.Version) populateMergeOptions(&copts.merge_opts, &opts.MergeOpts)
c.mainline = C.uint(opts.Mainline) populateCheckoutOptions(&copts.checkout_opts, &opts.CheckoutOpts, errorTarget)
c.merge_opts = *opts.MergeOpts.toC() return copts
c.checkout_opts = *opts.CheckoutOpts.toC(errorTarget)
return &c
} }
func freeCherrypickOpts(ptr *C.git_cherrypick_options) { func freeCherrypickOpts(copts *C.git_cherrypick_options) {
if ptr == nil { if copts == nil {
return return
} }
freeMergeOptions(&ptr.merge_opts) freeMergeOptions(&copts.merge_opts)
freeCheckoutOptions(&ptr.checkout_opts) freeCheckoutOptions(&copts.checkout_opts)
} }
func DefaultCherrypickOptions() (CherrypickOptions, error) { func DefaultCherrypickOptions() (CherrypickOptions, error) {
@ -64,7 +63,7 @@ func (v *Repository) Cherrypick(commit *Commit, opts CherrypickOptions) error {
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cOpts := opts.toC(&err) cOpts := populateCherrypickOptions(&C.git_cherrypick_options{}, &opts, &err)
defer freeCherrypickOpts(cOpts) defer freeCherrypickOpts(cOpts)
ret := C.git_cherrypick(v.ptr, commit.cast_ptr, cOpts) ret := C.git_cherrypick(v.ptr, commit.cast_ptr, cOpts)
@ -83,7 +82,7 @@ func (r *Repository) CherrypickCommit(pick, our *Commit, opts CherrypickOptions)
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
cOpts := opts.MergeOpts.toC() cOpts := populateMergeOptions(&C.git_merge_options{}, &opts.MergeOpts)
defer freeMergeOptions(cOpts) defer freeMergeOptions(cOpts)
var ptr *C.git_index var ptr *C.git_index

View File

@ -94,15 +94,14 @@ type cloneCallbackData struct {
errorTarget *error errorTarget *error
} }
func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions, errorTarget *error) *C.git_clone_options { func populateCloneOptions(copts *C.git_clone_options, opts *CloneOptions, errorTarget *error) *C.git_clone_options {
C.git_clone_options_init(ptr, C.GIT_CLONE_OPTIONS_VERSION) C.git_clone_options_init(copts, C.GIT_CLONE_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return nil return nil
} }
populateCheckoutOptions(&ptr.checkout_opts, opts.CheckoutOpts, errorTarget) populateCheckoutOptions(&copts.checkout_opts, opts.CheckoutOpts, errorTarget)
populateFetchOptions(&ptr.fetch_opts, opts.FetchOptions) populateFetchOptions(&copts.fetch_opts, opts.FetchOptions, errorTarget)
ptr.bare = cbool(opts.Bare) copts.bare = cbool(opts.Bare)
if opts.RemoteCreateCallback != nil { if opts.RemoteCreateCallback != nil {
data := &cloneCallbackData{ data := &cloneCallbackData{
@ -110,23 +109,24 @@ func populateCloneOptions(ptr *C.git_clone_options, opts *CloneOptions, errorTar
errorTarget: errorTarget, errorTarget: errorTarget,
} }
// Go v1.1 does not allow to assign a C function pointer // Go v1.1 does not allow to assign a C function pointer
C._go_git_populate_clone_callbacks(ptr) C._go_git_populate_clone_callbacks(copts)
ptr.remote_cb_payload = pointerHandles.Track(data) copts.remote_cb_payload = pointerHandles.Track(data)
} }
return ptr return copts
} }
func freeCloneOptions(ptr *C.git_clone_options) { func freeCloneOptions(copts *C.git_clone_options) {
if ptr == nil { if copts == nil {
return return
} }
freeCheckoutOptions(&ptr.checkout_opts) freeCheckoutOptions(&copts.checkout_opts)
freeFetchOptions(&copts.fetch_opts)
if ptr.remote_cb_payload != nil { if copts.remote_cb_payload != nil {
pointerHandles.Untrack(ptr.remote_cb_payload) pointerHandles.Untrack(copts.remote_cb_payload)
} }
C.free(unsafe.Pointer(ptr.checkout_branch)) C.free(unsafe.Pointer(copts.checkout_branch))
} }

82
diff.go
View File

@ -641,29 +641,24 @@ func diffNotifyCallback(_diff_so_far unsafe.Pointer, delta_to_add *C.git_diff_de
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
func (opts *DiffOptions) toC(repo *Repository, errorTarget *error) *C.git_diff_options { func populateDiffOptions(copts *C.git_diff_options, opts *DiffOptions, repo *Repository, errorTarget *error) *C.git_diff_options {
C.git_diff_options_init(copts, C.GIT_DIFF_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return nil return nil
} }
cpathspec := C.git_strarray{} copts.flags = C.uint32_t(opts.Flags)
if opts.Pathspec != nil { copts.ignore_submodules = C.git_submodule_ignore_t(opts.IgnoreSubmodules)
cpathspec.count = C.size_t(len(opts.Pathspec)) if len(opts.Pathspec) > 0 {
cpathspec.strings = makeCStringsFromStrings(opts.Pathspec) copts.pathspec.count = C.size_t(len(opts.Pathspec))
} copts.pathspec.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),
} }
copts.context_lines = C.uint32_t(opts.ContextLines)
copts.interhunk_lines = C.uint32_t(opts.InterhunkLines)
copts.id_abbrev = C.uint16_t(opts.IdAbbrev)
copts.max_size = C.git_off_t(opts.MaxSize)
copts.old_prefix = C.CString(opts.OldPrefix)
copts.new_prefix = C.CString(opts.NewPrefix)
if opts.NotifyCallback != nil { if opts.NotifyCallback != nil {
notifyData := &diffNotifyCallbackData{ notifyData := &diffNotifyCallbackData{
@ -681,8 +676,7 @@ func freeDiffOptions(copts *C.git_diff_options) {
if copts == nil { if copts == nil {
return return
} }
cpathspec := copts.pathspec freeStrarray(&copts.pathspec)
freeStrarray(&cpathspec)
C.free(unsafe.Pointer(copts.old_prefix)) C.free(unsafe.Pointer(copts.old_prefix))
C.free(unsafe.Pointer(copts.new_prefix)) C.free(unsafe.Pointer(copts.new_prefix))
if copts.payload != nil { if copts.payload != nil {
@ -703,7 +697,7 @@ func (v *Repository) DiffTreeToTree(oldTree, newTree *Tree, opts *DiffOptions) (
} }
var err error var err error
copts := opts.toC(v, &err) copts := populateDiffOptions(&C.git_diff_options{}, opts, v, &err)
defer freeDiffOptions(copts) defer freeDiffOptions(copts)
runtime.LockOSThread() runtime.LockOSThread()
@ -730,7 +724,7 @@ func (v *Repository) DiffTreeToWorkdir(oldTree *Tree, opts *DiffOptions) (*Diff,
} }
var err error var err error
copts := opts.toC(v, &err) copts := populateDiffOptions(&C.git_diff_options{}, opts, v, &err)
defer freeDiffOptions(copts) defer freeDiffOptions(copts)
runtime.LockOSThread() runtime.LockOSThread()
@ -762,7 +756,7 @@ func (v *Repository) DiffTreeToIndex(oldTree *Tree, index *Index, opts *DiffOpti
} }
var err error var err error
copts := opts.toC(v, &err) copts := populateDiffOptions(&C.git_diff_options{}, opts, v, &err)
defer freeDiffOptions(copts) defer freeDiffOptions(copts)
runtime.LockOSThread() runtime.LockOSThread()
@ -790,7 +784,7 @@ func (v *Repository) DiffTreeToWorkdirWithIndex(oldTree *Tree, opts *DiffOptions
} }
var err error var err error
copts := opts.toC(v, &err) copts := populateDiffOptions(&C.git_diff_options{}, opts, v, &err)
defer freeDiffOptions(copts) defer freeDiffOptions(copts)
runtime.LockOSThread() runtime.LockOSThread()
@ -817,7 +811,7 @@ func (v *Repository) DiffIndexToWorkdir(index *Index, opts *DiffOptions) (*Diff,
} }
var err error var err error
copts := opts.toC(v, &err) copts := populateDiffOptions(&C.git_diff_options{}, opts, v, &err)
defer freeDiffOptions(copts) defer freeDiffOptions(copts)
runtime.LockOSThread() runtime.LockOSThread()
@ -873,7 +867,7 @@ func DiffBlobs(oldBlob *Blob, oldAsPath string, newBlob *Blob, newAsPath string,
newBlobPath := C.CString(newAsPath) newBlobPath := C.CString(newAsPath)
defer C.free(unsafe.Pointer(newBlobPath)) defer C.free(unsafe.Pointer(newBlobPath))
copts := opts.toC(repo, &err) copts := populateDiffOptions(&C.git_diff_options{}, opts, repo, &err)
defer freeDiffOptions(copts) defer freeDiffOptions(copts)
runtime.LockOSThread() runtime.LockOSThread()
@ -977,40 +971,38 @@ func DefaultApplyOptions() (*ApplyOptions, error) {
return applyOptionsFromC(&opts), nil return applyOptionsFromC(&opts), nil
} }
func (a *ApplyOptions) toC(errorTarget *error) *C.git_apply_options { func populateApplyOptions(copts *C.git_apply_options, opts *ApplyOptions, errorTarget *error) *C.git_apply_options {
if a == nil { C.git_apply_options_init(copts, C.GIT_APPLY_OPTIONS_VERSION)
if opts == nil {
return nil return nil
} }
opts := &C.git_apply_options{ copts.flags = C.uint(opts.Flags)
version: C.GIT_APPLY_OPTIONS_VERSION,
flags: C.uint(a.Flags),
}
if a.ApplyDeltaCallback != nil || a.ApplyHunkCallback != nil { if opts.ApplyDeltaCallback != nil || opts.ApplyHunkCallback != nil {
data := &applyCallbackData{ data := &applyCallbackData{
options: a, options: opts,
errorTarget: errorTarget, errorTarget: errorTarget,
} }
C._go_git_populate_apply_callbacks(opts) C._go_git_populate_apply_callbacks(copts)
opts.payload = pointerHandles.Track(data) copts.payload = pointerHandles.Track(data)
} }
return opts return copts
} }
func freeApplyOptions(opts *C.git_apply_options) { func freeApplyOptions(copts *C.git_apply_options) {
if opts == nil { if copts == nil {
return return
} }
if opts.payload != nil { if copts.payload != nil {
pointerHandles.Untrack(opts.payload) pointerHandles.Untrack(copts.payload)
} }
} }
func applyOptionsFromC(opts *C.git_apply_options) *ApplyOptions { func applyOptionsFromC(copts *C.git_apply_options) *ApplyOptions {
return &ApplyOptions{ return &ApplyOptions{
Flags: uint(opts.flags), Flags: uint(copts.flags),
} }
} }
@ -1038,7 +1030,7 @@ func (v *Repository) ApplyDiff(diff *Diff, location ApplyLocation, opts *ApplyOp
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cOpts := opts.toC(&err) cOpts := populateApplyOptions(&C.git_apply_options{}, opts, &err)
defer freeApplyOptions(cOpts) defer freeApplyOptions(cOpts)
ret := C.git_apply(v.ptr, diff.ptr, C.git_apply_location_t(location), cOpts) ret := C.git_apply(v.ptr, diff.ptr, C.git_apply_location_t(location), cOpts)
@ -1061,7 +1053,7 @@ func (v *Repository) ApplyToTree(diff *Diff, tree *Tree, opts *ApplyOptions) (*I
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cOpts := opts.toC(&err) cOpts := populateApplyOptions(&C.git_apply_options{}, opts, &err)
defer freeApplyOptions(cOpts) defer freeApplyOptions(cOpts)
var indexPtr *C.git_index var indexPtr *C.git_index

View File

@ -21,32 +21,29 @@ import (
type Indexer struct { type Indexer struct {
ptr *C.git_indexer ptr *C.git_indexer
stats C.git_transfer_progress stats C.git_transfer_progress
callbacks RemoteCallbacks ccallbacks C.git_remote_callbacks
callbacksHandle unsafe.Pointer
} }
// NewIndexer creates a new indexer instance. // NewIndexer creates a new indexer instance.
func NewIndexer(packfilePath string, odb *Odb, callback TransferProgressCallback) (indexer *Indexer, err error) { func NewIndexer(packfilePath string, odb *Odb, callback TransferProgressCallback) (indexer *Indexer, err error) {
indexer = new(Indexer)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
var odbPtr *C.git_odb = nil var odbPtr *C.git_odb = nil
if odb != nil { if odb != nil {
odbPtr = odb.ptr odbPtr = odb.ptr
} }
indexer.callbacks.TransferProgressCallback = callback indexer = new(Indexer)
indexer.callbacksHandle = pointerHandles.Track(&indexer.callbacks) populateRemoteCallbacks(&indexer.ccallbacks, &RemoteCallbacks{TransferProgressCallback: callback}, nil)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
cstr := C.CString(packfilePath) cstr := C.CString(packfilePath)
defer C.free(unsafe.Pointer(cstr)) defer C.free(unsafe.Pointer(cstr))
ret := C._go_git_indexer_new(&indexer.ptr, cstr, 0, odbPtr, indexer.callbacksHandle) ret := C._go_git_indexer_new(&indexer.ptr, cstr, 0, odbPtr, indexer.ccallbacks.payload)
runtime.KeepAlive(odb) runtime.KeepAlive(odb)
if ret < 0 { if ret < 0 {
pointerHandles.Untrack(indexer.callbacksHandle) untrackCallbacksPayload(&indexer.ccallbacks)
return nil, MakeGitError(ret) return nil, MakeGitError(ret)
} }
@ -93,7 +90,7 @@ func (indexer *Indexer) Commit() (*Oid, error) {
// Free frees the indexer and its resources. // Free frees the indexer and its resources.
func (indexer *Indexer) Free() { func (indexer *Indexer) Free() {
pointerHandles.Untrack(indexer.callbacksHandle) untrackCallbacksPayload(&indexer.ccallbacks)
runtime.SetFinalizer(indexer, nil) runtime.SetFinalizer(indexer, nil)
C.git_indexer_free(indexer.ptr) C.git_indexer_free(indexer.ptr)
} }

View File

@ -172,21 +172,20 @@ func DefaultMergeOptions() (MergeOptions, error) {
return mergeOptionsFromC(&opts), nil return mergeOptionsFromC(&opts), nil
} }
func (mo *MergeOptions) toC() *C.git_merge_options { func populateMergeOptions(copts *C.git_merge_options, opts *MergeOptions) *C.git_merge_options {
if mo == nil { C.git_merge_options_init(copts, C.GIT_MERGE_OPTIONS_VERSION)
if opts == nil {
return nil return nil
} }
return &C.git_merge_options{ copts.flags = C.uint32_t(opts.TreeFlags)
version: C.uint(mo.Version), copts.rename_threshold = C.uint(opts.RenameThreshold)
flags: C.uint32_t(mo.TreeFlags), copts.target_limit = C.uint(opts.TargetLimit)
rename_threshold: C.uint(mo.RenameThreshold), copts.recursion_limit = C.uint(opts.RecursionLimit)
target_limit: C.uint(mo.TargetLimit), copts.file_favor = C.git_merge_file_favor_t(opts.FileFavor)
recursion_limit: C.uint(mo.RecursionLimit), return copts
file_favor: C.git_merge_file_favor_t(mo.FileFavor),
}
} }
func freeMergeOptions(opts *C.git_merge_options) { func freeMergeOptions(copts *C.git_merge_options) {
} }
type MergeFileFavor int type MergeFileFavor int
@ -203,9 +202,9 @@ func (r *Repository) Merge(theirHeads []*AnnotatedCommit, mergeOptions *MergeOpt
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cMergeOpts := mergeOptions.toC() cMergeOpts := populateMergeOptions(&C.git_merge_options{}, mergeOptions)
defer freeMergeOptions(cMergeOpts) defer freeMergeOptions(cMergeOpts)
cCheckoutOptions := checkoutOptions.toC(&err) cCheckoutOptions := populateCheckoutOptions(&C.git_checkout_options{}, checkoutOptions, &err)
defer freeCheckoutOptions(cCheckoutOptions) defer freeCheckoutOptions(cCheckoutOptions)
gmerge_head_array := make([]*C.git_annotated_commit, len(theirHeads)) gmerge_head_array := make([]*C.git_annotated_commit, len(theirHeads))
@ -269,7 +268,7 @@ func (r *Repository) MergeCommits(ours *Commit, theirs *Commit, options *MergeOp
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
copts := options.toC() copts := populateMergeOptions(&C.git_merge_options{}, options)
defer freeMergeOptions(copts) defer freeMergeOptions(copts)
var ptr *C.git_index var ptr *C.git_index
@ -287,7 +286,7 @@ func (r *Repository) MergeTrees(ancestor *Tree, ours *Tree, theirs *Tree, option
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
copts := options.toC() copts := populateMergeOptions(&C.git_merge_options{}, options)
defer freeMergeOptions(copts) defer freeMergeOptions(copts)
var ancestor_ptr *C.git_tree var ancestor_ptr *C.git_tree
@ -446,22 +445,28 @@ func mergeFileOptionsFromC(c C.git_merge_file_options) MergeFileOptions {
} }
} }
func populateCMergeFileOptions(c *C.git_merge_file_options, options MergeFileOptions) { func populateMergeFileOptions(copts *C.git_merge_file_options, opts *MergeFileOptions) *C.git_merge_file_options {
c.ancestor_label = C.CString(options.AncestorLabel) C.git_merge_file_options_init(copts, C.GIT_MERGE_FILE_OPTIONS_VERSION)
c.our_label = C.CString(options.OurLabel) if opts == nil {
c.their_label = C.CString(options.TheirLabel) return nil
c.favor = C.git_merge_file_favor_t(options.Favor) }
c.flags = C.uint32_t(options.Flags)
c.marker_size = C.ushort(options.MarkerSize) copts.ancestor_label = C.CString(opts.AncestorLabel)
copts.our_label = C.CString(opts.OurLabel)
copts.their_label = C.CString(opts.TheirLabel)
copts.favor = C.git_merge_file_favor_t(opts.Favor)
copts.flags = C.uint32_t(opts.Flags)
copts.marker_size = C.ushort(opts.MarkerSize)
return copts
} }
func freeCMergeFileOptions(c *C.git_merge_file_options) { func freeMergeFileOptions(copts *C.git_merge_file_options) {
if c == nil { if copts == nil {
return return
} }
C.free(unsafe.Pointer(c.ancestor_label)) C.free(unsafe.Pointer(copts.ancestor_label))
C.free(unsafe.Pointer(c.our_label)) C.free(unsafe.Pointer(copts.our_label))
C.free(unsafe.Pointer(c.their_label)) C.free(unsafe.Pointer(copts.their_label))
} }
func MergeFile(ancestor MergeFileInput, ours MergeFileInput, theirs MergeFileInput, options *MergeFileOptions) (*MergeFileResult, error) { func MergeFile(ancestor MergeFileInput, ours MergeFileInput, theirs MergeFileInput, options *MergeFileOptions) (*MergeFileResult, error) {
@ -494,8 +499,8 @@ func MergeFile(ancestor MergeFileInput, ours MergeFileInput, theirs MergeFileInp
if ecode < 0 { if ecode < 0 {
return nil, MakeGitError(ecode) return nil, MakeGitError(ecode)
} }
populateCMergeFileOptions(copts, *options) populateMergeFileOptions(copts, options)
defer freeCMergeFileOptions(copts) defer freeMergeFileOptions(copts)
} }
runtime.LockOSThread() runtime.LockOSThread()

15
odb.go
View File

@ -291,18 +291,16 @@ func (v *Odb) NewWriteStream(size int64, otype ObjectType) (*OdbWriteStream, err
// layer does not understand pack files, the objects will be stored in whatever // layer does not understand pack files, the objects will be stored in whatever
// format the ODB layer uses. // format the ODB layer uses.
func (v *Odb) NewWritePack(callback TransferProgressCallback) (*OdbWritepack, error) { func (v *Odb) NewWritePack(callback TransferProgressCallback) (*OdbWritepack, error) {
writepack := new(OdbWritepack)
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
writepack.callbacks.TransferProgressCallback = callback writepack := new(OdbWritepack)
writepack.callbacksHandle = pointerHandles.Track(&writepack.callbacks) populateRemoteCallbacks(&writepack.ccallbacks, &RemoteCallbacks{TransferProgressCallback: callback}, nil)
ret := C._go_git_odb_write_pack(&writepack.ptr, v.ptr, writepack.callbacksHandle) ret := C._go_git_odb_write_pack(&writepack.ptr, v.ptr, writepack.ccallbacks.payload)
runtime.KeepAlive(v) runtime.KeepAlive(v)
if ret < 0 { if ret < 0 {
pointerHandles.Untrack(writepack.callbacksHandle) untrackCallbacksPayload(&writepack.ccallbacks)
return nil, MakeGitError(ret) return nil, MakeGitError(ret)
} }
@ -444,8 +442,7 @@ func (stream *OdbWriteStream) Free() {
type OdbWritepack struct { type OdbWritepack struct {
ptr *C.git_odb_writepack ptr *C.git_odb_writepack
stats C.git_transfer_progress stats C.git_transfer_progress
callbacks RemoteCallbacks ccallbacks C.git_remote_callbacks
callbacksHandle unsafe.Pointer
} }
func (writepack *OdbWritepack) Write(data []byte) (int, error) { func (writepack *OdbWritepack) Write(data []byte) (int, error) {
@ -479,7 +476,7 @@ func (writepack *OdbWritepack) Commit() error {
} }
func (writepack *OdbWritepack) Free() { func (writepack *OdbWritepack) Free() {
pointerHandles.Untrack(writepack.callbacksHandle) untrackCallbacksPayload(&writepack.ccallbacks)
runtime.SetFinalizer(writepack, nil) runtime.SetFinalizer(writepack, nil)
C._go_git_odb_writepack_free(writepack.ptr) C._go_git_odb_writepack_free(writepack.ptr)
} }

View File

@ -78,7 +78,7 @@ func (v *Repository) PatchFromBuffers(oldPath, newPath string, oldBuf, newBuf []
defer C.free(unsafe.Pointer(cNewPath)) defer C.free(unsafe.Pointer(cNewPath))
var err error var err error
copts := opts.toC(v, &err) copts := populateDiffOptions(&C.git_diff_options{}, opts, v, &err)
defer freeDiffOptions(copts) defer freeDiffOptions(copts)
runtime.LockOSThread() runtime.LockOSThread()

View File

@ -72,20 +72,23 @@ func newRebaseOperationFromC(c *C.git_rebase_operation) *RebaseOperation {
} }
//export commitSigningCallback //export commitSigningCallback
func commitSigningCallback(errorMessage **C.char, _signature *C.git_buf, _signature_field *C.git_buf, _commit_content *C.char, _payload unsafe.Pointer) C.int { func commitSigningCallback(errorMessage **C.char, _signature *C.git_buf, _signature_field *C.git_buf, _commit_content *C.char, handle unsafe.Pointer) C.int {
opts, ok := pointerHandles.Get(_payload).(*RebaseOptions) data, ok := pointerHandles.Get(handle).(*rebaseOptionsData)
if !ok { if !ok {
panic("invalid sign payload") panic("invalid sign payload")
} }
if opts.CommitSigningCallback == nil { if data.options.CommitSigningCallback == nil {
return C.int(ErrorCodePassthrough) return C.int(ErrorCodePassthrough)
} }
commitContent := C.GoString(_commit_content) commitContent := C.GoString(_commit_content)
signature, signatureField, err := opts.CommitSigningCallback(commitContent) signature, signatureField, err := data.options.CommitSigningCallback(commitContent)
if err != nil { if err != nil {
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err) return setCallbackError(errorMessage, err)
} }
@ -107,12 +110,18 @@ func commitSigningCallback(errorMessage **C.char, _signature *C.git_buf, _signat
if signatureField != "" { if signatureField != "" {
err := fillBuf(signatureField, _signature_field) err := fillBuf(signatureField, _signature_field)
if err != nil { if err != nil {
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err) return setCallbackError(errorMessage, err)
} }
} }
err = fillBuf(signature, _signature) err = fillBuf(signature, _signature)
if err != nil { if err != nil {
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err) return setCallbackError(errorMessage, err)
} }
@ -130,6 +139,11 @@ type RebaseOptions struct {
CommitSigningCallback CommitSigningCallback CommitSigningCallback CommitSigningCallback
} }
type rebaseOptionsData struct {
options *RebaseOptions
errorTarget *error
}
// DefaultRebaseOptions returns a RebaseOptions with default values. // DefaultRebaseOptions returns a RebaseOptions with default values.
func DefaultRebaseOptions() (RebaseOptions, error) { func DefaultRebaseOptions() (RebaseOptions, error) {
opts := C.git_rebase_options{} opts := C.git_rebase_options{}
@ -155,37 +169,39 @@ func rebaseOptionsFromC(opts *C.git_rebase_options) RebaseOptions {
} }
} }
func (ro *RebaseOptions) toC(errorTarget *error) *C.git_rebase_options { func populateRebaseOptions(copts *C.git_rebase_options, opts *RebaseOptions, errorTarget *error) *C.git_rebase_options {
if ro == nil { C.git_rebase_options_init(copts, C.GIT_REBASE_OPTIONS_VERSION)
if opts == nil {
return nil return nil
} }
cOptions := &C.git_rebase_options{ copts.quiet = C.int(opts.Quiet)
version: C.uint(ro.Version), copts.inmemory = C.int(opts.InMemory)
quiet: C.int(ro.Quiet), copts.rewrite_notes_ref = mapEmptyStringToNull(opts.RewriteNotesRef)
inmemory: C.int(ro.InMemory), populateMergeOptions(&copts.merge_options, &opts.MergeOptions)
rewrite_notes_ref: mapEmptyStringToNull(ro.RewriteNotesRef), populateCheckoutOptions(&copts.checkout_options, &opts.CheckoutOptions, errorTarget)
merge_options: *ro.MergeOptions.toC(),
checkout_options: *ro.CheckoutOptions.toC(errorTarget), if opts.CommitSigningCallback != nil {
data := &rebaseOptionsData{
options: opts,
errorTarget: errorTarget,
}
C._go_git_populate_rebase_callbacks(copts)
copts.payload = pointerHandles.Track(data)
} }
if ro.CommitSigningCallback != nil { return copts
C._go_git_populate_rebase_callbacks(cOptions)
cOptions.payload = pointerHandles.Track(ro)
}
return cOptions
} }
func freeRebaseOptions(opts *C.git_rebase_options) { func freeRebaseOptions(copts *C.git_rebase_options) {
if opts == nil { if copts == nil {
return return
} }
C.free(unsafe.Pointer(opts.rewrite_notes_ref)) C.free(unsafe.Pointer(copts.rewrite_notes_ref))
freeMergeOptions(&opts.merge_options) freeMergeOptions(&copts.merge_options)
freeCheckoutOptions(&opts.checkout_options) freeCheckoutOptions(&copts.checkout_options)
if opts.payload != nil { if copts.payload != nil {
pointerHandles.Untrack(opts.payload) pointerHandles.Untrack(copts.payload)
} }
} }
@ -222,7 +238,7 @@ func (r *Repository) InitRebase(branch *AnnotatedCommit, upstream *AnnotatedComm
var ptr *C.git_rebase var ptr *C.git_rebase
var err error var err error
cOpts := opts.toC(&err) cOpts := populateRebaseOptions(&C.git_rebase_options{}, opts, &err)
ret := C.git_rebase_init(&ptr, r.ptr, branch.ptr, upstream.ptr, onto.ptr, cOpts) ret := C.git_rebase_init(&ptr, r.ptr, branch.ptr, upstream.ptr, onto.ptr, cOpts)
runtime.KeepAlive(branch) runtime.KeepAlive(branch)
runtime.KeepAlive(upstream) runtime.KeepAlive(upstream)
@ -246,7 +262,7 @@ func (r *Repository) OpenRebase(opts *RebaseOptions) (*Rebase, error) {
var ptr *C.git_rebase var ptr *C.git_rebase
var err error var err error
cOpts := opts.toC(&err) cOpts := populateRebaseOptions(&C.git_rebase_options{}, opts, &err)
ret := C.git_rebase_open(&ptr, r.ptr, cOpts) ret := C.git_rebase_open(&ptr, r.ptr, cOpts)
runtime.KeepAlive(r) runtime.KeepAlive(r)
if ret == C.int(ErrorCodeUser) && err != nil { if ret == C.int(ErrorCodeUser) && err != nil {

317
remote.go
View File

@ -7,7 +7,6 @@ package git
#include <git2/sys/cred.h> #include <git2/sys/cred.h>
extern void _go_git_populate_remote_callbacks(git_remote_callbacks *callbacks); extern void _go_git_populate_remote_callbacks(git_remote_callbacks *callbacks);
*/ */
import "C" import "C"
import ( import (
@ -72,6 +71,11 @@ type RemoteCallbacks struct {
PushUpdateReferenceCallback PushUpdateReferenceCallback
} }
type remoteCallbacksData struct {
callbacks *RemoteCallbacks
errorTarget *error
}
type FetchPrune uint type FetchPrune uint
const ( const (
@ -86,7 +90,6 @@ const (
type DownloadTags uint type DownloadTags uint
const ( const (
// Use the setting from the configuration. // Use the setting from the configuration.
DownloadTagsUnspecified DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED DownloadTagsUnspecified DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED
// Ask the server for tags pointing to objects we're already // Ask the server for tags pointing to objects we're already
@ -209,44 +212,58 @@ func newRemoteHeadFromC(ptr *C.git_remote_head) RemoteHead {
} }
} }
func untrackCalbacksPayload(callbacks *C.git_remote_callbacks) { func untrackCallbacksPayload(callbacks *C.git_remote_callbacks) {
if callbacks != nil && callbacks.payload != nil { 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 return
} }
pointerHandles.Untrack(callbacks.payload)
}
func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks, errorTarget *error) *C.git_remote_callbacks {
C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
if callbacks == nil {
return ptr
}
C._go_git_populate_remote_callbacks(ptr) C._go_git_populate_remote_callbacks(ptr)
ptr.payload = pointerHandles.Track(callbacks) data := &remoteCallbacksData{
callbacks: callbacks,
errorTarget: errorTarget,
}
ptr.payload = pointerHandles.Track(data)
return ptr
} }
//export sidebandProgressCallback //export sidebandProgressCallback
func sidebandProgressCallback(errorMessage **C.char, _str *C.char, _len C.int, data unsafe.Pointer) C.int { func sidebandProgressCallback(errorMessage **C.char, _str *C.char, _len C.int, handle unsafe.Pointer) C.int {
callbacks := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
if callbacks.SidebandProgressCallback == nil { if data.callbacks.SidebandProgressCallback == nil {
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
str := C.GoStringN(_str, _len) str := C.GoStringN(_str, _len)
ret := callbacks.SidebandProgressCallback(str) ret := data.callbacks.SidebandProgressCallback(str)
if ret < 0 { if ret < 0 {
return setCallbackError(errorMessage, errors.New(ErrorCode(ret).String())) err := errors.New(ErrorCode(ret).String())
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
//export completionCallback //export completionCallback
func completionCallback(errorMessage **C.char, completion_type C.git_remote_completion_type, data unsafe.Pointer) C.int { func completionCallback(errorMessage **C.char, completion_type C.git_remote_completion_type, handle unsafe.Pointer) C.int {
callbacks := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
if callbacks.CompletionCallback == nil { if data.callbacks.CompletionCallback == nil {
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
ret := callbacks.CompletionCallback(RemoteCompletion(completion_type)) ret := data.callbacks.CompletionCallback(RemoteCompletion(completion_type))
if ret < 0 { if ret < 0 {
return setCallbackError(errorMessage, errors.New(ErrorCode(ret).String())) err := errors.New(ErrorCode(ret).String())
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
@ -258,16 +275,19 @@ func credentialsCallback(
_url *C.char, _url *C.char,
_username_from_url *C.char, _username_from_url *C.char,
allowed_types uint, allowed_types uint,
data unsafe.Pointer, handle unsafe.Pointer,
) C.int { ) C.int {
callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
if callbacks.CredentialsCallback == nil { if data.callbacks.CredentialsCallback == nil {
return C.int(ErrorCodePassthrough) return C.int(ErrorCodePassthrough)
} }
url := C.GoString(_url) url := C.GoString(_url)
username_from_url := C.GoString(_username_from_url) username_from_url := C.GoString(_username_from_url)
cred, err := callbacks.CredentialsCallback(url, username_from_url, (CredentialType)(allowed_types)) cred, err := data.callbacks.CredentialsCallback(url, username_from_url, (CredentialType)(allowed_types))
if err != nil { if err != nil {
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err) return setCallbackError(errorMessage, err)
} }
if cred != nil { if cred != nil {
@ -281,14 +301,18 @@ func credentialsCallback(
} }
//export transferProgressCallback //export transferProgressCallback
func transferProgressCallback(errorMessage **C.char, stats *C.git_transfer_progress, data unsafe.Pointer) C.int { func transferProgressCallback(errorMessage **C.char, stats *C.git_transfer_progress, handle unsafe.Pointer) C.int {
callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
if callbacks.TransferProgressCallback == nil { if data.callbacks.TransferProgressCallback == nil {
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
ret := callbacks.TransferProgressCallback(newTransferProgressFromC(stats)) ret := data.callbacks.TransferProgressCallback(newTransferProgressFromC(stats))
if ret < 0 { if ret < 0 {
return setCallbackError(errorMessage, errors.New(ErrorCode(ret).String())) err := errors.New(ErrorCode(ret).String())
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
@ -299,18 +323,22 @@ func updateTipsCallback(
_refname *C.char, _refname *C.char,
_a *C.git_oid, _a *C.git_oid,
_b *C.git_oid, _b *C.git_oid,
data unsafe.Pointer, handle unsafe.Pointer,
) C.int { ) C.int {
callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
if callbacks.UpdateTipsCallback == nil { if data.callbacks.UpdateTipsCallback == nil {
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
refname := C.GoString(_refname) refname := C.GoString(_refname)
a := newOidFromC(_a) a := newOidFromC(_a)
b := newOidFromC(_b) b := newOidFromC(_b)
ret := callbacks.UpdateTipsCallback(refname, a, b) ret := data.callbacks.UpdateTipsCallback(refname, a, b)
if ret < 0 { if ret < 0 {
return setCallbackError(errorMessage, errors.New(ErrorCode(ret).String())) err := errors.New(ErrorCode(ret).String())
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
@ -321,11 +349,11 @@ func certificateCheckCallback(
_cert *C.git_cert, _cert *C.git_cert,
_valid C.int, _valid C.int,
_host *C.char, _host *C.char,
data unsafe.Pointer, handle unsafe.Pointer,
) C.int { ) C.int {
callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
// if there's no callback set, we need to make sure we fail if the library didn't consider this cert valid // 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 data.callbacks.CertificateCheckCallback == nil {
if _valid == 0 { if _valid == 0 {
return C.int(ErrorCodeCertificate) return C.int(ErrorCodeCertificate)
} }
@ -341,10 +369,17 @@ func certificateCheckCallback(
ccert := (*C.git_cert_x509)(unsafe.Pointer(_cert)) ccert := (*C.git_cert_x509)(unsafe.Pointer(_cert))
x509_certs, err := x509.ParseCertificates(C.GoBytes(ccert.data, C.int(ccert.len))) x509_certs, err := x509.ParseCertificates(C.GoBytes(ccert.data, C.int(ccert.len)))
if err != nil { if err != nil {
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err) return setCallbackError(errorMessage, err)
} }
if len(x509_certs) < 1 { if len(x509_certs) < 1 {
return setCallbackError(errorMessage, errors.New("empty certificate list")) err := errors.New("empty certificate list")
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
// we assume there's only one, which should hold true for any web server we want to talk to // we assume there's only one, which should hold true for any web server we want to talk to
@ -357,74 +392,95 @@ func certificateCheckCallback(
C.memcpy(unsafe.Pointer(&cert.Hostkey.HashSHA1[0]), unsafe.Pointer(&ccert.hash_sha1[0]), C.size_t(len(cert.Hostkey.HashSHA1))) C.memcpy(unsafe.Pointer(&cert.Hostkey.HashSHA1[0]), unsafe.Pointer(&ccert.hash_sha1[0]), C.size_t(len(cert.Hostkey.HashSHA1)))
C.memcpy(unsafe.Pointer(&cert.Hostkey.HashSHA256[0]), unsafe.Pointer(&ccert.hash_sha256[0]), C.size_t(len(cert.Hostkey.HashSHA256))) C.memcpy(unsafe.Pointer(&cert.Hostkey.HashSHA256[0]), unsafe.Pointer(&ccert.hash_sha256[0]), C.size_t(len(cert.Hostkey.HashSHA256)))
} else { } else {
return setCallbackError(errorMessage, errors.New("unsupported certificate type")) err := errors.New("unsupported certificate type")
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
ret := callbacks.CertificateCheckCallback(&cert, valid, host) ret := data.callbacks.CertificateCheckCallback(&cert, valid, host)
if ret < 0 { if ret < 0 {
return setCallbackError(errorMessage, errors.New(ErrorCode(ret).String())) err := errors.New(ErrorCode(ret).String())
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
//export packProgressCallback //export packProgressCallback
func packProgressCallback(errorMessage **C.char, stage C.int, current, total C.uint, data unsafe.Pointer) C.int { func packProgressCallback(errorMessage **C.char, stage C.int, current, total C.uint, handle unsafe.Pointer) C.int {
callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
if callbacks.PackProgressCallback == nil { if data.callbacks.PackProgressCallback == nil {
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
ret := callbacks.PackProgressCallback(int32(stage), uint32(current), uint32(total)) ret := data.callbacks.PackProgressCallback(int32(stage), uint32(current), uint32(total))
if ret < 0 { if ret < 0 {
return setCallbackError(errorMessage, errors.New(ErrorCode(ret).String())) err := errors.New(ErrorCode(ret).String())
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
//export pushTransferProgressCallback //export pushTransferProgressCallback
func pushTransferProgressCallback(errorMessage **C.char, current, total C.uint, bytes C.size_t, data unsafe.Pointer) C.int { func pushTransferProgressCallback(errorMessage **C.char, current, total C.uint, bytes C.size_t, handle unsafe.Pointer) C.int {
callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
if callbacks.PushTransferProgressCallback == nil { if data.callbacks.PushTransferProgressCallback == nil {
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
ret := callbacks.PushTransferProgressCallback(uint32(current), uint32(total), uint(bytes)) ret := data.callbacks.PushTransferProgressCallback(uint32(current), uint32(total), uint(bytes))
if ret < 0 { if ret < 0 {
return setCallbackError(errorMessage, errors.New(ErrorCode(ret).String())) err := errors.New(ErrorCode(ret).String())
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
//export pushUpdateReferenceCallback //export pushUpdateReferenceCallback
func pushUpdateReferenceCallback(errorMessage **C.char, refname, status *C.char, data unsafe.Pointer) C.int { func pushUpdateReferenceCallback(errorMessage **C.char, refname, status *C.char, handle unsafe.Pointer) C.int {
callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) data := pointerHandles.Get(handle).(*remoteCallbacksData)
if callbacks.PushUpdateReferenceCallback == nil { if data.callbacks.PushUpdateReferenceCallback == nil {
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
ret := callbacks.PushUpdateReferenceCallback(C.GoString(refname), C.GoString(status)) ret := data.callbacks.PushUpdateReferenceCallback(C.GoString(refname), C.GoString(status))
if ret < 0 { if ret < 0 {
return setCallbackError(errorMessage, errors.New(ErrorCode(ret).String())) err := errors.New(ErrorCode(ret).String())
if data.errorTarget != nil {
*data.errorTarget = err
}
return setCallbackError(errorMessage, err)
} }
return C.int(ErrorCodeOK) return C.int(ErrorCodeOK)
} }
func populateProxyOptions(ptr *C.git_proxy_options, opts *ProxyOptions) { func populateProxyOptions(copts *C.git_proxy_options, opts *ProxyOptions) *C.git_proxy_options {
C.git_proxy_options_init(ptr, C.GIT_PROXY_OPTIONS_VERSION) C.git_proxy_options_init(copts, C.GIT_PROXY_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return return nil
} }
ptr._type = C.git_proxy_t(opts.Type) copts._type = C.git_proxy_t(opts.Type)
ptr.url = C.CString(opts.Url) copts.url = C.CString(opts.Url)
return copts
} }
func freeProxyOptions(ptr *C.git_proxy_options) { func freeProxyOptions(copts *C.git_proxy_options) {
if ptr == nil { if copts == nil {
return return
} }
C.free(unsafe.Pointer(ptr.url)) C.free(unsafe.Pointer(copts.url))
} }
// RemoteIsValidName returns whether the remote name is well-formed. // RemoteIsValidName returns whether the remote name is well-formed.
@ -738,35 +794,54 @@ func (o *Remote) RefspecCount() uint {
return uint(count) return uint(count)
} }
func populateFetchOptions(options *C.git_fetch_options, opts *FetchOptions) { func populateFetchOptions(copts *C.git_fetch_options, opts *FetchOptions, errorTarget *error) *C.git_fetch_options {
C.git_fetch_options_init(options, C.GIT_FETCH_OPTIONS_VERSION) C.git_fetch_options_init(copts, C.GIT_FETCH_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return return nil
} }
populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks) populateRemoteCallbacks(&copts.callbacks, &opts.RemoteCallbacks, errorTarget)
options.prune = C.git_fetch_prune_t(opts.Prune) copts.prune = C.git_fetch_prune_t(opts.Prune)
options.update_fetchhead = cbool(opts.UpdateFetchhead) copts.update_fetchhead = cbool(opts.UpdateFetchhead)
options.download_tags = C.git_remote_autotag_option_t(opts.DownloadTags) copts.download_tags = C.git_remote_autotag_option_t(opts.DownloadTags)
options.custom_headers = C.git_strarray{} copts.custom_headers = C.git_strarray{
options.custom_headers.count = C.size_t(len(opts.Headers)) count: C.size_t(len(opts.Headers)),
options.custom_headers.strings = makeCStringsFromStrings(opts.Headers) strings: makeCStringsFromStrings(opts.Headers),
populateProxyOptions(&options.proxy_opts, &opts.ProxyOptions) }
populateProxyOptions(&copts.proxy_opts, &opts.ProxyOptions)
return copts
} }
func populatePushOptions(options *C.git_push_options, opts *PushOptions) { func freeFetchOptions(copts *C.git_fetch_options) {
C.git_push_options_init(options, C.GIT_PUSH_OPTIONS_VERSION) if copts == nil {
if opts == nil {
return return
} }
freeStrarray(&copts.custom_headers)
untrackCallbacksPayload(&copts.callbacks)
freeProxyOptions(&copts.proxy_opts)
}
options.pb_parallelism = C.uint(opts.PbParallelism) func populatePushOptions(copts *C.git_push_options, opts *PushOptions, errorTarget *error) *C.git_push_options {
C.git_push_options_init(copts, C.GIT_PUSH_OPTIONS_VERSION)
if opts == nil {
return nil
}
options.custom_headers = C.git_strarray{} copts.pb_parallelism = C.uint(opts.PbParallelism)
options.custom_headers.count = C.size_t(len(opts.Headers)) copts.custom_headers = C.git_strarray{
options.custom_headers.strings = makeCStringsFromStrings(opts.Headers) count: C.size_t(len(opts.Headers)),
strings: makeCStringsFromStrings(opts.Headers),
}
populateRemoteCallbacks(&copts.callbacks, &opts.RemoteCallbacks, errorTarget)
return copts
}
populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks) func freePushOptions(copts *C.git_push_options) {
if copts == nil {
return
}
untrackCallbacksPayload(&copts.callbacks)
freeStrarray(&copts.custom_headers)
} }
// Fetch performs a fetch operation. refspecs specifies which refspecs // Fetch performs a fetch operation. refspecs specifies which refspecs
@ -780,26 +855,29 @@ func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error
defer C.free(unsafe.Pointer(cmsg)) defer C.free(unsafe.Pointer(cmsg))
} }
crefspecs := C.git_strarray{} var err error
crefspecs.count = C.size_t(len(refspecs)) crefspecs := C.git_strarray{
crefspecs.strings = makeCStringsFromStrings(refspecs) count: C.size_t(len(refspecs)),
strings: makeCStringsFromStrings(refspecs),
}
defer freeStrarray(&crefspecs) defer freeStrarray(&crefspecs)
coptions := (*C.git_fetch_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_fetch_options{})))) coptions := populateFetchOptions(&C.git_fetch_options{}, opts, &err)
defer C.free(unsafe.Pointer(coptions)) defer freeFetchOptions(coptions)
populateFetchOptions(coptions, opts)
defer untrackCalbacksPayload(&coptions.callbacks)
defer freeStrarray(&coptions.custom_headers)
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
ret := C.git_remote_fetch(o.ptr, &crefspecs, coptions, cmsg) ret := C.git_remote_fetch(o.ptr, &crefspecs, coptions, cmsg)
runtime.KeepAlive(o) runtime.KeepAlive(o)
if ret == C.int(ErrorCodeUser) && err != nil {
return err
}
if ret < 0 { if ret < 0 {
return MakeGitError(ret) return MakeGitError(ret)
} }
return nil return nil
} }
@ -819,23 +897,27 @@ func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, proxyOpts *ProxyOptions
// //
// 'headers' are extra HTTP headers to use in this connection. // 'headers' are extra HTTP headers to use in this connection.
func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error { func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks, proxyOpts *ProxyOptions, headers []string) error {
var ccallbacks C.git_remote_callbacks var err error
populateRemoteCallbacks(&ccallbacks, callbacks) ccallbacks := populateRemoteCallbacks(&C.git_remote_callbacks{}, callbacks, &err)
defer untrackCallbacksPayload(ccallbacks)
var cproxy C.git_proxy_options cproxy := populateProxyOptions(&C.git_proxy_options{}, proxyOpts)
populateProxyOptions(&cproxy, proxyOpts) defer freeProxyOptions(cproxy)
defer freeProxyOptions(&cproxy)
cheaders := C.git_strarray{} cheaders := C.git_strarray{
cheaders.count = C.size_t(len(headers)) count: C.size_t(len(headers)),
cheaders.strings = makeCStringsFromStrings(headers) strings: makeCStringsFromStrings(headers),
}
defer freeStrarray(&cheaders) defer freeStrarray(&cheaders)
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders) ret := C.git_remote_connect(o.ptr, C.git_direction(direction), ccallbacks, cproxy, &cheaders)
runtime.KeepAlive(o) runtime.KeepAlive(o)
if ret == C.int(ErrorCodeUser) && err != nil {
return err
}
if ret != 0 { if ret != 0 {
return MakeGitError(ret) return MakeGitError(ret)
} }
@ -899,23 +981,24 @@ func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
} }
func (o *Remote) Push(refspecs []string, opts *PushOptions) error { func (o *Remote) Push(refspecs []string, opts *PushOptions) error {
crefspecs := C.git_strarray{} crefspecs := C.git_strarray{
crefspecs.count = C.size_t(len(refspecs)) count: C.size_t(len(refspecs)),
crefspecs.strings = makeCStringsFromStrings(refspecs) strings: makeCStringsFromStrings(refspecs),
}
defer freeStrarray(&crefspecs) defer freeStrarray(&crefspecs)
coptions := (*C.git_push_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_push_options{})))) var err error
defer C.free(unsafe.Pointer(coptions)) coptions := populatePushOptions(&C.git_push_options{}, opts, &err)
defer freePushOptions(coptions)
populatePushOptions(coptions, opts)
defer untrackCalbacksPayload(&coptions.callbacks)
defer freeStrarray(&coptions.custom_headers)
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
ret := C.git_remote_push(o.ptr, &crefspecs, coptions) ret := C.git_remote_push(o.ptr, &crefspecs, coptions)
runtime.KeepAlive(o) runtime.KeepAlive(o)
if ret == C.int(ErrorCodeUser) && err != nil {
return err
}
if ret < 0 { if ret < 0 {
return MakeGitError(ret) return MakeGitError(ret)
} }
@ -927,14 +1010,18 @@ func (o *Remote) PruneRefs() bool {
} }
func (o *Remote) Prune(callbacks *RemoteCallbacks) error { func (o *Remote) Prune(callbacks *RemoteCallbacks) error {
var ccallbacks C.git_remote_callbacks var err error
populateRemoteCallbacks(&ccallbacks, callbacks) ccallbacks := populateRemoteCallbacks(&C.git_remote_callbacks{}, callbacks, &err)
defer untrackCallbacksPayload(ccallbacks)
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
ret := C.git_remote_prune(o.ptr, &ccallbacks) ret := C.git_remote_prune(o.ptr, ccallbacks)
runtime.KeepAlive(o) runtime.KeepAlive(o)
if ret == C.int(ErrorCodeUser) && err != nil {
return err
}
if ret < 0 { if ret < 0 {
return MakeGitError(ret) return MakeGitError(ret)
} }

View File

@ -19,7 +19,7 @@ func (r *Repository) ResetToCommit(commit *Commit, resetType ResetType, opts *Ch
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cOpts := opts.toC(&err) cOpts := populateCheckoutOptions(&C.git_checkout_options{}, opts, &err)
defer freeCheckoutOptions(cOpts) defer freeCheckoutOptions(cOpts)
ret := C.git_reset(r.ptr, commit.ptr, C.git_reset_t(resetType), cOpts) ret := C.git_reset(r.ptr, commit.ptr, C.git_reset_t(resetType), cOpts)

View File

@ -15,48 +15,47 @@ type RevertOptions struct {
CheckoutOpts CheckoutOptions CheckoutOpts CheckoutOptions
} }
func (opts *RevertOptions) toC(errorTarget *error) *C.git_revert_options { func populateRevertOptions(copts *C.git_revert_options, opts *RevertOptions, errorTarget *error) *C.git_revert_options {
C.git_revert_options_init(copts, C.GIT_REVERT_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return nil return nil
} }
return &C.git_revert_options{ copts.mainline = C.uint(opts.Mainline)
version: C.GIT_REVERT_OPTIONS_VERSION, populateMergeOptions(&copts.merge_opts, &opts.MergeOpts)
mainline: C.uint(opts.Mainline), populateCheckoutOptions(&copts.checkout_opts, &opts.CheckoutOpts, errorTarget)
merge_opts: *opts.MergeOpts.toC(), return copts
checkout_opts: *opts.CheckoutOpts.toC(errorTarget),
}
} }
func revertOptionsFromC(opts *C.git_revert_options) RevertOptions { func revertOptionsFromC(copts *C.git_revert_options) RevertOptions {
return RevertOptions{ return RevertOptions{
Mainline: uint(opts.mainline), Mainline: uint(copts.mainline),
MergeOpts: mergeOptionsFromC(&opts.merge_opts), MergeOpts: mergeOptionsFromC(&copts.merge_opts),
CheckoutOpts: checkoutOptionsFromC(&opts.checkout_opts), CheckoutOpts: checkoutOptionsFromC(&copts.checkout_opts),
} }
} }
func freeRevertOptions(opts *C.git_revert_options) { func freeRevertOptions(copts *C.git_revert_options) {
if opts != nil { if copts != nil {
return return
} }
freeMergeOptions(&opts.merge_opts) freeMergeOptions(&copts.merge_opts)
freeCheckoutOptions(&opts.checkout_opts) freeCheckoutOptions(&copts.checkout_opts)
} }
// DefaultRevertOptions initialises a RevertOptions struct with default values // DefaultRevertOptions initialises a RevertOptions struct with default values
func DefaultRevertOptions() (RevertOptions, error) { func DefaultRevertOptions() (RevertOptions, error) {
opts := C.git_revert_options{} copts := C.git_revert_options{}
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
ecode := C.git_revert_options_init(&opts, C.GIT_REVERT_OPTIONS_VERSION) ecode := C.git_revert_options_init(&copts, C.GIT_REVERT_OPTIONS_VERSION)
if ecode < 0 { if ecode < 0 {
return RevertOptions{}, MakeGitError(ecode) return RevertOptions{}, MakeGitError(ecode)
} }
defer freeRevertOptions(&opts) defer freeRevertOptions(&copts)
return revertOptionsFromC(&opts), nil return revertOptionsFromC(&copts), nil
} }
// Revert the provided commit leaving the index updated with the results of the revert // Revert the provided commit leaving the index updated with the results of the revert
@ -65,7 +64,7 @@ func (r *Repository) Revert(commit *Commit, revertOptions *RevertOptions) error
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var err error var err error
cOpts := revertOptions.toC(&err) cOpts := populateRevertOptions(&C.git_revert_options{}, revertOptions, &err)
defer freeRevertOptions(cOpts) defer freeRevertOptions(cOpts)
ret := C.git_revert(r.ptr, commit.cast_ptr, cOpts) ret := C.git_revert(r.ptr, commit.cast_ptr, cOpts)
@ -88,7 +87,7 @@ func (r *Repository) RevertCommit(revertCommit *Commit, ourCommit *Commit, mainl
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
cOpts := mergeOptions.toC() cOpts := populateMergeOptions(&C.git_merge_options{}, mergeOptions)
defer freeMergeOptions(cOpts) defer freeMergeOptions(cOpts)
var index *C.git_index var index *C.git_index

View File

@ -161,34 +161,32 @@ func DefaultStashApplyOptions() (StashApplyOptions, error) {
}, nil }, nil
} }
func (opts *StashApplyOptions) toC(errorTarget *error) *C.git_stash_apply_options { func populateStashApplyOptions(copts *C.git_stash_apply_options, opts *StashApplyOptions, errorTarget *error) *C.git_stash_apply_options {
C.git_stash_apply_options_init(copts, C.GIT_STASH_APPLY_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return nil return nil
} }
optsC := &C.git_stash_apply_options{ copts.flags = C.uint32_t(opts.Flags)
version: C.GIT_STASH_APPLY_OPTIONS_VERSION, populateCheckoutOptions(&copts.checkout_options, &opts.CheckoutOptions, errorTarget)
flags: C.uint32_t(opts.Flags),
}
populateCheckoutOptions(&optsC.checkout_options, &opts.CheckoutOptions, errorTarget)
if opts.ProgressCallback != nil { if opts.ProgressCallback != nil {
progressData := &stashApplyProgressCallbackData{ progressData := &stashApplyProgressCallbackData{
callback: opts.ProgressCallback, callback: opts.ProgressCallback,
errorTarget: errorTarget, errorTarget: errorTarget,
} }
C._go_git_populate_stash_apply_callbacks(optsC) C._go_git_populate_stash_apply_callbacks(copts)
optsC.progress_payload = pointerHandles.Track(progressData) copts.progress_payload = pointerHandles.Track(progressData)
} }
return optsC return copts
} }
func freeStashApplyOptions(optsC *C.git_stash_apply_options) { func freeStashApplyOptions(copts *C.git_stash_apply_options) {
if optsC == nil { if copts == nil {
return return
} }
if optsC.progress_payload != nil { if copts.progress_payload != nil {
pointerHandles.Untrack(optsC.progress_payload) pointerHandles.Untrack(copts.progress_payload)
} }
freeCheckoutOptions(&optsC.checkout_options) freeCheckoutOptions(&copts.checkout_options)
} }
// Apply applies a single stashed state from the stash list. // Apply applies a single stashed state from the stash list.
@ -217,7 +215,7 @@ func freeStashApplyOptions(optsC *C.git_stash_apply_options) {
// Error codes can be interogated with IsErrorCode(err, ErrorCodeNotFound). // Error codes can be interogated with IsErrorCode(err, ErrorCodeNotFound).
func (c *StashCollection) Apply(index int, opts StashApplyOptions) error { func (c *StashCollection) Apply(index int, opts StashApplyOptions) error {
var err error var err error
optsC := opts.toC(&err) optsC := populateStashApplyOptions(&C.git_stash_apply_options{}, &opts, &err)
defer freeStashApplyOptions(optsC) defer freeStashApplyOptions(optsC)
runtime.LockOSThread() runtime.LockOSThread()
@ -320,7 +318,7 @@ func (c *StashCollection) Drop(index int) error {
// state for the given index. // state for the given index.
func (c *StashCollection) Pop(index int, opts StashApplyOptions) error { func (c *StashCollection) Pop(index int, opts StashApplyOptions) error {
var err error var err error
optsC := opts.toC(&err) optsC := populateStashApplyOptions(&C.git_stash_apply_options{}, &opts, &err)
defer freeStashApplyOptions(optsC) defer freeStashApplyOptions(optsC)
runtime.LockOSThread() runtime.LockOSThread()

View File

@ -383,22 +383,22 @@ func (sub *Submodule) Update(init bool, opts *SubmoduleUpdateOptions) error {
return nil return nil
} }
func populateSubmoduleUpdateOptions(ptr *C.git_submodule_update_options, opts *SubmoduleUpdateOptions, errorTarget *error) *C.git_submodule_update_options { func populateSubmoduleUpdateOptions(copts *C.git_submodule_update_options, opts *SubmoduleUpdateOptions, errorTarget *error) *C.git_submodule_update_options {
C.git_submodule_update_options_init(ptr, C.GIT_SUBMODULE_UPDATE_OPTIONS_VERSION) C.git_submodule_update_options_init(copts, C.GIT_SUBMODULE_UPDATE_OPTIONS_VERSION)
if opts == nil { if opts == nil {
return nil return nil
} }
populateCheckoutOptions(&ptr.checkout_opts, opts.CheckoutOpts, errorTarget) populateCheckoutOptions(&copts.checkout_opts, opts.CheckoutOpts, errorTarget)
populateFetchOptions(&ptr.fetch_opts, opts.FetchOptions) populateFetchOptions(&copts.fetch_opts, opts.FetchOptions, errorTarget)
return ptr return copts
} }
func freeSubmoduleUpdateOptions(ptr *C.git_submodule_update_options) { func freeSubmoduleUpdateOptions(copts *C.git_submodule_update_options) {
if ptr == nil { if copts == nil {
return return
} }
freeCheckoutOptions(&ptr.checkout_opts) freeCheckoutOptions(&copts.checkout_opts)
freeFetchOptions(&copts.fetch_opts)
} }

View File

@ -14,7 +14,7 @@
// //
// // myfile.go // // myfile.go
// type FooCallback func(...) (..., error) // type FooCallback func(...) (..., error)
// type FooCallbackData struct { // type fooCallbackData struct {
// callback FooCallback // callback FooCallback
// errorTarget *error // errorTarget *error
// } // }
@ -60,20 +60,28 @@
// return git_my_function(..., (git_foo_cb)&fooCallback, payload); // return git_my_function(..., (git_foo_cb)&fooCallback, payload);
// } // }
// //
// * Otherwise, if the same callback can be invoked from multiple functions or // * Additionally, if the same callback can be invoked from multiple functions or
// from different stacks (e.g. when passing the callback to an object), a // from different stacks (e.g. when passing the callback to an object), the
// different pattern should be used instead, which has the downside of losing // following pattern should be used in tandem, which has the downside of
// the original error object and converting it to a GitError: // losing the original error object and converting it to a GitError if the
// callback happens from a different stack:
// //
// // myfile.go // // myfile.go
// type FooCallback func(...) (..., error) // type FooCallback func(...) (..., error)
// type fooCallbackData struct {
// callback FooCallback
// errorTarget *error
// }
// //
// //export fooCallback // //export fooCallback
// func fooCallback(errorMessage **C.char, ..., handle unsafe.Pointer) C.int { // func fooCallback(errorMessage **C.char, ..., handle unsafe.Pointer) C.int {
// callback := pointerHandles.Get(data).(*FooCallback) // data := pointerHandles.Get(data).(*fooCallbackData)
// ... // ...
// err := callback(...) // err := data.callback(...)
// if err != nil { // if err != nil {
// if data.errorTarget != nil {
// *data.errorTarget = err
// }
// return setCallbackError(errorMessage, err) // return setCallbackError(errorMessage, err)
// } // }
// return C.int(ErrorCodeOK) // return C.int(ErrorCodeOK)