mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
diff: support regexp ignores
Emulate git's `-I` (`--ignore-matching-lines`) with a regular expression.
This commit is contained in:
@@ -444,6 +444,13 @@ typedef struct {
|
||||
* Defaults to "b".
|
||||
*/
|
||||
const char *new_prefix;
|
||||
|
||||
/**
|
||||
* Ignore lines matching the given regular expression(s); both
|
||||
* the preimage and postimage lines must match.
|
||||
*/
|
||||
const char **ignore_regexp;
|
||||
size_t ignore_regexp_count;
|
||||
} git_diff_options;
|
||||
|
||||
/* The current version of the diff options structure */
|
||||
|
||||
@@ -230,9 +230,12 @@ static int git_xdiff(git_patch_generated_output *output, git_patch_generated *pa
|
||||
return xo->output.error;
|
||||
}
|
||||
|
||||
void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts)
|
||||
int git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts)
|
||||
{
|
||||
git_regexp **regexen;
|
||||
uint32_t flags = opts ? opts->flags : 0;
|
||||
int regexp_flags = GIT_REGEXP_EXTENDED | GIT_REGEXP_NEWLINE;
|
||||
size_t i;
|
||||
|
||||
xo->output.diff_cb = git_xdiff;
|
||||
|
||||
@@ -256,5 +259,42 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts)
|
||||
if (flags & GIT_DIFF_IGNORE_BLANK_LINES)
|
||||
xo->params.flags |= XDF_IGNORE_BLANK_LINES;
|
||||
|
||||
if (opts && opts->ignore_regexp_count) {
|
||||
regexen = git__calloc(opts->ignore_regexp_count, sizeof(git_regexp *));
|
||||
GIT_ERROR_CHECK_ALLOC(regexen);
|
||||
|
||||
xo->params.ignore_regex = regexen;
|
||||
xo->params.ignore_regex_nr = opts->ignore_regexp_count;
|
||||
|
||||
for (i = 0; i < opts->ignore_regexp_count; i++) {
|
||||
regexen[i] = git__malloc(sizeof(git_regexp));
|
||||
GIT_ERROR_CHECK_ALLOC(regexen[i]);
|
||||
|
||||
if (git_regexp_compile(regexen[i],
|
||||
opts->ignore_regexp[i],
|
||||
regexp_flags) < 0) {
|
||||
git_error_set(GIT_ERROR_INVALID, "could not compile regular expression");
|
||||
git_xdiff_dispose(xo);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xo->callback.out_line = git_xdiff_cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void git_xdiff_dispose(git_xdiff_output *xo)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < xo->params.ignore_regex_nr; i++) {
|
||||
if (xo->params.ignore_regex[i]) {
|
||||
git_regexp_dispose(xo->params.ignore_regex[i]);
|
||||
git__free(xo->params.ignore_regex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
git__free(xo->params.ignore_regex);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ typedef struct {
|
||||
xdemitcb_t callback;
|
||||
} git_xdiff_output;
|
||||
|
||||
void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts);
|
||||
int git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts);
|
||||
void git_xdiff_dispose(git_xdiff_output *xo);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -540,13 +540,16 @@ static int diff_from_sources(
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
diff_output_init(
|
||||
&xo.output, opts, file_cb, binary_cb, hunk_cb, data_cb, payload);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
if ((error = git_xdiff_init(&xo, opts)) < 0)
|
||||
return error;
|
||||
|
||||
memset(&pd, 0, sizeof(pd));
|
||||
|
||||
error = patch_generated_from_sources(&pd, &xo, oldsrc, newsrc, opts);
|
||||
|
||||
git_patch_free(&pd.patch.base);
|
||||
git_xdiff_dispose(&xo);
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -570,13 +573,16 @@ static int patch_from_sources(
|
||||
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
diff_output_to_patch(&xo.output, &pd->patch);
|
||||
git_xdiff_init(&xo, opts);
|
||||
|
||||
if ((error = git_xdiff_init(&xo, opts)) < 0)
|
||||
return error;
|
||||
|
||||
if (!(error = patch_generated_from_sources(pd, &xo, oldsrc, newsrc, opts)))
|
||||
*out = (git_patch *)pd;
|
||||
else
|
||||
git_patch_free((git_patch *)pd);
|
||||
|
||||
git_xdiff_dispose(&xo);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -724,7 +730,9 @@ int git_patch_generated_from_diff(
|
||||
|
||||
memset(&xo, 0, sizeof(xo));
|
||||
diff_output_to_patch(&xo.output, patch);
|
||||
git_xdiff_init(&xo, &diff->opts);
|
||||
|
||||
if ((error = git_xdiff_init(&xo, &diff->opts)) < 0)
|
||||
return error;
|
||||
|
||||
error = patch_generated_invoke_file_callback(patch, &xo.output);
|
||||
|
||||
@@ -741,6 +749,7 @@ int git_patch_generated_from_diff(
|
||||
else
|
||||
*patch_ptr = &patch->base;
|
||||
|
||||
git_xdiff_dispose(&xo);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ int git_regexp_compile(git_regexp *r, const char *pattern, int flags);
|
||||
/**
|
||||
* Free memory associated with the regular expression
|
||||
*
|
||||
* @param r The regular expression structure to dispose.
|
||||
e @param r The regular expression structure to dispose.
|
||||
*/
|
||||
void git_regexp_dispose(git_regexp *r);
|
||||
|
||||
|
||||
@@ -29,14 +29,9 @@ GIT_INLINE(int) xdl_regexec_buf(
|
||||
const xdl_regex_t *preg, const char *buf, size_t size,
|
||||
size_t nmatch, xdl_regmatch_t pmatch[], int eflags)
|
||||
{
|
||||
GIT_UNUSED(preg);
|
||||
GIT_UNUSED(buf);
|
||||
GIT_UNUSED(size);
|
||||
GIT_UNUSED(nmatch);
|
||||
GIT_UNUSED(pmatch);
|
||||
GIT_UNUSED(eflags);
|
||||
GIT_ASSERT("not implemented");
|
||||
return -1;
|
||||
GIT_ASSERT(nmatch > 0 && pmatch && eflags == 0);
|
||||
|
||||
return git_regexp_search_n(preg, buf, size, nmatch, pmatch);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1061,3 +1061,70 @@ void test_diff_blob__can_compare_buffer_to_buffer(void)
|
||||
diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
|
||||
assert_one_modified(4, 9, 0, 5, 4, &expected);
|
||||
}
|
||||
|
||||
#define EMPTY_DIFF "diff --git a/file b/file\n" \
|
||||
"index 92dfa21..d5a68b2 100644\n" \
|
||||
"--- a/file\n" \
|
||||
"+++ b/file\n"
|
||||
|
||||
#define NOT_EMPTY_DIFF \
|
||||
"diff --git a/file b/file\n" \
|
||||
"index 92dfa21..d5a68b2 100644\n" \
|
||||
"--- a/file\n" \
|
||||
"+++ b/file\n" \
|
||||
"@@ -5 +5 @@ d\n" \
|
||||
"-e\n" \
|
||||
"+E\n"
|
||||
|
||||
void test_diff_blob__patch_with_ignore_regexp(void)
|
||||
{
|
||||
git_patch *p;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
const char *a = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n";
|
||||
const char *b = "a\nb\nc\nd\nE\nf\ng\nh\ni\nj\n";
|
||||
const char *ignore_lower = "e";
|
||||
const char *ignore_upper = "E";
|
||||
const char *ignore_both[] = { ignore_lower, ignore_upper };
|
||||
const char *ignore_match = "^(e|E)$";
|
||||
|
||||
opts.interhunk_lines = 0;
|
||||
opts.context_lines = 0;
|
||||
opts.ignore_regexp = ignore_both;
|
||||
opts.ignore_regexp_count = 2;
|
||||
|
||||
/* match both e and E */
|
||||
cl_git_pass(git_patch_from_buffers(&p, a, strlen(a), NULL,
|
||||
b, strlen(b), NULL, &opts));
|
||||
|
||||
cl_git_pass(git_patch_to_buf(&buf, p));
|
||||
cl_assert_equal_s(EMPTY_DIFF, buf.ptr);
|
||||
|
||||
git_patch_free(p);
|
||||
git_buf_dispose(&buf);
|
||||
|
||||
/* match ^(e|E)$ */
|
||||
opts.ignore_regexp = &ignore_match;
|
||||
opts.ignore_regexp_count = 1;
|
||||
|
||||
cl_git_pass(git_patch_from_buffers(&p, a, strlen(a), NULL,
|
||||
b, strlen(b), NULL, &opts));
|
||||
|
||||
cl_git_pass(git_patch_to_buf(&buf, p));
|
||||
cl_assert_equal_s(EMPTY_DIFF, buf.ptr);
|
||||
|
||||
git_patch_free(p);
|
||||
git_buf_dispose(&buf);
|
||||
|
||||
/* matching only E does not match preimage */
|
||||
opts.ignore_regexp = &ignore_upper;
|
||||
opts.ignore_regexp_count = 1;
|
||||
|
||||
cl_git_pass(git_patch_from_buffers(&p, a, strlen(a), NULL,
|
||||
b, strlen(b), NULL, &opts));
|
||||
|
||||
cl_git_pass(git_patch_to_buf(&buf, p));
|
||||
cl_assert_equal_s(NOT_EMPTY_DIFF, buf.ptr);
|
||||
|
||||
git_patch_free(p);
|
||||
git_buf_dispose(&buf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user