Skip to content

Commit 4197361

Browse files
committed
Merge branch 'mg/more-textconv'
Make "git grep" and "git show" pay attention to --textconv when dealing with blob objects. * mg/more-textconv: grep: honor --textconv for the case rev:path grep: allow to use textconv filters t7008: demonstrate behavior of grep with textconv cat-file: do not die on --textconv without textconv filters show: honor --textconv for blobs diff_opt: track whether flags have been set explicitly t4030: demonstrate behavior of show with textconv
2 parents eeb8e83 + afa15f3 commit 4197361

File tree

14 files changed

+237
-57
lines changed

14 files changed

+237
-57
lines changed

Documentation/git-grep.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-grep - Print lines matching a pattern
99
SYNOPSIS
1010
--------
1111
[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]
1313
[-v | --invert-match] [-h|-H] [--full-name]
1414
[-E | --extended-regexp] [-G | --basic-regexp]
1515
[-P | --perl-regexp]
@@ -80,6 +80,13 @@ OPTIONS
8080
--text::
8181
Process binary files as if they were text.
8282

83+
--textconv::
84+
Honor textconv filter settings.
85+
86+
--no-textconv::
87+
Do not honor textconv filter settings.
88+
This is the default.
89+
8390
-i::
8491
--ignore-case::
8592
Ignore case differences between the patterns and the

Documentation/technical/api-diff.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ Calling sequence
2828

2929
* Call `diff_setup_done()`; this inspects the options set up so far for
3030
internal consistency and make necessary tweaking to it (e.g. if
31-
textual patch output was asked, recursive behaviour is turned on).
31+
textual patch output was asked, recursive behaviour is turned on);
32+
the callback set_default in diff_options can be used to tweak this more.
3233

3334
* As you find different pairs of files, call `diff_change()` to feed
3435
modified files, `diff_addremove()` to feed created or deleted files,
@@ -115,6 +116,13 @@ Notable members are:
115116
operation, but some do not have anything to do with the diffcore
116117
library.
117118

119+
`touched_flags`::
120+
Records whether a flag has been changed due to user request
121+
(rather than just set/unset by default).
122+
123+
`set_default`::
124+
Callback which allows tweaking the options in diff_setup_done().
125+
118126
BINARY, TEXT;;
119127
Affects the way how a file that is seemingly binary is treated.
120128

builtin/cat-file.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
4545
case 'e':
4646
return !has_sha1_file(sha1);
4747

