shortlog: group by committer information
[gitweb.git] / upload-pack.c
index e40d15adaff6d164d72156ebddb9b4f152d92d96..e0db8b42be2d6ba400da987f8cb2ba573c5eda01 100644 (file)
 #include "sigchain.h"
 #include "version.h"
 #include "string-list.h"
+#include "parse-options.h"
 #include "argv-array.h"
+#include "prio-queue.h"
 
-static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>";
+static const char * const upload_pack_usage[] = {
+       N_("git upload-pack [<options>] <dir>"),
+       NULL
+};
 
 /* Remember to update object flag allocation in object.h */
 #define THEY_HAVE      (1u << 11)
@@ -54,26 +59,28 @@ static int keepalive = 5;
 static int use_sideband;
 static int advertise_refs;
 static int stateless_rpc;
+static const char *pack_objects_hook;
 
 static void reset_timeout(void)
 {
        alarm(timeout);
 }
 
-static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
+static void send_client_data(int fd, const char *data, ssize_t sz)
 {
-       if (use_sideband)
-               return send_sideband(1, fd, data, sz, use_sideband);
+       if (use_sideband) {
+               send_sideband(1, fd, data, sz, use_sideband);
+               return;
+       }
        if (fd == 3)
                /* emergency quit */
                fd = 2;
        if (fd == 2) {
                /* XXX: are we happy to lose stuff here? */
                xwrite(fd, data, sz);
-               return sz;
+               return;
        }
        write_or_die(fd, data, sz);
-       return sz;
 }
 
 static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
@@ -92,35 +99,39 @@ static void create_pack_file(void)
                "corruption on the remote side.";
        int buffered = -1;
        ssize_t sz;
-       const char *argv[13];
-       int i, arg = 0;
+       int i;
        FILE *pipe_fd;
 
+       if (!pack_objects_hook)
+               pack_objects.git_cmd = 1;
+       else {
+               argv_array_push(&pack_objects.args, pack_objects_hook);
+               argv_array_push(&pack_objects.args, "git");
+               pack_objects.use_shell = 1;
+       }
+
        if (shallow_nr) {
-               argv[arg++] = "--shallow-file";
-               argv[arg++] = "";
+               argv_array_push(&pack_objects.args, "--shallow-file");
+               argv_array_push(&pack_objects.args, "");
        }
-       argv[arg++] = "pack-objects";
-       argv[arg++] = "--revs";
+       argv_array_push(&pack_objects.args, "pack-objects");
+       argv_array_push(&pack_objects.args, "--revs");
        if (use_thin_pack)
-               argv[arg++] = "--thin";
+               argv_array_push(&pack_objects.args, "--thin");
 
-       argv[arg++] = "--stdout";
+       argv_array_push(&pack_objects.args, "--stdout");
        if (shallow_nr)
-               argv[arg++] = "--shallow";
+               argv_array_push(&pack_objects.args, "--shallow");
        if (!no_progress)
-               argv[arg++] = "--progress";
+               argv_array_push(&pack_objects.args, "--progress");
        if (use_ofs_delta)
-               argv[arg++] = "--delta-base-offset";
+               argv_array_push(&pack_objects.args, "--delta-base-offset");
        if (use_include_tag)
-               argv[arg++] = "--include-tag";
-       argv[arg++] = NULL;
+               argv_array_push(&pack_objects.args, "--include-tag");
 
        pack_objects.in = -1;
        pack_objects.out = -1;
        pack_objects.err = -1;
-       pack_objects.git_cmd = 1;
-       pack_objects.argv = argv;
 
        if (start_command(&pack_objects))
                die("git upload-pack: unable to fork git-pack-objects");
@@ -179,8 +190,7 @@ static void create_pack_file(void)
 
                if (ret < 0) {
                        if (errno != EINTR) {
-                               error("poll failed, resuming: %s",
-                                     strerror(errno));
+                               error_errno("poll failed, resuming");
                                sleep(1);
                        }
                        continue;
@@ -235,9 +245,7 @@ static void create_pack_file(void)
                        }
                        else
                                buffered = -1;
