mirror of
https://git.proxmox.com/git/libgit2
synced 2026-01-01 05:04:06 +00:00
Add functions to manipulate filter lists
Extend the git2/sys/filter API with functions to look up a filter and add it manually to a filter list. This requires some trickery because the regular attribute lookups and checks are bypassed when this happens, but in the right hands, it will allow a user to have granular control over applying filters.
This commit is contained in:
parent
0646634e2f
commit
40cb40fab9
@ -62,23 +62,6 @@ typedef struct git_filter git_filter;
|
||||
*/
|
||||
typedef struct git_filter_list git_filter_list;
|
||||
|
||||
/**
|
||||
* Look up a filter by name
|
||||
*/
|
||||
GIT_EXTERN(git_filter *) git_filter_lookup(const char *name);
|
||||
|
||||
#define GIT_FILTER_CRLF "crlf"
|
||||
|
||||
/**
|
||||
* Apply a single filter to a buffer of data
|
||||
*/
|
||||
GIT_EXTERN(int) git_filter_apply_to_buffer(
|
||||
git_buffer *out,
|
||||
git_filter *filter,
|
||||
const git_buffer *input,
|
||||
const char *as_path,
|
||||
git_filter_mode_t mode);
|
||||
|
||||
/**
|
||||
* Load the filter list for a given path.
|
||||
*
|
||||
|
||||
@ -18,6 +18,43 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Look up a filter by name
|
||||
*
|
||||
* @param name The name of the filter
|
||||
* @return Pointer to the filter object or NULL if not found
|
||||
*/
|
||||
GIT_EXTERN(git_filter *) git_filter_lookup(const char *name);
|
||||
|
||||
#define GIT_FILTER_CRLF "crlf"
|
||||
|
||||
/**
|
||||
* Create a new empty filter list
|
||||
*
|
||||
* Normally you won't use this because `git_filter_list_load` will create
|
||||
* the filter list for you, but you can use this in combination with the
|
||||
* `git_filter_lookup` and `git_filter_list_push` functions to assemble
|
||||
* your own chains of filters.
|
||||
*/
|
||||
GIT_EXTERN(int) git_filter_list_new(
|
||||
git_filter_list **out, git_repository *repo, git_filter_mode_t mode);
|
||||
|
||||
/**
|
||||
* Add a filter to a filter list with the given payload.
|
||||
*
|
||||
* Normally you won't have to do this because the filter list is created
|
||||
* by calling the "check" function on registered filters when the filter
|
||||
* attributes are set, but this does allow more direct manipulation of
|
||||
* filter lists when desired.
|
||||
*
|
||||
* Note that normally the "check" function can set up a payload for the
|
||||
* filter. Using this function, you can either pass in a payload if you
|
||||
* know the expected payload format, or you can pass NULL. Some filters
|
||||
* may fail with a NULL payload. Good luck!
|
||||
*/
|
||||
GIT_EXTERN(int) git_filter_list_push(
|
||||
git_filter_list *fl, git_filter *filter, void *payload);
|
||||
|
||||
/**
|
||||
* A filter source represents a file/blob to be processed
|
||||
*/
|
||||
|
||||
@ -548,9 +548,10 @@ int git_buffer_resize(git_buffer *buffer, size_t want_size)
|
||||
int git_buffer_copy(
|
||||
git_buffer *buffer, const void *data, size_t datalen)
|
||||
{
|
||||
if (git_buffer__resize(buffer, datalen, false) < 0)
|
||||
if (git_buffer__resize(buffer, datalen + 1, false) < 0)
|
||||
return -1;
|
||||
memcpy(buffer->ptr, data, datalen);
|
||||
buffer->ptr[datalen] = '\0';
|
||||
buffer->size = datalen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
14
src/crlf.c
14
src/crlf.c
@ -86,6 +86,9 @@ static int has_cr_in_index(const git_filter_source *src)
|
||||
git_off_t blobsize;
|
||||
bool found_cr;
|
||||
|
||||
if (!path)
|
||||
return false;
|
||||
|
||||
if (git_repository_index__weakptr(&index, repo) < 0) {
|
||||
giterr_clear();
|
||||
return false;
|
||||
@ -189,9 +192,7 @@ static const char *line_ending(struct crlf_attrs *ca)
|
||||
|
||||
switch (ca->eol) {
|
||||
case GIT_EOL_UNSET:
|
||||
return GIT_EOL_NATIVE == GIT_EOL_CRLF
|
||||
? "\r\n"
|
||||
: "\n";
|
||||
return GIT_EOL_NATIVE == GIT_EOL_CRLF ? "\r\n" : "\n";
|
||||
|
||||
case GIT_EOL_CRLF:
|
||||
return "\r\n";
|
||||
@ -302,7 +303,12 @@ static int crlf_apply(
|
||||
const git_buffer *from,
|
||||
const git_filter_source *src)
|
||||
{
|
||||
GIT_UNUSED(self);
|
||||
/* initialize payload in case `check` was bypassed */
|
||||
if (!*payload) {
|
||||
int error = crlf_check(self, payload, src, NULL);
|
||||
if (error < 0 && error != GIT_ENOTFOUND)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (git_filter_source_mode(src) == GIT_FILTER_SMUDGE)
|
||||
return crlf_apply_to_workdir(*payload, to, from);
|
||||
|
||||
52
src/filter.c
52
src/filter.c
@ -181,7 +181,13 @@ static int filter_def_name_key_check(const void *key, const void *fdef)
|
||||
{
|
||||
const char *name =
|
||||
fdef ? ((const git_filter_def *)fdef)->filter_name : NULL;
|
||||
return name ? -1 : git__strcmp(key, name);
|
||||
return name ? git__strcmp(key, name) : -1;
|
||||
}
|
||||
|
||||
static int filter_def_filter_key_check(const void *key, const void *fdef)
|
||||
{
|
||||
const void *filter = fdef ? ((const git_filter_def *)fdef)->filter : NULL;
|
||||
return (key == filter) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int filter_registry_find(size_t *pos, const char *name)
|
||||
@ -331,7 +337,7 @@ git_filter_mode_t git_filter_source_mode(const git_filter_source *src)
|
||||
return src->mode;
|
||||
}
|
||||
|
||||
static int git_filter_list_new(
|
||||
static int filter_list_new(
|
||||
git_filter_list **out, const git_filter_source *src)
|
||||
{
|
||||
git_filter_list *fl = NULL;
|
||||
@ -391,6 +397,16 @@ static int filter_list_check_attributes(
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_filter_list_new(
|
||||
git_filter_list **out, git_repository *repo, git_filter_mode_t mode)
|
||||
{
|
||||
git_filter_source src = { 0 };
|
||||
src.repo = repo;
|
||||
src.path = NULL;
|
||||
src.mode = mode;
|
||||
return filter_list_new(out, &src);
|
||||
}
|
||||
|
||||
int git_filter_list_load(
|
||||
git_filter_list **filters,
|
||||
git_repository *repo,
|
||||
@ -441,7 +457,7 @@ int git_filter_list_load(
|
||||
else if (error < 0)
|
||||
break;
|
||||
else {
|
||||
if (!fl && (error = git_filter_list_new(&fl, &src)) < 0)
|
||||
if (!fl && (error = filter_list_new(&fl, &src)) < 0)
|
||||
return error;
|
||||
|
||||
fe = git_array_alloc(fl->filters);
|
||||
@ -478,6 +494,36 @@ void git_filter_list_free(git_filter_list *fl)
|
||||
git__free(fl);
|
||||
}
|
||||
|
||||
int git_filter_list_push(
|
||||
git_filter_list *fl, git_filter *filter, void *payload)
|
||||
{
|
||||
int error = 0;
|
||||
size_t pos;
|
||||
git_filter_def *fdef;
|
||||
git_filter_entry *fe;
|
||||
|
||||
assert(fl && filter);
|
||||
|
||||
if (git_vector_search2(
|
||||
&pos, &git__filter_registry->filters,
|
||||
filter_def_filter_key_check, filter) < 0) {
|
||||
giterr_set(GITERR_FILTER, "Cannot use an unregistered filter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdef = git_vector_get(&git__filter_registry->filters, pos);
|
||||
|
||||
if (!fdef->initialized && (error = filter_initialize(fdef)) < 0)
|
||||
return error;
|
||||
|
||||
fe = git_array_alloc(fl->filters);
|
||||
GITERR_CHECK_ALLOC(fe);
|
||||
fe->filter = filter;
|
||||
fe->payload = payload;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int filter_list_out_buffer_from_raw(
|
||||
git_buffer *out, const void *ptr, size_t size)
|
||||
{
|
||||
|
||||
83
tests-clar/filter/crlf.c
Normal file
83
tests-clar/filter/crlf.c
Normal file
@ -0,0 +1,83 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "git2/sys/filter.h"
|
||||
|
||||
static git_repository *g_repo = NULL;
|
||||
|
||||
void test_filter_crlf__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");
|
||||
}
|
||||
|
||||
void test_filter_crlf__cleanup(void)
|
||||
{
|
||||
cl_git_sandbox_cleanup();
|
||||
}
|
||||
|
||||
void test_filter_crlf__to_worktree(void)
|
||||
{
|
||||
git_filter_list *fl;
|
||||
git_filter *crlf;
|
||||
git_buffer in = GIT_BUFFER_INIT, out = GIT_BUFFER_INIT;
|
||||
|
||||
{
|
||||
git_config *cfg;
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
cl_git_pass(git_config_set_string(cfg, "core.autocrlf", "true"));
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
cl_git_pass(git_filter_list_new(&fl, g_repo, GIT_FILTER_TO_WORKTREE));
|
||||
|
||||
crlf = git_filter_lookup(GIT_FILTER_CRLF);
|
||||
cl_assert(crlf != NULL);
|
||||
|
||||
cl_git_pass(git_filter_list_push(fl, crlf, NULL));
|
||||
|
||||
in.ptr = "Some text\nRight here\n";
|
||||
in.size = strlen(in.ptr);
|
||||
|
||||
cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
cl_assert_equal_s("Some text\r\nRight here\r\n", out.ptr);
|
||||
#else
|
||||
cl_assert_equal_s("Some text\nRight here\n", out.ptr);
|
||||
#endif
|
||||
|
||||
git_filter_list_free(fl);
|
||||
git_buffer_free(&out);
|
||||
}
|
||||
|
||||
void test_filter_crlf__to_odb(void)
|
||||
{
|
||||
git_filter_list *fl;
|
||||
git_filter *crlf;
|
||||
git_buffer in = GIT_BUFFER_INIT, out = GIT_BUFFER_INIT;
|
||||
|
||||
{
|
||||
git_config *cfg;
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
cl_git_pass(git_config_set_string(cfg, "core.autocrlf", "true"));
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
cl_git_pass(git_filter_list_new(&fl, g_repo, GIT_FILTER_TO_ODB));
|
||||
|
||||
crlf = git_filter_lookup(GIT_FILTER_CRLF);
|
||||
cl_assert(crlf != NULL);
|
||||
|
||||
cl_git_pass(git_filter_list_push(fl, crlf, NULL));
|
||||
|
||||
in.ptr = "Some text\r\nRight here\r\n";
|
||||
in.size = strlen(in.ptr);
|
||||
|
||||
cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
|
||||
|
||||
cl_assert_equal_s("Some text\nRight here\n", out.ptr);
|
||||
|
||||
git_filter_list_free(fl);
|
||||
git_buffer_free(&out);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user