Skip to content

Commit

Permalink
New Diff.deltas iterable
Browse files Browse the repository at this point in the history
  • Loading branch information
jdavid committed Dec 6, 2017
1 parent 28c3828 commit c4e0260
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 1 deletion.
82 changes: 81 additions & 1 deletion src/diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,13 +475,92 @@ PyTypeObject DiffIterType = {
(iternextfunc) DiffIter_iternext, /* tp_iternext */
};

PyObject *
diff_get_delta_byindex(git_diff *diff, size_t idx)
{
const git_diff_delta *delta = git_diff_get_delta(diff, idx);
if (delta == NULL) {
PyErr_SetObject(PyExc_IndexError, PyInt_FromSize_t(idx));
return NULL;
}

return (PyObject*) wrap_diff_delta(delta);
}

PyObject *
DeltasIter_iternext(DeltasIter *self)
{
if (self->i < self->n)
return diff_get_delta_byindex(self->diff->diff, self->i++);

PyErr_SetNone(PyExc_StopIteration);
return NULL;
}

void
DeltasIter_dealloc(DeltasIter *self)
{
Py_CLEAR(self->diff);
PyObject_Del(self);
}

PyDoc_STRVAR(DeltasIter__doc__, "Deltas iterator object.");

PyTypeObject DeltasIterType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_pygit2.DeltasIter", /* tp_name */
sizeof(DeltasIter), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)DeltasIter_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, /* tp_flags */
DeltasIter__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc) DeltasIter_iternext, /* tp_iternext */
};


Py_ssize_t
Diff_len(Diff *self)
{
assert(self->diff);
return (Py_ssize_t)git_diff_num_deltas(self->diff);
}

PyDoc_STRVAR(Diff_deltas__doc__, "Iterate over the diff deltas.");

PyObject *
Diff_deltas__get__(Diff *self)
{
DeltasIter *iter;

iter = PyObject_New(DeltasIter, &DeltasIterType);
if (iter != NULL) {
Py_INCREF(self);
iter->diff = self;
iter->i = 0;
iter->n = git_diff_num_deltas(self->diff);
}
return (PyObject*)iter;
}

PyDoc_STRVAR(Diff_patch__doc__,
"Patch diff string. Can be None in some cases, such as empty commits.");

Expand Down Expand Up @@ -814,7 +893,7 @@ Diff_getitem(Diff *self, PyObject *value)
return diff_get_patch_byindex(self->diff, i);
}

PyDoc_STRVAR(Diff_stats__doc__, "Accumulate diff statistics for all patches");
PyDoc_STRVAR(Diff_stats__doc__, "Accumulate diff statistics for all patches.");

PyObject *
Diff_stats__get__(Diff *self)
Expand All @@ -831,6 +910,7 @@ Diff_dealloc(Diff *self)
}

PyGetSetDef Diff_getseters[] = {
GETTER(Diff, deltas),
GETTER(Diff, patch),
GETTER(Diff, stats),
{NULL}
Expand Down
2 changes: 2 additions & 0 deletions src/pygit2.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern PyTypeObject OidType;
extern PyTypeObject ObjectType;
extern PyTypeObject CommitType;
extern PyTypeObject DiffType;
extern PyTypeObject DeltasIterType;
extern PyTypeObject DiffIterType;
extern PyTypeObject DiffDeltaType;
extern PyTypeObject DiffFileType;
Expand Down Expand Up @@ -335,6 +336,7 @@ moduleinit(PyObject* m)
* Diff
*/
INIT_TYPE(DiffType, NULL, NULL)
INIT_TYPE(DeltasIterType, NULL, NULL)
INIT_TYPE(DiffIterType, NULL, NULL)
INIT_TYPE(DiffDeltaType, NULL, NULL)
INIT_TYPE(DiffFileType, NULL, NULL)
Expand Down
7 changes: 7 additions & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ typedef struct {
/* git_diff */
SIMPLE_TYPE(Diff, git_diff, diff)

typedef struct {
PyObject_HEAD
Diff *diff;
size_t i;
size_t n;
} DeltasIter;

typedef struct {
PyObject_HEAD
Diff *diff;
Expand Down
18 changes: 18 additions & 0 deletions test/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,24 @@ def test_diff_stats(self):
width=80)
self.assertEqual(STATS_EXPECTED, formatted)

def test_deltas(self):
commit_a = self.repo[COMMIT_SHA1_1]
commit_b = self.repo[COMMIT_SHA1_2]
diff = commit_a.tree.diff_to_tree(commit_b.tree)
deltas = list(diff.deltas)
patches = list(diff)
self.assertEqual(len(deltas), len(patches))
for i, delta in enumerate(deltas):
patch_delta = patches[i].delta
self.assertEqual(delta.status, patch_delta.status)
self.assertEqual(delta.similarity, patch_delta.similarity)
self.assertEqual(delta.nfiles, patch_delta.nfiles)
self.assertEqual(delta.old_file.id, patch_delta.old_file.id)
self.assertEqual(delta.new_file.id, patch_delta.new_file.id)

# As explained in the libgit2 documentation, flags are not set
#self.assertEqual(delta.flags, patch_delta.flags)


class BinaryDiffTest(utils.BinaryFileRepoTestCase):
def test_binary_diff(self):
Expand Down

0 comments on commit c4e0260

Please sign in to comment.