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 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 diff --git a/include/pygit2/types.h b/include/pygit2/types.h index 9c8a429..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 @@ -76,17 +82,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/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 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) diff --git a/src/diff.c b/src/diff.c index 50f3b51..c9b4983 100644 --- a/src/diff.c +++ b/src/diff.c @@ -40,242 +40,263 @@ 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) +PyTypeObject DiffEntryType; + +PyObject* +diff_get_patch_byindex(git_diff_list* list, size_t i) { - PyObject *hunks, *data; - Hunk *hunk; - Py_ssize_t size; + const git_diff_delta* delta; + const git_diff_range* range; + git_diff_patch* patch = NULL; - hunks = PyDict_GetItemString(cb_data, "hunks"); - if (hunks == NULL) - return -1; + char buffer[41]; + const char* hunk_content; + size_t hunk_amounts, j, hunk_header_len, hunk_lines; + int err; - size = PyList_Size(hunks); - hunk = (Hunk *)PyList_GetItem(hunks, size - 1); - if (hunk == NULL) - return -1; + PyObject *file; + Hunk *py_hunk; + DiffEntry *py_entry = NULL; - data = Py_BuildValue("(s#,i)", - content, content_len, - line_origin - ); - PyList_Append(hunk->data, data); - Py_DECREF(data); + err = git_diff_get_patch(&patch, &delta, list, i); - return 0; + 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, + delta->new_file.path, + delta->status, + delta->similarity + ); + + PyList_Append((PyObject*) py_entry->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((PyObject*) py_entry->hunks, + (PyObject*) py_hunk); + } + } + } + } + } + + if (err < 0) + return Error_set(err); + + return (PyObject*) py_entry; } -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) +DiffEntry_call(DiffEntry *self, PyObject *args, PyObject *kwds) { - - 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 - ); + self->files = PyList_New(0); + if (self->files == NULL) { + Py_XDECREF(self); + return NULL; } - return PyDict_Copy(self->diff_changes); + self->hunks = PyList_New(0); + if (self->hunks == NULL) { + Py_XDECREF(self); + return NULL; + } + + return (PyObject*) self; } -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) +static void +DiffEntry_dealloc(DiffEntry *self) { - PyObject *data = PyBytes_FromStringAndSize(line, line_len); - PyBytes_ConcatAndDel((PyObject **)cb_data, data); - - return 0; + 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."); 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 = 0; + size_t i, len, num, size; + PyObject *py_patch = NULL; - git_diff_print_patch(self->diff, &diff_print_cb, (void*) &patch); + num = git_diff_num_deltas(self->list); + for (i = 0; i < num ; ++i) { + err = git_diff_get_patch(&patch, &delta, self->list, i); - return patch; -} + if (err < 0 || (err = git_diff_patch_to_str(&str, patch)) < 0) + goto error; -static int -Hunk_init(Hunk *self, PyObject *args, PyObject *kwds) -{ - self->header = NULL; + len = strlen(str) + 1; + size = (buffer == NULL) ? len : strlen(buffer) + len; + MALLOC(buffer, size, error); - self->old_file = NULL; - self->old_start = 0; - self->old_lines = 0; + if (len == size) + strcpy(buffer, str); + else + strcat(buffer, str); - 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; + FREE(str); } - return 0; + py_patch = PyUnicode_FromString(buffer); + +error: + FREE(str); + FREE(buffer); + FREE_FUNC(patch, git_diff_patch_free); + + return (err < 0) ? Error_set(err) : py_patch; } + 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 +310,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} }; @@ -338,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 */ }; @@ -357,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; } @@ -384,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), @@ -430,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 */ @@ -443,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 6727e65..cd56a6e 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; @@ -284,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 */ @@ -343,13 +349,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/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 68e4072..c0541b9 100644 --- a/src/repository.c +++ b/src/repository.c @@ -902,24 +902,6 @@ Repository_git_reference_symbolic_create(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, git_reference_symbolic_create, 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/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/data/testrepo.git/objects/10/2374bdb1e8efca5e66cded18fd8f30571654a5 b/test/data/testrepo.git/objects/10/2374bdb1e8efca5e66cded18fd8f30571654a5 new file mode 100644 index 0000000..4cb6eb7 Binary files /dev/null and b/test/data/testrepo.git/objects/10/2374bdb1e8efca5e66cded18fd8f30571654a5 differ diff --git a/test/data/testrepo.git/objects/11/19926b06311143cab273f0af84eae77f5b3462 b/test/data/testrepo.git/objects/11/19926b06311143cab273f0af84eae77f5b3462 new file mode 100644 index 0000000..8ac529e Binary files /dev/null and b/test/data/testrepo.git/objects/11/19926b06311143cab273f0af84eae77f5b3462 differ diff --git a/test/data/testrepo.git/objects/19/bf31524643d743751b09cf719456914bbd8bd5 b/test/data/testrepo.git/objects/19/bf31524643d743751b09cf719456914bbd8bd5 new file mode 100644 index 0000000..af11713 Binary files /dev/null and b/test/data/testrepo.git/objects/19/bf31524643d743751b09cf719456914bbd8bd5 differ diff --git a/test/data/testrepo.git/objects/55/60f04f38a674decf34d16d7c7476642fa03794 b/test/data/testrepo.git/objects/55/60f04f38a674decf34d16d7c7476642fa03794 new file mode 100644 index 0000000..16bf738 Binary files /dev/null and b/test/data/testrepo.git/objects/55/60f04f38a674decf34d16d7c7476642fa03794 differ diff --git a/test/data/testrepo.git/objects/78/4855caf26449a1914d2cf62d12b9374d76ae78 b/test/data/testrepo.git/objects/78/4855caf26449a1914d2cf62d12b9374d76ae78 new file mode 100644 index 0000000..69cb9de Binary files /dev/null and b/test/data/testrepo.git/objects/78/4855caf26449a1914d2cf62d12b9374d76ae78 differ diff --git a/test/data/testrepo.git/objects/f5/e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87 b/test/data/testrepo.git/objects/f5/e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87 new file mode 100644 index 0000000..5f61174 Binary files /dev/null and b/test/data/testrepo.git/objects/f5/e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87 differ 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 ff3a54c..8cb7b2c 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 @@ -40,8 +41,11 @@ 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 = b"""diff --git a/a b/a + +PATCH = """diff --git a/a b/a index 7f129fd..af431f2 100644 --- a/a +++ b/a @@ -86,16 +90,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 +113,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 +125,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 +148,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 +168,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,28 +200,29 @@ 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, '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.changes['files']) - diff.find_similar(pygit2.GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED) - self.assertTrue(('a', 'a.copy', 5, 100) in diff.changes['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: entry in x.files, diff) if __name__ == '__main__': unittest.main() 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__': 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')) 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: