summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/checkout.c12
-rw-r--r--src/checkout.h1
-rw-r--r--src/diff.c9
-rw-r--r--src/index.c2
-rw-r--r--src/iterator.c71
-rw-r--r--src/iterator.h6
-rw-r--r--src/pathspec.c2
-rw-r--r--tests/diff/iterator.c6
-rw-r--r--tests/repo/iterator.c34
-rw-r--r--tests/submodule/status.c5
-rw-r--r--tests/threads/iterator.c2
11 files changed, 119 insertions, 31 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 8203c39ea..44e2f3b27 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2242,6 +2242,7 @@ cleanup:
int git_checkout_iterator(
git_iterator *target,
+ git_index *index,
const git_checkout_options *opts)
{
int error = 0;
@@ -2278,7 +2279,7 @@ int git_checkout_iterator(
if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
(error = git_iterator_for_workdir_ext(
- &workdir, data.repo, data.opts.target_directory,
+ &workdir, data.repo, data.opts.target_directory, index, NULL,
iterflags | GIT_ITERATOR_DONT_AUTOEXPAND,
data.pfx, data.pfx)) < 0 ||
(error = git_iterator_for_tree(
@@ -2388,7 +2389,7 @@ int git_checkout_index(
GIT_REFCOUNT_INC(index);
if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL)))
- error = git_checkout_iterator(index_i, opts);
+ error = git_checkout_iterator(index_i, index, opts);
if (owned)
GIT_REFCOUNT_OWN(index, NULL);
@@ -2405,6 +2406,7 @@ int git_checkout_tree(
const git_checkout_options *opts)
{
int error;
+ git_index *index;
git_tree *tree = NULL;
git_iterator *tree_i = NULL;
@@ -2439,10 +2441,14 @@ int git_checkout_tree(
}
}
+ if ((error = git_repository_index(&index, repo)) < 0)
+ return error;
+
if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL)))
- error = git_checkout_iterator(tree_i, opts);
+ error = git_checkout_iterator(tree_i, index, opts);
git_iterator_free(tree_i);
+ git_index_free(index);
git_tree_free(tree);
return error;
diff --git a/src/checkout.h b/src/checkout.h
index f1fe69628..60aa29b26 100644
--- a/src/checkout.h
+++ b/src/checkout.h
@@ -19,6 +19,7 @@
*/
extern int git_checkout_iterator(
git_iterator *target,
+ git_index *index,
const git_checkout_options *opts);
#endif
diff --git a/src/diff.c b/src/diff.c
index 375d4cb13..89b3b77f3 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1214,7 +1214,7 @@ int git_diff_index_to_workdir(
DIFF_FROM_ITERATORS(
git_iterator_for_index(&a, index, 0, pfx, pfx),
git_iterator_for_workdir(
- &b, repo, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
+ &b, repo, index, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
);
if (!error && DIFF_FLAG_IS_SET(*diff, GIT_DIFF_UPDATE_INDEX))
@@ -1230,15 +1230,20 @@ int git_diff_tree_to_workdir(
const git_diff_options *opts)
{
int error = 0;
+ git_index *index;
assert(diff && repo);
+ if ((error = git_repository_index(&index, repo)))
+ return error;
+
DIFF_FROM_ITERATORS(
git_iterator_for_tree(&a, old_tree, 0, pfx, pfx),
git_iterator_for_workdir(
- &b, repo, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
+ &b, repo, index, old_tree, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
);
+ git_index_free(index);
return error;
}
diff --git a/src/index.c b/src/index.c
index 8a5bf61c1..d3bc081a5 100644
--- a/src/index.c
+++ b/src/index.c
@@ -2441,7 +2441,7 @@ int git_index_add_all(
goto cleanup;
if ((error = git_iterator_for_workdir(
- &wditer, repo, 0, ps.prefix, ps.prefix)) < 0)
+ &wditer, repo, NULL, NULL, 0, ps.prefix, ps.prefix)) < 0)
goto cleanup;
while (!(error = git_iterator_advance(&wd, wditer))) {
diff --git a/src/iterator.c b/src/iterator.c
index c664f17cd..d8a17a716 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -1268,6 +1268,16 @@ typedef struct {
fs_iterator fi;
git_ignores ignores;
int is_ignored;
+
+ /*
+ * We may have a tree or the index+snapshot to compare against
+ * when checking for submodules.
+ */
+ git_tree *tree;
+ git_index *index;
+ git_vector index_snapshot;
+ git_vector_cmp entry_srch;
+
} workdir_iterator;
GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path)
@@ -1289,6 +1299,49 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path)
return (len == 4 || path->ptr[len - 5] == '/');
}
+/**
+ * Figure out if an entry is a submodule.
+ *
+ * We consider it a submodule if the path is listed as a submodule in
+ * either the tree or the index.
+ */
+static int is_submodule(workdir_iterator *wi, git_path_with_stat *ie)
+{
+ int error, is_submodule = 0;
+
+ if (wi->tree) {
+ git_tree_entry *e;
+
+ /* remove the trailing slash for finding */
+ ie->path[ie->path_len-1] = '\0';
+ error = git_tree_entry_bypath(&e, wi->tree, ie->path);
+ ie->path[ie->path_len-1] = '/';
+ if (error < 0 && error != GIT_ENOTFOUND)
+ return 0;
+ if (!error) {
+ is_submodule = e->attr == GIT_FILEMODE_COMMIT;
+ git_tree_entry_free(e);
+ }
+ }
+
+ if (!is_submodule && wi->index) {
+ git_index_entry *e;
+ size_t pos;
+
+ error = git_index_snapshot_find(&pos, &wi->index_snapshot, wi->entry_srch, ie->path, ie->path_len-1, 0);
+ if (error < 0 && error != GIT_ENOTFOUND)
+ return 0;
+
+ if (!error) {
+ e = git_vector_get(&wi->index_snapshot, pos);
+
+ is_submodule = e->mode == GIT_FILEMODE_COMMIT;
+ }
+ }
+
+ return is_submodule;
+}
+
static int workdir_iterator__enter_dir(fs_iterator *fi)
{
workdir_iterator *wi = (workdir_iterator *)fi;
@@ -1321,7 +1374,7 @@ static int workdir_iterator__enter_dir(fs_iterator *fi)
if (!S_ISDIR(entry->st.st_mode) || !strcmp(GIT_DIR, entry->path))
continue;
- if (git_submodule__is_submodule(fi->base.repo, entry->path)) {
+ if (is_submodule(wi, entry)) {
entry->st.st_mode = GIT_FILEMODE_COMMIT;
entry->path_len--;
entry->path[entry->path_len] = '\0';
@@ -1363,6 +1416,8 @@ static int workdir_iterator__update_entry(fs_iterator *fi)
static void workdir_iterator__free(git_iterator *self)
{
workdir_iterator *wi = (workdir_iterator *)self;
+ if (wi->index)
+ git_index_snapshot_release(&wi->index_snapshot, wi->index);
fs_iterator__free(self);
git_ignore__free(&wi->ignores);
}
@@ -1371,6 +1426,8 @@ int git_iterator_for_workdir_ext(
git_iterator **out,
git_repository *repo,
const char *repo_workdir,
+ git_index *index,
+ git_tree *tree,
git_iterator_flag_t flags,
const char *start,
const char *end)
@@ -1402,6 +1459,18 @@ int git_iterator_for_workdir_ext(
return error;
}
+ if (tree && (error = git_object_dup((git_object **)&wi->tree, (git_object *)tree)) < 0)
+ return error;
+
+ wi->index = index;
+ if (index && (error = git_index_snapshot_new(&wi->index_snapshot, index)) < 0) {
+ git_iterator_free((git_iterator *)wi);
+ return error;
+ }
+ wi->entry_srch = iterator__ignore_case(wi) ?
+ git_index_entry_isrch : git_index_entry_srch;
+
+
/* try to look up precompose and set flag if appropriate */
if (git_repository__cvar(&precompose, repo, GIT_CVAR_PRECOMPOSE) < 0)
giterr_clear();
diff --git a/src/iterator.h b/src/iterator.h
index d88ad5191..1520bffc2 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -86,6 +86,8 @@ extern int git_iterator_for_workdir_ext(
git_iterator **out,
git_repository *repo,
const char *repo_workdir,
+ git_index *index,
+ git_tree *tree,
git_iterator_flag_t flags,
const char *start,
const char *end);
@@ -96,11 +98,13 @@ extern int git_iterator_for_workdir_ext(
GIT_INLINE(int) git_iterator_for_workdir(
git_iterator **out,
git_repository *repo,
+ git_index *index,
+ git_tree *tree,
git_iterator_flag_t flags,
const char *start,
const char *end)
{
- return git_iterator_for_workdir_ext(out, repo, NULL, flags, start, end);
+ return git_iterator_for_workdir_ext(out, repo, NULL, index, tree, flags, start, end);
}
/* for filesystem iterators, you have to explicitly pass in the ignore_case
diff --git a/src/pathspec.c b/src/pathspec.c
index a01d74f07..8b469f717 100644
--- a/src/pathspec.c
+++ b/src/pathspec.c
@@ -524,7 +524,7 @@ int git_pathspec_match_workdir(
assert(repo);
if (!(error = git_iterator_for_workdir(
- &iter, repo, pathspec_match_iter_flags(flags), NULL, NULL))) {
+ &iter, repo, NULL, NULL, pathspec_match_iter_flags(flags), NULL, NULL))) {
error = pathspec_match_from_iterator(out, iter, flags, ps);
diff --git a/tests/diff/iterator.c b/tests/diff/iterator.c
index 26f670cfa..6011c6a9b 100644
--- a/tests/diff/iterator.c
+++ b/tests/diff/iterator.c
@@ -586,7 +586,7 @@ static void workdir_iterator_test(
git_repository *repo = cl_git_sandbox_init(sandbox);
cl_git_pass(git_iterator_for_workdir(
- &i, repo, GIT_ITERATOR_DONT_AUTOEXPAND, start, end));
+ &i, repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, start, end));
error = git_iterator_current(&entry, i);
cl_assert((error == 0 && entry != NULL) ||
@@ -797,7 +797,7 @@ void test_diff_iterator__workdir_builtin_ignores(void)
cl_git_mkfile("attr/sub/.git", "whatever");
cl_git_pass(git_iterator_for_workdir(
- &i, repo, GIT_ITERATOR_DONT_AUTOEXPAND, "dir", "sub/sub/file"));
+ &i, repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, "dir", "sub/sub/file"));
cl_git_pass(git_iterator_current(&entry, i));
for (idx = 0; entry != NULL; ++idx) {
@@ -832,7 +832,7 @@ static void check_wd_first_through_third_range(
static const char *expected[] = { "FIRST", "second", "THIRD", NULL };
cl_git_pass(git_iterator_for_workdir(
- &i, repo, GIT_ITERATOR_IGNORE_CASE, start, end));
+ &i, repo, NULL, NULL, GIT_ITERATOR_IGNORE_CASE, start, end));
cl_git_pass(git_iterator_current(&entry, i));
for (idx = 0; entry != NULL; ++idx) {
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index 764c2c6cd..fb5561bc2 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -665,19 +665,19 @@ void test_repo_iterator__workdir(void)
g_repo = cl_git_sandbox_init("icase");
/* auto expand with no tree entries */
- cl_git_pass(git_iterator_for_workdir(&i, g_repo, 0, NULL, NULL));
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, 0, NULL, NULL));
expect_iterator_items(i, 20, NULL, 20, NULL);
git_iterator_free(i);
/* auto expand with tree entries */
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
+ &i, g_repo, NULL, NULL, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
expect_iterator_items(i, 22, NULL, 22, NULL);
git_iterator_free(i);
/* no auto expand (implies trees included) */
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
+ &i, g_repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
expect_iterator_items(i, 12, NULL, 22, NULL);
git_iterator_free(i);
}
@@ -692,66 +692,66 @@ void test_repo_iterator__workdir_icase(void)
flag = GIT_ITERATOR_DONT_IGNORE_CASE;
/* auto expand with no tree entries */
- cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "c", "k/D"));
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, flag, "c", "k/D"));
expect_iterator_items(i, 7, NULL, 7, NULL);
git_iterator_free(i);
- cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "k", "k/Z"));
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, flag, "k", "k/Z"));
expect_iterator_items(i, 3, NULL, 3, NULL);
git_iterator_free(i);
/* auto expand with tree entries */
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
+ &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
expect_iterator_items(i, 8, NULL, 8, NULL);
git_iterator_free(i);
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
+ &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
expect_iterator_items(i, 4, NULL, 4, NULL);
git_iterator_free(i);
/* no auto expand (implies trees included) */
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
+ &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
expect_iterator_items(i, 5, NULL, 8, NULL);
git_iterator_free(i);
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
+ &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
expect_iterator_items(i, 1, NULL, 4, NULL);
git_iterator_free(i);
flag = GIT_ITERATOR_IGNORE_CASE;
/* auto expand with no tree entries */
- cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "c", "k/D"));
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, flag, "c", "k/D"));
expect_iterator_items(i, 13, NULL, 13, NULL);
git_iterator_free(i);
- cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "k", "k/Z"));
+ cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, flag, "k", "k/Z"));
expect_iterator_items(i, 5, NULL, 5, NULL);
git_iterator_free(i);
/* auto expand with tree entries */
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
+ &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
expect_iterator_items(i, 14, NULL, 14, NULL);
git_iterator_free(i);
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
+ &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
expect_iterator_items(i, 6, NULL, 6, NULL);
git_iterator_free(i);
/* no auto expand (implies trees included) */
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
+ &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
expect_iterator_items(i, 9, NULL, 14, NULL);
git_iterator_free(i);
cl_git_pass(git_iterator_for_workdir(
- &i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
+ &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
expect_iterator_items(i, 1, NULL, 6, NULL);
git_iterator_free(i);
}
@@ -804,13 +804,13 @@ void test_repo_iterator__workdir_depth(void)
build_workdir_tree("icase/dir02/sUB01", 50, 0);
/* auto expand with no tree entries */
- cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL));
+ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, NULL, NULL, 0, NULL, NULL));
expect_iterator_items(iter, 125, NULL, 125, NULL);
git_iterator_free(iter);
/* auto expand with tree entries (empty dirs silently skipped) */
cl_git_pass(git_iterator_for_workdir(
- &iter, g_repo, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
+ &iter, g_repo, NULL, NULL, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
expect_iterator_items(iter, 337, NULL, 337, NULL);
git_iterator_free(iter);
}
diff --git a/tests/submodule/status.c b/tests/submodule/status.c
index 6473491b9..6efae35c6 100644
--- a/tests/submodule/status.c
+++ b/tests/submodule/status.c
@@ -317,14 +317,17 @@ void test_submodule_status__iterator(void)
};
submodule_expectations exp = { 0, expected, expected_flags };
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
+ git_index *index;
- cl_git_pass(git_iterator_for_workdir(&iter, g_repo,
+ cl_git_pass(git_repository_index(&index, g_repo));
+ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, index, NULL,
GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
for (i = 0; !git_iterator_advance(&entry, iter); ++i)
cl_assert_equal_s(expected[i], entry->path);
git_iterator_free(iter);
+ git_index_free(index);
opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
GIT_STATUS_OPT_INCLUDE_UNMODIFIED |
diff --git a/tests/threads/iterator.c b/tests/threads/iterator.c
index 8aeae1a6c..8a2d79c2e 100644
--- a/tests/threads/iterator.c
+++ b/tests/threads/iterator.c
@@ -16,7 +16,7 @@ static void *run_workdir_iterator(void *arg)
const git_index_entry *entry = NULL;
cl_git_pass(git_iterator_for_workdir(
- &iter, _repo, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
+ &iter, _repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
while (!error) {
if (entry && entry->mode == GIT_FILEMODE_TREE) {