Merge branch 'master' into next

This commit is contained in:
J. David Ibáñez
2013-03-09 21:17:09 +01:00
23 changed files with 386 additions and 333 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ MANIFEST
build
dist
pygit2.so
_pygit2.so
test/*.pyc
test/__pycache__
pygit2/*.pyc

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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);

View File

@@ -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}

View File

@@ -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),

View File

@@ -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;

View File

@@ -1 +1 @@
056e626e51b1fc1ee2182800e399ed8d84c8f082
784855caf26449a1914d2cf62d12b9374d76ae78

View File

@@ -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()

View File

@@ -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__':

View File

@@ -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):

View File

@@ -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'))

View File

@@ -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: