From 4df096a5ca24f2f39042c51cf51b8a2bec66a2b5 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 7 Sep 2006 15:12:02 +0200 Subject: [PATCH 1/5] Add git-archive git-archive is a command to make TAR and ZIP archives of a git tree. It helps prevent a proliferation of git-{format}-tree commands. Instead of directly calling git-{tar,zip}-tree command, it defines a very simple API, that archiver should implement and register in "git-archive.c". This API is made up by 2 functions whose prototype is defined in "archive.h" file. - The first one is used to parse 'extra' parameters which have signification only for the specific archiver. That would allow different archive backends to have different kind of options. - The second one is used to ask to an archive backend to build the archive given some already resolved parameters. The main reason for making this API is to avoid using git-{tar,zip}-tree commands, hence making them useless. Maybe it's time for them to die ? It also implements remote operations by defining a very simple protocol: it first sends the name of the specific uploader followed the repository name (git-upload-tar git://example.org/repo.git). Then it sends options. It's done by sending a sequence of one argument per packet, with prefix "argument ", followed by a flush. The remote protocol is implemented in "git-archive.c" for client side and is triggered by "--remote=" option. For example, to fetch a TAR archive in a remote repo, you can issue: $ git archive --format=tar --remote=git://xxx/yyy/zzz.git HEAD We choose to not make a new command "git-fetch-archive" for example, avoind one more GIT command which should be nice for users (less commands to remember, keeps existing --remote option). Signed-off-by: Franck Bui-Huu Acked-by: Rene Scharfe Signed-off-by: Junio C Hamano --- .gitignore | 1 + Documentation/git-archive.txt | 100 +++++++++++++++ Makefile | 3 +- archive.h | 41 ++++++ builtin-archive.c | 228 ++++++++++++++++++++++++++++++++++ builtin.h | 1 + generate-cmdlist.sh | 1 + git.c | 1 + 8 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 Documentation/git-archive.txt create mode 100644 archive.h create mode 100644 builtin-archive.c diff --git a/.gitignore b/.gitignore index 0d608fe12a..a3f33d4209 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ git-apply git-applymbox git-applypatch git-archimport +git-archive git-bisect git-branch git-cat-file diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt new file mode 100644 index 0000000000..913528d373 --- /dev/null +++ b/Documentation/git-archive.txt @@ -0,0 +1,100 @@ +git-archive(1) +============== + +NAME +---- +git-archive - Creates a archive of the files in the named tree + + +SYNOPSIS +-------- +'git-archive' --format= [--list] [--prefix=/] [] + [--remote=] [path...] + +DESCRIPTION +----------- +Creates an archive of the specified format containing the tree +structure for the named tree. If is specified it is +prepended to the filenames in the archive. + +'git-archive' behaves differently when given a tree ID versus when +given a commit ID or tag ID. In the first case the current time is +used as modification time of each file in the archive. In the latter +case the commit time as recorded in the referenced commit object is +used instead. Additionally the commit ID is stored in a global +extended pax header if the tar format is used; it can be extracted +using 'git-get-tar-commit-id'. In ZIP files it is stored as a file +comment. + +OPTIONS +------- + +--format=:: + Format of the resulting archive: 'tar', 'zip'... + +--list:: + Show all available formats. + +--prefix=/:: + Prepend / to each filename in the archive. + +:: + This can be any options that the archiver backend understand. + +--remote=:: + Instead of making a tar archive from local repository, + retrieve a tar archive from a remote repository. + +:: + The tree or commit to produce an archive for. + +path:: + If one or more paths are specified, include only these in the + archive, otherwise include all files and subdirectories. + +CONFIGURATION +------------- +By default, file and directories modes are set to 0666 or 0777 in tar +archives. It is possible to change this by setting the "umask" variable +in the repository configuration as follows : + +[tar] + umask = 002 ;# group friendly + +The special umask value "user" indicates that the user's current umask +will be used instead. The default value remains 0, which means world +readable/writable files and directories. + +EXAMPLES +-------- +git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -):: + + Create a tar archive that contains the contents of the + latest commit on the current branch, and extracts it in + `/var/tmp/junk` directory. + +git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip >git-1.4.0.tar.gz:: + + Create a compressed tarball for v1.4.0 release. + +git archive --format=tar --prefix=git-1.4.0/ v1.4.0{caret}\{tree\} | gzip >git-1.4.0.tar.gz:: + + Create a compressed tarball for v1.4.0 release, but without a + global extended pax header. + +git archive --format=zip --prefix=git-docs/ HEAD:Documentation/ > git-1.4.0-docs.zip:: + + Put everything in the current head's Documentation/ directory + into 'git-1.4.0-docs.zip', with the prefix 'git-docs/'. + +Author +------ +Written by Franck Bui-Huu and Rene Scharfe. + +Documentation +-------------- +Documentation by David Greaves, Junio C Hamano and the git-list . + +GIT +--- +Part of the gitlink:git[7] suite diff --git a/Makefile b/Makefile index 7b3114f3aa..8f62ceffaf 100644 --- a/Makefile +++ b/Makefile @@ -232,7 +232,7 @@ LIB_FILE=libgit.a XDIFF_LIB=xdiff/lib.a LIB_H = \ - blob.h cache.h commit.h csum-file.h delta.h \ + archive.h blob.h cache.h commit.h csum-file.h delta.h \ diff.h object.h pack.h pkt-line.h quote.h refs.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h @@ -256,6 +256,7 @@ LIB_OBJS = \ BUILTIN_OBJS = \ builtin-add.o \ builtin-apply.o \ + builtin-archive.o \ builtin-cat-file.o \ builtin-checkout-index.o \ builtin-check-ref-format.o \ diff --git a/archive.h b/archive.h new file mode 100644 index 0000000000..24b016f001 --- /dev/null +++ b/archive.h @@ -0,0 +1,41 @@ +#ifndef ARCHIVE_H +#define ARCHIVE_H + +#define MAX_EXTRA_ARGS 32 +#define MAX_ARGS (MAX_EXTRA_ARGS + 32) + +struct archiver_args { + const char *base; + struct tree *tree; + const unsigned char *commit_sha1; + time_t time; + const char **pathspec; + void *extra; +}; + +typedef int (*write_archive_fn_t)(struct archiver_args *); + +typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv); + +struct archiver { + const char *name; + const char *remote; + struct archiver_args args; + write_archive_fn_t write_archive; + parse_extra_args_fn_t parse_extra; +}; + +extern struct archiver archivers[]; + +extern int parse_archive_args(int argc, + const char **argv, + struct archiver *ar); + +extern void parse_treeish_arg(const char **treeish, + struct archiver_args *ar_args, + const char *prefix); + +extern void parse_pathspec_arg(const char **pathspec, + struct archiver_args *args); + +#endif /* ARCHIVE_H */ diff --git a/builtin-archive.c b/builtin-archive.c new file mode 100644 index 0000000000..f6bc269fdc --- /dev/null +++ b/builtin-archive.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2006 Franck Bui-Huu + * Copyright (c) 2006 Rene Scharfe + */ +#include +#include "cache.h" +#include "builtin.h" +#include "archive.h" +#include "commit.h" +#include "tree-walk.h" +#include "exec_cmd.h" +#include "pkt-line.h" + +static const char archive_usage[] = \ +"git-archive --format= [--prefix=/] [] [path...]"; + +struct archiver archivers[] = { + { "" /* dummy */ }, +}; + +static int run_remote_archiver(struct archiver *ar, int argc, + const char **argv) +{ + char *url, buf[1024]; + int fd[2], i, len, rv; + pid_t pid; + + sprintf(buf, "git-upload-archive"); + + url = xstrdup(ar->remote); + pid = git_connect(fd, url, buf); + if (pid < 0) + return pid; + + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "--remote=", 9)) + continue; + packet_write(fd[1], "argument %s\n", argv[i]); + } + packet_flush(fd[1]); + + len = packet_read_line(fd[0], buf, sizeof(buf)); + if (!len) + die("git-archive: expected ACK/NAK, got EOF"); + if (buf[len-1] == '\n') + buf[--len] = 0; + if (strcmp(buf, "ACK")) { + if (len > 5 && !strncmp(buf, "NACK ", 5)) + die("git-archive: NACK %s", buf + 5); + die("git-archive: protocol error"); + } + + len = packet_read_line(fd[0], buf, sizeof(buf)); + if (len) + die("git-archive: expected a flush"); + + /* Now, start reading from fd[0] and spit it out to stdout */ + rv = copy_fd(fd[0], 1); + + close(fd[0]); + rv |= finish_connect(pid); + + return !!rv; +} + +static int init_archiver(const char *name, struct archiver *ar) +{ + int rv = -1, i; + + for (i = 0; i < ARRAY_SIZE(archivers); i++) { + if (!strcmp(name, archivers[i].name)) { + memcpy(ar, &archivers[i], sizeof(struct archiver)); + rv = 0; + break; + } + } + return rv; +} + +void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args) +{ + ar_args->pathspec = get_pathspec(ar_args->base, pathspec); +} + +void parse_treeish_arg(const char **argv, struct archiver_args *ar_args, + const char *prefix) +{ + const char *name = argv[0]; + const unsigned char *commit_sha1; + time_t archive_time; + struct tree *tree; + struct commit *commit; + unsigned char sha1[20]; + + if (get_sha1(name, sha1)) + die("Not a valid object name"); + + commit = lookup_commit_reference_gently(sha1, 1); + if (commit) { + commit_sha1 = commit->object.sha1; + archive_time = commit->date; + } else { + commit_sha1 = NULL; + archive_time = time(NULL); + } + + tree = parse_tree_indirect(sha1); + if (tree == NULL) + die("not a tree object"); + + if (prefix) { + unsigned char tree_sha1[20]; + unsigned int mode; + int err; + + err = get_tree_entry(tree->object.sha1, prefix, + tree_sha1, &mode); + if (err || !S_ISDIR(mode)) + die("current working directory is untracked"); + + free(tree); + tree = parse_tree_indirect(tree_sha1); + } + ar_args->tree = tree; + ar_args->commit_sha1 = commit_sha1; + ar_args->time = archive_time; +} + +static const char *default_parse_extra(struct archiver *ar, + const char **argv) +{ + static char msg[64]; + + snprintf(msg, sizeof(msg) - 4, "'%s' format does not handle %s", + ar->name, *argv); + + return strcat(msg, "..."); +} + +int parse_archive_args(int argc, const char **argv, struct archiver *ar) +{ + const char *extra_argv[MAX_EXTRA_ARGS]; + int extra_argc = 0; + const char *format = NULL; /* might want to default to "tar" */ + const char *remote = NULL; + const char *base = ""; + int list = 0; + int i; + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + + if (!strcmp(arg, "--list") || !strcmp(arg, "-l")) { + list = 1; + continue; + } + if (!strncmp(arg, "--format=", 9)) { + format = arg + 9; + continue; + } + if (!strncmp(arg, "--prefix=", 9)) { + base = arg + 9; + continue; + } + if (!strncmp(arg, "--remote=", 9)) { + remote = arg + 9; + continue; + } + if (!strcmp(arg, "--")) { + i++; + break; + } + if (arg[0] == '-') { + if (extra_argc > MAX_EXTRA_ARGS - 1) + die("Too many extra options"); + extra_argv[extra_argc++] = arg; + continue; + } + break; + } + + if (list) { + if (!remote) { + for (i = 0; i < ARRAY_SIZE(archivers); i++) + printf("%s\n", archivers[i].name); + exit(0); + } + die("--list and --remote are mutually exclusive"); + } + + if (argc - i < 1) + usage(archive_usage); + if (!format) + die("You must specify an archive format"); + if (init_archiver(format, ar) < 0) + die("Unknown archive format '%s'", format); + + if (extra_argc && !remote) { + if (!ar->parse_extra) { + die("%s", default_parse_extra(ar, extra_argv)); + } + ar->args.extra = ar->parse_extra(extra_argc, extra_argv); + } + ar->remote = remote; + ar->args.base = base; + + return i; +} + +int cmd_archive(int argc, const char **argv, const char *prefix) +{ + struct archiver ar; + int tree_idx; + + tree_idx = parse_archive_args(argc, argv, &ar); + + if (ar.remote) + return run_remote_archiver(&ar, argc, argv); + + if (prefix == NULL) + prefix = setup_git_directory(); + + argv += tree_idx; + parse_treeish_arg(argv, &ar.args, prefix); + parse_pathspec_arg(argv + 1, &ar.args); + + return ar.write_archive(&ar.args); +} diff --git a/builtin.h b/builtin.h index 25431d7081..50852cd6a9 100644 --- a/builtin.h +++ b/builtin.h @@ -15,6 +15,7 @@ extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix); extern int cmd_add(int argc, const char **argv, const char *prefix); extern int cmd_apply(int argc, const char **argv, const char *prefix); +extern int cmd_archive(int argc, const char **argv, const char *prefix); extern int cmd_cat_file(int argc, const char **argv, const char *prefix); extern int cmd_checkout_index(int argc, const char **argv, const char *prefix); extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix); diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh index ec1eda20de..5450918be3 100755 --- a/generate-cmdlist.sh +++ b/generate-cmdlist.sh @@ -12,6 +12,7 @@ struct cmdname_help common_cmds[] = {" sort <<\EOF | add apply +archive bisect branch checkout diff --git a/git.c b/git.c index 335f405c20..8c64b2753f 100644 --- a/git.c +++ b/git.c @@ -220,6 +220,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) } commands[] = { { "add", cmd_add, RUN_SETUP }, { "apply", cmd_apply }, + { "archive", cmd_archive }, { "cat-file", cmd_cat_file, RUN_SETUP }, { "checkout-index", cmd_checkout_index, RUN_SETUP }, { "check-ref-format", cmd_check_ref_format }, From efd8696cd7ccfa5042ef710e89fe0d10efdcd085 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 7 Sep 2006 15:12:03 +0200 Subject: [PATCH 2/5] git-archive: wire up TAR format. 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 Acked-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive.h | 4 +++ builtin-archive.c | 2 +- builtin-tar-tree.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/archive.h b/archive.h index 24b016f001..5c3f29b8df 100644 --- 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 */ diff --git a/builtin-archive.c b/builtin-archive.c index f6bc269fdc..c6423b9c48 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -15,7 +15,7 @@ static const char archive_usage[] = \ "git-archive --format= [--prefix=/] [] [path...]"; struct archiver archivers[] = { - { "" /* dummy */ }, + { .name = "tar", .write_archive = write_tar_archive }, }; static int run_remote_archiver(struct archiver *ar, int argc, diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index fa666f78c5..c20eb0e364 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -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) From ec06bff5e6f76b46c22a3b2c97452568f088fa3c Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 7 Sep 2006 15:12:04 +0200 Subject: [PATCH 3/5] git-archive: wire up ZIP format. Again, 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 Acked-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive.h | 1 + builtin-archive.c | 1 + builtin-zip-tree.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/archive.h b/archive.h index 5c3f29b8df..f3d344b652 100644 --- a/archive.h +++ b/archive.h @@ -41,5 +41,6 @@ extern void parse_pathspec_arg(const char **pathspec, * Archive-format specific backends. */ extern int write_tar_archive(struct archiver_args *); +extern int write_zip_archive(struct archiver_args *); #endif /* ARCHIVE_H */ diff --git a/builtin-archive.c b/builtin-archive.c index c6423b9c48..651d1bf6d9 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -16,6 +16,7 @@ static const char archive_usage[] = \ struct archiver archivers[] = { { .name = "tar", .write_archive = write_tar_archive }, + { .name = "zip", .write_archive = write_zip_archive }, }; static int run_remote_archiver(struct archiver *ar, int argc, diff --git a/builtin-zip-tree.c b/builtin-zip-tree.c index 1c1f6830c1..3afb7bde74 100644 --- a/builtin-zip-tree.c +++ b/builtin-zip-tree.c @@ -8,6 +8,7 @@ #include "tree.h" #include "quote.h" #include "builtin.h" +#include "archive.h" static const char zip_tree_usage[] = "git-zip-tree [-0|...|-9] [ ]"; @@ -351,3 +352,30 @@ int cmd_zip_tree(int argc, const char **argv, const char *prefix) return 0; } + +int write_zip_archive(struct archiver_args *args) +{ + int plen = strlen(args->base); + + dos_time(&args->time, &zip_date, &zip_time); + + zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE); + zip_dir_size = ZIP_DIRECTORY_MIN_SIZE; + + 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_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; +} From 39345a216ff37bda9fb7cec85f6de44069f5205d Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 7 Sep 2006 15:12:05 +0200 Subject: [PATCH 4/5] Add git-upload-archive This command implements the git archive protocol on the server side. This command is not intended to be used by the end user. Underlying git-archive command line options are sent over the protocol from "git-archive --remote=...", just like upload-tar currently does with "git-tar-tree=...". As for "git-archive" command implementation, this new command does not execute any existing "git-{tar,zip}-tree" but rely on the archive API defined by "git-archive" patch. Hence we get 2 good points: - "git-archive" and "git-upload-archive" share all option parsing code. - All kind of git-upload-{tar,zip} can be deprecated. Signed-off-by: Franck Bui-Huu Signed-off-by: Junio C Hamano --- .gitignore | 1 + Documentation/git-upload-archive.txt | 37 ++++++++++++++ Makefile | 1 + builtin-upload-archive.c | 72 ++++++++++++++++++++++++++++ builtin.h | 1 + daemon.c | 7 +++ git.c | 1 + 7 files changed, 120 insertions(+) create mode 100644 Documentation/git-upload-archive.txt create mode 100644 builtin-upload-archive.c diff --git a/.gitignore b/.gitignore index a3f33d4209..90d6d7c667 100644 --- a/.gitignore +++ b/.gitignore @@ -119,6 +119,7 @@ git-unpack-objects git-update-index git-update-ref git-update-server-info +git-upload-archive git-upload-pack git-upload-tar git-var diff --git a/Documentation/git-upload-archive.txt b/Documentation/git-upload-archive.txt new file mode 100644 index 0000000000..388bb53d29 --- /dev/null +++ b/Documentation/git-upload-archive.txt @@ -0,0 +1,37 @@ +git-upload-archive(1) +==================== + +NAME +---- +git-upload-archive - Send archive + + +SYNOPSIS +-------- +'git-upload-archive' + +DESCRIPTION +----------- +Invoked by 'git-archive --remote' and sends a generated archive to the +other end over the git protocol. + +This command is usually not invoked directly by the end user. The UI +for the protocol is on the 'git-archive' side, and the program pair +is meant to be used to get an archive from a remote repository. + +OPTIONS +------- +:: + The repository to get a tar archive from. + +Author +------ +Written by Franck Bui-Huu. + +Documentation +-------------- +Documentation by Junio C Hamano and the git-list . + +GIT +--- +Part of the gitlink:git[7] suite diff --git a/Makefile b/Makefile index 8f62ceffaf..4ac85fdc7b 100644 --- a/Makefile +++ b/Makefile @@ -293,6 +293,7 @@ BUILTIN_OBJS = \ builtin-unpack-objects.o \ builtin-update-index.o \ builtin-update-ref.o \ + builtin-upload-archive.o \ builtin-upload-tar.o \ builtin-verify-pack.o \ builtin-write-tree.o \ diff --git a/builtin-upload-archive.c b/builtin-upload-archive.c new file mode 100644 index 0000000000..3bdb607e37 --- /dev/null +++ b/builtin-upload-archive.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006 Franck Bui-Huu + */ +#include +#include "cache.h" +#include "builtin.h" +#include "archive.h" +#include "pkt-line.h" + +static const char upload_archive_usage[] = + "git-upload-archive "; + + +int cmd_upload_archive(int argc, const char **argv, const char *prefix) +{ + struct archiver ar; + const char *sent_argv[MAX_ARGS]; + const char *arg_cmd = "argument "; + char *p, buf[4096]; + int treeish_idx; + int sent_argc; + int len; + + if (argc != 2) + usage(upload_archive_usage); + + if (strlen(argv[1]) > sizeof(buf)) + die("insanely long repository name"); + + strcpy(buf, argv[1]); /* enter-repo smudges its argument */ + + if (!enter_repo(buf, 0)) + die("not a git archive"); + + /* put received options in sent_argv[] */ + sent_argc = 1; + sent_argv[0] = "git-upload-archive"; + for (p = buf;;) { + /* This will die if not enough free space in buf */ + len = packet_read_line(0, p, (buf + sizeof buf) - p); + if (len == 0) + break; /* got a flush */ + if (sent_argc > MAX_ARGS - 2) + die("Too many options (>29)"); + + if (p[len-1] == '\n') { + p[--len] = 0; + } + if (len < strlen(arg_cmd) || + strncmp(arg_cmd, p, strlen(arg_cmd))) + die("'argument' token or flush expected"); + + len -= strlen(arg_cmd); + memmove(p, p + strlen(arg_cmd), len); + sent_argv[sent_argc++] = p; + p += len; + *p++ = 0; + } + sent_argv[sent_argc] = NULL; + + /* parse all options sent by the client */ + treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar); + + parse_treeish_arg(sent_argv + treeish_idx, &ar.args, prefix); + parse_pathspec_arg(sent_argv + treeish_idx + 1, &ar.args); + + packet_write(1, "ACK\n"); + packet_flush(1); + + return ar.write_archive(&ar.args); +} + diff --git a/builtin.h b/builtin.h index 50852cd6a9..6bfd2e79f5 100644 --- a/builtin.h +++ b/builtin.h @@ -57,6 +57,7 @@ extern int cmd_zip_tree(int argc, const char **argv, const char *prefix); extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix); extern int cmd_update_index(int argc, const char **argv, const char *prefix); extern int cmd_update_ref(int argc, const char **argv, const char *prefix); +extern int cmd_upload_archive(int argc, const char **argv, const char *prefix); extern int cmd_upload_tar(int argc, const char **argv, const char *prefix); extern int cmd_version(int argc, const char **argv, const char *prefix); extern int cmd_whatchanged(int argc, const char **argv, const char *prefix); diff --git a/daemon.c b/daemon.c index b14d8083bb..a2954a0451 100644 --- a/daemon.c +++ b/daemon.c @@ -325,7 +325,14 @@ static int upload_pack(void) return -1; } +static int upload_archive(void) +{ + execl_git_cmd("upload-archive", ".", NULL); + return -1; +} + static struct daemon_service daemon_service[] = { + { "upload-archive", "uploadarch", upload_archive, 0, 1 }, { "upload-pack", "uploadpack", upload_pack, 1, 1 }, }; diff --git a/git.c b/git.c index 8c64b2753f..bcf3fc8444 100644 --- a/git.c +++ b/git.c @@ -262,6 +262,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "unpack-objects", cmd_unpack_objects, RUN_SETUP }, { "update-index", cmd_update_index, RUN_SETUP }, { "update-ref", cmd_update_ref, RUN_SETUP }, + { "upload-archive", cmd_upload_archive }, { "upload-tar", cmd_upload_tar }, { "version", cmd_version }, { "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER }, From 854c4168e77a692dc198311f04bf31939355f2a3 Mon Sep 17 00:00:00 2001 From: Rene Scharfe Date: Sat, 9 Sep 2006 17:02:38 +0200 Subject: [PATCH 5/5] git-archive: make compression level of ZIP archives configurable Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive.h | 1 + builtin-archive.c | 11 +++++++++-- builtin-zip-tree.c | 13 +++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/archive.h b/archive.h index f3d344b652..d8cca735d2 100644 --- a/archive.h +++ b/archive.h @@ -42,5 +42,6 @@ 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); #endif /* ARCHIVE_H */ diff --git a/builtin-archive.c b/builtin-archive.c index 651d1bf6d9..b944737550 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -15,8 +15,15 @@ static const char archive_usage[] = \ "git-archive --format= [--prefix=/] [] [path...]"; struct archiver archivers[] = { - { .name = "tar", .write_archive = write_tar_archive }, - { .name = "zip", .write_archive = write_zip_archive }, + { + .name = "tar", + .write_archive = write_tar_archive, + }, + { + .name = "zip", + .write_archive = write_zip_archive, + .parse_extra = parse_extra_zip_args, + }, }; static int run_remote_archiver(struct archiver *ar, int argc, diff --git a/builtin-zip-tree.c b/builtin-zip-tree.c index 3afb7bde74..4e796338af 100644 --- a/builtin-zip-tree.c +++ b/builtin-zip-tree.c @@ -379,3 +379,16 @@ int write_zip_archive(struct archiver_args *args) return 0; } + +void *parse_extra_zip_args(int argc, const char **argv) +{ + for (; argc > 0; argc--, argv++) { + const char *arg = argv[0]; + + 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; +}