grep: allow to use textconv filters

Recently and not so recently, we made sure that log/grep type operations use textconv filters when a userfacing diff would do the same: ef90ab6 (pickaxe: use textconv for -S counting, 2012-10-28) b1c2f57 (diff_grep: use textconv buffers for add/deleted files, 2012-10-28) 0508fe5 (combine-diff: respect textconv attributes, 2011-05-23) "git grep" currently does not use textconv filters at all, that is neither for displaying the match and context nor for the actual grepping, even when requested by --textconv. Introduce an option "--textconv" which makes git grep use any configured textconv filters for grepping and output purposes. It is off by default. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed May 10, 2013 at 17:10 UTC 335ec3bf411ae6606b58885deb281192c86651c6
5 files changed +102 -16
Documentation/git-grep.txt
+8 -1
@@ -9,7 +9,7 @@ git-grep - Print lines matching a pattern
9 SYNOPSIS
10 --------
11 [verse]
12 -'git grep' [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
12 +'git grep' [-a | --text] [-I] [--textconv] [-i | --ignore-case] [-w | --word-regexp]
13 [-v | --invert-match] [-h|-H] [--full-name]
14 [-E | --extended-regexp] [-G | --basic-regexp]
15 [-P | --perl-regexp]
@@ -80,6 +80,13 @@ OPTIONS
80 --text::
81 Process binary files as if they were text.
82
83 +--textconv::
84 + Honor textconv filter settings.
85 +
86 +--no-textconv::
87 + Do not honor textconv filter settings.
88 + This is the default.
89 +
90 -i::
91 --ignore-case::
92 Ignore case differences between the patterns and the
builtin/grep.c
+2
@@ -659,6 +659,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
659 OPT_SET_INT('I', NULL, &opt.binary,
660 N_("don't match patterns in binary files"),
661 GREP_BINARY_NOMATCH),
662 + OPT_BOOL(0, "textconv", &opt.allow_textconv,
663 + N_("process binary files with textconv filters")),
664 { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
665 N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
666 NULL, 1 },
grep.c
+86 -14
@@ -2,6 +2,8 @@
2 #include "grep.h"
3 #include "userdiff.h"
4 #include "xdiff-interface.h"
5 +#include "diff.h"
6 +#include "diffcore.h"
7
8 static int grep_source_load(struct grep_source *gs);
9 static int grep_source_is_binary(struct grep_source *gs);
@@ -1322,6 +1324,58 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size)
1324 fwrite(buf, size, 1, stdout);
1325 }
1326
1327 +static int fill_textconv_grep(struct userdiff_driver *driver,
1328 + struct grep_source *gs)
1329 +{
1330 + struct diff_filespec *df;
1331 + char *buf;
1332 + size_t size;
1333 +
1334 + if (!driver || !driver->textconv)
1335 + return grep_source_load(gs);
1336 +
1337 + /*
1338 + * The textconv interface is intimately tied to diff_filespecs, so we
1339 + * have to pretend to be one. If we could unify the grep_source
1340 + * and diff_filespec structs, this mess could just go away.
1341 + */
1342 + df = alloc_filespec(gs->path);
1343 + switch (gs->type) {
1344 + case GREP_SOURCE_SHA1:
1345 + fill_filespec(df, gs->identifier, 1, 0100644);
1346 + break;
1347 + case GREP_SOURCE_FILE:
1348 + fill_filespec(df, null_sha1, 0, 0100644);
1349 + break;
1350 + default:
1351 + die("BUG: attempt to textconv something without a path?");
1352 + }
1353 +
1354 + /*
1355 + * fill_textconv is not remotely thread-safe; it may load objects
1356 + * behind the scenes, and it modifies the global diff tempfile
1357 + * structure.
1358 + */
1359 + grep_read_lock();
1360 + size = fill_textconv(driver, df, &buf);
1361 + grep_read_unlock();
1362 + free_filespec(df);
1363 +
1364 + /*
1365 + * The normal fill_textconv usage by the diff machinery would just keep
1366 + * the textconv'd buf separate from the diff_filespec. But much of the
1367 + * grep code passes around a grep_source and assumes that its "buf"
1368 + * pointer is the beginning of the thing we are searching. So let's
1369 + * install our textconv'd version into the grep_source, taking care not
1370 + * to leak any existing buffer.
1371 + */
1372 + grep_source_clear_data(gs);
1373 + gs->buf = buf;
1374 + gs->size = size;
1375 +
1376 + return 0;
1377 +}
1378 +
1379 static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int collect_hits)
1380 {
1381 char *bol;
@@ -1332,6 +1386,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
1386 unsigned count = 0;
1387 int try_lookahead = 0;
1388 int show_function = 0;
1389 + struct userdiff_driver *textconv = NULL;
1390 enum grep_context ctx = GREP_CONTEXT_HEAD;
1391 xdemitconf_t xecfg;
1392
@@ -1353,19 +1408,36 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
1408 }
1409 opt->last_shown = 0;
1410
1356 - switch (opt->binary) {
1357 - case GREP_BINARY_DEFAULT:
1358 - if (grep_source_is_binary(gs))
1359 - binary_match_only = 1;
1360 - break;
1361 - case GREP_BINARY_NOMATCH:
1362 - if (grep_source_is_binary(gs))
1363 - return 0; /* Assume unmatch */
1364 - break;
1365 - case GREP_BINARY_TEXT:
1366 - break;
1367 - default:
1368 - die("bug: unknown binary handling mode");
1411 + if (opt->allow_textconv) {
1412 + grep_source_load_driver(gs);
1413 + /*
1414 + * We might set up the shared textconv cache data here, which
1415 + * is not thread-safe.
1416 + */
1417 + grep_attr_lock();
1418 + textconv = userdiff_get_textconv(gs->driver);
1419 + grep_attr_unlock();
1420 + }
1421 +
1422 + /*
1423 + * We know the result of a textconv is text, so we only have to care
1424 + * about binary handling if we are not using it.
1425 + */
1426 + if (!textconv) {
1427 + switch (opt->binary) {
1428 + case GREP_BINARY_DEFAULT:
1429 + if (grep_source_is_binary(gs))
1430 + binary_match_only = 1;
1431 + break;
1432 + case GREP_BINARY_NOMATCH:
1433 + if (grep_source_is_binary(gs))
1434 + return 0; /* Assume unmatch */
1435 + break;
1436 + case GREP_BINARY_TEXT:
1437 + break;
1438 + default:
1439 + die("bug: unknown binary handling mode");
1440 + }
1441 }
1442
1443 memset(&xecfg, 0, sizeof(xecfg));
@@ -1373,7 +1445,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
1445
1446 try_lookahead = should_lookahead(opt);
1447
1376 - if (grep_source_load(gs) < 0)
1448 + if (fill_textconv_grep(textconv, gs) < 0)
1449 return 0;
1450
1451 bol = gs->buf;
grep.h
+1
@@ -107,6 +107,7 @@ struct grep_opt {
107 #define GREP_BINARY_NOMATCH 1
108 #define GREP_BINARY_TEXT 2
109 int binary;
110 + int allow_textconv;
111 int extended;
112 int use_reflog_filter;
113 int pcre;
t/t7008-grep-binary.sh
+5 -1
@@ -160,7 +160,7 @@ test_expect_success 'grep does not honor textconv' '
160 test_must_fail git grep Qfile
161 '
162
163 -test_expect_failure 'grep --textconv honors textconv' '
163 +test_expect_success 'grep --textconv honors textconv' '
164 echo "a:binaryQfile" >expect &&
165 git grep --textconv Qfile >actual &&
166 test_cmp expect actual
@@ -176,4 +176,8 @@ test_expect_failure 'grep --textconv blob honors textconv' '
176 test_cmp expect actual
177 '
178
179 +test_expect_success 'grep --no-textconv blob does not honor textconv' '
180 + test_must_fail git grep --no-textconv Qfile HEAD:a
181 +'
182 +
183 test_done