Merge branch 'python3'
This commit is contained in:
commit
ef9a5f6e55
@ -1,7 +1,8 @@
|
||||
pygit2 - libgit2 bindings in Python
|
||||
=====================================
|
||||
|
||||
pygit2 is a set of Python 2.5+ bindings to the libgit2 linkable C Git library.
|
||||
pygit2 is a set of Python bindings to the libgit2 linkable C Git library.
|
||||
The supported versions of Python are 2.6, 2.7, 3.1 and 3.2
|
||||
|
||||
INSTALLING AND RUNNING
|
||||
========================
|
||||
@ -16,7 +17,7 @@ For instance, in Debian-based systems run:
|
||||
|
||||
$ sudo apt-get install zlib1g-dev libssl-dev
|
||||
|
||||
Also, make sure you have Python 2.5+ installed together with the Python development headers.
|
||||
Also, make sure you have Python 2.6+ installed together with the Python development headers.
|
||||
|
||||
When those are installed, you can install pygit2:
|
||||
|
||||
|
153
pygit2.c
153
pygit2.c
@ -277,26 +277,37 @@ py_str_to_git_oid(PyObject *py_str, git_oid *oid)
|
||||
const char *hex_or_bin;
|
||||
int err;
|
||||
|
||||
hex_or_bin = PyString_AsString(py_str);
|
||||
if (hex_or_bin == NULL) {
|
||||
Error_set_py_obj(GIT_ENOTOID, py_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PyString_Size(py_str) == 20) {
|
||||
/* Case 1: raw sha */
|
||||
if (PyString_Check(py_str)) {
|
||||
hex_or_bin = PyString_AsString(py_str);
|
||||
if (hex_or_bin == NULL)
|
||||
return 0;
|
||||
git_oid_fromraw(oid, (const unsigned char*)hex_or_bin);
|
||||
err = 0;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
|
||||
/* Case 2: hex sha */
|
||||
if (PyUnicode_Check(py_str)) {
|
||||
py_str = PyUnicode_AsASCIIString(py_str);
|
||||
if (py_str == NULL)
|
||||
return 0;
|
||||
hex_or_bin = PyString_AsString(py_str);
|
||||
Py_DECREF(py_str);
|
||||
if (hex_or_bin == NULL)
|
||||
return 0;
|
||||
err = git_oid_fromstr(oid, hex_or_bin);
|
||||
if (err < 0) {
|
||||
Error_set_py_obj(err, py_str);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
Error_set_py_obj(err, py_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
/* Type error */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Git object id must be byte or a text string, not: %.200s",
|
||||
Py_TYPE(py_str)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
@ -305,7 +316,32 @@ git_oid_to_py_str(const git_oid *oid)
|
||||
char hex[GIT_OID_HEXSZ];
|
||||
|
||||
git_oid_fmt(hex, oid);
|
||||
return PyString_FromStringAndSize(hex, GIT_OID_HEXSZ);
|
||||
return PyUnicode_DecodeASCII(hex, GIT_OID_HEXSZ, "strict");
|
||||
}
|
||||
|
||||
char *
|
||||
py_str_to_c_str(PyObject *value)
|
||||
{
|
||||
char *c_str;
|
||||
|
||||
/* Case 1: byte string */
|
||||
if (PyString_Check(value))
|
||||
return PyString_AsString(value);
|
||||
|
||||
/* Case 2: text string */
|
||||
if (PyUnicode_Check(value)) {
|
||||
value = PyUnicode_AsUTF8String(value);
|
||||
if (value == NULL)
|
||||
return NULL;
|
||||
c_str = PyString_AsString(value);
|
||||
Py_DECREF(value);
|
||||
return c_str;
|
||||
}
|
||||
|
||||
/* Type error */
|
||||
PyErr_Format(PyExc_TypeError, "unexpected %.200s",
|
||||
Py_TYPE(value)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -494,11 +530,6 @@ Repository_walk(Repository *self, PyObject *args)
|
||||
if (!PyArg_ParseTuple(args, "OI", &value, &sort))
|
||||
return NULL;
|
||||
|
||||
if (value != Py_None && !PyString_Check(value)) {
|
||||
PyErr_SetObject(PyExc_TypeError, value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_revwalk_new(&walk, self->repo);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
@ -1027,7 +1058,14 @@ Commit_get_message_encoding(Commit *commit)
|
||||
static PyObject *
|
||||
Commit_get_message(Commit *commit)
|
||||
{
|
||||
return PyString_FromString(git_commit_message(commit->commit));
|
||||
const char *encoding;
|
||||
const char *message;
|
||||
int len;
|
||||
|
||||
encoding = git_commit_message_encoding(commit->commit);
|
||||
message = git_commit_message(commit->commit);
|
||||
len = strlen(message);
|
||||
return PyUnicode_Decode(message, (Py_ssize_t)len, encoding, "strict");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -1269,7 +1307,7 @@ Tree_contains(Tree *self, PyObject *py_name)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = PyString_AsString(py_name);
|
||||
name = py_str_to_c_str(py_name);
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
|
||||
@ -1290,21 +1328,6 @@ wrap_tree_entry(const git_tree_entry *entry, Tree *tree)
|
||||
return py_entry;
|
||||
}
|
||||
|
||||
static TreeEntry *
|
||||
Tree_getitem_by_name(Tree *self, PyObject *py_name)
|
||||
{
|
||||
char *name;
|
||||
const git_tree_entry *entry;
|
||||
|
||||
name = PyString_AS_STRING(py_name);
|
||||
entry = git_tree_entry_byname(self->tree, name);
|
||||
if (!entry) {
|
||||
PyErr_SetObject(PyExc_KeyError, py_name);
|
||||
return NULL;
|
||||
}
|
||||
return wrap_tree_entry(entry, self);
|
||||
}
|
||||
|
||||
static int
|
||||
Tree_fix_index(Tree *self, PyObject *py_index)
|
||||
{
|
||||
@ -1371,18 +1394,23 @@ Tree_getitem_by_index(Tree *self, PyObject *py_index)
|
||||
static TreeEntry *
|
||||
Tree_getitem(Tree *self, PyObject *value)
|
||||
{
|
||||
if (PyString_Check(value)) {
|
||||
return Tree_getitem_by_name(self, value);
|
||||
}
|
||||
else if (PyInt_Check(value)) {
|
||||
char *name;
|
||||
const git_tree_entry *entry;
|
||||
|
||||
/* Case 1: integer */
|
||||
if (PyInt_Check(value))
|
||||
return Tree_getitem_by_index(self, value);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Tree entry index must be int or str, not %.200s",
|
||||
Py_TYPE(value)->tp_name);
|
||||
|
||||
/* Case 2: byte or text string */
|
||||
name = py_str_to_c_str(value);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
entry = git_tree_entry_byname(self->tree, name);
|
||||
if (!entry) {
|
||||
PyErr_SetObject(PyExc_KeyError, value);
|
||||
return NULL;
|
||||
}
|
||||
return wrap_tree_entry(entry, self);
|
||||
}
|
||||
|
||||
static PySequenceMethods Tree_as_sequence = {
|
||||
@ -1750,17 +1778,8 @@ Index_get_position(Index *self, PyObject *value)
|
||||
char *path;
|
||||
int idx;
|
||||
|
||||
if (PyString_Check(value)) {
|
||||
path = PyString_AsString(value);
|
||||
if (!path)
|
||||
return -1;
|
||||
idx = git_index_find(self->index, path);
|
||||
if (idx < 0) {
|
||||
Error_set_str(idx, path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (PyInt_Check(value)) {
|
||||
/* Case 1: integer */
|
||||
if (PyInt_Check(value)) {
|
||||
idx = (int)PyInt_AsLong(value);
|
||||
if (idx == -1 && PyErr_Occurred())
|
||||
return -1;
|
||||
@ -1768,14 +1787,18 @@ Index_get_position(Index *self, PyObject *value)
|
||||
PyErr_SetObject(PyExc_ValueError, value);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Index entry key must be int or str, not %.200s",
|
||||
Py_TYPE(value)->tp_name);
|
||||
return -1;
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* Case 2: byte or text string */
|
||||
path = py_str_to_c_str(value);
|
||||
if (!path)
|
||||
return -1;
|
||||
idx = git_index_find(self->index, path);
|
||||
if (idx < 0) {
|
||||
Error_set_str(idx, path);
|
||||
return -1;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
@ -1785,7 +1808,7 @@ Index_contains(Index *self, PyObject *value)
|
||||
char *path;
|
||||
int idx;
|
||||
|
||||
path = PyString_AsString(value);
|
||||
path = py_str_to_c_str(value);
|
||||
if (!path)
|
||||
return -1;
|
||||
idx = git_index_find(self->index, path);
|
||||
|
@ -27,13 +27,15 @@
|
||||
|
||||
"""Tests for Blob objects."""
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
import pygit2
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
BLOB_SHA = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
|
||||
|
||||
|
||||
@ -43,8 +45,8 @@ class BlobTest(utils.BareRepoTestCase):
|
||||
blob = self.repo[BLOB_SHA]
|
||||
self.assertTrue(isinstance(blob, pygit2.Blob))
|
||||
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
|
||||
self.assertEqual('a contents\n', blob.data)
|
||||
self.assertEqual('a contents\n', blob.read_raw())
|
||||
self.assertEqual(b'a contents\n', blob.data)
|
||||
self.assertEqual(b'a contents\n', blob.read_raw())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -27,13 +27,15 @@
|
||||
|
||||
"""Tests for Commit objects."""
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
from pygit2 import GIT_OBJ_COMMIT
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
COMMIT_SHA = '5fe808e8953c12735680c257f56600cb0de44b10'
|
||||
|
||||
|
||||
|
@ -28,14 +28,16 @@
|
||||
|
||||
"""Tests for Index files."""
|
||||
|
||||
__author__ = 'jdavid@itaapy.com (J. David Ibáñez)'
|
||||
|
||||
import unittest
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
|
||||
import utils
|
||||
import unittest
|
||||
|
||||
import pygit2
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'jdavid@itaapy.com (J. David Ibáñez)'
|
||||
|
||||
|
||||
class IndexBareTest(utils.BareRepoTestCase):
|
||||
|
||||
@ -98,7 +100,7 @@ class IndexTest(utils.RepoTestCase):
|
||||
self.assertEqual(len(list(index)), n)
|
||||
|
||||
# Compare SHAs, not IndexEntry object identity
|
||||
entries = [index[x].sha for x in xrange(n)]
|
||||
entries = [index[x].sha for x in range(n)]
|
||||
self.assertEqual(list(x.sha for x in index), entries)
|
||||
|
||||
def test_mode(self):
|
||||
|
@ -28,15 +28,15 @@
|
||||
|
||||
"""Tests for reference objects."""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
from pygit2 import GIT_REF_OID, GIT_REF_SYMBOLIC
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'david.versmisse@itaapy.com (David Versmisse)'
|
||||
|
||||
import unittest
|
||||
import utils
|
||||
from pygit2 import GIT_REF_OID, GIT_REF_SYMBOLIC
|
||||
|
||||
|
||||
|
||||
LAST_COMMIT = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98'
|
||||
|
||||
|
||||
|
@ -27,8 +27,7 @@
|
||||
|
||||
"""Tests for Repository objects."""
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import binascii
|
||||
import unittest
|
||||
import os
|
||||
@ -38,6 +37,9 @@ from pygit2 import (GitError, GIT_OBJ_ANY, GIT_OBJ_BLOB, GIT_OBJ_COMMIT,
|
||||
init_repository)
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
A_HEX_SHA = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
|
||||
A_BIN_SHA = binascii.unhexlify(A_HEX_SHA)
|
||||
|
||||
@ -57,7 +59,7 @@ class RepositoryTest(utils.BareRepoTestCase):
|
||||
self.assertEqual((GIT_OBJ_BLOB, 'a contents 2\n'), a2)
|
||||
|
||||
def test_write(self):
|
||||
data = "hello world"
|
||||
data = b"hello world"
|
||||
# invalid object type
|
||||
self.assertRaises(GitError, self.repo.write, GIT_OBJ_ANY, data)
|
||||
|
||||
|
@ -28,13 +28,16 @@
|
||||
|
||||
"""Tests for revision walk."""
|
||||
|
||||
__author__ = 'jdavid@itaapy.com (J. David Ibáñez)'
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
from pygit2 import GIT_SORT_TIME, GIT_SORT_REVERSE
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'jdavid@itaapy.com (J. David Ibáñez)'
|
||||
|
||||
|
||||
# In the order given by git log
|
||||
log = [
|
||||
'2be5719152d4f82c7302b1c0932d8e5f0a4a0e98',
|
||||
|
@ -28,13 +28,15 @@
|
||||
|
||||
"""Tests for revision walk."""
|
||||
|
||||
__author__ = 'mike.perdide@gmail.com (Julien Miotte)'
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
import pygit2
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'mike.perdide@gmail.com (Julien Miotte)'
|
||||
|
||||
EXPECTED = {
|
||||
"current_file": pygit2.GIT_STATUS_CURRENT,
|
||||
"file_deleted": pygit2.GIT_STATUS_WT_DELETED,
|
||||
|
@ -27,13 +27,15 @@
|
||||
|
||||
"""Tests for Tag objects."""
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
import pygit2
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
TAG_SHA = '3d2962987c695a29f1f80b6c3aa4ec046ef44369'
|
||||
|
||||
|
||||
|
@ -27,14 +27,16 @@
|
||||
|
||||
"""Tests for Commit objects."""
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import operator
|
||||
import unittest
|
||||
|
||||
import pygit2
|
||||
import utils
|
||||
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
TREE_SHA = '967fce8df97cc71722d3c2a5930ef3e6f1d27b12'
|
||||
SUBTREE_SHA = '614fd9a3094bf618ea938fffc00e7d1a54f89ad0'
|
||||
|
||||
@ -55,27 +57,27 @@ class TreeTest(utils.BareRepoTestCase):
|
||||
self.assertRaisesWithArg(IndexError, 3, lambda: tree[3])
|
||||
|
||||
self.assertEqual(3, len(tree))
|
||||
a_sha = '7f129fd57e31e935c6d60a0c794efe4e6927664b'
|
||||
sha = '7f129fd57e31e935c6d60a0c794efe4e6927664b'
|
||||
self.assertTrue('a' in tree)
|
||||
self.assertTreeEntryEqual(tree[0], a_sha, 'a', 0100644)
|
||||
self.assertTreeEntryEqual(tree[-3], a_sha, 'a', 0100644)
|
||||
self.assertTreeEntryEqual(tree['a'], a_sha, 'a', 0100644)
|
||||
self.assertTreeEntryEqual(tree[0], sha, 'a', 0o0100644)
|
||||
self.assertTreeEntryEqual(tree[-3], sha, 'a', 0o0100644)
|
||||
self.assertTreeEntryEqual(tree['a'], sha, 'a', 0o0100644)
|
||||
|
||||
b_sha = '85f120ee4dac60d0719fd51731e4199aa5a37df6'
|
||||
sha = '85f120ee4dac60d0719fd51731e4199aa5a37df6'
|
||||
self.assertTrue('b' in tree)
|
||||
self.assertTreeEntryEqual(tree[1], b_sha, 'b', 0100644)
|
||||
self.assertTreeEntryEqual(tree[-2], b_sha, 'b', 0100644)
|
||||
self.assertTreeEntryEqual(tree['b'], b_sha, 'b', 0100644)
|
||||
self.assertTreeEntryEqual(tree[1], sha, 'b', 0o0100644)
|
||||
self.assertTreeEntryEqual(tree[-2], sha, 'b', 0o0100644)
|
||||
self.assertTreeEntryEqual(tree['b'], sha, 'b', 0o0100644)
|
||||
|
||||
def test_read_subtree(self):
|
||||
tree = self.repo[TREE_SHA]
|
||||
subtree_entry = tree['c']
|
||||
self.assertTreeEntryEqual(subtree_entry, SUBTREE_SHA, 'c', 0040000)
|
||||
self.assertTreeEntryEqual(subtree_entry, SUBTREE_SHA, 'c', 0o0040000)
|
||||
|
||||
subtree = subtree_entry.to_object()
|
||||
self.assertEqual(1, len(subtree))
|
||||
self.assertTreeEntryEqual(
|
||||
subtree[0], '297efb891a47de80be0cfe9c639e4b8c9b450989', 'd', 0100644)
|
||||
sha = '297efb891a47de80be0cfe9c639e4b8c9b450989'
|
||||
self.assertTreeEntryEqual(subtree[0], sha, 'd', 0o0100644)
|
||||
|
||||
# XXX Creating new trees was removed from libgit2 by v0.11.0, we
|
||||
# deactivate this test temporarily, since the feature may come back in
|
||||
@ -83,15 +85,15 @@ class TreeTest(utils.BareRepoTestCase):
|
||||
def xtest_new_tree(self):
|
||||
tree = pygit2.Tree(self.repo)
|
||||
self.assertEqual(0, len(tree))
|
||||
tree.add_entry('1' * 40, 'x', 0100644)
|
||||
tree.add_entry('2' * 40, 'y', 0100755)
|
||||
tree.add_entry('1' * 40, 'x', 0o0100644)
|
||||
tree.add_entry('2' * 40, 'y', 0o0100755)
|
||||
self.assertEqual(2, len(tree))
|
||||
self.assertTrue('x' in tree)
|
||||
self.assertTrue('y' in tree)
|
||||
self.assertRaisesWithArg(KeyError, '1' * 40, tree['x'].to_object)
|
||||
|
||||
tree.add_entry('3' * 40, 'z1', 0100644)
|
||||
tree.add_entry('4' * 40, 'z2', 0100644)
|
||||
tree.add_entry('3' * 40, 'z1', 0o0100644)
|
||||
tree.add_entry('4' * 40, 'z2', 0o0100644)
|
||||
self.assertEqual(4, len(tree))
|
||||
del tree['z1']
|
||||
del tree[2]
|
||||
@ -120,4 +122,4 @@ class TreeTest(utils.BareRepoTestCase):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
unittest.main()
|
||||
|
@ -25,11 +25,8 @@
|
||||
|
||||
"""Test utilities for libgit2."""
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
import unittest
|
||||
@ -37,6 +34,9 @@ import unittest
|
||||
import pygit2
|
||||
|
||||
|
||||
__author__ = 'dborowitz@google.com (Dave Borowitz)'
|
||||
|
||||
|
||||
class BaseTestCase(unittest.TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
@ -45,10 +45,7 @@ class BaseTestCase(unittest.TestCase):
|
||||
def assertRaisesWithArg(self, exc_class, arg, func, *args, **kwargs):
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
except exc_class:
|
||||
# XXX Use the 'exc_class as exc_value' syntax as soon as we drop
|
||||
# support for Python 2.5
|
||||
exc_value = sys.exc_info()[1]
|
||||
except exc_class as exc_value:
|
||||
self.assertEqual((arg,), exc_value.args)
|
||||
else:
|
||||
self.fail('%s(%r) not raised' % (exc_class.__name__, arg))
|
||||
|
Loading…
x
Reference in New Issue
Block a user