Skip to content

Commit

Permalink
Merge branch 'jb/required-filter'
Browse files Browse the repository at this point in the history
* jb/required-filter:
  Add a setting to require a filter to be successful

Conflicts:
	convert.c
  • Loading branch information
Junio C Hamano committed Feb 28, 2012
2 parents 25a7850 + 36daaac commit 524ee67
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 14 deletions.
41 changes: 31 additions & 10 deletions Documentation/gitattributes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -294,16 +294,27 @@ output is used to update the worktree file. Similarly, the
`clean` command is used to convert the contents of worktree file
upon checkin.

A missing filter driver definition in the config is not an error
but makes the filter a no-op passthru.

The content filtering is done to massage the content into a
shape that is more convenient for the platform, filesystem, and
the user to use. The key phrase here is "more convenient" and not
"turning something unusable into usable". In other words, the
intent is that if someone unsets the filter driver definition,
or does not have the appropriate filter program, the project
should still be usable.
One use of the content filtering is to massage the content into a shape
that is more convenient for the platform, filesystem, and the user to use.
For this mode of operation, the key phrase here is "more convenient" and
not "turning something unusable into usable". In other words, the intent
is that if someone unsets the filter driver definition, or does not have
the appropriate filter program, the project should still be usable.

Another use of the content filtering is to store the content that cannot
be directly used in the repository (e.g. a UUID that refers to the true
content stored outside git, or an encrypted content) and turn it into a
usable form upon checkout (e.g. download the external content, or decrypt
the encrypted content).

These two filters behave differently, and by default, a filter is taken as
the former, massaging the contents into more convenient shape. A missing
filter driver definition in the config, or a filter driver that exits with
a non-zero status, is not an error but makes the filter a no-op passthru.

You can declare that a filter turns a content that by itself is unusable
into a usable content by setting the filter.<driver>.required configuration
variable to `true`.

For example, in .gitattributes, you would assign the `filter`
attribute for paths.
Expand Down Expand Up @@ -335,6 +346,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.

If a filter _must_ succeed in order to make the stored contents usable,
you can declare that the filter is `required`, in the configuration:

------------------------
[filter "crypt"]
clean = openssl enc ...
smudge = openssl enc -d ...
required
------------------------

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:
Expand Down
28 changes: 24 additions & 4 deletions convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ static struct convert_driver {
struct convert_driver *next;
const char *smudge;
const char *clean;
int required;
} *user_convert, **user_convert_tail;

static int read_convert_config(const char *var, const char *value, void *cb)
Expand Down Expand Up @@ -495,6 +496,11 @@ static int read_convert_config(const char *var, const char *value, void *cb)
if (!strcmp("clean", ep))
return git_config_string(&drv->clean, var, value);

if (!strcmp("required", ep)) {
drv->required = git_config_bool(var, value);
return 0;
}

return 0;
}

Expand Down Expand Up @@ -773,13 +779,19 @@ int convert_to_git(const char *path, const char *src, size_t len,
{
int ret = 0;
const char *filter = NULL;
int required = 0;
struct conv_attrs ca;

convert_attrs(&ca, path);
if (ca.drv)
if (ca.drv) {
filter = ca.drv->clean;
required = ca.drv->required;
}

ret |= apply_filter(path, src, len, dst, filter);
if (!ret && required)
die("%s: clean filter '%s' failed", path, ca.drv->name);

if (ret && dst) {
src = dst->buf;
len = dst->len;
Expand All @@ -797,13 +809,16 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
size_t len, struct strbuf *dst,
int normalizing)
{
int ret = 0;
int ret = 0, ret_filter = 0;
const char *filter = NULL;
int required = 0;
struct conv_attrs ca;

convert_attrs(&ca, path);
if (ca.drv)
if (ca.drv) {
filter = ca.drv->smudge;
required = ca.drv->required;
}

ret |= ident_to_worktree(path, src, len, dst, ca.ident);
if (ret) {
Expand All @@ -822,7 +837,12 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
len = dst->len;
}
}
return ret | apply_filter(path, src, len, dst, filter);

ret_filter = apply_filter(path, src, len, dst, filter);
if (!ret_filter && required)
die("%s: smudge filter %s failed", path, ca.drv->name);

return ret | ret_filter;
}

int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
Expand Down
37 changes: 37 additions & 0 deletions t/t0021-conversion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,41 @@ test_expect_success 'filter shell-escaped filenames' '
:
'

test_expect_success 'required filter success' '
git config filter.required.smudge cat &&
git config filter.required.clean cat &&
git config filter.required.required true &&
echo "*.r filter=required" >.gitattributes &&
echo test >test.r &&
git add test.r &&
rm -f test.r &&
git checkout -- test.r
'

test_expect_success 'required filter smudge failure' '
git config filter.failsmudge.smudge false &&
git config filter.failsmudge.clean cat &&
git config filter.failsmudge.required true &&
echo "*.fs filter=failsmudge" >.gitattributes &&
echo test >test.fs &&
git add test.fs &&
rm -f test.fs &&
test_must_fail git checkout -- test.fs
'

test_expect_success 'required filter clean failure' '
git config filter.failclean.smudge cat &&
git config filter.failclean.clean false &&
git config filter.failclean.required true &&
echo "*.fc filter=failclean" >.gitattributes &&
echo test >test.fc &&
test_must_fail git add test.fc
'

test_done

0 comments on commit 524ee67

Please sign in to comment.