tree: recursive diff-index Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk> Signed-off-by: Vicent Marti <tanoku@gmail.com> # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # Author: Carlos Martín Nieto <carlos@cmartin.tk> # # On branch development # Your branch is ahead of 'origin/development' by 11 commits. # # Changes to be committed: # (use "git reset HEAD^1 <file>..." to unstage) # # modified: include/git2/tree.h # modified: src/tree.c # modified: tests-clay/clay_main.c # modified: tests-clay/object/tree/diff.c # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # 0001-remote-Cleanup-the-remotes-code.patch # 466.patch # 466.patch.1 # 488.patch # Makefile # libgit2.0.15.0.dylib # libgit2.0.dylib # libgit2.dylib # libgit2_clay # libgit2_test # tests-clay/object/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
diff --git a/include/git2/tree.h b/include/git2/tree.h
index 3ff017f..9826466 100644
--- a/include/git2/tree.h
+++ b/include/git2/tree.h
@@ -347,6 +347,7 @@ typedef int (*git_tree_diff_cb)(const git_tree_diff_data *ptr, void *data);
*/
int git_tree_diff(git_tree *old, git_tree *newer, git_tree_diff_cb cb, void *data);
+int git_tree_diff_index_recursive(git_tree *tree, git_index *index, git_tree_diff_cb cb, void *data);
GIT_END_DECL
#endif
diff --git a/src/tree.c b/src/tree.c
index 91e7f71..21376ba 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -930,3 +930,101 @@ int git_tree_diff(git_tree *a, git_tree *b, git_tree_diff_cb cb, void *data)
exit:
return error;
}
+
+struct diff_index_cbdata {
+ git_index *index;
+ unsigned int i;
+ git_tree_diff_cb cb;
+ void *data;
+};
+
+static int cmp_tentry_ientry(git_tree_entry *tentry, git_index_entry *ientry)
+{
+ int cmp;
+
+ cmp = tentry->attr - ientry->mode;
+ if (cmp != 0)
+ return cmp;
+
+ return git_oid_cmp(&tentry->oid, &ientry->oid);
+}
+
+static void make_tentry(git_tree_entry *tentry, git_index_entry *ientry, git_buf *buf)
+{
+ memset(tentry, 0x0, sizeof(git_tree_entry));
+ tentry->attr = ientry->mode;
+ git_oid_cpy(&tentry->oid, &ientry->oid);
+ if (buf != NULL) {
+ tentry->filename = buf->ptr;
+ tentry->filename_len = buf->size;
+ }
+}
+
+static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data)
+{
+ struct diff_index_cbdata *cbdata = (struct diff_index_cbdata *) data;
+ git_index_entry *ientry = git_index_get(cbdata->index, cbdata->i);
+ git_tree_entry fake_entry;
+ git_buf fn_buf = GIT_BUF_INIT;
+ int cmp, error = GIT_SUCCESS;
+
+ if (ENTRY_IS_TREE(tentry))
+ return GIT_SUCCESS;
+
+ git_buf_puts(&fn_buf, root);
+ git_buf_puts(&fn_buf, tentry->filename);
+
+ if (!ientry) {
+ error = signal_deletion(tentry, cbdata->cb, cbdata->data);
+ goto exit;
+ }
+
+ /* Like with 'git diff-index', the index is the right side*/
+ cmp = strcmp(git_buf_cstr(&fn_buf), ientry->path);
+ if (cmp == 0) {
+ cbdata->i++;
+ if (!cmp_tentry_ientry(tentry, ientry))
+ goto exit;
+ /* modification */
+ make_tentry(&fake_entry, ientry, &fn_buf);
+ if ((error = signal_modification(tentry, &fake_entry, cbdata->cb, cbdata->data)) < 0)
+ goto exit;
+ } else if (cmp < 0) {
+ /* deletion */
+ memcpy(&fake_entry, tentry, sizeof(git_tree_entry));
+ fake_entry.filename = fn_buf.ptr;
+ fake_entry.filename_len = fn_buf.size;
+ if ((error = signal_deletion(tentry, cbdata->cb, cbdata->data)) < 0)
+ goto exit;
+ } else {
+ /* addition */
+ cbdata->i++;
+ make_tentry(&fake_entry, ientry, &fn_buf);
+ if ((error = signal_addition(&fake_entry, cbdata->cb, cbdata->data)) < 0)
+ goto exit;
+ /*
+ * The index has an addition. This means that we need to use
+ * the next entry in the index without advancing the tree
+ * walker, so call ourselves with the same tree state.
+ */
+ if ((error = diff_index_cb(root, tentry, data)) < 0)
+ goto exit;
+ }
+
+ exit:
+ git_buf_free(&fn_buf);
+ return error;
+}
+
+int git_tree_diff_index_recursive(git_tree *tree, git_index *index, git_tree_diff_cb cb, void *data)
+{
+ struct diff_index_cbdata cbdata;
+ char dummy_path[GIT_PATH_MAX];
+
+ cbdata.index = index;
+ cbdata.i = 0;
+ cbdata.cb = cb;
+ cbdata.data = data;
+
+ return tree_walk_post(tree, diff_index_cb, dummy_path, 0, &cbdata);
+}