This lets you configure a format like: [tarfilter "tgz"] command = gzip extension = tgz extension = tar.gz and have it automatically used for "foo.tgz" or "foo.tar.gz". Signed-off-by: Jeff King <peff@xxxxxxxx> --- archive-tar-filter.c | 29 +++++++++++++++++++++++++++++ archive.c | 12 ++++++++++++ archive.h | 1 + t/t5000-tar-tree.sh | 4 ++-- 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/archive-tar-filter.c b/archive-tar-filter.c index ffe510e..e749133 100644 --- a/archive-tar-filter.c +++ b/archive-tar-filter.c @@ -39,6 +39,35 @@ struct tar_filter *tar_filter_by_name(const char *name) return tar_filter_by_namelen(name, strlen(name)); } +static int match_extension(const char *filename, const char *ext) +{ + int prefixlen = strlen(filename) - strlen(ext); + + /* + * We need 1 character for the '.', and 1 character to ensure that the + * prefix is non-empty (i.e., we don't match ".tar.gz" with no actual + * filename). + */ + if (prefixlen < 2 || filename[prefixlen-1] != '.') + return 0; + return !strcmp(filename + prefixlen, ext); +} + +struct tar_filter *tar_filter_by_extension(const char *filename) +{ + struct tar_filter *p; + + for (p = tar_filters; p; p = p->next) { + int i; + for (i = 0; i < p->extensions.nr; i++) { + const char *ext = p->extensions.items[i].string; + if (match_extension(filename, ext)) + return p; + } + } + return NULL; +} + static int tar_filter_config(const char *var, const char *value, void *data) { struct tar_filter *tf; diff --git a/archive.c b/archive.c index e04f689..e509b6c 100644 --- a/archive.c +++ b/archive.c @@ -434,11 +434,23 @@ int write_archive(int argc, const char **argv, const char *prefix, const char *archive_format_from_filename(const char *filename) { + struct tar_filter *tf; const char *ext = strrchr(filename, '.'); if (!ext) return NULL; ext++; if (!strcasecmp(ext, "zip")) return "zip"; + + /* + * Fallback to user-configured tar filters; but note + * that we might have to load config ourselves, first, + * if we are not being called via write_archive. + */ + tar_filter_load_config(); + tf = tar_filter_by_extension(filename); + if (tf) + return tf->name; + return NULL; } diff --git a/archive.h b/archive.h index 894d4c4..80c89dc 100644 --- a/archive.h +++ b/archive.h @@ -41,6 +41,7 @@ struct tar_filter { extern struct tar_filter *tar_filters; extern struct tar_filter *tar_filter_by_name(const char *name); +extern struct tar_filter *tar_filter_by_extension(const char *filename); extern void tar_filter_load_config(void); diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh index 9f959b1..fe661f3 100755 --- a/t/t5000-tar-tree.sh +++ b/t/t5000-tar-tree.sh @@ -289,7 +289,7 @@ test_expect_success 'archive outputs in configurable format' ' test_cmp b.tar config.tar ' -test_expect_failure 'archive selects implicit format by configured extension' ' +test_expect_success 'archive selects implicit format by configured extension' ' git archive -o config-implicit.tar.foo HEAD && test_cmp config.tar.foo config-implicit.tar.foo && git archive -o config-implicit.bar HEAD && @@ -301,7 +301,7 @@ test_expect_success 'default output format remains tar' ' test_cmp b.tar config-implicit.baz ' -test_expect_failure 'extension matching requires dot' ' +test_expect_success 'extension matching requires dot' ' git archive -o config-implicittar.foo HEAD && test_cmp b.tar config-implicittar.foo ' -- 1.7.6.rc1.4.g49204 -- 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