-                       sz = send_client_data(1, data, sz);
-                       if (sz < 0)
-                               goto fail;
+                       send_client_data(1, data, sz);
                }
 
                /*
@@ -264,9 +272,7 @@ static void create_pack_file(void)
        /* flush the data */
        if (0 <= buffered) {
                data[0] = buffered;
-               sz = send_client_data(1, data, 1);
-               if (sz < 0)
-                       goto fail;
+               send_client_data(1, data, 1);
                fprintf(stderr, "flushed.\n");
        }
        if (use_sideband)
@@ -314,12 +320,12 @@ static int got_sha1(const char *hex, unsigned char *sha1)
 
 static int reachable(struct commit *want)
 {
-       struct commit_list *work = NULL;
+       struct prio_queue work = { compare_commits_by_commit_date };
 
-       commit_list_insert_by_date(want, &work);
-       while (work) {
+       prio_queue_put(&work, want);
+       while (work.nr) {
                struct commit_list *list;
-               struct commit *commit = pop_commit(&work);
+               struct commit *commit = prio_queue_get(&work);
 
                if (commit->object.flags & THEY_HAVE) {
                        want->object.flags |= COMMON_KNOWN;
@@ -335,12 +341,12 @@ static int reachable(struct commit *want)
                for (list = commit->parents; list; list = list->next) {
                        struct commit *parent = list->item;
                        if (!(parent->object.flags & REACHABLE))
-                               commit_list_insert_by_date(parent, &work);
+                               prio_queue_put(&work, parent);
                }
        }
        want->object.flags |= REACHABLE;
        clear_commit_marks(want, REACHABLE);
-       free_commit_list(work);
+       clear_prio_queue(&work);
        return (want->object.flags & COMMON_KNOWN);
 }
 
@@ -392,13 +398,13 @@ static int get_common_commits(void)
                        if (multi_ack == 2 && got_common
                            && !got_other && ok_to_give_up()) {
                                sent_ready = 1;
-                               packet_write(1, "ACK %s ready\n", last_hex);
+                               packet_write_fmt(1, "ACK %s ready\n", last_hex);
                        }
                        if (have_obj.nr == 0 || multi_ack)
-                               packet_write(1, "NAK\n");
+                               packet_write_fmt(1, "NAK\n");
 
                        if (no_done && sent_ready) {
-                               packet_write(1, "ACK %s\n", last_hex);
+                               packet_write_fmt(1, "ACK %s\n", last_hex);
                                return 0;
                        }
                        if (stateless_rpc)
@@ -415,20 +421,20 @@ static int get_common_commits(void)
                                        const char *hex = sha1_to_hex(sha1);
                                        if (multi_ack == 2) {
                                                sent_ready = 1;
-                                               packet_write(1, "ACK %s ready\n", hex);
+                                               packet_write_fmt(1, "ACK %s ready\n", hex);
                                        } else
-                                               packet_write(1, "ACK %s continue\n", hex);
+                                               packet_write_fmt(1, "ACK %s continue\n", hex);
                                }
                                break;
                        default:
                                got_common = 1;
                                memcpy(last_hex, sha1_to_hex(sha1), 41);
                                if (multi_ack == 2)
-                                       packet_write(1, "ACK %s common\n", last_hex);
+                                       packet_write_fmt(1, "ACK %s common\n", last_hex);
                                else if (multi_ack)
-                                       packet_write(1, "ACK %s continue\n", last_hex);
+                                       packet_write_fmt(1, "ACK %s continue\n", last_hex);
                                else if (have_obj.nr == 1)
-                                       packet_write(1, "ACK %s\n", last_hex);
+                                       packet_write_fmt(1, "ACK %s\n", last_hex);
                                break;
                        }
                        continue;
@@ -436,10 +442,10 @@ static int get_common_commits(void)
                if (!strcmp(line, "done")) {
                        if (have_obj.nr > 0) {
                                if (multi_ack)
-                                       packet_write(1, "ACK %s\n", last_hex);
+                                       packet_write_fmt(1, "ACK %s\n", last_hex);
                                return 0;
                        }
-                       packet_write(1, "NAK\n");
+                       packet_write_fmt(1, "NAK\n");
                        return -1;
                }
                die("git upload-pack: expected SHA1 list, got '%s'", line);
