Implements 'Repository.create_blob_fromiobase'.

This commit allows blobs to be constructed from implementatons of the
'RawIOBase' ABC.  This allows any conformant stream implementation to be added
as a blob.

This is useful in the case where the contents of the blob would be too large to
create from memory (as 'create_blob_fromstring' allows) and avoids having to
write the data to disk (as 'create_blob_fromworkdir' allows).  The latter
operation is especially useful when reading data from a network socket, since
it avoids having to first commit all the data to disk.
This commit is contained in:
Masud Rahman 2015-02-10 01:28:23 -05:00
parent 3b27e16d08
commit 9cce003efe
3 changed files with 74 additions and 0 deletions

@ -132,6 +132,7 @@ them to the Git object database:
.. automethod:: pygit2.Repository.create_blob_fromworkdir
.. automethod:: pygit2.Repository.create_blob_fromdisk
.. automethod:: pygit2.Repository.create_blob_fromiobase
There are also some functions to calculate the id for a byte string without
creating the blob object:

@ -736,6 +736,66 @@ Repository_create_blob_fromdisk(Repository *self, PyObject *args)
}
PyDoc_STRVAR(Repository_create_blob_fromiobase__doc__,
"create_blob_fromiobase(io.IOBase) -> Oid\n"
"\n"
"Create a new blob from an IOBase object.");
int read_chunk(char *content, size_t max_length, void *payload)
{
PyObject *py_file;
PyObject *py_bytes;
char *bytes;
Py_ssize_t size;
py_file = (PyObject *)payload;
py_bytes = PyObject_CallMethod(py_file, "read", "i", max_length);
if (!py_bytes) {
return 0;
}
bytes = PyBytes_AsString(py_bytes);
size = PyBytes_Size(py_bytes);
memcpy(content, bytes, size);
Py_DECREF(py_bytes);
return size;
}
PyObject *
Repository_create_blob_fromiobase(Repository *self, PyObject *args)
{
git_oid oid;
PyObject *py_is_readable;
PyObject *py_file;
int err;
if (!PyArg_ParseTuple(args, "O", &py_file))
return NULL;
py_is_readable = PyObject_CallMethod(py_file, "readable", NULL);
if (!py_is_readable || !PyObject_IsTrue(py_is_readable)) {
PyErr_SetString(PyExc_TypeError, "expected readable IO type");
Py_DECREF(py_is_readable);
return NULL;
}
Py_DECREF(py_is_readable);
err = git_blob_create_fromchunks(&oid,
self->repo,
NULL,
&read_chunk,
py_file);
Py_DECREF(py_file);
if (err < 0)
return Error_set(err);
return git_oid_to_python(&oid);
}
PyDoc_STRVAR(Repository_create_commit__doc__,
"create_commit(reference, author, committer, message, tree, parents[, encoding]) -> Oid\n"
"\n"
@ -1386,6 +1446,7 @@ PyMethodDef Repository_methods[] = {
METHOD(Repository, create_blob, METH_VARARGS),
METHOD(Repository, create_blob_fromworkdir, METH_VARARGS),
METHOD(Repository, create_blob_fromdisk, METH_VARARGS),
METHOD(Repository, create_blob_fromiobase, METH_VARARGS),
METHOD(Repository, create_commit, METH_VARARGS),
METHOD(Repository, create_tag, METH_VARARGS),
METHOD(Repository, TreeBuilder, METH_VARARGS),

@ -30,6 +30,7 @@
from __future__ import absolute_import
from __future__ import unicode_literals
from os.path import dirname, join
import io
import unittest
import pygit2
@ -112,6 +113,17 @@ class BlobTest(utils.RepoTestCase):
self.assertTrue(isinstance(blob, pygit2.Blob))
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
def test_create_blob_fromiobase(self):
f = io.BytesIO(BLOB_CONTENT)
blob_oid = self.repo.create_blob_fromiobase(f)
blob = self.repo[blob_oid]
self.assertTrue(isinstance(blob, pygit2.Blob))
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
self.assertEqual(blob_oid, blob.id)
self.assertEqual(BLOB_SHA, blob_oid.hex)
def test_diff_blob(self):
blob = self.repo[BLOB_SHA]
old_blob = self.repo['3b18e512dba79e4c8300dd08aeb37f8e728b8dad']