add git_index_read_tree
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
diff --git a/include/git2/index.h b/include/git2/index.h
index 5e9c34d..627d6c4 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -301,6 +301,17 @@ GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_byindex(git_
*/
GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry);
+/**
+ * Read a tree into the index file
+ *
+ * The current index contents will be replaced by the specified tree.
+ *
+ * @param index an existing index object
+ * @param tree tree to read
+ * @return GIT_SUCCESS or an error code
+ */
+GIT_EXTERN(int) git_index_read_tree(git_index *index, git_tree *tree);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/src/index.c b/src/index.c
index 43e8efa..9f9a08f 100644
--- a/src/index.c
+++ b/src/index.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "repository.h"
#include "index.h"
+#include "tree.h"
#include "tree-cache.h"
#include "hash.h"
#include "git2/odb.h"
@@ -936,3 +937,44 @@ int git_index_entry_stage(const git_index_entry *entry)
{
return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT;
}
+
+static int read_tree_cb(const char *root, git_tree_entry *tentry, void *data)
+{
+ int ret = GIT_SUCCESS;
+ git_index *index = data;
+ git_index_entry *entry = NULL;
+ git_buf path = GIT_BUF_INIT;
+
+ if (entry_is_tree(tentry))
+ goto exit;
+
+ ret = git_buf_joinpath(&path, root, tentry->filename);
+ if (ret < GIT_SUCCESS)
+ goto exit;
+
+ entry = git__calloc(1, sizeof(git_index_entry));
+ if (!entry) {
+ ret = GIT_ENOMEM;
+ goto exit;
+ }
+
+ entry->mode = tentry->attr;
+ entry->oid = tentry->oid;
+ entry->path = git_buf_detach(&path);
+
+ ret = index_insert(index, entry, 0);
+
+exit:
+ git_buf_free(&path);
+
+ if (ret < GIT_SUCCESS)
+ index_entry_free(entry);
+ return ret;
+}
+
+int git_index_read_tree(git_index *index, git_tree *tree)
+{
+ git_index_clear(index);
+
+ return git_tree_walk(tree, read_tree_cb, GIT_TREEWALK_POST, index);
+}
diff --git a/tests-clay/index/read_tree.c b/tests-clay/index/read_tree.c
new file mode 100644
index 0000000..d884c8d
--- /dev/null
+++ b/tests-clay/index/read_tree.c
@@ -0,0 +1,46 @@
+#include "clay_libgit2.h"
+#include "testlib.h"
+#include "posix.h"
+
+/* Test that reading and writing a tree is a no-op */
+void test_index_read_tree__read_write_involution(void)
+{
+ git_repository *repo;
+ git_index *index;
+ git_oid tree_oid;
+ git_tree *tree;
+ git_oid expected;
+
+ p_mkdir("read_tree", 0700);
+
+ cl_git_pass(git_repository_init(&repo, "./read_tree", 0));
+ cl_git_pass(git_repository_index(&index, repo));
+
+ cl_assert(git_index_entrycount(index) == 0);
+
+ p_mkdir("./read_tree/abc", 0700);
+
+ /* Sort order: '-' < '/' < '_' */
+ file_create("./read_tree/abc-d", NULL);
+ file_create("./read_tree/abc/d", NULL);
+ file_create("./read_tree/abc_d", NULL);
+
+ cl_git_pass(git_index_add(index, "abc-d", 0));
+ cl_git_pass(git_index_add(index, "abc_d", 0));
+ cl_git_pass(git_index_add(index, "abc/d", 0));
+
+ /* write-tree */
+ cl_git_pass(git_tree_create_fromindex(&expected, index));
+
+ /* read-tree */
+ git_tree_lookup(&tree, repo, &expected);
+ cl_git_pass(git_index_read_tree(index, tree));
+
+ cl_git_pass(git_tree_create_fromindex(&tree_oid, index));
+ cl_assert(git_oid_cmp(&expected, &tree_oid) == 0);
+
+ git_index_free(index);
+ git_repository_free(repo);
+
+ cl_fixture_cleanup("read_tree");
+}
diff --git a/tests-clay/index/rename.c b/tests-clay/index/rename.c
index f811254..c949fa7 100644
--- a/tests-clay/index/rename.c
+++ b/tests-clay/index/rename.c
@@ -1,16 +1,7 @@
#include "clay_libgit2.h"
+#include "testlib.h"
#include "posix.h"
-static void file_create(const char *filename, const char *content)
-{
- int fd;
-
- fd = p_creat(filename, 0666);
- cl_assert(fd != 0);
- cl_git_pass(p_write(fd, content, strlen(content)));
- cl_git_pass(p_close(fd));
-}
-
void test_index_rename__single_file(void)
{
git_repository *repo;
diff --git a/tests-clay/testlib.c b/tests-clay/testlib.c
new file mode 100644
index 0000000..d45fc2c
--- /dev/null
+++ b/tests-clay/testlib.c
@@ -0,0 +1,20 @@
+#include "clay.h"
+#include "testlib.h"
+#include "posix.h"
+
+void file_create(const char *filename, const char *content)
+{
+ int fd;
+
+ fd = p_creat(filename, 0666);
+ cl_assert(fd != 0);
+
+ if (content) {
+ cl_must_pass(p_write(fd, content, strlen(content)));
+ } else {
+ cl_must_pass(p_write(fd, filename, strlen(filename)));
+ cl_must_pass(p_write(fd, "\n", 1));
+ }
+
+ cl_must_pass(p_close(fd));
+}
diff --git a/tests-clay/testlib.h b/tests-clay/testlib.h
new file mode 100644
index 0000000..2e8867c
--- /dev/null
+++ b/tests-clay/testlib.h
@@ -0,0 +1,6 @@
+#ifndef INCLUDE_testlib_h__
+#define INCLUDE_testlib_h__
+
+void file_create(const char *filename, const char *content);
+
+#endif