48+
case 'c':
49+
if (!obj_context.path[0])
50+
die("git cat-file --textconv %s: <object> must be <sha1:path>",
51+
obj_name);
52+
53+
if (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
54+
break;
55+
4856
case 'p':
4957
type = sha1_object_info(sha1, NULL);
5058
if (type < 0)
@@ -67,16 +75,6 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
6775
/* otherwise just spit out the data */
6876
break;
6977

70-
case 'c':
71-
if (!obj_context.path[0])
72-
die("git cat-file --textconv %s: <object> must be <sha1:path>",
73-
obj_name);
74-
75-
if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
76-
die("git cat-file --textconv: unable to run textconv on %s",
77-
obj_name);
78-
break;
79-
8078
case 0:
8179
if (type_from_string(exp_type) == OBJ_BLOB) {
8280
unsigned char blob_sha1[20];

builtin/grep.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
458458
}
459459

460460
static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
461-
struct object *obj, const char *name)
461+
struct object *obj, const char *name, struct object_context *oc)
462462
{
463463
if (obj->type == OBJ_BLOB)
464-
return grep_sha1(opt, obj->sha1, name, 0, NULL);
464+
return grep_sha1(opt, obj->sha1, name, 0, oc ? oc->path : NULL);
465465
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
466466
struct tree_desc tree;
467467
void *data;
@@ -503,7 +503,7 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
503503
for (i = 0; i < nr; i++) {
504504
struct object *real_obj;
505505
real_obj = deref_tag(list->objects[i].item, NULL, 0);
506-
if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {
506+
if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].context)) {
507507
hit = 1;
508508
if (opt->status_only)
509509
break;
@@ -658,6 +658,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
658658
OPT_SET_INT('I', NULL, &opt.binary,
659659
N_("don't match patterns in binary files"),
660660
GREP_BINARY_NOMATCH),
661+
OPT_BOOL(0, "textconv", &opt.allow_textconv,
662+
N_("process binary files with textconv filters")),
661663
{ OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
662664
N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
663665
NULL, 1 },
@@ -817,12 +819,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
817819
for (i = 0; i < argc; i++) {
818820
const char *arg = argv[i];
819821
unsigned char sha1[20];
822+
struct object_context oc;
820823
/* Is it a rev? */
821-
if (!get_sha1(arg, sha1)) {
824+
if (!get_sha1_with_context(arg, 0, sha1, &oc)) {
822825
struct object *object = parse_object_or_die(sha1, arg);
823826
if (!seen_dashdash)
824827
verify_non_filename(prefix, arg);
825-
add_object_array(object, arg, &list);
828+
add_object_array_with_context(object, arg, &list, xmemdupz(&oc, sizeof(struct object_context)));
826829
continue;
827830
}
828831
if (!strcmp(arg, "--")) {

builtin/log.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ static void cmd_log_init_defaults(struct rev_info *rev)
111111

112112
if (default_date_mode)
113113
rev->date_mode = parse_date_format(default_date_mode);
114+
rev->diffopt.touched_flags = 0;
114115
}
115116

116117
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
@@ -436,10 +437,29 @@ static void show_tagger(char *buf, int len, struct rev_info *rev)
436437
strbuf_release(&out);
437438
}
438439

439-
static int show_blob_object(const unsigned char *sha1, struct rev_info *rev)
440+
static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, const char *obj_name)
440441
{
442+
unsigned char sha1c[20];
443+
struct object_context obj_context;
444+
char *buf;
445+
unsigned long size;
446+
441447
fflush(stdout);
442-
return stream_blob_to_fd(1, sha1, NULL, 0);
448+
if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
449+
!DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
450+
return stream_blob_to_fd(1, sha1, NULL, 0);
451+
452+
if (get_sha1_with_context(obj_name, 0, sha1c, &obj_context))
453+
die("Not a valid object name %s", obj_name);
454+
if (!obj_context.path[0] ||
455+
!textconv_object(obj_context.path, obj_context.mode, sha1c, 1, &buf, &size))
456+
return stream_blob_to_fd(1, sha1, NULL, 0);
457+
458+
if (!buf)
459+
die("git show %s: bad file", obj_name);
460+
461+
write_or_die(1, buf, size);
462+
return 0;
443463
}
444464

445465
static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
@@ -525,7 +545,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
525545
const char *name = objects[i].name;
526546
switch (o->type) {
527547
case OBJ_BLOB:
528-
ret = show_blob_object(o->sha1, NULL);
548+
ret = show_blob_object(o->sha1, &rev, name);
529549
break;
530550
case OBJ_TAG: {
531551
struct tag *t = (struct tag *)o;

diff.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3219,6 +3219,9 @@ void diff_setup_done(struct diff_options *options)
32193219
{
32203220
int count = 0;
32213221

3222+
if (options->set_default)
3223+
options->set_default(options);
3224+
32223225
if (options->output_format & DIFF_FORMAT_NAME)
32233226
count++;
32243227
if (options->output_format & DIFF_FORMAT_NAME_STATUS)

diff.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
8888
#define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
8989

9090
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
91-
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
92-
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)
91+
#define DIFF_OPT_TOUCHED(opts, flag) ((opts)->touched_flags & DIFF_OPT_##flag)
92+
#define DIFF_OPT_SET(opts, flag) (((opts)->flags |= DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
93+
#define DIFF_OPT_CLR(opts, flag) (((opts)->flags &= ~DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
9394
#define DIFF_XDL_TST(opts, flag) ((opts)->xdl_opts & XDF_##flag)
9495
#define DIFF_XDL_SET(opts, flag) ((opts)->xdl_opts |= XDF_##flag)
9596
#define DIFF_XDL_CLR(opts, flag) ((opts)->xdl_opts &= ~XDF_##flag)
@@ -109,6 +110,7 @@ struct diff_options {
109110
const char *single_follow;
110111
const char *a_prefix, *b_prefix;
111112
unsigned flags;
113+
unsigned touched_flags;
112114

113115
/* diff-filter bits */
114116
unsigned int filter;
@@ -149,6 +151,8 @@ struct diff_options {
149151
/* to support internal diff recursion by --follow hack*/
150152
int found_follow;
151153

154+
void (*set_default)(struct diff_options *);
155+
152156
FILE *file;
153157
int close_file;
154158

grep.c

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#include "grep.h"
33
#include "userdiff.h"
44
#include "xdiff-interface.h"
5+
#include "diff.h"
6+
#include "diffcore.h"
57

68
static int grep_source_load(struct grep_source *gs);
79
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)
13221324
fwrite(buf, size, 1, stdout);
13231325
}
13241326

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+
13251379
static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int collect_hits)
13261380
{
13271381
char *bol;
@@ -1332,6 +1386,7 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
13321386
unsigned count = 0;
13331387
int try_lookahead = 0;
13341388
int show_function = 0;
1389+
struct userdiff_driver *textconv = NULL;
13351390
enum grep_context ctx = GREP_CONTEXT_HEAD;
13361391
xdemitconf_t xecfg;
13371392

@@ -1353,27 +1408,44 @@ static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int colle
13531408
}
13541409
opt->last_shown = 0;
13551410

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+
}
13691441
}
13701442

13711443
memset(&xecfg, 0, sizeof(xecfg));
13721444
opt->priv = &xecfg;
13731445

13741446
try_lookahead = should_lookahead(opt);
13751447

1376-
if (grep_source_load(gs) < 0)
1448+
if (fill_textconv_grep(textconv, gs) < 0)
13771449
return 0;
13781450

13791451
bol = gs->buf;

grep.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct grep_opt {
107107
#define GREP_BINARY_NOMATCH 1
108108
#define GREP_BINARY_TEXT 2
109109
int binary;
110+
int allow_textconv;
110111
int extended;
111112
int use_reflog_filter;
112113
int pcre;

0 commit comments

Comments
 (0)