Diff and Patch interface refactored

This commit is contained in:
Petr Hosek
2014-02-15 19:58:19 +00:00
committed by J. David Ibáñez
parent da98890bd1
commit a3cb12e928
10 changed files with 722 additions and 290 deletions

View File

@@ -28,106 +28,14 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "blob.h"
#include "diff.h"
#include "error.h"
#include "object.h"
#include "patch.h"
#include "utils.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"
":param Blob blob: the :py:class:`~pygit2.Blob` to diff.\n"
"\n"
":param flag: a GIT_DIFF_* constant.\n"
"\n"
":param str old_as_path: treat old blob as if it had this filename.\n"
"\n"
":param str new_as_path: treat new blob as if it had this filename.\n"
"\n"
":rtype: Patch\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!Iss", 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"
":param Blob buffer: Raw data for new side of diff.\n"
"\n"
":param flag: a GIT_DIFF_* constant.\n"
"\n"
":param str old_as_path: treat old blob as if it had this filename.\n"
"\n"
":param str buffer_as_path: treat buffer as if it had this filename.\n"
"\n"
":rtype: Patch\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#Iss", 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.");
PyObject *
@@ -246,7 +154,7 @@ PyTypeObject BlobType = {
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Blob_methods, /* tp_methods */
0, /* tp_methods */
0, /* tp_members */
Blob_getseters, /* tp_getset */
0, /* tp_base */

View File

@@ -103,41 +103,24 @@ wrap_diff_delta(const git_diff_delta *delta)
}
PyObject *
wrap_diff_hunk(git_patch *patch, size_t idx)
wrap_diff_hunk(const git_diff_hunk *hunk, size_t idx, Patch *patch)
{
DiffHunk *py_hunk;
const git_diff_hunk *hunk;
const git_diff_line *line;
size_t j, lines_in_hunk;
int err;
err = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, idx);
if (err < 0)
return Error_set(err);
if (!hunk)
Py_RETURN_NONE;
py_hunk = PyObject_New(DiffHunk, &DiffHunkType);
if (py_hunk) {
Py_INCREF(patch);
py_hunk->patch = patch;
py_hunk->index = idx;
py_hunk->old_start = hunk->old_start;
py_hunk->old_lines = hunk->old_lines;
py_hunk->new_start = hunk->new_start;
py_hunk->new_lines = hunk->new_lines;
py_hunk->header = to_unicode_n((const char *) &hunk->header,
hunk->header_len, NULL, NULL);
py_hunk->lines = PyList_New(lines_in_hunk);
for (j = 0; j < lines_in_hunk; ++j) {
PyObject *py_line = NULL;
err = git_patch_get_line_in_hunk(&line, patch, idx, j);
if (err < 0)
return Error_set(err);
py_line = wrap_diff_line(line);
if (py_line == NULL)
return NULL;
PyList_SetItem(py_hunk->lines, j, py_line);
}
}
return (PyObject *) py_hunk;
@@ -180,7 +163,6 @@ PyMemberDef DiffFile_members[] = {
{NULL}
};
PyDoc_STRVAR(DiffFile__doc__, "DiffFile object.");
PyTypeObject DiffFileType = {
@@ -390,44 +372,45 @@ PyTypeObject DiffLineType = {
};
PyObject *
diff_get_patch_byindex(git_diff *diff, size_t idx)
diff_hunk_get_line_byindex(git_patch *patch, size_t hunk_idx, size_t hunk_line)
{
git_patch *patch = NULL;
const git_diff_line *line = NULL;
int err;
err = git_patch_from_diff(&patch, diff, idx);
err = git_patch_get_line_in_hunk(&line, patch, hunk_idx, hunk_line);
if (err < 0)
return Error_set(err);
return (PyObject*) wrap_patch(patch);
return (PyObject*) wrap_diff_line(line);
}
PyObject *
DiffIter_iternext(DiffIter *self)
DiffHunkIter_iternext(DiffHunkIter *self)
{
if (self->i < self->n)
return diff_get_patch_byindex(self->diff->diff, self->i++);
return diff_hunk_get_line_byindex(self->hunk->patch->patch,
self->hunk->index, self->i++);
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
void
DiffIter_dealloc(DiffIter *self)
static void
DiffHunkIter_dealloc(DiffHunkIter *self)
{
Py_CLEAR(self->diff);
Py_CLEAR(self->hunk);
PyObject_Del(self);
}
PyDoc_STRVAR(DiffIter__doc__, "Diff iterator object.");
PyDoc_STRVAR(DiffHunkIter__doc__, "Diff Hunk iterator object.");
PyTypeObject DiffIterType = {
PyTypeObject DiffHunkIterType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_pygit2.DiffIter", /* tp_name */
sizeof(DiffIter), /* tp_basicsize */
"_pygit2.DiffHunkIter", /* tp_name */
sizeof(DiffHunkIter), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)DiffIter_dealloc, /* tp_dealloc */
(destructor)DiffHunkIter_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
@@ -443,74 +426,78 @@ PyTypeObject DiffIterType = {
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
DiffIter__doc__, /* tp_doc */
DiffHunkIter__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc) DiffIter_iternext, /* tp_iternext */
(iternextfunc) DiffHunkIter_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_patch__doc__, "Patch diff string.");
PyObject *
Diff_patch__get__(Diff *self)
DiffHunk_iter(DiffHunk *self)
{
git_patch* patch;
git_buf buf = {NULL};
int err = GIT_ERROR;
size_t i, num;
PyObject *py_patch = NULL;
DiffHunkIter *iter;
num = git_diff_num_deltas(self->diff);
if (num == 0)
Py_RETURN_NONE;
for (i = 0; i < num ; ++i) {
err = git_patch_from_diff(&patch, self->diff, i);
if (err < 0)
goto cleanup;
/* This appends to the current buf, so we can simply keep passing it */
err = git_patch_to_buf(&buf, patch);
if (err < 0)
goto cleanup;
git_patch_free(patch);
iter = PyObject_New(DiffHunkIter, &DiffHunkIterType);
if (iter != NULL) {
Py_INCREF(self);
iter->hunk = self;
iter->i = 0;
iter->n = git_patch_num_lines_in_hunk(self->patch->patch, self->index);
}
py_patch = to_unicode(buf.ptr, NULL, NULL);
git_buf_free(&buf);
cleanup:
git_buf_free(&buf);
return (err < 0) ? Error_set(err) : py_patch;
return (PyObject*)iter;
}
Py_ssize_t
DiffHunk_len(DiffHunk *self)
{
assert(self->hunk);
return (Py_ssize_t)git_patch_num_lines_in_hunk(self->patch->patch,
self->index);
}
PyObject *
DiffHunk_getitem(DiffHunk *self, PyObject *value)
{
size_t i;
if (PyLong_Check(value) < 0) {
PyErr_SetObject(PyExc_IndexError, value);
return NULL;
}
i = PyLong_AsUnsignedLong(value);
if (PyErr_Occurred()) {
PyErr_SetObject(PyExc_IndexError, value);
return NULL;
}
return diff_hunk_get_line_byindex(self->patch->patch, self->index, i);
}
static void
DiffHunk_dealloc(DiffHunk *self)
{
Py_CLEAR(self->header);
Py_CLEAR(self->lines);
Py_CLEAR(self->patch);
PyObject_Del(self);
}
PyMappingMethods DiffHunk_as_mapping = {
(lenfunc)DiffHunk_len, /* mp_length */
(binaryfunc)DiffHunk_getitem, /* mp_subscript */
0, /* mp_ass_subscript */
};
PyMemberDef DiffHunk_members[] = {
MEMBER(DiffHunk, old_start, T_INT, "Old start."),
MEMBER(DiffHunk, old_lines, T_INT, "Old lines."),
MEMBER(DiffHunk, new_start, T_INT, "New start."),
MEMBER(DiffHunk, new_lines, T_INT, "New lines."),
MEMBER(DiffHunk, header, T_OBJECT, "Header."),
MEMBER(DiffHunk, lines, T_OBJECT, "Lines."),
{NULL}
};
@@ -530,7 +517,7 @@ PyTypeObject DiffHunkType = {
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
&DiffHunk_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
@@ -543,7 +530,7 @@ PyTypeObject DiffHunkType = {
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
(getiterfunc)DiffHunk_iter, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
DiffHunk_members, /* tp_members */
@@ -586,6 +573,141 @@ Diff_from_c(Diff *dummy, PyObject *args)
return wrap_diff(diff, (Repository *) py_repository);
}
PyObject *
DiffPatchIter_iternext(DiffPatchIter *self)
{
if (self->i < self->n) {
git_patch *patch = NULL;
int err;
err = git_patch_from_diff(&patch, self->diff->diff, self->i++);
if (err < 0)
return Error_set(err);
return (PyObject *) wrap_patch(patch);
}
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
static void
DiffPatchIter_dealloc(DiffPatchIter *self)
{
Py_CLEAR(self->diff);
PyObject_Del(self);
}
PyDoc_STRVAR(DiffPatchIter__doc__, "Diff Patch iterator object.");
PyTypeObject DiffPatchIterType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_pygit2.DiffPatchIter", /* tp_name */
sizeof(DiffPatchIter), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)DiffPatchIter_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 */
DiffPatchIter__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc) DiffPatchIter_iternext, /* tp_iternext */
};
PyDoc_STRVAR(Diff_patches__doc__, "Get the delta associated with a patch.");
PyObject *
Diff_patches(Diff *self)
{
DiffPatchIter *iter;
iter = PyObject_New(DiffPatchIter, &DiffPatchIterType);
if (iter != NULL) {
Py_INCREF(self);
iter->diff = self;
iter->i = 0;
iter->n = git_diff_num_deltas(self->diff);
}
return (PyObject*)iter;
}
PyObject *
DiffIter_iternext(DiffIter *self)
{
if (self->i < self->n)
return wrap_diff_delta(git_diff_get_delta(self->diff->diff,
self->i++));
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
void
DiffIter_dealloc(DiffIter *self)
{
Py_CLEAR(self->diff);
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 */
};
Py_ssize_t
Diff_len(Diff *self)
{
assert(self->diff);
return (Py_ssize_t)git_diff_num_deltas(self->diff);
}
PyDoc_STRVAR(Diff_merge__doc__,
"merge(diff)\n"
"\n"
@@ -654,14 +776,25 @@ PyObject *
Diff_getitem(Diff *self, PyObject *value)
{
size_t i;
const git_diff_delta *delta;
if (!PyLong_Check(value))
return NULL;
i = PyLong_AsUnsignedLong(value);
return diff_get_patch_byindex(self->diff, i);
}
if (PyErr_Occurred()) {
PyErr_SetObject(PyExc_IndexError, value);
return NULL;
}
delta = git_diff_get_delta(self->diff, i);
if (!delta) {
PyErr_SetObject(PyExc_IndexError, value);
return NULL;
}
return wrap_diff_delta(delta);
}
static void
Diff_dealloc(Diff *self)
@@ -671,11 +804,6 @@ Diff_dealloc(Diff *self)
PyObject_Del(self);
}
PyGetSetDef Diff_getseters[] = {
GETTER(Diff, patch),
{NULL}
};
PyMappingMethods Diff_as_mapping = {
(lenfunc)Diff_len, /* mp_length */
(binaryfunc)Diff_getitem, /* mp_subscript */
@@ -686,10 +814,10 @@ static PyMethodDef Diff_methods[] = {
METHOD(Diff, merge, METH_VARARGS),
METHOD(Diff, find_similar, METH_VARARGS | METH_KEYWORDS),
METHOD(Diff, from_c, METH_STATIC | METH_VARARGS),
METHOD(Diff, patches, METH_NOARGS),
{NULL}
};
PyDoc_STRVAR(Diff__doc__, "Diff objects.");
PyTypeObject DiffType = {
@@ -722,7 +850,7 @@ PyTypeObject DiffType = {
0, /* tp_iternext */
Diff_methods, /* tp_methods */
0, /* tp_members */
Diff_getseters, /* tp_getset */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */

View File

@@ -33,13 +33,10 @@
#include <git2.h>
#include "types.h"
PyObject* Diff_changes(Diff *self);
PyObject* Diff_patch(Diff *self);
PyObject* wrap_diff(git_diff *diff, Repository *repo);
PyObject* wrap_diff_delta(const git_diff_delta *delta);
PyObject* wrap_diff_file(const git_diff_file *file);
PyObject * wrap_diff_hunk(git_patch *patch, size_t idx);
PyObject* wrap_diff_hunk(const git_diff_hunk *hunk, size_t idx, Patch *patch);
PyObject* wrap_diff_line(const git_diff_line *line);
#endif

View File

@@ -30,13 +30,18 @@
#include <structmember.h>
#include "diff.h"
#include "error.h"
#include "oid.h"
#include "patch.h"
#include "types.h"
#include "utils.h"
extern PyTypeObject DiffHunkType;
PyTypeObject PatchType;
extern PyObject *GitError;
extern PyTypeObject BlobType;
extern PyTypeObject DiffType;
extern PyTypeObject DiffHunkType;
extern PyTypeObject IndexType;
extern PyTypeObject PatchType;
extern PyTypeObject TreeType;
PyObject *
wrap_patch(git_patch *patch)
@@ -49,29 +54,305 @@ wrap_patch(git_patch *patch)
Py_RETURN_NONE;
py_patch = PyObject_New(Patch, &PatchType);
if (py_patch) {
if (py_patch)
py_patch->patch = patch;
hunk_amounts = git_patch_num_hunks(patch);
py_patch->hunks = PyList_New(hunk_amounts);
for (i = 0; i < hunk_amounts; ++i) {
py_hunk = wrap_diff_hunk(patch, i);
if (py_hunk)
PyList_SetItem((PyObject*) py_patch->hunks, i, py_hunk);
}
}
return (PyObject*) py_patch;
}
static void
Patch_dealloc(Patch *self)
PyObject *
patch_get_hunk_byindex(Patch *self, size_t idx)
{
Py_CLEAR(self->hunks);
git_patch_free(self->patch);
const git_diff_hunk *hunk = NULL;
int err;
err = git_patch_get_hunk(&hunk, NULL, self->patch, idx);
if (err < 0)
return Error_set(err);
return (PyObject*) wrap_diff_hunk(hunk, idx, self);
}
PyObject *
PatchIter_iternext(PatchIter *self)
{
if (self->i < self->n)
return patch_get_hunk_byindex(self->patch, self->i++);
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
static void
PatchIter_dealloc(PatchIter *self)
{
Py_CLEAR(self->patch);
PyObject_Del(self);
}
PyDoc_STRVAR(PatchIter__doc__, "Patch iterator object.");
PyTypeObject PatchIterType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_pygit2.PatchIter", /* tp_name */
sizeof(PatchIter), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PatchIter_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 */
PatchIter__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
PyObject_SelfIter, /* tp_iter */
(iternextfunc) PatchIter_iternext, /* tp_iternext */
};
PyObject *
Patch_iter(Patch *self)
{
PatchIter *iter;
iter = PyObject_New(PatchIter, &PatchIterType);
if (iter != NULL) {
Py_INCREF(self);
iter->patch = self;
iter->i = 0;
iter->n = git_patch_num_hunks(self->patch);
}
return (PyObject*)iter;
}
Py_ssize_t
Patch_len(Patch *self)
{
assert(self->patch);
return (Py_ssize_t)git_patch_num_hunks(self->patch);
}
PyObject *
Patch_getitem(Patch *self, PyObject *value)
{
size_t i;
if (PyLong_Check(value) < 0) {
PyErr_SetObject(PyExc_IndexError, value);
return NULL;
}
i = PyLong_AsUnsignedLong(value);
if (PyErr_Occurred()) {
PyErr_SetObject(PyExc_IndexError, value);
return NULL;
}
return patch_get_hunk_byindex(self, i);
}
PyObject *
Patch__str__(Patch *self)
{
git_buf buf = {NULL};
int err;
PyObject *py_str;
err = git_patch_to_buf(&buf, self->patch);
if (err < 0)
goto cleanup;
py_str = to_unicode(buf.ptr, NULL, NULL);
cleanup:
git_buf_free(&buf);
return (err < 0) ? Error_set(err) : py_str;
}
PyDoc_STRVAR(Patch_from_blob_and_buffer__doc__,
"from_blob_and_buffer([old_blob, old_as_path, buffer, buffer_as_path,\n"
" flags] -> Patch\n"
"\n"
"Directly generate a :py:class:`~pygit2.Patch` from the difference\n"
"between a blob and a buffer.\n"
"\n"
":param Blob old_blob: the :py:class:`~pygit2.Blob` for old side of diff.\n"
"\n"
":param str old_as_path: treat old blob as if it had this filename.\n"
"\n"
":param Blob buffer: Raw data for new side of diff.\n"
"\n"
":param str buffer_as_path: treat buffer as if it had this filename.\n"
"\n"
":param flag: a GIT_DIFF_* constant.\n"
"\n"
":rtype: Patch\n");
PyObject *
Patch_from_blob_and_buffer(PyTypeObject *type, 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;
Blob *py_old_blob = NULL;
int err;
char *keywords[] = {"old_blob", "old_as_path", "buffer", "buffer_as_path",
"flags", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!ss#sI", keywords,
&BlobType, &py_old_blob, &old_as_path,
&buffer, &buffer_len, &buffer_as_path,
&opts.flags))
return NULL;
err = git_patch_from_blob_and_buffer(&patch,
py_old_blob ? py_old_blob->blob : NULL,
old_as_path,
buffer,
buffer_len,
buffer_as_path,
&opts);
if (err < 0)
return Error_set(err);
return wrap_patch(patch);
}
PyDoc_STRVAR(Patch_from_blobs__doc__,
"from_blobs([old_blob, old_as_path, new_blob, new_as_path, flags] -> Patch\n"
"\n"
"Directly generate a :py:class:`pygit2.Patch` from the difference\n"
"between two blobs.\n"
"\n"
":param Blob old_blob: the :py:class:`~pygit2.Blob` for old side of diff.\n"
"\n"
":param str old_as_path: treat old blob as if it had this filename.\n"
"\n"
":param Blob new_blob: the :py:class:`~pygit2.Blob` for new side of diff.\n"
"\n"
":param str new_as_path: treat new blob as if it had this filename.\n"
"\n"
":param flag: a GIT_DIFF_* constant.\n"
"\n"
":rtype: Patch\n");
PyObject *
Patch_from_blobs(PyTypeObject *type, 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_new_blob = NULL, *py_old_blob = NULL;
int err;
char *keywords[] = {"old_blob", "old_as_path", "new_blob", "new_as_path",
"flags", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!sO!sI", keywords,
&BlobType, &py_old_blob, &old_as_path,
&BlobType, &py_new_blob, &new_as_path,
&opts.flags))
return NULL;
err = git_patch_from_blobs(&patch,
py_old_blob ? py_old_blob->blob : NULL,
old_as_path,
py_new_blob ? py_new_blob->blob : NULL,
new_as_path,
&opts);
if (err < 0)
return Error_set(err);
return wrap_patch(patch);
}
PyDoc_STRVAR(Patch_from_diff__doc__,
"from_diff(diff, idx) -> Patch\n"
"\n"
"Return the :py:class:`pygit2.Patch` for an entry in the diff list.\n"
"\n"
"Arguments:\n"
"\n"
"diff: the :py:class:`~pygit2.Diff` list object.\n"
"\n"
"idx: index into diff list.\n");
PyObject *
Patch_from_diff(PyTypeObject *type, PyObject *args)
{
git_patch *patch;
Diff *py_diff;
Py_ssize_t idx;
int err;
if (!PyArg_ParseTuple(args, "O!n", &DiffType, &py_diff, &idx))
return NULL;
err = git_patch_from_diff(&patch, py_diff->diff, idx);
if (err < 0)
return Error_set(err);
return wrap_patch(patch);
}
PyDoc_STRVAR(Patch_size__doc__,
"size([include_context, include_hunk_headers, include_file_headers]) -> size\n"
"\n"
"Look up size of patch diff data in bytes.\n"
"\n"
"Arguments:\n"
"\n"
"include_context: include context lines in size if non-zero.\n"
"\n"
"include_hunk_headers: include hunk header lines if non-zero.\n"
"\n"
"include_file_headers: include file header lines if non-zero.");
PyObject *
Patch_size(Patch *self, PyObject *args, PyObject *kwds)
{
int context = 0, hunk_headers = 0, file_headers = 0;
PyObject *py_context = NULL;
PyObject *py_hunk_headers = NULL;
PyObject *py_file_headers = NULL;
char *keywords[] = {"include_context", "include_hunk_headers",
"include_file_headers", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!O!", keywords,
&PyBool_Type, &py_context,
&PyBool_Type, &py_hunk_headers,
&PyBool_Type, &py_file_headers))
return NULL;
if (py_context)
context = PyObject_IsTrue(py_context);
if (py_hunk_headers)
hunk_headers = PyObject_IsTrue(py_hunk_headers);
if (py_file_headers)
file_headers = PyObject_IsTrue(py_file_headers);
return PyLong_FromSize_t(git_patch_size(self->patch,
context, hunk_headers, file_headers));
}
PyDoc_STRVAR(Patch_delta__doc__, "Get the delta associated with a patch.");
PyObject *
@@ -103,8 +384,24 @@ Patch_line_stats__get__(Patch *self)
return Py_BuildValue("III", context, additions, deletions);
}
PyMemberDef Patch_members[] = {
MEMBER(Patch, hunks, T_OBJECT, "hunks"),
void
Patch_dealloc(Patch *self)
{
git_patch_free(self->patch);
PyObject_Del(self);
}
PyMappingMethods Patch_as_mapping = {
(lenfunc)Patch_len, /* mp_length */
(binaryfunc)Patch_getitem, /* mp_subscript */
0, /* mp_ass_subscript */
};
PyMethodDef Patch_methods[] = {
METHOD(Patch, from_blob_and_buffer, METH_VARARGS | METH_KEYWORDS | METH_CLASS),
METHOD(Patch, from_blobs, METH_VARARGS | METH_KEYWORDS | METH_CLASS),
METHOD(Patch, from_diff, METH_VARARGS | METH_KEYWORDS | METH_CLASS),
METHOD(Patch, size, METH_VARARGS | METH_KEYWORDS),
{NULL}
};
@@ -114,7 +411,7 @@ PyGetSetDef Patch_getseters[] = {
{NULL}
};
PyDoc_STRVAR(Patch__doc__, "Diff patch object.");
PyDoc_STRVAR(Patch__doc__, "Patch object.");
PyTypeObject PatchType = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -129,10 +426,10 @@ PyTypeObject PatchType = {
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
&Patch_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
(reprfunc)Patch__str__, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
@@ -142,10 +439,10 @@ PyTypeObject PatchType = {
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
(getiterfunc)Patch_iter, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
Patch_members, /* tp_members */
Patch_methods, /* tp_methods */
0, /* tp_members */
Patch_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */

View File

@@ -48,8 +48,10 @@ extern PyTypeObject DiffIterType;
extern PyTypeObject DiffDeltaType;
extern PyTypeObject DiffFileType;
extern PyTypeObject DiffHunkType;
extern PyTypeObject DiffHunkIterType;
extern PyTypeObject DiffLineType;
extern PyTypeObject PatchType;
extern PyTypeObject PatchIterType;
extern PyTypeObject TreeType;
extern PyTypeObject TreeBuilderType;
extern PyTypeObject TreeEntryType;
@@ -300,14 +302,13 @@ moduleinit(PyObject* m)
INIT_TYPE(DiffDeltaType, NULL, NULL)
INIT_TYPE(DiffFileType, NULL, NULL)
INIT_TYPE(DiffHunkType, NULL, NULL)
INIT_TYPE(DiffHunkIterType, NULL, NULL)
INIT_TYPE(DiffLineType, NULL, NULL)
INIT_TYPE(PatchType, NULL, NULL)
ADD_TYPE(m, Diff)
ADD_TYPE(m, DiffDelta)
ADD_TYPE(m, DiffFile)
ADD_TYPE(m, DiffHunk)
ADD_TYPE(m, DiffLine)
ADD_TYPE(m, Patch)
ADD_CONSTANT_INT(m, GIT_DIFF_NORMAL)
ADD_CONSTANT_INT(m, GIT_DIFF_REVERSE)
ADD_CONSTANT_INT(m, GIT_DIFF_FORCE_TEXT)
@@ -340,6 +341,25 @@ moduleinit(PyObject* m)
ADD_CONSTANT_INT(m, GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED)
/* --break-rewrites=/M */
ADD_CONSTANT_INT(m, GIT_DIFF_FIND_AND_BREAK_REWRITES)
ADD_CONSTANT_INT(m, GIT_DIFF_FLAG_BINARY)
ADD_CONSTANT_INT(m, GIT_DIFF_FLAG_NOT_BINARY)
ADD_CONSTANT_INT(m, GIT_DIFF_FLAG_VALID_ID)
ADD_CONSTANT_INT(m, GIT_DELTA_UNMODIFIED)
ADD_CONSTANT_INT(m, GIT_DELTA_ADDED)
ADD_CONSTANT_INT(m, GIT_DELTA_DELETED)
ADD_CONSTANT_INT(m, GIT_DELTA_MODIFIED)
ADD_CONSTANT_INT(m, GIT_DELTA_RENAMED)
ADD_CONSTANT_INT(m, GIT_DELTA_COPIED)
ADD_CONSTANT_INT(m, GIT_DELTA_IGNORED)
ADD_CONSTANT_INT(m, GIT_DELTA_UNTRACKED)
ADD_CONSTANT_INT(m, GIT_DELTA_TYPECHANGE)
/*
* Patch
*/
INIT_TYPE(PatchType, NULL, NULL)
INIT_TYPE(PatchIterType, NULL, NULL)
ADD_TYPE(m, Patch)
/* DiffDelta and DiffFile flags */
ADD_CONSTANT_INT(m, GIT_DIFF_FLAG_BINARY)

View File

@@ -98,11 +98,14 @@ typedef struct {
} NoteIter;
/* git_patch */
SIMPLE_TYPE(Patch, git_patch, patch)
typedef struct {
PyObject_HEAD
git_patch *patch;
PyObject* hunks;
} Patch;
Patch *patch;
size_t i;
size_t n;
} PatchIter;
/* git_diff */
SIMPLE_TYPE(Diff, git_diff, diff)
@@ -114,6 +117,13 @@ typedef struct {
size_t n;
} DiffIter;
typedef struct {
PyObject_HEAD
Diff *diff;
size_t i;
size_t n;
} DiffPatchIter;
typedef struct {
PyObject_HEAD
PyObject *id;
@@ -135,7 +145,9 @@ typedef struct {
typedef struct {
PyObject_HEAD
PyObject* lines;
Patch *patch;
git_diff_hunk *hunk;
size_t index;
int old_start;
int old_lines;
int new_start;
@@ -143,6 +155,13 @@ typedef struct {
PyObject *header;
} DiffHunk;
typedef struct {
PyObject_HEAD
DiffHunk *hunk;
size_t i;
size_t n;
} DiffHunkIter;
typedef struct {
PyObject_HEAD
char origin;

View File

@@ -112,16 +112,5 @@ 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()

View File

@@ -47,22 +47,6 @@ COMMIT_SHA1_6 = 'f5e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87'
COMMIT_SHA1_7 = '784855caf26449a1914d2cf62d12b9374d76ae78'
PATCH = """diff --git a/a b/a
index 7f129fd..af431f2 100644
--- a/a
+++ b/a
@@ -1 +1 @@
-a contents 2
+a contents
diff --git a/c/d b/c/d
deleted file mode 100644
index 297efb8..0000000
--- a/c/d
+++ /dev/null
@@ -1 +0,0 @@
-c/d contents
"""
DIFF_HEAD_TO_INDEX_EXPECTED = [
'staged_changes',
'staged_changes_file_deleted',
@@ -108,11 +92,11 @@ class DiffDirtyTest(utils.DirtyRepoTestCase):
head = repo[repo.lookup_reference('HEAD').resolve().target]
diff = head.tree.diff_to_index(repo.index)
files = [patch.delta.new_file.path for patch in diff]
files = [delta.new_file.path for delta in diff]
self.assertEqual(DIFF_HEAD_TO_INDEX_EXPECTED, files)
diff = repo.diff('HEAD', cached=True)
files = [patch.delta.new_file.path for patch in diff]
files = [delta.new_file.path for delta in diff]
self.assertEqual(DIFF_HEAD_TO_INDEX_EXPECTED, files)
def test_workdir_to_tree(self):
@@ -120,16 +104,16 @@ class DiffDirtyTest(utils.DirtyRepoTestCase):
head = repo[repo.lookup_reference('HEAD').resolve().target]
diff = head.tree.diff_to_workdir()
files = [patch.delta.new_file.path for patch in diff]
files = [delta.new_file.path for delta in diff]
self.assertEqual(DIFF_HEAD_TO_WORKDIR_EXPECTED, files)
diff = repo.diff('HEAD')
files = [patch.delta.new_file.path for patch in diff]
files = [delta.new_file.path for delta in diff]
self.assertEqual(DIFF_HEAD_TO_WORKDIR_EXPECTED, files)
def test_index_to_workdir(self):
diff = self.repo.diff()
files = [patch.delta.new_file.path for patch in diff]
files = [delta.new_file.path for delta in diff]
self.assertEqual(DIFF_INDEX_TO_WORK_EXPECTED, files)
@@ -146,15 +130,15 @@ class DiffTest(utils.BareRepoTestCase):
head = repo[repo.lookup_reference('HEAD').resolve().target]
diff = self.repo.index.diff_to_tree(head.tree)
files = [patch.delta.new_file.path.split('/')[0] for patch in diff]
files = [delta.new_file.path.split('/')[0] for delta in diff]
self.assertEqual([x.name for x in head.tree], files)
diff = head.tree.diff_to_index(repo.index)
files = [patch.delta.new_file.path.split('/')[0] for patch in diff]
files = [delta.new_file.path.split('/')[0] for delta in diff]
self.assertEqual([x.name for x in head.tree], files)
diff = repo.diff('HEAD', cached=True)
files = [patch.delta.new_file.path.split('/')[0] for patch in diff]
files = [delta.new_file.path.split('/')[0] for delta in diff]
self.assertEqual([x.name for x in head.tree], files)
def test_diff_tree(self):
@@ -165,18 +149,19 @@ class DiffTest(utils.BareRepoTestCase):
# self.assertIsNotNone is 2.7 only
self.assertTrue(diff is not None)
# self.assertIn is 2.7 only
self.assertEqual(2, sum(map(lambda x: len(x.hunks), diff)))
self.assertEqual(2, sum(map(lambda x: len(x), diff.patches())))
patch = diff[0]
hunk = patch.hunks[0]
patch = pygit2.Patch.from_diff(diff, 0)
hunk = patch[0]
self.assertEqual(hunk.old_start, 1)
self.assertEqual(hunk.old_lines, 1)
self.assertEqual(hunk.new_start, 1)
self.assertEqual(hunk.new_lines, 1)
self.assertEqual(patch.delta.old_file.path, 'a')
self.assertEqual(patch.delta.new_file.path, 'a')
self.assertEqual(patch.delta.is_binary, False)
delta = diff[0]
self.assertEqual(delta.old_file.path, 'a')
self.assertEqual(delta.new_file.path, 'a')
self.assertEqual(delta.is_binary, False)
_test(commit_a.tree.diff_to_tree(commit_b.tree))
_test(self.repo.diff(COMMIT_SHA1_1, COMMIT_SHA1_2))
@@ -187,16 +172,16 @@ class DiffTest(utils.BareRepoTestCase):
diff = commit_a.tree.diff_to_tree()
def get_context_for_lines(diff):
hunks = chain(*map(lambda x: x.hunks, [p for p in diff]))
lines = chain(*map(lambda x: x.lines, hunks))
hunks = chain(*map(lambda x: x, [p for p in diff.patches()]))
lines = chain(*map(lambda x: x, hunks))
return map(lambda x: x.origin, lines)
entries = [p.delta.new_file.path for p in diff]
entries = [delta.new_file.path for delta in diff]
self.assertAll(lambda x: commit_a.tree[x], entries)
self.assertAll(lambda x: '-' == x, get_context_for_lines(diff))
diff_swaped = commit_a.tree.diff_to_tree(swap=True)
entries = [p.delta.new_file.path for p in diff_swaped]
entries = [delta.new_file.path for delta in diff_swaped]
self.assertAll(lambda x: commit_a.tree[x], entries)
self.assertAll(lambda x: '+' == x, get_context_for_lines(diff_swaped))
@@ -212,11 +197,13 @@ class DiffTest(utils.BareRepoTestCase):
GIT_DIFF_IGNORE_WHITESPACE_EOL]:
diff = commit_c.tree.diff_to_tree(commit_d.tree, flag)
self.assertTrue(diff is not None)
self.assertEqual(0, len(diff[0].hunks))
patch = pygit2.Patch.from_diff(diff, 0)
self.assertEqual(0, len(patch))
diff = commit_c.tree.diff_to_tree(commit_d.tree)
self.assertTrue(diff is not None)
self.assertEqual(1, len(diff[0].hunks))
patch = pygit2.Patch.from_diff(diff, 0)
self.assertEqual(1, len(patch))
def test_diff_merge(self):
commit_a = self.repo[COMMIT_SHA1_1]
@@ -232,16 +219,16 @@ class DiffTest(utils.BareRepoTestCase):
self.assertTrue(diff_c is not None)
# assertIn / assertNotIn are 2.7 only
self.assertFalse('b' in [patch.delta.new_file.path for patch in diff_b])
self.assertTrue('b' in [patch.delta.new_file.path for patch in diff_c])
self.assertFalse('b' in [delta.new_file.path for delta in diff_b])
self.assertTrue('b' in [delta.new_file.path for delta in diff_c])
diff_b.merge(diff_c)
# assertIn is 2.7 only
self.assertTrue('b' in [patch.delta.new_file.path for patch in diff_b])
self.assertTrue('b' in [delta.new_file.path for delta in diff_b])
patch = diff_b[0]
hunk = patch.hunks[0]
patch = pygit2.Patch.from_diff(diff_b, 0)
hunk = patch[0]
self.assertEqual(hunk.old_start, 1)
self.assertEqual(hunk.old_lines, 1)
self.assertEqual(hunk.new_start, 1)
@@ -250,29 +237,22 @@ class DiffTest(utils.BareRepoTestCase):
self.assertEqual(patch.delta.old_file.path, 'a')
self.assertEqual(patch.delta.new_file.path, 'a')
def test_diff_patch(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)
self.assertEqual(diff.patch, PATCH)
self.assertEqual(len(diff), len([patch for patch in diff]))
def test_diff_ids(self):
commit_a = self.repo[COMMIT_SHA1_1]
commit_b = self.repo[COMMIT_SHA1_2]
patch = commit_a.tree.diff_to_tree(commit_b.tree)[0]
self.assertEqual(patch.delta.old_file.id.hex,
delta = commit_a.tree.diff_to_tree(commit_b.tree)[0]
self.assertEqual(delta.old_file.id.hex,
'7f129fd57e31e935c6d60a0c794efe4e6927664b')
self.assertEqual(patch.delta.new_file.id.hex,
self.assertEqual(delta.new_file.id.hex,
'af431f20fc541ed6d5afede3e2dc7160f6f01f16')
def test_hunk_content(self):
commit_a = self.repo[COMMIT_SHA1_1]
commit_b = self.repo[COMMIT_SHA1_2]
patch = commit_a.tree.diff_to_tree(commit_b.tree)[0]
hunk = patch.hunks[0]
lines = ('{0} {1}'.format(x.origin, x.content) for x in hunk.lines)
diff = commit_a.tree.diff_to_tree(commit_b.tree)
patch = pygit2.Patch.from_diff(diff, 0)
hunk = patch[0]
lines = ('{0} {1}'.format(x.origin, x.content) for x in hunk)
self.assertEqual(HUNK_EXPECTED, ''.join(lines))
def test_find_similar(self):
@@ -283,11 +263,11 @@ class DiffTest(utils.BareRepoTestCase):
#~ --find-copies-harder during rename transformion...
diff = commit_a.tree.diff_to_tree(commit_b.tree,
GIT_DIFF_INCLUDE_UNMODIFIED)
self.assertAll(lambda x: x.delta.status != GIT_DELTA_RENAMED, diff)
self.assertAll(lambda x: x.delta.status_char() != 'R', diff)
self.assertAll(lambda delta: delta.status != GIT_DELTA_RENAMED, diff)
self.assertAll(lambda delta: delta.status_char() != 'R', diff)
diff.find_similar()
self.assertAny(lambda x: x.delta.status == GIT_DELTA_RENAMED, diff)
self.assertAny(lambda x: x.delta.status_char() == 'R', diff)
self.assertAny(lambda delta: delta.status == GIT_DELTA_RENAMED, diff)
self.assertAny(lambda delta: delta.status_char() == 'R', diff)
if __name__ == '__main__':
unittest.main()

93
test/test_patch.py Normal file
View File

@@ -0,0 +1,93 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
# as published by the Free Software Foundation.
#
# In addition to the permissions in the GNU General Public License,
# the authors give you unlimited permission to link the compiled
# version of this file into combinations with other programs,
# and to distribute those combinations without any restriction
# coming from the use of this file. (The General Public License
# restrictions do apply in other respects; for example, they cover
# modification of the file, and distribution when not linked into
# a combined executable.)
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
"""Tests for Patch objects."""
from __future__ import absolute_import
from __future__ import unicode_literals
from os.path import dirname, join
import unittest
import pygit2
from . import utils
COMMIT_SHA1_1 = '5fe808e8953c12735680c257f56600cb0de44b10'
COMMIT_SHA1_2 = 'c2792cfa289ae6321ecf2cd5806c2194b0fd070c'
PATCH = """diff --git a/a b/a
index 7f129fd..af431f2 100644
--- a/a
+++ b/a
@@ -1 +1 @@
-a contents 2
+a contents
diff --git a/c/d b/c/d
deleted file mode 100644
index 297efb8..0000000
--- a/c/d
+++ /dev/null
@@ -1 +0,0 @@
-c/d contents
"""
BLOB_SHA = 'a520c24d85fbfc815d385957eed41406ca5a860b'
BLOB_CONTENT = """hello world
hola mundo
bonjour le monde
""".encode()
BLOB_NEW_CONTENT = b'foo bar\n'
BLOB_FILE_CONTENT = b'bye world\n'
class DiffTest(utils.BareRepoTestCase):
def test_diff_patch(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)
self.assertEqual(''.join([str(pygit2.Patch.from_diff(diff, i)) for i in range(len(diff))]), PATCH)
self.assertEqual(len(diff), len([patch for patch in diff]))
class BlobTest(utils.RepoTestCase):
def test_diff_blob(self):
old_blob = self.repo[BLOB_SHA]
new_blob = self.repo['3b18e512dba79e4c8300dd08aeb37f8e728b8dad']
patch = pygit2.Patch.from_blobs(old_blob, "hello.txt", new_blob)
self.assertEqual(len(patch), 1)
self.assertEqual(patch.delta.old_file.path, "hello.txt")
def test_diff_blob_to_buffer(self):
old_blob = self.repo[BLOB_SHA]
patch = pygit2.Patch.from_blob_and_buffer(old_blob, buffer="hello world")
self.assertEqual(len(patch), 1)
if __name__ == '__main__':
unittest.main()

View File

@@ -381,7 +381,7 @@ class RepositoryTest_II(utils.RepoTestCase):
#soft reset will keep changes in the index
diff = self.repo.diff(cached=True)
self.assertRaises(KeyError, lambda: diff[0])
self.assertTrue(KeyError, lambda: diff[0])
def test_reset_mixed(self):
ref = "5ebeeebb320790caf276b9fc8b24546d63316533"
@@ -404,8 +404,9 @@ class RepositoryTest_II(utils.RepoTestCase):
#mixed reset will set the index to match working copy
diff = self.repo.diff(cached=True)
self.assertTrue("hola mundo\n" in diff.patch)
self.assertTrue("bonjour le monde\n" in diff.patch)
self.assertTrue("hola mundo\n" in ''.join([str(patch) for patch in diff.patches()]))
self.assertTrue("bonjour le monde\n" in ''.join([str(patch) for patch in diff.patches()]))
class RepositorySignatureTest(utils.RepoTestCase):