diff options
| -rw-r--r-- | include/git2/filter.h | 17 | ||||
| -rw-r--r-- | include/git2/sys/filter.h | 37 | ||||
| -rw-r--r-- | src/buffer.c | 3 | ||||
| -rw-r--r-- | src/crlf.c | 14 | ||||
| -rw-r--r-- | src/filter.c | 52 | ||||
| -rw-r--r-- | tests-clar/filter/crlf.c | 83 | 
6 files changed, 181 insertions, 25 deletions
| diff --git a/include/git2/filter.h b/include/git2/filter.h index cb23ae4f4..8ef88d81b 100644 --- a/include/git2/filter.h +++ b/include/git2/filter.h @@ -63,23 +63,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.   *   * This will return 0 (success) but set the output git_filter_list to NULL diff --git a/include/git2/sys/filter.h b/include/git2/sys/filter.h index dbb086b0e..ca5738a53 100644 --- a/include/git2/sys/filter.h +++ b/include/git2/sys/filter.h @@ -19,6 +19,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   */  typedef struct git_filter_source git_filter_source; diff --git a/src/buffer.c b/src/buffer.c index aaebac776..07725b9cc 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -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;  } diff --git a/src/crlf.c b/src/crlf.c index e974208a6..99c154f70 100644 --- a/src/crlf.c +++ b/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); diff --git a/src/filter.c b/src/filter.c index 73c2ceacb..79ccac0cf 100644 --- a/src/filter.c +++ b/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)  { diff --git a/tests-clar/filter/crlf.c b/tests-clar/filter/crlf.c new file mode 100644 index 000000000..098a85d4c --- /dev/null +++ b/tests-clar/filter/crlf.c @@ -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); +} | 
