From 78d134c016f88921dc54c3f237107fbd8534934d Mon Sep 17 00:00:00 2001 From: Brodie Rao Date: Wed, 8 Jan 2014 15:14:27 -0800 Subject: [PATCH] repository: add listall_reference_objects() method This allows for efficient reading of many references and their targets, without incurring the overhead of lookup_reference() (which stats for a loose ref and then reads packed-refs) which can be expensive on NFS with thousands of refs. --- docs/references.rst | 1 + src/repository.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ src/repository.h | 2 ++ test/test_refs.py | 11 ++++++++++ 4 files changed, 65 insertions(+) diff --git a/docs/references.rst b/docs/references.rst index 3391392..0682f0e 100644 --- a/docs/references.rst +++ b/docs/references.rst @@ -4,6 +4,7 @@ References .. contents:: +.. automethod:: pygit2.Repository.listall_reference_objects .. automethod:: pygit2.Repository.listall_references .. automethod:: pygit2.Repository.lookup_reference diff --git a/src/repository.c b/src/repository.c index f8d42a7..e83302c 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1123,6 +1123,56 @@ out: } +PyDoc_STRVAR(Repository_listall_reference_objects__doc__, + "listall_reference_objects() -> [Reference, ...]\n" + "\n" + "Return a list with all the reference objects in the repository."); + +PyObject * +Repository_listall_reference_objects(Repository *self, PyObject *args) +{ + git_reference_iterator *iter; + git_reference *ref = NULL; + int err; + PyObject *list; + + list = PyList_New(0); + if (list == NULL) + return NULL; + + if ((err = git_reference_iterator_new(&iter, self->repo)) < 0) + return Error_set(err); + + while ((err = git_reference_next(&ref, iter)) == 0) { + PyObject *py_ref = wrap_reference(ref, self); + if (py_ref == NULL) + goto error; + + err = PyList_Append(list, py_ref); + Py_DECREF(py_ref); + + if (err < 0) + goto error; + } + + git_reference_iterator_free(iter); + if (err == GIT_ITEROVER) + err = 0; + + if (err < 0) { + Py_CLEAR(list); + return Error_set(err); + } + + return list; + +error: + git_reference_iterator_free(iter); + Py_CLEAR(list); + return NULL; +} + + PyDoc_STRVAR(Repository_listall_branches__doc__, "listall_branches([flag]) -> [str, ...]\n" "\n" @@ -1643,6 +1693,7 @@ PyMethodDef Repository_methods[] = { METHOD(Repository, create_reference_direct, METH_VARARGS), METHOD(Repository, create_reference_symbolic, METH_VARARGS), METHOD(Repository, listall_references, METH_NOARGS), + METHOD(Repository, listall_reference_objects, METH_NOARGS), METHOD(Repository, listall_submodules, METH_NOARGS), METHOD(Repository, lookup_reference, METH_O), METHOD(Repository, revparse_single, METH_O), diff --git a/src/repository.h b/src/repository.h index 6947269..bc6cc38 100644 --- a/src/repository.h +++ b/src/repository.h @@ -58,6 +58,8 @@ PyObject* Repository_create_commit(Repository *self, PyObject *args); PyObject* Repository_create_tag(Repository *self, PyObject *args); PyObject* Repository_create_branch(Repository *self, PyObject *args); PyObject* Repository_listall_references(Repository *self, PyObject *args); +PyObject* Repository_listall_reference_objects(Repository *self, + PyObject *args); PyObject* Repository_listall_branches(Repository *self, PyObject *args); PyObject* Repository_lookup_reference(Repository *self, PyObject *py_name); diff --git a/test/test_refs.py b/test/test_refs.py index 53de205..9429146 100644 --- a/test/test_refs.py +++ b/test/test_refs.py @@ -42,6 +42,17 @@ LAST_COMMIT = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98' class ReferencesTest(utils.RepoTestCase): + def test_list_all_reference_objects(self): + repo = self.repo + + refs = [(ref.name, ref.target.hex) + for ref in repo.listall_reference_objects()] + self.assertEqual(sorted(refs), + [('refs/heads/i18n', + '5470a671a80ac3789f1a6a8cefbcf43ce7af0563'), + ('refs/heads/master', + '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98')]) + def test_list_all_references(self): repo = self.repo