Skip to content

Commit 909e03d

Browse files
committed
New DiffDelta and DiffFile
Comes from PR libgit2#346
1 parent 8881b75 commit 909e03d

File tree

7 files changed

+258
-67
lines changed

7 files changed

+258
-67
lines changed

README.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,20 @@ Changelog
3131
- Make pygit work in a frozen environment
3232
`#453 <https://github.com/libgit2/pygit2/pull/453>`_
3333

34+
- New ``pygit2.DiffDelta`` and ``pygit2.DiffFile``
35+
3436
- Rename ``pygit2.Hunk`` to ``pygit2.DiffHunk``
3537

38+
API changes::
39+
40+
Patch.old_file_path => Patch.delta.old_file.path
41+
Patch.new_file_path => Patch.delta.new_file.path
42+
Patch.old_id => Patch.delta.old_file.id
43+
Patch.new_id => Patch.delta.new_file.id
44+
Patch.status => Patch.delta.status
45+
Patch.similarity => Patch.delta.similarity
46+
Patch.is_binary => Patch.delta.is_binary
47+
3648

3749
0.22.0 (2015-01-16)
3850
-------------------

src/diff.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ extern PyObject *GitError;
4040
extern PyTypeObject TreeType;
4141
extern PyTypeObject IndexType;
4242
extern PyTypeObject DiffType;
43+
extern PyTypeObject DiffDeltaType;
44+
extern PyTypeObject DiffFileType;
4345
extern PyTypeObject DiffHunkType;
4446
extern PyTypeObject RepositoryType;
4547

@@ -58,6 +60,180 @@ wrap_diff(git_diff *diff, Repository *repo)
5860
return (PyObject*) py_diff;
5961
}
6062

