Skip to content

Commit 3f5fc86

Browse files
committed
Internal: Refactoring callbacks code (cont.)
Now clone_repository callbacks are implemented the same way.
1 parent 97019db commit 3f5fc86

File tree

2 files changed

+74
-71
lines changed

2 files changed

+74
-71
lines changed

pygit2/__init__.py

+15-60
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131

3232
# High level API
3333
from .blame import Blame, BlameHunk
34-
from .callbacks import git_fetch_options, get_credentials, RemoteCallbacks
34+
from .callbacks import git_clone_options, git_fetch_options, get_credentials
35+
from .callbacks import Payload, RemoteCallbacks
3536
from .config import Config
3637
from .credentials import *
3738
from .errors import check_error, Passthrough
@@ -152,33 +153,6 @@ def init_repository(path, bare=False,
152153
# Ok
153154
return Repository(to_str(path))
154155

155-
@ffi.def_extern()
156-
def _repository_create_cb(repo_out, path, bare, data):
157-
d = ffi.from_handle(data)
158-
try:
159-
repository = d['repository_cb'](ffi.string(path), bare != 0)
160-
# we no longer own the C object
161-
repository._disown()
162-
repo_out[0] = repository._repo
163-
except Exception as e:
164-
d['exception'] = e
165-
return C.GIT_EUSER
166-
167-
return 0
168-
169-
@ffi.def_extern()
170-
def _remote_create_cb(remote_out, repo, name, url, data):
171-
d = ffi.from_handle(data)
172-
try:
173-
remote = d['remote_cb'](Repository._from_c(repo, False), ffi.string(name), ffi.string(url))
174-
remote_out[0] = remote._remote
175-
# we no longer own the C object
176-
remote._remote = ffi.NULL
177-
except Exception as e:
178-
d['exception'] = e
179-
return C.GIT_EUSER
180-
181-
return 0
182156

183157
def clone_repository(
184158
url, path, bare=False, repository=None, remote=None,
@@ -218,41 +192,22 @@ def clone_repository(
218192
`pyclass:RemoteCallbacks`.
219193
"""
220194

221-
opts = ffi.new('git_clone_options *')
222-
crepo = ffi.new('git_repository **')
195+
# Initialize payload
196+
payload = Payload(repository=repository, remote=remote)
223197

224-
branch = checkout_branch or None
198+
with git_clone_options(payload) as (opts, _):
199+
opts.bare = bare
225200

226-
# Data, let's use a dict as we don't really want much more
227-
d = {'repository_cb': repository,
228-
'remote_cb': remote}
229-
d_handle = ffi.new_handle(d)
201+
#checkout_branch_ref = None
202+
if checkout_branch:
203+
checkout_branch_ref = ffi.new('char []', to_bytes(checkout_branch))
204+
opts.checkout_branch = checkout_branch_ref
230205

231-
# Perform the initialization with the version we compiled
232-
C.git_clone_options_init(opts, C.GIT_CLONE_OPTIONS_VERSION)
233-
234-
# We need to keep the ref alive ourselves
235-
checkout_branch_ref = None
236-
if branch:
237-
checkout_branch_ref = ffi.new('char []', to_bytes(branch))
238-
opts.checkout_branch = checkout_branch_ref
239-
240-
if repository:
241-
opts.repository_cb = C._repository_create_cb
242-
opts.repository_cb_payload = d_handle
243-
244-
if remote:
245-
opts.remote_cb = C._remote_create_cb
246-
opts.remote_cb_payload = d_handle
247-
248-
opts.bare = bare
249-
250-
with git_fetch_options(callbacks, opts=opts.fetch_opts) as (_, cb):
251-
err = C.git_clone(crepo, to_bytes(url), to_bytes(path), opts)
252-
exc = d.get('exception')
253-
if exc:
254-
raise exc
255-
check_error(err, cb)
206+
with git_fetch_options(callbacks, opts=opts.fetch_opts) as (_, cb):
207+
crepo = ffi.new('git_repository **')
208+
err = C.git_clone(crepo, to_bytes(url), to_bytes(path), opts)
209+
payload.check_error()
210+
check_error(err, cb)
256211

257212
# Ok
258213
return Repository._from_c(crepo[0], owned=True)

pygit2/callbacks.py

+59-11
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,38 @@
5555
# function, or raises exception from libgit2 error
5656
#
5757

58+
class Payload:
59+
60+
def __init__(self, **kw):
61+
for key, value in kw.items():
62+
setattr(self, key, value)
63+
self._stored_exception = None
64+
65+
def check_error(self):
66+
if self._stored_exception is not None:
67+
raise self._stored_exception
68+
69+
70+
@contextmanager
71+
def git_clone_options(payload, opts=None):
72+
if opts is None:
73+
opts = ffi.new('git_clone_options *')
74+
C.git_clone_options_init(opts, C.GIT_CLONE_OPTIONS_VERSION)
75+
76+
handle = ffi.new_handle(payload)
77+
78+
# Plug callbacks
79+
if payload.repository:
80+
opts.repository_cb = C._repository_create_cb
81+
opts.repository_cb_payload = handle
82+
if payload.remote:
83+
opts.remote_cb = C._remote_create_cb
84+
opts.remote_cb_payload = handle
85+
86+
# Give back control
87+
yield opts, payload
88+
89+
5890
@contextmanager
5991
def git_fetch_options(callbacks, opts=None):
6092
if callbacks is None:
@@ -153,16 +185,15 @@ def wrapper(*args):
153185
data._stored_exception = e
154186
return C.GIT_EUSER
155187

156-
return wrapper
188+
return ffi.def_extern()(wrapper)
157189

158190

159-
@ffi.def_extern()
160191
@callback_proxy
161192
def _certificate_cb(cert_i, valid, host, data):
162-
# We want to simulate what should happen if libgit2 supported pass-through for
163-
# this callback. For SSH, 'valid' is always False, because it doesn't look
164-
# at known_hosts, but we do want to let it through in order to do what libgit2 would
165-
# if the callback were not set.
193+
# We want to simulate what should happen if libgit2 supported pass-through
194+
# for this callback. For SSH, 'valid' is always False, because it doesn't
195+
# look at known_hosts, but we do want to let it through in order to do what
196+
# libgit2 would if the callback were not set.
166197
try:
167198
is_ssh = cert_i.cert_type == C.GIT_CERT_HOSTKEY_LIBSSH2
168199

@@ -185,7 +216,6 @@ def _certificate_cb(cert_i, valid, host, data):
185216
return 0
186217

187218

188-
@ffi.def_extern()
189219
@callback_proxy
190220
def _credentials_cb(cred_out, url, username, allowed, data):
191221
credentials = getattr(data, 'credentials', None)
@@ -197,7 +227,6 @@ def _credentials_cb(cred_out, url, username, allowed, data):
197227
return 0
198228

199229

200-
@ffi.def_extern()
201230
@callback_proxy
202231
def _push_update_reference_cb(ref, msg, data):
203232
push_update_reference = getattr(data, 'push_update_reference', None)
@@ -210,7 +239,28 @@ def _push_update_reference_cb(ref, msg, data):
210239
return 0
211240

212241

213-
@ffi.def_extern()
242+
@callback_proxy
243+
def _remote_create_cb(remote_out, repo, name, url, data):
244+
from .repository import Repository
245+
246+
remote = data.remote(Repository._from_c(repo, False), ffi.string(name), ffi.string(url))
247+
remote_out[0] = remote._remote
248+
# we no longer own the C object
249+
remote._remote = ffi.NULL
250+
251+
return 0
252+
253+
254+
@callback_proxy
255+
def _repository_create_cb(repo_out, path, bare, data):
256+
repository = data.repository(ffi.string(path), bare != 0)
257+
# we no longer own the C object
258+
repository._disown()
259+
repo_out[0] = repository._repo
260+
261+
return 0
262+
263+
214264
@callback_proxy
215265
def _sideband_progress_cb(string, length, data):
216266
progress = getattr(data, 'progress', None)
@@ -222,7 +272,6 @@ def _sideband_progress_cb(string, length, data):
222272
return 0
223273

224274

225-
@ffi.def_extern()
226275
@callback_proxy
227276
def _transfer_progress_cb(stats_ptr, data):
228277
from .remote import TransferProgress
@@ -235,7 +284,6 @@ def _transfer_progress_cb(stats_ptr, data):
235284
return 0
236285

237286

238-
@ffi.def_extern()
239287
@callback_proxy
240288
def _update_tips_cb(refname, a, b, data):
241289
update_tips = getattr(data, 'update_tips', None)

0 commit comments

Comments
 (0)