diff options
Diffstat (limited to 'builtin-archive.c')
-rw-r--r-- | builtin-archive.c | 92 |
1 files changed, 86 insertions, 6 deletions
diff --git a/builtin-archive.c b/builtin-archive.c index 187491bc17..14a1b3077c 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -10,6 +10,7 @@ #include "exec_cmd.h" #include "pkt-line.h" #include "sideband.h" +#include "attr.h" static const char archive_usage[] = \ "git-archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]"; @@ -29,7 +30,7 @@ static int run_remote_archiver(const char *remote, int argc, { char *url, buf[LARGE_PACKET_MAX]; int fd[2], i, len, rv; - pid_t pid; + struct child_process *conn; const char *exec = "git-upload-archive"; int exec_at = 0; @@ -45,9 +46,7 @@ static int run_remote_archiver(const char *remote, int argc, } url = xstrdup(remote); - pid = git_connect(fd, url, exec, 0); - if (pid < 0) - return pid; + conn = git_connect(fd, url, exec, 0); for (i = 1; i < argc; i++) { if (i == exec_at) @@ -75,11 +74,91 @@ static int run_remote_archiver(const char *remote, int argc, rv = recv_sideband("archive", fd[0], 1, 2); close(fd[0]); close(fd[1]); - rv |= finish_connect(pid); + rv |= finish_connect(conn); return !!rv; } +static void format_subst(const struct commit *commit, + const char *src, size_t len, + struct strbuf *buf) +{ + char *to_free = NULL; + struct strbuf fmt; + + if (src == buf->buf) + to_free = strbuf_detach(buf, NULL); + strbuf_init(&fmt, 0); + for (;;) { + const char *b, *c; + + b = memmem(src, len, "$Format:", 8); + if (!b || src + len < b + 9) + break; + c = memchr(b + 8, '$', len - 8); + if (!c) + break; + + strbuf_reset(&fmt); + strbuf_add(&fmt, b + 8, c - b - 8); + + strbuf_add(buf, src, b - src); + format_commit_message(commit, fmt.buf, buf); + len -= c + 1 - src; + src = c + 1; + } + strbuf_add(buf, src, len); + strbuf_release(&fmt); + 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) +{ + void *buffer; + + buffer = read_sha1_file(sha1, type, sizep); + if (buffer && S_ISREG(mode)) { + struct strbuf buf; + size_t size = 0; + + 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); + buffer = strbuf_detach(&buf, &size); + *sizep = size; + } + + return buffer; +} + static int init_archiver(const char *name, struct archiver *ar) { int rv = -1, i; @@ -109,7 +188,7 @@ void parse_treeish_arg(const char **argv, struct archiver_args *ar_args, const unsigned char *commit_sha1; time_t archive_time; struct tree *tree; - struct commit *commit; + const struct commit *commit; unsigned char sha1[20]; if (get_sha1(name, sha1)) @@ -142,6 +221,7 @@ void parse_treeish_arg(const char **argv, struct archiver_args *ar_args, } ar_args->tree = tree; ar_args->commit_sha1 = commit_sha1; + ar_args->commit = commit; ar_args->time = archive_time; } |