From ce4e41113569936c4bc14e906c8d6740cff79a82 Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Wed, 30 May 2012 14:39:02 +0200 Subject: [PATCH] added revlog --- include/pygit2/types.h | 8 +++ src/pygit2.c | 3 + src/pygit2/reference.c | 129 +++++++++++++++++++++++++++++++++++++++++ test/test_revwalk.py | 17 ++++++ 4 files changed, 157 insertions(+) diff --git a/include/pygit2/types.h b/include/pygit2/types.h index 81f302f..264a939 100644 --- a/include/pygit2/types.h +++ b/include/pygit2/types.h @@ -76,6 +76,14 @@ typedef struct { git_reference *reference; } Reference; +typedef struct { + PyObject_HEAD + PyObject *oid_old; + PyObject *oid_new; + PyObject *committer; + char *msg; +} ReferenceLogEntry; + typedef struct { PyObject_HEAD Object *obj; diff --git a/src/pygit2.c b/src/pygit2.c index 7e1ad75..d2b1ba8 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -53,6 +53,7 @@ PyTypeObject IndexEntryType; PyTypeObject IndexIterType; PyTypeObject WalkerType; PyTypeObject ReferenceType; +PyTypeObject ReferenceLogEntryType; PyTypeObject SignatureType; @@ -165,6 +166,8 @@ moduleinit(PyObject* m) ReferenceType.tp_new = PyType_GenericNew; if (PyType_Ready(&ReferenceType) < 0) return NULL; + if (PyType_Ready(&ReferenceLogEntryType) < 0) + return NULL; SignatureType.tp_new = PyType_GenericNew; if (PyType_Ready(&SignatureType) < 0) return NULL; diff --git a/src/pygit2/reference.c b/src/pygit2/reference.c index 37f24c4..8f8e6a9 100644 --- a/src/pygit2/reference.c +++ b/src/pygit2/reference.c @@ -1,13 +1,18 @@ #define PY_SSIZE_T_CLEAN #include +#include +#include #include #include #include #include +#include #include extern PyObject *GitError; +extern PyTypeObject ReferenceLogEntryType; + void Reference_dealloc(Reference *self) { @@ -221,6 +226,128 @@ Reference_get_type(Reference *self) return PyInt_FromLong(c_type); } +PyObject * +Reference_log(Reference *self) +{ + ReferenceLogEntry *py_entry; + PyObject *py_list; + git_reflog *reflog; + ssize_t i, size; + + CHECK_REFERENCE(self); + + git_reflog_read(&reflog, self->reference); + + size = git_reflog_entrycount(reflog); + + py_list = PyList_New(size); + + for(i = 0; i < size; ++i) { + char oid_old[40], oid_new[40]; + git_signature *signature = NULL; + + const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, i); + + py_entry = (ReferenceLogEntry*) PyType_GenericNew( + &ReferenceLogEntryType, NULL, NULL + ); + + git_oid_fmt(oid_old, git_reflog_entry_oidold(entry)); + git_oid_fmt(oid_new, git_reflog_entry_oidnew(entry)); + + py_entry->oid_new = PyUnicode_FromStringAndSize(oid_new, 40); + py_entry->oid_old = PyUnicode_FromStringAndSize(oid_old, 40); + + py_entry->msg = strdup(git_reflog_entry_msg(entry)); + + signature = git_signature_dup( + git_reflog_entry_committer(entry) + ); + + if(signature != NULL) + py_entry->committer = build_signature( + (PyObject*)py_entry, signature, "utf-8" + ); + + PyList_SetItem(py_list, i, (PyObject*) py_entry); + } + + git_reflog_free(reflog); + + return py_list; +} + +static int +ReferenceLogEntry_init(ReferenceLogEntry *self, PyObject *args, PyObject *kwds) +{ + self->oid_old = Py_None; + self->oid_new = Py_None; + self->msg = ""; + self->committer = Py_None; + + return 0; +} + + +static void +ReferenceLogEntry_dealloc(ReferenceLogEntry *self) +{ + Py_XDECREF(self->oid_old); + Py_XDECREF(self->oid_new); + Py_XDECREF(self->committer); + free(self->msg); + PyObject_Del(self); +} + +PyMemberDef ReferenceLogEntry_members[] = { + {"oid_new", T_OBJECT, offsetof(ReferenceLogEntry, oid_new), 0, "new oid"}, + {"oid_old", T_OBJECT, offsetof(ReferenceLogEntry, oid_old), 0, "old oid"}, + {"message", T_STRING, offsetof(ReferenceLogEntry, msg), 0, "message"}, + {"committer", T_OBJECT, offsetof(ReferenceLogEntry, committer), 0, "committer"}, + {NULL} +}; + +PyTypeObject ReferenceLogEntryType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pygit2.ReferenceLogEntry", /* tp_name */ + sizeof(ReferenceLogEntry), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)ReferenceLogEntry_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "ReferenceLog object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + ReferenceLogEntry_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)ReferenceLogEntry_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + PyMethodDef Reference_methods[] = { {"delete", (PyCFunction)Reference_delete, METH_NOARGS, "Delete this reference. It will no longer be valid!"}, @@ -230,6 +357,8 @@ PyMethodDef Reference_methods[] = { "Reload the reference from the file-system."}, {"resolve", (PyCFunction)Reference_resolve, METH_NOARGS, "Resolve a symbolic reference and return a direct reference."}, + {"log", (PyCFunction)Reference_log, METH_NOARGS, + "Retrieves the current reference log."}, {NULL} }; diff --git a/test/test_revwalk.py b/test/test_revwalk.py index 9cfb0d2..47058ac 100644 --- a/test/test_revwalk.py +++ b/test/test_revwalk.py @@ -46,6 +46,23 @@ log = [ '6aaa262e655dd54252e5813c8e5acd7780ed097d', 'acecd5ea2924a4b900e7e149496e1f4b57976e51'] +REVLOGS = [ + ('J. David Ibañez', 'commit (initial): First commit'), + ('J. David Ibañez', 'checkout: moving from master to i18n'), + ('J. David Ibañez', 'commit: Say hello in Spanish'), + ('J. David Ibañez', 'commit: Say hello in French'), + ('J. David Ibañez', 'checkout: moving from i18n to master'), + ('J. David Ibañez', 'commit: Add .gitignore file'), + ('J. David Ibañez', 'merge i18n: Merge made by recursive.') +] + + +class RevlogTestTest(utils.RepoTestCase): + def test_log(self): + ref = self.repo.lookup_reference('HEAD') + for i,entry in enumerate(ref.log()): + self.assertEqual(entry.committer.name, REVLOGS[i][0]) + self.assertEqual(entry.message, REVLOGS[i][1]) class WalkerTest(utils.RepoTestCase):