Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f4f4cd7

Browse files
committed
OdbBackend: initial pass on Python subclassing
The basic approach here is to have backends created from C (loose, pack) circumvent the OdbBackend_init function. However, backends created from Python will not. We then use this backend to pull out the functions implemented in Python and rig them up through shim functions to the libgit2 git_odb_backend.
1 parent d58f077 commit f4f4cd7

3 files changed

Lines changed: 158 additions & 5 deletions

File tree

src/odb.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ Odb_read_raw(git_odb *odb, const git_oid *oid, size_t len)
158158
int err;
159159

160160
err = git_odb_read_prefix(&obj, odb, oid, (unsigned int)len);
161-
if (err < 0) {
161+
if (err < 0 && err != GIT_EUSER) {
162162
Error_set_oid(err, oid, len);
163163
return NULL;
164164
}
@@ -263,7 +263,7 @@ Odb_add_backend(Odb *self, PyObject *args)
263263
}
264264

265265
err = git_odb_add_backend(self->odb, backend->odb_backend, priority);
266-
if (err > 0)
266+
if (err != 0)
267267
return Error_set(err);
268268

269269
Py_RETURN_NONE;

src/odb_backend.c

Lines changed: 155 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,117 @@
3636
#include <git2/sys/alloc.h>
3737
#include <git2/sys/odb_backend.h>
3838

39+
struct py_odb_backend
40+
{
41+
git_odb_backend backend;
42+
PyObject *self;
43+
PyObject *read_callable,
44+
*read_prefix_callable;
45+
};
46+
47+
static int
48+
py_odb_backend_read(void **ptr, size_t *sz,
49+
git_object_t *type, git_odb_backend *_be, const git_oid *oid)
50+
{
51+
int err;
52+
PyObject *args, *py_oid, *result;
53+
struct py_odb_backend *be = (struct py_odb_backend *)_be;
54+
55+
py_oid = git_oid_to_python(oid);
56+
args = Py_BuildValue("(O)", py_oid);
57+
result = PyObject_CallObject(be->read_callable, args);
58+
Py_DECREF(py_oid);
59+
60+
if ((err = git_error_for_exc()) != 0) {
61+
return err;
62+
}
63+
64+
if (result == NULL)
65+
return GIT_EUSER;
66+
67+
const char *bytes;
68+
if (!PyArg_ParseTuple(result, "iy#", type, &bytes, sz) || !bytes)
69+
return GIT_EUSER;
70+
71+
/* XXX: This assumes the default libgit2 allocator is in use and will
72+
* probably segfault and/or destroy the universe otherwise */
73+
*ptr = malloc(*sz);
74+
if (!*ptr)
75+
return GIT_EUSER;
76+
77+
memcpy(*ptr, bytes, *sz);
78+
return 0;
79+
}
80+
81+
static int
82+
py_odb_backend_read_prefix(git_oid *oid_out, void **ptr, size_t *sz,
83+
git_object_t *type, git_odb_backend *_be,
84+
const git_oid *short_oid, size_t len)
85+
{
86+
int err;
87+
PyObject *args, *py_oid, *py_oid_out, *result;
88+
struct py_odb_backend *be = (struct py_odb_backend *)_be;
89+
90+
py_oid = git_oid_to_python(short_oid);
91+
args = Py_BuildValue("(O)", py_oid);
92+
result = PyObject_CallObject(be->read_prefix_callable, args);
93+
Py_DECREF(py_oid);
94+
95+
if ((err = git_error_for_exc()) != 0) {
96+
return err;
97+
}
98+
99+
if (result == NULL)
100+
return GIT_EUSER;
101+
102+
const char *bytes;
103+
if (!PyArg_ParseTuple(result, "Oiy#",
104+
&py_oid_out, type, &bytes, sz) || !bytes)
105+
return GIT_EUSER;
106+
107+
/* XXX: This assumes the default libgit2 allocator is in use and will
108+
* probably segfault and/or destroy the universe otherwise */
109+
*ptr = malloc(*sz);
110+
if (!*ptr)
111+
return GIT_EUSER;
112+
113+
memcpy(*ptr, bytes, *sz);
114+
py_oid_to_git_oid(py_oid_out, oid_out);
115+
return 0;
116+
}
117+
118+
int
119+
OdbBackend_init(OdbBackend *self, PyObject *args, PyObject *kwds)
120+
{
121+
if (kwds && PyTuple_Size(args) > 0) {
122+
PyErr_SetString(PyExc_TypeError,
123+
"OdbBackend takes no arguments");
124+
return -1;
125+
}
126+
127+
if (kwds && PyDict_Size(kwds) > 0) {
128+
PyErr_SetString(PyExc_TypeError,
129+
"OdbBackend takes no keyword arguments");
130+
return -1;
131+
}
132+
133+
struct py_odb_backend *be = calloc(1, sizeof(struct py_odb_backend));
134+
be->backend.version = GIT_ODB_BACKEND_VERSION;
135+
be->self = (PyObject *)self;
136+
137+
be->read_callable = PyObject_GetAttrString((PyObject *)self, "read");
138+
if (be->read_callable)
139+
be->backend.read = py_odb_backend_read;
140+
141+
be->read_prefix_callable = PyObject_GetAttrString(
142+
(PyObject *)self, "read_prefix");
143+
if (be->read_prefix_callable)
144+
be->backend.read_prefix = py_odb_backend_read_prefix;
145+
146+
self->odb_backend = &be->backend;
147+
return 0;
148+
}
149+
39150
static int
40151
OdbBackend_build_as_iter(const git_oid *oid, void *accum)
41152
{
@@ -77,7 +188,7 @@ OdbBackend_as_iter(OdbBackend *self)
77188
}
78189

