Skip to content

Commit cb3ba67

Browse files
committed
Introduce Odb type
This refactors the Repository type's ODB accessors to a dedicated Odb type. Later we'll extend this to support more of the libgit2 odb functions.
1 parent 9afd7b7 commit cb3ba67

File tree

8 files changed

+338
-165
lines changed

8 files changed

+338
-165
lines changed

pygit2/repository.py

+19
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

+9-1
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

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
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+
void
50+
Odb_dealloc(Odb *self)
51+
{
52+
git_odb_free(self->odb);
53+
54+
Py_TYPE(self)->tp_free((PyObject *) self);
55+
}
56+
57+
static int
58+
Odb_build_as_iter(const git_oid *oid, void *accum)
59+
{
60+
int err;
61+
PyObject *py_oid = git_oid_to_python(oid);
62+
63+
err = PyList_Append((PyObject*)accum, py_oid);
64+
Py_DECREF(py_oid);
65+
return err;
66+
}
67+
68+
PyObject *
69+
Odb_as_iter(Odb *self)
70+
{
71+
int err;
72+
PyObject *accum = PyList_New(0);
73+
PyObject *ret;
74+
75+
err = git_odb_foreach(self->odb, Odb_build_as_iter, (void*)accum);
76+
if (err == GIT_EUSER)
77+
return NULL;
78+
if (err < 0)
79+
return Error_set(err);
80+
81+
ret = PyObject_GetIter(accum);
82+
Py_DECREF(accum);
83+
84+
return ret;
85+
}
86+
87+
git_odb_object *
88+
Odb_read_raw(git_odb *odb, const git_oid *oid, size_t len)
89+
{
90+
git_odb_object *obj;
91+
int err;
92+
93+
err = git_odb_read_prefix(&obj, odb, oid, (unsigned int)len);
94+
if (err < 0) {
95+
Error_set_oid(err, oid, len);
96+
return NULL;
97+
}
98+
99+
return obj;
100+
}
101+
102+
103+
PyDoc_STRVAR(Odb_read__doc__,
104+
"read(oid) -> type, data, size\n"
105+
"\n"
106+
"Read raw object data from the object db.");
107+
108+
PyObject *
109+
Odb_read(Odb *self, PyObject *py_hex)
110+
{
111+
git_oid oid;
112+
git_odb_object *obj;
113+
size_t len;
114+
PyObject* tuple;
115+
116+
len = py_oid_to_git_oid(py_hex, &oid);
117+
if (len == 0)
118+
return NULL;
119+
120+
obj = Odb_read_raw(self->odb, &oid, len);
121+
if (obj == NULL)
122+
return NULL;
123+
124+
tuple = Py_BuildValue(
125+
#if PY_MAJOR_VERSION == 2
126+
"(ns#)",
127+
#else
128+
"(ny#)",
129+
#endif
130+
git_odb_object_type(obj),
131+
git_odb_object_data(obj),
132+
git_odb_object_size(obj));
133+
134+
git_odb_object_free(obj);
135+
return tuple;
136+
}
137+
138+
PyDoc_STRVAR(Odb_write__doc__,
139+
"write(type, data) -> Oid\n"
140+
"\n"
141+
"Write raw object data into the object db. First arg is the object\n"
142+
"type, the second one a buffer with data. Return the Oid of the created\n"
143+
"object.");
144+
145+
PyObject *
146+
Odb_write(Odb *self, PyObject *args)
147+
{
148+
int err;
149+
git_oid oid;
150+
git_odb_stream* stream;
151+
int type_id;
152+
const char* buffer;
153+
Py_ssize_t buflen;
154+
git_otype type;
155+
156+
if (!PyArg_ParseTuple(args, "Is#", &type_id, &buffer, &buflen))
157+
return NULL;
158+
159+
type = int_to_loose_object_type(type_id);
160+
if (type == GIT_OBJ_BAD)
161+
return PyErr_Format(PyExc_ValueError, "%d", type_id);
162+
163+
err = git_odb_open_wstream(&stream, self->odb, buflen, type);
164+
if (err < 0)
165+
return Error_set(err);
166+
167+
err = git_odb_stream_write(stream, buffer, buflen);
168+
if (err) {
169+
git_odb_stream_free(stream);
170+
return Error_set(err);
171+
}
172+
173+
err = git_odb_stream_finalize_write(&oid, stream);
174+
git_odb_stream_free(stream);
175+
if (err)
176+
return Error_set(err);
177+
178+
return git_oid_to_python(&oid);
179+
}
180+
181+
182+
PyMethodDef Odb_methods[] = {
183+
METHOD(Odb, read, METH_O),
184+
METHOD(Odb, write, METH_VARARGS),
185+
{NULL}
186+
};
187+
188+
PyDoc_STRVAR(Odb__doc__, "Object database.");
189+
190+
PyTypeObject OdbType = {
191+
PyVarObject_HEAD_INIT(NULL, 0)
192+
"_pygit2.Odb", /* tp_name */
193+
sizeof(Odb), /* tp_basicsize */
194+
0, /* tp_itemsize */
195+
(destructor)Odb_dealloc, /* tp_dealloc */
196+
0, /* tp_print */
197+
0, /* tp_getattr */
198+
0, /* tp_setattr */
199+
0, /* tp_compare */
200+
0, /* tp_repr */
201+
0, /* tp_as_number */
202+
0, /* tp_as_sequence */
203+
0, /* tp_as_mapping */
204+
0, /* tp_hash */
205+
0, /* tp_call */
206+
0, /* tp_str */
207+
0, /* tp_getattro */
208+
0, /* tp_setattro */
209+
0, /* tp_as_buffer */
210+
Py_TPFLAGS_DEFAULT, /* tp_flags */
211+
Odb__doc__, /* tp_doc */
212+
0, /* tp_traverse */
213+
0, /* tp_clear */
214+
0, /* tp_richcompare */
215+
0, /* tp_weaklistoffset */
216+
(getiterfunc)Odb_as_iter, /* tp_iter */
217+
0, /* tp_iternext */
218+
Odb_methods, /* tp_methods */
219+
0, /* tp_members */
220+
0, /* tp_getset */
221+
0, /* tp_base */
222+
0, /* tp_dict */
223+
0, /* tp_descr_get */
224+
0, /* tp_descr_set */
225+
0, /* tp_dictoffset */
226+
0, /* tp_init */
227+
0, /* tp_alloc */
228+
0, /* tp_new */
229+
};
230+
231+
PyObject *
232+
wrap_odb(git_odb *c_odb)
233+
{
234+
Odb *py_odb = PyObject_New(Odb, &OdbType);
235+
236+
if (py_odb)
237+
py_odb->odb = c_odb;
238+
239+
return (PyObject *)py_odb;
240+
}

