Code

Revert removal of multi-match discard heuristic in 27af01
[git.git] / archive.c
index f0b4e85513eaab597225a23e2d132389224ea4c6..2a7a28e3ed35fe9db03ccf70b71867f7f8a22b8e 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -298,9 +298,10 @@ static void parse_treeish_arg(const char **argv,
          PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, NULL, (p) }
 
 static int parse_archive_args(int argc, const char **argv,
-               const struct archiver **ar, struct archiver_args *args)
+               const struct archiver **ar, struct archiver_args *args,
+               const char *name_hint, int is_remote)
 {
-       const char *format = "tar";
+       const char *format = NULL;
        const char *base = NULL;
        const char *remote = NULL;
        const char *exec = NULL;
@@ -355,15 +356,21 @@ static int parse_archive_args(int argc, const char **argv,
 
        if (list) {
                for (i = 0; i < nr_archivers; i++)
-                       printf("%s\n", archivers[i]->name);
+                       if (!is_remote || archivers[i]->flags & ARCHIVER_REMOTE)
+                               printf("%s\n", archivers[i]->name);
                exit(0);
        }
 
+       if (!format && name_hint)
+               format = archive_format_from_filename(name_hint);
+       if (!format)
+               format = "tar";
+
        /* We need at least one parameter -- tree-ish */
        if (argc < 1)
                usage_with_options(archive_usage, opts);
        *ar = lookup_archiver(format);
-       if (!*ar)
+       if (!*ar || (is_remote && !((*ar)->flags & ARCHIVER_REMOTE)))
                die("Unknown archive format '%s'", format);
 
        args->compression_level = Z_DEFAULT_COMPRESSION;
@@ -384,7 +391,7 @@ static int parse_archive_args(int argc, const char **argv,
 }
 
 int write_archive(int argc, const char **argv, const char *prefix,
-               int setup_prefix)
+                 int setup_prefix, const char *name_hint, int remote)
 {
        int nongit = 0;
        const struct archiver *ar = NULL;
@@ -397,7 +404,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
        init_tar_archiver();
        init_zip_archiver();
 
-       argc = parse_archive_args(argc, argv, &ar, &args);
+       argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
        if (nongit) {
                /*
                 * We know this will die() with an error, so we could just
@@ -410,5 +417,29 @@ int write_archive(int argc, const char **argv, const char *prefix,
        parse_treeish_arg(argv, &args, prefix);
        parse_pathspec_arg(argv + 1, &args);
 
-       return ar->write_archive(&args);
+       return ar->write_archive(ar, &args);
+}
+
+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 (k.e., we don't match .tar.gz with no actual
+        * filename).
+        */
+       if (prefixlen < 2 || filename[prefixlen-1] != '.')
+               return 0;
+       return !strcmp(filename + prefixlen, ext);
+}
+
+const char *archive_format_from_filename(const char *filename)
+{
+       int i;
+
+       for (i = 0; i < nr_archivers; i++)
+               if (match_extension(filename, archivers[i]->name))
+                       return archivers[i]->name;
+       return NULL;
 }