@@ -3,10 +3,11 @@ package git
33/*
44#include <git2.h>
55
6- extern void _go_git_populate_checkout_cb (git_checkout_options *opts);
6+ extern void _go_git_populate_checkout_callbacks (git_checkout_options *opts);
77*/
88import "C"
99import (
10+ "errors"
1011 "os"
1112 "runtime"
1213 "unsafe"
@@ -75,30 +76,37 @@ func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOptions {
7576 NotifyFlags : CheckoutNotifyType (c .notify_flags ),
7677 }
7778 if c .notify_payload != nil {
78- opts .NotifyCallback = pointerHandles .Get (c .notify_payload ).(* CheckoutOptions ) .NotifyCallback
79+ opts .NotifyCallback = pointerHandles .Get (c .notify_payload ).(* checkoutCallbackData ). options .NotifyCallback
7980 }
8081 if c .progress_payload != nil {
81- opts .ProgressCallback = pointerHandles .Get (c .progress_payload ).(* CheckoutOptions ) .ProgressCallback
82+ opts .ProgressCallback = pointerHandles .Get (c .progress_payload ).(* checkoutCallbackData ). options .ProgressCallback
8283 }
8384 if c .target_directory != nil {
8485 opts .TargetDirectory = C .GoString (c .target_directory )
8586 }
8687 return opts
8788}
8889
89- func (opts * CheckoutOptions ) toC () * C.git_checkout_options {
90+ func (opts * CheckoutOptions ) toC (errorTarget * error ) * C.git_checkout_options {
9091 if opts == nil {
9192 return nil
9293 }
93- c := C.git_checkout_options {}
94- populateCheckoutOptions (& c , opts )
95- return & c
94+ return populateCheckoutOptions (& C.git_checkout_options {}, opts , errorTarget )
95+ }
96+
97+ type checkoutCallbackData struct {
98+ options * CheckoutOptions
99+ errorTarget * error
96100}
97101
98102//export checkoutNotifyCallback
99- func checkoutNotifyCallback (why C.git_checkout_notify_t , cpath * C.char , cbaseline , ctarget , cworkdir , data unsafe.Pointer ) int {
100- if data == nil {
101- return 0
103+ func checkoutNotifyCallback (
104+ why C.git_checkout_notify_t ,
105+ cpath * C.char ,
106+ cbaseline , ctarget , cworkdir , handle unsafe.Pointer ,
107+ ) C.int {
108+ if handle == nil {
109+ return C .int (ErrorCodeOK )
102110 }
103111 path := C .GoString (cpath )
104112 var baseline , target , workdir DiffFile
@@ -111,26 +119,35 @@ func checkoutNotifyCallback(why C.git_checkout_notify_t, cpath *C.char, cbaselin
111119 if cworkdir != nil {
112120 workdir = diffFileFromC ((* C .git_diff_file )(cworkdir ))
113121 }
114- opts := pointerHandles .Get (data ).(* CheckoutOptions )
115- if opts .NotifyCallback == nil {
116- return 0
122+ data := pointerHandles .Get (handle ).(* checkoutCallbackData )
123+ if data .options .NotifyCallback == nil {
124+ return C .int (ErrorCodeOK )
125+ }
126+ ret := data .options .NotifyCallback (CheckoutNotifyType (why ), path , baseline , target , workdir )
127+ if ret < 0 {
128+ * data .errorTarget = errors .New (ErrorCode (ret ).String ())
129+ return C .int (ErrorCodeUser )
117130 }
118- return int (opts . NotifyCallback ( CheckoutNotifyType ( why ), path , baseline , target , workdir ) )
131+ return C . int (ErrorCodeOK )
119132}
120133
121134//export checkoutProgressCallback
122- func checkoutProgressCallback (path * C.char , completed_steps , total_steps C.size_t , data unsafe.Pointer ) int {
123- opts := pointerHandles .Get (data ).(* CheckoutOptions )
124- if opts .ProgressCallback == nil {
125- return 0
135+ func checkoutProgressCallback (
136+ path * C.char ,
137+ completed_steps , total_steps C.size_t ,
138+ handle unsafe.Pointer ,
139+ ) {
140+ data := pointerHandles .Get (handle ).(* checkoutCallbackData )
141+ if data .options .ProgressCallback == nil {
142+ return
126143 }
127- return int ( opts . ProgressCallback (C .GoString (path ), uint (completed_steps ), uint (total_steps ) ))
144+ data . options . ProgressCallback (C .GoString (path ), uint (completed_steps ), uint (total_steps ))
128145}
129146
130147// Convert the CheckoutOptions struct to the corresponding
131148// C-struct. Returns a pointer to ptr, or nil if opts is nil, in order
132149// to help with what to pass.
133- func populateCheckoutOptions (ptr * C.git_checkout_options , opts * CheckoutOptions ) * C.git_checkout_options {
150+ func populateCheckoutOptions (ptr * C.git_checkout_options , opts * CheckoutOptions , errorTarget * error ) * C.git_checkout_options {
134151 if opts == nil {
135152 return nil
136153 }
@@ -142,14 +159,18 @@ func populateCheckoutOptions(ptr *C.git_checkout_options, opts *CheckoutOptions)
142159 ptr .file_mode = C .uint (opts .FileMode .Perm ())
143160 ptr .notify_flags = C .uint (opts .NotifyFlags )
144161 if opts .NotifyCallback != nil || opts .ProgressCallback != nil {
145- C ._go_git_populate_checkout_cb (ptr )
146- }
147- payload := pointerHandles .Track (opts )
148- if opts .NotifyCallback != nil {
149- ptr .notify_payload = payload
150- }
151- if opts .ProgressCallback != nil {
152- ptr .progress_payload = payload
162+ C ._go_git_populate_checkout_callbacks (ptr )
163+ data := & checkoutCallbackData {
164+ options : opts ,
165+ errorTarget : errorTarget ,
166+ }
167+ payload := pointerHandles .Track (data )
168+ if opts .NotifyCallback != nil {
169+ ptr .notify_payload = payload
170+ }
171+ if opts .ProgressCallback != nil {
172+ ptr .progress_payload = payload
173+ }
153174 }
154175 if opts .TargetDirectory != "" {
155176 ptr .target_directory = C .CString (opts .TargetDirectory )
@@ -176,6 +197,8 @@ func freeCheckoutOptions(ptr *C.git_checkout_options) {
176197 }
177198 if ptr .notify_payload != nil {
178199 pointerHandles .Untrack (ptr .notify_payload )
200+ } else if ptr .progress_payload != nil {
201+ pointerHandles .Untrack (ptr .progress_payload )
179202 }
180203}
181204
@@ -185,11 +208,16 @@ func (v *Repository) CheckoutHead(opts *CheckoutOptions) error {
185208 runtime .LockOSThread ()
186209 defer runtime .UnlockOSThread ()
187210
188- cOpts := opts .toC ()
211+ var err error
212+ cOpts := opts .toC (& err )
189213 defer freeCheckoutOptions (cOpts )
190214
191215 ret := C .git_checkout_head (v .ptr , cOpts )
192216 runtime .KeepAlive (v )
217+
218+ if ret == C .int (ErrorCodeUser ) && err != nil {
219+ return err
220+ }
193221 if ret < 0 {
194222 return MakeGitError (ret )
195223 }
@@ -209,11 +237,15 @@ func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOptions) error {
209237 runtime .LockOSThread ()
210238 defer runtime .UnlockOSThread ()
211239
212- cOpts := opts .toC ()
240+ var err error
241+ cOpts := opts .toC (& err )
213242 defer freeCheckoutOptions (cOpts )
214243
215244 ret := C .git_checkout_index (v .ptr , iptr , cOpts )
216245 runtime .KeepAlive (v )
246+ if ret == C .int (ErrorCodeUser ) && err != nil {
247+ return err
248+ }
217249 if ret < 0 {
218250 return MakeGitError (ret )
219251 }
@@ -225,11 +257,16 @@ func (v *Repository) CheckoutTree(tree *Tree, opts *CheckoutOptions) error {
225257 runtime .LockOSThread ()
226258 defer runtime .UnlockOSThread ()
227259
228- cOpts := opts .toC ()
260+ var err error
261+ cOpts := opts .toC (& err )
229262 defer freeCheckoutOptions (cOpts )
230263
231264 ret := C .git_checkout_tree (v .ptr , tree .ptr , cOpts )
232265 runtime .KeepAlive (v )
266+ runtime .KeepAlive (tree )
267+ if ret == C .int (ErrorCodeUser ) && err != nil {
268+ return err
269+ }
233270 if ret < 0 {
234271 return MakeGitError (ret )
235272 }
0 commit comments