diff --git a/.gitignore b/.gitignore index e95efa8..71926bd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /pygit2-0.21.2.tar.gz /pygit2-0.21.3.tar.gz /pygit2-0.21.4.tar.gz +/pygit2-0.22.0.tar.gz diff --git a/0001-Remove-remote-calling-unit-tests.patch b/0001-Remove-remote-calling-unit-tests.patch index d26182f..d4844be 100644 --- a/0001-Remove-remote-calling-unit-tests.patch +++ b/0001-Remove-remote-calling-unit-tests.patch @@ -1,20 +1,20 @@ -From c846d973b2797ad52fa6991f86f0794c8373d961 Mon Sep 17 00:00:00 2001 -From: Mathieu Bridon -Date: Fri, 19 Sep 2014 17:25:38 +0200 +From 7552a25ca68931143332e49edd072bd92e7f9904 Mon Sep 17 00:00:00 2001 +From: Mathieu Bridon +Date: Wed, 21 Jan 2015 09:33:46 +0100 Subject: [PATCH] Remove remote-calling unit tests These can only fail when building in Koji, as the builder can't access the Internet. --- - test/test_credentials.py | 18 ------------------ + test/test_credentials.py | 17 ----------------- test/test_repository.py | 8 -------- - 2 files changed, 26 deletions(-) + 2 files changed, 25 deletions(-) diff --git a/test/test_credentials.py b/test/test_credentials.py -index 3bdeb6f..22dbacc 100644 +index 376032f..abcce52 100644 --- a/test/test_credentials.py +++ b/test/test_credentials.py -@@ -71,23 +71,5 @@ class CredentialCallback(utils.RepoTestCase): +@@ -79,23 +79,6 @@ class CredentialCallback(utils.RepoTestCase): self.assertRaises(Exception, remote.fetch) @@ -35,16 +35,16 @@ index 3bdeb6f..22dbacc 100644 - remote.credentials = UserPass("libgit2", "libgit2") - - remote.fetch() -- + if __name__ == '__main__': unittest.main() diff --git a/test/test_repository.py b/test/test_repository.py -index 72a5e64..9cbca66 100644 +index 7640f39..decb974 100644 --- a/test/test_repository.py +++ b/test/test_repository.py -@@ -454,14 +454,6 @@ class CloneRepositoryTest(utils.NoRepoTestCase): - clone_into(repo, remote) - self.assertTrue('refs/remotes/origin/master' in repo.listall_references()) +@@ -457,14 +457,6 @@ class CloneRepositoryTest(utils.NoRepoTestCase): + self.assertTrue('refs/remotes/custom_remote/master' in repo.listall_references()) + self.assertIsNotNone(repo.remotes["custom_remote"]) - def test_clone_with_credentials(self): - credentials = pygit2.UserPass("libgit2", "libgit2") diff --git a/0001-Safer-handling-of-string-arrays.patch b/0001-Safer-handling-of-string-arrays.patch new file mode 100644 index 0000000..1e24c19 --- /dev/null +++ b/0001-Safer-handling-of-string-arrays.patch @@ -0,0 +1,172 @@ +From 6b935d6b53fdfcf6d83a0016487da807ed3a9139 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= +Date: Fri, 6 Feb 2015 03:41:37 +0100 +Subject: [PATCH] Safer handling of string arrays + +We need to keep hold of the strings which we create. We must also hold +on to the array of strings which we assing to our git_strarray. + +We were not doing the latter, which meant that our strings may have been +freed too early, leaving us with with memory access errors (though often +not leading to a crash due to the custom allocator in python). + +As we need to keep hold of two/three pieces of information, this looks +like a good place to introduce a context manager. This allows us to +keep these pointers alive without burdening the call sites with a return +of multiple objects they have no use for. +--- + pygit2/index.py | 8 ++++---- + pygit2/remote.py | 20 ++++++++++---------- + pygit2/utils.py | 46 +++++++++++++++++++++++----------------------- + 3 files changed, 37 insertions(+), 37 deletions(-) + +diff --git a/pygit2/index.py b/pygit2/index.py +index 61b7c97..47d4cd6 100644 +--- a/pygit2/index.py ++++ b/pygit2/index.py +@@ -32,7 +32,7 @@ from __future__ import absolute_import, unicode_literals + from _pygit2 import Oid, Tree, Diff + from .errors import check_error + from .ffi import ffi, C +-from .utils import is_string, strings_to_strarray, to_bytes, to_str ++from .utils import is_string, to_bytes, to_str, StrArray + + + class Index(object): +@@ -175,9 +175,9 @@ class Index(object): + If pathspecs are specified, only files matching those pathspecs will + be added. + """ +- arr, refs = strings_to_strarray(pathspecs) +- err = C.git_index_add_all(self._index, arr, 0, ffi.NULL, ffi.NULL) +- check_error(err, True) ++ with StrArray(pathspecs) as arr: ++ err = C.git_index_add_all(self._index, arr, 0, ffi.NULL, ffi.NULL) ++ check_error(err, True) + + def add(self, path_or_entry): + """add([path|entry]) +diff --git a/pygit2/remote.py b/pygit2/remote.py +index c4a195f..d2fbdcf 100644 +--- a/pygit2/remote.py ++++ b/pygit2/remote.py +@@ -34,7 +34,7 @@ from .errors import check_error, GitError + from .ffi import ffi, C + from .credentials import KeypairFromAgent + from .refspec import Refspec +-from .utils import to_bytes, strarray_to_strings, strings_to_strarray ++from .utils import to_bytes, strarray_to_strings, StrArray + + + def maybe_string(ptr): +@@ -253,9 +253,9 @@ class Remote(object): + + @fetch_refspecs.setter + def fetch_refspecs(self, l): +- arr, refs = strings_to_strarray(l) +- err = C.git_remote_set_fetch_refspecs(self._remote, arr) +- check_error(err) ++ with StrArray(l) as arr: ++ err = C.git_remote_set_fetch_refspecs(self._remote, arr) ++ check_error(err) + + @property + def push_refspecs(self): +@@ -269,9 +269,9 @@ class Remote(object): + + @push_refspecs.setter + def push_refspecs(self, l): +- arr, refs = strings_to_strarray(l) +- err = C.git_remote_set_push_refspecs(self._remote, arr) +- check_error(err) ++ with StrArray(l) as arr: ++ err = C.git_remote_set_push_refspecs(self._remote, arr) ++ check_error(err) + + def add_fetch(self, spec): + """add_fetch(refspec) +@@ -305,7 +305,6 @@ class Remote(object): + err = C.git_remote_init_callbacks(defaultcallbacks, 1) + check_error(err) + +- refspecs, refspecs_refs = strings_to_strarray(specs) + if signature: + sig_cptr = ffi.new('git_signature **') + ffi.buffer(sig_cptr)[:] = signature._pointer[:] +@@ -333,8 +332,9 @@ class Remote(object): + raise + + try: +- err = C.git_remote_push(self._remote, refspecs, ffi.NULL, sig_ptr, to_bytes(message)) +- check_error(err) ++ with StrArray(specs) as refspecs: ++ err = C.git_remote_push(self._remote, refspecs, ffi.NULL, sig_ptr, to_bytes(message)) ++ check_error(err) + finally: + self._self_handle = None + +diff --git a/pygit2/utils.py b/pygit2/utils.py +index 3c5fc88..17582a4 100644 +--- a/pygit2/utils.py ++++ b/pygit2/utils.py +@@ -50,34 +50,34 @@ def strarray_to_strings(arr): + return l + + +-def strings_to_strarray(l): +- """Convert a list of strings to a git_strarray ++class StrArray(object): ++ """A git_strarray wrapper + +- We return first the git_strarray* you can pass to libgit2 and a +- list of references to the memory, which we must keep around for as +- long as the git_strarray must live. +- """ ++ Use this in order to get a git_strarray* to pass to libgit2 out of a ++ list of strings. This has a context manager, which you should use, e.g. + +- if not isinstance(l, list): +- raise TypeError("Value must be a list") ++ with StrArray(list_of_strings) as arr: ++ C.git_function_that_takes_strarray(arr) ++ """ + +- arr = ffi.new('git_strarray *') +- strings = ffi.new('char *[]', len(l)) ++ def __init__(self, l): ++ if not isinstance(l, list): ++ raise TypeError("Value must be a list") + +- # We need refs in order to keep a reference to the value returned +- # by the ffi.new(). Otherwise, they will be freed and the memory +- # re-used, with less than great consequences. +- refs = [None] * len(l) ++ arr = ffi.new('git_strarray *') ++ strings = [None] * len(l) ++ for i in range(len(l)): ++ if not is_string(l[i]): ++ raise TypeError("Value must be a string") + +- for i in range(len(l)): +- if not is_string(l[i]): +- raise TypeError("Value must be a string") ++ strings[i] = ffi.new('char []', to_bytes(l[i])) + +- s = ffi.new('char []', to_bytes(l[i])) +- refs[i] = s +- strings[i] = s ++ self._arr = ffi.new('char *[]', strings) ++ self._strings = strings ++ self.array = ffi.new('git_strarray *', [self._arr, len(strings)]) + +- arr.strings = strings +- arr.count = len(l) ++ def __enter__(self): ++ return self.array + +- return arr, refs ++ def __exit__(self, type, value, traceback): ++ pass +-- +2.1.0 + diff --git a/python-pygit2.spec b/python-pygit2.spec index 87b7422..e9043e1 100644 --- a/python-pygit2.spec +++ b/python-pygit2.spec @@ -1,7 +1,7 @@ %global pkgname pygit2 Name: python-%{pkgname} -Version: 0.21.4 +Version: 0.22.0 Release: 1%{?dist} Summary: Python 2.x bindings for libgit2 URL: http://www.pygit2.org @@ -16,11 +16,15 @@ BuildRequires: python-setuptools Requires: python-cffi -Patch0: 0001-Remove-remote-calling-unit-tests.patch +Patch1: 0001-Remove-remote-calling-unit-tests.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1186880 +# https://github.com/libgit2/pygit2/pull/487 +Patch2: 0001-Safer-handling-of-string-arrays.patch %description pygit2 is a set of Python bindings to the libgit2 library, which implements -the core of Git. Pygit2 works with Python 2.7, 3.1, 3.2, 3.3 and 3.4. +the core of Git. Pygit2 works with Python 2.7, 3.1, 3.2, 3.3, 3.4 and pypy. %package -n python3-%{pkgname} @@ -50,7 +54,8 @@ Documentation for %{name}. %prep %setup -qn %{pkgname}-%{version} -%patch0 -p1 +%patch1 -p1 +%patch2 -p1 rm -rf %{py3dir} cp -a . %{py3dir} @@ -103,6 +108,9 @@ popd %changelog +* Wed Jan 21 2015 Mathieu Bridon - 0.22.0-1 +- Update to 0.22.0 + * Mon Nov 17 2014 Mathieu Bridon - 0.21.4-1 - Update to 0.21.4 diff --git a/sources b/sources index 439b191..5d28080 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -8a3d02eded2bef2e0af18172814eec32 pygit2-0.21.4.tar.gz +31dc65b3cbe6e39d75a39db86dd7cd8c pygit2-0.22.0.tar.gz