libgit-thin: pygit: New methods
[git/libgit-gsoc.git] / libgit-thin / pygit / pygit.c
blob9a88737d0d4247e8a024c3da0b3b3f429a052180
1 #include <Python.h>
2 #include "structmember.h"
4 #include <libgit-thin.h>
6 static PyObject *PyGitError;
8 PyMODINIT_FUNC initpygit(void);
11 * Useful helpers for all the types
14 #define UNUSED(x) (x = x)
16 static PyObject *
17 pygit_error(void)
19 return PyErr_Format(PyGitError, "[Errno: %d] %s", errno,
20 strerror(errno));
23 static PyObject *
24 pygit_error_revlist(void)
26 PyErr_SetString(PyGitError, "revlist not configured");
27 return NULL;
30 static int
31 pyarg_to_sha1(PyObject *args, unsigned char *sha1)
33 const char *hex;
35 if (!PyArg_ParseTuple(args, "s", &hex))
36 return -1;
38 if (git_hex_to_sha1(hex, sha1)) {
39 pygit_error();
40 return -1;
43 return 0;
46 static PyObject *
47 sha1_to_pystr(unsigned char *sha1)
49 char hex[GIT_HEX_LENGTH + 1];
51 if (git_sha1_to_hex(sha1, hex))
52 return pygit_error();
54 return PyString_FromString(hex);
58 * Commit Type
61 typedef struct {
62 PyObject_HEAD
63 struct git_commit *commit;
64 } GitCommitObject;
66 static PyObject *
67 pygit_call_commit_op(struct git_commit *commit,
68 const char *(*commit_op)(struct git_commit *))
70 const char *ret;
72 ret = commit_op(commit);
73 if (!ret)
74 return pygit_error();
76 return PyString_FromString(ret);
79 static PyObject *
80 pygit_commit_message(GitCommitObject *self, PyObject *args)
82 UNUSED(args);
83 return pygit_call_commit_op(self->commit, git_commit_message);
86 static PyObject *
87 pygit_commit_raw(GitCommitObject *self, PyObject *args)
89 UNUSED(args);
90 return pygit_call_commit_op(self->commit, git_commit_raw);
93 static PyObject *
94 pygit_commit_id(GitCommitObject *self, PyObject *args)
96 int err;
97 unsigned char sha1[GIT_SHA1_SIZE];
99 UNUSED(args);
101 err = git_commit_id(self->commit, sha1);
102 if (err)
103 return pygit_error();
105 return sha1_to_pystr(sha1);
108 static PyMethodDef git_commit_methods[] = {
109 {"message", (PyCFunction) pygit_commit_message, METH_VARARGS, NULL},
110 {"id", (PyCFunction) pygit_commit_id, METH_VARARGS, NULL},
111 {"buffer", (PyCFunction) pygit_commit_raw, METH_VARARGS, NULL},
112 {NULL, NULL, 0, NULL}
115 static void
116 git_commit_dealloc(GitCommitObject *self)
118 git_commit_free(self->commit);
119 self->ob_type->tp_free((PyObject*) self);
122 static PyTypeObject Git_Commit_Type = {
123 PyObject_HEAD_INIT(NULL)
124 0, /* ob_size */
125 "pygit.comit", /* tp_name */
126 sizeof(GitCommitObject), /* tp_basicsize */
127 0, /* tp_itemsize */
128 (destructor)git_commit_dealloc, /* tp_dealloc */
129 0, /* tp_print */
130 0, /* tp_getattr */
131 0, /* tp_setattr */
132 0, /* tp_compare */
133 0, /* tp_repr */
134 0, /* tp_as_number */
135 0, /* tp_as_sequence */
136 0, /* tp_as_mapping */
137 0, /* tp_hash */
138 0, /* tp_call */
139 0, /* tp_str */
140 0, /* tp_getattro */
141 0, /* tp_setattro */
142 0, /* tp_as_buffer */
143 Py_TPFLAGS_DEFAULT, /* tp_flags */
144 0, /* tp_doc */
145 0, /* tp_traverse */
146 0, /* tp_clear */
147 0, /* tp_richcompare */
148 0, /* tp_weaklistoffset */
149 0, /* tp_iter */
150 0, /* tp_iternext */
151 git_commit_methods, /* tp_methods */
152 0, /* tp_members */
153 0, /* tp_getset */
154 0, /* tp_base */
155 0, /* tp_dict */
156 0, /* tp_descr_get */
157 0, /* tp_descr_set */
158 0, /* tp_dictoffset */
159 0, /* tp_init */
160 0, /* tp_alloc */
161 0, /* tp_new */
165 * Repository Type
168 typedef struct {
169 PyObject_HEAD
170 PyObject *path;
171 struct git_revlist_opt *revlist_opt;
172 } GitRepoObject;
174 static PyObject *
175 repo_read_obj(PyObject *args,
176 int (*read_obj)(unsigned char *sha1, void **buf, size_t *len))
178 int err;
179 void *buf;
180 PyObject *ret;
181 unsigned char sha1[GIT_SHA1_SIZE];
183 err = pyarg_to_sha1(args, sha1);
184 if (err)
185 return NULL;
187 err = read_obj(sha1, &buf, NULL);
188 if (err)
189 return pygit_error();
191 ret = PyString_FromString((char *) buf);
192 free(buf);
194 return ret;
197 static PyObject *
198 pygit_repo_head_commit(GitRepoObject *self, PyObject *args)
200 int err;
201 unsigned char sha1[GIT_SHA1_SIZE];
203 UNUSED(self);
204 UNUSED(args);
206 err = git_repo_head(sha1);
207 if (err)
208 return pygit_error();
210 return sha1_to_pystr(sha1);
213 static PyObject *
214 pygit_repo_read_commit(GitRepoObject *self, PyObject *args)
216 UNUSED(self);
217 return repo_read_obj(args, git_repo_commit_read);
220 static PyObject *
221 pygit_repo_read_blob(GitRepoObject *self, PyObject *args)
223 UNUSED(self);
224 return repo_read_obj(args, git_repo_blob_read);
227 static PyObject *
228 pygit_repo_lookup_commit(GitRepoObject *self, PyObject *args)
230 int err;
231 GitCommitObject *m;
232 struct git_commit *commit;
233 unsigned char sha1[GIT_SHA1_SIZE];
235 UNUSED(self);
237 err = pyarg_to_sha1(args, sha1);
238 if (err)
239 return NULL;
241 commit = git_commit_lookup(sha1);
242 if (!commit)
243 return pygit_error();
245 m = PyObject_New(GitCommitObject, &Git_Commit_Type);
246 if (!m) {
247 git_commit_free(commit);
248 return NULL;
251 m->commit = commit;
253 err = PyType_Ready(&Git_Commit_Type);
254 if (err) {
255 PyObject_DEL(m);
256 return NULL;
259 return (PyObject *) m;
262 static PyObject *
263 pygit_repo_revlist_include(GitRepoObject *self, PyObject *args)
265 int err;
266 unsigned char sha1[GIT_SHA1_SIZE];
268 if (!self->revlist_opt) {
269 self->revlist_opt = git_revlist_init();
270 if (!self->revlist_opt)
271 return pygit_error();
274 err = pyarg_to_sha1(args, sha1);
275 if (err) {
276 git_revlist_free(self->revlist_opt);
277 self->revlist_opt = NULL;
278 return NULL;
281 err = git_revlist_include(self->revlist_opt, sha1);
282 if (err)
283 return pygit_error();
285 Py_RETURN_NONE;
288 static PyObject *
289 pygit_repo_translate_ref(GitRepoObject *self, PyObject *args)
291 int err;
292 const char *ref;
293 unsigned char sha1[GIT_SHA1_SIZE];
295 UNUSED(self);
297 if (!PyArg_ParseTuple(args, "s", &ref))
298 return NULL;
300 err = git_repo_translate_ref(ref, sha1);
301 if (err)
302 return pygit_error();
304 return sha1_to_pystr(sha1);
307 static PyMethodDef git_repo_methods[] = {
308 {"read_commit", (PyCFunction) pygit_repo_read_commit,
309 METH_VARARGS, NULL},
310 {"read_blob", (PyCFunction) pygit_repo_read_blob,
311 METH_VARARGS, NULL},
312 {"lookup_commit", (PyCFunction) pygit_repo_lookup_commit,
313 METH_VARARGS, NULL},
314 {"head_commit", (PyCFunction) pygit_repo_head_commit, METH_NOARGS,
315 NULL},
316 {"revlist_include", (PyCFunction) pygit_repo_revlist_include,
317 METH_VARARGS, NULL},
318 {"translate_ref", (PyCFunction) pygit_repo_translate_ref,
319 METH_VARARGS, NULL},
320 {NULL, NULL, 0, NULL}
323 static PyMemberDef git_repo_members[] = {
324 {"path", T_OBJECT_EX, offsetof(GitRepoObject, path), 0,
325 "repository's path"},
326 {NULL, 0, 0, 0, NULL}
329 static void
330 git_repo_dealloc(GitRepoObject *self)
332 Py_XDECREF(self->path);
333 git_revlist_free(self->revlist_opt);
334 self->ob_type->tp_free((PyObject*) self);
337 static PyObject *
338 git_repo_iter(GitRepoObject *self)
340 if (!self->revlist_opt)
341 return pygit_error_revlist();
343 Py_INCREF(self);
344 return (PyObject *) self;
347 static PyObject *
348 git_repo_iternext(GitRepoObject *self)
350 int ret;
351 GitCommitObject *m;
352 struct git_commit *commit;
354 if (!self->revlist_opt)
355 return pygit_error_revlist();
357 commit = git_commit_init();
358 if (!commit)
359 return pygit_error();
361 ret = git_revlist_next(self->revlist_opt, commit);
362 if (ret != 1) {
363 git_commit_free(commit);
364 Py_DECREF(self);
365 return NULL;
368 m = PyObject_New(GitCommitObject, &Git_Commit_Type);
369 if (!m) {
370 git_commit_free(commit);
371 Py_DECREF(self);
372 return NULL;
375 m->commit = commit;
377 ret = PyType_Ready(&Git_Commit_Type);
378 if (ret) {
379 PyObject_DEL(m);
380 Py_DECREF(self);
381 return NULL;
384 return (PyObject *) m;
387 static PyTypeObject Git_Repo_Type = {
388 PyObject_HEAD_INIT(NULL)
389 0, /* ob_size */
390 "pygit.repo", /* tp_name */
391 sizeof(GitRepoObject), /* tp_basicsize */
392 0, /* tp_itemsize */
393 (destructor)git_repo_dealloc, /* tp_dealloc */
394 0, /* tp_print */
395 0, /* tp_getattr */
396 0, /* tp_setattr */
397 0, /* tp_compare */
398 0, /* tp_repr */
399 0, /* tp_as_number */
400 0, /* tp_as_sequence */
401 0, /* tp_as_mapping */
402 0, /* tp_hash */
403 0, /* tp_call */
404 0, /* tp_str */
405 0, /* tp_getattro */
406 0, /* tp_setattro */
407 0, /* tp_as_buffer */
408 Py_TPFLAGS_DEFAULT, /* tp_flags */
409 0, /* tp_doc */
410 0, /* tp_traverse */
411 0, /* tp_clear */
412 0, /* tp_richcompare */
413 0, /* tp_weaklistoffset */
414 (getiterfunc)git_repo_iter, /* tp_iter */
415 (iternextfunc)git_repo_iternext, /* tp_iternext */
416 git_repo_methods, /* tp_methods */
417 git_repo_members, /* tp_members */
418 0, /* tp_getset */
419 0, /* tp_base */
420 0, /* tp_dict */
421 0, /* tp_descr_get */
422 0, /* tp_descr_set */
423 0, /* tp_dictoffset */
424 0, /* tp_init */
425 0, /* tp_alloc */
426 0, /* tp_new */
429 static PyObject *
430 pygit_open(PyObject *self, PyObject *args)
432 int err;
433 const char *dir;
434 GitRepoObject *m;
436 UNUSED(self);
438 if (!PyArg_ParseTuple(args, "s", &dir))
439 return NULL;
441 err = git_repo_open(dir);
442 if (err)
443 return pygit_error();
445 m = PyObject_New(GitRepoObject, &Git_Repo_Type);
446 if (!m)
447 return NULL;
449 err = PyType_Ready(&Git_Repo_Type);
450 if (err) {
451 PyObject_DEL(m);
452 return NULL;
455 m->path = PyString_FromString(dir);
456 if (!m->path) {
457 PyObject_DEL(m);
458 return NULL;
460 m->revlist_opt = NULL;
462 return (PyObject *) m;
466 * Module definitions
469 static PyMethodDef pygit_methods[] = {
470 { "open", pygit_open, METH_VARARGS, "Open a GIT repository" },
471 { NULL, NULL, 0, NULL}
474 PyMODINIT_FUNC
475 initpygit(void)
477 PyObject *m;
479 m = Py_InitModule("pygit", pygit_methods);
480 if (!m)
481 return;
483 PyGitError = PyErr_NewException("pygit.error", NULL, NULL);
484 if (!PyGitError)
485 return ;
487 Py_INCREF(PyGitError);
488 PyModule_AddObject(m, "error", PyGitError);