diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d4b73342..1fff2d499 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,6 +133,9 @@ support for HTTPS connections insead of OpenSSL. path. For this, `GIT_CREDTYPE_SSH_MEMORY` and `git_cred_ssh_key_memory_new()` have been added. +* `git_filter_list_contains` will indicate whether a particular + filter will be run in the given filter list. + ### API removals * `git_remote_save()` and `git_remote_clear_refspecs()` have been diff --git a/include/git2/filter.h b/include/git2/filter.h index dc59e6341..1828903e4 100644 --- a/include/git2/filter.h +++ b/include/git2/filter.h @@ -95,6 +95,22 @@ GIT_EXTERN(int) git_filter_list_load( git_filter_mode_t mode, uint32_t flags); +/** + * Query the filter list to see if a given filter (by name) will run. + * The built-in filters "crlf" and "ident" can be queried, otherwise this + * is the name of the filter specified by the filter attribute. + * + * This will return 0 if the given filter is not in the list, or 1 if + * the filter will be applied. + * + * @param filters A loaded git_filter_list (or NULL) + * @param name The name of the filter to query + * @return 1 if the filter is in the list, 0 otherwise + */ +GIT_EXTERN(int) git_filter_list_contains( + git_filter_list *filters, + const char *name); + /** * Apply filter list to a data buffer. * diff --git a/src/filter.c b/src/filter.c index 3c6a0a9d8..e25d37c35 100644 --- a/src/filter.c +++ b/src/filter.c @@ -27,6 +27,7 @@ struct git_filter_source { }; typedef struct { + const char *filter_name; git_filter *filter; void *payload; } git_filter_entry; @@ -526,7 +527,9 @@ int git_filter_list__load_ext( fe = git_array_alloc(fl->filters); GITERR_CHECK_ALLOC(fe); - fe->filter = fdef->filter; + + fe->filter = fdef->filter; + fe->filter_name = fdef->filter_name; fe->payload = payload; } } @@ -574,6 +577,25 @@ void git_filter_list_free(git_filter_list *fl) git__free(fl); } +int git_filter_list_contains( + git_filter_list *fl, + const char *name) +{ + size_t i; + + assert(name); + + if (!fl) + return 0; + + for (i = 0; i < fl->filters.size; i++) { + if (strcmp(fl->filters.ptr[i].filter_name, name) == 0) + return 1; + } + + return 0; +} + int git_filter_list_push( git_filter_list *fl, git_filter *filter, void *payload) { diff --git a/tests/filter/query.c b/tests/filter/query.c new file mode 100644 index 000000000..6889d715b --- /dev/null +++ b/tests/filter/query.c @@ -0,0 +1,91 @@ +#include "clar_libgit2.h" +#include "git2/sys/filter.h" +#include "crlf.h" +#include "buffer.h" + +static git_repository *g_repo = NULL; + +void test_filter_query__initialize(void) +{ + g_repo = cl_git_sandbox_init("crlf"); + + cl_git_mkfile("crlf/.gitattributes", + "*.txt text\n" + "*.bin binary\n" + "*.crlf text eol=crlf\n" + "*.lf text eol=lf\n" + "*.binident binary ident\n" + "*.ident text ident\n" + "*.identcrlf ident text eol=crlf\n" + "*.identlf ident text eol=lf\n" + "*.custom custom ident text\n"); +} + +void test_filter_query__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static int filter_for(const char *filename, const char *filter) +{ + git_filter_list *fl; + int filtered; + + cl_git_pass(git_filter_list_load( + &fl, g_repo, NULL, filename, GIT_FILTER_TO_WORKTREE, 0)); + filtered = git_filter_list_contains(fl, filter); + git_filter_list_free(fl); + + return filtered; +} + +void test_filter_query__filters(void) +{ + cl_assert_equal_i(1, filter_for("text.txt", "crlf")); + cl_assert_equal_i(0, filter_for("binary.bin", "crlf")); + + cl_assert_equal_i(1, filter_for("foo.lf", "crlf")); + cl_assert_equal_i(0, filter_for("foo.lf", "ident")); + + cl_assert_equal_i(1, filter_for("id.ident", "crlf")); + cl_assert_equal_i(1, filter_for("id.ident", "ident")); + + cl_assert_equal_i(0, filter_for("id.binident", "crlf")); + cl_assert_equal_i(1, filter_for("id.binident", "ident")); +} + +void test_filter_query__autocrlf_true_implies_crlf(void) +{ + cl_repo_set_bool(g_repo, "core.autocrlf", true); + cl_assert_equal_i(1, filter_for("not_in_gitattributes", "crlf")); + cl_assert_equal_i(1, filter_for("foo.txt", "crlf")); + cl_assert_equal_i(0, filter_for("foo.bin", "crlf")); + cl_assert_equal_i(1, filter_for("foo.lf", "crlf")); + + cl_repo_set_bool(g_repo, "core.autocrlf", false); + cl_assert_equal_i(0, filter_for("not_in_gitattributes", "crlf")); + cl_assert_equal_i(1, filter_for("foo.txt", "crlf")); + cl_assert_equal_i(0, filter_for("foo.bin", "crlf")); + cl_assert_equal_i(1, filter_for("foo.lf", "crlf")); +} + +void test_filter_query__unknown(void) +{ + cl_assert_equal_i(1, filter_for("foo.custom", "crlf")); + cl_assert_equal_i(1, filter_for("foo.custom", "ident")); + cl_assert_equal_i(0, filter_for("foo.custom", "custom")); +} + +void test_filter_query__custom(void) +{ + git_filter custom = { GIT_FILTER_VERSION }; + + cl_git_pass(git_filter_register( + "custom", &custom, 42)); + + cl_assert_equal_i(1, filter_for("foo.custom", "crlf")); + cl_assert_equal_i(1, filter_for("foo.custom", "ident")); + cl_assert_equal_i(1, filter_for("foo.custom", "custom")); + + git_filter_unregister("custom"); +}