Code

Merge branch 'rs/archive'
authorJunio C Hamano <gitster@pobox.com>
Thu, 17 Jul 2008 00:12:18 +0000 (17:12 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 17 Jul 2008 00:12:18 +0000 (17:12 -0700)
* rs/archive:
  archive: remove extra arguments parsing code
  archive: unify file attribute handling
  archive: centralize archive entry writing
  archive: add baselen member to struct archiver_args
  add context pointer to read_tree_recursive()
  archive: remove args member from struct archiver

12 files changed:
archive-tar.c
archive-zip.c
archive.c
archive.h
builtin-archive.c
builtin-checkout.c
builtin-log.c
builtin-ls-tree.c
builtin-merge-recursive.c
builtin-upload-archive.c
tree.c
tree.h

index 99db58f1cf21ee30f150c54acd6ffefbb14b6f57..f9eb726116854f6e45ab208e3b5e121c26cf8b05 100644 (file)
 static char block[BLOCKSIZE];
 static unsigned long offset;
 
-static time_t archive_time;
 static int tar_umask = 002;
-static int verbose;
-static const struct commit *commit;
-static size_t base_len;
 
 /* writes out the whole block, but only if it is full */
 static void write_if_needed(void)
@@ -114,22 +110,24 @@ static unsigned int ustar_header_chksum(const struct ustar_header *header)
        return chksum;
 }
 
-static int get_path_prefix(const struct strbuf *path, int maxlen)
+static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen)
 {
-       int i = path->len;
+       size_t i = pathlen;
        if (i > maxlen)
                i = maxlen;
        do {
                i--;
-       } while (i > 0 && path->buf[i] != '/');
+       } while (i > 0 && path[i] != '/');
        return i;
 }
 
-static void write_entry(const unsigned char *sha1, struct strbuf *path,
-                        unsigned int mode, void *buffer, unsigned long size)
+static int write_tar_entry(struct archiver_args *args,
+               const unsigned char *sha1, const char *path, size_t pathlen,
+               unsigned int mode, void *buffer, unsigned long size)
 {
        struct ustar_header header;
        struct strbuf ext_header;
+       int err = 0;
 
        memset(&header, 0, sizeof(header));
        strbuf_init(&ext_header, 0);
@@ -143,8 +141,6 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
                mode = 0100666;
                sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
        } else {
-               if (verbose)
-                       fprintf(stderr, "%.*s\n", (int)path->len, path->buf);
                if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
                        *header.typeflag = TYPEFLAG_DIR;
                        mode = (mode | 0777) & ~tar_umask;
@@ -155,24 +151,24 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
                        *header.typeflag = TYPEFLAG_REG;
                        mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
                } else {
-                       error("unsupported file mode: 0%o (SHA1: %s)",
-                             mode, sha1_to_hex(sha1));
-                       return;
+                       return error("unsupported file mode: 0%o (SHA1: %s)",
+                                       mode, sha1_to_hex(sha1));
                }
-               if (path->len > sizeof(header.name)) {
-                       int plen = get_path_prefix(path, sizeof(header.prefix));
-                       int rest = path->len - plen - 1;
+               if (pathlen > sizeof(header.name)) {
+                       size_t plen = get_path_prefix(path, pathlen,
+                                       sizeof(header.prefix));
+                       size_t rest = pathlen - plen - 1;
                        if (plen > 0 && rest <= sizeof(header.name)) {
-                               memcpy(header.prefix, path->buf, plen);
-                               memcpy(header.name, path->buf + plen + 1, rest);
+                               memcpy(header.prefix, path, plen);
+                               memcpy(header.name, path + plen + 1, rest);
                        } else {
                                sprintf(header.name, "%s.data",
                                        sha1_to_hex(sha1));
                                strbuf_append_ext_header(&ext_header, "path",
-                                                        path->buf, path->len);
+                                               path, pathlen);
                        }
                } else