63+
PyObject *
64+
wrap_diff_file(const git_diff_file *file)
65+
{
66+
DiffFile *py_file;
67+
68+
if (!file)
69+
Py_RETURN_NONE;
70+
71+
py_file = PyObject_New(DiffFile, &DiffFileType);
72+
if (py_file) {
73+
py_file->id = git_oid_to_python(&file->id);
74+
py_file->path = file->path != NULL ? strdup(file->path) : NULL;
75+
}
76+
77+
return (PyObject *) py_file;
78+
}
79+
80+
PyObject *
81+
wrap_diff_delta(const git_diff_delta *delta)
82+
{
83+
DiffDelta *py_delta;
84+
85+
if (!delta)
86+
Py_RETURN_NONE;
87+
88+
py_delta = PyObject_New(DiffDelta, &DiffDeltaType);
89+
if (py_delta) {
90+
py_delta->status = git_diff_status_char(delta->status);
91+
py_delta->flags = delta->flags;
92+
py_delta->similarity = delta->similarity;
93+
py_delta->nfiles = delta->nfiles;
94+
py_delta->old_file = wrap_diff_file(&delta->old_file);
95+
py_delta->new_file = wrap_diff_file(&delta->new_file);
96+
}
97+
98+
return (PyObject *) py_delta;
99+
}
100+
101+
static void
102+
DiffFile_dealloc(DiffFile *self)
103+
{
104+
Py_CLEAR(self->id);
105+
if (self->path)
106+
free(self->path);
107+
PyObject_Del(self);
108+
}
109+
110+
PyMemberDef DiffFile_members[] = {
111+
MEMBER(DiffFile, id, T_OBJECT, "Oid of the item."),
112+
MEMBER(DiffFile, path, T_STRING, "Path to the entry."),
113+
{NULL}
114+
};
115+
116+
117+
PyDoc_STRVAR(DiffFile__doc__, "DiffFile object.");
118+
119+
PyTypeObject DiffFileType = {
120+
PyVarObject_HEAD_INIT(NULL, 0)
121+
"_pygit2.DiffFile", /* tp_name */
122+
sizeof(DiffFile), /* tp_basicsize */
123+
0, /* tp_itemsize */
124+
(destructor)DiffFile_dealloc, /* tp_dealloc */
125+
0, /* tp_print */
126+
0, /* tp_getattr */
127+
0, /* tp_setattr */
128+
0, /* tp_compare */
129+
0, /* tp_repr */
130+
0, /* tp_as_number */
131+
0, /* tp_as_sequence */
132+
0, /* tp_as_mapping */
133+
0, /* tp_hash */
134+
0, /* tp_call */
135+
0, /* tp_str */
136+
0, /* tp_getattro */
137+
0, /* tp_setattro */
138+
0, /* tp_as_buffer */
139+
Py_TPFLAGS_DEFAULT, /* tp_flags */
140+
DiffFile__doc__, /* tp_doc */
141+
0, /* tp_traverse */
142+
0, /* tp_clear */
143+
0, /* tp_richcompare */
144+
0, /* tp_weaklistoffset */
145+
0, /* tp_iter */
146+
0, /* tp_iternext */
147+
0, /* tp_methods */
148+
DiffFile_members, /* tp_members */
149+
0, /* tp_getset */
150+
0, /* tp_base */
151+
0, /* tp_dict */
152+
0, /* tp_descr_get */
153+
0, /* tp_descr_set */
154+
0, /* tp_dictoffset */
155+
0, /* tp_init */
156+
0, /* tp_alloc */
157+
0, /* tp_new */
158+
};
159+
160+
PyDoc_STRVAR(DiffDelta_is_binary__doc__, "True if binary data, False if not.");
161+
162+
PyObject *
163+
DiffDelta_is_binary__get__(DiffDelta *self)
164+
{
165+
if (!(self->flags & GIT_DIFF_FLAG_NOT_BINARY) &&
166+
(self->flags & GIT_DIFF_FLAG_BINARY))
167+
Py_RETURN_TRUE;
168+
Py_RETURN_FALSE;
169+
}
170+
171+
static void
172+
DiffDelta_dealloc(DiffDelta *self)
173+
{
174+
Py_CLEAR(self->old_file);
175+
Py_CLEAR(self->new_file);
176+
PyObject_Del(self);
177+
}
178+
179+
PyMemberDef DiffDelta_members[] = {
180+
MEMBER(DiffDelta, status, T_CHAR, "A GIT_DELTA_* constant."),
181+
MEMBER(DiffDelta, flags, T_UINT, "Combination of GIT_DIFF_FLAG_* flags."),
182+
MEMBER(DiffDelta, similarity, T_USHORT, "For renamed and copied."),
183+
MEMBER(DiffDelta, nfiles, T_USHORT, "Number of files in the delta."),
184+
MEMBER(DiffDelta, old_file, T_OBJECT, "\"from\" side of the diff."),
185+
MEMBER(DiffDelta, new_file, T_OBJECT, "\"to\" side of the diff."),
186+
{NULL}
187+
};
188+
189+
PyGetSetDef DiffDelta_getseters[] = {
190+
GETTER(DiffDelta, is_binary),
191+
{NULL}
192+
};
193+
194+
PyDoc_STRVAR(DiffDelta__doc__, "DiffDelta object.");
195+
196+
PyTypeObject DiffDeltaType = {
197+
PyVarObject_HEAD_INIT(NULL, 0)
198+
"_pygit2.DiffDelta", /* tp_name */
199+
sizeof(DiffDelta), /* tp_basicsize */
200+
0, /* tp_itemsize */
201+
(destructor)DiffDelta_dealloc, /* tp_dealloc */
202+
0, /* tp_print */
203+
0, /* tp_getattr */
204+
0, /* tp_setattr */
205+
0, /* tp_compare */
206+
0, /* tp_repr */
207+
0, /* tp_as_number */
208+
0, /* tp_as_sequence */
209+
0, /* tp_as_mapping */
210+
0, /* tp_hash */
211+
0, /* tp_call */
212+
0, /* tp_str */
213+
0, /* tp_getattro */
214+
0, /* tp_setattro */
215+
0, /* tp_as_buffer */
216+
Py_TPFLAGS_DEFAULT, /* tp_flags */
217+
DiffDelta__doc__, /* tp_doc */
218+
0, /* tp_traverse */
219+
0, /* tp_clear */
220+
0, /* tp_richcompare */
221+
0, /* tp_weaklistoffset */
222+
0, /* tp_iter */
223+
0, /* tp_iternext */
224+
0, /* tp_methods */
225+
DiffDelta_members, /* tp_members */
226+
DiffDelta_getseters, /* tp_getset */
227+
0, /* tp_base */
228+
0, /* tp_dict */
229+
0, /* tp_descr_get */
230+
0, /* tp_descr_set */
231+
0, /* tp_dictoffset */
232+
0, /* tp_init */
233+
0, /* tp_alloc */
234+
0, /* tp_new */
235+
};
236+
61237
PyObject *
62238
diff_get_patch_byindex(git_diff *diff, size_t idx)
63239
{

src/diff.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,7 @@ PyObject* Diff_changes(Diff *self);
3737
PyObject* Diff_patch(Diff *self);
3838

3939
PyObject* wrap_diff(git_diff *diff, Repository *repo);
40+
PyObject* wrap_diff_file(const git_diff_file *file);
41+
PyObject* wrap_diff_delta(const git_diff_delta *delta);
4042

4143
#endif

src/patch.c

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define PY_SSIZE_T_CLEAN
2929
#include <Python.h>
3030
#include <structmember.h>
31+
#include "diff.h"
3132
#include "error.h"
3233
#include "oid.h"
3334
#include "types.h"
@@ -53,15 +54,9 @@ wrap_patch(git_patch *patch)
5354
const git_diff_line *line;
5455
int err;
5556

56-
delta = git_patch_get_delta(patch);
57+
py_patch->patch = patch;
5758

58-
py_patch->old_file_path = strdup(delta->old_file.path);
59-
py_patch->new_file_path = strdup(delta->new_file.path);
60-
py_patch->status = git_diff_status_char(delta->status);
61-
py_patch->similarity = delta->similarity;
62-
py_patch->flags = delta->flags;
63-
py_patch->old_id = git_oid_to_python(&delta->old_file.id);
64-
py_patch->new_id = git_oid_to_python(&delta->new_file.id);
59+
delta = git_patch_get_delta(patch);
6560

6661
git_patch_line_stats(NULL, &additions, &deletions, patch);
6762
py_patch->additions = additions;
@@ -107,7 +102,6 @@ wrap_patch(git_patch *patch)
107102
}
108103
}
109104
}
110-
git_patch_free(patch);
111105

