diff --git a/src/pygit2.c b/src/pygit2.c index 97eb421..7c72e50 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -63,6 +63,7 @@ extern PyTypeObject RefLogEntryType; extern PyTypeObject BranchType; extern PyTypeObject SignatureType; extern PyTypeObject RemoteType; +extern PyTypeObject RefspecType; extern PyTypeObject NoteType; extern PyTypeObject NoteIterType; extern PyTypeObject BlameType; @@ -420,6 +421,11 @@ moduleinit(PyObject* m) /* Remotes */ INIT_TYPE(RemoteType, NULL, NULL) ADD_TYPE(m, Remote) + INIT_TYPE(RefspecType, NULL, NULL) + ADD_TYPE(m, Refspec) + /* Direction for the refspec */ + ADD_CONSTANT_INT(m, GIT_DIRECTION_FETCH) + ADD_CONSTANT_INT(m, GIT_DIRECTION_PUSH) /* Blame */ INIT_TYPE(BlameType, NULL, NULL) diff --git a/src/remote.c b/src/remote.c index b5d7059..265828d 100644 --- a/src/remote.c +++ b/src/remote.c @@ -36,6 +36,181 @@ extern PyObject *GitError; extern PyTypeObject RepositoryType; +extern PyTypeObject RefspecType; + +Refspec * +wrap_refspec(const Remote *owner, const git_refspec *refspec) +{ + Refspec *spec; + + spec = PyObject_New(Refspec, &RefspecType); + if (!spec) + return NULL; + + Py_INCREF(owner); + spec->owner = owner; + spec->refspec = refspec; + + return spec; +} + +PyDoc_STRVAR(Refspec_direction__doc__, + "The direction of this refspec (fetch or push)"); + +PyObject * +Refspec_direction__get__(Refspec *self) +{ + return Py_BuildValue("i", git_refspec_direction(self->refspec)); +} + +PyDoc_STRVAR(Refspec_src__doc__, "Source or lhs of the refspec"); + +PyObject * +Refspec_src__get__(Refspec *self) +{ + return to_unicode(git_refspec_src(self->refspec), NULL, NULL); +} + +PyDoc_STRVAR(Refspec_dst__doc__, "Destination or rhs of the refspec"); + +PyObject * +Refspec_dst__get__(Refspec *self) +{ + return to_unicode(git_refspec_dst(self->refspec), NULL, NULL); +} + +PyDoc_STRVAR(Refspec_string__doc__, "String used to create this refspec"); + +PyObject * +Refspec_string__get__(Refspec *self) +{ + return to_unicode(git_refspec_string(self->refspec), NULL, NULL); +} + +PyDoc_STRVAR(Refspec_force__doc__, + "Whether this refspec allows non-fast-forward updates"); + +PyObject * +Refspec_force__get__(Refspec *self) +{ + if (git_refspec_force(self->refspec)) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(Refspec_src_matches__doc__, + "src_matches(str) -> Bool\n" + "\n" + "Returns whether the string matches the source refspec\n"); + +PyObject * +Refspec_src_matches(Refspec *self, PyObject *py_str) +{ + char *str; + int res; + + str = py_str_to_c_str(py_str, NULL); + if (!str) + return NULL; + + res = git_refspec_src_matches(self->refspec, str); + free(str); + + if (res) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(Refspec_dst_matches__doc__, + "dst_matches(str) -> Bool\n" + "\n" + "Returns whether the string matches the destination refspec\n"); + +PyObject * +Refspec_dst_matches(Refspec *self, PyObject *py_str) +{ + char *str; + int res; + + str = py_str_to_c_str(py_str, NULL); + if (!str) + return NULL; + + res = git_refspec_dst_matches(self->refspec, str); + free(str); + + if (res) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +PyMethodDef Refspec_methods[] = { + METHOD(Refspec, src_matches, METH_O), + METHOD(Refspec, dst_matches, METH_O), + {NULL} +}; + +PyGetSetDef Refspec_getseters[] = { + GETTER(Refspec, direction), + GETTER(Refspec, src), + GETTER(Refspec, dst), + GETTER(Refspec, string), + GETTER(Refspec, force), + {NULL} +}; + +static void +Refspec_dealloc(Refspec *self) +{ + Py_CLEAR(self->owner); + PyObject_Del(self); +} + +PyDoc_STRVAR(Refspec__doc__, "Refspec object."); + +PyTypeObject RefspecType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pygit2.Refspec", /* tp_name */ + sizeof(Remote), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Refspec_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 | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Refspec__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Refspec_methods, /* tp_methods */ + 0, /* tp_members */ + Refspec_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 */ +}; PyObject * Remote_init(Remote *self, PyObject *args, PyObject *kwds) @@ -306,8 +481,7 @@ Remote_get_refspec(Remote *self, PyObject *value) return NULL; } - return Py_BuildValue("(ss)", git_refspec_src(refspec), - git_refspec_dst(refspec)); + return (PyObject*) wrap_refspec(self, refspec); } diff --git a/src/types.h b/src/types.h index 94ce790..63a5672 100644 --- a/src/types.h +++ b/src/types.h @@ -198,6 +198,12 @@ typedef struct { /* git_remote */ SIMPLE_TYPE(Remote, git_remote, remote) +/* git_refspec */ +typedef struct { + PyObject_HEAD + const Remote *owner; + const git_refspec *refspec; +} Refspec; /* git_blame */ SIMPLE_TYPE(Blame, git_blame, blame) diff --git a/test/test_remote.py b/test/test_remote.py index 741cd50..981e3bd 100644 --- a/test/test_remote.py +++ b/test/test_remote.py @@ -39,6 +39,7 @@ REMOTE_FETCHSPEC_DST = 'refs/remotes/origin/*' REMOTE_REPO_OBJECTS = 30 REMOTE_REPO_BYTES = 2758 +ORIGIN_REFSPEC = '+refs/heads/*:refs/remotes/origin/*' class RepositoryTest(utils.RepoTestCase): def test_remote_create(self): @@ -80,13 +81,17 @@ class RepositoryTest(utils.RepoTestCase): self.assertEqual(remote.refspec_count, 1) refspec = remote.get_refspec(0) - self.assertEqual(refspec[0], REMOTE_FETCHSPEC_SRC) - self.assertEqual(refspec[1], REMOTE_FETCHSPEC_DST) + self.assertEqual(refspec.src, REMOTE_FETCHSPEC_SRC) + self.assertEqual(refspec.dst, REMOTE_FETCHSPEC_DST) + self.assertEqual(True, refspec.force) + self.assertEqual(ORIGIN_REFSPEC, refspec.string) self.assertEqual(list, type(remote.get_fetch_refspecs())) self.assertEqual(1, len(remote.get_fetch_refspecs())) - self.assertEqual('+refs/heads/*:refs/remotes/origin/*', - remote.get_fetch_refspecs()[0]) + self.assertEqual(ORIGIN_REFSPEC, remote.get_fetch_refspecs()[0]) + + self.assertTrue(refspec.src_matches('refs/heads/master')) + self.assertTrue(refspec.dst_matches('refs/remotes/origin/master')) self.assertEqual(list, type(remote.get_push_refspecs())) self.assertEqual(0, len(remote.get_push_refspecs()))