From be807a1dfc0c7a5ea0f3316c6d10e24ad37bacd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20David=20Ib=C3=A1=C3=B1ez?= Date: Mon, 28 Jul 2014 17:51:51 +0200 Subject: [PATCH] internal: split code for Python 2/3 compatibility --- pygit2/__init__.py | 15 ++++---- pygit2/config.py | 4 ++- pygit2/ffi.py | 71 ++----------------------------------- pygit2/index.py | 5 +-- pygit2/py2.py | 47 +++++++++++++++++++++++++ pygit2/py3.py | 46 ++++++++++++++++++++++++ pygit2/refspec.py | 4 ++- pygit2/remote.py | 5 +-- pygit2/repository.py | 10 ++++-- pygit2/utils.py | 83 ++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 206 insertions(+), 84 deletions(-) create mode 100644 pygit2/py2.py create mode 100644 pygit2/py3.py create mode 100644 pygit2/utils.py diff --git a/pygit2/__init__.py b/pygit2/__init__.py index 0d841cc..6da88cf 100644 --- a/pygit2/__init__.py +++ b/pygit2/__init__.py @@ -32,15 +32,16 @@ from __future__ import absolute_import from _pygit2 import * # High level API -from .repository import Repository -from .version import __version__ -from .settings import Settings -from .credentials import * -from .remote import Remote, get_credentials from .config import Config -from .index import Index, IndexEntry +from .credentials import * from .errors import check_error -from .ffi import ffi, C, to_bytes +from .ffi import ffi, C +from .index import Index, IndexEntry +from .remote import Remote, get_credentials +from .repository import Repository +from .settings import Settings +from .utils import to_bytes +from .version import __version__ def init_repository(path, bare=False, diff --git a/pygit2/config.py b/pygit2/config.py index 296d896..9d55fa2 100644 --- a/pygit2/config.py +++ b/pygit2/config.py @@ -28,8 +28,10 @@ # Import from the future from __future__ import absolute_import, unicode_literals -from .ffi import ffi, C, to_bytes, is_string +# Import from pygit2 from .errors import check_error +from .ffi import ffi, C +from .utils import to_bytes, is_string def assert_string(v, desc): diff --git a/pygit2/ffi.py b/pygit2/ffi.py index 8ecb247..4238fe3 100644 --- a/pygit2/ffi.py +++ b/pygit2/ffi.py @@ -28,84 +28,19 @@ # Import from the future from __future__ import absolute_import +# Import from the Standard Library import inspect import codecs from os import path, getenv + +# Import from cffi from cffi import FFI -import sys -(major_version, _, _, _, _) = sys.version_info -if major_version < 3: - def to_bytes(s, encoding='utf-8', errors='strict'): - if s == ffi.NULL or s is None: - return ffi.NULL - - if isinstance(s, unicode): - encoding = encoding or 'utf-8' - return s.encode(encoding, errors) - - return s -else: - def to_bytes(s, encoding='utf-8', errors='strict'): - if s == ffi.NULL or s is None: - return ffi.NULL - - if isinstance(s, bytes): - return s - - return s.encode(encoding, errors) - -if major_version < 3: - def is_string(s): - return isinstance(s, basestring) -else: - def is_string(s): - return isinstance(s, str) ffi = FFI() -def strarray_to_strings(arr): - l = [None] * arr.count - for i in range(arr.count): - l[i] = ffi.string(arr.strings[i]).decode() - - return l - - -def strings_to_strarray(l): - """Convert a list of strings to a git_strarray - - 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. - """ - - if not isinstance(l, list): - raise TypeError("Value must be a list") - - arr = ffi.new('git_strarray *') - strings = ffi.new('char *[]', len(l)) - - # 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) - - for i in range(len(l)): - if not is_string(l[i]): - raise TypeError("Value must be a string") - - s = ffi.new('char []', to_bytes(l[i])) - refs[i] = s - strings[i] = s - - arr.strings = strings - arr.count = len(l) - - return arr, refs - dir_path = path.dirname(path.abspath(inspect.getfile(inspect.currentframe()))) decl_path = path.join(dir_path, 'decl.h') diff --git a/pygit2/index.py b/pygit2/index.py index 63a95fe..f1b851c 100644 --- a/pygit2/index.py +++ b/pygit2/index.py @@ -28,10 +28,11 @@ # Import from the future from __future__ import absolute_import, unicode_literals +# Import from pygit2 from _pygit2 import Oid, Tree, Diff - -from .ffi import ffi, C, to_bytes, is_string, strings_to_strarray from .errors import check_error +from .ffi import ffi, C +from .utils import to_bytes, is_string, strings_to_strarray class Index(object): diff --git a/pygit2/py2.py b/pygit2/py2.py new file mode 100644 index 0000000..af8888b --- /dev/null +++ b/pygit2/py2.py @@ -0,0 +1,47 @@ +# -*- 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. + +# Import from the future +from __future__ import absolute_import + +# Import from pygit2 +from .ffi import ffi + + +def to_bytes(s, encoding='utf-8', errors='strict'): + if s == ffi.NULL or s is None: + return ffi.NULL + + if isinstance(s, unicode): + encoding = encoding or 'utf-8' + return s.encode(encoding, errors) + + return s + + +def is_string(s): + return isinstance(s, basestring) diff --git a/pygit2/py3.py b/pygit2/py3.py new file mode 100644 index 0000000..fa46af1 --- /dev/null +++ b/pygit2/py3.py @@ -0,0 +1,46 @@ +# -*- 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. + +# Import from the future +from __future__ import absolute_import + +# Import from pygit2 +from .ffi import ffi + + +def to_bytes(s, encoding='utf-8', errors='strict'): + if s == ffi.NULL or s is None: + return ffi.NULL + + if isinstance(s, bytes): + return s + + return s.encode(encoding, errors) + + +def is_string(s): + return isinstance(s, str) diff --git a/pygit2/refspec.py b/pygit2/refspec.py index 55d3205..423b72b 100644 --- a/pygit2/refspec.py +++ b/pygit2/refspec.py @@ -28,8 +28,10 @@ # Import from the future from __future__ import absolute_import -from .ffi import ffi, C, to_bytes +# Import from pygit2 from .errors import check_error +from .ffi import ffi, C +from .utils import to_bytes class Refspec(object): diff --git a/pygit2/remote.py b/pygit2/remote.py index 0dca198..b2fdec2 100644 --- a/pygit2/remote.py +++ b/pygit2/remote.py @@ -28,11 +28,12 @@ # Import from the future from __future__ import absolute_import +# Import from pygit2 from _pygit2 import Oid - -from .ffi import ffi, C, to_bytes, strarray_to_strings, strings_to_strarray from .errors import check_error, GitError +from .ffi import ffi, C from .refspec import Refspec +from .utils import to_bytes, strarray_to_strings, strings_to_strarray def maybe_string(ptr): diff --git a/pygit2/repository.py b/pygit2/repository.py index 6b5b41e..45bc170 100644 --- a/pygit2/repository.py +++ b/pygit2/repository.py @@ -25,6 +25,9 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. +# Import from the future +from __future__ import absolute_import + # Import from the Standard Library from string import hexdigits @@ -34,11 +37,12 @@ from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN from _pygit2 import GIT_CHECKOUT_SAFE_CREATE, GIT_DIFF_NORMAL from _pygit2 import Reference, Tree, Commit, Blob -from .ffi import ffi, C, to_bytes -from .errors import check_error -from .remote import Remote from .config import Config +from .errors import check_error +from .ffi import ffi, C from .index import Index +from .remote import Remote +from .utils import to_bytes class Repository(_Repository): diff --git a/pygit2/utils.py b/pygit2/utils.py new file mode 100644 index 0000000..3a4a01a --- /dev/null +++ b/pygit2/utils.py @@ -0,0 +1,83 @@ +# -*- 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. + +# Import from the future +from __future__ import absolute_import + +# Import from the Standard Library +from sys import version_info + +# Import from pygit2 +from .ffi import ffi + + +if version_info[0] < 3: + from .py2 import to_bytes, is_string +else: + from .py3 import to_bytes, is_string + + + +def strarray_to_strings(arr): + l = [None] * arr.count + for i in range(arr.count): + l[i] = ffi.string(arr.strings[i]).decode() + + return l + + +def strings_to_strarray(l): + """Convert a list of strings to a git_strarray + + 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. + """ + + if not isinstance(l, list): + raise TypeError("Value must be a list") + + arr = ffi.new('git_strarray *') + strings = ffi.new('char *[]', len(l)) + + # 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) + + for i in range(len(l)): + if not is_string(l[i]): + raise TypeError("Value must be a string") + + s = ffi.new('char []', to_bytes(l[i])) + refs[i] = s + strings[i] = s + + arr.strings = strings + arr.count = len(l) + + return arr, refs