Commit f2d110f1 by Vicent Martí

Merge pull request #1662 from arrbee/examples-like-git

Command line status example (with bug fixes)
parents 8b2fa181 94ef2a35
......@@ -3,7 +3,7 @@
CC = gcc
CFLAGS = -g -I../include -I../src -Wall -Wextra -Wmissing-prototypes -Wno-missing-field-initializers
LFLAGS = -L../build -lgit2 -lz
APPS = general showindex diff rev-list cat-file
APPS = general showindex diff rev-list cat-file status
all: $(APPS)
......
......@@ -111,6 +111,12 @@ typedef enum {
* - GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR indicates tha rename
* detection should be run between the index and the working directory
* and enabled GIT_STATUS_WT_RENAMED as a possible status flag.
* - GIT_STATUS_OPT_SORT_CASE_SENSITIVELY overrides the native case
* sensitivity for the file system and forces the output to be in
* case-sensitive order
* - GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY overrides the native case
* sensitivity for the file system and forces the output to be in
* case-insensitive order
*
* Calling `git_status_foreach()` is like calling the extended version
* with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED,
......@@ -127,6 +133,8 @@ typedef enum {
GIT_STATUS_OPT_RECURSE_IGNORED_DIRS = (1u << 6),
GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX = (1u << 7),
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR = (1u << 8),
GIT_STATUS_OPT_SORT_CASE_SENSITIVELY = (1u << 9),
GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY = (1u << 10),
} git_status_opt_t;
#define GIT_STATUS_OPT_DEFAULTS \
......
......@@ -498,7 +498,7 @@ int git_attr_assignment__parse(
assert(assigns && !assigns->length);
assigns->_cmp = sort_by_hash_and_name;
git_vector_set_cmp(assigns, sort_by_hash_and_name);
while (*scan && *scan != '\n') {
const char *name_start, *value_start;
......
......@@ -365,7 +365,7 @@ static git_diff_list *diff_list_alloc(
diff->pfxcomp = git__prefixcmp_icase;
diff->entrycomp = git_index_entry__cmp_icase;
diff->deltas._cmp = git_diff_delta__casecmp;
git_vector_set_cmp(&diff->deltas, git_diff_delta__casecmp);
}
return diff;
......@@ -786,10 +786,15 @@ static int diff_scan_inside_untracked_dir(
/* need to recurse into non-ignored directories */
if (!is_ignored && S_ISDIR(info->nitem->mode)) {
if ((error = git_iterator_advance_into(
&info->nitem, info->new_iter)) < 0)
break;
continue;
error = git_iterator_advance_into(&info->nitem, info->new_iter);
if (!error)
continue;
else if (error == GIT_ENOTFOUND) {
error = 0;
is_ignored = true; /* treat empty as ignored */
} else
break; /* real error, must stop */
}
/* found a non-ignored item - treat parent dir as untracked */
......@@ -1160,7 +1165,7 @@ int git_diff_tree_to_index(
d->pfxcomp = git__prefixcmp_icase;
d->entrycomp = git_index_entry__cmp_icase;
d->deltas._cmp = git_diff_delta__casecmp;
git_vector_set_cmp(&d->deltas, git_diff_delta__casecmp);
git_vector_sort(&d->deltas);
}
}
......@@ -1261,10 +1266,10 @@ int git_diff__paired_foreach(
/* force case-sensitive delta sort */
if (icase_mismatch) {
if (head2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) {
head2idx->deltas._cmp = git_diff_delta__cmp;
git_vector_set_cmp(&head2idx->deltas, git_diff_delta__cmp);
git_vector_sort(&head2idx->deltas);
} else {
idx2wd->deltas._cmp = git_diff_delta__cmp;
git_vector_set_cmp(&idx2wd->deltas, git_diff_delta__cmp);
git_vector_sort(&idx2wd->deltas);
}
}
......@@ -1296,10 +1301,10 @@ int git_diff__paired_foreach(
/* restore case-insensitive delta sort */
if (icase_mismatch) {
if (head2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) {
head2idx->deltas._cmp = git_diff_delta__casecmp;
git_vector_set_cmp(&head2idx->deltas, git_diff_delta__casecmp);
git_vector_sort(&head2idx->deltas);
} else {
idx2wd->deltas._cmp = git_diff_delta__casecmp;
git_vector_set_cmp(&idx2wd->deltas, git_diff_delta__casecmp);
git_vector_sort(&idx2wd->deltas);
}
}
......
......@@ -290,16 +290,16 @@ void git_index__set_ignore_case(git_index *index, bool ignore_case)
{
index->ignore_case = ignore_case;
index->entries._cmp = ignore_case ? index_icmp : index_cmp;
index->entries_cmp_path = ignore_case ? index_icmp_path : index_cmp_path;
index->entries_search = ignore_case ? index_isrch : index_srch;
index->entries_search_path = ignore_case ? index_isrch_path : index_srch_path;
index->entries.sorted = 0;
git_vector_set_cmp(&index->entries, ignore_case ? index_icmp : index_cmp);
git_vector_sort(&index->entries);
index->reuc._cmp = ignore_case ? reuc_icmp : reuc_cmp;
index->reuc_search = ignore_case ? reuc_isrch : reuc_srch;
index->reuc.sorted = 0;
git_vector_set_cmp(&index->reuc, ignore_case ? reuc_icmp : reuc_cmp);
git_vector_sort(&index->reuc);
}
......@@ -2024,7 +2024,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
git_vector_sort(&index->entries);
entries._cmp = index->entries._cmp;
git_vector_set_cmp(&entries, index->entries._cmp);
git_vector_swap(&entries, &index->entries);
git_index_clear(index);
......
......@@ -335,8 +335,16 @@ int git_status_list_new(
status->head2idx, status->idx2wd, status_collect, status)) < 0)
goto done;
if ((flags & GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX) != 0 ||
(flags & GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR) != 0)
if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY)
git_vector_set_cmp(&status->paired, status_entry_cmp);
if (flags & GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)
git_vector_set_cmp(&status->paired, status_entry_icmp);
if ((flags &
(GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR |
GIT_STATUS_OPT_SORT_CASE_SENSITIVELY |
GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)) != 0)
git_vector_sort(&status->paired);
done:
......
......@@ -151,7 +151,7 @@ int git_submodule_foreach(
int error;
git_submodule *sm;
git_vector seen = GIT_VECTOR_INIT;
seen._cmp = submodule_cmp;
git_vector_set_cmp(&seen, submodule_cmp);
assert(repo && callback);
......
......@@ -78,4 +78,13 @@ void git_vector_remove_matching(
int git_vector_resize_to(git_vector *v, size_t new_length);
int git_vector_set(void **old, git_vector *v, size_t position, void *value);
/** Set the comparison function used for sorting the vector */
GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp)
{
if (cmp != v->_cmp) {
v->_cmp = cmp;
v->sorted = 0;
}
}
#endif
......@@ -1109,6 +1109,26 @@ void test_diff_workdir__untracked_directory_scenarios(void)
git_diff_list_free(diff);
/* empty directory in empty directory */
cl_git_pass(p_mkdir("status/subdir/directory/empty", 0777));
memset(&exp, 0, sizeof(exp));
exp.names = files1;
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
cl_assert_equal_i(4, exp.files);
cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
git_diff_list_free(diff);
/* directory with only ignored files */
cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777));
......
......@@ -6,6 +6,9 @@ int cb_status__normal(
{
status_entry_counts *counts = payload;
if (counts->debug)
cb_status__print(path, status_flags, NULL);
if (counts->entry_count >= counts->expected_entry_count) {
counts->wrong_status_flags_count++;
goto exit;
......
......@@ -8,6 +8,7 @@ typedef struct {
const unsigned int* expected_statuses;
const char** expected_paths;
int expected_entry_count;
bool debug;
} status_entry_counts;
/* cb_status__normal takes payload of "status_entry_counts *" */
......
......@@ -743,3 +743,83 @@ void test_status_worktree__simple_delete_indexed(void)
GIT_STATUS_WT_DELETED, git_status_byindex(status, 0)->status);
git_status_list_free(status);
}
static const char *icase_paths[] = { "B", "c", "g", "H" };
static unsigned int icase_statuses[] = {
GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED,
GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED,
};
static const char *case_paths[] = { "B", "H", "c", "g" };
static unsigned int case_statuses[] = {
GIT_STATUS_WT_MODIFIED, GIT_STATUS_WT_DELETED,
GIT_STATUS_WT_DELETED, GIT_STATUS_WT_MODIFIED,
};
void test_status_worktree__sorting_by_case(void)
{
git_repository *repo = cl_git_sandbox_init("icase");
git_index *index;
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
bool native_ignore_case;
status_entry_counts counts;
cl_git_pass(git_repository_index(&index, repo));
native_ignore_case =
(git_index_caps(index) & GIT_INDEXCAP_IGNORE_CASE) != 0;
git_index_free(index);
memset(&counts, 0, sizeof(counts));
counts.expected_entry_count = 0;
counts.expected_paths = NULL;
counts.expected_statuses = NULL;
cl_git_pass(
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts));
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
cl_git_rewritefile("icase/B", "new stuff");
cl_must_pass(p_unlink("icase/c"));
cl_git_rewritefile("icase/g", "new stuff");
cl_must_pass(p_unlink("icase/H"));
memset(&counts, 0, sizeof(counts));
counts.expected_entry_count = 4;
if (native_ignore_case) {
counts.expected_paths = icase_paths;
counts.expected_statuses = icase_statuses;
} else {
counts.expected_paths = case_paths;
counts.expected_statuses = case_statuses;
}
cl_git_pass(
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts));
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
opts.flags = GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
memset(&counts, 0, sizeof(counts));
counts.expected_entry_count = 4;
counts.expected_paths = case_paths;
counts.expected_statuses = case_statuses;
cl_git_pass(
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts));
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
opts.flags = GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY;
memset(&counts, 0, sizeof(counts));
counts.expected_entry_count = 4;
counts.expected_paths = icase_paths;
counts.expected_statuses = icase_statuses;
cl_git_pass(
git_status_foreach_ext(repo, &opts, cb_status__normal, &counts));
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment