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} could be removed. Signed-off-by: Franck Bui-Huu <vagabon.xyz@xxxxxxxxx> --- .gitignore | 1 Makefile | 1 builtin-upload-archive.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++ builtin.h | 1 daemon.c | 13 +++++- git.c | 1 6 files changed, 117 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a3e7ca1..fda9bf2 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/Makefile b/Makefile index 51ed4dd..461e1d6 100644 --- a/Makefile +++ b/Makefile @@ -305,6 +305,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 0000000..5e389fc --- /dev/null +++ b/builtin-upload-archive.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2006 Franck Bui-Huu + */ +#include <time.h> +#include "cache.h" +#include "builtin.h" +#include "archive.h" +#include "pkt-line.h" + +#define MAX_ARGS 32 + +static const char upload_archive_usage[] = + "git-upload-archive --format=fmt <repo>"; + +static int NACK(const char *reason) +{ + packet_write(1, "NACK %s\n", reason); + packet_flush(1); + return -1; +} + +int cmd_upload_archive(int argc, const char **argv, const char *prefix) +{ + struct archiver_struct *ar; + const char *sent_argv[MAX_ARGS]; + const char *arg_cmd = "arguments "; + const char *reason; + char *p, buf[8192]; + int treeish_idx; + int sent_argc; + int len; + int rv; + + const char **pathspec; + struct tree *tree; + const unsigned char *commit_sha1; + time_t archive_time; + + if (argc != 3) + usage(upload_archive_usage); + + if (strlen(argv[2]) > sizeof(buf)) { + reason = "insanely long repository name"; + goto nack; + } + strcpy(buf, argv[2]); /* enter-repo smudges its argument */ + + if (!enter_repo(buf, 0)) { + reason = "not a git archive"; + goto nack; + } + + len = packet_read_line(0, buf, sizeof(buf)); + if (len < strlen(arg_cmd) || strncmp(arg_cmd, buf, strlen(arg_cmd))) { + reason = "expected 'arguments' command"; + goto nack; + } + if (buf[len-1] == '\n') + buf[--len] = 0; + + /* we can safely override 'arg_cmd' */ + len = packet_read_line(0, buf, strlen(arg_cmd)); + if (len) { + reason = "flush expected"; + goto nack; + } + p = buf + strlen(arg_cmd); + + /* put received line options in sent_argv[] */ + sent_argv[0] = "git-upload-archive"; + sent_argv[1] = argv[1]; /* --format=<fmt> */ + sent_argc = 2; + while (p) { + if (sent_argc > MAX_ARGS - 2) { + reason = "Too many options (>29)"; + goto nack; + } + sent_argv[sent_argc++] = strsep(&p, " "); + } + sent_argv[sent_argc] = NULL; + + /* parse all options sent by the client */ + treeish_idx = parse_archive_args(sent_argc, sent_argv, &ar, &reason); + if (treeish_idx < 0) + goto nack; + + rv = parse_treeish_arg(sent_argv + treeish_idx, &tree, &commit_sha1, + &archive_time, prefix, &reason); + if (rv < 0) + goto nack; + + pathspec = get_pathspec(ar->prefix, sent_argv + treeish_idx + 1); + + packet_write(1, "ACK\n"); + packet_flush(1); + + return ar->write_archive(tree, commit_sha1, ar->prefix, + archive_time, pathspec); +nack: + return NACK(reason); +} + diff --git a/builtin.h b/builtin.h index 2391afb..f3efb58 100644 --- a/builtin.h +++ b/builtin.h @@ -58,6 +58,7 @@ extern int cmd_zip_tree(int argc, const 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 a4a08f3..c09280f 100644 --- a/daemon.c +++ b/daemon.c @@ -324,12 +324,21 @@ static int upload_pack(void) return -1; } -static int upload_tar(void) +static int upload_archive(const char *fmt) { - execl_git_cmd("upload-tar", ".", NULL); + char buf[64]; + + snprintf(buf, sizeof(buf), "--format=%s", fmt); + + execl_git_cmd("upload-archive", buf, ".", NULL); return -1; } +static int upload_tar(void) +{ + return upload_archive("tar"); +} + static struct daemon_service daemon_service[] = { { "upload-pack", "uploadpack", upload_pack, 1, 1 }, { "upload-tar", "uploadtar", upload_tar, 0, 1 }, diff --git a/git.c b/git.c index c62c5cf..315dc0b 100644 --- a/git.c +++ b/git.c @@ -261,6 +261,7 @@ static void handle_internal_command(int { "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 }, -- 1.4.2.gbba4 - 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