-                       memcpy(header.name, path->buf, path->len);
+                       memcpy(header.name, path, pathlen);
        }
 
        if (S_ISLNK(mode) && buffer) {
@@ -187,7 +183,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
 
        sprintf(header.mode, "%07o", mode & 07777);
        sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
-       sprintf(header.mtime, "%011lo", archive_time);
+       sprintf(header.mtime, "%011lo", args->time);
 
        sprintf(header.uid, "%07o", 0);
        sprintf(header.gid, "%07o", 0);
@@ -202,22 +198,30 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
        sprintf(header.chksum, "%07o", ustar_header_chksum(&header));
 
        if (ext_header.len > 0) {
-               write_entry(sha1, NULL, 0, ext_header.buf, ext_header.len);
+               err = write_tar_entry(args, sha1, NULL, 0, 0, ext_header.buf,
+                               ext_header.len);
+               if (err)
+                       return err;
        }
        strbuf_release(&ext_header);
        write_blocked(&header, sizeof(header));
        if (S_ISREG(mode) && buffer && size > 0)
                write_blocked(buffer, size);
+       return err;
 }
 
-static void write_global_extended_header(const unsigned char *sha1)
+static int write_global_extended_header(struct archiver_args *args)
 {
+       const unsigned char *sha1 = args->commit_sha1;
        struct strbuf ext_header;
+       int err;
 
        strbuf_init(&ext_header, 0);
        strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
-       write_entry(NULL, NULL, 0, ext_header.buf, ext_header.len);
+       err = write_tar_entry(args, NULL, NULL, 0, 0, ext_header.buf,
+                       ext_header.len);
        strbuf_release(&ext_header);
+       return err;
 }
 
 static int git_tar_config(const char *var, const char *value, void *cb)
@@ -234,64 +238,17 @@ static int git_tar_config(const char *var, const char *value, void *cb)
        return git_default_config(var, value, cb);
 }
 
-static int write_tar_entry(const unsigned char *sha1,
-                           const char *base, int baselen,
-                           const char *filename, unsigned mode, int stage)
-{
-       static struct strbuf path = STRBUF_INIT;
-       void *buffer;
-       enum object_type type;
-       unsigned long size;
-
-       strbuf_reset(&path);
-       strbuf_grow(&path, PATH_MAX);
-       strbuf_add(&path, base, baselen);
-       strbuf_addstr(&path, filename);
-       if (is_archive_path_ignored(path.buf + base_len))
-               return 0;
-       if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
-               strbuf_addch(&path, '/');
-               buffer = NULL;
-               size = 0;
-       } else {
-               buffer = sha1_file_to_archive(path.buf + base_len, sha1, mode,
-                               &type, &size, commit);
-               if (!buffer)
-                       die("cannot read %s", sha1_to_hex(sha1));
-       }
-
-       write_entry(sha1, &path, mode, buffer, size);
-       free(buffer);
-
-       return READ_TREE_RECURSIVE;
-}
-
 int write_tar_archive(struct archiver_args *args)
 {
-       int plen = args->base ? strlen(args->base) : 0;
+       int err = 0;
 
        git_config(git_tar_config, NULL);
 
-       archive_time = args->time;
-       verbose = args->verbose;
-       commit = args->commit;
-       base_len = args->base ? strlen(args->base) : 0;
-
        if (args->commit_sha1)
-               write_global_extended_header(args->commit_sha1);
-
-       if (args->base && plen > 0 && args->base[plen - 1] == '/') {
-               char *base = xstrdup(args->base);
-               int baselen = strlen(base);
-
-               while (baselen > 0 && base[baselen - 1] == '/')
-                       base[--baselen] = '\0';
-               write_tar_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
-               free(base);
-       }
-       read_tree_recursive(args->tree, args->base, plen, 0,
-                           args->pathspec, write_tar_entry);
-       write_trailer();
-
-       return 0;
+               err = write_global_extended_header(args);
+       if (!err)
+               err = write_archive_entries(args, write_tar_entry);
+       if (!err)
+               write_trailer();
+       return err;
 }
index 5742762ac30c92e796255b74d2ed1ea087f3fba0..d56e5cfc1e4047a2e86a2aeacaafc8fb2931179e 100644 (file)
@@ -9,11 +9,8 @@
 #include "builtin.h"
 #include "archive.h"
 
