Commits

sigmaris  committed 160cf64

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.

  • Participants
  • Parent commits 73af642

Comments (0)

Files changed (4)

 
     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;
     }
 }
 
 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);
     }
 
     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)
 {
     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 *
     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);
 
         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);
 
     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);
         }
         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);
     }
 
     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);

File test/test_commit.py

         committer = ('John Doe', 'jdoe@example.com', 12346, 0)
         author = ('J. David Ibáñez', 'jdavid@example.com', 12345, 0)
         tree = '967fce8df97cc71722d3c2a5930ef3e6f1d27b12'
-
-        parents = [COMMIT_SHA]
-        sha = repo.create_commit(None, author, committer, message, tree,
-                                 parents)
+        tree_prefix = tree[:5]
+        too_short_prefix = tree[:3]
+
+        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)

File test/test_repository.py

 
         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"
         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]
                           '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'))

File test/test_tag.py

         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)