112106
return (PyObject*) py_patch;
113107
}
@@ -116,39 +110,30 @@ static void
116110
Patch_dealloc(Patch *self)
117111
{
118112
Py_CLEAR(self->hunks);
119-
Py_CLEAR(self->old_id);
120-
Py_CLEAR(self->new_id);
121-
free(self->old_file_path);
122-
free(self->new_file_path);
113+
git_patch_free(self->patch);
123114
PyObject_Del(self);
124115
}
125116

117+
PyDoc_STRVAR(Patch_delta__doc__, "Get the delta associated with a patch.");
118+
119+
PyObject *
120+
Patch_delta__get__(Patch *self)
121+
{
122+
if (!self->patch)
123+
Py_RETURN_NONE;
124+
125+
return wrap_diff_delta(git_patch_get_delta(self->patch));
126+
}
127+
126128
PyMemberDef Patch_members[] = {
127-
MEMBER(Patch, old_file_path, T_STRING, "old file path"),
128-
MEMBER(Patch, new_file_path, T_STRING, "new file path"),
129-
MEMBER(Patch, old_id, T_OBJECT, "old oid"),
130-
MEMBER(Patch, new_id, T_OBJECT, "new oid"),
131-
MEMBER(Patch, status, T_CHAR, "status"),
132-
MEMBER(Patch, similarity, T_INT, "similarity"),
133129
MEMBER(Patch, hunks, T_OBJECT, "hunks"),
134130
MEMBER(Patch, additions, T_INT, "additions"),
135131
MEMBER(Patch, deletions, T_INT, "deletions"),
136132
{NULL}
137133
};
138134

