Skip to content

Commit 24d176c

Browse files
committed
Merge remote-tracking branch 'ddevault/odb'
2 parents 84cd5d5 + 1b6d926 commit 24d176c

File tree

9 files changed

+522
-165
lines changed

9 files changed

+522
-165
lines changed

pygit2/repository.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,25 @@ def _common_init(self):
7676
ffi.buffer(repo_cptr)[:] = self._pointer[:]
7777
self._repo = repo_cptr[0]
7878

79+
# Backwards compatible ODB access
80+
def read(self, *args, **kwargs):
81+
"""read(oid) -> type, data, size
82+
83+
Read raw object data from the repository.
84+
"""
85+
return self.odb.read(*args, **kwargs)
86+
87+
def write(self, *args, **kwargs):
88+
"""write(type, data) -> Oid
89+
90+
Write raw object data into the repository. First arg is the object
91+
type, the second one a buffer with data. Return the Oid of the created
92+
object."""
93+
return self.odb.write(*args, **kwargs)
94+
95+
def __iter__(self):
96+
return iter(self.odb)
97+
7998
def lookup_submodule(self, path):
8099
csub = ffi.new('git_submodule **')
81100
cpath = ffi.new('char[]', to_bytes(path))

src/object.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "error.h"
3232
#include "types.h"
3333
#include "utils.h"
34+
#include "odb.h"
3435
#include "oid.h"
3536
#include "repository.h"
3637
#include "object.h"
@@ -162,13 +163,20 @@ PyDoc_STRVAR(Object_read_raw__doc__,
162163
PyObject *
163164
Object_read_raw(Object *self)
164165
{
166+
int err;
165167
const git_oid *oid;
168+
git_odb *odb;
166169
git_odb_object *obj;
167170
PyObject *aux;
168171

169172
oid = git_object_id(self->obj);
170173

171-
obj = Repository_read_raw(self->repo->repo, oid, GIT_OID_HEXSZ);
174+
err = git_repository_odb(&odb, self->repo->repo);
175+
if (err < 0)
176+
return Error_set(err);
177+
178+
obj = Odb_read_raw(odb, oid, GIT_OID_HEXSZ);
179+
git_odb_free(odb);
172180
if (obj == NULL)
173181
return NULL;
174182

src/odb.c

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
/*
2+
* Copyright 2010-2019 The pygit2 contributors
3+
*
4+
* This file is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License, version 2,
6+
* as published by the Free Software Foundation.
7+
*
8+
* In addition to the permissions in the GNU General Public License,
9+
* the authors give you unlimited permission to link the compiled
10+
* version of this file into combinations with other programs,
11+
* and to distribute those combinations without any restriction
12+
* coming from the use of this file. (The General Public License
13+
* restrictions do apply in other respects; for example, they cover
14+
* modification of the file, and distribution when not linked into
15+
* a combined executable.)
16+
*
17+
* This file is distributed in the hope that it will be useful, but
18+
* WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20+
* General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU General Public License
23+
* along with this program; see the file COPYING. If not, write to
24+
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
25+
* Boston, MA 02110-1301, USA.
26+
*/
27+
28+
#define PY_SSIZE_T_CLEAN
29+
#include <Python.h>
30+
#include "error.h"
31+
#include "object.h"
32+
#include "oid.h"
33+
#include "types.h"
34+
#include "utils.h"
35+
#include <git2/odb.h>
36+
37+
static git_otype
38+
int_to_loose_object_type(int type_id)
39+
{
40+
switch((git_otype)type_id) {
41+
case GIT_OBJ_COMMIT: return GIT_OBJ_COMMIT;
42+
case GIT_OBJ_TREE: return GIT_OBJ_TREE;
43+
case GIT_OBJ_BLOB: return GIT_OBJ_BLOB;
44+
case GIT_OBJ_TAG: return GIT_OBJ_TAG;
45+
default: return GIT_OBJ_BAD;
46+
}
47+
}
48+
49+
int
50+
Odb_init(Odb *self, PyObject *args, PyObject *kwds)
51+
{
52+
PyObject *py_path = NULL;
53+
const char *path;
54+
int err;
55+
56+
if (kwds && PyDict_Size(kwds) > 0) {
57+
PyErr_SetString(PyExc_TypeError,
58+
"Odb takes no keyword arguments");
59+
return -1;
60+
}
61+
62+
if (!PyArg_ParseTuple(args, "|O", &py_path))
63+
return -1;
64+
65+
if (py_path) {
66+
path = py_path_to_c_str(py_path);
67+
if (path == NULL)
68+
return -1;
69+
err = git_odb_open(&self->odb, path);
70+
} else {
71+
err = git_odb_new(&self->odb);
72+
}
73+
74+
if (err < 0) {
75+
Error_set(err);
76+
return -1;
77+
}
78+
79+
return 0;
80+
}
81+
82+
void
83+
Odb_dealloc(Odb *self)
84+
{
85+
git_odb_free(self->odb);
86+
87+
Py_TYPE(self)->tp_free((PyObject *) self);
88+
}
89+
90+
static int
91+
Odb_build_as_iter(const git_oid *oid, void *accum)
92+
{
93+
int err;
94+
PyObject *py_oid = git_oid_to_python(oid);
95+
96+
err = PyList_Append((PyObject*)accum, py_oid);
97+
Py_DECREF(py_oid);
98+
return err;
99+
}
100+
101+
PyObject *
102+
Odb_as_iter(Odb *self)
103+
{
104+
int err;
105+
PyObject *accum = PyList_New(0);
106+
PyObject *ret;
107+
108+
err = git_odb_foreach(self->odb, Odb_build_as_iter, (void*)accum);
109+
if (err == GIT_EUSER)
110+
return NULL;
111+
if (err < 0)
112+
return Error_set(err);
113+
114+
ret = PyObject_GetIter(accum);
115+
Py_DECREF(accum);
116+
117+
return ret;
118+
}
119+
120+
121+
PyDoc_STRVAR(Odb_add_disk_alternate__doc__,
122+
"Adds a path on disk as an alternate backend for objects.\n"
123+
"Alternate backends are checked for objects only *after* the main backends\n"
124+
"are checked. Writing is disabled on alternate backends.\n");
125+
126+
PyObject *
127+
Odb_add_disk_alternate(Odb *self, PyObject *py_path)
128+
{
129+
int err;
130+
const char *path;
131+
132+
path = py_path_to_c_str(py_path);
133+
if (path == NULL)
134+
return NULL;
135+
136+
err = git_odb_add_disk_alternate(self->odb, path);
137+
if (err < 0)
138+
return Error_set(err);
139+
140+
Py_RETURN_NONE;
141+
}
142+
143+
git_odb_object *
144+
Odb_read_raw(git_odb *odb, const git_oid *oid, size_t len)
145+
{
146+
git_odb_object *obj;
147+
int err;
148+
149+
err = git_odb_read_prefix(&obj, odb, oid, (unsigned int)len);
150+
if (err < 0) {
151+
Error_set_oid(err, oid, len);
152+
return NULL;
153+
}
154+
155+
return obj;
156+
}
157+
158+
PyDoc_STRVAR(Odb_read__doc__,
159+
"read(oid) -> type, data, size\n"
160+
"\n"
161+
"Read raw object data from the object db.");
162+
163+
PyObject *
164+
Odb_read(Odb *self, PyObject *py_hex)
165+
{
166+
git_oid oid;
167+
git_odb_object *obj;
168+
size_t len;
169+
PyObject* tuple;
170+
171+
len = py_oid_to_git_oid(py_hex, &oid);
172+
if (len == 0)
173+
return NULL;
174+
175+
obj = Odb_read_raw(self->odb, &oid, len);
176+
if (obj == NULL)
177+
return NULL;
178+
179+
tuple = Py_BuildValue(
180+
#if PY_MAJOR_VERSION == 2
181+
"(ns#)",
182+
#else
183+
"(ny#)",
184+
#endif
185+
git_odb_object_type(obj),
186+
git_odb_object_data(obj),
187+
git_odb_object_size(obj));
188+
189+
git_odb_object_free(obj);
190+
return tuple;
191+
}
192+
193+
PyDoc_STRVAR(Odb_write__doc__,
194+
"write(type, data) -> Oid\n"
195+
"\n"
196+
"Write raw object data into the object db. First arg is the object\n"
197+
"type, the second one a buffer with data. Return the Oid of the created\n"
198+
"object.");
199+
200+
PyObject *
201+
Odb_write(Odb *self, PyObject *args)
202+
{
203+
int err;
204+
git_oid oid;
205+
git_odb_stream* stream;
206+
int type_id;
207+
const char* buffer;
208+
Py_ssize_t buflen;
209+
git_otype type;
210+
211+
if (!PyArg_ParseTuple(args, "Is#", &type_id, &buffer, &buflen))
212+
return NULL;
213+
214+
type = int_to_loose_object_type(type_id);
215+
if (type == GIT_OBJ_BAD)
216+
return PyErr_Format(PyExc_ValueError, "%d", type_id);
217+
218+
err = git_odb_open_wstream(&stream, self->odb, buflen, type);
219+
if (err < 0)
220+
return Error_set(err);
221+
222+
err = git_odb_stream_write(stream, buffer, buflen);
223+
if (err) {
224+
git_odb_stream_free(stream);
225+
return Error_set(err);
226+
}
227+
228+
err = git_odb_stream_finalize_write(&oid, stream);
229+
git_odb_stream_free(stream);
230+
if (err)
231+
return Error_set(err);
232+
233+
return git_oid_to_python(&oid);
234+
}
235+
236+
237+
int
238+
Odb_contains(Odb *self, PyObject *py_name)
239+
{
240+
git_oid oid;
241+
size_t len;
242+
243+
len = py_oid_to_git_oid(py_name, &oid);
244+
if (len == 0) {
245+
PyErr_SetString(PyExc_TypeError, "name must be an oid");
246+
return -1;
247+
}
248+
249+
return git_odb_exists(self->odb, &oid);
250+
}
251+
252+
253+
PyMethodDef Odb_methods[] = {
254+
METHOD(Odb, add_disk_alternate, METH_O),
255+
METHOD(Odb, read, METH_O),
256+
METHOD(Odb, write, METH_VARARGS),
257+
{NULL}
258+
};
259+
260+
PySequenceMethods Odb_as_sequence = {
261+
0, /* sq_length */
262+
0, /* sq_concat */
263+
0, /* sq_repeat */
264+
0, /* sq_item */
265+
0, /* sq_slice */
266+
0, /* sq_ass_item */
267+
0, /* sq_ass_slice */
268+
(objobjproc)Odb_contains, /* sq_contains */
269+
};
270+
271+
PyDoc_STRVAR(Odb__doc__, "Object database.");
272+
273+
PyTypeObject OdbType = {
274+
PyVarObject_HEAD_INIT(NULL, 0)
275+
"_pygit2.Odb", /* tp_name */
276+
sizeof(Odb), /* tp_basicsize */
277+
0, /* tp_itemsize */
278+
(destructor)Odb_dealloc, /* tp_dealloc */
279+
0, /* tp_print */
280+
0, /* tp_getattr */
281+
0, /* tp_setattr */
282+
0, /* tp_compare */
283+
0, /* tp_repr */
284+
0, /* tp_as_number */
285+
&Odb_as_sequence, /* tp_as_sequence */
286+
0, /* tp_as_mapping */
287+
0, /* tp_hash */
288+
0, /* tp_call */
289+
0, /* tp_str */
290+
0, /* tp_getattro */
291+
0, /* tp_setattro */
292+
0, /* tp_as_buffer */
293+
Py_TPFLAGS_DEFAULT, /* tp_flags */
294+
Odb__doc__, /* tp_doc */
295+
0, /* tp_traverse */
296+
0, /* tp_clear */
297+
0, /* tp_richcompare */
298+
0, /* tp_weaklistoffset */
299+
(getiterfunc)Odb_as_iter, /* tp_iter */
300+
0, /* tp_iternext */
301+
Odb_methods, /* tp_methods */
302+
0, /* tp_members */
303+
0, /* tp_getset */
304+
0, /* tp_base */
305+
0, /* tp_dict */
306+
0, /* tp_descr_get */
307+
0, /* tp_descr_set */
308+
0, /* tp_dictoffset */
309+
(initproc)Odb_init, /* tp_init */
310+
0, /* tp_alloc */
311+
0, /* tp_new */
312+
};
313+
314+
PyObject *
315+
wrap_odb(git_odb *c_odb)
316+
{
317+
Odb *py_odb = PyObject_New(Odb, &OdbType);
318+
319+
if (py_odb)
320+
py_odb->odb = c_odb;
321+
322+
return (PyObject *)py_odb;
323+
}

0 commit comments

Comments
 (0)