-static int verbose;
 static int zip_date;
 static int zip_time;
-static const struct commit *commit;
-static size_t base_len;
 
 static unsigned char *zip_dir;
 static unsigned int zip_dir_size;
@@ -128,33 +125,9 @@ static void *zlib_deflate(void *data, unsigned long size,
        return buffer;
 }
 
-static char *construct_path(const char *base, int baselen,
-                            const char *filename, int isdir, int *pathlen)
-{
-       int filenamelen = strlen(filename);
-       int len = baselen + filenamelen;
-       char *path, *p;
-
-       if (isdir)
-               len++;
-       p = path = xmalloc(len + 1);
-
-       memcpy(p, base, baselen);
-       p += baselen;
-       memcpy(p, filename, filenamelen);
-       p += filenamelen;
-       if (isdir)
-               *p++ = '/';
-       *p = '\0';
-
-       *pathlen = len;
-
-       return path;
-}
-
-static int write_zip_entry(const unsigned char *sha1,
-                           const char *base, int baselen,
-                           const char *filename, unsigned mode, int stage)
+static int write_zip_entry(struct archiver_args *args,
+               const unsigned char *sha1, const char *path, size_t pathlen,
+               unsigned int mode, void *buffer, unsigned long size)
 {
        struct zip_local_header header;
        struct zip_dir_header dirent;
@@ -163,33 +136,20 @@ static int write_zip_entry(const unsigned char *sha1,
        unsigned long uncompressed_size;
        unsigned long crc;
        unsigned long direntsize;
-       unsigned long size;
        int method;
-       int result = -1;
-       int pathlen;
        unsigned char *out;
-       char *path;
-       enum object_type type;
-       void *buffer = NULL;
        void *deflated = NULL;
 
        crc = crc32(0, NULL, 0);
 
-       path = construct_path(base, baselen, filename, S_ISDIR(mode), &pathlen);
-       if (is_archive_path_ignored(path + base_len))
-               return 0;
-       if (verbose)
-               fprintf(stderr, "%s\n", path);
        if (pathlen > 0xffff) {
-               error("path too long (%d chars, SHA1: %s): %s", pathlen,
-                     sha1_to_hex(sha1), path);
-               goto out;
+               return error("path too long (%d chars, SHA1: %s): %s",
+                               (int)pathlen, sha1_to_hex(sha1), path);
        }
 
        if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
                method = 0;
                attr2 = 16;
-               result = (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
                out = NULL;
                uncompressed_size = 0;
                compressed_size = 0;
@@ -199,19 +159,13 @@ static int write_zip_entry(const unsigned char *sha1,
                        (mode & 0111) ? ((mode) << 16) : 0;
                if (S_ISREG(mode) && zlib_compression_level != 0)
                        method = 8;
-               result = 0;
-               buffer = sha1_file_to_archive(path + base_len, sha1, mode,
-                               &type, &size, commit);
-               if (!buffer)
-                       die("cannot read %s", sha1_to_hex(sha1));
                crc = crc32(crc, buffer, size);
                out = buffer;
                uncompressed_size = size;
                compressed_size = size;
        } else {
-               error("unsupported file mode: 0%o (SHA1: %s)", mode,
-                     sha1_to_hex(sha1));
-               goto out;
+               return error("unsupported file mode: 0%o (SHA1: %s)", mode,
+                               sha1_to_hex(sha1));
        }
 
        if (method == 8) {
@@ -278,12 +232,9 @@ static int write_zip_entry(const unsigned char *sha1,
                zip_offset += compressed_size;
        }
 
-out:
-       free(buffer);
        free(deflated);
-       free(path);
 
-       return result;
+       return 0;
 }
 
 static void write_zip_trailer(const unsigned char *sha1)
@@ -316,43 +267,18 @@ static void dos_time(time_t *time, int *dos_date, int *dos_time)
 
 int write_zip_archive(struct archiver_args *args)
 {
-       int plen = strlen(args->base);
+       int err;
 
        dos_time(&args->time, &zip_date, &zip_time);
 
        zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE);
        zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
-       verbose = args->verbose;
-       commit = args->commit;
-       base_len = args->base ? strlen(args->base) : 0;
-
-       if (args->base && plen > 0 && args->base[plen - 1] == '/') {
-               char *base = xstrdup(args->base);
-               int baselen = strlen(base);
-
-               while (baselen > 0 && base[baselen - 1] == '/')
-                       base[--baselen] = '\0';
-               write_zip_entry(args->tree->object.sha1, "", 0, base, 040777, 0);
-               free(base);
-       }
-       read_tree_recursive(args->tree, args->base, plen, 0,
-                           args->pathspec, write_zip_entry);
-       write_zip_trailer(args->commit_sha1);
-
-       free(zip_dir);
 
-       return 0;
-}
+       err = write_archive_entries(args, write_zip_entry);
+       if (!err)
+               write_zip_trailer(args->commit_sha1);
 
-void *parse_extra_zip_args(int argc, const char **argv)
-{
-       for (; argc > 0; argc--, argv++) {
-               const char *arg = argv[0];
+       free(zip_dir);
 
-               if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0')
-                       zlib_compression_level = arg[1] - '0';
-               else
-                       die("Unknown argument for zip format: %s", arg);
-       }
-       return NULL;
+       return err;
 }
index 6502b76ef10a182e9d9f0e60ad926c55a31a737a..b8b45bad77230b0258622e993dbbac3a20e3716c 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "commit.h"
 #include "attr.h"
+#include "archive.h"
 
 static void format_subst(const struct commit *commit,
                          const char *src, size_t len,
@@ -35,34 +36,9 @@ static void format_subst(const struct commit *commit,
        free(to_free);
 }
 
-static int convert_to_archive(const char *path,
-                              const void *src, size_t len,
-                              struct strbuf *buf,
-                              const struct commit *commit)
-{
-       static struct git_attr *attr_export_subst;
-       struct git_attr_check check[1];
-
-       if (!commit)
-               return 0;
-
-       if (!attr_export_subst)
-               attr_export_subst = git_attr("export-subst", 12);
-
-       check[0].attr = attr_export_subst;
-       if (git_checkattr(path, ARRAY_SIZE(check), check))
-               return 0;
-       if (!ATTR_TRUE(check[0].value))
-               return 0;
-
-       format_subst(commit, src, len, buf);
-       return 1;
-}
-
-void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
-                           unsigned int mode, enum object_type *type,
-                           unsigned long *sizep,
-                           const struct commit *commit)
+static void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
+               unsigned int mode, enum object_type *type,
+               unsigned long *sizep, const struct commit *commit)
 {
        void *buffer;
 
@@ -74,7 +50,8 @@ void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
                strbuf_init(&buf, 0);
                strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
                convert_to_working_tree(path, buf.buf, buf.len, &buf);
-               convert_to_archive(path, buf.buf, buf.len, &buf, commit);
+               if (commit)
+                       format_subst(commit, buf.buf, buf.len, &buf);
                buffer = strbuf_detach(&buf, &size);
                *sizep = size;
        }
@@ -82,16 +59,99 @@ void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
        return buffer;
 }
 
