diff options
author | Vicent Marti <tanoku@gmail.com> | 2011-12-03 18:05:44 +0100 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2011-12-03 18:06:34 +0100 |
commit | e92386876606c734fae9d2f5bd6c80861ccfe409 (patch) | |
tree | 07be96439653415e22e3aee9adc3a4b3c117574c | |
parent | b4d757c0a8566937df4df9eda205ebb1fbe7aeff (diff) | |
download | libgit2-e92386876606c734fae9d2f5bd6c80861ccfe409.tar.gz |
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/
-rw-r--r-- | include/git2/tree.h | 1 | ||||
-rw-r--r-- | src/tree.c | 98 |
2 files changed, 99 insertions, 0 deletions
diff --git a/include/git2/tree.h b/include/git2/tree.h index 3ff017fbf..982646628 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 91e7f7164..21376bae7 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); +} |