Commit 855c66de by Edward Thomson

Introduce core.safecrlf handling

parent 5f74c476
......@@ -68,6 +68,7 @@ static struct map_data _cvar_maps[] = {
{"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT },
{"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT },
{"core.precomposeunicode", NULL, 0, GIT_PRECOMPOSE_DEFAULT },
{"core.safecrlf", NULL, 0, GIT_SAFE_CRLF_DEFAULT},
};
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
......
......@@ -21,6 +21,7 @@ struct crlf_attrs {
int crlf_action;
int eol;
int auto_crlf;
int safe_crlf;
};
struct crlf_filter {
......@@ -123,6 +124,9 @@ static int crlf_apply_to_odb(
const git_buf *from,
const git_filter_source *src)
{
git_buf safe = GIT_BUF_INIT;
int error = 0;
/* Empty file? Nothing to do */
if (!git_buf_len(from))
return 0;
......@@ -154,12 +158,31 @@ static int crlf_apply_to_odb(
return GIT_PASSTHROUGH;
}
if (!stats.cr)
if (!stats.cr && !ca->safe_crlf)
return GIT_PASSTHROUGH;
}
/* Actually drop the carriage returns */
return git_buf_text_crlf_to_lf(to, from);
if ((error = git_buf_text_crlf_to_lf(to, from)) < 0)
return error;
/* If safecrlf is enabled, sanity-check the result. */
if (ca->safe_crlf) {
if ((error = git_buf_grow(&safe, max(from->size, to->size))) < 0 ||
(error = git_buf_text_lf_to_crlf(&safe, to)) < 0)
goto done;
if (git_buf_cmp(from, &safe) != 0) {
giterr_set(GITERR_FILTER, "LF would be replaced by CRLF in '%s'",
git_filter_source_path(src));
error = -1;
}
}
done:
git_buf_free(&safe);
return error;
}
static const char *line_ending(struct crlf_attrs *ca)
......@@ -272,6 +295,13 @@ static int crlf_check(
return GIT_PASSTHROUGH;
}
if (git_filter_source_mode(src) == GIT_FILTER_CLEAN) {
error = git_repository__cvar(
&ca.safe_crlf, git_filter_source_repo(src), GIT_CVAR_SAFE_CRLF);
if (error < 0)
return error;
}
*payload = git__malloc(sizeof(ca));
GITERR_CHECK_ALLOC(*payload);
memcpy(*payload, &ca, sizeof(ca));
......
......@@ -38,6 +38,7 @@ typedef enum {
GIT_CVAR_TRUSTCTIME, /* core.trustctime */
GIT_CVAR_ABBREV, /* core.abbrev */
GIT_CVAR_PRECOMPOSE, /* core.precomposeunicode */
GIT_CVAR_SAFE_CRLF, /* core.safecrlf */
GIT_CVAR_CACHE_MAX
} git_cvar_cached;
......@@ -89,7 +90,8 @@ typedef enum {
GIT_ABBREV_DEFAULT = 7,
/* core.precomposeunicode */
GIT_PRECOMPOSE_DEFAULT = GIT_CVAR_FALSE,
/* core.safecrlf */
GIT_SAFE_CRLF_DEFAULT = GIT_CVAR_FALSE,
} git_cvar_value;
/* internal repository init flags */
......
#include "clar_libgit2.h"
#include "git2/sys/filter.h"
#include "buffer.h"
static git_repository *g_repo = NULL;
......@@ -69,3 +70,82 @@ void test_filter_crlf__to_odb(void)
git_filter_list_free(fl);
git_buf_free(&out);
}
void test_filter_crlf__with_safecrlf(void)
{
git_filter_list *fl;
git_filter *crlf;
git_buf in = {0}, out = GIT_BUF_INIT;
cl_repo_set_bool(g_repo, "core.safecrlf", true);
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));
/* Normalized \r\n succeeds with safecrlf */
in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n";
in.size = strlen(in.ptr);
cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr);
/* Mix of line endings fails with safecrlf */
in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
in.size = strlen(in.ptr);
cl_git_fail(git_filter_list_apply_to_data(&out, fl, &in));
cl_assert_equal_i(giterr_last()->klass, GITERR_FILTER);
/* Normalized \n fails with safecrlf */
in.ptr = "Normal\nLF\nonly\nline-endings.\n";
in.size = strlen(in.ptr);
cl_git_fail(git_filter_list_apply_to_data(&out, fl, &in));
cl_assert_equal_i(giterr_last()->klass, GITERR_FILTER);
git_filter_list_free(fl);
git_buf_free(&out);
}
void test_filter_crlf__no_safecrlf(void)
{
git_filter_list *fl;
git_filter *crlf;
git_buf in = {0}, out = GIT_BUF_INIT;
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));
/* Normalized \r\n succeeds with safecrlf */
in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n";
in.size = strlen(in.ptr);
cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr);
/* Mix of line endings fails with safecrlf */
in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n";
in.size = strlen(in.ptr);
cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
cl_assert_equal_s("Mixed\nup\nLF\nand\nCRLF\nline-endings.\n", out.ptr);
/* Normalized \n fails with safecrlf */
in.ptr = "Normal\nLF\nonly\nline-endings.\n";
in.size = strlen(in.ptr);
cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in));
cl_assert_equal_s("Normal\nLF\nonly\nline-endings.\n", out.ptr);
git_filter_list_free(fl);
git_buf_free(&out);
}
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