-int is_archive_path_ignored(const char *path)
+static void setup_archive_check(struct git_attr_check *check)
 {
        static struct git_attr *attr_export_ignore;
-       struct git_attr_check check[1];
+       static struct git_attr *attr_export_subst;
 
-       if (!attr_export_ignore)
+       if (!attr_export_ignore) {
                attr_export_ignore = git_attr("export-ignore", 13);
-
+               attr_export_subst = git_attr("export-subst", 12);
+       }
        check[0].attr = attr_export_ignore;
-       if (git_checkattr(path, ARRAY_SIZE(check), check))
-               return 0;
-       return ATTR_TRUE(check[0].value);
+       check[1].attr = attr_export_subst;
+}
+
+struct archiver_context {
+       struct archiver_args *args;
+       write_archive_entry_fn_t write_entry;
+};
+
+static int write_archive_entry(const unsigned char *sha1, const char *base,
+               int baselen, const char *filename, unsigned mode, int stage,
+               void *context)
+{
+       static struct strbuf path = STRBUF_INIT;
+       struct archiver_context *c = context;
+       struct archiver_args *args = c->args;
+       write_archive_entry_fn_t write_entry = c->write_entry;
+       struct git_attr_check check[2];
+       const char *path_without_prefix;
+       int convert = 0;
+       int err;
+       enum object_type type;
+       unsigned long size;
+       void *buffer;
+
+       strbuf_reset(&path);
+       strbuf_grow(&path, PATH_MAX);
+       strbuf_add(&path, base, baselen);
+       strbuf_addstr(&path, filename);
+       path_without_prefix = path.buf + args->baselen;
+
+       setup_archive_check(check);
+       if (!git_checkattr(path_without_prefix, ARRAY_SIZE(check), check)) {
+               if (ATTR_TRUE(check[0].value))
+                       return 0;
+               convert = ATTR_TRUE(check[1].value);
+       }
+
+       if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
+               strbuf_addch(&path, '/');
+               if (args->verbose)
+                       fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
+               err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0);
+               if (err)
+                       return err;
+               return READ_TREE_RECURSIVE;
+       }
+
+       buffer = sha1_file_to_archive(path_without_prefix, sha1, mode,
+                       &type, &size, convert ? args->commit : NULL);
+       if (!buffer)
+               return error("cannot read %s", sha1_to_hex(sha1));
+       if (args->verbose)
+               fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
+       err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size);
+       free(buffer);
+       return err;
+}
+
+int write_archive_entries(struct archiver_args *args,
+               write_archive_entry_fn_t write_entry)
+{
+       struct archiver_context context;
+       int err;
+
+       if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
+               size_t len = args->baselen;
+
+               while (len > 1 && args->base[len - 2] == '/')
+                       len--;
+               if (args->verbose)
+                       fprintf(stderr, "%.*s\n", (int)len, args->base);
+               err = write_entry(args, args->tree->object.sha1, args->base,
+                               len, 040777, NULL, 0);
+               if (err)
+                       return err;
+       }
+
+       context.args = args;
+       context.write_entry = write_entry;
+
+       err =  read_tree_recursive(args->tree, args->base, args->baselen, 0,
+                       args->pathspec, write_archive_entry, &context);
+       if (err == READ_TREE_RECURSIVE)
+               err = 0;
+       return err;
 }
