summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-06-20 12:16:06 -0700
committerRussell Belfer <rb@github.com>2013-06-20 12:16:06 -0700
commit22b6b82f2c0d95ce7a433394a6c0574a5714cf4c (patch)
tree432b4d109e004ed816127b9d22e2b8e706da75b0
parentcf300bb9e50c65e4140f7e204243b34f2898fa95 (diff)
downloadlibgit2-22b6b82f2c0d95ce7a433394a6c0574a5714cf4c.tar.gz
Add status flags to force output sort order
Files in status will, be default, be sorted according to the case insensitivity of the filesystem that we're running on. However, in some cases, this is not desirable. Even on case insensitive file systems, 'git status' at the command line will generally use a case sensitive sort (like 'ls'). Some GUIs prefer to display a list of file case insensitively even on case-sensitive platforms. This adds two new flags: GIT_STATUS_OPT_SORT_CASE_SENSITIVELY and GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY that will override the default sort order of the status output and give the user control. This includes tests for exercising these new options and makes the examples/status.c program emulate core Git and always use a case sensitive sort.
-rw-r--r--examples/status.c3
-rw-r--r--include/git2/status.h8
-rw-r--r--src/attr_file.c2
-rw-r--r--src/diff.c12
-rw-r--r--src/index.c10
-rw-r--r--src/status.c12
-rw-r--r--src/submodule.c2
-rw-r--r--src/vector.h9
-rw-r--r--tests-clar/status/status_helpers.c3
-rw-r--r--tests-clar/status/status_helpers.h1
-rw-r--r--tests-clar/status/worktree.c80
11 files changed, 126 insertions, 16 deletions
diff --git a/examples/status.c b/examples/status.c
index 2378c78b6..3c82640b2 100644
--- a/examples/status.c
+++ b/examples/status.c
@@ -203,7 +203,8 @@ int main(int argc, char *argv[])
opt.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
opt.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
- GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX;
+ GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
+ GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
for (i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
diff --git a/include/git2/status.h b/include/git2/status.h
index 282b606cb..63aea2f3b 100644
--- a/include/git2/status.h
+++ b/include/git2/status.h
@@ -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 \
diff --git a/src/attr_file.c b/src/attr_file.c
index d059cfec7..d880398e8 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -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;
diff --git a/src/diff.c b/src/diff.c
index 3846a5e1b..26e117402 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -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;
@@ -1165,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);
}
}
@@ -1266,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);
}
}
@@ -1301,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);
}
}
diff --git a/src/index.c b/src/index.c
index d5568528b..1d46779bf 100644
--- a/src/index.c
+++ b/src/index.c
@@ -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);
diff --git a/src/status.c b/src/status.c
index 375100a89..e520c1017 100644
--- a/src/status.c
+++ b/src/status.c
@@ -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:
diff --git a/src/submodule.c b/src/submodule.c
index af488b7f3..89eba2aa4 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -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);
diff --git a/src/vector.h b/src/vector.h
index e2f729b83..1bda9c93d 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -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
diff --git a/tests-clar/status/status_helpers.c b/tests-clar/status/status_helpers.c
index f073c2491..902b65c4f 100644
--- a/tests-clar/status/status_helpers.c
+++ b/tests-clar/status/status_helpers.c
@@ -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;
diff --git a/tests-clar/status/status_helpers.h b/tests-clar/status/status_helpers.h
index ae1469e79..f1f009e02 100644
--- a/tests-clar/status/status_helpers.h
+++ b/tests-clar/status/status_helpers.h
@@ -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 *" */
diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c
index 7c27ee588..920671e13 100644
--- a/tests-clar/status/worktree.c
+++ b/tests-clar/status/worktree.c
@@ -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);
+}