From 858adab759a8852ef4db819c3f5e6fd3b170edb2 Mon Sep 17 00:00:00 2001 From: David Versmisse <david.versmisse@itaapy.com> Date: Wed, 27 Apr 2011 09:31:04 +0200 Subject: [PATCH] Implement the References (part II) --- pygit2.c | 163 +++++++++++++++++++++++++++++++++++++++------- test/test_refs.py | 73 +++++++++++++++++++-- 2 files changed, 208 insertions(+), 28 deletions(-) diff --git a/pygit2.c b/pygit2.c index ad79352..192ad05 100644 --- a/pygit2.c +++ b/pygit2.c @@ -500,26 +500,29 @@ Repository_create_tag(Repository *self, PyObject *args) { } static PyObject * -Repository_listall_references(Repository *self, PyObject *args) -{ +Repository_listall_references(Repository *self, PyObject *args) { + unsigned list_flags=GIT_REF_LISTALL; 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); + /* 1- Get list_flags */ + if (!PyArg_ParseTuple(args, "|I", &list_flags)) + return NULL; + + /* 2- Get the C result */ + err = git_reference_listall(&c_result, self->repo, list_flags); if (err < 0) return Error_set(err); - /* 2- Create a new PyTuple */ + /* 3- Create a new PyTuple */ if ( (py_result = PyTuple_New(c_result.count)) == NULL) { git_strarray_free(&c_result); return NULL; } - /* 3- Fill it */ + /* 4- Fill it */ for (index=0; index < c_result.count; index++) { if ((py_string = PyString_FromString( (c_result.strings)[index] )) == NULL) { @@ -530,16 +533,15 @@ Repository_listall_references(Repository *self, PyObject *args) PyTuple_SET_ITEM(py_result, index, py_string); } - /* 4- Destroy the c_result */ + /* 5- Destroy the c_result */ git_strarray_free(&c_result); - /* 5- And return the py_result */ + /* 6- And return the py_result */ return py_result; } static PyObject * -Repository_lookup_reference(Repository *self, PyObject *py_name) -{ +Repository_lookup_reference(Repository *self, PyObject *py_name) { git_reference *c_reference; char *c_name; int err; @@ -559,8 +561,7 @@ Repository_lookup_reference(Repository *self, PyObject *py_name) } static PyObject * -Repository_create_reference(Repository *self, PyObject *args) -{ +Repository_create_reference(Repository *self, PyObject *args) { git_reference *c_reference; char *c_name; git_oid oid; @@ -580,6 +581,39 @@ Repository_create_reference(Repository *self, PyObject *args) return wrap_reference(c_reference); } +static PyObject * +Repository_create_symbolic_reference(Repository *self, PyObject *args) { + git_reference *c_reference; + char *c_name, *c_target; + int err; + + /* 1- Get the C variables */ + if (!PyArg_ParseTuple(args, "ss", &c_name, &c_target)) + return NULL; + + /* 2- Create the reference */ + err = git_reference_create_symbolic(&c_reference, self->repo, c_name, + c_target); + if (err < 0) + return Error_set(err); + + /* 3- Make an instance of Reference and return it */ + return wrap_reference(c_reference); +} + +static PyObject * +Repository_packall_references(Repository *self, PyObject *args) { + int err; + + /* 1- Pack */ + err = git_reference_packall(self->repo); + if (err < 0) + return Error_set(err); + + /* 2- Return None */ + Py_RETURN_NONE; +} + static PyMethodDef Repository_methods[] = { {"create_commit", (PyCFunction)Repository_create_commit, METH_VARARGS, "Create a new commit object, return its SHA."}, @@ -590,7 +624,7 @@ static PyMethodDef Repository_methods[] = { {"read", (PyCFunction)Repository_read, METH_O, "Read raw object data from the repository."}, {"listall_references", (PyCFunction)Repository_listall_references, - METH_NOARGS, + METH_VARARGS, "Return a list with all the references that can be found in a " "repository."}, {"lookup_reference", (PyCFunction)Repository_lookup_reference, METH_O, @@ -598,6 +632,12 @@ static PyMethodDef Repository_methods[] = { {"create_reference", (PyCFunction)Repository_create_reference, METH_VARARGS, "Create a new reference \"name\" that points to the object given by its " "\"sha\"."}, + {"create_symbolic_reference", + (PyCFunction)Repository_create_symbolic_reference, METH_VARARGS, + "Create a new symbolic reference \"name\" that points to the reference " + "\"target\"."}, + {"packall_references", (PyCFunction)Repository_packall_references, + METH_NOARGS, "Pack all the loose references in the repository."}, {NULL} }; @@ -1817,8 +1857,42 @@ static PyTypeObject WalkerType = { }; static PyObject * -Reference_resolve(Reference *self, PyObject *args) -{ +Reference_delete(Reference *self, PyObject *args) { + int err; + + /* 1- Delete the reference */ + err = git_reference_delete(self->reference); + if (err < 0) + return Error_set(err); + + /* 2- Invalidate the pointer */ + self->reference = NULL; + + /* 3- Return None */ + Py_RETURN_NONE; +} + +static PyObject * +Reference_rename(Reference *self, PyObject *py_name) { + char *c_name; + int err; + + /* 1- Get the C name */ + c_name = PyString_AsString(py_name); + if (c_name == NULL) + return NULL; + + /* 2- Rename */ + err = git_reference_rename(self->reference, c_name); + if (err < 0) + return Error_set(err); + + /* 3- Return None */ + Py_RETURN_NONE; +} + +static PyObject * +Reference_resolve(Reference *self, PyObject *args) { git_reference *c_reference; int err; @@ -1832,8 +1906,7 @@ Reference_resolve(Reference *self, PyObject *args) } static PyObject * -Reference_get_target(Reference *self, PyObject *args) -{ +Reference_get_target(Reference *self) { const char * c_name; /* 1- Get the target */ @@ -1847,6 +1920,27 @@ Reference_get_target(Reference *self, PyObject *args) return PyString_FromString(c_name); } +static int +Reference_set_target(Reference *self, PyObject *py_name) { + char *c_name; + int err; + + /* 1- Get the C name */ + c_name = PyString_AsString(py_name); + if (c_name == NULL) + return -1; + + /* 2- Set the new target */ + err = git_reference_set_target(self->reference, c_name); + if (err < 0) { + Error_set(err); + return -1; + } + + /* 3- All OK */ + return 0; +} + static PyObject * Reference_get_name(Reference *self) { const char *c_name; @@ -1874,6 +1968,26 @@ Reference_get_sha(Reference *self) { return PyString_FromStringAndSize(hex, GIT_OID_HEXSZ); } +static int +Reference_set_sha(Reference *self, PyObject *py_sha) { + git_oid oid; + int err; + + /* 1- Get the oid from the py_sha */ + if (!py_str_to_git_oid(py_sha, &oid)) + return -1; + + /* 2- Set the oid */ + err = git_reference_set_oid (self->reference, &oid); + if (err < 0) { + Error_set(err); + return -1; + } + + /* 3- All OK */ + return 0; +} + static PyObject * Reference_get_type(Reference *self) { git_rtype c_type; @@ -1883,17 +1997,22 @@ Reference_get_type(Reference *self) { } static PyMethodDef Reference_methods[] = { + {"delete", (PyCFunction)Reference_delete, METH_NOARGS, + "Delete this reference. It will no longer be valid!"}, + {"rename", (PyCFunction)Reference_rename, METH_O, + "Rename the reference."}, {"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."}, + "Resolve a symbolic reference and return a direct 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}, + {"sha", (getter)Reference_get_sha, (setter)Reference_set_sha, "hex SHA", + NULL}, + {"target", (getter)Reference_get_target, (setter)Reference_set_target, + "target", NULL}, {"type", (getter)Reference_get_type, NULL, "type (GIT_REF_OID, GIT_REF_SYMBOLIC or GIT_REF_PACKED).", NULL}, {NULL} diff --git a/test/test_refs.py b/test/test_refs.py index 52e615e..7c4d328 100644 --- a/test/test_refs.py +++ b/test/test_refs.py @@ -33,7 +33,7 @@ __author__ = 'david.versmisse@itaapy.com (David Versmisse)' import unittest import utils -from pygit2 import GIT_REF_OID +from pygit2 import GIT_REF_OID, GIT_REF_SYMBOLIC @@ -44,9 +44,23 @@ LAST_COMMIT = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98' class ReferencesTest(utils.RepoTestCase): def test_list_all_references(self): - self.assertEqual(self.repo.listall_references(), + repo = self.repo + + # Without argument + self.assertEqual(repo.listall_references(), ('refs/heads/i18n', 'refs/heads/master')) + # We add a symbolic reference + reference = repo.create_symbolic_reference('refs/tags/version1', + 'refs/heads/master') + self.assertEqual(repo.listall_references(), + ('refs/heads/i18n', 'refs/heads/master', + 'refs/tags/version1')) + + # Now we list only the symbolic references + self.assertEqual(repo.listall_references(GIT_REF_SYMBOLIC), + ('refs/tags/version1', )) + def test_lookup_reference(self): repo = self.repo @@ -64,19 +78,54 @@ class ReferencesTest(utils.RepoTestCase): self.assertEqual(reference.sha, LAST_COMMIT) + def test_reference_set_sha(self): + NEW_COMMIT = '5ebeeebb320790caf276b9fc8b24546d63316533' + reference = self.repo.lookup_reference('refs/heads/master') + reference.sha = NEW_COMMIT + self.assertEqual(reference.sha, NEW_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 + reference = self.repo.lookup_reference('HEAD') + self.assertEqual(reference.target, 'refs/heads/master') + + + def test_set_target(self): + reference = self.repo.lookup_reference('HEAD') + self.assertEqual(reference.target, 'refs/heads/master') + reference.target = 'refs/heads/i18n' + self.assertEqual(reference.target, 'refs/heads/i18n') + + + def test_delete(self): + repo = self.repo + + # We add a tag as a new reference that points to "origin/master" + reference = repo.create_reference('refs/tags/version1', LAST_COMMIT) + self.assertTrue('refs/tags/version1' in repo.listall_references()) + + # And we delete it + reference.delete() + self.assertFalse('refs/tags/version1' in repo.listall_references()) + + + def test_rename(self): + # We add a tag as a new reference that points to "origin/master" + reference = self.repo.create_reference('refs/tags/version1', + LAST_COMMIT) + self.assertEqual(reference.name, 'refs/tags/version1') + reference.rename('refs/tags/version2') + self.assertEqual(reference.name, 'refs/tags/version2') 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 = self.repo.lookup_reference('HEAD') + self.assertEqual(reference.type, GIT_REF_SYMBOLIC) reference = reference.resolve() self.assertEqual(reference.type, GIT_REF_OID) self.assertEqual(reference.sha, LAST_COMMIT) @@ -92,6 +141,18 @@ class ReferencesTest(utils.RepoTestCase): self.assertEqual(reference.sha, LAST_COMMIT) + def test_create_symbolic_reference(self): + # We add a tag as a new symbolic reference that always points to + # "refs/heads/master" + reference = self.repo.create_symbolic_reference('refs/tags/beta', + 'refs/heads/master') + self.assertEqual(reference.type, GIT_REF_SYMBOLIC) + self.assertEqual(reference.target, 'refs/heads/master') + + + def test_packall_references(self): + self.repo.packall_references() + if __name__ == '__main__': unittest.main()