By default, if a filter driver fails, the unfiltered content will be used. This patch adds a "filter.<name>.required" config option. When set to true, git will abort if the filter fails. A typical usage would be for a "bigfile" filter, where the smudge command can fail if the file is not available locally. Without the "required", the content of repository, i.e. a reference to the real content, will be checked out. Unless one saves the output logs, it then fairly easy to lose track of what "bigfile" wasn't checked out correctly. Another example would be for an encrypted repository if the clean command (encryption) fails. Without the "required", an unencrypted content could be stored in the repository by mistake. Signed-off-by: Jehan Bing <jehan@xxxxxxx> --- Documentation/gitattributes.txt | 14 ++++++++++++ convert.c | 28 +++++++++++++++++++++--- t/t0021-conversion.sh | 43 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index a85b187..4d1af93 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -305,6 +305,10 @@ intent is that if someone unsets the filter driver definition, or does not have the appropriate filter program, the project should still be usable. +The exception is if the filter definition has the `required` +attribute set to `true`. In that case, the filter must apply +successfully or git will abort the current operation. + For example, in .gitattributes, you would assign the `filter` attribute for paths. @@ -335,6 +339,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 you do not wish git to continue if `clean` or `smudge` fail, you can +add a `required` attribute to the filter: + +------------------------ +[filter "crypt"] + clean = openssl enc ... + smudge = openssl enc -d ... + required = true +------------------------ + 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: diff --git a/convert.c b/convert.c index 12868ed..6c95a90 100644 --- a/convert.c +++ b/convert.c @@ -429,6 +429,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) @@ -472,6 +473,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; } @@ -747,13 +753,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("required filter '%s' failed", ca.drv->name); + if (ret) { src = dst->buf; len = dst->len; @@ -771,13 +783,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) { @@ -796,7 +811,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("required filter %s failed", ca.drv->name); + + return ret | ret_filter; } int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst) diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index f19e651..f80a59f 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -153,4 +153,47 @@ 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 && + ! 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 && + ! git add test.fc +' + test_done -- 1.7.9 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html