Skip to content

Commit 9e98354

Browse files
committed
Merge branch 'pw/convert-pathname-substitution'
* pw/convert-pathname-substitution: t0021: avoid getting filter killed with SIGPIPE convert filter: supply path to external driver
2 parents 0c30ed0 + 4290f69 commit 9e98354

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

Documentation/gitattributes.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,16 @@ input that is already correctly indented. In this case, the lack of a
335335
smudge filter means that the clean filter _must_ accept its own output
336336
without modifying it.
337337

338+
Sequence "%f" on the filter command line is replaced with the name of
339+
the file the filter is working on. A filter might use this in keyword
340+
substitution. For example:
341+
342+
------------------------
343+
[filter "p4"]
344+
clean = git-p4-filter --clean %f
345+
smudge = git-p4-filter --smudge %f
346+
------------------------
347+
338348

339349
Interaction between checkin/checkout attributes
340350
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

convert.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "cache.h"
22
#include "attr.h"
33
#include "run-command.h"
4+
#include "quote.h"
45

56
/*
67
* convert.c - convert a file when checking it out and checking it in.
@@ -318,6 +319,7 @@ struct filter_params {
318319
const char *src;
319320
unsigned long size;
320321
const char *cmd;
322+
const char *path;
321323
};
322324

323325
static int filter_buffer(int in, int out, void *data)
@@ -330,7 +332,23 @@ static int filter_buffer(int in, int out, void *data)
330332
int write_err, status;
331333
const char *argv[] = { NULL, NULL };
332334

333-
argv[0] = params->cmd;
335+
/* apply % substitution to cmd */
336+
struct strbuf cmd = STRBUF_INIT;
337+
struct strbuf path = STRBUF_INIT;
338+
struct strbuf_expand_dict_entry dict[] = {
339+
{ "f", NULL, },
340+
{ NULL, NULL, },
341+
};
342+
343+
/* quote the path to preserve spaces, etc. */
344+
sq_quote_buf(&path, params->path);
345+
dict[0].value = path.buf;
346+
347+
/* expand all %f with the quoted path */
348+
strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
349+
strbuf_release(&path);
350+
351+
argv[0] = cmd.buf;
334352

335353
memset(&child_process, 0, sizeof(child_process));
336354
child_process.argv = argv;
@@ -350,6 +368,8 @@ static int filter_buffer(int in, int out, void *data)
350368
status = finish_command(&child_process);
351369
if (status)
352370
error("external filter %s failed %d", params->cmd, status);
371+
372+
strbuf_release(&cmd);
353373
return (write_err || status);
354374
}
355375

@@ -377,6 +397,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
377397
params.src = src;
378398
params.size = len;
379399
params.cmd = cmd;
400+
params.path = path;
380401

381402
fflush(NULL);
382403
if (start_async(&async))

t/t0021-conversion.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,47 @@ test_expect_success expanded_in_repo '
9393
cmp expanded-keywords expected-output
9494
'
9595

96+
# The use of %f in a filter definition is expanded to the path to
97+
# the filename being smudged or cleaned. It must be shell escaped.
98+
# First, set up some interesting file names and pet them in
99+
# .gitattributes.
100+
test_expect_success 'filter shell-escaped filenames' '
101+
cat >argc.sh <<-EOF &&
102+
#!$SHELL_PATH
103+
cat >/dev/null
104+
echo argc: \$# "\$@"
105+
EOF
106+
normal=name-no-magic &&
107+
special="name with '\''sq'\'' and \$x" &&
108+
echo some test text >"$normal" &&
109+
echo some test text >"$special" &&
110+
git add "$normal" "$special" &&
111+
git commit -q -m "add files" &&
112+
echo "name* filter=argc" >.gitattributes &&
113+
114+
# delete the files and check them out again, using a smudge filter
115+
# that will count the args and echo the command-line back to us
116+
git config filter.argc.smudge "sh ./argc.sh %f" &&
117+
rm "$normal" "$special" &&
118+
git checkout -- "$normal" "$special" &&
119+
120+
# make sure argc.sh counted the right number of args
121+
echo "argc: 1 $normal" >expect &&
122+
test_cmp expect "$normal" &&
123+
echo "argc: 1 $special" >expect &&
124+
test_cmp expect "$special" &&
125+
126+
# do the same thing, but with more args in the filter expression
127+
git config filter.argc.smudge "sh ./argc.sh %f --my-extra-arg" &&
128+
rm "$normal" "$special" &&
129+
git checkout -- "$normal" "$special" &&
130+
131+
# make sure argc.sh counted the right number of args
132+
echo "argc: 2 $normal --my-extra-arg" >expect &&
133+
test_cmp expect "$normal" &&
134+
echo "argc: 2 $special --my-extra-arg" >expect &&
135+
test_cmp expect "$special" &&
136+
:
137+
'
138+
96139
test_done

0 commit comments

Comments
 (0)