summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2011-01-05 21:31:01 (GMT)
committerJunio C Hamano <gitster@pobox.com>2011-01-05 21:31:01 (GMT)
commit9e98354ab9717480e2e15b5ae56c10c3d5702a9b (patch)
tree716ed1df67e67bd8dccaca8909af135452806614
parent0c30ed0cb57988378d721d817c55f74a93dffb13 (diff)
parent4290f690676bc14c49c7cddbcda1c09017948718 (diff)
downloadgit-9e98354ab9717480e2e15b5ae56c10c3d5702a9b.zip
git-9e98354ab9717480e2e15b5ae56c10c3d5702a9b.tar.gz
git-9e98354ab9717480e2e15b5ae56c10c3d5702a9b.tar.bz2
Merge branch 'pw/convert-pathname-substitution'
* pw/convert-pathname-substitution: t0021: avoid getting filter killed with SIGPIPE convert filter: supply path to external driver
-rw-r--r--Documentation/gitattributes.txt10
-rw-r--r--convert.c23
-rwxr-xr-xt/t0021-conversion.sh43
3 files changed, 75 insertions, 1 deletions
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 5a7f936..22b8582 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -335,6 +335,16 @@ input that is already correctly indented. In this case, the lack of a
smudge filter means that the clean filter _must_ accept its own output
without modifying it.
+Sequence "%f" on the filter command line is replaced with the name of
+the file the filter is working on. A filter might use this in keyword
+substitution. For example:
+
+------------------------
+[filter "p4"]
+ clean = git-p4-filter --clean %f
+ smudge = git-p4-filter --smudge %f
+------------------------
+
Interaction between checkin/checkout attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/convert.c b/convert.c
index 01de9a8..d5aebed 100644
--- a/convert.c
+++ b/convert.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "attr.h"
#include "run-command.h"
+#include "quote.h"
/*
* convert.c - convert a file when checking it out and checking it in.
@@ -318,6 +319,7 @@ struct filter_params {
const char *src;
unsigned long size;
const char *cmd;
+ const char *path;
};
static int filter_buffer(int in, int out, void *data)
@@ -330,7 +332,23 @@ static int filter_buffer(int in, int out, void *data)
int write_err, status;
const char *argv[] = { NULL, NULL };
- argv[0] = params->cmd;
+ /* apply % substitution to cmd */
+ struct strbuf cmd = STRBUF_INIT;
+ struct strbuf path = STRBUF_INIT;
+ struct strbuf_expand_dict_entry dict[] = {
+ { "f", NULL, },
+ { NULL, NULL, },
+ };
+
+ /* quote the path to preserve spaces, etc. */
+ sq_quote_buf(&path, params->path);
+ dict[0].value = path.buf;
+
+ /* expand all %f with the quoted path */
+ strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
+ strbuf_release(&path);
+
+ argv[0] = cmd.buf;
memset(&child_process, 0, sizeof(child_process));
child_process.argv = argv;
@@ -350,6 +368,8 @@ static int filter_buffer(int in, int out, void *data)
status = finish_command(&child_process);
if (status)
error("external filter %s failed %d", params->cmd, status);
+
+ strbuf_release(&cmd);
return (write_err || status);
}
@@ -377,6 +397,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
params.src = src;
params.size = len;
params.cmd = cmd;
+ params.path = path;
fflush(NULL);
if (start_async(&async))
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 828e35b..9078b84 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -93,4 +93,47 @@ test_expect_success expanded_in_repo '
cmp expanded-keywords expected-output
'
+# The use of %f in a filter definition is expanded to the path to
+# the filename being smudged or cleaned. It must be shell escaped.
+# First, set up some interesting file names and pet them in
+# .gitattributes.
+test_expect_success 'filter shell-escaped filenames' '
+ cat >argc.sh <<-EOF &&
+ #!$SHELL_PATH
+ cat >/dev/null
+ echo argc: \$# "\$@"
+ EOF
+ normal=name-no-magic &&
+ special="name with '\''sq'\'' and \$x" &&
+ echo some test text >"$normal" &&
+ echo some test text >"$special" &&
+ git add "$normal" "$special" &&
+ git commit -q -m "add files" &&
+ echo "name* filter=argc" >.gitattributes &&
+
+ # delete the files and check them out again, using a smudge filter
+ # that will count the args and echo the command-line back to us
+ git config filter.argc.smudge "sh ./argc.sh %f" &&
+ rm "$normal" "$special" &&
+ git checkout -- "$normal" "$special" &&
+
+ # make sure argc.sh counted the right number of args
+ echo "argc: 1 $normal" >expect &&
+ test_cmp expect "$normal" &&
+ echo "argc: 1 $special" >expect &&
+ test_cmp expect "$special" &&
+
+ # do the same thing, but with more args in the filter expression
+ git config filter.argc.smudge "sh ./argc.sh %f --my-extra-arg" &&
+ rm "$normal" "$special" &&
+ git checkout -- "$normal" "$special" &&
+
+ # make sure argc.sh counted the right number of args
+ echo "argc: 2 $normal --my-extra-arg" >expect &&
+ test_cmp expect "$normal" &&
+ echo "argc: 2 $special --my-extra-arg" >expect &&
+ test_cmp expect "$special" &&
+ :
+'
+
test_done