Skip to content

Commit 97019db

Browse files
committed
Internal: Refactoring callbacks code (cont.)
Use decorator to wrap callbacks, to write once input and error handling.
1 parent 68fd019 commit 97019db

File tree

1 file changed

+48
-61
lines changed

1 file changed

+48
-61
lines changed

pygit2/callbacks.py

+48-61
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
# Standard Library
3232
from contextlib import contextmanager
33+
from functools import wraps
3334

3435
# pygit2
3536
from ._pygit2 import Oid
@@ -134,18 +135,38 @@ def git_remote_callbacks(callbacks):
134135
# and keep the exception, to be re-raised later.
135136
#
136137

138+
def callback_proxy(f):
139+
@wraps(f)
140+
def wrapper(*args):
141+
data = ffi.from_handle(args[-1])
142+
args = args[:-1] + (data,)
143+
try:
144+
return f(*args)
145+
except Passthrough:
146+
# A user defined callback can raise Passthrough to decline to act;
147+
# then libgit2 will behave as if there was no callback set in the
148+
# first place.
149+
return C.GIT_PASSTHROUGH
150+
except Exception as e:
151+
# Keep the exception to be re-raised later, and inform libgit2 that
152+
# the user defined callback has failed.
153+
data._stored_exception = e
154+
return C.GIT_EUSER
155+
156+
return wrapper
157+
158+
137159
@ffi.def_extern()
160+
@callback_proxy
138161
def _certificate_cb(cert_i, valid, host, data):
139-
self = ffi.from_handle(data)
140-
141162
# We want to simulate what should happen if libgit2 supported pass-through for
142163
# this callback. For SSH, 'valid' is always False, because it doesn't look
143164
# at known_hosts, but we do want to let it through in order to do what libgit2 would
144165
# if the callback were not set.
145166
try:
146167
is_ssh = cert_i.cert_type == C.GIT_CERT_HOSTKEY_LIBSSH2
147168

148-
certificate_check = getattr(self, 'certificate_check', None)
169+
certificate_check = getattr(data, 'certificate_check', None)
149170
if not certificate_check:
150171
raise Passthrough
151172

@@ -160,105 +181,71 @@ def _certificate_cb(cert_i, valid, host, data):
160181
return 0
161182
else:
162183
return C.GIT_ECERTIFICATE
163-
except Exception as e:
164-
self._stored_exception = e
165-
return C.GIT_EUSER
166184

167185
return 0
168186

169187

170188
@ffi.def_extern()
189+
@callback_proxy
171190
def _credentials_cb(cred_out, url, username, allowed, data):
172-
self = ffi.from_handle(data)
173-
174-
credentials = getattr(self, 'credentials', None)
191+
credentials = getattr(data, 'credentials', None)
175192
if not credentials:
176193
return 0
177194

178-
try:
179-
ccred = get_credentials(credentials, url, username, allowed)
180-
cred_out[0] = ccred[0]
181-
except Passthrough:
182-
return C.GIT_PASSTHROUGH
183-
except Exception as e:
184-
self._stored_exception = e
185-
return C.GIT_EUSER
186-
195+
ccred = get_credentials(credentials, url, username, allowed)
196+
cred_out[0] = ccred[0]
187197
return 0
188198

199+
189200
@ffi.def_extern()
201+
@callback_proxy
190202
def _push_update_reference_cb(ref, msg, data):
191-
self = ffi.from_handle(data)
192-
193-
push_update_reference = getattr(self, 'push_update_reference', None)
203+
push_update_reference = getattr(data, 'push_update_reference', None)
194204
if not push_update_reference:
195205
return 0
196206

197-
try:
198-
refname = ffi.string(ref)
199-
message = maybe_string(msg)
200-
push_update_reference(refname, message)
201-
except Exception as e:
202-
self._stored_exception = e
203-
return C.GIT_EUSER
204-
207+
refname = ffi.string(ref)
208+
message = maybe_string(msg)
209+
push_update_reference(refname, message)
205210
return 0
206211

212+
207213
@ffi.def_extern()
214+
@callback_proxy
208215
def _sideband_progress_cb(string, length, data):
209-
self = ffi.from_handle(data)
210-
211-
progress = getattr(self, 'progress', None)
216+
progress = getattr(data, 'progress', None)
212217
if not progress:
213218
return 0
214219

215-
try:
216-
s = ffi.string(string, length).decode('utf-8')
217-
progress(s)
218-
except Exception as e:
219-
self._stored_exception = e
220-
return C.GIT_EUSER
221-
220+
s = ffi.string(string, length).decode('utf-8')
221+
progress(s)
222222
return 0
223223

224224

225225
@ffi.def_extern()
226+
@callback_proxy
226227
def _transfer_progress_cb(stats_ptr, data):
227228
from .remote import TransferProgress
228229

229-
self = ffi.from_handle(data)
230-
231-
transfer_progress = getattr(self, 'transfer_progress', None)
230+
transfer_progress = getattr(data, 'transfer_progress', None)
232231
if not transfer_progress:
233232
return 0
234233

235-
try:
236-
transfer_progress(TransferProgress(stats_ptr))
237-
except Exception as e:
238-
self._stored_exception = e
239-
return C.GIT_EUSER
240-
234+
transfer_progress(TransferProgress(stats_ptr))
241235
return 0
242236

243237

244238
@ffi.def_extern()
239+
@callback_proxy
245240
def _update_tips_cb(refname, a, b, data):
246-
self = ffi.from_handle(data)
247-
248-
update_tips = getattr(self, 'update_tips', None)
241+
update_tips = getattr(data, 'update_tips', None)
249242
if not update_tips:
250243
return 0
251244

252-
try:
253-
s = maybe_string(refname)
254-
a = Oid(raw=bytes(ffi.buffer(a)[:]))
255-
b = Oid(raw=bytes(ffi.buffer(b)[:]))
256-
257-
update_tips(s, a, b)
258-
except Exception as e:
259-
self._stored_exception = e
260-
return C.GIT_EUSER
261-
245+
s = maybe_string(refname)
246+
a = Oid(raw=bytes(ffi.buffer(a)[:]))
247+
b = Oid(raw=bytes(ffi.buffer(b)[:]))
248+
update_tips(s, a, b)
262249
return 0
263250

264251

0 commit comments

Comments
 (0)