Support diff for blobs
This commit is contained in:
parent
cde2456327
commit
dcc9051a8c
97
src/blob.c
97
src/blob.c
@ -27,10 +27,105 @@
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "diff.h"
|
||||
#include "error.h"
|
||||
#include "utils.h"
|
||||
#include "object.h"
|
||||
#include "blob.h"
|
||||
|
||||
extern PyObject *GitError;
|
||||
|
||||
extern PyTypeObject BlobType;
|
||||
|
||||
PyDoc_STRVAR(Blob_diff__doc__,
|
||||
"diff([blob, flag, old_as_path, new_as_path] -> Patch\n"
|
||||
"\n"
|
||||
"Directly generate a :py:class:`pygit2.Patch` from the difference\n"
|
||||
" between two blobs.\n"
|
||||
"\n"
|
||||
"Arguments:\n"
|
||||
"\n"
|
||||
"blob: the :py:class:`~pygit2.Blob` to diff.\n"
|
||||
"\n"
|
||||
"flag: a GIT_DIFF_* constant.\n"
|
||||
"\n"
|
||||
"old_as_path: treat old blob as if it had this filename.\n"
|
||||
"\n"
|
||||
"new_as_path: treat new blob as if it had this filename.\n");
|
||||
|
||||
PyObject *
|
||||
Blob_diff(Blob *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
||||
git_patch *patch;
|
||||
char *old_as_path = NULL, *new_as_path = NULL;
|
||||
Blob *py_blob = NULL;
|
||||
int err;
|
||||
char *keywords[] = {"blob", "flag", "old_as_path", "new_as_path", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!ssI", keywords,
|
||||
&BlobType, &py_blob, &opts.flags,
|
||||
&old_as_path, &new_as_path))
|
||||
return NULL;
|
||||
|
||||
err = git_patch_from_blobs(&patch, self->blob, old_as_path,
|
||||
py_blob ? py_blob->blob : NULL, new_as_path,
|
||||
&opts);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return wrap_patch(patch);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Blob_diff_to_buffer__doc__,
|
||||
"diff_to_buffer([buffer, flag, old_as_path, buffer_as_path] -> Patch\n"
|
||||
"\n"
|
||||
"Directly generate a :py:class:`~pygit2.Patch` from the difference\n"
|
||||
" between a blob and a buffer.\n"
|
||||
"\n"
|
||||
"Arguments:\n"
|
||||
"\n"
|
||||
"buffer: Raw data for new side of diff.\n"
|
||||
"\n"
|
||||
"flag: a GIT_DIFF_* constant.\n"
|
||||
"\n"
|
||||
"old_as_path: treat old blob as if it had this filename.\n"
|
||||
"\n"
|
||||
"buffer_as_path: treat buffer as if it had this filename.\n");
|
||||
|
||||
PyObject *
|
||||
Blob_diff_to_buffer(Blob *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
||||
git_patch *patch;
|
||||
char *old_as_path = NULL, *buffer_as_path = NULL;
|
||||
const char *buffer = NULL;
|
||||
Py_ssize_t buffer_len;
|
||||
int err;
|
||||
char *keywords[] = {"buffer", "flag", "old_as_path", "buffer_as_path",
|
||||
NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s#ssI", keywords,
|
||||
&buffer, &buffer_len, &opts.flags,
|
||||
&old_as_path, &buffer_as_path))
|
||||
return NULL;
|
||||
|
||||
err = git_patch_from_blob_and_buffer(&patch, self->blob, old_as_path,
|
||||
buffer, buffer_len, buffer_as_path,
|
||||
&opts);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return wrap_patch(patch);
|
||||
}
|
||||
|
||||
static PyMethodDef Blob_methods[] = {
|
||||
METHOD(Blob, diff, METH_VARARGS | METH_KEYWORDS),
|
||||
METHOD(Blob, diff_to_buffer, METH_VARARGS | METH_KEYWORDS),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
PyDoc_STRVAR(Blob_size__doc__, "Size.");
|
||||
|
||||
@ -94,7 +189,7 @@ PyTypeObject BlobType = {
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
Blob_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
Blob_getseters, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
|
74
src/diff.c
74
src/diff.c
@ -57,27 +57,24 @@ wrap_diff(git_diff *diff, Repository *repo)
|
||||
return (PyObject*) py_diff;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
diff_get_patch_byindex(git_diff* diff, size_t idx)
|
||||
PyObject *
|
||||
wrap_patch(git_patch *patch)
|
||||
{
|
||||
const git_diff_delta* delta;
|
||||
const git_diff_hunk *hunk;
|
||||
const git_diff_line *line;
|
||||
git_patch* patch = NULL;
|
||||
size_t i, j, hunk_amounts, lines_in_hunk, additions, deletions;
|
||||
int err;
|
||||
Hunk *py_hunk = NULL;
|
||||
Patch *py_patch = NULL;
|
||||
PyObject *py_line_origin=NULL, *py_line=NULL;
|
||||
Patch *py_patch;
|
||||
|
||||
err = git_patch_from_diff(&patch, diff, idx);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
delta = git_patch_get_delta(patch);
|
||||
if (!patch)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
py_patch = PyObject_New(Patch, &PatchType);
|
||||
if (py_patch != NULL) {
|
||||
if (py_patch) {
|
||||
size_t i, j, hunk_amounts, lines_in_hunk, additions, deletions;
|
||||
const git_diff_delta *delta;
|
||||
const git_diff_hunk *hunk;
|
||||
const git_diff_line *line;
|
||||
int err;
|
||||
|
||||
delta = git_patch_get_delta(patch);
|
||||
|
||||
py_patch->old_file_path = delta->old_file.path;
|
||||
py_patch->new_file_path = delta->new_file.path;
|
||||
py_patch->status = git_diff_status_char(delta->status);
|
||||
@ -92,11 +89,12 @@ diff_get_patch_byindex(git_diff* diff, size_t idx)
|
||||
|
||||
hunk_amounts = git_patch_num_hunks(patch);
|
||||
py_patch->hunks = PyList_New(hunk_amounts);
|
||||
for (i=0; i < hunk_amounts; ++i) {
|
||||
err = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, i);
|
||||
for (i = 0; i < hunk_amounts; ++i) {
|
||||
Hunk *py_hunk = NULL;
|
||||
|
||||
err = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, i);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
return Error_set(err);
|
||||
|
||||
py_hunk = PyObject_New(Hunk, &HunkType);
|
||||
if (py_hunk != NULL) {
|
||||
@ -106,20 +104,20 @@ diff_get_patch_byindex(git_diff* diff, size_t idx)
|
||||
py_hunk->new_lines = hunk->new_lines;
|
||||
|
||||
py_hunk->lines = PyList_New(lines_in_hunk);
|
||||
for (j=0; j < lines_in_hunk; ++j) {
|
||||
for (j = 0; j < lines_in_hunk; ++j) {
|
||||
PyObject *py_line_origin = NULL, *py_line = NULL;
|
||||
|
||||
err = git_patch_get_line_in_hunk(&line, patch, i, j);
|
||||
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
return Error_set(err);
|
||||
|
||||
py_line_origin = to_unicode_n(&line->origin, 1, NULL, NULL);
|
||||
py_line = to_unicode_n(line->content, line->content_len, NULL, NULL);
|
||||
py_line_origin = to_unicode_n(&line->origin, 1,
|
||||
NULL, NULL);
|
||||
py_line = to_unicode_n(line->content, line->content_len,
|
||||
NULL, NULL);
|
||||
PyList_SetItem(py_hunk->lines, j,
|
||||
Py_BuildValue("OO",
|
||||
py_line_origin,
|
||||
py_line
|
||||
)
|
||||
);
|
||||
Py_BuildValue("OO", py_line_origin, py_line));
|
||||
|
||||
Py_DECREF(py_line_origin);
|
||||
Py_DECREF(py_line);
|
||||
}
|
||||
@ -130,10 +128,20 @@ diff_get_patch_byindex(git_diff* diff, size_t idx)
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_patch_free(patch);
|
||||
return (PyObject*) py_patch;
|
||||
}
|
||||
|
||||
return (err < 0) ? Error_set(err) : (PyObject*) py_patch;
|
||||
PyObject*
|
||||
diff_get_patch_byindex(git_diff *diff, size_t idx)
|
||||
{
|
||||
git_patch *patch = NULL;
|
||||
int err;
|
||||
|
||||
err = git_patch_from_diff(&patch, diff, idx);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return (PyObject*) wrap_patch(patch);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -42,5 +42,6 @@ PyObject* Diff_changes(Diff *self);
|
||||
PyObject* Diff_patch(Diff *self);
|
||||
|
||||
PyObject* wrap_diff(git_diff *diff, Repository *repo);
|
||||
PyObject* wrap_patch(git_patch *patch);
|
||||
|
||||
#endif
|
||||
|
@ -105,5 +105,16 @@ class BlobTest(utils.RepoTestCase):
|
||||
self.assertTrue(isinstance(blob, pygit2.Blob))
|
||||
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
|
||||
|
||||
def test_diff_blob(self):
|
||||
blob = self.repo[BLOB_SHA]
|
||||
old_blob = self.repo['3b18e512dba79e4c8300dd08aeb37f8e728b8dad']
|
||||
patch = blob.diff(old_blob, old_as_path="hello.txt")
|
||||
self.assertEqual(len(patch.hunks), 1)
|
||||
|
||||
def test_diff_blob_to_buffer(self):
|
||||
blob = self.repo[BLOB_SHA]
|
||||
patch = blob.diff_to_buffer("hello world")
|
||||
self.assertEqual(len(patch.hunks), 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user