Skip to content

Commit

Permalink
convert filter: supply path to external driver
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Pete Wyckoff authored and Junio C Hamano committed Dec 22, 2010
1 parent 853563d commit a2b665d
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Documentation/gitattributes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
23 changes: 22 additions & 1 deletion convert.c
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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);
}

Expand Down Expand Up @@ -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))
Expand Down
42 changes: 42 additions & 0 deletions t/t0021-conversion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,46 @@ 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
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

0 comments on commit a2b665d

Please sign in to comment.