git-archive: wire up TAR format.
authorFranck Bui-Huu <vagabon.xyz@gmail.com>
Thu, 7 Sep 2006 13:12:03 +0000 (15:12 +0200)
committerJunio C Hamano <junkio@cox.net>
Sat, 9 Sep 2006 18:57:37 +0000 (11:57 -0700)
This is based on Rene Scharfe's earlier patch, but uses the
archiver support introduced by the previous patch.

Signed-off-by: Franck Bui-Huu <vagabon.xyz@gmail.com>
Acked-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
Signed-off-by: Junio C Hamano <junkio@cox.net>
archive.h
builtin-archive.c
builtin-tar-tree.c

index 24b016f001117715999baf9eaa486164ba15567e..5c3f29b8df2722805c5009c99c64a39191f14fb1 100644 (file)
--- a/archive.h
+++ b/archive.h
@@ -37,5 +37,9 @@ extern void parse_treeish_arg(const char **treeish,
 
 extern void parse_pathspec_arg(const char **pathspec,
                               struct archiver_args *args);
+/*
+ * Archive-format specific backends.
+ */
+extern int write_tar_archive(struct archiver_args *);
 
 #endif /* ARCHIVE_H */
index f6bc269fdc7e79d601e18cdb53511e6139fb1b7b..c6423b9c48b4d84269343e30c790d5c82dc9cd83 100644 (file)
@@ -15,7 +15,7 @@ static const char archive_usage[] = \
 "git-archive --format=<fmt> [--prefix=<prefix>/] [<extra>] <tree-ish> [path...]";
 
 struct archiver archivers[] = {
-       { "" /* dummy */ },
+       { .name = "tar", .write_archive = write_tar_archive },
 };
 
 static int run_remote_archiver(struct archiver *ar, int argc,
index fa666f78c5b5e44617495abb2716eded8407626c..c20eb0e364d683ef03978851619a79cb7840c379 100644 (file)
@@ -9,6 +9,7 @@
 #include "tar.h"
 #include "builtin.h"
 #include "pkt-line.h"
+#include "archive.h"
 
 #define RECORDSIZE     (512)
 #define BLOCKSIZE      (RECORDSIZE * 20)
@@ -338,6 +339,72 @@ static int generate_tar(int argc, const char **argv, const char *prefix)
        return 0;
 }
 
+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;
+       int filenamelen = strlen(filename);
+       void *buffer;
+       char type[20];
+       unsigned long size;
+
+       if (!path.alloc) {
+               path.buf = xmalloc(PATH_MAX);
+               path.alloc = PATH_MAX;
+               path.len = path.eof = 0;
+       }
+       if (path.alloc < baselen + filenamelen) {
+               free(path.buf);
+               path.buf = xmalloc(baselen + filenamelen);
+               path.alloc = baselen + filenamelen;
+       }
+       memcpy(path.buf, base, baselen);
+       memcpy(path.buf + baselen, filename, filenamelen);
+       path.len = baselen + filenamelen;
+       if (S_ISDIR(mode)) {
+               strbuf_append_string(&path, "/");
+               buffer = NULL;
+               size = 0;
+       } else {
+               buffer = read_sha1_file(sha1, type, &size);
+               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 = strlen(args->base);
+
+       git_config(git_tar_config);
+
+       archive_time = args->time;
+
+       if (args->commit_sha1)
+               write_global_extended_header(args->commit_sha1);
+
+       if (args->base && plen > 0 && args->base[plen - 1] == '/') {
+               char *base = strdup(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;
+}
+
 static const char *exec = "git-upload-tar";
 
 static int remote_tar(int argc, const char **argv)