139-
PyDoc_STRVAR(Patch_is_binary__doc__, "True if binary data, False if not.");
140-
141-
PyObject *
142-
Patch_is_binary__get__(Patch *self)
143-
{
144-
if (!(self->flags & GIT_DIFF_FLAG_NOT_BINARY) &&
145-
(self->flags & GIT_DIFF_FLAG_BINARY))
146-
Py_RETURN_TRUE;
147-
Py_RETURN_FALSE;
148-
}
149-
150135
PyGetSetDef Patch_getseters[] = {
151-
GETTER(Patch, is_binary),
136+
GETTER(Patch, delta),
152137
{NULL}
153138
};
154139

src/pygit2.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ extern PyTypeObject ObjectType;
4444
extern PyTypeObject CommitType;
4545
extern PyTypeObject DiffType;
4646
extern PyTypeObject DiffIterType;
47-
extern PyTypeObject PatchType;
47+
extern PyTypeObject DiffDeltaType;
48+
extern PyTypeObject DiffFileType;
4849
extern PyTypeObject DiffHunkType;
50+
extern PyTypeObject PatchType;
4951
extern PyTypeObject TreeType;
5052
extern PyTypeObject TreeBuilderType;
5153
extern PyTypeObject TreeEntryType;
@@ -287,11 +289,15 @@ moduleinit(PyObject* m)
287289
*/
288290
INIT_TYPE(DiffType, NULL, NULL)
289291
INIT_TYPE(DiffIterType, NULL, NULL)
290-
INIT_TYPE(PatchType, NULL, NULL)
292+
INIT_TYPE(DiffDeltaType, NULL, NULL)
293+
INIT_TYPE(DiffFileType, NULL, NULL)
291294
INIT_TYPE(DiffHunkType, NULL, NULL)
295+
INIT_TYPE(PatchType, NULL, NULL)
292296
ADD_TYPE(m, Diff)
293-
ADD_TYPE(m, Patch)
297+
ADD_TYPE(m, DiffDelta)
298+
ADD_TYPE(m, DiffFile)
294299
ADD_TYPE(m, DiffHunk)
300+
ADD_TYPE(m, Patch)
295301
ADD_CONSTANT_INT(m, GIT_DIFF_NORMAL)
296302
ADD_CONSTANT_INT(m, GIT_DIFF_REVERSE)
297303
ADD_CONSTANT_INT(m, GIT_DIFF_FORCE_TEXT)

src/types.h

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ typedef struct {
9090
char* ref;
9191
} NoteIter;
9292

93+
/* git_patch */
94+
typedef struct {
95+
PyObject_HEAD
96+
git_patch *patch;
97+
PyObject* hunks;
98+
unsigned additions;
99+
unsigned deletions;
100+
} Patch;
93101

94102
/* git_diff */
95103
SIMPLE_TYPE(Diff, git_diff, diff)
@@ -103,17 +111,19 @@ typedef struct {
103111

104112
typedef struct {
105113
PyObject_HEAD
106-
PyObject* hunks;
107-
char * old_file_path;
108-
char * new_file_path;
109-
PyObject* old_id;
110-
PyObject* new_id;
111-
char status;
112-
unsigned similarity;
113-
unsigned additions;
114-
unsigned deletions;
115-
unsigned flags;
116-
} Patch;
114+
PyObject *id;
115+
char *path;
116+
} DiffFile;
117+
118+
typedef struct {
119+
PyObject_HEAD
120+
git_delta_t status;
121+
uint32_t flags;
122+
uint16_t similarity;
123+
uint16_t nfiles;
124+
PyObject *old_file;
125+
PyObject *new_file;
126+
} DiffDelta;
117127

118128
typedef struct {
119129
PyObject_HEAD

0 commit comments

Comments
 (0)