diff --git a/include/pygit2/types.h b/include/pygit2/types.h index a2c7f56..9b4d917 100644 --- a/include/pygit2/types.h +++ b/include/pygit2/types.h @@ -57,9 +57,16 @@ OBJECT_STRUCT(Blob, git_blob, blob) OBJECT_STRUCT(Tag, git_tag, tag) OBJECT_STRUCT(Index, git_index, index) OBJECT_STRUCT(Walker, git_revwalk, walk) -OBJECT_STRUCT(Diff, git_diff_list, diff) OBJECT_STRUCT(Config, git_config, config) +typedef struct { + PyObject_HEAD + Repository *repo; + git_diff_list *diff; + PyObject *diff_changes; +} Diff; + + typedef struct { PyObject_HEAD PyObject *owner; /* Tree or TreeBuilder */ diff --git a/src/pygit2/config.c b/src/pygit2/config.c index 0983bac..5924a95 100644 --- a/src/pygit2/config.c +++ b/src/pygit2/config.c @@ -133,13 +133,14 @@ int Config_contains(Config *self, PyObject *py_key) { int err; const char *c_value; - const char *c_key; + char *c_key; - if (!(c_key = py_str_to_c_str(py_key,NULL))) + c_key = py_str_to_c_str(py_key,NULL); + if (c_key == NULL) return -1; err = git_config_get_string(&c_value, self->config, c_key); - + free(c_key); if (err == GIT_ENOTFOUND) return 0; if (err < 0) { @@ -154,25 +155,28 @@ PyObject * Config_getitem(Config *self, PyObject *py_key) { int err; - int64_t c_intvalue; - int c_boolvalue; - const char *c_charvalue; - const char *c_key; + int64_t c_intvalue; + int c_boolvalue; + const char *c_charvalue; + char *c_key; if (!(c_key = py_str_to_c_str(py_key,NULL))) return NULL; err = git_config_get_int64(&c_intvalue, self->config, c_key); if (err == GIT_OK) { + free(c_key); return PyInt_FromLong((long)c_intvalue); } err = git_config_get_bool(&c_boolvalue, self->config, c_key); if (err == GIT_OK) { + free(c_key); return PyBool_FromLong((long)c_boolvalue); } err = git_config_get_string(&c_charvalue, self->config, c_key); + free(c_key); if (err < 0) { if (err == GIT_ENOTFOUND) { PyErr_SetObject(PyExc_KeyError, py_key); @@ -188,7 +192,8 @@ int Config_setitem(Config *self, PyObject *py_key, PyObject *py_value) { int err; - const char *c_key; + char *c_key; + char *py_str; if (!(c_key = py_str_to_c_str(py_key,NULL))) return -1; @@ -203,9 +208,12 @@ Config_setitem(Config *self, PyObject *py_key, PyObject *py_value) (int64_t)PyInt_AsLong(py_value)); } else { py_value = PyObject_Str(py_value); - err = git_config_set_string(self->config, c_key, - py_str_to_c_str(py_value,NULL)); + py_str = py_str_to_c_str(py_value,NULL); + err = git_config_set_string(self->config, c_key, py_str); + free(py_str); } + + free(c_key); if (err < 0) { Error_set(err); return -1; diff --git a/src/pygit2/diff.c b/src/pygit2/diff.c index d010442..81751ae 100644 --- a/src/pygit2/diff.c +++ b/src/pygit2/diff.c @@ -48,7 +48,7 @@ static int diff_data_cb( const char *content, size_t content_len) { - PyObject *hunks, *data, *tmp; + PyObject *hunks, *data; Hunk *hunk; Py_ssize_t size; @@ -61,14 +61,12 @@ static int diff_data_cb( if (hunk == NULL) return -1; - tmp = PyBytes_FromStringAndSize(content, content_len); - - data = Py_BuildValue("(O,i)", - tmp, + data = Py_BuildValue("(s#,i)", + content, content_len, line_origin ); - PyList_Append(hunk->data, data); + Py_DECREF(data); return 0; } @@ -91,6 +89,7 @@ static int diff_hunk_cb( if (hunks == NULL) { hunks = PyList_New(0); PyDict_SetItemString(cb_data, "hunks", hunks); + Py_DECREF(hunks); } hunk = (Hunk*)PyType_GenericNew(&HunkType, NULL, NULL); @@ -125,6 +124,7 @@ static int diff_hunk_cb( old_path = malloc(sizeof(char) * len); if (old_path == NULL) { free(hunk->header); + hunk->header = NULL; return -1; } @@ -153,7 +153,12 @@ static int diff_hunk_cb( hunk->data = PyList_New(0); } - PyList_Append(hunks, (PyObject *)hunk); + if(PyList_Append(hunks, (PyObject *)hunk) == 0) { + Py_DECREF(hunk); + } + else { + return -1; + } return 0; }; @@ -169,6 +174,7 @@ static int diff_file_cb(void *cb_data, const git_diff_delta *delta, if(files == NULL) { files = PyList_New(0); PyDict_SetItemString(cb_data, "files", files); + Py_DECREF(files); } file = Py_BuildValue("(s,s,i)", @@ -177,7 +183,10 @@ static int diff_file_cb(void *cb_data, const git_diff_delta *delta, delta->status ); - PyList_Append(files, file); + if (PyList_Append(files, file) == 0) { + // If success + Py_DECREF(file); + } } return 0; @@ -186,18 +195,20 @@ static int diff_file_cb(void *cb_data, const git_diff_delta *delta, PyObject * Diff_changes(Diff *self) { - PyObject *payload; - payload = PyDict_New(); - git_diff_foreach( - self->diff, - payload, - &diff_file_cb, - &diff_hunk_cb, - &diff_data_cb - ); + if (self->diff_changes == NULL) { + self->diff_changes = PyDict_New(); - return payload; + git_diff_foreach( + self->diff, + self->diff_changes, + &diff_file_cb, + &diff_hunk_cb, + &diff_data_cb + ); + } + + return PyDict_Copy(self->diff_changes); } static int diff_print_cb( @@ -227,24 +238,42 @@ Diff_patch(Diff *self) static int Hunk_init(Hunk *self, PyObject *args, PyObject *kwds) { - self->old_start = 0; - self->old_lines = 0; + self->header = NULL; - self->new_start = 0; - self->new_lines = 0; + self->old_file = NULL; + self->old_start = 0; + self->old_lines = 0; - self->data = PyList_New(0); - if (self->data == NULL) { - Py_XDECREF(self); - return -1; - } + self->new_file = NULL; + self->new_start = 0; + self->new_lines = 0; - return 0; + self->old_oid = NULL; + self->new_oid = NULL; + + self->data = PyList_New(0); + if (self->data == NULL) { + Py_XDECREF(self); + return -1; + } + + return 0; } static void Hunk_dealloc(Hunk *self) { + if (self->header != NULL) { + free(self->header); + } + if (self->new_file != NULL) { + free(self->new_file); + } + if (self->old_file != NULL) { + free(self->old_file); + } + Py_XDECREF(self->old_oid); + Py_XDECREF(self->new_oid); Py_XDECREF(self->data); PyObject_Del(self); } @@ -321,6 +350,8 @@ Diff_merge(Diff *self, PyObject *args) if (err < 0) return Error_set(err); + Py_XDECREF(self->diff_changes); + self->diff_changes = NULL; Py_RETURN_NONE; } @@ -329,6 +360,7 @@ Diff_dealloc(Diff *self) { git_diff_list_free(self->diff); Py_XDECREF(self->repo); + Py_XDECREF(self->diff_changes); PyObject_Del(self); } diff --git a/src/pygit2/index.c b/src/pygit2/index.c index e800733..327e314 100644 --- a/src/pygit2/index.c +++ b/src/pygit2/index.c @@ -216,6 +216,7 @@ Index_get_position(Index *self, PyObject *value) free(path); return -1; } + free(path); return idx; } @@ -229,14 +230,16 @@ Index_contains(Index *self, PyObject *value) if (!path) return -1; idx = git_index_find(self->index, path); - if (idx == GIT_ENOTFOUND) + if (idx == GIT_ENOTFOUND) { + free(path); return 0; + } if (idx < 0) { Error_set_str(idx, path); free(path); return -1; } - + free(path); return 1; } @@ -341,6 +344,7 @@ Index_read_tree(Index *self, PyObject *value) return Error_set(err); err = git_index_read_tree(self->index, tree); + git_tree_free(tree); if (err < 0) return Error_set(err); diff --git a/src/pygit2/object.c b/src/pygit2/object.c index 172cf3f..c990fd2 100644 --- a/src/pygit2/object.c +++ b/src/pygit2/object.c @@ -176,7 +176,7 @@ wrap_object(git_object *c_object, Repository *repo) if (py_obj) { py_obj->obj = c_object; - if (repo) { + if (repo) { py_obj->repo = repo; Py_INCREF(repo); } diff --git a/src/pygit2/repository.c b/src/pygit2/repository.c index 0fcfbb7..2754591 100644 --- a/src/pygit2/repository.c +++ b/src/pygit2/repository.c @@ -166,6 +166,7 @@ Repository_head(Repository *self) { git_reference *head; const git_oid *oid; + PyObject *pyobj; int err; err = git_repository_head(&head, self->repo); @@ -179,8 +180,9 @@ Repository_head(Repository *self) } oid = git_reference_oid(head); - - return lookup_object(self, oid, GIT_OBJ_COMMIT); + pyobj = lookup_object(self, oid, GIT_OBJ_COMMIT); + git_reference_free(head); + return pyobj; } @@ -202,7 +204,7 @@ Repository_revparse_single(Repository *self, PyObject *py_spec) { git_object *c_obj; char *c_spec; - char *encoding = "ascii"; + char *encoding = "ascii"; int err; /* 1- Get the C revision spec */ @@ -212,11 +214,13 @@ Repository_revparse_single(Repository *self, PyObject *py_spec) /* 2- Lookup */ err = git_revparse_single(&c_obj, self->repo, c_spec); - if (err < 0) { + + if (err < 0) { PyObject *err_obj = Error_set_str(err, c_spec); free(c_spec); return err_obj; } + free(c_spec); return wrap_object(c_obj, self); } @@ -630,12 +634,12 @@ Repository_lookup_reference(Repository *self, PyObject *py_name) /* 2- Lookup */ err = git_reference_lookup(&c_reference, self->repo, c_name); - if (err < 0) { + if (err < 0) { PyObject *err_obj = Error_set_str(err, c_name); free(c_name); return err_obj; } - + free(c_name); /* 3- Make an instance of Reference and return it */ return wrap_reference(c_reference); } diff --git a/src/pygit2/signature.c b/src/pygit2/signature.c index cd53a32..cb8425d 100644 --- a/src/pygit2/signature.c +++ b/src/pygit2/signature.c @@ -85,7 +85,7 @@ Signature_dealloc(Signature *self) Py_DECREF(self->obj); else { git_signature_free((git_signature*)self->signature); - free((void*)self->encoding); + free((char*)self->encoding); } Py_TYPE(self)->tp_free((PyObject*)self); } diff --git a/src/pygit2/tree.c b/src/pygit2/tree.c index 097c609..ccdeea6 100644 --- a/src/pygit2/tree.c +++ b/src/pygit2/tree.c @@ -43,6 +43,7 @@ void TreeEntry_dealloc(TreeEntry *self) { Py_XDECREF(self->owner); + git_tree_entry_free((git_tree_entry*)self->entry); PyObject_Del(self); } @@ -231,7 +232,7 @@ Tree_getitem_by_index(Tree *self, PyObject *py_index) PyErr_SetObject(PyExc_IndexError, py_index); return NULL; } - return wrap_tree_entry(entry, self); + return wrap_tree_entry(git_tree_entry_dup(entry), self); } TreeEntry * @@ -249,7 +250,7 @@ Tree_getitem(Tree *self, PyObject *value) path = py_path_to_c_str(value); if (path == NULL) return NULL; - + err = git_tree_entry_bypath(&entry, self->tree, path); free(path); @@ -261,6 +262,7 @@ Tree_getitem(Tree *self, PyObject *value) if (err < 0) return (TreeEntry*)Error_set(err); + // git_tree_entry_dup is already done in git_tree_entry_bypath return wrap_tree_entry(entry, self); } @@ -274,7 +276,7 @@ Tree_diff_tree(Tree *self, PyObject *args) Diff *py_diff; PyObject *py_obj = NULL; - if (!PyArg_ParseTuple(args, "|O", &py_obj)) + if (!PyArg_ParseTuple(args, "|Oi", &py_obj, &opts.flags)) return NULL; if (py_obj == NULL) { @@ -306,10 +308,10 @@ Tree_diff_tree(Tree *self, PyObject *args) py_diff = PyObject_New(Diff, &DiffType); if (py_diff) { - Py_INCREF(py_diff); Py_INCREF(self->repo); py_diff->repo = self->repo; py_diff->diff = diff; + py_diff->diff_changes = NULL; } return (PyObject*)py_diff; @@ -528,7 +530,7 @@ TreeIter_iternext(TreeIter *self) return NULL; self->i += 1; - return (TreeEntry*)wrap_tree_entry(tree_entry, self->owner); + return (TreeEntry*)wrap_tree_entry(git_tree_entry_dup(tree_entry), self->owner); } PyTypeObject TreeIterType = { diff --git a/test/data/testrepo.git/objects/18/e2d2e9db075f9eb43bcb2daa65a2867d29a15e b/test/data/testrepo.git/objects/18/e2d2e9db075f9eb43bcb2daa65a2867d29a15e new file mode 100644 index 0000000..4e796d7 Binary files /dev/null and b/test/data/testrepo.git/objects/18/e2d2e9db075f9eb43bcb2daa65a2867d29a15e differ diff --git a/test/data/testrepo.git/objects/77/88019febe4f40259a64c529a9aed561e64ddbd b/test/data/testrepo.git/objects/77/88019febe4f40259a64c529a9aed561e64ddbd new file mode 100644 index 0000000..189c2d5 Binary files /dev/null and b/test/data/testrepo.git/objects/77/88019febe4f40259a64c529a9aed561e64ddbd differ diff --git a/test/data/testrepo.git/objects/cc/ca47fbb26183e71a7a46d165299b84e2e6c0b3 b/test/data/testrepo.git/objects/cc/ca47fbb26183e71a7a46d165299b84e2e6c0b3 new file mode 100644 index 0000000..bed3d1e --- /dev/null +++ b/test/data/testrepo.git/objects/cc/ca47fbb26183e71a7a46d165299b84e2e6c0b3 @@ -0,0 +1,2 @@ +x[j0DUB#%(%[[ +Iwп9ҷ> a"I֓咭06Ilb㡮b.}Iވ9ss0|YXN[}ZmS \ No newline at end of file diff --git a/test/data/testrepo.git/refs/heads/master b/test/data/testrepo.git/refs/heads/master index e863952..101232d 100644 --- a/test/data/testrepo.git/refs/heads/master +++ b/test/data/testrepo.git/refs/heads/master @@ -1 +1 @@ -2cdae28389c059815e951d0bb9eed6533f61a46b +ccca47fbb26183e71a7a46d165299b84e2e6c0b3 diff --git a/test/test_diff.py b/test/test_diff.py index 5f61b09..6fa9ba0 100644 --- a/test/test_diff.py +++ b/test/test_diff.py @@ -30,13 +30,14 @@ from __future__ import absolute_import from __future__ import unicode_literals import unittest - +import pygit2 from . import utils COMMIT_SHA1_1 = '5fe808e8953c12735680c257f56600cb0de44b10' COMMIT_SHA1_2 = 'c2792cfa289ae6321ecf2cd5806c2194b0fd070c' COMMIT_SHA1_3 = '2cdae28389c059815e951d0bb9eed6533f61a46b' +COMMIT_SHA1_4 = 'ccca47fbb26183e71a7a46d165299b84e2e6c0b3' PATCH = b"""diff --git a/a b/a index 7f129fd..af431f2 100644 @@ -133,6 +134,20 @@ class DiffTest(utils.BareRepoTestCase): #self.assertEqual(hunk.data[0][0], b'a contents 2\n') #self.assertEqual(hunk.data[1][0], b'a contents\n') + def test_diff_tree_opts(self): + commit_c = self.repo[COMMIT_SHA1_3] + commit_d = self.repo[COMMIT_SHA1_4] + + for opt in [pygit2.GIT_DIFF_IGNORE_WHITESPACE, + 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()))) + + diff = commit_c.tree.diff(commit_d.tree) + self.assertTrue(diff is not None) + self.assertEqual(1, len(diff.changes.get('hunks', list()))) + def test_diff_merge(self): commit_a = self.repo[COMMIT_SHA1_1] commit_b = self.repo[COMMIT_SHA1_2] diff --git a/test/test_refs.py b/test/test_refs.py index 5ba77e1..b61d855 100644 --- a/test/test_refs.py +++ b/test/test_refs.py @@ -175,9 +175,9 @@ class ReferencesTest(utils.RepoTestCase): reference = self.repo.lookup_reference('refs/tags/version1') self.assertEqual(reference.hex, LAST_COMMIT) - # try to create existing reference - self.assertRaises(ValueError, self.repo.create_reference, - 'refs/tags/version1', LAST_COMMIT) + # try to create existing reference + self.assertRaises(ValueError, self.repo.create_reference, + 'refs/tags/version1', LAST_COMMIT) # try to create existing reference with force reference = self.repo.create_reference('refs/tags/version1', @@ -195,8 +195,8 @@ class ReferencesTest(utils.RepoTestCase): # try to create existing symbolic reference - self.assertRaises(ValueError, self.repo.create_reference, - 'refs/tags/beta','refs/heads/master', symbolic=True) + self.assertRaises(ValueError, self.repo.create_reference, + 'refs/tags/beta','refs/heads/master', symbolic=True) # try to create existing symbolic reference with force reference = self.repo.create_reference('refs/tags/beta', diff --git a/test/test_repository.py b/test/test_repository.py index fa3a932..5f38322 100644 --- a/test/test_repository.py +++ b/test/test_repository.py @@ -39,8 +39,8 @@ from pygit2 import GIT_OBJ_ANY, GIT_OBJ_BLOB, GIT_OBJ_COMMIT, init_repository, \ from . import utils -HEAD_SHA = '2cdae28389c059815e951d0bb9eed6533f61a46b' -PARENT_SHA = '5fe808e8953c12735680c257f56600cb0de44b10' # HEAD^ +HEAD_SHA = 'ccca47fbb26183e71a7a46d165299b84e2e6c0b3' +PARENT_SHA = '2cdae28389c059815e951d0bb9eed6533f61a46b' # HEAD^ A_HEX_SHA = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16' A_BIN_SHA = binascii.unhexlify(A_HEX_SHA.encode('ascii'))