Add credentials support to clone_repository()
This commit is contained in:
@@ -51,7 +51,7 @@ def init_repository(path, bare=False):
|
|||||||
|
|
||||||
def clone_repository(
|
def clone_repository(
|
||||||
url, path, bare=False, ignore_cert_errors=False,
|
url, path, bare=False, ignore_cert_errors=False,
|
||||||
remote_name="origin", checkout_branch=None):
|
remote_name="origin", checkout_branch=None, credentials=None):
|
||||||
"""Clones a new Git repository from *url* in the given *path*.
|
"""Clones a new Git repository from *url* in the given *path*.
|
||||||
|
|
||||||
Returns a Repository class pointing to the newly cloned repository.
|
Returns a Repository class pointing to the newly cloned repository.
|
||||||
@@ -67,10 +67,15 @@ def clone_repository(
|
|||||||
:param str checkout_branch: Branch to checkout after the
|
:param str checkout_branch: Branch to checkout after the
|
||||||
clone. The default is to use the remote's default branch.
|
clone. The default is to use the remote's default branch.
|
||||||
|
|
||||||
|
:param callable credentials: authentication to use if the remote
|
||||||
|
requires it
|
||||||
|
|
||||||
|
:rtype: Repository
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_pygit2.clone_repository(
|
_pygit2.clone_repository(
|
||||||
url, path, bare, ignore_cert_errors, remote_name, checkout_branch)
|
url, path, bare, ignore_cert_errors, remote_name, checkout_branch, credentials)
|
||||||
return Repository(path)
|
return Repository(path)
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
16
src/pygit2.c
16
src/pygit2.c
@@ -118,6 +118,14 @@ init_repository(PyObject *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
credentials_cb(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, void *data)
|
||||||
|
{
|
||||||
|
PyObject *credentials = (PyObject *) data;
|
||||||
|
|
||||||
|
return callable_to_credentials(out, url, username_from_url, allowed_types, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(clone_repository__doc__,
|
PyDoc_STRVAR(clone_repository__doc__,
|
||||||
"clone_repository(url, path, bare, remote_name, checkout_branch)\n"
|
"clone_repository(url, path, bare, remote_name, checkout_branch)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -146,11 +154,12 @@ clone_repository(PyObject *self, PyObject *args) {
|
|||||||
const char *path;
|
const char *path;
|
||||||
unsigned int bare, ignore_cert_errors;
|
unsigned int bare, ignore_cert_errors;
|
||||||
const char *remote_name, *checkout_branch;
|
const char *remote_name, *checkout_branch;
|
||||||
|
PyObject *credentials;
|
||||||
int err;
|
int err;
|
||||||
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "zzIIzz",
|
if (!PyArg_ParseTuple(args, "zzIIzzO",
|
||||||
&url, &path, &bare, &ignore_cert_errors, &remote_name, &checkout_branch))
|
&url, &path, &bare, &ignore_cert_errors, &remote_name, &checkout_branch, &credentials))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
opts.bare = bare;
|
opts.bare = bare;
|
||||||
@@ -158,6 +167,9 @@ clone_repository(PyObject *self, PyObject *args) {
|
|||||||
opts.remote_name = remote_name;
|
opts.remote_name = remote_name;
|
||||||
opts.checkout_branch = checkout_branch;
|
opts.checkout_branch = checkout_branch;
|
||||||
|
|
||||||
|
opts.remote_callbacks.credentials = credentials_cb;
|
||||||
|
opts.remote_callbacks.payload = credentials;
|
||||||
|
|
||||||
err = git_clone(&repo, url, path, &opts);
|
err = git_clone(&repo, url, path, &opts);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return Error_set(err);
|
return Error_set(err);
|
||||||
|
66
src/remote.c
66
src/remote.c
@@ -158,76 +158,12 @@ progress_cb(const char *str, int len, void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
py_cred_to_git_cred(git_cred **out, PyObject *py_cred, unsigned int allowed)
|
|
||||||
{
|
|
||||||
Cred *base_cred;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!PyObject_TypeCheck(py_cred, &CredUsernamePasswordType) &&
|
|
||||||
!PyObject_TypeCheck(py_cred, &CredSshKeyType)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "unkown credential type");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
base_cred = (Cred *) py_cred;
|
|
||||||
|
|
||||||
/* Sanity check, make sure we're given credentials we can use */
|
|
||||||
if (!(allowed & base_cred->credtype)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "invalid credential type");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (base_cred->credtype) {
|
|
||||||
case GIT_CREDTYPE_USERPASS_PLAINTEXT:
|
|
||||||
{
|
|
||||||
CredUsernamePassword *cred = (CredUsernamePassword *) base_cred;
|
|
||||||
err = git_cred_userpass_plaintext_new(out, cred->username, cred->password);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GIT_CREDTYPE_SSH_KEY:
|
|
||||||
{
|
|
||||||
CredSshKey *cred = (CredSshKey *) base_cred;
|
|
||||||
err = git_cred_ssh_key_new(out, cred->username, cred->pubkey, cred->privkey, cred->passphrase);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
PyErr_SetString(PyExc_TypeError, "unsupported credential type");
|
|
||||||
err = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
credentials_cb(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, void *data)
|
credentials_cb(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, void *data)
|
||||||
{
|
{
|
||||||
Remote *remote = (Remote *) data;
|
Remote *remote = (Remote *) data;
|
||||||
PyObject *arglist, *py_cred;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (remote->credentials == NULL)
|
return callable_to_credentials(out, url, username_from_url, allowed_types, remote->credentials);
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!PyCallable_Check(remote->credentials)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "credentials callback is not callable");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
arglist = Py_BuildValue("(szI)", url, username_from_url, allowed_types);
|
|
||||||
py_cred = PyObject_CallObject(remote->credentials, arglist);
|
|
||||||
Py_DECREF(arglist);
|
|
||||||
|
|
||||||
if (!py_cred)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
err = py_cred_to_git_cred(out, py_cred, allowed_types);
|
|
||||||
|
|
||||||
|
|
||||||
Py_DECREF(py_cred);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
71
src/utils.c
71
src/utils.c
@@ -31,6 +31,8 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
extern PyTypeObject ReferenceType;
|
extern PyTypeObject ReferenceType;
|
||||||
|
extern PyTypeObject CredUsernamePasswordType;
|
||||||
|
extern PyTypeObject CredSshKeyType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* py_str_to_c_str() returns a newly allocated C string holding the string
|
* py_str_to_c_str() returns a newly allocated C string holding the string
|
||||||
@@ -153,3 +155,72 @@ on_error:
|
|||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
py_cred_to_git_cred(git_cred **out, PyObject *py_cred, unsigned int allowed)
|
||||||
|
{
|
||||||
|
Cred *base_cred;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!PyObject_TypeCheck(py_cred, &CredUsernamePasswordType) &&
|
||||||
|
!PyObject_TypeCheck(py_cred, &CredSshKeyType)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "unkown credential type");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
base_cred = (Cred *) py_cred;
|
||||||
|
|
||||||
|
/* Sanity check, make sure we're given credentials we can use */
|
||||||
|
if (!(allowed & base_cred->credtype)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "invalid credential type");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (base_cred->credtype) {
|
||||||
|
case GIT_CREDTYPE_USERPASS_PLAINTEXT:
|
||||||
|
{
|
||||||
|
CredUsernamePassword *cred = (CredUsernamePassword *) base_cred;
|
||||||
|
err = git_cred_userpass_plaintext_new(out, cred->username, cred->password);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GIT_CREDTYPE_SSH_KEY:
|
||||||
|
{
|
||||||
|
CredSshKey *cred = (CredSshKey *) base_cred;
|
||||||
|
err = git_cred_ssh_key_new(out, cred->username, cred->pubkey, cred->privkey, cred->passphrase);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
PyErr_SetString(PyExc_TypeError, "unsupported credential type");
|
||||||
|
err = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
callable_to_credentials(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, PyObject *credentials)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
PyObject *py_cred, *arglist;
|
||||||
|
|
||||||
|
if (credentials == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!PyCallable_Check(credentials)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "credentials callback is not callable");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arglist = Py_BuildValue("(szI)", url, username_from_url, allowed_types);
|
||||||
|
py_cred = PyObject_CallObject(credentials, arglist);
|
||||||
|
Py_DECREF(arglist);
|
||||||
|
|
||||||
|
if (!py_cred)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
err = py_cred_to_git_cred(out, py_cred, allowed_types);
|
||||||
|
Py_DECREF(py_cred);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@@ -117,6 +117,8 @@ const char *py_str_borrow_c_str(PyObject **tvaue, PyObject *value, const char *e
|
|||||||
PyObject * get_pylist_from_git_strarray(git_strarray *strarray);
|
PyObject * get_pylist_from_git_strarray(git_strarray *strarray);
|
||||||
int get_strarraygit_from_pylist(git_strarray *array, PyObject *pylist);
|
int get_strarraygit_from_pylist(git_strarray *array, PyObject *pylist);
|
||||||
|
|
||||||
|
int callable_to_credentials(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, PyObject *credentials);
|
||||||
|
|
||||||
#define py_path_to_c_str(py_path) \
|
#define py_path_to_c_str(py_path) \
|
||||||
py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding)
|
py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user