index ddf004acdfa2125a73df11e923eda902d3ca8277..96bb1cd85362e68ee42c81d5017222411e6bf669 100644 (file)
--- a/archive.h
+++ b/archive.h
@@ -6,29 +6,26 @@
 
 struct archiver_args {
        const char *base;
+       size_t baselen;
        struct tree *tree;
        const unsigned char *commit_sha1;
        const struct commit *commit;
        time_t time;
        const char **pathspec;
        unsigned int verbose : 1;
-       void *extra;
 };
 
 typedef int (*write_archive_fn_t)(struct archiver_args *);
 
-typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv);
+typedef int (*write_archive_entry_fn_t)(struct archiver_args *args, const unsigned char *sha1, const char *path, size_t pathlen, unsigned int mode, void *buffer, unsigned long size);
 
 struct archiver {
        const char *name;
-       struct archiver_args args;
        write_archive_fn_t write_archive;
-       parse_extra_args_fn_t parse_extra;
+       unsigned int flags;
 };
 
-extern int parse_archive_args(int argc,
-                             const char **argv,
-                             struct archiver *ar);
+extern int parse_archive_args(int argc, const char **argv, const struct archiver **ar, struct archiver_args *args);
 
 extern void parse_treeish_arg(const char **treeish,
                              struct archiver_args *ar_args,
@@ -41,9 +38,7 @@ extern void parse_pathspec_arg(const char **pathspec,
  */
 extern int write_tar_archive(struct archiver_args *);
 extern int write_zip_archive(struct archiver_args *);
-extern void *parse_extra_zip_args(int argc, const char **argv);
 
-extern void *sha1_file_to_archive(const char *path, const unsigned char *sha1, unsigned int mode, enum object_type *type, unsigned long *size, const struct commit *commit);
-extern int is_archive_path_ignored(const char *path);
+extern int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
 
 #endif /* ARCHIVE_H */
index c2e0c1ea5a676f30baa52151d9e6a2a94d4cd091..88204bf733ebdba79b1ac175da8ec26f6cfec597 100644 (file)
 static const char archive_usage[] = \
 "git-archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]";
 
-static struct archiver_desc
-{
-       const char *name;
-       write_archive_fn_t write_archive;
-       parse_extra_args_fn_t parse_extra;
-} archivers[] = {
-       { "tar", write_tar_archive, NULL },
-       { "zip", write_zip_archive, parse_extra_zip_args },
+#define USES_ZLIB_COMPRESSION 1
+
+const struct archiver archivers[] = {
+       { "tar", write_tar_archive },
+       { "zip", write_zip_archive, USES_ZLIB_COMPRESSION },
 };
 
 static int run_remote_archiver(const char *remote, int argc,
@@ -79,21 +76,15 @@ static int run_remote_archiver(const char *remote, int argc,
        return !!rv;
 }
 
-static int init_archiver(const char *name, struct archiver *ar)
+static const struct archiver *lookup_archiver(const char *name)
 {
-       int rv = -1, i;
+       int i;
 
        for (i = 0; i < ARRAY_SIZE(archivers); i++) {
-               if (!strcmp(name, archivers[i].name)) {
-                       memset(ar, 0, sizeof(*ar));
-                       ar->name = archivers[i].name;
-                       ar->write_archive = archivers[i].write_archive;
-                       ar->parse_extra = archivers[i].parse_extra;
-                       rv = 0;
-                       break;
-               }
+               if (!strcmp(name, archivers[i].name))
+                       return &archivers[i];
        }
-       return rv;
+       return NULL;
 }
 
 void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args)
@@ -145,12 +136,12 @@ void parse_treeish_arg(const char **argv, struct archiver_args *ar_args,
        ar_args->time = archive_time;
 }
 
-int parse_archive_args(int argc, const char **argv, struct archiver *ar)
+int parse_archive_args(int argc, const char **argv, const struct archiver **ar,
+               struct archiver_args *args)
 {
-       const char *extra_argv[MAX_EXTRA_ARGS];
-       int extra_argc = 0;
        const char *format = "tar";
        const char *base = "";
+       int compression_level = -1;
        int verbose = 0;
        int i;
 
@@ -178,29 +169,33 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
                        i++;
                        break;
                }
-               if (arg[0] == '-') {
-                       if (extra_argc > MAX_EXTRA_ARGS - 1)
-                               die("Too many extra options");
-                       extra_argv[extra_argc++] = arg;
+               if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0') {
+                       compression_level = arg[1] - '0';
                        continue;
                }
+               if (arg[0] == '-')
+                       die("Unknown argument: %s", arg);
                break;
        }
 
        /* We need at least one parameter -- tree-ish */
        if (argc - 1 < i)
                usage(archive_usage);
-       if (init_archiver(format, ar) < 0)
+       *ar = lookup_archiver(format);
+       if (!*ar)
                die("Unknown archive format '%s'", format);
 
-       if (extra_argc) {
-               if (!ar->parse_extra)
-                       die("'%s' format does not handle %s",
-                           ar->name, extra_argv[0]);
-               ar->args.extra = ar->parse_extra(extra_argc, extra_argv);
+       if (compression_level != -1) {
+               if ((*ar)->flags & USES_ZLIB_COMPRESSION)
+                       zlib_compression_level = compression_level;
+               else {
+                       die("Argument not supported for format '%s': -%d",
+                                       format, compression_level);
+               }
        }
-       ar->args.verbose = verbose;
-       ar->args.base = base;
+       args->verbose = verbose;
+       args->base = base;
+       args->baselen = strlen(base);
 
        return i;
 }
@@ -238,7 +233,8 @@ static const char *extract_remote_arg(int *ac, const char **av)
 
 int cmd_archive(int argc, const char **argv, const char *prefix)
 {
-       struct archiver ar;
+       const struct archiver *ar = NULL;
+       struct archiver_args args;
        int tree_idx;
        const char *remote = NULL;
 
@@ -248,14 +244,13 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
 
        setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
 
-       memset(&ar, 0, sizeof(ar));
-       tree_idx = parse_archive_args(argc, argv, &ar);
+       tree_idx = parse_archive_args(argc, argv, &ar, &args);
        if (prefix == NULL)
                prefix = setup_git_directory();
 
        argv += tree_idx;
-       parse_treeish_arg(argv, &ar.args, prefix);
-       parse_pathspec_arg(argv + 1, &ar.args);
+       parse_treeish_arg(argv, &args, prefix);
+       parse_pathspec_arg(argv + 1, &args);
 
-       return ar.write_archive(&ar.args);
+       return ar->write_archive(&args);
 }
index d6641c2c562c6b35bfed1cd3053945b460472581..fbd5105a8302a6c00e191ef49f3dfef1fc979c53 100644 (file)
@@ -43,7 +43,7 @@ static int post_checkout_hook(struct commit *old, struct commit *new,
 }
 
 static int update_some(const unsigned char *sha1, const char *base, int baselen,
-                      const char *pathname, unsigned mode, int stage)
+               const char *pathname, unsigned mode, int stage, void *context)
 {
        int len;
        struct cache_entry *ce;
@@ -67,7 +67,7 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
 
 static int read_tree_some(struct tree *tree, const char **pathspec)
 {
-       read_tree_recursive(tree, "", 0, 0, pathspec, update_some);
+       read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL);
 
        /* update the index with the given tree's info
         * for all args, expanding wildcards, and exit
index 430d87661e37a4b08963de1ee5c31b8143ebc373..617aa67f2b2d1fd82c34eea62fd73145ff646ae0 100644 (file)
@@ -313,7 +313,7 @@ static int show_object(const unsigned char *sha1, int show_tag_object,
 
 static int show_tree_object(const unsigned char *sha1,
                const char *base, int baselen,
-               const char *pathname, unsigned mode, int stage)
+               const char *pathname, unsigned mode, int stage, void *context)
 {
        printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
        return 0;
@@ -366,7 +366,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
                                        name,
                                        diff_get_color_opt(&rev.diffopt, DIFF_RESET));
                        read_tree_recursive((struct tree *)o, "", 0, 0, NULL,
-                                       show_tree_object);
+                                       show_tree_object, NULL);
                        break;
                case OBJ_COMMIT:
                        rev.pending.nr = rev.pending.alloc = 0;
index f4a75ddbc3fecb9c1690a94d39ce230e82fefd8d..0da047c3bd40f4a7db43f70e2e00c0adcf673188 100644 (file)
@@ -56,7 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
 }
 
 static int show_tree(const unsigned char *sha1, const char *base, int baselen,
-                    const char *pathname, unsigned mode, int stage)
+               const char *pathname, unsigned mode, int stage, void *context)
 {
        int retval = 0;
        const char *type = blob_type;
@@ -189,7 +189,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
        tree = parse_tree_indirect(sha1);
        if (!tree)
                die("not a tree object");
-       read_tree_recursive(tree, "", 0, 0, pathspec, show_tree);
+       read_tree_recursive(tree, "", 0, 0, pathspec, show_tree, NULL);
 
        return 0;
 }
index 3731853f83be37d3790a5db8ef037af0b0a4f7c5..652a2c32bb0913108e0435de86392764da3ad611 100644 (file)
@@ -248,7 +248,7 @@ struct tree *write_tree_from_memory(void)
 
 static int save_files_dirs(const unsigned char *sha1,
                const char *base, int baselen, const char *path,
-               unsigned int mode, int stage)
+               unsigned int mode, int stage, void *context)
 {
        int len = strlen(path);
        char *newpath = xmalloc(baselen + len + 1);
@@ -268,7 +268,7 @@ static int save_files_dirs(const unsigned char *sha1,
 static int get_files_dirs(struct tree *tree)
 {
        int n;
-       if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs) != 0)
+       if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs, NULL))
                return 0;
        n = current_file_set.nr + current_directory_set.nr;
        return n;
index 371400d49a5ff9f6ce297d7af07eb3fd6426c9ee..295e24c2fa95f6e59380024ca757ad8dec80688f 100644 (file)
@@ -19,7 +19,8 @@ static const char lostchild[] =
 
 static int run_upload_archive(int argc, const char **argv, const char *prefix)
 {
-       struct archiver ar;
+       const struct archiver *ar;
+       struct archiver_args args;
        const char *sent_argv[MAX_ARGS];
        const char *arg_cmd = "argument ";
        char *p, buf[4096];
@@ -65,12 +66,12 @@ static int run_upload_archive(int argc, const char **argv, const char *prefix)
        sent_argv[sent_argc] = NULL;
 
        /* parse all options sent by the client */
-       treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar);
+       treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar, &args);
 
