From a19a3d2515765b1170fa42753b3bf6a853dec35e Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Mon, 4 Mar 2013 10:39:44 +0100 Subject: [PATCH 01/11] diff - use old fashioned iterators instead of callback based ones --- include/pygit2/types.h | 10 +- src/diff.c | 281 +++++++++++++++-------------------------- src/pygit2.c | 7 - test/test_diff.py | 2 +- 4 files changed, 107 insertions(+), 193 deletions(-) diff --git a/include/pygit2/types.h b/include/pygit2/types.h index 9c8a429..7625b89 100644 --- a/include/pygit2/types.h +++ b/include/pygit2/types.h @@ -76,17 +76,17 @@ typedef struct { typedef struct { PyObject_HEAD - char *header; + const char *header; int old_start; int old_lines; - PyObject *old_oid; + char* old_oid; int old_mode; - char* old_file; + const char* old_file; int new_start; int new_lines; - PyObject *new_oid; + char* new_oid; int new_mode; - char* new_file; + const char* new_file; PyObject *data; } Hunk; diff --git a/src/diff.c b/src/diff.c index 50f3b51..7440013 100644 --- a/src/diff.c +++ b/src/diff.c @@ -40,204 +40,125 @@ extern PyTypeObject IndexType; extern PyTypeObject DiffType; extern PyTypeObject HunkType; -static int diff_data_cb( - const git_diff_delta *delta, - const git_diff_range *range, - char line_origin, - const char *content, - size_t content_len, - void *cb_data) -{ - PyObject *hunks, *data; - Hunk *hunk; - Py_ssize_t size; - - hunks = PyDict_GetItemString(cb_data, "hunks"); - if (hunks == NULL) - return -1; - - size = PyList_Size(hunks); - hunk = (Hunk *)PyList_GetItem(hunks, size - 1); - if (hunk == NULL) - return -1; - - data = Py_BuildValue("(s#,i)", - content, content_len, - line_origin - ); - PyList_Append(hunk->data, data); - Py_DECREF(data); - - return 0; -} - -static int diff_hunk_cb( - const git_diff_delta *delta, - const git_diff_range *range, - const char *header, - size_t header_len, - void *cb_data) -{ - PyObject *hunks; - Hunk *hunk; - int len; - char* old_path = NULL, *new_path = NULL; - char oid[GIT_OID_HEXSZ]; - - - hunks = PyDict_GetItemString(cb_data, "hunks"); - if (hunks == NULL) { - hunks = PyList_New(0); - PyDict_SetItemString(cb_data, "hunks", hunks); - Py_DECREF(hunks); - } - - hunk = (Hunk*)PyType_GenericNew(&HunkType, NULL, NULL); - if (hunk == NULL) - return -1; - - hunk->old_start = range->old_start; - hunk->old_lines = range->old_lines; - hunk->new_start = range->new_start; - hunk->new_lines = range->new_lines; - - hunk->old_mode = delta->old_file.mode; - hunk->new_mode = delta->new_file.mode; - - git_oid_fmt(oid, &delta->old_file.oid); - hunk->old_oid = PyUnicode_FromStringAndSize(oid, GIT_OID_HEXSZ); - git_oid_fmt(oid, &delta->new_file.oid); - hunk->new_oid = PyUnicode_FromStringAndSize(oid, GIT_OID_HEXSZ); - - if (header) { - hunk->header = malloc(header_len+1); - - if (hunk->header == NULL) - return -1; - - memcpy(hunk->header, header, header_len); - hunk->header[header_len] = '\0'; - } - - if (delta->old_file.path != NULL) { - len = strlen(delta->old_file.path) + 1; - old_path = malloc(sizeof(char) * len); - if (old_path == NULL) { - free(hunk->header); - hunk->header = NULL; - return -1; - } - - memcpy(old_path, delta->old_file.path, len); - hunk->old_file = old_path; - } else { - hunk->old_file = ""; - } - - if (delta->new_file.path != NULL) { - len = strlen(delta->new_file.path) + 1; - new_path = malloc(sizeof(char) * len); - if (new_path == NULL) { - free(hunk->header); - free(old_path); - return -1; - } - - memcpy(new_path, delta->new_file.path, len); - hunk->new_file = new_path; - } else { - hunk->new_file = ""; - } - - if (hunk->data == NULL) - hunk->data = PyList_New(0); - - if (PyList_Append(hunks, (PyObject *)hunk) == 0) { - Py_DECREF(hunk); - } - else { - return -1; - } - - return 0; -}; - -static int -diff_file_cb(const git_diff_delta *delta, float progress, void *cb_data) -{ - PyObject *files, *file; - - if (delta->old_file.path != NULL && delta->new_file.path != NULL) { - files = PyDict_GetItemString(cb_data, "files"); - - if (files == NULL) { - files = PyList_New(0); - PyDict_SetItemString(cb_data, "files", files); - Py_DECREF(files); - } - - file = Py_BuildValue("(s,s,i,i)", - delta->old_file.path, - delta->new_file.path, - delta->status, - delta->similarity - ); - - /* If success */ - if (PyList_Append(files, file) == 0) - Py_DECREF(file); - } - - return 0; -} - PyDoc_STRVAR(Diff_changes__doc__, "Raw changes."); PyObject * Diff_changes__get__(Diff *self) { + const git_diff_delta* delta; + const git_diff_range* range; + git_diff_patch* patch; + char buffer[41]; + const char* hunk_content; + size_t amounts, hunk_amounts, i, j, hunk_header_len, hunk_lines; + PyObject *file, *files, *hunks; + Hunk *py_hunk; + int err; if (self->diff_changes == NULL) { self->diff_changes = PyDict_New(); - git_diff_foreach( - self->diff, - &diff_file_cb, - &diff_hunk_cb, - &diff_data_cb, - self->diff_changes - ); + files = PyList_New(0); + PyDict_SetItemString(self->diff_changes, "files", files); + + hunks = PyList_New(0); + PyDict_SetItemString(self->diff_changes, "hunks", hunks); + + amounts = git_diff_num_deltas(self->diff); + for (i = 0; i < amounts ; ++i) { + err = git_diff_get_patch(&patch, &delta, self->diff, i); + + if (err == GIT_OK) { + file = Py_BuildValue("(s,s,i,i)", + delta->old_file.path, + delta->new_file.path, + delta->status, + delta->similarity + ); + + PyList_Append(files, file); + } + + hunk_amounts = git_diff_patch_num_hunks(patch); + + for (j=0; j < hunk_amounts; ++j) { + err = git_diff_patch_get_hunk(&range, &hunk_content, + &hunk_header_len, &hunk_lines, patch, j); + + if (err == GIT_OK) { + py_hunk = (Hunk*)PyType_GenericNew(&HunkType, NULL, NULL); + if (py_hunk != NULL) { + py_hunk->old_file = delta->old_file.path; + py_hunk->new_file = delta->new_file.path; + py_hunk->header = hunk_content; + py_hunk->old_start = range->old_start; + py_hunk->old_lines = range->old_lines; + py_hunk->new_start = range->new_start; + py_hunk->new_lines = range->new_lines; + + git_oid_fmt(buffer, &delta->old_file.oid); + py_hunk->old_oid = calloc(41, sizeof(char)); + memcpy(py_hunk->old_oid, buffer, 40); + + git_oid_fmt(buffer, &delta->new_file.oid); + py_hunk->new_oid = calloc(41, sizeof(char)); + memcpy(py_hunk->new_oid, buffer, 40); + + py_hunk->data = Py_BuildValue("(s#,i)", + hunk_content, hunk_header_len, + hunk_lines); + PyList_Append(hunks, (PyObject*) py_hunk); + } + } + } + } } return PyDict_Copy(self->diff_changes); } -static int diff_print_cb( - const git_diff_delta *delta, - const git_diff_range *range, - char usage, - const char *line, - size_t line_len, - void *cb_data) -{ - PyObject *data = PyBytes_FromStringAndSize(line, line_len); - PyBytes_ConcatAndDel((PyObject **)cb_data, data); - - return 0; -} - PyDoc_STRVAR(Diff_patch__doc__, "Patch."); PyObject * Diff_patch__get__(Diff *self) { - PyObject *patch = PyBytes_FromString(""); + const git_diff_delta* delta; + git_diff_patch* patch; + char* str = NULL, *buffer = NULL; + int err; + size_t i, len, num, size; + PyObject *py_patch; - git_diff_print_patch(self->diff, &diff_print_cb, (void*) &patch); + num = git_diff_num_deltas(self->diff); + for (i = 0; i < num ; ++i) { + err = git_diff_get_patch(&patch, &delta, self->diff, i); - return patch; + if (err < 0 || git_diff_patch_to_str(&str, patch) < 0) + return Error_set(err); + + len = strlen(str) + 1; + size = (buffer == NULL) ? len : strlen(buffer) + len; + buffer = realloc(buffer, size * sizeof(char)); + + if (len == size) + strcpy(buffer, str); + else + strcat(buffer, str); + + free(str); + } + + py_patch = PyUnicode_FromString(buffer); + + if (buffer != NULL) + free(buffer); + + if (patch != NULL) + git_diff_patch_free; + + return py_patch; } static int @@ -269,13 +190,13 @@ static void Hunk_dealloc(Hunk *self) { if (self->header != NULL) { - free(self->header); + free((void*) self->header); } if (self->new_file != NULL) { - free(self->new_file); + free((void*) self->new_file); } if (self->old_file != NULL) { - free(self->old_file); + free((void*) self->old_file); } Py_XDECREF(self->old_oid); Py_XDECREF(self->new_oid); @@ -289,12 +210,12 @@ PyMemberDef Hunk_members[] = { MEMBER(Hunk, old_lines, T_INT, "Old lines."), MEMBER(Hunk, old_mode, T_INT, "Old mode."), MEMBER(Hunk, old_file, T_STRING, "Old file."), - MEMBER(Hunk, old_oid, T_OBJECT, "Old oid."), + MEMBER(Hunk, old_oid, T_STRING, "Old oid."), MEMBER(Hunk, new_start, T_INT, "New start."), MEMBER(Hunk, new_lines, T_INT, "New lines."), MEMBER(Hunk, new_mode, T_INT, "New mode."), MEMBER(Hunk, new_file, T_STRING, "New file."), - MEMBER(Hunk, new_oid, T_OBJECT, "New oid."), + MEMBER(Hunk, new_oid, T_STRING, "New oid."), MEMBER(Hunk, data, T_OBJECT, "Data."), {NULL} }; diff --git a/src/pygit2.c b/src/pygit2.c index 6727e65..f2acbf0 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -343,13 +343,6 @@ moduleinit(PyObject* m) PyModule_AddIntConstant(m, "GIT_DIFF_FIND_AND_BREAK_REWRITES", GIT_DIFF_FIND_AND_BREAK_REWRITES); - /* Flags for diffed files */ - PyModule_AddIntConstant(m, "GIT_DIFF_FLAG_BINARY", GIT_DIFF_FLAG_BINARY); - PyModule_AddIntConstant(m, "GIT_DIFF_FLAG_NOT_BINARY", - GIT_DIFF_FLAG_NOT_BINARY); - PyModule_AddIntConstant(m, "GIT_DIFF_FLAG_VALID_OID", - GIT_DIFF_FLAG_VALID_OID); - /* Flags for diff deltas */ PyModule_AddIntConstant(m, "GIT_DELTA_UNMODIFIED", GIT_DELTA_UNMODIFIED); PyModule_AddIntConstant(m, "GIT_DELTA_ADDED", GIT_DELTA_ADDED); diff --git a/test/test_diff.py b/test/test_diff.py index ff3a54c..03f49e5 100644 --- a/test/test_diff.py +++ b/test/test_diff.py @@ -41,7 +41,7 @@ COMMIT_SHA1_3 = '2cdae28389c059815e951d0bb9eed6533f61a46b' COMMIT_SHA1_4 = 'ccca47fbb26183e71a7a46d165299b84e2e6c0b3' COMMIT_SHA1_5 = '056e626e51b1fc1ee2182800e399ed8d84c8f082' -PATCH = b"""diff --git a/a b/a +PATCH = """diff --git a/a b/a index 7f129fd..af431f2 100644 --- a/a +++ b/a From 4b89994ff4c51ef3e13726c6f7c7d7585f3c0059 Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Mon, 4 Mar 2013 11:18:11 +0100 Subject: [PATCH 02/11] memory allocation helper macros --- include/pygit2/utils.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/pygit2/utils.h b/include/pygit2/utils.h index e9768b1..161b194 100644 --- a/include/pygit2/utils.h +++ b/include/pygit2/utils.h @@ -119,5 +119,21 @@ char * py_str_to_c_str(PyObject *value, const char *encoding); #define MEMBER(type, attr, attr_type, docstr)\ {#attr, attr_type, offsetof(type, attr), 0, PyDoc_STR(docstr)} +/* Helpers for memory allocation */ + + +#define MALLOC(ptr, size, label) \ + ptr = realloc(ptr, size * sizeof(char));\ + if (ptr == NULL) {\ + err = GIT_ERROR;\ + giterr_set_oom();\ + goto label;\ + }\ + +#define FREE(to_free)\ + if (to_free != NULL) { free(to_free); to_free = NULL; } +#define FREE_FUNC(to_free, fnct)\ + if (to_free != NULL) { fnct(to_free); to_free = NULL; } + #endif From 996663c97d4ed3e44c0611f4d08d488e1a72e3da Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Mon, 4 Mar 2013 11:18:58 +0100 Subject: [PATCH 03/11] diff - use new memory alloc macros --- src/diff.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/diff.c b/src/diff.c index 7440013..de19fdd 100644 --- a/src/diff.c +++ b/src/diff.c @@ -127,7 +127,7 @@ Diff_patch__get__(Diff *self) const git_diff_delta* delta; git_diff_patch* patch; char* str = NULL, *buffer = NULL; - int err; + int err = 0; size_t i, len, num, size; PyObject *py_patch; @@ -135,30 +135,29 @@ Diff_patch__get__(Diff *self) for (i = 0; i < num ; ++i) { err = git_diff_get_patch(&patch, &delta, self->diff, i); - if (err < 0 || git_diff_patch_to_str(&str, patch) < 0) - return Error_set(err); + if (err < 0 || (err = git_diff_patch_to_str(&str, patch)) < 0) + goto error; len = strlen(str) + 1; size = (buffer == NULL) ? len : strlen(buffer) + len; - buffer = realloc(buffer, size * sizeof(char)); + MALLOC(buffer, size, error); if (len == size) strcpy(buffer, str); else strcat(buffer, str); - free(str); + FREE(str); } py_patch = PyUnicode_FromString(buffer); - if (buffer != NULL) - free(buffer); +error: + FREE(str); + FREE(buffer); + FREE_FUNC(patch, git_diff_patch_free); - if (patch != NULL) - git_diff_patch_free; - - return py_patch; + return (err < 0) ? Error_set(err) : py_patch; } static int From 2771c8a15069709c78698de0987ba132ce4facdd Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Mon, 4 Mar 2013 15:44:17 +0100 Subject: [PATCH 04/11] added assertAll and assertAny for test cases --- test/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/utils.py b/test/utils.py index f034b94..0cf41d5 100644 --- a/test/utils.py +++ b/test/utils.py @@ -83,6 +83,11 @@ class NoRepoTestCase(unittest.TestCase): except: self.assertEqual(exc_class, sys.exc_info()[0]) + def assertAll(self, func, entries): + return self.assertTrue(all(func(x) for x in entries)) + + def assertAny(self, func, entries): + return self.assertTrue(any(func(x) for x in entries)) def assertRaisesWithArg(self, exc_class, arg, func, *args, **kwargs): try: From 204fbd9cbb93bf1210b5233993c24626a55f5981 Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Mon, 4 Mar 2013 15:45:17 +0100 Subject: [PATCH 05/11] diff - use generator instead of list --- include/pygit2/types.h | 14 ++- src/diff.c | 253 +++++++++++++++++++++++++++++++---------- src/index.c | 2 +- src/pygit2.c | 6 + src/tree.c | 3 +- test/test_diff.py | 39 +++---- 6 files changed, 230 insertions(+), 87 deletions(-) diff --git a/include/pygit2/types.h b/include/pygit2/types.h index 7625b89..dfd08c0 100644 --- a/include/pygit2/types.h +++ b/include/pygit2/types.h @@ -59,14 +59,20 @@ OBJECT_STRUCT(Index, git_index, index) OBJECT_STRUCT(Walker, git_revwalk, walk) OBJECT_STRUCT(Config, git_config, config) OBJECT_STRUCT(Remote, git_remote, remote) +OBJECT_STRUCT(Diff, git_diff_list, list) typedef struct { PyObject_HEAD - Repository *repo; - git_diff_list *diff; - PyObject *diff_changes; -} Diff; + git_diff_list* list; + size_t i; + size_t n; +} DiffIter; +typedef struct { + PyObject_HEAD + PyObject* files; + PyObject* hunks; +} DiffEntry; typedef struct { PyObject_HEAD diff --git a/src/diff.c b/src/diff.c index de19fdd..c9b4983 100644 --- a/src/diff.c +++ b/src/diff.c @@ -40,35 +40,29 @@ extern PyTypeObject IndexType; extern PyTypeObject DiffType; extern PyTypeObject HunkType; +PyTypeObject DiffEntryType; -PyDoc_STRVAR(Diff_changes__doc__, "Raw changes."); - -PyObject * -Diff_changes__get__(Diff *self) +PyObject* +diff_get_patch_byindex(git_diff_list* list, size_t i) { const git_diff_delta* delta; const git_diff_range* range; - git_diff_patch* patch; + git_diff_patch* patch = NULL; + char buffer[41]; const char* hunk_content; - size_t amounts, hunk_amounts, i, j, hunk_header_len, hunk_lines; - PyObject *file, *files, *hunks; - Hunk *py_hunk; + size_t hunk_amounts, j, hunk_header_len, hunk_lines; int err; - if (self->diff_changes == NULL) { - self->diff_changes = PyDict_New(); + PyObject *file; + Hunk *py_hunk; + DiffEntry *py_entry = NULL; - files = PyList_New(0); - PyDict_SetItemString(self->diff_changes, "files", files); - - hunks = PyList_New(0); - PyDict_SetItemString(self->diff_changes, "hunks", hunks); - - amounts = git_diff_num_deltas(self->diff); - for (i = 0; i < amounts ; ++i) { - err = git_diff_get_patch(&patch, &delta, self->diff, i); + err = git_diff_get_patch(&patch, &delta, list, i); + if (err == GIT_OK) { + py_entry = (DiffEntry*) INSTANCIATE_CLASS(DiffEntryType, NULL); + if (py_entry != NULL) { if (err == GIT_OK) { file = Py_BuildValue("(s,s,i,i)", delta->old_file.path, @@ -77,7 +71,7 @@ Diff_changes__get__(Diff *self) delta->similarity ); - PyList_Append(files, file); + PyList_Append((PyObject*) py_entry->files, file); } hunk_amounts = git_diff_patch_num_hunks(patch); @@ -108,16 +102,147 @@ Diff_changes__get__(Diff *self) py_hunk->data = Py_BuildValue("(s#,i)", hunk_content, hunk_header_len, hunk_lines); - PyList_Append(hunks, (PyObject*) py_hunk); + + PyList_Append((PyObject*) py_entry->hunks, + (PyObject*) py_hunk); } } } } } - return PyDict_Copy(self->diff_changes); + if (err < 0) + return Error_set(err); + + return (PyObject*) py_entry; } +PyObject * +DiffEntry_call(DiffEntry *self, PyObject *args, PyObject *kwds) +{ + self->files = PyList_New(0); + if (self->files == NULL) { + Py_XDECREF(self); + return NULL; + } + + self->hunks = PyList_New(0); + if (self->hunks == NULL) { + Py_XDECREF(self); + return NULL; + } + + return (PyObject*) self; +} + +static void +DiffEntry_dealloc(DiffEntry *self) +{ + Py_DECREF((PyObject*) self->files); + Py_DECREF((PyObject*) self->hunks); + PyObject_Del(self); +} + +PyMemberDef DiffEntry_members[] = { + MEMBER(DiffEntry, files, T_OBJECT, "files"), + MEMBER(DiffEntry, hunks, T_OBJECT, "hunks"), + {NULL} +}; + +PyDoc_STRVAR(DiffEntry__doc__, "Diff entry object."); + +PyTypeObject DiffEntryType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pygit2.DiffEntry", /* tp_name */ + sizeof(DiffEntry), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)DiffEntry_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 */ + (ternaryfunc) DiffEntry_call, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + DiffEntry__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + DiffEntry_members, /* tp_members */ + 0, /* 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 * +DiffIter_iternext(DiffIter *self) +{ + if (self->i < self->n) + return diff_get_patch_byindex(self->list, self->i++); + + PyErr_SetNone(PyExc_StopIteration); + return NULL; +} + +void +DiffIter_dealloc(DiffIter *self) +{ + Py_CLEAR(self->list); + PyObject_Del(self); +} + + +PyDoc_STRVAR(DiffIter__doc__, "Diff iterator object."); + +PyTypeObject DiffIterType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pygit2.DiffIter", /* tp_name */ + sizeof(DiffIter), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)DiffIter_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 */ + DiffIter__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc) DiffIter_iternext, /* tp_iternext */ +}; + PyDoc_STRVAR(Diff_patch__doc__, "Patch."); @@ -129,11 +254,11 @@ Diff_patch__get__(Diff *self) char* str = NULL, *buffer = NULL; int err = 0; size_t i, len, num, size; - PyObject *py_patch; + PyObject *py_patch = NULL; - num = git_diff_num_deltas(self->diff); + num = git_diff_num_deltas(self->list); for (i = 0; i < num ; ++i) { - err = git_diff_get_patch(&patch, &delta, self->diff, i); + err = git_diff_get_patch(&patch, &delta, self->list, i); if (err < 0 || (err = git_diff_patch_to_str(&str, patch)) < 0) goto error; @@ -160,30 +285,6 @@ error: return (err < 0) ? Error_set(err) : py_patch; } -static int -Hunk_init(Hunk *self, PyObject *args, PyObject *kwds) -{ - self->header = NULL; - - self->old_file = NULL; - self->old_start = 0; - self->old_lines = 0; - - self->new_file = NULL; - self->new_start = 0; - self->new_lines = 0; - - self->old_oid = NULL; - self->new_oid = NULL; - - self->data = PyList_New(0); - if (self->data == NULL) { - Py_XDECREF(self); - return -1; - } - - return 0; -} static void Hunk_dealloc(Hunk *self) @@ -258,7 +359,7 @@ PyTypeObject HunkType = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)Hunk_init, /* tp_init */ + 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; @@ -277,15 +378,14 @@ Diff_merge(Diff *self, PyObject *args) if (!PyArg_ParseTuple(args, "O!", &DiffType, &py_diff)) return NULL; + if (py_diff->repo->repo != self->repo->repo) return Error_set(GIT_ERROR); - err = git_diff_merge(self->diff, py_diff->diff); + err = git_diff_merge(self->list, py_diff->list); if (err < 0) return Error_set(err); - Py_XDECREF(self->diff_changes); - self->diff_changes = NULL; Py_RETURN_NONE; } @@ -304,30 +404,61 @@ Diff_find_similar(Diff *self, PyObject *args) if (!PyArg_ParseTuple(args, "|i", &opts.flags)) return NULL; - err = git_diff_find_similar(self->diff, &opts); + err = git_diff_find_similar(self->list, &opts); if (err < 0) return Error_set(err); - Py_XDECREF(self->diff_changes); - self->diff_changes = NULL; Py_RETURN_NONE; } +PyObject * +Diff_iter(Diff *self) +{ + DiffIter *iter; + + iter = PyObject_New(DiffIter, &DiffIterType); + if (iter) { + Py_INCREF(self); + iter->list = self->list; + iter->i = 0; + iter->n = git_diff_num_deltas(self->list); + } + return (PyObject*)iter; +} + +PyObject * +Diff_getitem(Diff *self, PyObject *value) +{ + size_t i; + + if (PyLong_Check(value) < 0) + return NULL; + + i = PyLong_AsUnsignedLong(value); + + return diff_get_patch_byindex(self->list, i); +} + + static void Diff_dealloc(Diff *self) { - git_diff_list_free(self->diff); + git_diff_list_free(self->list); Py_XDECREF(self->repo); - Py_XDECREF(self->diff_changes); PyObject_Del(self); } PyGetSetDef Diff_getseters[] = { - GETTER(Diff, changes), GETTER(Diff, patch), {NULL} }; +PyMappingMethods Diff_as_mapping = { + 0, /* mp_length */ + (binaryfunc)Diff_getitem, /* mp_subscript */ + 0, /* mp_ass_subscript */ +}; + static PyMethodDef Diff_methods[] = { METHOD(Diff, merge, METH_VARARGS), METHOD(Diff, find_similar, METH_VARARGS), @@ -350,7 +481,7 @@ PyTypeObject DiffType = { 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ + &Diff_as_mapping, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ @@ -363,7 +494,7 @@ PyTypeObject DiffType = { 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ + (getiterfunc)Diff_iter, /* tp_iter */ 0, /* tp_iternext */ Diff_methods, /* tp_methods */ 0, /* tp_members */ diff --git a/src/index.c b/src/index.c index dfcb355..79554fc 100644 --- a/src/index.c +++ b/src/index.c @@ -158,7 +158,7 @@ Index_diff(Index *self, PyObject *args) if (py_diff) { Py_INCREF(self->repo); py_diff->repo = self->repo; - py_diff->diff = diff; + py_diff->list = diff; } return (PyObject*)py_diff; diff --git a/src/pygit2.c b/src/pygit2.c index f2acbf0..1c3f42b 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -41,6 +41,8 @@ extern PyTypeObject RepositoryType; extern PyTypeObject ObjectType; extern PyTypeObject CommitType; extern PyTypeObject DiffType; +extern PyTypeObject DiffIterType; +extern PyTypeObject DiffEntryType; extern PyTypeObject HunkType; extern PyTypeObject TreeType; extern PyTypeObject TreeBuilderType; @@ -197,6 +199,10 @@ moduleinit(PyObject* m) if (PyType_Ready(&DiffType) < 0) return NULL; + if (PyType_Ready(&DiffIterType) < 0) + return NULL; + if (PyType_Ready(&DiffEntryType) < 0) + return NULL; if (PyType_Ready(&HunkType) < 0) return NULL; diff --git a/src/tree.c b/src/tree.c index 0b22eee..7493299 100644 --- a/src/tree.c +++ b/src/tree.c @@ -346,8 +346,7 @@ Tree_diff(Tree *self, PyObject *args) if (py_diff) { Py_INCREF(self->repo); py_diff->repo = self->repo; - py_diff->diff = diff; - py_diff->diff_changes = NULL; + py_diff->list = diff; } return (PyObject*)py_diff; diff --git a/test/test_diff.py b/test/test_diff.py index 03f49e5..9b3b3d2 100644 --- a/test/test_diff.py +++ b/test/test_diff.py @@ -31,6 +31,7 @@ from __future__ import absolute_import from __future__ import unicode_literals import unittest import pygit2 +import itertools from pygit2 import GIT_DIFF_INCLUDE_UNMODIFIED from . import utils @@ -86,16 +87,16 @@ class DiffDirtyTest(utils.DirtyRepoTestCase): head = repo[repo.lookup_reference('HEAD').resolve().oid] diff = head.tree.diff(repo.index) - files = [x[1] for x in diff.changes['files']] - self.assertEqual(DIFF_INDEX_EXPECTED, files) + files = [[x[0] for x in entry.files] for entry in diff] + self.assertEqual(DIFF_INDEX_EXPECTED, list(itertools.chain(*files))) def test_workdir_to_tree(self): repo = self.repo head = repo[repo.lookup_reference('HEAD').resolve().oid] diff = head.tree.diff() - files = [x[1] for x in diff.changes['files']] - self.assertEqual(DIFF_WORKDIR_EXPECTED, files) + files = [[x[0] for x in entry.files] for entry in diff] + self.assertEqual(DIFF_WORKDIR_EXPECTED, list(itertools.chain(*files))) class DiffTest(utils.BareRepoTestCase): @@ -109,8 +110,8 @@ class DiffTest(utils.BareRepoTestCase): head = repo[repo.lookup_reference('HEAD').resolve().oid] diff = head.tree.diff(repo.index) - files = [x[0].split('/')[0] for x in diff.changes['files']] - self.assertEqual([x.name for x in head.tree], files) + files = [[x[0].split('/')[0] for x in entry.files] for entry in diff] + self.assertEqual([x.name for x in head.tree], list(itertools.chain(*files))) def test_diff_tree(self): commit_a = self.repo[COMMIT_SHA1_1] @@ -121,10 +122,10 @@ class DiffTest(utils.BareRepoTestCase): # self.assertIsNotNone is 2.7 only self.assertTrue(diff is not None) # self.assertIn is 2.7 only - self.assertTrue(('a', 'a', 3, 0) in diff.changes['files']) - self.assertEqual(2, len(diff.changes['hunks'])) + self.assertAny(lambda x: ('a', 'a', 3, 0) in x.files, diff) + self.assertEqual(2, sum(map(lambda x: len(x.hunks), diff))) - hunk = diff.changes['hunks'][0] + hunk = diff[0].hunks[0] self.assertEqual(hunk.old_start, 1) self.assertEqual(hunk.old_lines, 1) self.assertEqual(hunk.new_start, 1) @@ -144,11 +145,11 @@ class DiffTest(utils.BareRepoTestCase): pygit2.GIT_DIFF_IGNORE_WHITESPACE_EOL]: diff = commit_c.tree.diff(commit_d.tree, opt) self.assertTrue(diff is not None) - self.assertEqual(0, len(diff.changes.get('hunks', list()))) + self.assertEqual(0, len(diff[0].hunks)) diff = commit_c.tree.diff(commit_d.tree) self.assertTrue(diff is not None) - self.assertEqual(1, len(diff.changes.get('hunks', list()))) + self.assertEqual(1, len(diff[0].hunks)) def test_diff_merge(self): commit_a = self.repo[COMMIT_SHA1_1] @@ -164,15 +165,15 @@ class DiffTest(utils.BareRepoTestCase): self.assertTrue(diff_c is not None) # assertIn / assertNotIn are 2.7 only - self.assertTrue(('b', 'b', 3, 0) not in diff_b.changes['files']) - self.assertTrue(('b', 'b', 3, 0) in diff_c.changes['files']) + self.assertAll(lambda x:('b', 'b', 3, 0) not in x.files, diff_b) + self.assertAny(lambda x:('b', 'b', 3, 0) in x.files, diff_c) diff_b.merge(diff_c) # assertIn is 2.7 only - self.assertTrue(('b', 'b', 3, 0) in diff_b.changes['files']) + self.assertAny(lambda x:('b', 'b', 3, 0) in x.files, diff_b) - hunk = diff_b.changes['hunks'][1] + hunk = diff_b[1].hunks[0] self.assertEqual(hunk.old_start, 1) self.assertEqual(hunk.old_lines, 1) self.assertEqual(hunk.new_start, 1) @@ -196,13 +197,13 @@ class DiffTest(utils.BareRepoTestCase): commit_b = self.repo[COMMIT_SHA1_2] diff = commit_a.tree.diff(commit_b.tree) - self.assertEqual(diff.changes['hunks'][0].header, "@@ -1 +1 @@\n") + self.assertEqual(diff[0].hunks[0].header, "@@ -1 +1 @@\n") def test_diff_oids(self): commit_a = self.repo[COMMIT_SHA1_1] commit_b = self.repo[COMMIT_SHA1_2] diff = commit_a.tree.diff(commit_b.tree) - hunk = diff.changes['hunks'][0] + hunk = diff[0].hunks[0] self.assertEqual(hunk.old_oid, '7f129fd57e31e935c6d60a0c794efe4e6927664b') self.assertEqual(hunk.new_oid, @@ -215,9 +216,9 @@ class DiffTest(utils.BareRepoTestCase): #~ Must pass GIT_DIFF_INCLUDE_UNMODIFIED if you expect to emulate #~ --find-copies-harder during rename transformion... diff = commit_a.tree.diff(commit_b.tree, GIT_DIFF_INCLUDE_UNMODIFIED) - self.assertFalse(('a', 'a.copy', 5, 100) in diff.changes['files']) + self.assertFalse(('a', 'a.copy', 5, 100) in diff[0].files) diff.find_similar(pygit2.GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED) - self.assertTrue(('a', 'a.copy', 5, 100) in diff.changes['files']) + self.assertAny(lambda x:('a', 'a.copy', 5, 100) in x.files, diff) if __name__ == '__main__': unittest.main() From da4abb78cb3033ecb0ea00e965c137f2e97ba7d2 Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Mon, 4 Mar 2013 18:37:45 +0100 Subject: [PATCH 06/11] added test data for diff.find_similiar --- .../10/2374bdb1e8efca5e66cded18fd8f30571654a5 | Bin 0 -> 209 bytes .../11/19926b06311143cab273f0af84eae77f5b3462 | Bin 0 -> 136 bytes .../19/bf31524643d743751b09cf719456914bbd8bd5 | Bin 0 -> 136 bytes .../55/60f04f38a674decf34d16d7c7476642fa03794 | Bin 0 -> 129 bytes .../78/4855caf26449a1914d2cf62d12b9374d76ae78 | Bin 0 -> 176 bytes .../f5/e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87 | Bin 0 -> 172 bytes test/data/testrepo.git/refs/heads/master | 2 +- test/test_diff.py | 13 ++++++++----- test/test_remote.py | 4 ++-- test/test_repository.py | 4 ++-- 10 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 test/data/testrepo.git/objects/10/2374bdb1e8efca5e66cded18fd8f30571654a5 create mode 100644 test/data/testrepo.git/objects/11/19926b06311143cab273f0af84eae77f5b3462 create mode 100644 test/data/testrepo.git/objects/19/bf31524643d743751b09cf719456914bbd8bd5 create mode 100644 test/data/testrepo.git/objects/55/60f04f38a674decf34d16d7c7476642fa03794 create mode 100644 test/data/testrepo.git/objects/78/4855caf26449a1914d2cf62d12b9374d76ae78 create mode 100644 test/data/testrepo.git/objects/f5/e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87 diff --git a/test/data/testrepo.git/objects/10/2374bdb1e8efca5e66cded18fd8f30571654a5 b/test/data/testrepo.git/objects/10/2374bdb1e8efca5e66cded18fd8f30571654a5 new file mode 100644 index 0000000000000000000000000000000000000000..4cb6eb7dde59cc87984dbcd34132839d06296f3f GIT binary patch literal 209 zcmV;?051P{0qs&dP6ROwrREgx0HZ08C@AUaIDwN`Bkv~hkk}*b?eT!bR&W9eH-2AP zPE`}0U!ES`bZ~?0(;JFb9hhRE#Aw8w(~E6rqN$-P;W;qiKP0 z+rvcqA;r7F4V6-afbBbg(P--gs`BBtFyKKE_TzVG_1&CSyc!N33f6h5DQBN2-*EA1 zisCV6Xa2&OFgSTz@gAj-qbK1?vtaYYV;kI;Xd6icqpLIud{WQmp`V7|Z?XP?{om>S LGwb6g(ihq?OFd`O literal 0 HcmV?d00001 diff --git a/test/data/testrepo.git/objects/11/19926b06311143cab273f0af84eae77f5b3462 b/test/data/testrepo.git/objects/11/19926b06311143cab273f0af84eae77f5b3462 new file mode 100644 index 0000000000000000000000000000000000000000..8ac529e9ac5413e8aa6e578eb38d6061a627552f GIT binary patch literal 136 zcmV;30C)d*0V^p=O;s>7HD)k0FfcPQQAlJc?_iw&`pFlj$Ynl3vu3>wlS{d~7bdBf zoL^9hPel^L^lPFI_o&-Aob)Qn5P81S{&tkKnTY`qC?qo^`rlm4>HSUO)#U#F2l#5G qLVnD;05v)%zbG}AK|r}=@5UGJPsOF3eJk;|-ymEpWGMjU?LoUvmqAAW literal 0 HcmV?d00001 diff --git a/test/data/testrepo.git/objects/19/bf31524643d743751b09cf719456914bbd8bd5 b/test/data/testrepo.git/objects/19/bf31524643d743751b09cf719456914bbd8bd5 new file mode 100644 index 0000000000000000000000000000000000000000..af11713b32bf8b0e22f687aa1a74440110a4c8a3 GIT binary patch literal 136 zcmV;30C)d*0V^p=O;s>7HD)k0FfcPQQAlJc?_iw&`pFlj$Ynl3vu3>wlS{d~7bdBf zoL^9hPel^L^lPFI_o&-Aob)Qn5P81S{&tkKnTY`qC?qo^`rlm4>HSUO)#U#F2l#5G qLVnD;05v+Zptv-bK|r}=@5UGJPsOF3eJk;|-ymEpWGMjWKtalDDM67v}71LW? z%IJMtU|f1yQv@(^v*?W@XKQdacx0VQ3z(dzgpRpJu3nwADM|Th4*q=qDBu2&{@%H!g3fIjv zqe*q!mQL!1r``Y(k!eytv$t1tHpN*-TR4{B5HXHrn62|_zGK7Qi3bm_9)rwMk^m|} z12gP2A%`4X3WbB3_}jl~qt7K(`l~yg@c&ck_2!2=zaP&pA86~cA2QxZtXC)DdO^=D a%qHDWJ05A6m@_i1wPB;OtS}dDrb~bhy;CCq literal 0 HcmV?d00001 diff --git a/test/data/testrepo.git/refs/heads/master b/test/data/testrepo.git/refs/heads/master index b8e9848..436950f 100644 --- a/test/data/testrepo.git/refs/heads/master +++ b/test/data/testrepo.git/refs/heads/master @@ -1 +1 @@ -056e626e51b1fc1ee2182800e399ed8d84c8f082 +784855caf26449a1914d2cf62d12b9374d76ae78 diff --git a/test/test_diff.py b/test/test_diff.py index 9b3b3d2..e67f321 100644 --- a/test/test_diff.py +++ b/test/test_diff.py @@ -41,6 +41,9 @@ COMMIT_SHA1_2 = 'c2792cfa289ae6321ecf2cd5806c2194b0fd070c' COMMIT_SHA1_3 = '2cdae28389c059815e951d0bb9eed6533f61a46b' COMMIT_SHA1_4 = 'ccca47fbb26183e71a7a46d165299b84e2e6c0b3' COMMIT_SHA1_5 = '056e626e51b1fc1ee2182800e399ed8d84c8f082' +COMMIT_SHA1_6 = 'f5e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87' +COMMIT_SHA1_7 = '784855caf26449a1914d2cf62d12b9374d76ae78' + PATCH = """diff --git a/a b/a index 7f129fd..af431f2 100644 @@ -210,15 +213,15 @@ class DiffTest(utils.BareRepoTestCase): 'af431f20fc541ed6d5afede3e2dc7160f6f01f16') def test_find_similar(self): - commit_a = self.repo[COMMIT_SHA1_4] - commit_b = self.repo[COMMIT_SHA1_5] + commit_a = self.repo[COMMIT_SHA1_6] + commit_b = self.repo[COMMIT_SHA1_7] #~ Must pass GIT_DIFF_INCLUDE_UNMODIFIED if you expect to emulate #~ --find-copies-harder during rename transformion... diff = commit_a.tree.diff(commit_b.tree, GIT_DIFF_INCLUDE_UNMODIFIED) - self.assertFalse(('a', 'a.copy', 5, 100) in diff[0].files) - diff.find_similar(pygit2.GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED) - self.assertAny(lambda x:('a', 'a.copy', 5, 100) in x.files, diff) + self.assertFalse(('lorem', 'ipsum', 4, 100) in diff[0].files) + diff.find_similar() + self.assertAny(lambda x: ('lorem', 'ipsum', 4, 100) in x.files, diff) if __name__ == '__main__': unittest.main() diff --git a/test/test_remote.py b/test/test_remote.py index aacdc10..9b2c8c8 100644 --- a/test/test_remote.py +++ b/test/test_remote.py @@ -35,8 +35,8 @@ REMOTE_NAME = 'origin' REMOTE_URL = 'git://github.com/libgit2/pygit2.git' REMOTE_FETCHSPEC_SRC = 'refs/heads/*' REMOTE_FETCHSPEC_DST = 'refs/remotes/origin/*' -REMOTE_REPO_OBJECTS = 19 -REMOTE_REPO_BYTES = 1586 +REMOTE_REPO_OBJECTS = 24 +REMOTE_REPO_BYTES = 2253 class RepositoryTest(utils.RepoTestCase): def test_remote_create(self): diff --git a/test/test_repository.py b/test/test_repository.py index 105d1c5..c3457c4 100644 --- a/test/test_repository.py +++ b/test/test_repository.py @@ -42,8 +42,8 @@ import pygit2 from . import utils -HEAD_SHA = '056e626e51b1fc1ee2182800e399ed8d84c8f082' -PARENT_SHA = 'ccca47fbb26183e71a7a46d165299b84e2e6c0b3' # HEAD^ +HEAD_SHA = '784855caf26449a1914d2cf62d12b9374d76ae78' +PARENT_SHA = 'f5e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87' # HEAD^ A_HEX_SHA = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16' A_BIN_SHA = binascii.unhexlify(A_HEX_SHA.encode('ascii')) From 86b063fbd02967065418b683b5b243c6825d47b5 Mon Sep 17 00:00:00 2001 From: Nico von Geyso Date: Mon, 4 Mar 2013 19:32:12 +0100 Subject: [PATCH 07/11] fixed assert for diff.find_similiar test --- test/test_diff.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test_diff.py b/test/test_diff.py index e67f321..8cb7b2c 100644 --- a/test/test_diff.py +++ b/test/test_diff.py @@ -219,9 +219,10 @@ class DiffTest(utils.BareRepoTestCase): #~ Must pass GIT_DIFF_INCLUDE_UNMODIFIED if you expect to emulate #~ --find-copies-harder during rename transformion... diff = commit_a.tree.diff(commit_b.tree, GIT_DIFF_INCLUDE_UNMODIFIED) - self.assertFalse(('lorem', 'ipsum', 4, 100) in diff[0].files) + entry = ('lorem', 'ipsum', pygit2.GIT_DELTA_RENAMED, 100) + self.assertAll(lambda x: entry not in x.files, diff) diff.find_similar() - self.assertAny(lambda x: ('lorem', 'ipsum', 4, 100) in x.files, diff) + self.assertAny(lambda x: entry in x.files, diff) if __name__ == '__main__': unittest.main() From 8d8416e083120885f9233d9f2d378226b9976bc4 Mon Sep 17 00:00:00 2001 From: Valentin Haenel Date: Fri, 8 Mar 2013 22:02:26 +0100 Subject: [PATCH 08/11] pep8 fixes for setup.py as reported by flake8 --- setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index d52e935..e38ebec 100644 --- a/setup.py +++ b/setup.py @@ -64,8 +64,9 @@ if libgit2_path is None: libgit2_bin = os.path.join(libgit2_path, 'bin') libgit2_include = os.path.join(libgit2_path, 'include') libgit2_lib = os.getenv('LIBGIT2_LIB', os.path.join(libgit2_path, 'lib')) -pygit2_exts = [ os.path.join('src', name) for name in os.listdir('src') - if name.endswith('.c') ] +pygit2_exts = [os.path.join('src', name) for name in os.listdir('src') + if name.endswith('.c')] + class TestCommand(Command): """Command for running unittests without install.""" @@ -155,7 +156,6 @@ class sdist_files_from_git(sdist): self.write_manifest() - cmdclass = { 'test': TestCommand, 'sdist': sdist_files_from_git} @@ -183,11 +183,11 @@ setup(name='pygit2', maintainer=u('J. David Ibáñez'), maintainer_email='jdavid.ibp@gmail.com', long_description=long_description, - packages = ['pygit2'], + packages=['pygit2'], ext_modules=[ Extension('_pygit2', pygit2_exts, include_dirs=[libgit2_include, 'include'], library_dirs=[libgit2_lib], libraries=['git2']), - ], + ], cmdclass=cmdclass) From 2ffb39397d932bc238a90a07e2434447ca1cea26 Mon Sep 17 00:00:00 2001 From: Valentin Haenel Date: Fri, 8 Mar 2013 22:08:37 +0100 Subject: [PATCH 09/11] syntax highlighting for shell commands in sphinx --- docs/install.rst | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/install.rst b/docs/install.rst index aacad2f..6cde5b5 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -14,7 +14,9 @@ platform-specific instructions to build the library in the libgit2 website: Also, make sure you have Python 2.6+ installed together with the Python development headers. -When those are installed, you can install pygit2:: +When those are installed, you can install pygit2: + +.. code-block:: sh $ git clone git://github.com/libgit2/pygit2.git $ cd pygit2 @@ -36,7 +38,9 @@ using the default installation procedure (e.g. without specifying ``CMAKE_INSTALL_PREFIX``), you probably installed it under ``/usr/local/lib``. On some distributions (e.g. Ubuntu), ``/usr/local/lib`` is not in the linker's default search path (see the -`ld man page`_ for details), and you will get errors like:: +`ld man page`_ for details), and you will get errors like: + +.. code-block:: sh $ python -c 'import pygit2' Traceback (most recent call last): @@ -47,7 +51,9 @@ using the default installation procedure (e.g. without specifying The following recipe shows how to install libgit2 and pygit2 on these systems. First, download and install libgit2 (following the -instructions in the libgit2 ``README.md``):: +instructions in the libgit2 ``README.md``): + +.. code-block:: sh $ git clone git://github.com/libgit2/libgit2.git $ mkdir libgit2/build @@ -59,7 +65,9 @@ instructions in the libgit2 ``README.md``):: Now, download and install pygit2. You will probably have to set the ``LIBGIT2`` environment variable so the compiler can find the libgit2 -headers and libraries:: +headers and libraries: + +.. code-block:: sh $ git clone git://github.com/libgit2/pygit2.git $ cd pygit2 @@ -72,7 +80,9 @@ This compiles the pygit2 libraries with a ``RUNPATH``, which bakes extra library search paths directly into the binaries (see the `ld man page`_ for details). With ``RUNPATH`` compiled in, you won't have to use ``LD_LIBRARY_PATH``. You can check to ensure ``RUNPATH`` was set -with readelf_:: +with readelf_: + +.. code-block:: sh $ readelf --dynamic build/lib.linux-x86_64-3.2/_pygit2.cpython-32.so | grep PATH 0x000000000000000f (RPATH) Library rpath: [/usr/local/lib] @@ -90,7 +100,9 @@ in the ``LIBGIT2`` environment variable. In addition, make sure that libgit2 is build in "__cdecl" mode. The following recipe shows you how to do it, assuming you're working -from a bash shell:: +from a bash shell: + +.. code-block:: sh $ export LIBGIT2=C:/Dev/libgit2 $ git clone git://github.com/libgit2/libgit2.git From 27aba1f3c8746a81c6fc1beb82f8d913f7959707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20David=20Ib=C3=A1=C3=B1ez?= Date: Sat, 9 Mar 2013 12:36:58 +0100 Subject: [PATCH 10/11] Update to changes in libgit2 concerning refs Two methods have been drop: - Repository.packall_references - Reference.reload The unit tests have been commented until we wrap the new reference database from libgit2. --- src/pygit2.c | 2 +- src/reference.c | 44 +++++++++++--------------------------------- src/repository.c | 19 ------------------- test/test_refs.py | 22 +++++++++++----------- 4 files changed, 23 insertions(+), 64 deletions(-) diff --git a/src/pygit2.c b/src/pygit2.c index 1c3f42b..cd56a6e 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -290,9 +290,9 @@ moduleinit(PyObject* m) 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_INVALID", GIT_REF_INVALID); 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); PyModule_AddIntConstant(m, "GIT_REF_LISTALL", GIT_REF_LISTALL); /* Git status flags */ diff --git a/src/reference.c b/src/reference.c index f13ed31..129ed44 100644 --- a/src/reference.c +++ b/src/reference.c @@ -161,6 +161,7 @@ Reference_rename(Reference *self, PyObject *py_name) { char *c_name; int err; + git_reference *new_reference; CHECK_REFERENCE(self); @@ -170,33 +171,12 @@ Reference_rename(Reference *self, PyObject *py_name) return NULL; /* Rename */ - err = git_reference_rename(self->reference, c_name, 0); + err = git_reference_rename(&new_reference, self->reference, c_name, 0); free(c_name); if (err < 0) return Error_set(err); - Py_RETURN_NONE; -} - - -PyDoc_STRVAR(Reference_reload__doc__, - "reload()\n" - "\n" - "Reload the reference from the file-system."); - -PyObject * -Reference_reload(Reference *self) -{ - int err; - - CHECK_REFERENCE(self); - - err = git_reference_reload(self->reference); - if (err < 0) { - self->reference = NULL; - return Error_set(err); - } - + self->reference = new_reference; Py_RETURN_NONE; } @@ -214,13 +194,8 @@ Reference_resolve(Reference *self, PyObject *args) CHECK_REFERENCE(self); - /* Direct: reload */ + /* Direct: return myself */ if (git_reference_type(self->reference) == GIT_REF_OID) { - err = git_reference_reload(self->reference); - if (err < 0) { - self->reference = NULL; - return Error_set(err); - } Py_INCREF(self); return (PyObject *)self; } @@ -263,6 +238,7 @@ Reference_target__set__(Reference *self, PyObject *py_name) { char *c_name; int err; + git_reference *new_ref; CHECK_REFERENCE_INT(self); @@ -272,13 +248,14 @@ Reference_target__set__(Reference *self, PyObject *py_name) return -1; /* Set the new target */ - err = git_reference_symbolic_set_target(self->reference, c_name); + err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name); free(c_name); if (err < 0) { Error_set(err); return -1; } + self->reference = new_ref; return 0; } @@ -320,6 +297,7 @@ Reference_oid__set__(Reference *self, PyObject *py_hex) { git_oid oid; int err; + git_reference *new_ref; CHECK_REFERENCE_INT(self); @@ -332,12 +310,13 @@ Reference_oid__set__(Reference *self, PyObject *py_hex) } /* Set the oid */ - err = git_reference_set_target(self->reference, &oid); + err = git_reference_set_target(&new_ref, self->reference, &oid); if (err < 0) { Error_set(err); return -1; } + self->reference = new_ref; return 0; } @@ -366,7 +345,7 @@ Reference_hex__get__(Reference *self) PyDoc_STRVAR(Reference_type__doc__, - "Type (GIT_REF_OID, GIT_REF_SYMBOLIC or GIT_REF_PACKED)."); + "Type (GIT_REF_OID or GIT_REF_SYMBOLIC)."); PyObject * Reference_type__get__(Reference *self) @@ -481,7 +460,6 @@ PyTypeObject RefLogEntryType = { PyMethodDef Reference_methods[] = { METHOD(Reference, delete, METH_NOARGS), METHOD(Reference, rename, METH_O), - METHOD(Reference, reload, METH_NOARGS), METHOD(Reference, resolve, METH_NOARGS), METHOD(Reference, log, METH_NOARGS), {NULL} diff --git a/src/repository.c b/src/repository.c index 1016948..497e28d 100644 --- a/src/repository.c +++ b/src/repository.c @@ -902,24 +902,6 @@ Repository_create_symbolic_reference(Repository *self, PyObject *args, } -PyDoc_STRVAR(Repository_packall_references__doc__, - "packall_references()\n" - "\n" - "Pack all the loose references in the repository."); - -PyObject * -Repository_packall_references(Repository *self, PyObject *args) -{ - int err; - - err = git_reference_packall(self->repo); - if (err < 0) - return Error_set(err); - - Py_RETURN_NONE; -} - - PyDoc_STRVAR(Repository_status__doc__, "status() -> {str: int}\n" "\n" @@ -1145,7 +1127,6 @@ PyMethodDef Repository_methods[] = { METHOD(Repository, create_symbolic_reference, METH_VARARGS), METHOD(Repository, listall_references, METH_VARARGS), METHOD(Repository, lookup_reference, METH_O), - METHOD(Repository, packall_references, METH_NOARGS), METHOD(Repository, revparse_single, METH_O), METHOD(Repository, status, METH_NOARGS), METHOD(Repository, status_file, METH_O), diff --git a/test/test_refs.py b/test/test_refs.py index 0b2f61c..fb00182 100644 --- a/test/test_refs.py +++ b/test/test_refs.py @@ -142,16 +142,16 @@ class ReferencesTest(utils.RepoTestCase): self.assertEqual(reference.name, 'refs/tags/version2') - def test_reload(self): - name = 'refs/tags/version1' +# def test_reload(self): +# name = 'refs/tags/version1' - repo = self.repo - ref = repo.create_reference(name, "refs/heads/master", symbolic=True) - ref2 = repo.lookup_reference(name) - ref.delete() - self.assertEqual(ref2.name, name) - self.assertRaises(KeyError, ref2.reload) - self.assertRaises(GitError, getattr, ref2, 'name') +# repo = self.repo +# ref = repo.create_reference(name, "refs/heads/master", symbolic=True) +# ref2 = repo.lookup_reference(name) +# ref.delete() +# self.assertEqual(ref2.name, name) +# self.assertRaises(KeyError, ref2.reload) +# self.assertRaises(GitError, getattr, ref2, 'name') def test_reference_resolve(self): @@ -209,8 +209,8 @@ class ReferencesTest(utils.RepoTestCase): self.assertEqual(reference.target, 'refs/heads/master') - def test_packall_references(self): - self.repo.packall_references() +# def test_packall_references(self): +# self.repo.packall_references() if __name__ == '__main__': From 33638b66e22c43cc9d983e43bf6029a054a810c3 Mon Sep 17 00:00:00 2001 From: Valentin Haenel Date: Sat, 9 Mar 2013 13:02:48 +0100 Subject: [PATCH 11/11] the extension compiles to _pygit2.so, so ignore that too --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 972131d..d802242 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ MANIFEST build dist pygit2.so +_pygit2.so test/*.pyc test/__pycache__ pygit2/*.pyc