git-receive-pack$X git-rev-parse$X \
git-send-pack$X git-show-branch$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
- git-ssh-upload$X git-tar-tree$X git-unpack-file$X \
+ git-ssh-upload$X git-unpack-file$X \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X git-write-tree$X \
git-update-ref$X git-symbolic-ref$X \
BUILT_INS = git-log$X git-whatchanged$X git-show$X \
git-count-objects$X git-diff$X git-push$X \
git-grep$X git-rev-list$X git-check-ref-format$X \
- git-init-db$X
+ git-init-db$X git-tar-tree$X git-upload-tar$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
- builtin-init-db.o
+ builtin-init-db.o builtin-tar-tree.o builtin-upload-tar.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
#include "commit.h"
#include "strbuf.h"
#include "tar.h"
+#include "builtin.h"
+#include "pkt-line.h"
#define RECORDSIZE (512)
#define BLOCKSIZE (RECORDSIZE * 20)
-static const char tar_tree_usage[] = "git-tar-tree <key> [basedir]";
+static const char tar_tree_usage[] =
+"git-tar-tree [--remote=<repo>] <ent> [basedir]";
static char block[BLOCKSIZE];
static unsigned long offset;
}
}
-int main(int argc, char **argv)
+int generate_tar(int argc, const char **argv)
{
unsigned char sha1[20], tree_sha1[20];
struct commit *commit;
free(current_path.buf);
return 0;
}
+
+static const char *exec = "git-upload-tar";
+
+static int remote_tar(int argc, const char **argv)
+{
+ int fd[2], ret, len;
+ pid_t pid;
+ char buf[1024];
+ char *url;
+
+ if (argc < 3 || 4 < argc)
+ usage(tar_tree_usage);
+
+ /* --remote=<repo> */
+ url = strdup(argv[1]+9);
+ pid = git_connect(fd, url, exec);
+ if (pid < 0)
+ return 1;
+
+ packet_write(fd[1], "want %s\n", argv[2]);
+ if (argv[3])
+ packet_write(fd[1], "base %s\n", argv[3]);
+ packet_flush(fd[1]);
+
+ len = packet_read_line(fd[0], buf, sizeof(buf));
+ if (!len)
+ die("git-tar-tree: expected ACK/NAK, got EOF");
+ if (buf[len-1] == '\n')
+ buf[--len] = 0;
+ if (strcmp(buf, "ACK")) {
+ if (5 < len && !strncmp(buf, "NACK ", 5))
+ die("git-tar-tree: NACK %s", buf + 5);
+ die("git-tar-tree: protocol error");
+ }
+ /* expect a flush */
+ len = packet_read_line(fd[0], buf, sizeof(buf));
+ if (len)
+ die("git-tar-tree: expected a flush");
+
+ /* Now, start reading from fd[0] and spit it out to stdout */
+ ret = copy_fd(fd[0], 1);
+ close(fd[0]);
+
+ ret |= finish_connect(pid);
+ return !!ret;
+}
+
+int cmd_tar_tree(int argc, const char **argv, char **envp)
+{
+ if (argc < 2)
+ usage(tar_tree_usage);
+ if (!strncmp("--remote=", argv[1], 9))
+ return remote_tar(argc, argv);
+ return generate_tar(argc, argv);
+}
--- /dev/null
+/*
+ * Copyright (c) 2006 Junio C Hamano
+ */
+#include "cache.h"
+#include "pkt-line.h"
+#include "exec_cmd.h"
+#include "builtin.h"
+
+static const char upload_tar_usage[] = "git-upload-tar <repo>";
+
+static int nak(const char *reason)
+{
+ packet_write(1, "NACK %s\n", reason);
+ packet_flush(1);
+ return 1;
+}
+
+int cmd_upload_tar(int argc, const char **argv, char **envp)
+{
+ int len;
+ const char *dir = argv[1];
+ char buf[8192];
+ unsigned char sha1[20];
+ char *base = NULL;
+ char hex[41];
+ int ac;
+ const char *av[4];
+
+ if (argc != 2)
+ usage(upload_tar_usage);
+ if (strlen(dir) < sizeof(buf)-1)
+ strcpy(buf, dir); /* enter-repo smudges its argument */
+ else
+ packet_write(1, "NACK insanely long repository name %s\n", dir);
+ if (!enter_repo(buf, 0)) {
+ packet_write(1, "NACK not a git archive %s\n", dir);
+ packet_flush(1);
+ return 1;
+ }
+
+ len = packet_read_line(0, buf, sizeof(buf));
+ if (len < 5 || strncmp("want ", buf, 5))
+ return nak("expected want");
+ if (buf[len-1] == '\n')
+ buf[--len] = 0;
+ if (get_sha1(buf + 5, sha1))
+ return nak("expected sha1");
+ strcpy(hex, sha1_to_hex(sha1));
+
+ len = packet_read_line(0, buf, sizeof(buf));
+ if (len) {
+ if (len < 5 || strncmp("base ", buf, 5))
+ return nak("expected (optional) base");
+ if (buf[len-1] == '\n')
+ buf[--len] = 0;
+ base = strdup(buf + 5);
+ len = packet_read_line(0, buf, sizeof(buf));
+ }
+ if (len)
+ return nak("expected flush");
+
+ packet_write(1, "ACK\n");
+ packet_flush(1);
+
+ ac = 0;
+ av[ac++] = "tar-tree";
+ av[ac++] = hex;
+ if (base)
+ av[ac++] = base;
+ av[ac++] = NULL;
+ execv_git_cmd(av);
+ /* should it return that is an error */
+ return 1;
+}
extern int cmd_rev_list(int argc, const char **argv, char **envp);
extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
extern int cmd_init_db(int argc, const char **argv, char **envp);
+extern int cmd_tar_tree(int argc, const char **argv, char **envp);
+extern int cmd_upload_tar(int argc, const char **argv, char **envp);
#endif
{ "count-objects", cmd_count_objects },
{ "diff", cmd_diff },
{ "grep", cmd_grep },
- { "rev-list", cmd_rev_list },
{ "init-db", cmd_init_db },
+ { "tar-tree", cmd_tar_tree },
+ { "upload-tar", cmd_upload_tar },
+ { "rev-list", cmd_rev_list },
{ "check-ref-format", cmd_check_ref_format }
};
int i;