-       parse_treeish_arg(sent_argv + treeish_idx, &ar.args, prefix);
-       parse_pathspec_arg(sent_argv + treeish_idx + 1, &ar.args);
+       parse_treeish_arg(sent_argv + treeish_idx, &args, prefix);
+       parse_pathspec_arg(sent_argv + treeish_idx + 1, &args);
 
-       return ar.write_archive(&ar.args);
+       return ar->write_archive(&args);
 }
 
 static void error_clnt(const char *fmt, ...)
diff --git a/tree.c b/tree.c
index 4b1825c2adac94ad806d729862c90cf8dfa37e9a..03e782a9cabc0a12ed5baec0ef59c99f19dbc843 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -29,7 +29,7 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b
        return add_cache_entry(ce, opt);
 }
 
-static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
+static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
 {
        return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
                                  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
@@ -39,7 +39,7 @@ static int read_one_entry(const unsigned char *sha1, const char *base, int basel
  * This is used when the caller knows there is no existing entries at
  * the stage that will conflict with the entry being added.
  */
-static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
+static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
 {
        return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
                                  ADD_CACHE_JUST_APPEND);
@@ -92,7 +92,7 @@ static int match_tree_entry(const char *base, int baselen, const char *path, uns
 int read_tree_recursive(struct tree *tree,
                        const char *base, int baselen,
                        int stage, const char **match,
-                       read_tree_fn_t fn)
+                       read_tree_fn_t fn, void *context)
 {
        struct tree_desc desc;
        struct name_entry entry;
@@ -106,7 +106,7 @@ int read_tree_recursive(struct tree *tree,
                if (!match_tree_entry(base, baselen, entry.path, entry.mode, match))
                        continue;
 
-               switch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage)) {
+               switch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage, context)) {
                case 0:
                        continue;
                case READ_TREE_RECURSIVE:
@@ -126,7 +126,7 @@ int read_tree_recursive(struct tree *tree,
                        retval = read_tree_recursive(lookup_tree(entry.sha1),
                                                     newbase,
                                                     baselen + pathlen + 1,
-                                                    stage, match, fn);
+                                                    stage, match, fn, context);
                        free(newbase);
                        if (retval)
                                return -1;
@@ -174,7 +174,7 @@ int read_tree(struct tree *tree, int stage, const char **match)
 
        if (!fn)
                fn = read_one_entry_quick;
-       err = read_tree_recursive(tree, "", 0, stage, match, fn);
+       err = read_tree_recursive(tree, "", 0, stage, match, fn, NULL);
        if (fn == read_one_entry || err)
                return err;
 
diff --git a/tree.h b/tree.h
index dd25c539efbb0ab018caa4cda2d133285634e9b5..2ff01a4f839ecc2206fcc1c13fee9d5d202b1128 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -21,12 +21,12 @@ int parse_tree(struct tree *tree);
 struct tree *parse_tree_indirect(const unsigned char *sha1);
 
 #define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int);
+typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
 
 extern int read_tree_recursive(struct tree *tree,
                               const char *base, int baselen,
                               int stage, const char **match,
-                              read_tree_fn_t fn);
+                              read_tree_fn_t fn, void *context);
 
 extern int read_tree(struct tree *tree, int stage, const char **paths);