Add support for using short hex string prefixes

Allows Repository_getitem, Repository_read(_raw), Repository_create_commit,
Repository_create_tag and Object_read_raw to use short hex strings to
lookup objects.
Also test getting objects from Repository using prefixes, looking up commit
trees and parents by hex prefix, and looking up tag targets by prefix.
Also stop raising TypeError if passing a too-short hex prefix to the
lookup functions, instead use ValueError.
This commit is contained in:
Hugh Cole-Baker 2011-10-10 23:48:35 +01:00
parent 73af642b8f
commit 160cf64abc
4 changed files with 63 additions and 24 deletions

@ -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);

@ -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)

@ -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'))

@ -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)