static void *run_workdir_iterator(void *arg) { int error = 0; git_iterator *iter; const git_index_entry *entry = NULL; cl_git_pass(git_iterator_for_workdir( &iter, _repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); while (!error) { if (entry && entry->mode == GIT_FILEMODE_TREE) { error = git_iterator_advance_into(&entry, iter); if (error == GIT_ENOTFOUND) error = git_iterator_advance(&entry, iter); } else { error = git_iterator_advance(&entry, iter); } if (!error) (void)git_iterator_current_is_ignored(iter); } cl_assert_equal_i(GIT_ITEROVER, error); git_iterator_free(iter); giterr_clear(); return arg; }
void test_diff_iterator__workdir_builtin_ignores(void) { git_repository *repo = cl_git_sandbox_init("attr"); git_iterator *i; git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT; const git_index_entry *entry; int idx; static struct { const char *path; bool ignored; } expected[] = { { "dir/", true }, { "file", false }, { "ign", true }, { "macro_bad", false }, { "macro_test", false }, { "root_test1", false }, { "root_test2", false }, { "root_test3", false }, { "root_test4.txt", false }, { "sub/", false }, { "sub/.gitattributes", false }, { "sub/abc", false }, { "sub/dir/", true }, { "sub/file", false }, { "sub/ign/", true }, { "sub/sub/", false }, { "sub/sub/.gitattributes", false }, { "sub/sub/dir", false }, /* file is not actually a dir */ { "sub/sub/file", false }, { NULL, false } }; cl_git_pass(p_mkdir("attr/sub/sub/.git", 0777)); cl_git_mkfile("attr/sub/.git", "whatever"); i_opts.flags = GIT_ITERATOR_DONT_AUTOEXPAND; i_opts.start = "dir"; i_opts.end = "sub/sub/file"; cl_git_pass(git_iterator_for_workdir( &i, repo, NULL, NULL, &i_opts)); cl_git_pass(git_iterator_current(&entry, i)); for (idx = 0; entry != NULL; ++idx) { int ignored = git_iterator_current_is_ignored(i); cl_assert_equal_s(expected[idx].path, entry->path); cl_assert_(ignored == expected[idx].ignored, expected[idx].path); if (!ignored && (entry->mode == GIT_FILEMODE_TREE || entry->mode == GIT_FILEMODE_COMMIT)) { /* it is possible to advance "into" a submodule */ cl_git_pass(git_iterator_advance_into(&entry, i)); } else { int error = git_iterator_advance(&entry, i); cl_assert(!error || error == GIT_ITEROVER); } } cl_assert(expected[idx].path == NULL); git_iterator_free(i); }
static void workdir_iterator_test( const char *sandbox, const char *start, const char *end, int expected_count, int expected_ignores, const char **expected_names, const char *an_ignored_name) { git_iterator *i; git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT; const git_index_entry *entry; int error, count = 0, count_all = 0, count_all_post_reset = 0; git_repository *repo = cl_git_sandbox_init(sandbox); i_opts.flags = GIT_ITERATOR_DONT_AUTOEXPAND; i_opts.start = start; i_opts.end = end; cl_git_pass(git_iterator_for_workdir(&i, repo, NULL, NULL, &i_opts)); error = git_iterator_current(&entry, i); cl_assert((error == 0 && entry != NULL) || (error == GIT_ITEROVER && entry == NULL)); while (entry != NULL) { int ignored = git_iterator_current_is_ignored(i); if (S_ISDIR(entry->mode)) { cl_git_pass(git_iterator_advance_into(&entry, i)); continue; } if (expected_names != NULL) cl_assert_equal_s(expected_names[count_all], entry->path); if (an_ignored_name && strcmp(an_ignored_name,entry->path)==0) cl_assert(ignored); if (!ignored) count++; count_all++; error = git_iterator_advance(&entry, i); cl_assert((error == 0 && entry != NULL) || (error == GIT_ITEROVER && entry == NULL)); } cl_assert_equal_i(expected_count, count); cl_assert_equal_i(expected_count + expected_ignores, count_all); cl_git_pass(git_iterator_reset(i, NULL, NULL)); error = git_iterator_current(&entry, i); cl_assert((error == 0 && entry != NULL) || (error == GIT_ITEROVER && entry == NULL)); while (entry != NULL) { if (S_ISDIR(entry->mode)) { cl_git_pass(git_iterator_advance_into(&entry, i)); continue; } if (expected_names != NULL) cl_assert_equal_s( expected_names[count_all_post_reset], entry->path); count_all_post_reset++; error = git_iterator_advance(&entry, i); cl_assert(error == 0 || error == GIT_ITEROVER); } cl_assert_equal_i(count_all, count_all_post_reset); git_iterator_free(i); }
static int checkout_action( checkout_data *data, git_diff_delta *delta, git_iterator *workdir, const git_index_entry **wditem_ptr, git_vector *pathspec) { const git_index_entry *wd = *wditem_ptr; int cmp = -1, act; int (*strcomp)(const char *, const char *) = data->diff->strcomp; int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp; int error; /* move workdir iterator to follow along with deltas */ while (1) { if (!wd) return checkout_action_no_wd(data, delta); cmp = strcomp(wd->path, delta->old_file.path); /* 1. wd before delta ("a/a" before "a/b") * 2. wd prefixes delta & should expand ("a/" before "a/b") * 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c") * 4. wd equals delta ("a/b" and "a/b") * 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b") * 6. wd after delta ("a/c" after "a/b") */ if (cmp < 0) { cmp = pfxcomp(delta->old_file.path, wd->path); if (cmp == 0) { if (wd->mode == GIT_FILEMODE_TREE) { /* case 2 - entry prefixed by workdir tree */ error = git_iterator_advance_into_or_over(&wd, workdir); if (error && error != GIT_ITEROVER) goto fail; *wditem_ptr = wd; continue; } /* case 3 maybe - wd contains non-dir where dir expected */ if (delta->old_file.path[strlen(wd->path)] == '/') { act = checkout_action_with_wd_blocker(data, delta, wd); *wditem_ptr = git_iterator_advance(&wd, workdir) ? NULL : wd; return act; } } /* case 1 - handle wd item (if it matches pathspec) */ if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0) goto fail; if ((error = git_iterator_advance(&wd, workdir)) < 0 && error != GIT_ITEROVER) goto fail; *wditem_ptr = wd; continue; } if (cmp == 0) { /* case 4 */ act = checkout_action_with_wd(data, delta, wd); *wditem_ptr = git_iterator_advance(&wd, workdir) ? NULL : wd; return act; } cmp = pfxcomp(wd->path, delta->old_file.path); if (cmp == 0) { /* case 5 */ if (wd->path[strlen(delta->old_file.path)] != '/') return checkout_action_no_wd(data, delta); if (delta->status == GIT_DELTA_TYPECHANGE) { if (delta->old_file.mode == GIT_FILEMODE_TREE) { act = checkout_action_with_wd(data, delta, wd); if ((error = git_iterator_advance_into(&wd, workdir)) < 0 && error != GIT_ENOTFOUND) goto fail; *wditem_ptr = wd; return act; } if (delta->new_file.mode == GIT_FILEMODE_TREE || delta->new_file.mode == GIT_FILEMODE_COMMIT || delta->old_file.mode == GIT_FILEMODE_COMMIT) { act = checkout_action_with_wd(data, delta, wd); if ((error = git_iterator_advance(&wd, workdir)) < 0 && error != GIT_ITEROVER) goto fail; *wditem_ptr = wd; return act; } } return checkout_action_with_wd_dir(data, delta, wd); } /* case 6 - wd is after delta */ return checkout_action_no_wd(data, delta); } fail: *wditem_ptr = NULL; return -1; }
static void expect_iterator_items( git_iterator *i, int expected_flat, const char **expected_flat_paths, int expected_total, const char **expected_total_paths) { const git_index_entry *entry; int count, error; int no_trees = !(git_iterator_flags(i) & GIT_ITERATOR_INCLUDE_TREES); bool v = false; if (expected_flat < 0) { v = true; expected_flat = -expected_flat; } if (expected_total < 0) { v = true; expected_total = -expected_total; } if (v) fprintf(stderr, "== %s ==\n", no_trees ? "notrees" : "trees"); count = 0; while (!git_iterator_advance(&entry, i)) { if (v) fprintf(stderr, " %s %07o\n", entry->path, (int)entry->mode); if (no_trees) cl_assert(entry->mode != GIT_FILEMODE_TREE); if (expected_flat_paths) { const char *expect_path = expected_flat_paths[count]; size_t expect_len = strlen(expect_path); cl_assert_equal_s(expect_path, entry->path); if (expect_path[expect_len - 1] == '/') cl_assert_equal_i(GIT_FILEMODE_TREE, entry->mode); else cl_assert(entry->mode != GIT_FILEMODE_TREE); } if (++count > expected_flat) break; } cl_assert_equal_i(expected_flat, count); cl_git_pass(git_iterator_reset(i, NULL, NULL)); count = 0; cl_git_pass(git_iterator_current(&entry, i)); if (v) fprintf(stderr, "-- %s --\n", no_trees ? "notrees" : "trees"); while (entry != NULL) { if (v) fprintf(stderr, " %s %07o\n", entry->path, (int)entry->mode); if (no_trees) cl_assert(entry->mode != GIT_FILEMODE_TREE); if (expected_total_paths) { const char *expect_path = expected_total_paths[count]; size_t expect_len = strlen(expect_path); cl_assert_equal_s(expect_path, entry->path); if (expect_path[expect_len - 1] == '/') cl_assert_equal_i(GIT_FILEMODE_TREE, entry->mode); else cl_assert(entry->mode != GIT_FILEMODE_TREE); } if (entry->mode == GIT_FILEMODE_TREE) { error = git_iterator_advance_into(&entry, i); /* could return NOTFOUND if directory is empty */ cl_assert(!error || error == GIT_ENOTFOUND); if (error == GIT_ENOTFOUND) { error = git_iterator_advance(&entry, i); cl_assert(!error || error == GIT_ITEROVER); } } else { error = git_iterator_advance(&entry, i); cl_assert(!error || error == GIT_ITEROVER); } if (++count > expected_total) break; } cl_assert_equal_i(expected_total, count); }