Reference: implement peel()

This makes both objects and references peelable via the same interface,
simplifying how to get to the wanted type.
This commit is contained in:
Carlos Martín Nieto
2014-10-07 20:12:43 +02:00
parent 510f6174f1
commit b98e9e85de
6 changed files with 77 additions and 29 deletions

View File

@@ -28,6 +28,7 @@ The Reference type
.. automethod:: pygit2.Reference.delete
.. automethod:: pygit2.Reference.rename
.. automethod:: pygit2.Reference.resolve
.. automethod:: pygit2.Reference.peel
.. automethod:: pygit2.Reference.log
Example::

View File

@@ -135,24 +135,6 @@ Object_read_raw(Object *self)
return aux;
}
static git_otype
py_type_to_git_type(PyTypeObject *py_type)
{
git_otype type = GIT_OBJ_BAD;
if (py_type == &CommitType) {
type = GIT_OBJ_COMMIT;
} else if (py_type == &TreeType) {
type = GIT_OBJ_TREE;
} else if (py_type == &BlobType) {
type = GIT_OBJ_BLOB;
} else if (py_type == &TagType) {
type = GIT_OBJ_TAG;
}
return type;
}
PyDoc_STRVAR(Object_peel__doc__,
"peel(target_type) -> Object\n"
"\n"
@@ -164,18 +146,9 @@ Object_peel(Object *self, PyObject *py_type)
int type = -1, err;
git_object *peeled;
if (PyLong_Check(py_type)) {
type = PyLong_AsLong(py_type);
if (type == -1 && PyErr_Occurred())
return NULL;
} else if (PyType_Check(py_type)) {
type = py_type_to_git_type((PyTypeObject *) py_type);
}
if (type == -1) {
PyErr_SetString(PyExc_ValueError, "invalid target type");
type = py_object_to_object_type(py_type);
if (type == -1)
return NULL;
}
err = git_object_peel(&peeled, self->obj, (git_otype)type);
if (err < 0)

View File

@@ -384,6 +384,29 @@ Reference_get_object(Reference *self)
return wrap_object(obj, self->repo);
}
PyDoc_STRVAR(Reference_peel__doc__,
"peel(type) -> object\n"
"\n"
"Retrieve an object of the given type by recursive peeling.");
PyObject *
Reference_peel(Reference *self, PyObject *py_type)
{
int err, type;
git_object *obj;
CHECK_REFERENCE(self);
type = py_object_to_object_type(py_type);
if (type == -1)
return NULL;
err = git_reference_peel(&obj, self->reference, type);
if (err < 0)
return Error_set(err);
return wrap_object(obj, self->repo);
}
PyDoc_STRVAR(RefLogEntry_committer__doc__, "Committer.");
@@ -479,6 +502,7 @@ PyMethodDef Reference_methods[] = {
METHOD(Reference, log, METH_NOARGS),
METHOD(Reference, get_object, METH_NOARGS),
METHOD(Reference, set_target, METH_VARARGS | METH_KEYWORDS),
METHOD(Reference, peel, METH_O),
{NULL}
};

View File

@@ -31,6 +31,10 @@
#include "utils.h"
extern PyTypeObject ReferenceType;
extern PyTypeObject TreeType;
extern PyTypeObject CommitType;
extern PyTypeObject BlobType;
extern PyTypeObject TagType;
/**
* py_str_to_c_str() returns a newly allocated C string holding the string
@@ -153,3 +157,41 @@ on_error:
return -1;
}
static git_otype
py_type_to_git_type(PyTypeObject *py_type)
{
git_otype type = GIT_OBJ_BAD;
if (py_type == &CommitType) {
type = GIT_OBJ_COMMIT;
} else if (py_type == &TreeType) {
type = GIT_OBJ_TREE;
} else if (py_type == &BlobType) {
type = GIT_OBJ_BLOB;
} else if (py_type == &TagType) {
type = GIT_OBJ_TAG;
}
return type;
}
int
py_object_to_object_type(PyObject *py_type)
{
int type = -1;
if (PyLong_Check(py_type)) {
type = PyLong_AsLong(py_type);
if (type == -1 && PyErr_Occurred())
return -1;
} else if (PyType_Check(py_type)) {
type = py_type_to_git_type((PyTypeObject *) py_type);
}
if (type == -1) {
PyErr_SetString(PyExc_ValueError, "invalid target type");
}
return type;
}

View File

@@ -119,6 +119,8 @@ const char *py_str_borrow_c_str(PyObject **tvaue, PyObject *value, const char *e
PyObject * get_pylist_from_git_strarray(git_strarray *strarray);
int get_strarraygit_from_pylist(git_strarray *array, PyObject *pylist);
int py_object_to_object_type(PyObject *py_type);
#define py_path_to_c_str(py_path) \
py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding)

View File

@@ -32,6 +32,7 @@ from __future__ import unicode_literals
import unittest
from pygit2 import GitError, GIT_REF_OID, GIT_REF_SYMBOLIC, Signature
from pygit2 import Commit, Tree
from . import utils
@@ -223,6 +224,11 @@ class ReferencesTest(utils.RepoTestCase):
ref = repo.lookup_reference('refs/heads/master')
self.assertEqual(repo[ref.target].id, ref.get_object().id)
def test_peel(self):
ref = self.repo.lookup_reference('refs/heads/master')
commit = ref.peel(Commit)
self.assertEqual(commit.tree.id, ref.peel(Tree).id)
if __name__ == '__main__':
unittest.main()