Add support for custom backends

Signed-off-by: Matthaus Woolard <matthaus.woolard@gmail.com>
This commit is contained in:
Matthaus Woolard 2017-01-20 16:11:51 +00:00
parent 5c061cbb0a
commit 4fbc1f1c05
3 changed files with 72 additions and 27 deletions

View File

@ -40,7 +40,7 @@ else:
import six
# Import from pygit2
from _pygit2 import Repository as _Repository
from _pygit2 import Repository as _Repository, init_file_backend
from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN
from _pygit2 import GIT_CHECKOUT_SAFE, GIT_CHECKOUT_RECREATE_MISSING, GIT_DIFF_NORMAL
from _pygit2 import GIT_FILEMODE_LINK
@ -56,23 +56,12 @@ from .utils import to_bytes, is_string
from .submodule import Submodule
class Repository(_Repository):
class BaseRepository(_Repository):
def __init__(self, path, *args, **kwargs):
if not isinstance(path, six.string_types):
path = path.decode('utf-8')
super(Repository, self).__init__(path, *args, **kwargs)
def __init__(self, backend, *args, **kwargs):
super(BaseRepository, self).__init__(backend, *args, **kwargs)
self._common_init()
@classmethod
def _from_c(cls, ptr, owned):
cptr = ffi.new('git_repository **')
cptr[0] = ptr
repo = cls.__new__(cls)
super(cls, repo)._from_c(bytes(ffi.buffer(cptr)[:]), owned)
repo._common_init()
return repo
def _common_init(self):
self.remotes = RemoteCollection(self)
@ -318,19 +307,19 @@ class Repository(_Repository):
Keyword arguments:
a
None, a str (that refers to an Object, see revparse_single()) or a
None, a str (that refers to an Object, see revparse_single()) or a
Reference object.
If None, b must be None, too. In this case the working directory is
compared with the index. Otherwise the referred object is compared to
'b'.
b
None, a str (that refers to an Object, see revparse_single()) or a
Reference object.
If None, the working directory is compared to 'a'. (except
'cached' is True, in which case the index is compared to 'a').
Otherwise the referred object is compared to 'a'
cached
if 'b' is None, by default the working directory is compared to 'a'.
If 'cached' is set to True, the index/staging area is used for comparing.
@ -915,3 +904,21 @@ class Repository(_Repository):
err = C.git_repository_set_ident(self._repo, to_bytes(name), to_bytes(email))
check_error(err)
class Repository(BaseRepository):
def __init__(self, path, *args, **kwargs):
if not isinstance(path, six.string_types):
path = path.decode('utf-8')
path_backend = init_file_backend(path)
super(Repository, self).__init__(backend=path_backend, *args, **kwargs)
@classmethod
def _from_c(cls, ptr, owned):
cptr = ffi.new('git_repository **')
cptr[0] = ptr
repo = cls.__new__(cls)
super(cls, repo)._from_c(bytes(ffi.buffer(cptr)[:]), owned)
repo._common_init()
return repo

View File

@ -144,7 +144,43 @@ hash(PyObject *self, PyObject *args)
}
PyDoc_STRVAR(init_file_backend__doc__,
"init_file_backend(path) -> object\n"
"\n"
"open repo backend given path.");
PyObject *
init_file_backend(PyObject *self, PyObject *args)
{
const char* path;
int err = GIT_OK;
git_repository *repository = NULL;
if (!PyArg_ParseTuple(args, "s", &path)) {
return NULL;
};
err = git_repository_open(&repository, path);
if (err < 0) {
Error_set_str(err, path);
err = -1;
goto cleanup;
}
return PyCapsule_New(repository, "backend", NULL);
cleanup:
if (repository)
git_repository_free(repository);
PyErr_Format(PyExc_Exception,
"Git error %d during construction of git repo", err);
return NULL;
}
PyMethodDef module_methods[] = {
{"init_file_backend", init_file_backend, METH_VARARGS,
init_file_backend__doc__},
{"discover_repository", discover_repository, METH_VARARGS,
discover_repository__doc__},
{"hashfile", hashfile, METH_VARARGS, hashfile__doc__},

View File

@ -88,7 +88,7 @@ wrap_repository(git_repository *c_repo)
int
Repository_init(Repository *self, PyObject *args, PyObject *kwds)
{
char *path;
PyObject *backend;
int err;
if (kwds && PyDict_Size(kwds) > 0) {
@ -97,15 +97,16 @@ Repository_init(Repository *self, PyObject *args, PyObject *kwds)
return -1;
}
if (!PyArg_ParseTuple(args, "s", &path))
return -1;
err = git_repository_open(&self->repo, path);
if (err < 0) {
Error_set_str(err, path);
return -1;
if (!PyArg_ParseTuple(args, "O", &backend)) {
return -1;
}
self->repo = PyCapsule_GetPointer(backend, "backend");
if (self->repo == NULL) {
PyErr_SetString(PyExc_TypeError,
"Repository unable to unpack backend.");
return -1;
}
self->owned = 1;
self->config = NULL;
self->index = NULL;
@ -1747,7 +1748,7 @@ PyGetSetDef Repository_getseters[] = {
PyDoc_STRVAR(Repository__doc__,
"Repository(path) -> Repository\n"
"Repository(backend) -> Repository\n"
"\n"
"Git repository.");
@ -1793,3 +1794,4 @@ PyTypeObject RepositoryType = {
0, /* tp_alloc */
0, /* tp_new */
};