summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2022-01-29 15:41:53 -0500
committerEdward Thomson <ethomson@edwardthomson.com>2022-01-30 13:32:47 -0500
commit50887e521fc22e2eefa473bd31a0990534bacfbe (patch)
tree23db0acb07773bc338860b798fa4c03740d539ce
parentf85a69aed58d44ea9a2ec1788c82646b4ae01acc (diff)
downloadlibgit2-ethomson/diff_regexp_ignore.tar.gz
diff: support regexp ignoresethomson/diff_regexp_ignore
Emulate git's `-I` (`--ignore-matching-lines`) with a regular expression.
-rw-r--r--include/git2/diff.h7
-rw-r--r--src/diff_xdiff.c42
-rw-r--r--src/diff_xdiff.h3
-rw-r--r--src/patch_generate.c15
-rw-r--r--src/regexp.h2
-rw-r--r--src/xdiff/git-xdiff.h11
-rw-r--r--tests/diff/blob.c67
7 files changed, 133 insertions, 14 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 9424ffd06..334614680 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -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 */
diff --git a/src/diff_xdiff.c b/src/diff_xdiff.c
index 3f6eccac1..3425f33a3 100644
--- a/src/diff_xdiff.c
+++ b/src/diff_xdiff.c
@@ -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);
}
diff --git a/src/diff_xdiff.h b/src/diff_xdiff.h
index 9b303e9dc..3e051d1e1 100644
--- a/src/diff_xdiff.h
+++ b/src/diff_xdiff.h
@@ -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
diff --git a/src/patch_generate.c b/src/patch_generate.c
index bc598fea8..1d80c036e 100644
--- a/src/patch_generate.c
+++ b/src/patch_generate.c
@@ -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;
}
diff --git a/src/regexp.h b/src/regexp.h
index 61824bf5c..f4810c70b 100644
--- a/src/regexp.h
+++ b/src/regexp.h
@@ -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);
diff --git a/src/xdiff/git-xdiff.h b/src/xdiff/git-xdiff.h
index 0b4f0bc04..cdfb315bd 100644
--- a/src/xdiff/git-xdiff.h
+++ b/src/xdiff/git-xdiff.h
@@ -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
diff --git a/tests/diff/blob.c b/tests/diff/blob.c
index d2f42207d..88aeeebd3 100644
--- a/tests/diff/blob.c
+++ b/tests/diff/blob.c
@@ -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);
+}