Skip to content

Move remote callbacks to an interface/object #568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/remotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ The Remote type
.. autoclass:: pygit2.Remote
:members:

The RemoteCallbacks type
========================

.. autoclass:: pygit2.RemoteCallbacks
:members:

The TransferProgress type
===========================

Expand Down
60 changes: 11 additions & 49 deletions pygit2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
from .blame import Blame, BlameHunk
from .config import Config
from .credentials import *
from .errors import check_error
from .errors import check_error, Passthrough
from .ffi import ffi, C
from .index import Index, IndexEntry
from .remote import Remote, get_credentials
from .remote import Remote, RemoteCallbacks, get_credentials
from .repository import Repository
from .settings import Settings
from .submodule import Submodule
Expand Down Expand Up @@ -143,22 +143,6 @@ def init_repository(path, bare=False,
# Ok
return Repository(to_str(path))


@ffi.callback('int (*credentials)(git_cred **cred, const char *url,'
'const char *username_from_url, unsigned int allowed_types,'
'void *data)')
def _credentials_cb(cred_out, url, username_from_url, allowed, data):
d = ffi.from_handle(data)

try:
ccred = get_credentials(d['credentials_cb'], url, username_from_url, allowed)
cred_out[0] = ccred[0]
except Exception as e:
d['exception'] = e
return C.GIT_EUSER

return 0

@ffi.callback('int (*git_repository_create_cb)(git_repository **out,'
'const char *path, int bare, void *payload)')
def _repository_create_cb(repo_out, path, bare, data):
Expand Down Expand Up @@ -189,24 +173,9 @@ def _remote_create_cb(remote_out, repo, name, url, data):

return 0

@ffi.callback('int (*git_transport_certificate_check_cb)'
'(git_cert *cert, int valid, const char *host, void *payload)')
def _certificate_cb(cert_i, valid, host, data):
d = ffi.from_handle(data)
try:
# python's parting is deep in the libraries and assumes an OpenSSL-owned cert
val = d['certificate_cb'](None, bool(valid), ffi.string(host))
if not val:
return C.GIT_ECERTIFICATE
except Exception as e:
d['exception'] = e
return C.GIT_EUSER

return 0

def clone_repository(
url, path, bare=False, repository=None, remote=None,
checkout_branch=None, credentials=None, certificate=None):
checkout_branch=None, callbacks=None):
"""Clones a new Git repository from *url* in the given *path*.

Returns a Repository class pointing to the newly cloned repository.
Expand All @@ -224,11 +193,8 @@ def clone_repository(
:param str checkout_branch: Branch to checkout after the
clone. The default is to use the remote's default branch.

:param callable credentials: authentication to use if the remote
requires it

:param callable certificate: callback to verify the host's
certificate or fingerprint.
:param RemoteCallbacks callbacks: object which implements the
callbacks as methods.

:rtype: Repository

Expand All @@ -240,8 +206,8 @@ def clone_repository(
signature. The Remote it returns will be used instead of the default
one.

The certificate callback has `(cert, valid, hostname) -> bool` as
a signature. Return True to accept the connection, False to abort.
The callbacks should be an object which inherits from
`pyclass:RemoteCallbacks`.

"""

Expand All @@ -252,10 +218,8 @@ def clone_repository(

# Data, let's use a dict as we don't really want much more
d = {}
d['credentials_cb'] = credentials
d['repository_cb'] = repository
d['remote_cb'] = remote
d['certificate_cb'] = certificate
d_handle = ffi.new_handle(d)

# Perform the initialization with the version we compiled
Expand All @@ -277,13 +241,11 @@ def clone_repository(


opts.bare = bare
if credentials:
opts.fetch_opts.callbacks.credentials = _credentials_cb
opts.fetch_opts.callbacks.payload = d_handle

if certificate:
opts.fetch_opts.callbacks.certificate_check = _certificate_cb
opts.fetch_opts.callbacks.payload = d_handle
if callbacks is None:
callbacks = RemoteCallbacks()

callbacks._fill_fetch_options(opts.fetch_opts)

err = C.git_clone(crepo, to_bytes(url), to_bytes(path), opts)

Expand Down
3 changes: 3 additions & 0 deletions pygit2/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ def check_error(err, io=False):

# Generic Git error
raise GitError(message)

# Indicate that we want libgit2 to pretend a function was not set
Passthrough = Exception("The function asked for pass-through")
Loading