Implement the References (part I)
This commit is contained in:
parent
713b14d2ee
commit
aac4cf1b86
304
pygit2.c
304
pygit2.c
@ -49,6 +49,7 @@ OBJECT_STRUCT(Object, git_object, obj)
|
||||
OBJECT_STRUCT(Commit, git_commit, commit)
|
||||
OBJECT_STRUCT(Tree, git_tree, tree)
|
||||
OBJECT_STRUCT(Blob, git_blob, blob)
|
||||
OBJECT_STRUCT(Walker, git_revwalk, walk)
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
@ -77,9 +78,8 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Repository *repo;
|
||||
git_revwalk *walk;
|
||||
} Walker;
|
||||
git_reference *reference;
|
||||
} Reference;
|
||||
|
||||
static PyTypeObject RepositoryType;
|
||||
static PyTypeObject ObjectType;
|
||||
@ -91,6 +91,7 @@ static PyTypeObject TagType;
|
||||
static PyTypeObject IndexType;
|
||||
static PyTypeObject IndexEntryType;
|
||||
static PyTypeObject WalkerType;
|
||||
static PyTypeObject ReferenceType;
|
||||
|
||||
static PyObject *GitError;
|
||||
|
||||
@ -163,6 +164,46 @@ Error_set_py_obj(int err, PyObject *py_obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Object *
|
||||
wrap_object(git_object *obj, Repository *repo) {
|
||||
Object *py_obj = NULL;
|
||||
switch (git_object_type(obj)) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
py_obj = (Object*)CommitType.tp_alloc(&CommitType, 0);
|
||||
break;
|
||||
case GIT_OBJ_TREE:
|
||||
py_obj = (Object*)TreeType.tp_alloc(&TreeType, 0);
|
||||
break;
|
||||
case GIT_OBJ_BLOB:
|
||||
py_obj = (Object*)BlobType.tp_alloc(&BlobType, 0);
|
||||
break;
|
||||
case GIT_OBJ_TAG:
|
||||
py_obj = (Object*)TagType.tp_alloc(&TagType, 0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (!py_obj)
|
||||
return (Object*)PyErr_NoMemory();
|
||||
|
||||
py_obj->obj = obj;
|
||||
py_obj->repo = repo;
|
||||
Py_INCREF(repo);
|
||||
return py_obj;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
wrap_reference(git_reference * c_reference)
|
||||
{
|
||||
Reference *py_reference=NULL;
|
||||
|
||||
py_reference = (Reference *)ReferenceType.tp_alloc(&ReferenceType, 0);
|
||||
if (py_reference == NULL)
|
||||
return NULL;
|
||||
py_reference->reference = c_reference;
|
||||
return (PyObject *)py_reference;
|
||||
}
|
||||
|
||||
static int
|
||||
py_str_to_git_oid(PyObject *py_str, git_oid *oid) {
|
||||
char *hex;
|
||||
@ -224,34 +265,6 @@ Repository_contains(Repository *self, PyObject *value) {
|
||||
return git_odb_exists(git_repository_database(self->repo), &oid);
|
||||
}
|
||||
|
||||
static Object *
|
||||
wrap_object(git_object *obj, Repository *repo) {
|
||||
Object *py_obj = NULL;
|
||||
switch (git_object_type(obj)) {
|
||||
case GIT_OBJ_COMMIT:
|
||||
py_obj = (Object*)CommitType.tp_alloc(&CommitType, 0);
|
||||
break;
|
||||
case GIT_OBJ_TREE:
|
||||
py_obj = (Object*)TreeType.tp_alloc(&TreeType, 0);
|
||||
break;
|
||||
case GIT_OBJ_BLOB:
|
||||
py_obj = (Object*)BlobType.tp_alloc(&BlobType, 0);
|
||||
break;
|
||||
case GIT_OBJ_TAG:
|
||||
py_obj = (Object*)TagType.tp_alloc(&TagType, 0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (!py_obj)
|
||||
return (Object*)PyErr_NoMemory();
|
||||
|
||||
py_obj->obj = obj;
|
||||
py_obj->repo = repo;
|
||||
Py_INCREF(repo);
|
||||
return py_obj;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Repository_getitem(Repository *self, PyObject *value) {
|
||||
git_oid oid;
|
||||
@ -273,7 +286,8 @@ Repository_getitem(Repository *self, PyObject *value) {
|
||||
}
|
||||
|
||||
static int
|
||||
Repository_read_raw(git_odb_object **obj, git_repository *repo, const git_oid *oid) {
|
||||
Repository_read_raw(git_odb_object **obj, git_repository *repo,
|
||||
const git_oid *oid) {
|
||||
return git_odb_read(obj, git_repository_database(repo), oid);
|
||||
}
|
||||
|
||||
@ -485,6 +499,87 @@ Repository_create_tag(Repository *self, PyObject *args) {
|
||||
return PyString_FromStringAndSize(hex, GIT_OID_HEXSZ);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Repository_listall_references(Repository *self, PyObject *args)
|
||||
{
|
||||
git_strarray c_result;
|
||||
PyObject *py_result, *py_string;
|
||||
unsigned index;
|
||||
int err;
|
||||
|
||||
/* 1- Get the C result */
|
||||
/* TODO We can choose an other option (instead of GIT_REF_LISTALL) */
|
||||
err = git_reference_listall (&c_result, self->repo, GIT_REF_LISTALL);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
/* 2- Create a new PyTuple */
|
||||
if ( (py_result = PyTuple_New(c_result.count)) == NULL) {
|
||||
git_strarray_free(&c_result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 3- Fill it */
|
||||
for (index=0; index < c_result.count; index++) {
|
||||
if ((py_string = PyString_FromString( (c_result.strings)[index] ))
|
||||
== NULL) {
|
||||
Py_XDECREF(py_result);
|
||||
git_strarray_free(&c_result);
|
||||
return NULL;
|
||||
}
|
||||
PyTuple_SET_ITEM(py_result, index, py_string);
|
||||
}
|
||||
|
||||
/* 4- Destroy the c_result */
|
||||
git_strarray_free(&c_result);
|
||||
|
||||
/* 5- And return the py_result */
|
||||
return py_result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Repository_lookup_reference(Repository *self, PyObject *py_name)
|
||||
{
|
||||
git_reference *c_reference;
|
||||
char *c_name;
|
||||
int err;
|
||||
|
||||
/* 1- Get the C name */
|
||||
c_name = PyString_AsString(py_name);
|
||||
if (c_name == NULL)
|
||||
return NULL;
|
||||
|
||||
/* 2- Lookup */
|
||||
err = git_reference_lookup(&c_reference, self->repo, c_name);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
/* 3- Make an instance of Reference and return it */
|
||||
return wrap_reference(c_reference);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Repository_create_reference(Repository *self, PyObject *args)
|
||||
{
|
||||
git_reference *c_reference;
|
||||
char *c_name;
|
||||
git_oid oid;
|
||||
int err;
|
||||
|
||||
/* 1- Get the C variables */
|
||||
if (!PyArg_ParseTuple(args, "sO&", &c_name,
|
||||
py_str_to_git_oid, &oid))
|
||||
return NULL;
|
||||
|
||||
/* 2- Create the reference */
|
||||
err = git_reference_create_oid(&c_reference, self->repo, c_name, &oid);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
/* 3- Make an instance of Reference and return it */
|
||||
return wrap_reference(c_reference);
|
||||
}
|
||||
|
||||
static PyMethodDef Repository_methods[] = {
|
||||
{"create_commit", (PyCFunction)Repository_create_commit, METH_VARARGS,
|
||||
"Create a new commit object, return its SHA."},
|
||||
@ -494,6 +589,15 @@ static PyMethodDef Repository_methods[] = {
|
||||
"Generator that traverses the history starting from the given commit."},
|
||||
{"read", (PyCFunction)Repository_read, METH_O,
|
||||
"Read raw object data from the repository."},
|
||||
{"listall_references", (PyCFunction)Repository_listall_references,
|
||||
METH_NOARGS,
|
||||
"Return a list with all the references that can be found in a "
|
||||
"repository."},
|
||||
{"lookup_reference", (PyCFunction)Repository_lookup_reference, METH_O,
|
||||
"Lookup a reference by its name in a repository."},
|
||||
{"create_reference", (PyCFunction)Repository_create_reference, METH_VARARGS,
|
||||
"Create a new reference \"name\" that points to the object given by its "
|
||||
"\"sha\"."},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
@ -530,7 +634,7 @@ static PyTypeObject RepositoryType = {
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
&Repository_as_sequence, /* tp_as_sequence */
|
||||
&Repository_as_mapping, /* tp_as_mapping */
|
||||
@ -1712,6 +1816,131 @@ static PyTypeObject WalkerType = {
|
||||
0, /* tp_new */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
Reference_resolve(Reference *self, PyObject *args)
|
||||
{
|
||||
git_reference *c_reference;
|
||||
int err;
|
||||
|
||||
/* 1- Resolve */
|
||||
err = git_reference_resolve(&c_reference, self->reference);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
/* 2- Make an instance of Reference and return it */
|
||||
return wrap_reference(c_reference);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Reference_get_target(Reference *self, PyObject *args)
|
||||
{
|
||||
const char * c_name;
|
||||
|
||||
/* 1- Get the target */
|
||||
c_name = git_reference_target(self->reference);
|
||||
if (c_name == NULL) {
|
||||
PyErr_Format(PyExc_ValueError, "Not target available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 2- Make a PyString and return it */
|
||||
return PyString_FromString(c_name);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Reference_get_name(Reference *self) {
|
||||
const char *c_name;
|
||||
|
||||
c_name = git_reference_name(self->reference);
|
||||
return PyString_FromString(c_name);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Reference_get_sha(Reference *self) {
|
||||
char hex[GIT_OID_HEXSZ];
|
||||
const git_oid *oid;
|
||||
|
||||
/* 1- Get the oid (only for "direct" references) */
|
||||
oid = git_reference_oid(self->reference);
|
||||
if (oid == NULL)
|
||||
{
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"sha is only available if the reference is direct (i.e. not symbolic)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 2- Convert and return it */
|
||||
git_oid_fmt(hex, oid);
|
||||
return PyString_FromStringAndSize(hex, GIT_OID_HEXSZ);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Reference_get_type(Reference *self) {
|
||||
git_rtype c_type;
|
||||
|
||||
c_type = git_reference_type(self->reference);
|
||||
return PyInt_FromLong(c_type);
|
||||
}
|
||||
|
||||
static PyMethodDef Reference_methods[] = {
|
||||
{"resolve", (PyCFunction)Reference_resolve, METH_NOARGS,
|
||||
"Resolve a symbolic reference and return a direct reference"},
|
||||
{"get_target", (PyCFunction)Reference_get_target, METH_NOARGS,
|
||||
"Get full name to the reference pointed by this symbolic reference."},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyGetSetDef Reference_getseters[] = {
|
||||
{"name", (getter)Reference_get_name, NULL,
|
||||
"The full name of a reference.", NULL},
|
||||
{"sha", (getter)Reference_get_sha, NULL, "hex SHA", NULL},
|
||||
{"type", (getter)Reference_get_type, NULL,
|
||||
"type (GIT_REF_OID, GIT_REF_SYMBOLIC or GIT_REF_PACKED).", NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyTypeObject ReferenceType = {
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0, /* ob_size */
|
||||
"pygit2.Reference", /* tp_name */
|
||||
sizeof(Reference), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
0, /* 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 */
|
||||
"Reference", /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
Reference_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
Reference_getseters, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
init_repository(PyObject *self, PyObject *args) {
|
||||
git_repository *repo;
|
||||
@ -1786,6 +2015,9 @@ initpygit2(void)
|
||||
WalkerType.tp_new = PyType_GenericNew;
|
||||
if (PyType_Ready(&WalkerType) < 0)
|
||||
return;
|
||||
ReferenceType.tp_new = PyType_GenericNew;
|
||||
if (PyType_Ready(&ReferenceType) < 0)
|
||||
return;
|
||||
|
||||
m = Py_InitModule3("pygit2", module_methods,
|
||||
"Python bindings for libgit2.");
|
||||
@ -1823,6 +2055,9 @@ initpygit2(void)
|
||||
Py_INCREF(&IndexEntryType);
|
||||
PyModule_AddObject(m, "IndexEntry", (PyObject *)&IndexEntryType);
|
||||
|
||||
Py_INCREF(&ReferenceType);
|
||||
PyModule_AddObject(m, "Reference", (PyObject *)&ReferenceType);
|
||||
|
||||
PyModule_AddIntConstant(m, "GIT_OBJ_ANY", GIT_OBJ_ANY);
|
||||
PyModule_AddIntConstant(m, "GIT_OBJ_COMMIT", GIT_OBJ_COMMIT);
|
||||
PyModule_AddIntConstant(m, "GIT_OBJ_TREE", GIT_OBJ_TREE);
|
||||
@ -1832,4 +2067,7 @@ initpygit2(void)
|
||||
PyModule_AddIntConstant(m, "GIT_SORT_TOPOLOGICAL", GIT_SORT_TOPOLOGICAL);
|
||||
PyModule_AddIntConstant(m, "GIT_SORT_TIME", GIT_SORT_TIME);
|
||||
PyModule_AddIntConstant(m, "GIT_SORT_REVERSE", GIT_SORT_REVERSE);
|
||||
PyModule_AddIntConstant(m,"GIT_REF_OID", GIT_REF_OID);
|
||||
PyModule_AddIntConstant(m,"GIT_REF_SYMBOLIC", GIT_REF_SYMBOLIC);
|
||||
PyModule_AddIntConstant(m,"GIT_REF_PACKED", GIT_REF_PACKED);
|
||||
}
|
||||
|
@ -35,7 +35,8 @@ import sys
|
||||
import unittest
|
||||
|
||||
|
||||
names = ['blob', 'commit', 'index', 'repository', 'revwalk', 'tag', 'tree']
|
||||
names = ['blob', 'commit', 'index', 'refs', 'repository', 'revwalk', 'tag',
|
||||
'tree']
|
||||
def test_suite():
|
||||
modules = ['test.test_%s' % n for n in names]
|
||||
return unittest.defaultTestLoader.loadTestsFromNames(modules)
|
||||
|
97
test/test_refs.py
Normal file
97
test/test_refs.py
Normal file
@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2011 Itaapy
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License, version 2,
|
||||
# as published by the Free Software Foundation.
|
||||
#
|
||||
# In addition to the permissions in the GNU General Public License,
|
||||
# the authors give you unlimited permission to link the compiled
|
||||
# version of this file into combinations with other programs,
|
||||
# and to distribute those combinations without any restriction
|
||||
# coming from the use of this file. (The General Public License
|
||||
# restrictions do apply in other respects; for example, they cover
|
||||
# modification of the file, and distribution when not linked into
|
||||
# a combined executable.)
|
||||
#
|
||||
# This file is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
"""Tests for reference objects."""
|
||||
|
||||
|
||||
__author__ = 'david.versmisse@itaapy.com (David Versmisse)'
|
||||
|
||||
import unittest
|
||||
import utils
|
||||
from pygit2 import GIT_REF_OID
|
||||
|
||||
|
||||
|
||||
LAST_COMMIT = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98'
|
||||
|
||||
|
||||
|
||||
class ReferencesTest(utils.RepoTestCase):
|
||||
|
||||
def test_list_all_references(self):
|
||||
self.assertEqual(self.repo.listall_references(),
|
||||
('refs/heads/i18n', 'refs/heads/master'))
|
||||
|
||||
|
||||
def test_lookup_reference(self):
|
||||
repo = self.repo
|
||||
|
||||
# Raise KeyError ?
|
||||
self.assertRaises(KeyError, repo.lookup_reference, 'foo')
|
||||
|
||||
# Test a lookup
|
||||
reference = repo.lookup_reference('refs/heads/master')
|
||||
self.assertEqual(reference.name, 'refs/heads/master')
|
||||
|
||||
|
||||
def test_reference_get_sha(self):
|
||||
reference = self.repo.lookup_reference('refs/heads/master')
|
||||
self.assertEqual(reference.sha, LAST_COMMIT)
|
||||
|
||||
|
||||
def test_reference_get_type(self):
|
||||
reference = self.repo.lookup_reference('refs/heads/master')
|
||||
self.assertEqual(reference.type, GIT_REF_OID)
|
||||
|
||||
|
||||
def test_get_target(self):
|
||||
# XXX We must have a symbolic reference to make this test
|
||||
pass
|
||||
|
||||
|
||||
def test_reference_resolve(self):
|
||||
# XXX We must have a symbolic reference to make a better test
|
||||
reference = self.repo.lookup_reference('refs/heads/master')
|
||||
reference = reference.resolve()
|
||||
self.assertEqual(reference.type, GIT_REF_OID)
|
||||
self.assertEqual(reference.sha, LAST_COMMIT)
|
||||
|
||||
|
||||
def test_create_reference(self):
|
||||
# We add a tag as a new reference that points to "origin/master"
|
||||
reference = self.repo.create_reference('refs/tags/version1',
|
||||
LAST_COMMIT)
|
||||
refs = self.repo.listall_references()
|
||||
self.assertTrue('refs/tags/version1' in refs)
|
||||
reference = self.repo.lookup_reference('refs/tags/version1')
|
||||
self.assertEqual(reference.sha, LAST_COMMIT)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user