diff --git a/docs/objects.rst b/docs/objects.rst index b9d038b..1609d31 100644 --- a/docs/objects.rst +++ b/docs/objects.rst @@ -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: diff --git a/src/repository.c b/src/repository.c index 31075c2..31523c2 100644 --- a/src/repository.c +++ b/src/repository.c @@ -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), diff --git a/test/test_blob.py b/test/test_blob.py index 9fd1d4f..f66d1e1 100644 --- a/test/test_blob.py +++ b/test/test_blob.py @@ -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']