diff --git a/include/pygit2/note.h b/include/pygit2/note.h new file mode 100644 index 0000000..a4ded36 --- /dev/null +++ b/include/pygit2/note.h @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2013 The pygit2 contributors + * + * 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. + */ + +#ifndef INCLUDE_pygit2_note_h +#define INCLUDE_pygit2_note_h + +#define PY_SSIZE_T_CLEAN +#include +#include + +PyObject* wrap_note(Repository* repo, git_oid* annotated_id, const char* ref); + +#endif diff --git a/include/pygit2/types.h b/include/pygit2/types.h index 27bccda..218a8e6 100644 --- a/include/pygit2/types.h +++ b/include/pygit2/types.h @@ -67,6 +67,21 @@ typedef struct { typedef struct { PyObject_HEAD + Repository *repo; + git_note *note; + char* annotated_id; +} Note; + +typedef struct { + PyObject_HEAD + Repository *repo; + git_note_iterator* iter; + char* ref; +} NoteIter; + +typedef struct { + PyObject_HEAD + Diff* diff; size_t i; size_t n; diff --git a/src/note.c b/src/note.c new file mode 100644 index 0000000..110ca8b --- /dev/null +++ b/src/note.c @@ -0,0 +1,236 @@ +/* + * Copyright 2010-2013 The pygit2 contributors + * + * 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. + */ + +#define PY_SSIZE_T_CLEAN +#include +#include +#include +#include +#include +#include +#include + +extern PyTypeObject SignatureType; + +PyDoc_STRVAR(Note_remove__doc__, + "Removes a note for an annotated object"); + +PyObject* +Note_remove(Note *self, PyObject* args) +{ + char *ref = "refs/notes/commits"; + int err = GIT_ERROR; + git_oid annotated_id; + Signature *py_author, *py_committer; + + if (!PyArg_ParseTuple(args, "O!O!|s", + &SignatureType, &py_author, + &SignatureType, &py_committer, + &ref)) + return NULL; + + err = git_oid_fromstr(&annotated_id, self->annotated_id); + if (err < 0) + return Error_set(err); + + err = git_note_remove(self->repo->repo, ref, py_author->signature, + py_committer->signature, &annotated_id); + if (err < 0) + return Error_set(err); + + Py_RETURN_NONE; +} + + +PyDoc_STRVAR(Note_oid__doc__, + "Gets the id of the blob containing the note message\n"); + +PyObject * +Note_oid__get__(Note *self) +{ + return git_oid_to_py_str(git_note_oid(self->note)); +} + + +PyDoc_STRVAR(Note_message__doc__, + "Gets message of the note\n"); + +PyObject * +Note_message__get__(Note *self) +{ + return PyUnicode_FromString(git_note_message(self->note)); +} + + +static void +Note_dealloc(Note *self) +{ + Py_CLEAR(self->repo); + free(self->annotated_id); + git_note_free(self->note); + PyObject_Del(self); +} + + +PyMethodDef Note_methods[] = { + METHOD(Note, remove, METH_VARARGS), + {NULL} +}; + +PyMemberDef Note_members[] = { + MEMBER(Note, annotated_id, T_STRING, "id of the annotated object."), + {NULL} +}; + +PyGetSetDef Note_getseters[] = { + GETTER(Note, message), + GETTER(Note, oid), + {NULL} +}; + +PyDoc_STRVAR(Note__doc__, "Note object."); + +PyTypeObject NoteType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pygit2.Note", /* tp_name */ + sizeof(Note), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Note_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 */ + Note__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Note_methods, /* tp_methods */ + Note_members, /* tp_members */ + Note_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 * +NoteIter_iternext(NoteIter *self) +{ + int err; + git_oid note_id, annotated_id; + + err = git_note_next(¬e_id, &annotated_id, self->iter); + if (err < 0) + return Error_set(err); + + return (PyObject*) wrap_note(self->repo, &annotated_id, self->ref); +} + +void +NoteIter_dealloc(NoteIter *self) +{ + git_note_iterator_free(self->iter); + PyObject_Del(self); +} + + +PyDoc_STRVAR(NoteIter__doc__, "Note iterator object."); + +PyTypeObject NoteIterType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pygit2.NoteIter", /* tp_name */ + sizeof(NoteIter), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)NoteIter_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 */ + NoteIter__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc) NoteIter_iternext, /* tp_iternext */ +}; + + +PyObject* +wrap_note(Repository* repo, git_oid* annotated_id, const char* ref) +{ + Note* py_note = NULL; + int err = GIT_ERROR; + + py_note = (Note*) PyType_GenericNew(&NoteType, NULL, NULL); + if (py_note == NULL) { + PyErr_NoMemory(); + return NULL; + } + + err = git_note_read(&py_note->note, repo->repo, ref, annotated_id); + if (err < 0) + return Error_set(err); + + py_note->repo = repo; + Py_INCREF(repo); + py_note->annotated_id = git_oid_allocfmt(annotated_id); + + return (PyObject*) py_note; +} + + diff --git a/src/pygit2.c b/src/pygit2.c index 09573ef..e730bf7 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -60,6 +60,8 @@ extern PyTypeObject RefLogIterType; extern PyTypeObject RefLogEntryType; extern PyTypeObject SignatureType; extern PyTypeObject RemoteType; +extern PyTypeObject NoteType; +extern PyTypeObject NoteIterType; @@ -236,6 +238,11 @@ moduleinit(PyObject* m) if (PyType_Ready(&RemoteType) < 0) return NULL; + if (PyType_Ready(&NoteType) < 0) + return NULL; + if (PyType_Ready(&NoteIterType) < 0) + return NULL; + Py_INCREF(GitError); PyModule_AddObject(m, "GitError", GitError); @@ -281,6 +288,9 @@ moduleinit(PyObject* m) Py_INCREF(&RemoteType); PyModule_AddObject(m, "Remote", (PyObject *)&RemoteType); + Py_INCREF(&NoteType); + PyModule_AddObject(m, "Note", (PyObject *)&NoteType); + 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); diff --git a/src/repository.c b/src/repository.c index 87ff395..e487fc9 100644 --- a/src/repository.c +++ b/src/repository.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,8 @@ extern PyTypeObject ConfigType; extern PyTypeObject DiffType; extern PyTypeObject RemoteType; extern PyTypeObject ReferenceType; +extern PyTypeObject NoteType; +extern PyTypeObject NoteIterType; git_otype int_to_loose_object_type(int type_id) @@ -1132,6 +1135,93 @@ Repository_checkout(Repository *self, PyObject *args, PyObject *kw) } +PyDoc_STRVAR(Repository_notes__doc__, ""); + +PyObject * +Repository_notes(Repository *self, PyObject* args) +{ + NoteIter *iter = NULL; + char *ref = "refs/notes/commits"; + int err = GIT_ERROR; + + if (!PyArg_ParseTuple(args, "|s", &ref)) + return NULL; + + iter = PyObject_New(NoteIter, &NoteIterType); + if (iter != NULL) { + iter->repo = self; + iter->ref = ref; + + err = git_note_iterator_new(&iter->iter, self->repo, iter->ref); + if (err == GIT_OK) { + Py_INCREF(self); + return (PyObject*)iter; + } + } + + return Error_set(err); + +} + + +PyDoc_STRVAR(Repository_create_note__doc__, + "create_note(message, author, committer, annotated_id [,ref, force]) -> ID\n" + "\n" + "Create a new note for an object, return its SHA-ID." + "If no ref is given 'refs/notes/commits' will be used."); + +PyObject * +Repository_create_note(Repository *self, PyObject* args) +{ + git_oid note_id, annotated_id; + char *annotated = NULL, *message = NULL, *ref = "refs/notes/commits"; + int err = GIT_ERROR; + unsigned int force = 0; + Signature *py_author, *py_committer; + + if (!PyArg_ParseTuple(args, "sO!O!s|si", + &message, + &SignatureType, &py_author, + &SignatureType, &py_committer, + &annotated, &ref, &force)) + return NULL; + + err = git_oid_fromstr(&annotated_id, annotated); + if (err < 0) + return Error_set(err); + + err = git_note_create(¬e_id, self->repo, py_author->signature, + py_committer->signature, ref, + &annotated_id, message, force); + if (err < 0) + return Error_set(err); + + return git_oid_to_python(note_id.id); +} + + +PyDoc_STRVAR(Repository_lookup_note__doc__, + "lookup_note(annotated_id [, ref]) -> Note\n" + "\n" + "Lookup a note for an annotated object in a repository."); + +PyObject * +Repository_lookup_note(Repository *self, PyObject* args) +{ + git_oid annotated_id; + char* annotated = NULL, *ref = "refs/notes/commits"; + int err; + + if (!PyArg_ParseTuple(args, "s|s", &annotated, &ref)) + return NULL; + + err = git_oid_fromstr(&annotated_id, annotated); + if (err < 0) + return Error_set(err); + + return (PyObject*) wrap_note(self, &annotated_id, ref); +} + PyMethodDef Repository_methods[] = { METHOD(Repository, create_blob, METH_VARARGS), METHOD(Repository, create_blob_fromfile, METH_VARARGS), @@ -1150,6 +1240,9 @@ PyMethodDef Repository_methods[] = { METHOD(Repository, status_file, METH_O), METHOD(Repository, create_remote, METH_VARARGS), METHOD(Repository, checkout, METH_VARARGS|METH_KEYWORDS), + METHOD(Repository, notes, METH_VARARGS), + METHOD(Repository, create_note, METH_VARARGS), + METHOD(Repository, lookup_note, METH_VARARGS), {NULL} };