diff --git a/pygit2.c b/pygit2.c index 6a65f3a..c1bf4df 100644 --- a/pygit2.c +++ b/pygit2.c @@ -190,9 +190,10 @@ Error_set_py_obj(int err, PyObject *py_obj) assert(err < 0); - if (err == GIT_ENOTOID && !PyString_Check(py_obj)) { + if (err == GIT_ENOTOID && !PyString_Check(py_obj) + && !PyUnicode_Check(py_obj)) { PyErr_Format(PyExc_TypeError, - "Git object id must be byte string, not: %.200s", + "Git object id must be byte or a text string, not: %.200s", Py_TYPE(py_obj)->tp_name); return NULL; } @@ -209,17 +210,19 @@ Error_set_py_obj(int err, PyObject *py_obj) } static PyObject * -lookup_object(Repository *repo, const git_oid *oid, git_otype type) +lookup_object_prefix(Repository *repo, const git_oid *oid, size_t len, + git_otype type) { int err; char hex[GIT_OID_HEXSZ + 1]; git_object *obj; Object *py_obj = NULL; - err = git_object_lookup(&obj, repo->repo, oid, type); + err = git_object_lookup_prefix(&obj, repo->repo, oid, + (unsigned int)len, type); if (err < 0) { git_oid_fmt(hex, oid); - hex[GIT_OID_HEXSZ] = '\0'; + hex[len] = '\0'; return Error_set_str(err, hex); } @@ -248,6 +251,12 @@ lookup_object(Repository *repo, const git_oid *oid, git_otype type) return (PyObject*)py_obj; } +static PyObject * +lookup_object(Repository *repo, const git_oid *oid, git_otype type) +{ + return lookup_object_prefix(repo, oid, GIT_OID_HEXSZ, type); +} + static git_otype int_to_loose_object_type(int type_id) { @@ -415,18 +424,18 @@ Repository_getitem(Repository *self, PyObject *value) size_t len; len = py_str_to_git_oid(value, &oid); - TODO_SUPPORT_SHORT_HEXS(len) if (len == 0) return NULL; - return lookup_object(self, &oid, GIT_OBJ_ANY); + return lookup_object_prefix(self, &oid, len, GIT_OBJ_ANY); } static int Repository_read_raw(git_odb_object **obj, git_repository *repo, - const git_oid *oid) + const git_oid *oid, size_t len) { - return git_odb_read(obj, git_repository_database(repo), oid); + return git_odb_read_prefix(obj, git_repository_database(repo), + oid, (unsigned int)len); } static PyObject * @@ -438,11 +447,10 @@ Repository_read(Repository *self, PyObject *py_hex) size_t len; len = py_str_to_git_oid(py_hex, &oid); - TODO_SUPPORT_SHORT_HEXS(len) if (len == 0) return NULL; - err = Repository_read_raw(&obj, self->repo, &oid); + err = Repository_read_raw(&obj, self->repo, &oid, len); if (err < 0) return Error_set_py_obj(err, py_hex); @@ -659,13 +667,12 @@ Repository_create_commit(Repository *self, PyObject *args) return NULL; len = py_str_to_git_oid(py_oid, &oid); - TODO_SUPPORT_SHORT_HEXS(len) if (len == 0) return NULL; message = py_str_to_c_str(py_message); - err = git_tree_lookup(&tree, self->repo, &oid); + err = git_tree_lookup_prefix(&tree, self->repo, &oid, (unsigned int)len); if (err < 0) return Error_set(err); @@ -679,12 +686,12 @@ Repository_create_commit(Repository *self, PyObject *args) for (i = 0; i < parent_count; i++) { py_parent = PyList_GET_ITEM(py_parents, i); len = py_str_to_git_oid(py_parent, &oid); - TODO_SUPPORT_SHORT_HEXS(len) if (len == 0) { git_tree_close(tree); return free_parents(parents, i); } - if (git_commit_lookup(&parents[i], self->repo, &oid)) { + if (git_commit_lookup_prefix(&parents[i], self->repo, &oid, + (unsigned int)len)) { git_tree_close(tree); return free_parents(parents, i); } @@ -721,14 +728,14 @@ Repository_create_tag(Repository *self, PyObject *args) return NULL; len = py_str_to_git_oid(py_oid, &oid); - TODO_SUPPORT_SHORT_HEXS(len) if (len == 0) return NULL; - err = git_object_lookup(&target, self->repo, &oid, target_type); + err = git_object_lookup_prefix(&target, self->repo, &oid, + (unsigned int)len, target_type); if (err < 0) { git_oid_fmt(hex, &oid); - hex[GIT_OID_HEXSZ] = '\0'; + hex[len] = '\0'; return Error_set_str(err, hex); } @@ -1041,7 +1048,7 @@ Object_read_raw(Object *self) oid = git_object_id(self->obj); assert(oid); - err = Repository_read_raw(&obj, self->repo->repo, oid); + err = Repository_read_raw(&obj, self->repo->repo, oid, GIT_OID_HEXSZ); if (err < 0) { aux = git_oid_to_py_str(oid); Error_set_py_obj(err, aux); diff --git a/test/test_commit.py b/test/test_commit.py index f67fd74..6635959 100644 --- a/test/test_commit.py +++ b/test/test_commit.py @@ -71,10 +71,15 @@ class CommitTest(utils.BareRepoTestCase): committer = ('John Doe', 'jdoe@example.com', 12346, 0) author = ('J. David Ibáñez', 'jdavid@example.com', 12345, 0) tree = '967fce8df97cc71722d3c2a5930ef3e6f1d27b12' + tree_prefix = tree[:5] + too_short_prefix = tree[:3] - parents = [COMMIT_SHA] - sha = repo.create_commit(None, author, committer, message, tree, - parents) + parents = [COMMIT_SHA[:5]] + self.assertRaises(ValueError, repo.create_commit, None, author, + committer, message, too_short_prefix, parents) + + sha = repo.create_commit(None, author, committer, message, + tree_prefix, parents) commit = repo[sha] self.assertEqual(GIT_OBJ_COMMIT, commit.type) diff --git a/test/test_repository.py b/test/test_repository.py index 89edcbe..c62537f 100644 --- a/test/test_repository.py +++ b/test/test_repository.py @@ -58,6 +58,10 @@ class RepositoryTest(utils.BareRepoTestCase): a2 = self.repo.read('7f129fd57e31e935c6d60a0c794efe4e6927664b') self.assertEqual((GIT_OBJ_BLOB, 'a contents 2\n'), a2) + + a_hex_prefix = A_HEX_SHA[:4] + a3 = self.repo.read(a_hex_prefix) + self.assertEqual((GIT_OBJ_BLOB, 'a contents\n'), a3) def test_write(self): data = b"hello world" @@ -82,6 +86,12 @@ class RepositoryTest(utils.BareRepoTestCase): self.assertEqual(A_HEX_SHA, a.hex) self.assertEqual(GIT_OBJ_BLOB, a.type) + def test_lookup_blob_prefix(self): + a = self.repo[A_HEX_SHA[:5]] + self.assertEqual(b'a contents\n', a.read_raw()) + self.assertEqual(A_HEX_SHA, a.hex) + self.assertEqual(GIT_OBJ_BLOB, a.type) + def test_lookup_commit(self): commit_sha = '5fe808e8953c12735680c257f56600cb0de44b10' commit = self.repo[commit_sha] @@ -91,6 +101,18 @@ class RepositoryTest(utils.BareRepoTestCase): 'This commit has some additional text.\n'), commit.message) + def test_lookup_commit_prefix(self): + commit_sha = '5fe808e8953c12735680c257f56600cb0de44b10' + commit_sha_prefix = commit_sha[:7] + too_short_prefix = commit_sha[:3] + commit = self.repo[commit_sha_prefix] + self.assertEqual(commit_sha, commit.hex) + self.assertEqual(GIT_OBJ_COMMIT, commit.type) + self.assertEqual(('Second test data commit.\n\n' + 'This commit has some additional text.\n'), + commit.message) + self.assertRaises(ValueError, self.repo.__getitem__, too_short_prefix) + def test_get_path(self): directory = realpath(self.repo.path) expected = realpath(join(self._temp_dir, 'testrepo.git')) diff --git a/test/test_tag.py b/test/test_tag.py index ad786f0..a138882 100644 --- a/test/test_tag.py +++ b/test/test_tag.py @@ -62,8 +62,13 @@ class TagTest(utils.BareRepoTestCase): message = 'Tag a blob.\n' tagger = ('John Doe', 'jdoe@example.com', 12347, 0) - sha = self.repo.create_tag(name, target, pygit2.GIT_OBJ_BLOB, tagger, - message) + target_prefix = target[:5] + too_short_prefix = target[:3] + self.assertRaises(ValueError, self.repo.create_tag, name, + too_short_prefix, pygit2.GIT_OBJ_BLOB, tagger, + message) + sha = self.repo.create_tag(name, target_prefix, pygit2.GIT_OBJ_BLOB, + tagger, message) tag = self.repo[sha] self.assertEqual('3ee44658fd11660e828dfc96b9b5c5f38d5b49bb', tag.hex)