@matheusbsbs / matheus-bagliano / commits / a2b665de4b
Fork 0

convert filter: supply path to external driver

Filtering to support keyword expansion may need the name of the file being filtered. In particular, to support p4 keywords like $File: //depot/product/dir/script.sh $ the smudge filter needs to know the name of the file it is smudging. Allow "%f" in the custom filter command line specified in the configuration. This will be substituted by the filename inside a single-quote pair to be passed to the shell. Signed-off-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Pete Wyckoff committed Dec 22, 2010 at 06:40 UTC a2b665de4b694b04959f6371f9887f7ad5cae404
3 files changed +74 -1
Documentation/gitattributes.txt
+10
@@ -335,6 +335,16 @@ input that is already correctly indented. In this case, the lack of a
335 smudge filter means that the clean filter _must_ accept its own output
336 without modifying it.
337
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 +
348
349 Interaction between checkin/checkout attributes
350 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
convert.c
+22 -1
@@ -1,6 +1,7 @@
1 #include "cache.h"
2 #include "attr.h"
3 #include "run-command.h"
4 +#include "quote.h"
5
6 /*
7 * convert.c - convert a file when checking it out and checking it in.
@@ -318,6 +319,7 @@ struct filter_params {
319 const char *src;
320 unsigned long size;
321 const char *cmd;
322 + const char *path;
323 };
324
325 static int filter_buffer(int in, int out, void *data)
@@ -330,7 +332,23 @@ static int filter_buffer(int in, int out, void *data)
332 int write_err, status;
333 const char *argv[] = { NULL, NULL };
334
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;
352
353 memset(&child_process, 0, sizeof(child_process));
354 child_process.argv = argv;
@@ -350,6 +368,8 @@ static int filter_buffer(int in, int out, void *data)
368 status = finish_command(&child_process);
369 if (status)
370 error("external filter %s failed %d", params->cmd, status);
371 +
372 + strbuf_release(&cmd);
373 return (write_err || status);
374 }
375
@@ -377,6 +397,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
397 params.src = src;
398 params.size = len;
399 params.cmd = cmd;
400 + params.path = path;
401
402 fflush(NULL);
403 if (start_async(&async))
t/t0021-conversion.sh
+42
@@ -93,4 +93,46 @@ test_expect_success expanded_in_repo '
93 cmp expanded-keywords expected-output
94 '
95
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 + echo argc: \$# "\$@"
104 + EOF
105 + normal=name-no-magic &&
106 + special="name with '\''sq'\'' and \$x" &&
107 + echo some test text >"$normal" &&
108 + echo some test text >"$special" &&
109 + git add "$normal" "$special" &&
110 + git commit -q -m "add files" &&
111 + echo "name* filter=argc" >.gitattributes &&
112 +
113 + # delete the files and check them out again, using a smudge filter
114 + # that will count the args and echo the command-line back to us
115 + git config filter.argc.smudge "sh ./argc.sh %f" &&
116 + rm "$normal" "$special" &&
117 + git checkout -- "$normal" "$special" &&
118 +
119 + # make sure argc.sh counted the right number of args
120 + echo "argc: 1 $normal" >expect &&
121 + test_cmp expect "$normal" &&
122 + echo "argc: 1 $special" >expect &&
123 + test_cmp expect "$special" &&
124 +
125 + # do the same thing, but with more args in the filter expression
126 + git config filter.argc.smudge "sh ./argc.sh %f --my-extra-arg" &&
127 + rm "$normal" "$special" &&
128 + git checkout -- "$normal" "$special" &&
129 +
130 + # make sure argc.sh counted the right number of args
131 + echo "argc: 2 $normal --my-extra-arg" >expect &&
132 + test_cmp expect "$normal" &&
133 + echo "argc: 2 $special --my-extra-arg" >expect &&
134 + test_cmp expect "$special" &&
135 + :
136 +'
137 +
138 test_done