79190
PyDoc_STRVAR(OdbBackend_read__doc__,
80-
"read(oid) -> (type, data, size)\n"
191+
"read(oid) -> (type, data)\n"
81192
"\n"
82193
"Read raw object data from this odb backend.\n");
83194

@@ -115,8 +226,50 @@ OdbBackend_read(OdbBackend *self, PyObject *py_hex)
115226
return tuple;
116227
}
117228

229+
PyDoc_STRVAR(OdbBackend_read_prefix__doc__,
230+
"read_prefix(oid) -> (oid, type, data)\n"
231+
"\n"
232+
"Read raw object data from this odb backend based on an oid prefix.\n");
233+
234+
PyObject *
235+
OdbBackend_read_prefix(OdbBackend *self, PyObject *py_hex)
236+
{
237+
int err;
238+
git_oid oid, oid_out;
239+
git_object_t type;
240+
size_t len, sz;
241+
void *data;
242+
PyObject *tuple, *py_oid_out;
243+
244+
if (self->odb_backend->read_prefix == NULL) {
245+
Py_INCREF(Py_NotImplemented);
246+
return Py_NotImplemented;
247+
}
248+
249+
len = py_oid_to_git_oid(py_hex, &oid);
250+
if (len == 0)
251+
return NULL;
252+
253+
err = self->odb_backend->read_prefix(&oid_out,
254+
&data, &sz, &type, self->odb_backend, &oid, len);
255+
if (err != 0) {
256+
Error_set_oid(err, &oid, len);
257+
return NULL;
258+
}
259+
260+
py_oid_out = git_oid_to_python(&oid_out);
261+
tuple = Py_BuildValue("(ny#o)", type, data, sz, py_oid_out);
262+
263+
/* XXX: This assumes the default libgit2 allocator is in use and will
264+
* probably segfault and/or destroy the universe otherwise */
265+
free(data);
266+
267+
return tuple;
268+
}
269+
118270
PyMethodDef OdbBackend_methods[] = {
119271
METHOD(OdbBackend, read, METH_O),
272+
METHOD(OdbBackend, read_prefix, METH_O),
120273
{NULL}
121274
};
122275

@@ -158,7 +311,7 @@ PyTypeObject OdbBackendType = {
158311
0, /* tp_descr_get */
159312
0, /* tp_descr_set */
160313
0, /* tp_dictoffset */
161-
0, /* tp_init */
314+
(initproc)OdbBackend_init, /* tp_init */
162315
0, /* tp_alloc */
163316
0, /* tp_new */
164317
};

src/pygit2.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ moduleinit(PyObject* m)
309309
INIT_TYPE(OdbType, NULL, PyType_GenericNew)
310310
ADD_TYPE(m, Odb)
311311

312-
INIT_TYPE(OdbBackendType, NULL, NULL)
312+
INIT_TYPE(OdbBackendType, NULL, PyType_GenericNew)
313313
ADD_TYPE(m, OdbBackend)
314314
INIT_TYPE(OdbBackendPackType, &OdbBackendType, PyType_GenericNew)
315315
ADD_TYPE(m, OdbBackendPack)

0 commit comments

Comments
 (0)