|
36 | 36 | #include <git2/sys/alloc.h> |
37 | 37 | #include <git2/sys/odb_backend.h> |
38 | 38 |
|
| 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 | + |
39 | 150 | static int |
40 | 151 | OdbBackend_build_as_iter(const git_oid *oid, void *accum) |
41 | 152 | { |
@@ -77,7 +188,7 @@ OdbBackend_as_iter(OdbBackend *self) |
77 | 188 | } |
78 | 189 |
|
79 | 190 | PyDoc_STRVAR(OdbBackend_read__doc__, |
80 | | - "read(oid) -> (type, data, size)\n" |
| 191 | + "read(oid) -> (type, data)\n" |
81 | 192 | "\n" |
82 | 193 | "Read raw object data from this odb backend.\n"); |
83 | 194 |
|
@@ -115,8 +226,50 @@ OdbBackend_read(OdbBackend *self, PyObject *py_hex) |
115 | 226 | return tuple; |
116 | 227 | } |
117 | 228 |
|
| 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 | + |
118 | 270 | PyMethodDef OdbBackend_methods[] = { |
119 | 271 | METHOD(OdbBackend, read, METH_O), |
| 272 | + METHOD(OdbBackend, read_prefix, METH_O), |
120 | 273 | {NULL} |
121 | 274 | }; |
122 | 275 |
|
@@ -158,7 +311,7 @@ PyTypeObject OdbBackendType = { |
158 | 311 | 0, /* tp_descr_get */ |
159 | 312 | 0, /* tp_descr_set */ |
160 | 313 | 0, /* tp_dictoffset */ |
161 | | - 0, /* tp_init */ |
| 314 | + (initproc)OdbBackend_init, /* tp_init */ |
162 | 315 | 0, /* tp_alloc */ |
163 | 316 | 0, /* tp_new */ |
164 | 317 | }; |
|
0 commit comments