libgit-thin: pygit: Kill pygit_ prefix
[git/libgit-gsoc.git] / libgit-thin / pygit / pygit.c
blobf092d97ba2b7a0083e071c65f68fc2956384b377
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 int
24 pyarg_to_sha1(PyObject *args, unsigned char *sha1)
26 const char *hex;
28 if (!PyArg_ParseTuple(args, "s", &hex))
29 return -1;
31 if (git_hex_to_sha1(hex, sha1)) {
32 pygit_error();
33 return -1;
36 return 0;
39 static PyObject *
40 sha1_to_pystr(unsigned char *sha1)
42 char hex[GIT_HEX_LENGTH + 1];
44 if (git_sha1_to_hex(sha1, hex))
45 return pygit_error();
47 return PyString_FromString(hex);
51 * Commit Type
54 typedef struct {
55 PyObject_HEAD
56 struct git_commit *commit;
57 } GitCommitObject;
59 static PyObject *
60 pygit_call_commit_op(struct git_commit *commit,
61 const char *(*commit_op)(struct git_commit *))
63 const char *ret;
65 ret = commit_op(commit);
66 if (!ret)
67 return pygit_error();
69 return PyString_FromString(ret);
72 static PyObject *
73 commit_message(GitCommitObject *self, PyObject *args)
75 UNUSED(args);
76 return pygit_call_commit_op(self->commit, git_commit_message);
79 static PyObject *
80 commit_raw(GitCommitObject *self, PyObject *args)
82 UNUSED(args);
83 return pygit_call_commit_op(self->commit, git_commit_raw);
86 static PyObject *
87 commit_id(GitCommitObject *self, PyObject *args)
89 int err;
90 unsigned char sha1[GIT_SHA1_SIZE];
92 UNUSED(args);
94 err = git_commit_id(self->commit, sha1);
95 if (err)
96 return pygit_error();
98 return sha1_to_pystr(sha1);
101 static PyMethodDef commit_methods[] = {
102 {"message", (PyCFunction) commit_message, METH_VARARGS, NULL},
103 {"id", (PyCFunction) commit_id, METH_VARARGS, NULL},
104 {"buffer", (PyCFunction) commit_raw, METH_VARARGS, NULL},
105 {NULL, NULL, 0, NULL}
108 static void
109 commit_dealloc(GitCommitObject *self)
111 git_commit_free(self->commit);
112 self->ob_type->tp_free((PyObject*) self);
115 static int
116 commit_compare(GitCommitObject *a, GitCommitObject *b)
118 int ret = 0;
119 int err, a_tz, b_tz;
120 time_t a_time, b_time;
122 err = git_commit_committer_date(a->commit, &a_time, &a_tz);
123 if (err) {
124 pygit_error();
125 return -1;
128 err = git_commit_committer_date(b->commit, &b_time, &b_tz);
129 if (err) {
130 pygit_error();
131 return -1;
134 if (a_tz != b_tz) {
135 PyErr_SetString(PyGitError, "time zone must be equal");
136 return -1;
139 if (a_time < b_time)
140 ret = -1;
141 else if (a_time > b_time)
142 ret = 1;
144 return ret;
147 static PyTypeObject Git_Commit_Type = {
148 PyObject_HEAD_INIT(NULL)
149 0, /* ob_size */
150 "pygit.comit", /* tp_name */
151 sizeof(GitCommitObject), /* tp_basicsize */
152 0, /* tp_itemsize */
153 (destructor)commit_dealloc, /* tp_dealloc */
154 0, /* tp_print */
155 0, /* tp_getattr */
156 0, /* tp_setattr */
157 (cmpfunc)commit_compare, /* tp_compare */
158 0, /* tp_repr */
159 0, /* tp_as_number */
160 0, /* tp_as_sequence */
161 0, /* tp_as_mapping */
162 0, /* tp_hash */
163 0, /* tp_call */
164 0, /* tp_str */
165 0, /* tp_getattro */
166 0, /* tp_setattro */
167 0, /* tp_as_buffer */
168 Py_TPFLAGS_DEFAULT, /* tp_flags */
169 0, /* tp_doc */
170 0, /* tp_traverse */
171 0, /* tp_clear */
172 0, /* tp_richcompare */
173 0, /* tp_weaklistoffset */
174 0, /* tp_iter */
175 0, /* tp_iternext */
176 commit_methods, /* tp_methods */
177 0, /* tp_members */
178 0, /* tp_getset */
179 0, /* tp_base */
180 0, /* tp_dict */
181 0, /* tp_descr_get */
182 0, /* tp_descr_set */
183 0, /* tp_dictoffset */
184 0, /* tp_init */
185 0, /* tp_alloc */
186 0, /* tp_new */
190 * Revision list type
193 typedef struct {
194 PyObject_HEAD
195 int list_end;
196 struct git_revlist_opt *opt;
197 } GitRevListObject;
199 static void
200 revlist_free(GitRevListObject *self)
202 git_revlist_free(self->opt);
203 self->opt = NULL;
206 static PyObject *
207 revlist_add_commit(GitRevListObject *self, PyObject *args, int exclude)
209 int err;
210 unsigned char sha1[GIT_SHA1_SIZE];
212 err = pyarg_to_sha1(args, sha1);
213 if (err) {
214 revlist_free(self);
215 return NULL;
218 if (exclude)
219 err = git_revlist_exclude(self->opt, sha1);
220 else
221 err = git_revlist_include(self->opt, sha1);
223 if (err)
224 return pygit_error();
226 Py_RETURN_NONE;
229 static PyObject *
230 revlist_include(GitRevListObject *self, PyObject *args)
232 return revlist_add_commit(self, args, 0);
235 static PyObject *
236 revlist_exclude(GitRevListObject *self, PyObject *args)
238 return revlist_add_commit(self, args, 1);
241 static PyObject *
242 revlist_reverse(GitRevListObject *self, PyObject *args)
244 int err;
246 UNUSED(args);
248 err = git_revlist_reverse(self->opt);
249 if (err)
250 return pygit_error();
252 Py_RETURN_NONE;
255 static PyObject *
256 revlist_show_merges(GitRevListObject *self, PyObject *args)
258 int err;
260 UNUSED(args);
262 err = git_revlist_show_merges(self->opt);
263 if (err)
264 return pygit_error();
266 Py_RETURN_NONE;
269 static PyObject *
270 revlist_max_count(GitRevListObject *self, PyObject *args)
272 int err;
273 unsigned long count;
275 if (!PyArg_ParseTuple(args, "k", &count))
276 return NULL;
278 err = git_revlist_max_count(self->opt, (size_t) count);
279 if (err)
280 return pygit_error();
282 Py_RETURN_NONE;
285 static PyMethodDef revlist_methods[] = {
286 {"include", (PyCFunction) revlist_include, METH_VARARGS, NULL},
287 {"exclude", (PyCFunction) revlist_exclude, METH_VARARGS, NULL},
288 {"reverse", (PyCFunction) revlist_reverse, METH_NOARGS, NULL},
289 {"show_merges", (PyCFunction) revlist_show_merges, METH_NOARGS, NULL},
290 {"max_count", (PyCFunction) revlist_max_count,METH_VARARGS,NULL},
291 {NULL, NULL, 0, NULL}
294 static void
295 revlist_dealloc(GitRevListObject *self)
297 git_revlist_free(self->opt);
298 self->ob_type->tp_free((PyObject*) self);
301 static PyObject *
302 revlist_iter(GitRevListObject *self)
304 Py_INCREF(self);
305 return (PyObject *) self;
308 static PyObject *
309 revlist_iternext(GitRevListObject *self)
311 int ret;
312 GitCommitObject *m;
313 struct git_commit *commit;
315 commit = git_commit_init();
316 if (!commit)
317 return pygit_error();
319 ret = git_revlist_next(self->opt, commit);
320 if (ret != 1) {
321 git_commit_free(commit);
322 if (!self->list_end) {
323 Py_DECREF(self);
324 self->list_end = 1;
326 return NULL;
329 m = PyObject_New(GitCommitObject, &Git_Commit_Type);
330 if (!m) {
331 git_commit_free(commit);
332 return NULL;
335 m->commit = commit;
337 ret = PyType_Ready(&Git_Commit_Type);
338 if (ret) {
339 PyObject_DEL(m);
340 return NULL;
343 return (PyObject *) m;
346 static PyTypeObject Git_RevList_Type = {
347 PyObject_HEAD_INIT(NULL)
348 0, /* ob_size */
349 "pygit.revlist", /* tp_name */
350 sizeof(GitRevListObject), /* tp_basicsize */
351 0, /* tp_itemsize */
352 (destructor)revlist_dealloc, /* tp_dealloc */
353 0, /* tp_print */
354 0, /* tp_getattr */
355 0, /* tp_setattr */
356 0, /* tp_compare */
357 0, /* tp_repr */
358 0, /* tp_as_number */
359 0, /* tp_as_sequence */
360 0, /* tp_as_mapping */
361 0, /* tp_hash */
362 0, /* tp_call */
363 0, /* tp_str */
364 0, /* tp_getattro */
365 0, /* tp_setattro */
366 0, /* tp_as_buffer */
367 Py_TPFLAGS_DEFAULT, /* tp_flags */
368 0, /* tp_doc */
369 0, /* tp_traverse */
370 0, /* tp_clear */
371 0, /* tp_richcompare */
372 0, /* tp_weaklistoffset */
373 (getiterfunc)revlist_iter, /* tp_iter */
374 (iternextfunc)revlist_iternext, /* tp_iternext */
375 revlist_methods, /* tp_methods */
376 0, /* tp_members */
377 0, /* tp_getset */
378 0, /* tp_base */
379 0, /* tp_dict */
380 0, /* tp_descr_get */
381 0, /* tp_descr_set */
382 0, /* tp_dictoffset */
383 0, /* tp_init */
384 0, /* tp_alloc */
385 0, /* tp_new */
389 * Repository type
392 typedef struct {
393 PyObject_HEAD
394 PyObject *path;
395 } GitRepoObject;
397 static PyObject *
398 repo_read_obj(PyObject *args,
399 int (*read_obj)(unsigned char *sha1, void **buf, size_t *len))
401 int err;
402 void *buf;
403 PyObject *ret;
404 unsigned char sha1[GIT_SHA1_SIZE];
406 err = pyarg_to_sha1(args, sha1);
407 if (err)
408 return NULL;
410 err = read_obj(sha1, &buf, NULL);
411 if (err)
412 return pygit_error();
414 ret = PyString_FromString((char *) buf);
415 free(buf);
417 return ret;
420 static PyObject *
421 repo_head_commit(GitRepoObject *self, PyObject *args)
423 int err;
424 unsigned char sha1[GIT_SHA1_SIZE];
426 UNUSED(self);
427 UNUSED(args);
429 err = git_repo_head(sha1);
430 if (err)
431 return pygit_error();
433 return sha1_to_pystr(sha1);
436 static PyObject *
437 repo_read_commit(GitRepoObject *self, PyObject *args)
439 UNUSED(self);
440 return repo_read_obj(args, git_repo_commit_read);
443 static PyObject *
444 repo_read_blob(GitRepoObject *self, PyObject *args)
446 UNUSED(self);
447 return repo_read_obj(args, git_repo_blob_read);
450 static PyObject *
451 repo_lookup_commit(GitRepoObject *self, PyObject *args)
453 int err;
454 GitCommitObject *m;
455 struct git_commit *commit;
456 unsigned char sha1[GIT_SHA1_SIZE];
458 UNUSED(self);
460 err = pyarg_to_sha1(args, sha1);
461 if (err)
462 return NULL;
464 commit = git_commit_lookup(sha1);
465 if (!commit)
466 return pygit_error();
468 m = PyObject_New(GitCommitObject, &Git_Commit_Type);
469 if (!m) {
470 git_commit_free(commit);
471 return NULL;
474 m->commit = commit;
476 err = PyType_Ready(&Git_Commit_Type);
477 if (err) {
478 PyObject_DEL(m);
479 return NULL;
482 return (PyObject *) m;
485 static PyObject *
486 repo_translate_ref(GitRepoObject *self, PyObject *args)
488 int err;
489 const char *ref;
490 unsigned char sha1[GIT_SHA1_SIZE];
492 UNUSED(self);
494 if (!PyArg_ParseTuple(args, "s", &ref))
495 return NULL;
497 err = git_repo_translate_ref(ref, sha1);
498 if (err)
499 return pygit_error();
501 return sha1_to_pystr(sha1);
504 static PyObject *
505 repo_revlist(GitRepoObject *self, PyObject *args)
507 int err;
508 GitRevListObject *m;
510 UNUSED(self);
511 UNUSED(args);
513 m = PyObject_New(GitRevListObject, &Git_RevList_Type);
514 if (!m)
515 return NULL;
517 err = PyType_Ready(&Git_RevList_Type);
518 if (err) {
519 PyObject_DEL(m);
520 return NULL;
523 m->opt = git_revlist_init();
524 if (!m->opt) {
525 PyObject_DEL(m);
526 return pygit_error();
528 m->list_end = 0;
530 return (PyObject *) m;
533 static PyMethodDef repo_methods[] = {
534 {"read_commit", (PyCFunction) repo_read_commit, METH_VARARGS, NULL},
535 {"read_blob", (PyCFunction) repo_read_blob, METH_VARARGS, NULL},
536 {"lookup_commit", (PyCFunction) repo_lookup_commit, METH_VARARGS,NULL},
537 {"head_commit", (PyCFunction) repo_head_commit, METH_NOARGS, NULL},
538 {"translate_ref", (PyCFunction) repo_translate_ref,METH_VARARGS, NULL},
539 {"revlist", (PyCFunction) repo_revlist, METH_VARARGS, NULL},
540 {NULL, NULL, 0, NULL}
543 static PyMemberDef repo_members[] = {
544 {"path", T_OBJECT_EX, offsetof(GitRepoObject, path), 0,
545 "repository's path"},
546 {NULL, 0, 0, 0, NULL}
549 static void
550 repo_dealloc(GitRepoObject *self)
552 Py_XDECREF(self->path);
553 self->ob_type->tp_free((PyObject*) self);
556 static PyTypeObject Git_Repo_Type = {
557 PyObject_HEAD_INIT(NULL)
558 0, /* ob_size */
559 "pygit.repo", /* tp_name */
560 sizeof(GitRepoObject), /* tp_basicsize */
561 0, /* tp_itemsize */
562 (destructor)repo_dealloc, /* tp_dealloc */
563 0, /* tp_print */
564 0, /* tp_getattr */
565 0, /* tp_setattr */
566 0, /* tp_compare */
567 0, /* tp_repr */
568 0, /* tp_as_number */
569 0, /* tp_as_sequence */
570 0, /* tp_as_mapping */
571 0, /* tp_hash */
572 0, /* tp_call */
573 0, /* tp_str */
574 0, /* tp_getattro */
575 0, /* tp_setattro */
576 0, /* tp_as_buffer */
577 Py_TPFLAGS_DEFAULT, /* tp_flags */
578 0, /* tp_doc */
579 0, /* tp_traverse */
580 0, /* tp_clear */
581 0, /* tp_richcompare */
582 0, /* tp_weaklistoffset */
583 0, /* tp_iter */
584 0, /* tp_iternext */
585 repo_methods, /* tp_methods */
586 repo_members, /* tp_members */
587 0, /* tp_getset */
588 0, /* tp_base */
589 0, /* tp_dict */
590 0, /* tp_descr_get */
591 0, /* tp_descr_set */
592 0, /* tp_dictoffset */
593 0, /* tp_init */
594 0, /* tp_alloc */
595 0, /* tp_new */
599 * Module's stuff
602 static PyObject *
603 pygit_open(PyObject *self, PyObject *args)
605 int err;
606 const char *dir;
607 GitRepoObject *m;
609 UNUSED(self);
611 if (!PyArg_ParseTuple(args, "s", &dir))
612 return NULL;
614 err = git_repo_open(dir);
615 if (err)
616 return pygit_error();
618 m = PyObject_New(GitRepoObject, &Git_Repo_Type);
619 if (!m)
620 return NULL;
622 err = PyType_Ready(&Git_Repo_Type);
623 if (err) {
624 PyObject_DEL(m);
625 return NULL;
628 m->path = PyString_FromString(dir);
629 if (!m->path) {
630 PyObject_DEL(m);
631 return NULL;
634 return (PyObject *) m;
637 static PyMethodDef pygit_methods[] = {
638 { "open", pygit_open, METH_VARARGS, "Open a GIT repository" },
639 { NULL, NULL, 0, NULL}
642 PyMODINIT_FUNC
643 initpygit(void)
645 PyObject *m;
647 m = Py_InitModule("pygit", pygit_methods);
648 if (!m)
649 return;
651 PyGitError = PyErr_NewException("pygit.error", NULL, NULL);
652 if (!PyGitError)
653 return ;
655 Py_INCREF(PyGitError);
656 PyModule_AddObject(m, "error", PyGitError);