src/odb.h

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
#ifndef INCLUDE_pygit2_odb_h
29+
#define INCLUDE_pygit2_odb_h
30+
31+
#define PY_SSIZE_T_CLEAN
32+
#include <Python.h>
33+
#include <git2.h>
34+
#include "types.h"
35+
36+
PyObject *wrap_odb(git_odb *c_odb);
37+
38+
git_odb_object *Odb_read_raw(git_odb *odb, const git_oid *oid, size_t len);
39+
40+
PyObject *Odb_read(Odb *self, PyObject *py_hex);
41+
42+
#endif

src/pygit2.c

+5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ extern PyObject *AlreadyExistsError;
4141
extern PyObject *InvalidSpecError;
4242

4343
extern PyTypeObject RepositoryType;
44+
extern PyTypeObject OdbType;
4445
extern PyTypeObject OidType;
4546
extern PyTypeObject ObjectType;
4647
extern PyTypeObject CommitType;
@@ -277,6 +278,10 @@ moduleinit(PyObject* m)
277278
INIT_TYPE(RepositoryType, NULL, PyType_GenericNew)
278279
ADD_TYPE(m, Repository)
279280

281+
/* Odb */
282+
INIT_TYPE(OdbType, NULL, PyType_GenericNew)
283+
ADD_TYPE(m, Odb)
284+
280285
/* Oid */
281286
INIT_TYPE(OidType, NULL, PyType_GenericNew)
282287
ADD_TYPE(m, Oid)

0 commit comments

Comments
 (0)