summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-11-08 14:40:53 +0100
committerCarlos Martín Nieto <cmn@dwim.me>2014-11-08 20:53:38 +0100
commite1ac0101480c29631ad56409d77f2dd7b65bfd09 (patch)
tree0fa9ac517503c0f0882c77d789add24b4bba4f8a
parent4e1b3b3b7186b017223b8302a51289ff92ccba25 (diff)
downloadlibgit2-cmn/empty-objects.tar.gz
odb: hardcode the empty blob and treecmn/empty-objects
git hardocodes these as objects which exist regardless of whether they are in the odb and uses them in the shell interface as a way of expressing the lack of a blob or tree for one side of e.g. a diff. In the library we use each language's natural way of declaring a lack of value which makes a workaround like this unnecessary. Since git uses it, it does however mean each shell application would need to perform this check themselves. This makes it common work across a range of applications and an issue with compatibility with git, which fits right into what the library aims to provide. Thus we introduce the hard-coded empty blob and tree in the odb frontend. These hard-coded objects are checked for before going to the backends, but after the cache check, which means the second time they're used, they will be treated as normal cached objects instead of creating new ones.
-rw-r--r--src/odb.c24
-rw-r--r--tests/odb/emptyobjects.c39
2 files changed, 62 insertions, 1 deletions
diff --git a/src/odb.c b/src/odb.c
index a4fc02686..2c19c0311 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -752,6 +752,28 @@ int git_odb__read_header_or_object(
return 0;
}
+static git_oid empty_blob = {{ 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1, 0xd6, 0x43, 0x4b, 0x8b,
+ 0x29, 0xae, 0x77, 0x5a, 0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91 }};
+static git_oid empty_tree = {{ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
+ 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04 }};
+
+static int hardcoded_objects(git_rawobj *raw, const git_oid *id)
+{
+ if (!git_oid_cmp(id, &empty_blob)) {
+ raw->type = GIT_OBJ_BLOB;
+ raw->len = 0;
+ raw->data = NULL;
+ return 0;
+ } else if (!git_oid_cmp(id, &empty_tree)) {
+ raw->type = GIT_OBJ_TREE;
+ raw->len = 0;
+ raw->data = NULL;
+ return 0;
+ } else {
+ return GIT_ENOTFOUND;
+ }
+}
+
int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
{
size_t i, reads = 0;
@@ -765,7 +787,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id)
if (*out != NULL)
return 0;
- error = GIT_ENOTFOUND;
+ error = hardcoded_objects(&raw, id);
for (i = 0; i < db->backends.length && error < 0; ++i) {
backend_internal *internal = git_vector_get(&db->backends, i);
diff --git a/tests/odb/emptyobjects.c b/tests/odb/emptyobjects.c
new file mode 100644
index 000000000..d6d832cdf
--- /dev/null
+++ b/tests/odb/emptyobjects.c
@@ -0,0 +1,39 @@
+#include "clar_libgit2.h"
+#include "odb.h"
+#include "filebuf.h"
+
+git_repository *g_repo;
+
+void test_odb_emptyobjects__initialize(void)
+{
+ cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git")));
+}
+void test_odb_emptyobjects__cleanup(void)
+{
+ git_repository_free(g_repo);
+}
+
+void test_odb_emptyobjects__read(void)
+{
+ git_oid id;
+ git_blob *blob;
+
+ cl_git_pass(git_oid_fromstr(&id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"));
+ cl_git_pass(git_blob_lookup(&blob, g_repo, &id));
+ cl_assert_equal_i(GIT_OBJ_BLOB, git_object_type((git_object *) blob));
+ cl_assert_equal_i(0, git_blob_rawsize(blob));
+ git_blob_free(blob);
+}
+
+void test_odb_emptyobjects__read_tree(void)
+{
+ git_oid id;
+ git_tree *tree;
+
+ cl_git_pass(git_oid_fromstr(&id, "4b825dc642cb6eb9a060e54bf8d69288fbee4904"));
+ cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
+ cl_assert_equal_i(GIT_OBJ_TREE, git_object_type((git_object *) tree));
+ cl_assert_equal_i(0, git_tree_entrycount(tree));
+ cl_assert_equal_p(NULL, git_tree_entry_byname(tree, "foo"));
+ git_tree_free(tree);
+}