@@ -632,8 +638,8 @@ static void send_shallow(struct commit_list *result)
        while (result) {
                struct object *object = &result->item->object;
                if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {
-                       packet_write(1, "shallow %s",
-                                    oid_to_hex(&object->oid));
+                       packet_write_fmt(1, "shallow %s",
+                                        oid_to_hex(&object->oid));
                        register_shallow(object->oid.hash);
                        shallow_nr++;
                }
@@ -649,8 +655,8 @@ static void send_unshallow(const struct object_array *shallows)
                struct object *object = shallows->objects[i].item;
                if (object->flags & NOT_SHALLOW) {
                        struct commit_list *parents;
-                       packet_write(1, "unshallow %s",
-                                    oid_to_hex(&object->oid));
+                       packet_write_fmt(1, "unshallow %s",
+                                        oid_to_hex(&object->oid));
                        object->flags &= ~CLIENT_SHALLOW;
                        /*
                         * We want to _register_ "object" as shallow, but we
@@ -926,7 +932,7 @@ static int send_ref(const char *refname, const struct object_id *oid,
                struct strbuf symref_info = STRBUF_INIT;
 
                format_symref_info(&symref_info, cb_data);
-               packet_write(1, "%s %s%c%s%s%s%s%s agent=%s\n",
+               packet_write_fmt(1, "%s %s%c%s%s%s%s%s agent=%s\n",
                             oid_to_hex(oid), refname_nons,
                             0, capabilities,
                             (allow_unadvertised_object_request & ALLOW_TIP_SHA1) ?
@@ -938,11 +944,11 @@ static int send_ref(const char *refname, const struct object_id *oid,
                             git_user_agent_sanitized());
                strbuf_release(&symref_info);
        } else {
-               packet_write(1, "%s %s\n", oid_to_hex(oid), refname_nons);
+               packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), refname_nons);
        }
        capabilities = NULL;
        if (!peel_ref(refname, peeled.hash))
-               packet_write(1, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
+               packet_write_fmt(1, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons);
        return 0;
 }
 
@@ -1006,56 +1012,43 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
                keepalive = git_config_int(var, value);
                if (!keepalive)
                        keepalive = -1;
+       } else if (current_config_scope() != CONFIG_SCOPE_REPO) {
+               if (!strcmp("uploadpack.packobjectshook", var))
+                       return git_config_string(&pack_objects_hook, var, value);
        }
        return parse_hide_refs_config(var, value, "uploadpack");
 }
 
-int main(int argc, char **argv)
+int cmd_main(int argc, const char **argv)
 {
-       char *dir;
-       int i;
+       const char *dir;
        int strict = 0;
-
-       git_setup_gettext();
+       struct option options[] = {
+               OPT_BOOL(0, "stateless-rpc", &stateless_rpc,
+                        N_("quit after a single request/response exchange")),
+               OPT_BOOL(0, "advertise-refs", &advertise_refs,
+                        N_("exit immediately after initial ref advertisement")),
+               OPT_BOOL(0, "strict", &strict,
+                        N_("do not try <directory>/.git/ if <directory> is no Git directory")),
+               OPT_INTEGER(0, "timeout", &timeout,
+                           N_("interrupt transfer after <n> seconds of inactivity")),
+               OPT_END()
+       };
 
        packet_trace_identity("upload-pack");
-       git_extract_argv0_path(argv[0]);
        check_replace_refs = 0;
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       argc = parse_options(argc, argv, NULL, options, upload_pack_usage, 0);
 
-               if (arg[0] != '-')
-                       break;
-               if (!strcmp(arg, "--advertise-refs")) {
-                       advertise_refs = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--stateless-rpc")) {
-                       stateless_rpc = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--strict")) {
-                       strict = 1;
-                       continue;
-               }
-               if (skip_prefix(arg, "--timeout=", &arg)) {
-                       timeout = atoi(arg);
-                       daemon_mode = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--")) {
-                       i++;
-                       break;
-               }
-       }
+       if (argc != 1)
+               usage_with_options(upload_pack_usage, options);
 
-       if (i != argc-1)
-               usage(upload_pack_usage);
+       if (timeout)
+               daemon_mode = 1;
 
        setup_path();
 
-       dir = argv[i];
+       dir = argv[0];
 
        if (!enter_repo(dir, strict))
                die("'%s' does not appear to be a git repository", dir);